flat: 视频版本0.1
This commit is contained in:
8
App.vue
8
App.vue
@@ -7,12 +7,9 @@ const { $api, navTo, appendScriptTagElement } = inject('globalFunction');
|
||||
|
||||
onLaunch((options) => {
|
||||
useDictStore().getDictData();
|
||||
// uni.onTabBarMidButtonTap(() => {
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/chat/chat',
|
||||
// });
|
||||
// });
|
||||
// uni.hideTabBar();
|
||||
|
||||
// 登录
|
||||
let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
|
||||
if (token) {
|
||||
useUserStore()
|
||||
@@ -52,6 +49,7 @@ onHide(() => {
|
||||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
@import '@/common/animation.css';
|
||||
@import '@/common/common.css';
|
||||
/* 修改pages tabbar样式 H5有效 */
|
||||
.uni-tabbar .uni-tabbar__item:nth-child(4) .uni-tabbar__bd .uni-tabbar__icon {
|
||||
|
193
common/animation.css
Normal file
193
common/animation.css
Normal file
@@ -0,0 +1,193 @@
|
||||
/*base code*/
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.infinite {
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animated.hinge {
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
/*the animation definition*/
|
||||
@-webkit-keyframes tada {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
|
||||
10%,
|
||||
20% {
|
||||
-webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)
|
||||
}
|
||||
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)
|
||||
}
|
||||
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tada {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
-ms-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
|
||||
10%,
|
||||
20% {
|
||||
-webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
|
||||
-ms-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)
|
||||
}
|
||||
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
-ms-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)
|
||||
}
|
||||
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
-ms-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
-ms-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
.tada {
|
||||
-webkit-animation-name: tada;
|
||||
animation-name: tada
|
||||
}
|
||||
|
||||
|
||||
.btn-tada:active {
|
||||
-webkit-animation-name: tada;
|
||||
animation-name: tada
|
||||
}
|
||||
|
||||
/*the animation definition*/
|
||||
@-webkit-keyframes rubberBand {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
|
||||
30% {
|
||||
-webkit-transform: scale3d(1.25, .75, 1);
|
||||
transform: scale3d(1.25, .75, 1)
|
||||
}
|
||||
|
||||
40% {
|
||||
-webkit-transform: scale3d(0.75, 1.25, 1);
|
||||
transform: scale3d(0.75, 1.25, 1)
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.15, .85, 1);
|
||||
transform: scale3d(1.15, .85, 1)
|
||||
}
|
||||
|
||||
65% {
|
||||
-webkit-transform: scale3d(.95, 1.05, 1);
|
||||
transform: scale3d(.95, 1.05, 1)
|
||||
}
|
||||
|
||||
75% {
|
||||
-webkit-transform: scale3d(1.05, .95, 1);
|
||||
transform: scale3d(1.05, .95, 1)
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rubberBand {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
-ms-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
|
||||
30% {
|
||||
-webkit-transform: scale3d(1.25, .75, 1);
|
||||
-ms-transform: scale3d(1.25, .75, 1);
|
||||
transform: scale3d(1.25, .75, 1)
|
||||
}
|
||||
|
||||
40% {
|
||||
-webkit-transform: scale3d(0.75, 1.25, 1);
|
||||
-ms-transform: scale3d(0.75, 1.25, 1);
|
||||
transform: scale3d(0.75, 1.25, 1)
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.15, .85, 1);
|
||||
-ms-transform: scale3d(1.15, .85, 1);
|
||||
transform: scale3d(1.15, .85, 1)
|
||||
}
|
||||
|
||||
65% {
|
||||
-webkit-transform: scale3d(.95, 1.05, 1);
|
||||
-ms-transform: scale3d(.95, 1.05, 1);
|
||||
transform: scale3d(.95, 1.05, 1)
|
||||
}
|
||||
|
||||
75% {
|
||||
-webkit-transform: scale3d(1.05, .95, 1);
|
||||
-ms-transform: scale3d(1.05, .95, 1);
|
||||
transform: scale3d(1.05, .95, 1)
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
-ms-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
.rubberBand {
|
||||
-webkit-animation-name: rubberBand;
|
||||
animation-name: rubberBand
|
||||
}
|
||||
|
||||
|
||||
.btn-rubberBand:active {
|
||||
-webkit-animation-name: tada;
|
||||
animation-name: tada
|
||||
}
|
@@ -56,6 +56,7 @@ html {
|
||||
background-color: rgba(189, 197, 254, 0.15);
|
||||
}
|
||||
|
||||
|
||||
.btn-incline {
|
||||
transition: transform 0.2s ease;
|
||||
transform-style: preserve-3d;
|
||||
@@ -74,6 +75,23 @@ html {
|
||||
transform: perspective(600px) rotateX(6deg) scale(0.98);
|
||||
}
|
||||
|
||||
.press-button {
|
||||
padding: 10px 20px;
|
||||
background: #3A4750;
|
||||
/* 深灰蓝 */
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.1s ease, box-shadow 0.1s ease;
|
||||
/* box-shadow: 0 4px 0 #2C3E50; */
|
||||
}
|
||||
|
||||
.press-button:active {
|
||||
transform: scale(0.95) translateY(2px);
|
||||
/* box-shadow: 0 2px 0 #1C2833; */
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
.btn-shaky:active {
|
||||
|
312
components/TikTok/TikTok.vue
Normal file
312
components/TikTok/TikTok.vue
Normal file
@@ -0,0 +1,312 @@
|
||||
<template>
|
||||
<swiper
|
||||
class="m-tiktok-video-swiper"
|
||||
circular
|
||||
@change="swiperChange"
|
||||
:current="state.current"
|
||||
:vertical="true"
|
||||
duration="300"
|
||||
>
|
||||
<swiper-item v-for="(item, index) in state.displaySwiperList" :key="index">
|
||||
<view class="swiper-item" @click="(e) => handleClick(index, e)">
|
||||
<video
|
||||
:id="`video__${index}`"
|
||||
:controls="controls"
|
||||
:autoplay="false"
|
||||
:loop="loop"
|
||||
@ended="ended"
|
||||
@controlstoggle="controlstoggle"
|
||||
@play="onPlay"
|
||||
@error="emits('error')"
|
||||
class="m-tiktok-video-player"
|
||||
:src="item.src || item.explainUrl"
|
||||
v-if="index === 0 || !state.isFirstLoad"
|
||||
></video>
|
||||
<view class="cover-triangle" v-if="pause"></view>
|
||||
<image
|
||||
v-if="item.poster && state.displayIndex != index"
|
||||
:src="item.poster"
|
||||
class="m-tiktok-video-poster"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<slot :item="item"></slot>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, getCurrentInstance, watch, nextTick } from 'vue';
|
||||
import { onLoad, onUnload } from '@dcloudio/uni-app';
|
||||
const _this = getCurrentInstance();
|
||||
const emits = defineEmits(['play', 'error', 'loadMore', 'change', 'controlstoggle', 'click', 'ended']);
|
||||
|
||||
const lastTapTime = ref(0);
|
||||
const pause = ref(false);
|
||||
const props = defineProps({
|
||||
/**
|
||||
* 视频列表
|
||||
*/
|
||||
videoList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
/**
|
||||
* 是否循环播放一个视频
|
||||
*/
|
||||
loop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 显示原生控制栏
|
||||
*/
|
||||
controls: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 是否自动播放
|
||||
*/
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 是否自动滚动播放
|
||||
*/
|
||||
autoChange: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 滚动加载阈值(即播放到剩余多少个之后触发加载更多
|
||||
*/
|
||||
loadMoreOffsetCount: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
/**
|
||||
* 暂停 1 单机暂停; 2 双击暂停; 0关闭
|
||||
*/
|
||||
pauseType: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
originList: [], // 源数据
|
||||
displaySwiperList: [], // swiper需要的数据
|
||||
displayIndex: 0, // 用于显示swiper的真正的下标数值只有:0,1,2。
|
||||
originIndex: 0, // 记录源数据的下标
|
||||
current: 0,
|
||||
oid: 0,
|
||||
showControls: '',
|
||||
toggleShow: true, // 显示面板
|
||||
videoContexts: [],
|
||||
isFirstLoad: true,
|
||||
});
|
||||
|
||||
const initVideoContexts = () => {
|
||||
state.videoContexts = [
|
||||
uni.createVideoContext('video__0', _this),
|
||||
uni.createVideoContext('video__1', _this),
|
||||
uni.createVideoContext('video__2', _this),
|
||||
];
|
||||
};
|
||||
|
||||
const onPlay = (e) => {
|
||||
emits('play', e);
|
||||
};
|
||||
|
||||
const setVideoRef = (el, index) => {
|
||||
if (el) {
|
||||
videoRefs.value[index] = el;
|
||||
}
|
||||
};
|
||||
|
||||
function handleClick(index, e) {
|
||||
const now = Date.now();
|
||||
switch (props.pauseType) {
|
||||
case 1:
|
||||
if (pause.value) {
|
||||
state.videoContexts[index].play();
|
||||
pause.value = false;
|
||||
} else {
|
||||
state.videoContexts[index].pause();
|
||||
pause.value = true;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (now - lastTapTime.value < 300) {
|
||||
if (pause.value) {
|
||||
state.videoContexts[index].play();
|
||||
pause.value = false;
|
||||
} else {
|
||||
state.videoContexts[index].pause();
|
||||
pause.value = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
lastTapTime.value = now;
|
||||
state.toggleShow = !state.toggleShow;
|
||||
emits('click', e);
|
||||
}
|
||||
function ended() {
|
||||
// 自动切换下一个视频
|
||||
if (props.autoChange) {
|
||||
if (state.displayIndex < 2) {
|
||||
state.current = state.displayIndex + 1;
|
||||
} else {
|
||||
state.current = 0;
|
||||
}
|
||||
}
|
||||
emits('ended');
|
||||
}
|
||||
/**
|
||||
* 初始一个显示的swiper数据
|
||||
* @originIndex 从源数据的哪个开始显示默认0,如从其他页面跳转进来,要显示第n个,这个参数就是他的下标
|
||||
*/
|
||||
function initSwiperData(originIndex = state.originIndex) {
|
||||
const originListLength = state.originList.length; // 源数据长度
|
||||
const displayList = [];
|
||||
displayList[state.displayIndex] = state.originList[originIndex];
|
||||
displayList[state.displayIndex - 1 == -1 ? 2 : state.displayIndex - 1] =
|
||||
state.originList[originIndex - 1 == -1 ? originListLength - 1 : originIndex - 1];
|
||||
displayList[state.displayIndex + 1 == 3 ? 0 : state.displayIndex + 1] =
|
||||
state.originList[originIndex + 1 == originListLength ? 0 : originIndex + 1];
|
||||
state.displaySwiperList = displayList;
|
||||
|
||||
if (state.oid >= state.originList.length) {
|
||||
state.oid = 0;
|
||||
}
|
||||
if (state.oid < 0) {
|
||||
state.oid = state.originList.length - 1;
|
||||
}
|
||||
// 暂停所有视频
|
||||
state.videoContexts.map((item) => item?.stop());
|
||||
setTimeout(() => {
|
||||
// 当前视频
|
||||
if (props.autoplay) {
|
||||
uni.createVideoContext(`video__${state.displayIndex}`, _this).play();
|
||||
}
|
||||
}, 500);
|
||||
// 数据改变
|
||||
emits('change', {
|
||||
index: originIndex,
|
||||
detail: state.originList[originIndex],
|
||||
});
|
||||
// 加载更多
|
||||
var pCount = state.originList.length - props.loadMoreOffsetCount;
|
||||
if (originIndex == pCount) {
|
||||
emits('loadMore');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* swiper滑动时候
|
||||
*/
|
||||
function swiperChange(event) {
|
||||
const { current } = event.detail;
|
||||
state.isFirstLoad = false;
|
||||
const originListLength = state.originList.length; // 源数据长度
|
||||
// 向后滚动
|
||||
if (state.displayIndex - current == 2 || state.displayIndex - current == -1) {
|
||||
state.originIndex = state.originIndex + 1 == originListLength ? 0 : state.originIndex + 1;
|
||||
state.displayIndex = state.displayIndex + 1 == 3 ? 0 : state.displayIndex + 1;
|
||||
state.oid = state.originIndex - 1;
|
||||
initSwiperData(state.originIndex);
|
||||
}
|
||||
// 如果两者的差为-2或者1则是向前滑动
|
||||
else if (state.displayIndex - current == -2 || state.displayIndex - current == 1) {
|
||||
state.originIndex = state.originIndex - 1 == -1 ? originListLength - 1 : state.originIndex - 1;
|
||||
state.displayIndex = state.displayIndex - 1 == -1 ? 2 : state.displayIndex - 1;
|
||||
state.oid = state.originIndex + 1;
|
||||
initSwiperData(state.originIndex);
|
||||
}
|
||||
state.toggleShow = true;
|
||||
}
|
||||
|
||||
function controlstoggle(e) {
|
||||
state.showControls = e.detail.show;
|
||||
emits('controlstoggle', e);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.videoList,
|
||||
() => {
|
||||
if (props.videoList?.length) {
|
||||
state.originList = props.videoList;
|
||||
if (state.isFirstLoad || !state.videoContexts?.length) {
|
||||
initSwiperData();
|
||||
initVideoContexts();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
let loadTimer = null;
|
||||
onLoad(() => {
|
||||
// 为了首次只加载一条视频(提高首次加载性能),延迟加载后续视频
|
||||
loadTimer = setTimeout(() => {
|
||||
state.isFirstLoad = false;
|
||||
clearTimeout(loadTimer);
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
onUnload(() => {
|
||||
clearTimeout(loadTimer);
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
initSwiperData,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.m-tiktok-video-swiper,
|
||||
.m-tiktok-video-player {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
}
|
||||
.m-tiktok-video-swiper {
|
||||
.swiper-item {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
.m-tiktok-video-poster {
|
||||
background-color: #000;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.cover-triangle{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%)
|
||||
width: 132rpx
|
||||
height: 132rpx
|
||||
border-radius: 50%;
|
||||
background: rgba(0,0,0,0.3)
|
||||
}
|
||||
.cover-triangle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-40%, -50%) rotate(90deg);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 40rpx solid transparent;
|
||||
border-right: 40rpx solid transparent;
|
||||
border-bottom: 60rpx solid #fff;
|
||||
}
|
||||
</style>
|
@@ -6,6 +6,7 @@
|
||||
background-color="#FFFFFF"
|
||||
@maskClick="maskClickFn"
|
||||
:mask-click="maskClick"
|
||||
class="popup-fix"
|
||||
>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
@@ -183,6 +184,15 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-fix {
|
||||
position: fixed !important;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
z-index: 9999;
|
||||
}
|
||||
.popup-content {
|
||||
color: #000000;
|
||||
height: 80vh;
|
||||
@@ -320,7 +330,7 @@ defineExpose({
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 15rpx;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
}
|
||||
.content-item:first-child {
|
||||
@@ -329,8 +339,8 @@ defineExpose({
|
||||
|
||||
.check-content {
|
||||
display: grid;
|
||||
gap:16rpx;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180rpx, 1fr));
|
||||
gap: 16rpx;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180rpx, 1fr));
|
||||
place-items: stretch;
|
||||
|
||||
.checkbox-item {
|
||||
@@ -338,9 +348,9 @@ defineExpose({
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
background-color: #d9d9d9;
|
||||
|
||||
min-width: 0;
|
||||
padding: 0 10rpx;
|
||||
|
||||
min-width: 0;
|
||||
padding: 0 10rpx;
|
||||
height: 80rpx;
|
||||
background: #e8eaee;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
@@ -348,12 +358,11 @@ defineExpose({
|
||||
.option-label {
|
||||
font-size: 28rpx;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.checkedstyle {
|
||||
|
||||
height: 76rpx;
|
||||
background: rgba(37, 107, 250, 0.06);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
@@ -362,4 +371,4 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<view class="tabbar_container">
|
||||
<view class="tabbar_item" v-for="(item, index) in tabbarList" :key="index" @click="changeItem(item)">
|
||||
<view class="item-top" :class="[item.centerItem ? 'center-item-img' : '']">
|
||||
<view
|
||||
class="item-top"
|
||||
:class="[
|
||||
item.centerItem ? 'center-item-img ' : '',
|
||||
item.centerItem && currentItem === item.id ? 'rubberBand animated' : '',
|
||||
]"
|
||||
>
|
||||
<image :src="currentItem == item.id ? item.selectedIconPath : item.iconPath"></image>
|
||||
</view>
|
||||
<view class="item-bottom" :class="[currentItem == item.id ? 'item-active' : '']">
|
||||
@@ -37,8 +43,8 @@ export default {
|
||||
id: 2,
|
||||
text: '',
|
||||
path: '/pages/chat/chat',
|
||||
iconPath: '../../static/tabbar/logo2copy.png',
|
||||
selectedIconPath: '../../static/tabbar/logo2copy.png',
|
||||
iconPath: '../../static/tabbar/logo3.png',
|
||||
selectedIconPath: '../../static/tabbar/logo3.png',
|
||||
centerItem: true,
|
||||
},
|
||||
{
|
||||
@@ -84,17 +90,18 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.tabbar_container {
|
||||
background-color: #ffffff;
|
||||
position: fixed;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
width: 100%;
|
||||
height: 126rpx;
|
||||
// box-shadow: 0 0 5px #999;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5rpx 0;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
z-index: 998;
|
||||
overflow: hidden;
|
||||
// position: fixed;
|
||||
// bottom: 0rpx;
|
||||
// left: 0rpx;
|
||||
// box-shadow: 0 0 5px #999;
|
||||
// padding-bottom: env(safe-area-inset-bottom);
|
||||
// z-index: 998;
|
||||
.tabbar_item {
|
||||
width: 33.33%;
|
||||
height: 100rpx;
|
||||
@@ -120,12 +127,12 @@ export default {
|
||||
}
|
||||
}
|
||||
.center-item-img {
|
||||
position: absolute;
|
||||
top: 0rpx;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
width: 96rpx !important;
|
||||
height: 96rpx !important;
|
||||
// position: absolute;
|
||||
// top: 0rpx;
|
||||
// left: 50%;
|
||||
// transform: translate(-50%, 0);
|
||||
width: 108rpx !important;
|
||||
height: 98rpx !important;
|
||||
}
|
||||
.item-active {
|
||||
color: #256bfa;
|
||||
|
173
hook/usePagination.js
Normal file
173
hook/usePagination.js
Normal file
@@ -0,0 +1,173 @@
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
watch,
|
||||
isRef,
|
||||
nextTick
|
||||
} from 'vue'
|
||||
|
||||
export function usePagination(
|
||||
requestFn,
|
||||
transformFn,
|
||||
options = {}
|
||||
) {
|
||||
const list = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(false)
|
||||
const finished = ref(false)
|
||||
const firstLoading = ref(true)
|
||||
const empty = ref(false)
|
||||
|
||||
const {
|
||||
pageSize = 10,
|
||||
search = {},
|
||||
autoWatchSearch = false,
|
||||
debounceTime = 300,
|
||||
autoFetch = false,
|
||||
|
||||
// 字段映射
|
||||
dataKey = 'rows',
|
||||
totalKey = 'total',
|
||||
|
||||
// 分页字段名映射
|
||||
pageField = 'current',
|
||||
sizeField = 'pageSize',
|
||||
|
||||
onBeforeRequest,
|
||||
onAfterRequest
|
||||
} = options
|
||||
|
||||
const pageState = reactive({
|
||||
page: 1,
|
||||
pageSize: isRef(pageSize) ? pageSize.value : pageSize,
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
search: isRef(search) ? search.value : search
|
||||
})
|
||||
|
||||
let debounceTimer = null
|
||||
|
||||
const fetchData = async (type = 'refresh') => {
|
||||
if (loading.value) return Promise.resolve()
|
||||
|
||||
loading.value = true
|
||||
error.value = false
|
||||
|
||||
if (typeof onBeforeRequest === 'function') {
|
||||
try {
|
||||
onBeforeRequest(type, pageState)
|
||||
} catch (err) {
|
||||
console.warn('onBeforeRequest 执行异常:', err)
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1
|
||||
finished.value = false
|
||||
if (list.value.length === 0) {
|
||||
firstLoading.value = true
|
||||
}
|
||||
} else if (type === 'loadMore') {
|
||||
if (pageState.page >= pageState.maxPage) {
|
||||
loading.value = false
|
||||
finished.value = true
|
||||
return Promise.resolve('no more')
|
||||
}
|
||||
pageState.page += 1
|
||||
}
|
||||
|
||||
const params = {
|
||||
[pageField]: pageState.page,
|
||||
[sizeField]: pageState.pageSize,
|
||||
...pageState.search
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await requestFn(params)
|
||||
|
||||
const rawData = res[dataKey]
|
||||
const total = res[totalKey]
|
||||
|
||||
const data = typeof transformFn === 'function' ? transformFn(rawData) : rawData
|
||||
|
||||
if (type === 'refresh') {
|
||||
list.value = data
|
||||
} else {
|
||||
list.value.push(...data)
|
||||
}
|
||||
|
||||
pageState.total = total
|
||||
pageState.maxPage = Math.ceil(total / pageState.pageSize)
|
||||
|
||||
finished.value = list.value.length >= total
|
||||
empty.value = list.value.length === 0
|
||||
} catch (err) {
|
||||
console.error('分页请求失败:', err)
|
||||
error.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
firstLoading.value = false
|
||||
|
||||
if (typeof onAfterRequest === 'function') {
|
||||
try {
|
||||
onAfterRequest(type, pageState, {
|
||||
error: error.value
|
||||
})
|
||||
} catch (err) {
|
||||
console.warn('onAfterRequest 执行异常:', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const refresh = () => fetchData('refresh')
|
||||
const loadMore = () => fetchData('loadMore')
|
||||
|
||||
const resetPagination = () => {
|
||||
list.value = []
|
||||
pageState.page = 1
|
||||
pageState.total = 0
|
||||
pageState.maxPage = 1
|
||||
finished.value = false
|
||||
error.value = false
|
||||
firstLoading.value = true
|
||||
empty.value = false
|
||||
}
|
||||
|
||||
if (autoWatchSearch && isRef(search)) {
|
||||
watch(search, (newVal) => {
|
||||
pageState.search = newVal
|
||||
// clearTimeout(debounceTimer)
|
||||
// debounceTimer = setTimeout(() => {
|
||||
// refresh()
|
||||
// }, debounceTime)
|
||||
}, {
|
||||
deep: true
|
||||
})
|
||||
}
|
||||
|
||||
watch(pageSize, (newVal) => {
|
||||
pageState.pageSize = newVal
|
||||
}, {
|
||||
deep: true
|
||||
})
|
||||
|
||||
if (autoFetch) {
|
||||
nextTick(() => {
|
||||
refresh()
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
list,
|
||||
loading,
|
||||
error,
|
||||
finished,
|
||||
firstLoading,
|
||||
empty,
|
||||
pageState,
|
||||
refresh,
|
||||
loadMore,
|
||||
resetPagination
|
||||
}
|
||||
}
|
@@ -13,7 +13,13 @@
|
||||
</template>
|
||||
<view class="content" v-show="!isEmptyObject(jobInfo)">
|
||||
<view class="content-top btn-feel">
|
||||
<view class="top-salary">{{ jobInfo.minSalary }}-{{ jobInfo.maxSalary }}/月</view>
|
||||
<view class="top-salary">
|
||||
<Salary-Expectation
|
||||
:max-salary="jobInfo.maxSalary"
|
||||
:min-salary="jobInfo.minSalary"
|
||||
:is-month="true"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
<view class="top-name">{{ jobInfo.jobTitle }}</view>
|
||||
<view class="top-info">
|
||||
<view class="info-img"><image src="/static/icon/post12.png"></image></view>
|
||||
|
136
packageA/pages/tiktok/tiktok.vue
Normal file
136
packageA/pages/tiktok/tiktok.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="video-container">
|
||||
<view class="back-box">
|
||||
<view class="btn">
|
||||
<uni-icons type="left" size="26" color="#FFFFFF" @click="navBack"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<mTikTok :video-list="state.videoList" :pause-type="1" :controls="false" @loadMore="loadMore" @change="change">
|
||||
<template v-slot="data">
|
||||
<view class="video-layer">
|
||||
<view class="title line_1">{{ currentItem.companyName }}</view>
|
||||
<view class="discription">
|
||||
<text class="line_1">
|
||||
{{ currentItem.jobTitle }}
|
||||
</text>
|
||||
<view class="seedetail" @click="nextDetail">
|
||||
查看详情
|
||||
<uni-icons type="right" color="#FFFFFF" size="14"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</mTikTok>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, navBack, navTo } = inject('globalFunction');
|
||||
import mTikTok from '@/components/TikTok/TikTok.vue';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { useRecommedIndexedDBStore } from '@/stores/useRecommedIndexedDBStore.js';
|
||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
const state = reactive({
|
||||
videoList: [],
|
||||
});
|
||||
const currentItem = ref(null);
|
||||
|
||||
onLoad(() => {
|
||||
const jobInfo = uni.getStorageSync(`job-Info`);
|
||||
if (jobInfo) {
|
||||
currentItem.value = jobInfo;
|
||||
state.videoList.push(jobInfo);
|
||||
}
|
||||
getNextVideoSrc(2);
|
||||
});
|
||||
|
||||
function nextDetail() {
|
||||
const job = currentItem.value;
|
||||
// 记录岗位类型,用作数据分析
|
||||
if (job.jobCategory) {
|
||||
const recordData = recommedIndexDb.JobParameter(job);
|
||||
recommedIndexDb.addRecord(recordData);
|
||||
}
|
||||
console.log(job.jobId);
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`);
|
||||
}
|
||||
|
||||
function getNextVideoSrc(num) {
|
||||
let params = {
|
||||
uuid: useUserStore().seesionId,
|
||||
count: num || 1,
|
||||
};
|
||||
$api.createRequest('/app/job/littleVideo/random', params).then((resData) => {
|
||||
const { data, code } = resData;
|
||||
state.videoList.push(...data);
|
||||
});
|
||||
}
|
||||
|
||||
const loadMore = () => {
|
||||
// 触发加载更多
|
||||
console.log('加载更多');
|
||||
getNextVideoSrc();
|
||||
};
|
||||
|
||||
const change = (e) => {
|
||||
currentItem.value = e.detail;
|
||||
console.log('🚀 ~ file: index.vue:53 ~ change ~ data:', e);
|
||||
};
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.video-container{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative
|
||||
.back-box{
|
||||
position: absolute;
|
||||
left: 20rpx;
|
||||
top: 20rpx
|
||||
color: #FFFFFF
|
||||
z-index: 2
|
||||
}
|
||||
}
|
||||
.video-layer {
|
||||
position: absolute;
|
||||
left: 24rpx;
|
||||
right: 24rpx;
|
||||
bottom: 30rpx;
|
||||
color: #fff;
|
||||
.title{
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
line-height: 100%;
|
||||
letter-spacing: 0%;
|
||||
}
|
||||
.discription{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
letter-spacing: 0%;
|
||||
margin-top: 20rpx
|
||||
display: flex
|
||||
align-items: center
|
||||
.seedetail{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
line-height: 100%;
|
||||
letter-spacing: 0%;
|
||||
white-space: nowrap
|
||||
padding-left: 20rpx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
10
pages.json
10
pages.json
@@ -186,10 +186,20 @@
|
||||
"navigationBarTitleText": "系统通知",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tiktok/tiktok",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
}],
|
||||
"tabBar": {
|
||||
"custom": true,
|
||||
"display": "none",
|
||||
"color": "#5E5F60",
|
||||
"selectedColor": "#256BFA",
|
||||
"borderStyle": "black",
|
||||
|
@@ -39,7 +39,7 @@
|
||||
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower">
|
||||
<view class="cards" v-if="fairList.length">
|
||||
<view
|
||||
class="card btn-incline"
|
||||
class="card press-button"
|
||||
v-for="(item, index) in fairList"
|
||||
:key="index"
|
||||
@click="navTo('/packageA/pages/exhibitors/exhibitors?jobFairId=' + item.jobFairId)"
|
||||
@@ -83,6 +83,7 @@
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<Tabbar :currentpage="1"></Tabbar>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -90,6 +91,7 @@
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
|
@@ -62,10 +62,11 @@
|
||||
<view class="chatmain-warpper">
|
||||
<ai-paging ref="paging"></ai-paging>
|
||||
</view>
|
||||
<!-- 自定义tabbar -->
|
||||
<view class="chatmain-footer" v-show="!isDrawerOpen">
|
||||
<Tabbar :currentpage="2"></Tabbar>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义tabbar -->
|
||||
<!-- <tabbar-custom :currentpage="2"></tabbar-custom> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -73,6 +74,7 @@
|
||||
import { ref, inject, nextTick, computed } from 'vue';
|
||||
const { $api, navTo, insertSortData } = inject('globalFunction');
|
||||
import { onLoad, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import useChatGroupDBStore from '@/stores/userChatGroupStore';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import aiPaging from './components/ai-paging.vue';
|
||||
@@ -108,16 +110,16 @@ onHide(() => {
|
||||
paging.value?.handleTouchCancel();
|
||||
if (isDrawerOpen.value) {
|
||||
isDrawerOpen.value = false;
|
||||
uni.showTabBar();
|
||||
// uni.showTabBar();
|
||||
}
|
||||
});
|
||||
|
||||
const toggleDrawer = () => {
|
||||
isDrawerOpen.value = !isDrawerOpen.value;
|
||||
if (isDrawerOpen.value) {
|
||||
uni.hideTabBar();
|
||||
// uni.hideTabBar();
|
||||
} else {
|
||||
uni.showTabBar();
|
||||
// uni.showTabBar();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,6 +146,7 @@ function updateSetting() {
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
header-height = 88rpx
|
||||
footer-height = 98rpx
|
||||
|
||||
/* 页面容器 */
|
||||
.container {
|
||||
@@ -277,6 +280,8 @@ header-height = 88rpx
|
||||
transition: margin-left 0.3s ease-in-out;
|
||||
position: relative
|
||||
background: #FFFFFF
|
||||
display: flex
|
||||
flex-direction: column
|
||||
.head
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
@@ -304,15 +309,20 @@ header-height = 88rpx
|
||||
height: 37rpx;
|
||||
|
||||
.chatmain-warpper
|
||||
height: 'calc(100% - %s)' % header-height
|
||||
height: 'calc(100% - %s)' %( header-height + footer-height)
|
||||
position: relative;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
border-top: 2rpx solid #F4F4F4;
|
||||
flex: 1
|
||||
|
||||
/* 页面被挤压时向右移动 */
|
||||
.main-content.shift {
|
||||
margin-left: 500rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
.chatmain-footer{
|
||||
height: footer-height;
|
||||
}
|
||||
</style>
|
||||
|
@@ -9,11 +9,11 @@
|
||||
<view class="chart button-click">职业图谱</view>
|
||||
</view>
|
||||
<view class="cards">
|
||||
<view class="card btn-feel" @click="navTo('/pages/nearby/nearby')">
|
||||
<view class="card press-button" @click="navTo('/pages/nearby/nearby')">
|
||||
<view class="card-title">附近工作</view>
|
||||
<view class="card-text">好岗职等你来</view>
|
||||
</view>
|
||||
<view class="card btn-feel" @click="navTo('/packageA/pages/choiceness/choiceness')">
|
||||
<view class="card press-button" @click="navTo('/packageA/pages/choiceness/choiceness')">
|
||||
<view class="card-title">精选企业</view>
|
||||
<view class="card-text">优选职得信赖</view>
|
||||
</view>
|
||||
@@ -132,6 +132,14 @@
|
||||
</view>
|
||||
<!-- 筛选 -->
|
||||
<select-filter ref="selectFilterModel"></select-filter>
|
||||
|
||||
<view class="maskFristEntry" v-if="maskFristEntry">
|
||||
<view class="entry-content">
|
||||
<text>左滑查看视频</text>
|
||||
<image class="indicateArrow" src="/static/gif/indicateArrow.gif"></image>
|
||||
</view>
|
||||
<view class="maskFristEntry-Close" @click="closeFristEntry"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -153,11 +161,13 @@ import { useScrollDirection } from '@/hook/useScrollDirection';
|
||||
import { useColumnCount } from '@/hook/useColumnCount';
|
||||
const { isScrollingDown, handleScroll } = useScrollDirection();
|
||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
const emits = defineEmits(['onShowTabbar']);
|
||||
|
||||
const waterfallsFlowRef = ref(null);
|
||||
const loadmoreRef = ref(null);
|
||||
const conditionSearch = ref({});
|
||||
const waterfallcolumn = ref(2);
|
||||
const maskFristEntry = ref(false);
|
||||
const state = reactive({
|
||||
tabIndex: 'all',
|
||||
});
|
||||
@@ -193,6 +203,12 @@ const isLoaded = ref(false);
|
||||
// { name: '创意总监', highlight: false },
|
||||
// ]);
|
||||
|
||||
onLoad(() => {
|
||||
// 判断浏览器是否有 fristEntry 第一次进入
|
||||
let fristEntry = uni.getStorageSync('fristEntry') || true; // 默认未读
|
||||
maskFristEntry.value = fristEntry;
|
||||
});
|
||||
|
||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
pageState.pageSize = 10 * (columnCount.value - 1);
|
||||
getJobRecommend('refresh');
|
||||
@@ -202,6 +218,11 @@ const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
});
|
||||
});
|
||||
|
||||
function closeFristEntry() {
|
||||
uni.setStorageSync('fristEntry', false);
|
||||
maskFristEntry.value = false;
|
||||
}
|
||||
|
||||
// onLoad(() => {
|
||||
// getJobRecommend('refresh');
|
||||
// });
|
||||
@@ -286,6 +307,7 @@ function nextDetail(job) {
|
||||
|
||||
function openFilter() {
|
||||
showFilter.value = true;
|
||||
emits('onShowTabbar', false);
|
||||
selectFilterModel.value?.open({
|
||||
title: '筛选',
|
||||
maskClick: true,
|
||||
@@ -301,6 +323,7 @@ function openFilter() {
|
||||
},
|
||||
cancel: () => {
|
||||
showFilter.value = false;
|
||||
emits('onShowTabbar', true);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -438,6 +461,51 @@ defineExpose({ loadData });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.maskFristEntry
|
||||
position: fixed;
|
||||
right: 20rpx;
|
||||
bottom: calc(50% - 200rpx);
|
||||
// background: rgba(0,0,0,0.3)
|
||||
.entry-content
|
||||
display: flex;
|
||||
align-items: center
|
||||
text
|
||||
font-size: 36rpx
|
||||
background: linear-gradient(273.34deg, #356CFA 3.58%, #A47FFD 85.84%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text; /* 有些浏览器兼容用 */
|
||||
text-fill-color: transparent;
|
||||
.indicateArrow
|
||||
height: 76rpx
|
||||
width: 68rpx
|
||||
.maskFristEntry-Close
|
||||
position: absolute;
|
||||
left: calc(50% - 10rpx);
|
||||
top: 86rpx
|
||||
width: 42rpx
|
||||
height: 42rpx
|
||||
background: linear-gradient(273.34deg, #356CFA 3.58%, #A47FFD 85.84%);
|
||||
border-radius: 50%;
|
||||
.maskFristEntry-Close::before
|
||||
position: absolute;
|
||||
left: calc( 50% - 2rpx)
|
||||
top: calc( 50% - 10rpx)
|
||||
transform: rotate(45deg);
|
||||
content: ''
|
||||
background: #FFFFFF
|
||||
width: 4rpx
|
||||
height: 20rpx
|
||||
.maskFristEntry-Close::after
|
||||
position: absolute;
|
||||
left: calc( 50% - 2rpx)
|
||||
top: calc( 50% - 10rpx)
|
||||
transform: rotate(-45deg);
|
||||
content: ''
|
||||
background: #FFFFFF
|
||||
width: 4rpx
|
||||
height: 20rpx
|
||||
|
||||
|
||||
.app-container
|
||||
width: 100%;
|
||||
|
@@ -29,16 +29,40 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="cards">
|
||||
<scroll-view :scroll-y="true" class="tab-scroll">
|
||||
<scroll-view :scroll-y="true" class="tab-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="scroll-content">
|
||||
<custom-waterfalls-flow ref="waterfallsFlowRef" :value="data.list">
|
||||
<template v-slot:default="item">
|
||||
<view class="item">
|
||||
<view class="title">{{ item.title }}</view>
|
||||
<view class="desc">{{ item.desc }}</view>
|
||||
<custom-waterfalls-flow
|
||||
ref="waterfallsFlowRef"
|
||||
:column="columnCount"
|
||||
:columnSpace="columnSpace"
|
||||
@loaded="imageloaded"
|
||||
:value="list"
|
||||
>
|
||||
<template v-slot:default="job">
|
||||
<view class="slot-item">
|
||||
<view class="job-image btn-feel" @click="nextVideo(job)">
|
||||
<image class="cover-image" :src="job.cover" mode="aspectFill"></image>
|
||||
<view class="cover-triangle"></view>
|
||||
</view>
|
||||
<view class="job-info" @click="nextDetail(job)">
|
||||
<view class="salary">
|
||||
<Salary-Expectation
|
||||
:max-salary="job.maxSalary"
|
||||
:min-salary="job.minSalary"
|
||||
:is-month="true"
|
||||
></Salary-Expectation>
|
||||
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
||||
</view>
|
||||
<view class="title">{{ job.jobTitle }}</view>
|
||||
<view class="desc">
|
||||
<!-- <uni-icons type="location" size="14"></uni-icons> -->
|
||||
<view class="descText">{{ job.companyName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</custom-waterfalls-flow>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -47,77 +71,100 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick } from 'vue';
|
||||
import { usePagination } from '@/hook/usePagination';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
import img from '@/static/icon/filter.png';
|
||||
import { useColumnCount } from '@/hook/useColumnCount';
|
||||
import { useRecommedIndexedDBStore, jobRecommender } from '@/stores/useRecommedIndexedDBStore.js';
|
||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
// status
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
const isLoaded = ref(false);
|
||||
const waterfallsFlowRef = ref(null);
|
||||
const loadmoreRef = ref(null);
|
||||
const state = reactive({
|
||||
tabIndex: 'all',
|
||||
});
|
||||
const data = reactive({
|
||||
list: [
|
||||
{
|
||||
image: 'https://via.placeholder.com/200x500.png/ff0000',
|
||||
title: '我是标题1',
|
||||
desc: '描述描述描述描述描述描述描述描述1',
|
||||
|
||||
// 响应式搜索条件(可以被修改)
|
||||
const searchParams = ref({});
|
||||
const pageSize = ref(10);
|
||||
const { list, loading, refresh, loadMore } = usePagination(
|
||||
(params) => $api.createRequest('/app/job/littleVideo', params),
|
||||
dataToImg, // 转换函数
|
||||
{
|
||||
pageSize: pageSize,
|
||||
search: searchParams,
|
||||
dataKey: 'data',
|
||||
onBeforeRequest: () => {
|
||||
loadmoreRef.value?.change('loading');
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/200x200.png/2878ff',
|
||||
title: '我是标题2',
|
||||
desc: '描述描述描述描述描述描述描述描述2',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/200x100.png/FFB6C1',
|
||||
title: '我是标题3',
|
||||
desc: '描述描述描述描述描述描述描述描述3',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/200x300.png/9400D3',
|
||||
title: '我是标题4',
|
||||
desc: '描述描述描述描述描述描述描述描述4',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/100x240.png/B0E0E6',
|
||||
title: '我是标题5',
|
||||
desc: '描述描述描述描述描述描述描述描述5',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/140x280.png/7FFFAA',
|
||||
title: '我是标题6',
|
||||
desc: '描述描述描述描述描述描述描述描述6',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/40x60.png/EEE8AA',
|
||||
title: '我是标题7',
|
||||
desc: '描述描述描述描述描述描述描述描述7',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/140x280.png/7FFFAA',
|
||||
title: '我是标题6',
|
||||
desc: '描述描述描述描述描述描述描述描述6',
|
||||
},
|
||||
{
|
||||
image: 'https://via.placeholder.com/40x60.png/EEE8AA',
|
||||
title: '我是标题7',
|
||||
desc: '描述描述描述描述描述描述描述描述7',
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
function imageloaded() {
|
||||
loadmoreRef.value?.change('more');
|
||||
}
|
||||
|
||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
pageSize.value = 10 * (columnCount.value - 1);
|
||||
nextTick(() => {
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
useLocationStore().getLocation();
|
||||
});
|
||||
});
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
isLoaded.value = true;
|
||||
refresh();
|
||||
} catch (err) {
|
||||
isLoaded.value = false; // 重置状态允许重试
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function choosePosition() {}
|
||||
async function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
if (index === 'all') {
|
||||
searchParams.value.jobTitle = '';
|
||||
} else {
|
||||
searchParams.value.jobTitle = userInfo.value.jobTitle[index];
|
||||
}
|
||||
console.log(searchParams.value);
|
||||
refresh('refresh');
|
||||
waterfallsFlowRef.value.refresh();
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
loadMore();
|
||||
}
|
||||
|
||||
function nextDetail(job) {
|
||||
// 记录岗位类型,用作数据分析
|
||||
if (job.jobCategory) {
|
||||
const recordData = recommedIndexDb.JobParameter(job);
|
||||
recommedIndexDb.addRecord(recordData);
|
||||
}
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`);
|
||||
}
|
||||
|
||||
function nextVideo(job) {
|
||||
uni.setStorageSync(`job-Info`, job);
|
||||
navTo(`/packageA/pages/tiktok/tiktok`);
|
||||
}
|
||||
|
||||
function dataToImg(data) {
|
||||
return data.map((item) => ({
|
||||
...item,
|
||||
// image: item.cover,
|
||||
image: img,
|
||||
hide: true,
|
||||
}));
|
||||
}
|
||||
|
||||
defineExpose({ loadData });
|
||||
</script>
|
||||
@@ -159,9 +206,10 @@ defineExpose({ loadData });
|
||||
.jobs-left
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
align-items: center
|
||||
.job
|
||||
font-weight: 400;
|
||||
font-size: 36rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666D7F;
|
||||
margin-right: 32rpx;
|
||||
white-space: nowrap
|
||||
@@ -174,9 +222,11 @@ defineExpose({ loadData });
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666D7F;
|
||||
line-height: 38rpx;
|
||||
.iconsearch
|
||||
margin-right: 6rpx
|
||||
.filter-bottom
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
@@ -202,4 +252,71 @@ defineExpose({ loadData });
|
||||
height: 26rpx;
|
||||
.active
|
||||
transform: rotate(180deg)
|
||||
|
||||
.slot-item
|
||||
background: #f4f4f4;
|
||||
// background: #f6f8fa;
|
||||
.job-image{
|
||||
width: 100%;
|
||||
height: 280rpx;
|
||||
position: relative;
|
||||
.cover-image{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.cover-triangle{
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 20rpx
|
||||
width: 36rpx
|
||||
height: 36rpx
|
||||
border-radius: 50%
|
||||
background: rgba(0,0,0,0.3)
|
||||
}
|
||||
.cover-triangle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-40%, -50%) rotate(90deg);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8rpx solid transparent;
|
||||
border-right: 8rpx solid transparent;
|
||||
border-bottom: 12rpx solid #fff;
|
||||
}
|
||||
}
|
||||
.job-info{
|
||||
padding: 10rpx 24rpx 24rpx 24rpx
|
||||
}
|
||||
.salary
|
||||
color: #4C6EFB;
|
||||
font-size: 28rpx
|
||||
display: flex
|
||||
align-items: flex-start
|
||||
justify-content: space-between
|
||||
.flame
|
||||
margin-top: 4rpx
|
||||
margin-right: 4rpx
|
||||
width: 24rpx
|
||||
height: 31rpx
|
||||
.title
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-top: 6rpx;
|
||||
white-space: pre-wrap
|
||||
.desc
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
margin-top: 6rpx;
|
||||
display: flex
|
||||
.descText{
|
||||
white-space: pre-wrap
|
||||
}
|
||||
</style>
|
||||
|
@@ -6,21 +6,35 @@
|
||||
<swiper class="swiper" :current="state.current" @change="changeSwiperType">
|
||||
<swiper-item class="swiper-item" v-for="(_, index) in 2" :key="index">
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<component
|
||||
:is="components[index]"
|
||||
@onShowTabbar="changeShowTabbar"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<IndexOne v-show="currentIndex === 0" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<IndexTwo v-show="currentIndex === 1" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<IndexOne
|
||||
v-show="currentIndex === 0"
|
||||
@onShowTabbar="changeShowTabbar"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
<IndexTwo
|
||||
v-show="currentIndex === 1"
|
||||
@onShowTabbar="changeShowTabbar"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
<!-- #endif -->
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<Tabbar v-show="showTabbar" :currentpage="0"></Tabbar>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import IndexOne from './components/index-one.vue';
|
||||
import IndexTwo from './components/index-two.vue';
|
||||
@@ -30,6 +44,7 @@ const components = [IndexOne, IndexTwo];
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
const { unreadCount } = storeToRefs(useReadMsg());
|
||||
const showTabbar = ref(true);
|
||||
|
||||
onShow(() => {
|
||||
// 获取消息列表
|
||||
@@ -49,6 +64,11 @@ const handelComponentsRef = (el, index) => {
|
||||
swiperRefs[index].value = el;
|
||||
}
|
||||
};
|
||||
|
||||
function changeShowTabbar(val) {
|
||||
showTabbar.value = val;
|
||||
}
|
||||
|
||||
// 查看消息类型
|
||||
function changeSwiperType(e) {
|
||||
const index = e.detail.current;
|
||||
|
@@ -96,12 +96,16 @@
|
||||
></uni-popup-dialog>
|
||||
</uni-popup>
|
||||
</view>
|
||||
<template #footer>
|
||||
<Tabbar :currentpage="4"></Tabbar>
|
||||
</template>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
@@ -170,7 +174,7 @@ function getUserstatistics() {
|
||||
width: auto;
|
||||
max-width: 60%;
|
||||
white-space: nowrap
|
||||
overflow:hidden;
|
||||
overflow:hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.top-btn{
|
||||
@@ -307,4 +311,4 @@ function getUserstatistics() {
|
||||
border-radius: 2rpx
|
||||
background: #A2A2A2;
|
||||
transform: rotate(45deg)
|
||||
</style>
|
||||
</style>
|
||||
|
@@ -27,6 +27,8 @@
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<Tabbar :currentpage="3"></Tabbar>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -34,6 +36,7 @@
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import ReadComponent from './read.vue';
|
||||
import UnreadComponent from './unread.vue';
|
||||
const loadedMap = reactive([false, false]);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<scroll-view scroll-y class="main-scroll">
|
||||
<view class="scrollmain">
|
||||
<view
|
||||
class="list-card btn-feel"
|
||||
class="list-card press-button"
|
||||
v-for="(item, index) in msgList"
|
||||
:key="index"
|
||||
@click="seeDetail(item, index)"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<scroll-view scroll-y class="main-scroll">
|
||||
<view class="scrollmain">
|
||||
<view
|
||||
class="list-card btn-feel"
|
||||
class="list-card press-button"
|
||||
v-for="(item, index) in unreadMsgList"
|
||||
:key="index"
|
||||
@click="seeDetail(item)"
|
||||
|
@@ -1,33 +1,70 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="top">
|
||||
<image class="btnback button-click" src="@/static/icon/back.png" @click="navBack"></image>
|
||||
<view class="search-box">
|
||||
<uni-icons
|
||||
class="iconsearch"
|
||||
color="#666666"
|
||||
type="search"
|
||||
size="18"
|
||||
@confirm="searchCollection"
|
||||
></uni-icons>
|
||||
<input
|
||||
class="inputed"
|
||||
type="text"
|
||||
focus
|
||||
v-model="searchValue"
|
||||
placeholder="搜索职位名称"
|
||||
placeholder-class="placeholder"
|
||||
@confirm="searchBtn"
|
||||
/>
|
||||
<view>
|
||||
<view class="top">
|
||||
<image class="btnback button-click" src="@/static/icon/back.png" @click="navBack"></image>
|
||||
<view class="search-box">
|
||||
<uni-icons
|
||||
class="iconsearch"
|
||||
color="#666666"
|
||||
type="search"
|
||||
size="18"
|
||||
@confirm="searchCollection"
|
||||
></uni-icons>
|
||||
<input
|
||||
class="inputed"
|
||||
type="text"
|
||||
focus
|
||||
v-model="searchValue"
|
||||
placeholder="搜索职位名称"
|
||||
placeholder-class="placeholder"
|
||||
@confirm="searchBtn"
|
||||
/>
|
||||
</view>
|
||||
<view class="search-btn button-click" @click="searchBtn">搜索</view>
|
||||
</view>
|
||||
<view class="view-top" v-show="listCom.length || list.length">
|
||||
<view class="top-item" @click="changeType(0)" :class="{ active: currentTab === 0 }">综合</view>
|
||||
<view class="top-item" @click="changeType(1)" :class="{ active: currentTab === 1 }">视频</view>
|
||||
</view>
|
||||
<view class="search-btn button-click" @click="searchBtn">搜索</view>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view" v-show="list.length" @scrolltolower="getJobList('add')">
|
||||
<view class="cards-box">
|
||||
<renderJobs :list="list" :longitude="longitudeVal" :latitude="latitudeVal"></renderJobs>
|
||||
<scroll-view scroll-y class="Detailscroll-view" v-show="listCom.length" @scrolltolower="choosePosition">
|
||||
<view class="cards-box" v-show="currentTab === 0">
|
||||
<renderJobs :list="listCom" :longitude="longitudeVal" :latitude="latitudeVal"></renderJobs>
|
||||
</view>
|
||||
<view class="cards-box" style="padding-top: 24rpx" v-show="currentTab === 1">
|
||||
<custom-waterfalls-flow
|
||||
ref="waterfallsFlowRef"
|
||||
:column="columnCount"
|
||||
:columnSpace="columnSpace"
|
||||
@loaded="imageloaded"
|
||||
:value="list"
|
||||
>
|
||||
<template v-slot:default="job">
|
||||
<view class="slot-item">
|
||||
<view class="job-image btn-feel" @click="nextVideo(job)">
|
||||
<image class="cover-image" :src="job.cover" mode="aspectFill"></image>
|
||||
<view class="cover-triangle"></view>
|
||||
</view>
|
||||
<view class="job-info" @click="nextDetail(job)">
|
||||
<view class="salary">
|
||||
<Salary-Expectation
|
||||
:max-salary="job.maxSalary"
|
||||
:min-salary="job.minSalary"
|
||||
:is-month="true"
|
||||
></Salary-Expectation>
|
||||
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
||||
</view>
|
||||
<view class="title">{{ job.jobTitle }}</view>
|
||||
<view class="desc">{{ job.companyName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</custom-waterfalls-flow>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="main-content" v-show="!list.length">
|
||||
<view class="main-content" v-show="!listCom.length">
|
||||
<view class="content-top">
|
||||
<view class="top-left">历史搜索</view>
|
||||
<view class="top-right button-click" @click="remove">
|
||||
@@ -44,16 +81,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { inject, ref, reactive, nextTick } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import SelectJobs from '@/components/selectJobs/selectJobs.vue';
|
||||
const { $api, navBack } = inject('globalFunction');
|
||||
const { $api, navBack, navTo } = inject('globalFunction');
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useColumnCount } from '@/hook/useColumnCount';
|
||||
import { usePagination } from '@/hook/usePagination';
|
||||
import img from '@/static/icon/filter.png';
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
const searchValue = ref('');
|
||||
const historyList = ref([]);
|
||||
const list = ref([]);
|
||||
const listCom = ref([]);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
@@ -63,6 +103,47 @@ const pageState = reactive({
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const isLoaded = ref(false);
|
||||
const waterfallsFlowRef = ref(null);
|
||||
const loadmoreRef = ref(null);
|
||||
const currentTab = ref(0);
|
||||
// 响应式搜索条件(可以被修改)
|
||||
const searchParams = ref({});
|
||||
const pageSize = ref(10);
|
||||
|
||||
const { list, loading, refresh, loadMore } = usePagination(
|
||||
(params) => $api.createRequest('/app/job/littleVideo', params),
|
||||
dataToImg, // 转换函数
|
||||
{
|
||||
pageSize: pageSize,
|
||||
search: searchParams,
|
||||
dataKey: 'data',
|
||||
autoWatchSearch: true,
|
||||
onBeforeRequest: () => {
|
||||
loadmoreRef.value?.change('loading');
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
async function choosePosition(index) {
|
||||
if (currentTab.value === 0) {
|
||||
getJobList('add');
|
||||
} else {
|
||||
loadMore();
|
||||
}
|
||||
}
|
||||
|
||||
function imageloaded() {
|
||||
loadmoreRef.value?.change('more');
|
||||
}
|
||||
|
||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
pageSize.value = 10 * (columnCount.value - 1);
|
||||
nextTick(() => {
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
useLocationStore().getLocation();
|
||||
});
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
let arr = uni.getStorageSync('searchList');
|
||||
@@ -71,6 +152,20 @@ onLoad(() => {
|
||||
}
|
||||
});
|
||||
|
||||
function changeType(type) {
|
||||
if (currentTab.value === type) return;
|
||||
switch (type) {
|
||||
case 0:
|
||||
currentTab.value = 0;
|
||||
getJobList('refresh');
|
||||
break;
|
||||
case 1:
|
||||
currentTab.value = 1;
|
||||
refresh();
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
break;
|
||||
}
|
||||
}
|
||||
function searchFn(item) {
|
||||
searchValue.value = item;
|
||||
searchBtn();
|
||||
@@ -83,7 +178,15 @@ function searchBtn() {
|
||||
historyList.value.unshift(searchValue.value);
|
||||
historyList.value = unique(historyList.value);
|
||||
uni.setStorageSync('searchList', historyList.value);
|
||||
getJobList('refresh');
|
||||
searchParams.value = {
|
||||
jobTitle: searchValue,
|
||||
};
|
||||
if (currentTab.value === 0) {
|
||||
getJobList('refresh');
|
||||
} else {
|
||||
refresh();
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
}
|
||||
}
|
||||
|
||||
function searchCollection(e) {
|
||||
@@ -112,12 +215,25 @@ function remove() {
|
||||
historyList.value = [];
|
||||
}
|
||||
|
||||
function nextDetail(job) {
|
||||
// 记录岗位类型,用作数据分析
|
||||
if (job.jobCategory) {
|
||||
const recordData = recommedIndexDb.JobParameter(job);
|
||||
recommedIndexDb.addRecord(recordData);
|
||||
}
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`);
|
||||
}
|
||||
|
||||
function nextVideo(job) {
|
||||
uni.setStorageSync(`job-Info`, job);
|
||||
navTo(`/packageA/pages/tiktok/tiktok`);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -132,11 +248,11 @@ function getJobList(type = 'add') {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const end = listCom.value.length;
|
||||
const reslist = rows;
|
||||
list.value.splice(str, end, ...reslist);
|
||||
listCom.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = rows;
|
||||
listCom.value = rows;
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
@@ -147,6 +263,15 @@ function getJobList(type = 'add') {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dataToImg(data) {
|
||||
return data.map((item) => ({
|
||||
...item,
|
||||
// image: item.cover,
|
||||
image: img,
|
||||
hide: true,
|
||||
}));
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@@ -156,12 +281,35 @@ function getJobList(type = 'add') {
|
||||
.Detailscroll-view{
|
||||
flex: 1
|
||||
overflow: hidden
|
||||
|
||||
}
|
||||
.container{
|
||||
display: flex
|
||||
flex-direction: column
|
||||
background: #F4f4f4
|
||||
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
.view-top{
|
||||
display: flex;
|
||||
justify-content: space-around
|
||||
background: #FFFFFF;
|
||||
.top-item{
|
||||
padding: 6rpx 0 18rpx 0
|
||||
}
|
||||
.active{
|
||||
color: #256BFA;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
}
|
||||
.active::after{
|
||||
position: absolute;
|
||||
content: ''
|
||||
left: calc(50% - 12rpx)
|
||||
bottom: 10rpx
|
||||
width: 24rpx
|
||||
height: 6rpx
|
||||
background: #256BFA
|
||||
}
|
||||
}
|
||||
.main-content{
|
||||
background: #FFFFFF
|
||||
height: 100%
|
||||
@@ -244,4 +392,67 @@ function getJobList(type = 'add') {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slot-item
|
||||
// background: #f4f4f4;
|
||||
background: #FFFFFF;
|
||||
.job-info{
|
||||
padding: 10rpx 24rpx 24rpx 24rpx
|
||||
}
|
||||
.job-image{
|
||||
width: 100%;
|
||||
height: 280rpx;
|
||||
position: relative;
|
||||
.cover-image{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.cover-triangle{
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 20rpx
|
||||
width: 36rpx
|
||||
height: 36rpx
|
||||
border-radius: 50%
|
||||
background: rgba(0,0,0,0.3)
|
||||
}
|
||||
.cover-triangle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-40%, -50%) rotate(90deg);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8rpx solid transparent;
|
||||
border-right: 8rpx solid transparent;
|
||||
border-bottom: 12rpx solid #fff;
|
||||
}
|
||||
}
|
||||
.salary
|
||||
color: #4C6EFB;
|
||||
font-size: 28rpx
|
||||
display: flex
|
||||
align-items: flex-start
|
||||
justify-content: space-between
|
||||
.flame
|
||||
margin-top: 4rpx
|
||||
margin-right: 4rpx
|
||||
width: 24rpx
|
||||
height: 31rpx
|
||||
.title
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-top: 6rpx;
|
||||
white-space: pre-wrap
|
||||
.desc
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
margin-top: 6rpx;
|
||||
</style>
|
||||
|
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
BIN
static/gif/.DS_Store
vendored
Normal file
BIN
static/gif/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
static/gif/indicateArrow.gif
Normal file
BIN
static/gif/indicateArrow.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
BIN
static/gif/logo.gif
Normal file
BIN
static/gif/logo.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
BIN
static/imgs/4501750561414_.pic.jpg
Normal file
BIN
static/imgs/4501750561414_.pic.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 248 KiB |
@@ -57,7 +57,7 @@ const useUserStore = defineStore("user", () => {
|
||||
hasLogin.value = true;
|
||||
userInfo.value = value;
|
||||
openId.value = value.wxOpenId;
|
||||
token.value = value.token
|
||||
token.value = value.token;
|
||||
uni.setStorage({
|
||||
key: 'token',
|
||||
data: value.token
|
||||
|
BIN
unpackage/dist/build/.DS_Store
vendored
BIN
unpackage/dist/build/.DS_Store
vendored
Binary file not shown.
Reference in New Issue
Block a user