Compare commits
44 Commits
1d6bf629ec
...
46e3659d98
| Author | SHA1 | Date | |
|---|---|---|---|
| 46e3659d98 | |||
| 361afe206c | |||
| 3160dad246 | |||
| 7ffab64a82 | |||
| 5a70129c70 | |||
| 45c59a2d36 | |||
| cc0d8a2f70 | |||
| b963268639 | |||
| dc96d856a2 | |||
| 9a6ad76000 | |||
| 99d932a453 | |||
| 1b1b5f7ac7 | |||
| c98f54ade6 | |||
| 2cc5d98763 | |||
| 438a6f3938 | |||
| 05fd135b3c | |||
| 25fb1fa2f1 | |||
| 9c22cc4444 | |||
| 4a1aa68245 | |||
|
|
95b9c1cc29 | ||
|
|
e048ba6b0b | ||
|
|
55cc52c046 | ||
|
|
c71ad5f98c | ||
|
|
476e44f400 | ||
|
|
d80baf6f0b | ||
|
|
5a31d56c9a | ||
|
|
12906b65ec | ||
|
|
2d6370b796 | ||
|
|
92ee5c5311 | ||
|
|
0b339ee061 | ||
|
|
4450aa21bc | ||
|
|
b72b7dd7d6 | ||
| 3e58a71658 | |||
| d605e940ee | |||
| e287209dcf | |||
|
|
20f2038f8c | ||
|
|
4f94090b42 | ||
|
|
8bb3c424e2 | ||
| 4d87af9c3c | |||
|
|
968e6b4091 | ||
|
|
d9c1f83693 | ||
|
|
ae91ded327 | ||
|
|
959e9ee9e4 | ||
|
|
14dafac147 |
7
App.vue
@@ -3,17 +3,20 @@ import { reactive, inject, onMounted } from 'vue';
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import useUserStore from './stores/useUserStore';
|
||||
import useDictStore from './stores/useDictStore';
|
||||
import { tabbarManager } from './utils/tabbarManager';
|
||||
const { $api, navTo, appendScriptTagElement } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
|
||||
onLaunch((options) => {
|
||||
useUserStore().initSeesionId(); //更新
|
||||
useDictStore().getDictData();
|
||||
// uni.hideTabBar();
|
||||
|
||||
// 尝试从缓存恢复用户信息
|
||||
// 先尝试从缓存恢复用户信息
|
||||
const restored = useUserStore().restoreUserInfo();
|
||||
|
||||
// 用户信息恢复后再初始化自定义tabbar
|
||||
tabbarManager.initTabBar();
|
||||
|
||||
if (restored) {
|
||||
// 如果成功恢复用户信息,验证token是否有效
|
||||
let token = uni.getStorageSync('token') || '';
|
||||
|
||||
@@ -2,7 +2,8 @@ import useUserStore from "../stores/useUserStore";
|
||||
import {
|
||||
request,
|
||||
createRequest,
|
||||
uploadFile
|
||||
uploadFile,
|
||||
myRequest
|
||||
} from "../utils/request";
|
||||
import streamRequest, {
|
||||
chatRequest
|
||||
@@ -885,7 +886,8 @@ export const $api = {
|
||||
uploadFile,
|
||||
formatFileSize,
|
||||
sendingMiniProgramMessage,
|
||||
copyText
|
||||
copyText,
|
||||
myRequest
|
||||
}
|
||||
|
||||
|
||||
@@ -916,4 +918,4 @@ export default {
|
||||
insertSortData,
|
||||
isInWechatMiniProgramWebview,
|
||||
isEmptyObject,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
>
|
||||
<!-- 顶部头部区域 -->
|
||||
<view
|
||||
v-if="title"
|
||||
class="container-header"
|
||||
:style="border ? { borderBottom: `2rpx solid ${borderColor}` } : { borderBottom: 'none' }"
|
||||
>
|
||||
@@ -49,7 +50,7 @@ const emit = defineEmits(['onScrollBottom']);
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '标题',
|
||||
default: '',
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
|
||||
337
components/CustomTabBar/CustomTabBar.vue
Normal file
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<view class="custom-tabbar">
|
||||
<view
|
||||
class="tabbar-item"
|
||||
v-for="(item, index) in tabbarList"
|
||||
:key="index"
|
||||
@click="switchTab(item, index)"
|
||||
>
|
||||
<view class="tabbar-icon">
|
||||
<image
|
||||
:src="currentItem === item.id ? item.selectedIconPath : item.iconPath"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
<view class="badge" v-if="item.badge && item.badge > 0">{{ item.badge }}</view>
|
||||
<view class="tabbar-text" :class="{ 'active': currentItem === item.id }">
|
||||
{{ item.text }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
|
||||
const props = defineProps({
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userInfo } = storeToRefs(userStore);
|
||||
const readMsg = useReadMsg();
|
||||
const currentItem = ref(props.currentPage);
|
||||
|
||||
// 监听props变化
|
||||
watch(() => props.currentPage, (newPage) => {
|
||||
currentItem.value = newPage;
|
||||
});
|
||||
|
||||
// 生成tabbar配置的函数
|
||||
const generateTabbarList = () => {
|
||||
const baseItems = [
|
||||
{
|
||||
id: 0,
|
||||
text: '职位',
|
||||
path: '/pages/index/index',
|
||||
iconPath: '/static/tabbar/calendar.png',
|
||||
selectedIconPath: '/static/tabbar/calendared.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[0]?.count || 0,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
text: 'AI+',
|
||||
path: '/pages/chat/chat',
|
||||
iconPath: '/static/tabbar/logo3.png',
|
||||
selectedIconPath: '/static/tabbar/logo3.png',
|
||||
centerItem: true,
|
||||
badge: readMsg.badges[2]?.count || 0,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
text: '消息',
|
||||
path: '/pages/msglog/msglog',
|
||||
iconPath: '/static/tabbar/chat4.png',
|
||||
selectedIconPath: '/static/tabbar/chat4ed.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[3]?.count || 0,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
text: '我的',
|
||||
path: '/pages/mine/mine',
|
||||
iconPath: '/static/tabbar/mine.png',
|
||||
selectedIconPath: '/static/tabbar/mined.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[4]?.count || 0,
|
||||
},
|
||||
];
|
||||
|
||||
// 获取用户类型,统一使用isCompanyUser字段(0=企业用户,1=求职者, 3=网格员)
|
||||
// 优先从store获取,如果为空则直接从缓存获取
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
|
||||
// 获取isCompanyUser字段
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
|
||||
|
||||
// 获取用户类型的逻辑:
|
||||
// 1. 优先使用store中的isCompanyUser
|
||||
// 2. 如果store中没有,使用缓存中的isCompanyUser
|
||||
// 3. 最后默认为1(求职者)
|
||||
const userType = Number(storeIsCompanyUser !== undefined ? storeIsCompanyUser : (cachedIsCompanyUser !== undefined ? cachedIsCompanyUser : 1));
|
||||
if (userType === 0 || userType === 2) {
|
||||
// 企业用户:显示发布岗位
|
||||
baseItems.splice(1, 0, {
|
||||
id: 1,
|
||||
text: '发布岗位',
|
||||
path: '/pages/job/publishJob',
|
||||
iconPath: '/static/tabbar/post.png',
|
||||
selectedIconPath: '/static/tabbar/posted.png',
|
||||
centerItem: false,
|
||||
badge: 0,
|
||||
});
|
||||
} else {
|
||||
// 求职者用户(包括未登录状态):显示招聘会
|
||||
baseItems.splice(1, 0, {
|
||||
id: 1,
|
||||
text: '招聘会',
|
||||
path: '/pages/careerfair/careerfair',
|
||||
iconPath: '/static/tabbar/post.png',
|
||||
selectedIconPath: '/static/tabbar/posted.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[1]?.count || 0,
|
||||
});
|
||||
}
|
||||
|
||||
return baseItems;
|
||||
};
|
||||
|
||||
// 根据用户类型生成不同的导航栏配置
|
||||
const tabbarList = computed(() => {
|
||||
return generateTabbarList();
|
||||
});
|
||||
|
||||
// 强制刷新tabbar的方法
|
||||
const forceRefresh = () => {
|
||||
// 触发响应式更新
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const currentUserType = userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : (cachedUserInfo.isCompanyUser !== undefined ? cachedUserInfo.isCompanyUser : 1);
|
||||
};
|
||||
|
||||
// 监听用户类型变化(只监听isCompanyUser字段)
|
||||
watch(() => userInfo.value?.isCompanyUser, (newIsCompanyUser, oldIsCompanyUser) => {
|
||||
if (newIsCompanyUser !== oldIsCompanyUser) {
|
||||
// 强制触发computed重新计算
|
||||
forceRefresh();
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 监听用户信息变化(包括登录状态)
|
||||
watch(() => userInfo.value, (newUserInfo, oldUserInfo) => {
|
||||
if (newUserInfo !== oldUserInfo) {
|
||||
// 强制触发computed重新计算
|
||||
forceRefresh();
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 切换tab
|
||||
const switchTab = (item, index) => {
|
||||
// 检查是否为"发布岗位"页面,需要判断企业信息是否完整
|
||||
if (item.path === '/pages/job/publishJob') {
|
||||
// 检查用户是否已登录
|
||||
const token = uni.getStorageSync('token') || '';
|
||||
const hasLogin = userStore.hasLogin;
|
||||
|
||||
if (!token || !hasLogin) {
|
||||
// 未登录,发送事件显示登录弹窗
|
||||
uni.$emit('showLoginModal');
|
||||
return; // 不进行页面跳转
|
||||
}
|
||||
|
||||
// 已登录,检查企业信息是否完整
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const storeUserInfo = userInfo.value || {};
|
||||
const currentUserInfo = storeUserInfo.id ? storeUserInfo : cachedUserInfo;
|
||||
|
||||
// 判断企业信息字段company是否为null或undefined
|
||||
if (!currentUserInfo.company || currentUserInfo.company === null) {
|
||||
// 企业信息为空,跳转到企业信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/company-info',
|
||||
});
|
||||
} else {
|
||||
// 企业信息完整,跳转到发布岗位页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/job/publishJob',
|
||||
});
|
||||
}
|
||||
|
||||
currentItem.value = item.id;
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否为"我的"页面,需要登录验证和用户类型判断
|
||||
if (item.path === '/pages/mine/mine') {
|
||||
// 检查用户是否已登录
|
||||
const token = uni.getStorageSync('token') || '';
|
||||
const hasLogin = userStore.hasLogin;
|
||||
|
||||
if (!token || !hasLogin) {
|
||||
// 未登录,发送事件显示登录弹窗
|
||||
uni.$emit('showLoginModal');
|
||||
return; // 不进行页面跳转
|
||||
}
|
||||
|
||||
// 已登录,根据用户类型跳转到不同的"我的"页面
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
|
||||
|
||||
// 获取用户类型
|
||||
const userType = Number(storeIsCompanyUser !== undefined ? storeIsCompanyUser : (cachedIsCompanyUser !== undefined ? cachedIsCompanyUser : 1));
|
||||
|
||||
let targetPath = '/pages/mine/mine'; // 默认求职者页面
|
||||
|
||||
if (userType === 0) {
|
||||
// 企业用户,跳转到企业我的页面
|
||||
targetPath = '/pages/mine/company-mine';
|
||||
} else {
|
||||
// 求职者或其他用户类型,跳转到普通我的页面
|
||||
targetPath = '/pages/mine/mine';
|
||||
}
|
||||
|
||||
// 跳转到对应的页面
|
||||
uni.navigateTo({
|
||||
url: targetPath,
|
||||
});
|
||||
|
||||
currentItem.value = item.id;
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否为 tabBar 页面
|
||||
const tabBarPages = [
|
||||
'/pages/index/index',
|
||||
'/pages/careerfair/careerfair',
|
||||
'/pages/chat/chat',
|
||||
'/pages/msglog/msglog',
|
||||
'/pages/mine/mine'
|
||||
];
|
||||
|
||||
if (tabBarPages.includes(item.path)) {
|
||||
// TabBar 页面使用 redirectTo 避免页面栈溢出
|
||||
uni.redirectTo({
|
||||
url: item.path,
|
||||
});
|
||||
} else {
|
||||
// 非 TabBar 页面使用 navigateTo
|
||||
uni.navigateTo({
|
||||
url: item.path,
|
||||
});
|
||||
}
|
||||
|
||||
currentItem.value = item.id;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
currentItem.value = props.currentPage;
|
||||
// 调试信息:显示当前用户状态和tabbar配置
|
||||
forceRefresh();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-tabbar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 88rpx;
|
||||
background-color: #ffffff;
|
||||
border-top: 1rpx solid #e5e5e5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
z-index: 999;
|
||||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.tabbar-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #5E5F60;
|
||||
font-size: 22rpx;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tabbar-icon {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
margin-bottom: 4rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabbar-icon image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tabbar-text {
|
||||
font-size: 20rpx;
|
||||
line-height: 1;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.tabbar-text.active {
|
||||
color: #256BFA;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: 4rpx;
|
||||
right: 20rpx;
|
||||
min-width: 30rpx;
|
||||
height: 30rpx;
|
||||
background-color: #ff4444;
|
||||
color: #fff;
|
||||
font-size: 18rpx;
|
||||
border-radius: 15rpx;
|
||||
text-align: center;
|
||||
line-height: 30rpx;
|
||||
padding: 0 10rpx;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
/* 中间按钮特殊样式 */
|
||||
.tabbar-item:has(.center-item) {
|
||||
.tabbar-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -31,13 +31,13 @@ const userTypes = [
|
||||
{ value: 3, label: '政府人员' }
|
||||
];
|
||||
|
||||
const currentUserType = computed(() => userInfo.value?.userType || 0);
|
||||
const currentUserType = computed(() => userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : 0);
|
||||
|
||||
const switchUserType = (userType) => {
|
||||
console.log('切换用户类型:', userType);
|
||||
console.log('切换前 userInfo:', userInfo.value);
|
||||
|
||||
userInfo.value.userType = userType;
|
||||
userInfo.value.isCompanyUser = userType;
|
||||
|
||||
console.log('切换后 userInfo:', userInfo.value);
|
||||
|
||||
|
||||
@@ -13,7 +13,30 @@
|
||||
<view class="btn-confirm" @click="confirm">确认</view>
|
||||
</view>
|
||||
<view class="popup-list">
|
||||
<!-- 多选模式 -->
|
||||
<view v-if="multiSelect" class="multi-select-list">
|
||||
<view v-if="!processedListData[0] || processedListData[0].length === 0" class="empty-tip">
|
||||
暂无数据
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="skill-tags-container"
|
||||
>
|
||||
<view
|
||||
v-for="(item, index) in processedListData[0]"
|
||||
:key="index"
|
||||
class="skill-tag"
|
||||
:class="{ 'skill-tag-active': selectedValues.includes(item[this.rowKey]) }"
|
||||
@click.stop="toggleSelect(item)"
|
||||
@touchstart.stop="toggleSelect(item)"
|
||||
>
|
||||
<text class="skill-tag-text">{{ getLabel(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 单选模式 -->
|
||||
<picker-view
|
||||
v-else
|
||||
indicator-style="height: 84rpx;"
|
||||
:value="selectedIndex"
|
||||
@change="bindChange"
|
||||
@@ -54,6 +77,8 @@ export default {
|
||||
rowKey: 'value',
|
||||
selectedItems: [],
|
||||
unit: '',
|
||||
multiSelect: false,
|
||||
selectedValues: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -66,6 +91,13 @@ export default {
|
||||
});
|
||||
});
|
||||
},
|
||||
// 计算选中的项目
|
||||
computedSelectedItems() {
|
||||
if (!this.multiSelect) return this.selectedItems;
|
||||
return this.processedListData[0] ? this.processedListData[0].filter(item =>
|
||||
this.selectedValues.includes(item[this.rowKey])
|
||||
) : [];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open(newConfig = {}) {
|
||||
@@ -80,7 +112,10 @@ export default {
|
||||
rowKey = 'value',
|
||||
maskClick = false,
|
||||
defaultIndex = [],
|
||||
multiSelect = false,
|
||||
defaultValues = [],
|
||||
} = newConfig;
|
||||
|
||||
this.reset();
|
||||
if (title) this.title = title;
|
||||
if (typeof success === 'function') this.confirmCallback = success;
|
||||
@@ -92,10 +127,16 @@ export default {
|
||||
this.rowKey = rowKey;
|
||||
this.maskClick = maskClick;
|
||||
this.unit = unit;
|
||||
this.multiSelect = multiSelect;
|
||||
|
||||
this.selectedIndex =
|
||||
defaultIndex.length === this.listData.length ? defaultIndex : new Array(this.listData.length).fill(0);
|
||||
this.selectedItems = this.selectedIndex.map((val, index) => this.processedListData[index][val]);
|
||||
if (multiSelect) {
|
||||
this.selectedValues = defaultValues || [];
|
||||
} else {
|
||||
this.selectedIndex =
|
||||
defaultIndex.length === this.listData.length ? defaultIndex : new Array(this.listData.length).fill(0);
|
||||
this.selectedItems = this.selectedIndex.map((val, index) => this.processedListData[index][val]);
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.popup.open();
|
||||
});
|
||||
@@ -117,6 +158,22 @@ export default {
|
||||
getLabel(item) {
|
||||
return item?.[this.rowLabel] ?? '';
|
||||
},
|
||||
toggleSelect(item) {
|
||||
if (!item || !this.rowKey || !item[this.rowKey]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = item[this.rowKey];
|
||||
const index = this.selectedValues.indexOf(value);
|
||||
|
||||
if (index > -1) {
|
||||
// 取消选中
|
||||
this.selectedValues.splice(index, 1);
|
||||
} else {
|
||||
// 选中
|
||||
this.selectedValues.push(value);
|
||||
}
|
||||
},
|
||||
setColunm(index, list) {
|
||||
if (index > this.listData.length) {
|
||||
return console.warn('最长' + this.listData.length);
|
||||
@@ -135,7 +192,14 @@ export default {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await callback(this.selectedIndex, this.selectedItems); // 无论是 async 还是返回 Promise 的函数都可以 await
|
||||
let result;
|
||||
if (this.multiSelect) {
|
||||
// 多选模式:传递 selectedValues 和 selectedItems
|
||||
result = await callback(this.selectedValues, this.computedSelectedItems);
|
||||
} else {
|
||||
// 单选模式:传递 selectedIndex 和 selectedItems
|
||||
result = await callback(this.selectedIndex, this.selectedItems);
|
||||
}
|
||||
if (result !== false) {
|
||||
this.$refs.popup.close();
|
||||
}
|
||||
@@ -154,6 +218,8 @@ export default {
|
||||
this.rowKey = 'value';
|
||||
this.selectedItems = [];
|
||||
this.unit = '';
|
||||
this.multiSelect = false;
|
||||
this.selectedValues = [];
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -224,10 +290,83 @@ export default {
|
||||
color: #666d7f;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
.btn-confirm {
|
||||
.btn-confirm {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #256bfa;
|
||||
}
|
||||
}
|
||||
|
||||
.multi-select-list {
|
||||
padding: 20rpx 30rpx;
|
||||
max-height: calc(60vh - 120rpx);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 60rpx 0;
|
||||
color: #999999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.skill-tags-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.skill-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 2rpx solid #e8eaee;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background-color: #e9ecef;
|
||||
border-color: #d0d0d0;
|
||||
transform: translateY(-1rpx);
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
background-color: #dee2e6;
|
||||
}
|
||||
|
||||
.skill-tag-text {
|
||||
font-size: 24rpx;
|
||||
color: inherit;
|
||||
line-height: 1.2;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #256bfa;
|
||||
}
|
||||
|
||||
&.skill-tag-active {
|
||||
background-color: #256bfa;
|
||||
border-color: #256bfa;
|
||||
color: #ffffff;
|
||||
box-shadow: 0 2rpx 8rpx rgba(37, 107, 250, 0.3);
|
||||
|
||||
.skill-tag-text {
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #1e5ce6;
|
||||
border-color: #1e5ce6;
|
||||
transform: translateY(-1rpx);
|
||||
box-shadow: 0 4rpx 12rpx rgba(37, 107, 250, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
>
|
||||
<image :src="currentItem == item.id ? item.selectedIconPath : item.iconPath"></image>
|
||||
</view>
|
||||
<view class="badge" v-if="item.badge">{{ item.badge }}</view>
|
||||
<view class="badge" v-if="item.badge && item.badge > 0">{{ item.badge }}</view>
|
||||
<view class="item-bottom" :class="[currentItem == item.id ? 'item-active' : '']">
|
||||
<text>{{ item.text }}</text>
|
||||
</view>
|
||||
@@ -19,7 +19,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { ref, onMounted, computed, watch, nextTick } from 'vue';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
@@ -36,35 +36,60 @@ const readMsg = useReadMsg();
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
const currentItem = ref(0);
|
||||
|
||||
// 根据用户类型生成不同的导航栏配置
|
||||
const tabbarList = computed(() => {
|
||||
// 监听用户类型变化,重新生成tabbar配置
|
||||
watch(() => userInfo.value?.isCompanyUser, (newIsCompanyUser, oldIsCompanyUser) => {
|
||||
console.log('midell-box用户类型变化监听:', { newIsCompanyUser, oldIsCompanyUser, userInfo: userInfo.value });
|
||||
if (newIsCompanyUser !== oldIsCompanyUser) {
|
||||
console.log('用户类型发生变化,重新生成tabbar:', newIsCompanyUser);
|
||||
// tabbarList是computed,会自动重新计算
|
||||
// 强制触发响应式更新
|
||||
nextTick(() => {
|
||||
console.log('tabbar配置已更新:', tabbarList.value);
|
||||
});
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 监听用户信息变化(包括登录状态)
|
||||
watch(() => userInfo.value, (newUserInfo, oldUserInfo) => {
|
||||
console.log('midell-box用户信息变化监听:', { newUserInfo, oldUserInfo });
|
||||
if (newUserInfo !== oldUserInfo) {
|
||||
console.log('用户信息发生变化,重新生成tabbar');
|
||||
// 强制触发响应式更新
|
||||
nextTick(() => {
|
||||
console.log('tabbar配置已更新:', tabbarList.value);
|
||||
});
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 生成tabbar配置的函数
|
||||
const generateTabbarList = () => {
|
||||
const baseItems = [
|
||||
{
|
||||
id: 0,
|
||||
text: '首页',
|
||||
text: '职位2',
|
||||
path: '/pages/index/index',
|
||||
iconPath: '../../static/tabbar/calendar.png',
|
||||
selectedIconPath: '../../static/tabbar/calendared.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[0].count,
|
||||
badge: readMsg.badges[0]?.count || 0,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
text: '',
|
||||
text: 'AI+',
|
||||
path: '/pages/chat/chat',
|
||||
iconPath: '../../static/tabbar/logo3.png',
|
||||
selectedIconPath: '../../static/tabbar/logo3.png',
|
||||
centerItem: true,
|
||||
badge: readMsg.badges[2].count,
|
||||
badge: readMsg.badges[2]?.count || 0,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
text: '消息',
|
||||
text: '消息2',
|
||||
path: '/pages/msglog/msglog',
|
||||
iconPath: '../../static/tabbar/chat4.png',
|
||||
selectedIconPath: '../../static/tabbar/chat4ed.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[3].count,
|
||||
badge: readMsg.badges[3]?.count || 0,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
@@ -73,12 +98,12 @@ const tabbarList = computed(() => {
|
||||
iconPath: '../../static/tabbar/mine.png',
|
||||
selectedIconPath: '../../static/tabbar/mined.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[4].count,
|
||||
badge: readMsg.badges[4]?.count || 0,
|
||||
},
|
||||
];
|
||||
|
||||
// 根据用户类型添加不同的导航项
|
||||
const userType = userInfo.value?.userType || 0;
|
||||
// 根据用户类型添加不同的导航项,未登录时默认为求职者
|
||||
const userType = userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : 1;
|
||||
|
||||
if (userType === 0) {
|
||||
// 企业用户:显示发布岗位,隐藏招聘会
|
||||
@@ -86,13 +111,13 @@ const tabbarList = computed(() => {
|
||||
id: 1,
|
||||
text: '发布岗位',
|
||||
path: '/pages/job/publishJob',
|
||||
iconPath: '../../static/tabbar/publish-job.svg',
|
||||
selectedIconPath: '../../static/tabbar/publish-job-selected.svg',
|
||||
iconPath: '../../static/tabbar/post.png',
|
||||
selectedIconPath: '../../static/tabbar/posted.png',
|
||||
centerItem: false,
|
||||
badge: 0,
|
||||
});
|
||||
} else {
|
||||
// 普通用户、网格员、政府人员:显示招聘会
|
||||
// 求职者用户(包括未登录状态):显示招聘会
|
||||
baseItems.splice(1, 0, {
|
||||
id: 1,
|
||||
text: '招聘会',
|
||||
@@ -100,11 +125,16 @@ const tabbarList = computed(() => {
|
||||
iconPath: '../../static/tabbar/post.png',
|
||||
selectedIconPath: '../../static/tabbar/posted.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[1].count,
|
||||
badge: readMsg.badges[1]?.count || 0,
|
||||
});
|
||||
}
|
||||
|
||||
return baseItems;
|
||||
};
|
||||
|
||||
// 根据用户类型生成不同的导航栏配置
|
||||
const tabbarList = computed(() => {
|
||||
return generateTabbarList();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
@@ -114,7 +144,7 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
const changeItem = (item) => {
|
||||
// 判断是否为 tabBar 页面
|
||||
// 判断是否为 TabBar 页面
|
||||
const tabBarPages = [
|
||||
'/pages/index/index',
|
||||
'/pages/careerfair/careerfair',
|
||||
@@ -124,12 +154,12 @@ const changeItem = (item) => {
|
||||
];
|
||||
|
||||
if (tabBarPages.includes(item.path)) {
|
||||
// tabBar 页面使用 switchTab
|
||||
uni.switchTab({
|
||||
// TabBar 页面使用 redirectTo 避免页面栈溢出
|
||||
uni.redirectTo({
|
||||
url: item.path,
|
||||
});
|
||||
} else {
|
||||
// 非 tabBar 页面使用 navigateTo
|
||||
// 非 TabBar 页面使用 navigateTo
|
||||
uni.navigateTo({
|
||||
url: item.path,
|
||||
});
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
<script setup>
|
||||
import { ref, inject } from 'vue';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { tabbarManager } from '@/utils/tabbarManager';
|
||||
|
||||
const { $api } = inject('globalFunction');
|
||||
const { loginSetToken } = useUserStore();
|
||||
@@ -162,22 +163,33 @@ const getPhoneNumber = (e) => {
|
||||
userType: userType.value
|
||||
}, 'post').then((resData) => {
|
||||
uni.hideLoading();
|
||||
|
||||
console.log(resData, 'resume.idCard');
|
||||
if (resData.token) {
|
||||
// 登录成功,存储token
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
// 更新用户类型到缓存
|
||||
if (resData.isCompanyUser !== undefined) {
|
||||
console.log(resData.isCompanyUser, 'resData.isCompanyUser');
|
||||
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||
userInfo.isCompanyUser = Number(resData.isCompanyUser); // 0-企业用户,1-求职者
|
||||
uni.setStorageSync('userInfo', userInfo);
|
||||
}
|
||||
|
||||
$api.msg('登录成功');
|
||||
// 刷新tabbar以显示正确的用户类型
|
||||
tabbarManager.refreshTabBar();
|
||||
close();
|
||||
emit('success');
|
||||
|
||||
// 根据用户类型跳转到不同的信息补全页面
|
||||
if (!resume.data.jobTitleId) {
|
||||
if (userType.value === 1) {
|
||||
if (!resume.jobTitleId) {
|
||||
console.log(resume, 'resume.idCard');
|
||||
if (userType.value === 1 && !resData.idCard) {
|
||||
// 求职者跳转到个人信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/complete-info?step=1'
|
||||
});
|
||||
} else if (userType.value === 0) {
|
||||
} else if (userType.value === 0 && !resData.idCard) {
|
||||
// 招聘者跳转到企业信息补全页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/complete-info/company-info'
|
||||
@@ -233,6 +245,15 @@ const wxLogin = () => {
|
||||
|
||||
if (resData.token) {
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
console.log(resData, 'resData.isCompanyUser');
|
||||
// 更新用户类型到缓存
|
||||
if (resData.isCompanyUser) {
|
||||
console.log(resData.isCompanyUser, 'resData.isCompanyUser');
|
||||
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||
userInfo.isCompanyUser = Number(resData.isCompanyUser); // 0-企业用户,1-求职者
|
||||
uni.setStorageSync('userInfo', userInfo);
|
||||
}
|
||||
|
||||
$api.msg('登录成功');
|
||||
close();
|
||||
emit('success');
|
||||
@@ -285,7 +306,16 @@ const wxLogin = () => {
|
||||
}, 'post').then((resData) => {
|
||||
if (resData.token) {
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
// 更新用户类型到缓存
|
||||
if (resData.isCompanyUser !== undefined) {
|
||||
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||
userInfo.isCompanyUser = resData.isCompanyUser ? 0 : 1; // 0-企业用户,1-求职者
|
||||
uni.setStorageSync('userInfo', userInfo);
|
||||
}
|
||||
|
||||
$api.msg('登录成功');
|
||||
// 刷新tabbar以显示正确的用户类型
|
||||
tabbarManager.refreshTabBar();
|
||||
close();
|
||||
emit('success');
|
||||
|
||||
@@ -330,7 +360,16 @@ const testLogin = () => {
|
||||
uni.hideLoading();
|
||||
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
// 更新用户类型到缓存
|
||||
if (resData.isCompanyUser !== undefined) {
|
||||
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||
userInfo.isCompanyUser = resData.isCompanyUser ? 0 : 1; // 0-企业用户,1-求职者
|
||||
uni.setStorageSync('userInfo', userInfo);
|
||||
}
|
||||
|
||||
$api.msg('测试登录成功');
|
||||
// 刷新tabbar以显示正确的用户类型
|
||||
tabbarManager.refreshTabBar();
|
||||
close();
|
||||
emit('success');
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
export default {
|
||||
// baseUrl: 'http://39.98.44.136:8080', // 测试
|
||||
baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // 测试
|
||||
|
||||
LCBaseUrl:'http://10.110.145.145:9100',//招聘、培训、帮扶
|
||||
LCBaseUrlInner:'http://10.110.145.145:10100',//内网端口
|
||||
// sseAI+
|
||||
// StreamBaseURl: 'http://39.98.44.136:8000',
|
||||
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
|
||||
@@ -70,4 +73,4 @@ export default {
|
||||
desc: '融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!',
|
||||
imgUrl: 'https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
117
docs/企业我的页面功能说明.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# 企业我的页面功能说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
本功能为企业用户提供了专门的"我的"页面和企业信息展示页面,实现了根据用户类型显示不同内容的功能。
|
||||
|
||||
## 页面结构
|
||||
|
||||
### 1. 企业我的页面 (`pages/mine/company-mine.vue`)
|
||||
- **功能**: 企业用户的个人中心页面
|
||||
- **特点**:
|
||||
- 显示企业头像、名称和信息完整度
|
||||
- 包含服务专区(实名认证、通知与提醒)
|
||||
- 提供退出登录功能
|
||||
- 点击头像区域可跳转到企业信息页面
|
||||
|
||||
### 2. 企业信息展示页面 (`pages/mine/company-info.vue`)
|
||||
- **功能**: 显示详细的企业信息
|
||||
- **特点**:
|
||||
- 显示企业头像编辑功能
|
||||
- 展示完整的企业信息(名称、统一社会代码、注册地点等)
|
||||
- 支持编辑各项企业信息
|
||||
- 包含企业联系人和法人信息
|
||||
|
||||
### 3. 修改后的我的页面 (`pages/mine/mine.vue`)
|
||||
- **功能**: 根据用户类型显示不同的内容
|
||||
- **特点**:
|
||||
- 企业用户显示企业信息卡片
|
||||
- 求职者用户显示个人简历信息
|
||||
- 自动根据 `userInfo.isCompanyUser` 字段判断用户类型
|
||||
|
||||
## 用户类型判断
|
||||
|
||||
系统通过 `userInfo.isCompanyUser` 字段来判断用户类型:
|
||||
- `0` = 企业用户
|
||||
- `1` = 求职者
|
||||
- `2` = 网格员
|
||||
- `3` = 政府人员
|
||||
|
||||
## 页面跳转逻辑
|
||||
|
||||
### 从我的页面跳转
|
||||
- **企业用户**: 点击头像区域 → 跳转到企业信息页面 (`/pages/mine/company-info`)
|
||||
- **求职者用户**: 点击头像区域 → 跳转到简历页面 (`/packageA/pages/myResume/myResume`)
|
||||
|
||||
### 企业信息页面功能
|
||||
- 点击头像 → 编辑头像(调用相册选择图片)
|
||||
- 点击各项信息 → 跳转到对应的编辑页面(需要后续开发)
|
||||
|
||||
## 路由配置
|
||||
|
||||
新增的路由配置:
|
||||
```json
|
||||
{
|
||||
"path": "pages/mine/company-mine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/company-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "企业信息",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 测试页面
|
||||
|
||||
创建了测试页面 `pages/test/company-mine-test.vue` 用于测试功能:
|
||||
- 用户类型切换测试
|
||||
- 页面跳转测试
|
||||
- 用户信息显示
|
||||
|
||||
## 样式特点
|
||||
|
||||
### 企业信息卡片
|
||||
- 白色背景,圆角设计
|
||||
- 阴影效果,现代化UI
|
||||
- 头像圆形显示
|
||||
- 信息完整度显示
|
||||
|
||||
### 企业信息页面
|
||||
- 清晰的信息层级
|
||||
- 可点击的编辑区域
|
||||
- 统一的视觉风格
|
||||
|
||||
## 数据流
|
||||
|
||||
1. 用户登录时设置 `userInfo.isCompanyUser` 字段
|
||||
2. 我的页面根据此字段判断显示内容
|
||||
3. 企业用户点击头像跳转到企业信息页面
|
||||
4. 企业信息页面展示详细的企业数据
|
||||
|
||||
## 后续开发建议
|
||||
|
||||
1. **编辑功能**: 为每个信息项创建对应的编辑页面
|
||||
2. **数据接口**: 连接真实的企业信息API
|
||||
3. **头像上传**: 完善头像上传功能
|
||||
4. **表单验证**: 添加企业信息编辑的表单验证
|
||||
5. **权限控制**: 根据用户权限控制可编辑的字段
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 在测试页面切换用户类型为企业用户
|
||||
2. 访问我的页面,查看企业信息卡片
|
||||
3. 点击头像区域跳转到企业信息页面
|
||||
4. 在企业信息页面查看详细的企业信息
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 确保用户类型字段正确设置
|
||||
- 企业信息数据需要从后端API获取
|
||||
- 头像上传功能需要配置服务器接口
|
||||
- 编辑页面需要根据实际需求进行开发
|
||||
187
docs/企业搜索功能实现说明.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# 企业搜索功能实现说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
根据用户类型对发布岗位页面的"招聘公司"输入框进行不同的交互处理:
|
||||
|
||||
- **企业用户**:直接输入公司名称
|
||||
- **网格员**:点击输入框跳转到企业搜索页面,支持模糊查询
|
||||
|
||||
## 实现细节
|
||||
|
||||
### 1. 用户类型判断
|
||||
|
||||
通过 `userInfo.isCompanyUser` 字段判断用户类型:
|
||||
- `0`: 企业用户
|
||||
- `1`: 求职者
|
||||
- `2`: 网格员
|
||||
- `3`: 政府人员
|
||||
|
||||
### 2. 页面修改
|
||||
|
||||
#### 发布岗位页面 (`pages/job/publishJob.vue`)
|
||||
|
||||
**模板修改:**
|
||||
```vue
|
||||
<!-- 企业用户:直接输入 -->
|
||||
<input
|
||||
v-if="isCompanyUser"
|
||||
class="input"
|
||||
placeholder="请输入公司名称"
|
||||
v-model="formData.companyName"
|
||||
/>
|
||||
<!-- 网格员:点击跳转到搜索页面 -->
|
||||
<view
|
||||
v-else
|
||||
class="company-selector"
|
||||
@click="openCompanySearch"
|
||||
>
|
||||
<view class="selector-text" :class="{ 'placeholder': !formData.companyName }">
|
||||
{{ formData.companyName || '请选择企业' }}
|
||||
</view>
|
||||
<view class="selector-icon">
|
||||
<view class="arrow-icon">></view>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
**脚本修改:**
|
||||
- 添加用户类型判断逻辑
|
||||
- 添加打开企业搜索页面的方法
|
||||
- 添加页面显示时处理返回数据的逻辑
|
||||
|
||||
#### 企业搜索页面 (`pages/job/companySearch.vue`)
|
||||
|
||||
**功能特性:**
|
||||
- 搜索框支持实时输入
|
||||
- 防抖节流:500ms延迟执行搜索
|
||||
- 调用接口:`/app/company/likeList`,参数:`name`
|
||||
- 支持企业选择和数据回传
|
||||
- 空状态和加载状态处理
|
||||
|
||||
**核心代码:**
|
||||
```javascript
|
||||
// 防抖搜索
|
||||
const onSearchInput = () => {
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
if (searchKeyword.value.trim()) {
|
||||
searchCompanies();
|
||||
} else {
|
||||
searchResults.value = [];
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 搜索企业
|
||||
const searchCompanies = async () => {
|
||||
const response = await createRequest('/app/company/likeList', {
|
||||
name: searchKeyword.value.trim()
|
||||
}, 'GET', false);
|
||||
|
||||
if (response.code === 200) {
|
||||
searchResults.value = response.data || [];
|
||||
}
|
||||
};
|
||||
|
||||
// 选择企业
|
||||
const selectCompany = (company) => {
|
||||
uni.navigateBack({
|
||||
success: () => {
|
||||
getApp().globalData = getApp().globalData || {};
|
||||
getApp().globalData.selectedCompany = company;
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### 3. 数据传递
|
||||
|
||||
使用全局数据传递选中的企业信息:
|
||||
|
||||
**企业搜索页面:**
|
||||
```javascript
|
||||
// 选择企业后设置全局数据
|
||||
getApp().globalData.selectedCompany = company;
|
||||
```
|
||||
|
||||
**发布岗位页面:**
|
||||
```javascript
|
||||
// 页面显示时检查全局数据
|
||||
onShow(() => {
|
||||
const app = getApp();
|
||||
if (app.globalData && app.globalData.selectedCompany) {
|
||||
const selectedCompany = app.globalData.selectedCompany;
|
||||
formData.companyName = selectedCompany.name;
|
||||
formData.companyId = selectedCompany.id;
|
||||
|
||||
// 清除全局数据
|
||||
app.globalData.selectedCompany = null;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 4. 页面配置
|
||||
|
||||
在 `pages.json` 中添加了企业搜索页面配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "pages/job/companySearch",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择企业",
|
||||
"navigationStyle": "custom",
|
||||
"disableScroll": false,
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundColor": "#f5f5f5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 测试页面
|
||||
|
||||
创建了测试页面 `pages/test/company-search-test.vue` 用于验证功能:
|
||||
- 用户类型切换
|
||||
- 功能说明展示
|
||||
- 直接跳转到发布岗位页面测试
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 企业用户
|
||||
1. 进入发布岗位页面
|
||||
2. 招聘公司输入框为普通输入框
|
||||
3. 直接输入公司名称
|
||||
|
||||
### 网格员
|
||||
1. 进入发布岗位页面
|
||||
2. 点击"招聘公司"输入框
|
||||
3. 跳转到企业搜索页面
|
||||
4. 输入企业名称进行搜索(支持防抖)
|
||||
5. 选择企业后自动返回
|
||||
6. 企业名称显示在输入框中
|
||||
|
||||
## 技术特点
|
||||
|
||||
1. **防抖节流**:搜索输入500ms延迟,避免频繁请求
|
||||
2. **用户类型判断**:根据 `isCompanyUser` 字段动态显示不同交互
|
||||
3. **数据传递**:使用全局数据实现页面间数据传递
|
||||
4. **响应式设计**:支持不同屏幕尺寸
|
||||
5. **错误处理**:完善的错误提示和空状态处理
|
||||
|
||||
## 接口说明
|
||||
|
||||
**搜索企业接口:**
|
||||
- 地址:`/app/company/likeList`
|
||||
- 方法:`GET`
|
||||
- 参数:`name` (企业名称)
|
||||
- 返回:企业列表数据
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保用户类型字段 `isCompanyUser` 正确设置
|
||||
2. 搜索接口需要支持模糊查询
|
||||
3. 企业数据需要包含 `id` 和 `name` 字段
|
||||
4. 防抖时间可根据实际需求调整
|
||||
129
docs/自定义TabBar使用说明.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# 自定义TabBar使用说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
本项目实现了基于用户类型的动态自定义TabBar,支持根据用户登录状态和类型显示不同的导航项:
|
||||
|
||||
- **未登录状态**:默认显示求职者tabbar(职位 + 招聘会 + AI+ + 消息 + 我的)
|
||||
- **企业用户(userType=0)**:显示"发布岗位"导航
|
||||
- **求职者用户(userType=1,2,3)**:显示"招聘会"导航
|
||||
|
||||
## 实现方案
|
||||
|
||||
### 1. 微信小程序原生自定义TabBar
|
||||
|
||||
在 `custom-tab-bar/` 目录下创建了微信小程序原生自定义TabBar组件:
|
||||
|
||||
- `index.js` - 组件逻辑,根据用户类型动态生成TabBar配置
|
||||
- `index.wxml` - 模板文件
|
||||
- `index.wxss` - 样式文件
|
||||
- `index.json` - 组件配置文件
|
||||
|
||||
### 2. UniApp兼容的自定义TabBar组件
|
||||
|
||||
创建了 `components/CustomTabBar/CustomTabBar.vue` 组件,支持多端兼容:
|
||||
|
||||
- 支持微信小程序、H5、APP等多端
|
||||
- 响应式设计,根据用户类型动态显示
|
||||
- 支持消息徽章显示
|
||||
- 支持页面跳转逻辑
|
||||
|
||||
### 3. 配置修改
|
||||
|
||||
在 `pages.json` 中启用了自定义TabBar:
|
||||
|
||||
```json
|
||||
"tabBar": {
|
||||
"custom": true,
|
||||
// ... 其他配置
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 在页面中引入自定义TabBar
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- 页面内容 -->
|
||||
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="0" />
|
||||
</view>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 2. 用户类型判断
|
||||
|
||||
组件会自动从 `useUserStore` 中获取用户信息,根据用户登录状态和 `userInfo.userType` 字段判断用户类型:
|
||||
|
||||
```javascript
|
||||
// 用户类型说明
|
||||
// 未登录: 默认显示求职者tabbar
|
||||
// 0: 企业用户 - 显示"发布岗位"
|
||||
// 1: 求职者 - 显示"招聘会"
|
||||
// 2: 网格员 - 显示"招聘会"
|
||||
// 3: 政府人员 - 显示"招聘会"
|
||||
```
|
||||
|
||||
### 3. 动态切换用户类型
|
||||
|
||||
当用户登录状态或类型发生变化时,TabBar会自动更新:
|
||||
|
||||
```javascript
|
||||
// 未登录状态:自动显示求职者tabbar
|
||||
// 登录后根据用户类型显示对应tabbar
|
||||
|
||||
// 切换用户类型
|
||||
userInfo.value.userType = 1; // 切换到求职者
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
|
||||
// 登出时清除用户信息,自动回到未登录状态
|
||||
userStore.logOut(false);
|
||||
```
|
||||
|
||||
## 页面配置
|
||||
|
||||
### 已配置的页面
|
||||
|
||||
- `pages/index/index.vue` - 首页(currentPage: 0)
|
||||
- `pages/careerfair/careerfair.vue` - 招聘会页面(currentPage: 1)
|
||||
- `pages/chat/chat.vue` - AI+页面(currentPage: 2)
|
||||
- `pages/msglog/msglog.vue` - 消息页面(currentPage: 3)
|
||||
- `pages/mine/mine.vue` - 我的页面(currentPage: 4)
|
||||
|
||||
### 测试页面
|
||||
|
||||
- `pages/test/tabbar-test.vue` - TabBar功能测试页面
|
||||
|
||||
## 技术特点
|
||||
|
||||
1. **响应式设计**:根据用户类型动态显示不同的导航项
|
||||
2. **多端兼容**:支持微信小程序、H5、APP等平台
|
||||
3. **消息徽章**:支持显示未读消息数量
|
||||
4. **页面跳转**:智能判断tabBar页面和普通页面的跳转方式
|
||||
5. **用户类型监听**:实时监听用户类型变化并更新TabBar
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保在 `pages.json` 中设置了 `"custom": true`
|
||||
2. 每个页面的 `currentPage` 参数需要正确设置
|
||||
3. 用户类型存储在 `userInfo.userType` 字段中
|
||||
4. 组件会自动监听用户类型变化并更新显示
|
||||
|
||||
## 测试方法
|
||||
|
||||
1. 访问测试页面:`/pages/test/tabbar-test`
|
||||
2. 切换不同的用户类型
|
||||
3. 观察底部TabBar的变化
|
||||
4. 测试页面跳转功能
|
||||
|
||||
## 故障排除
|
||||
|
||||
如果TabBar不显示或显示异常:
|
||||
|
||||
1. 检查 `pages.json` 中的 `custom: true` 配置
|
||||
2. 确认用户信息是否正确存储
|
||||
3. 检查组件是否正确引入
|
||||
4. 查看控制台是否有错误信息
|
||||
17
main.js
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Date: 2025-10-23 14:48:48
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-10-31 16:51:55
|
||||
* @LastEditTime: 2025-10-31 18:11:22
|
||||
*/
|
||||
import App from './App'
|
||||
import * as Pinia from 'pinia'
|
||||
@@ -19,12 +19,13 @@ import { request, get, post, packageRcRequest, packageRcGet, packageRcPost } fro
|
||||
// 组件
|
||||
import AppLayout from './components/AppLayout/AppLayout.vue';
|
||||
import Empty from './components/empty/empty.vue';
|
||||
import NoBouncePage from './components/NoBouncePage/NoBouncePage.vue'
|
||||
import MsgTips from './components/MsgTips/MsgTips.vue'
|
||||
import SelectPopup from './components/selectPopup/selectPopup.vue'
|
||||
import SelectPopupPlugin from './components/selectPopup/selectPopupPlugin';
|
||||
import RenderJobs from './components/renderJobs/renderJobs.vue';
|
||||
import RenderCompanys from './components/renderCompanys/renderCompanys.vue';
|
||||
import NoBouncePage from '@/components/NoBouncePage/NoBouncePage.vue'
|
||||
import MsgTips from '@/components/MsgTips/MsgTips.vue'
|
||||
import SelectPopup from '@/components/selectPopup/selectPopup.vue'
|
||||
import SelectPopupPlugin from '@/components/selectPopup/selectPopupPlugin';
|
||||
import RenderJobs from '@/components/renderJobs/renderJobs.vue';
|
||||
import RenderCompanys from '@/components/renderCompanys/renderCompanys.vue';
|
||||
// iconfont.css 已在 App.vue 中通过 @import 引入,无需在此处重复引入
|
||||
// import Tabbar from '@/components/tabbar/midell-box.vue'
|
||||
// 自动导入 directives 目录下所有指令
|
||||
const directives = import.meta.glob('./directives/*.js', {
|
||||
@@ -36,8 +37,6 @@ import { createSSRApp } from 'vue'
|
||||
import uniIcons from './uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
|
||||
import uniPopup from './uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
|
||||
|
||||
|
||||
import storeRc from './utilsRc/store/index.js'
|
||||
// const foldFeature = window.visualViewport && 'segments' in window.visualViewport
|
||||
// console.log('是否支持多段屏幕:', foldFeature)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "wxc0f37e549415bb4e",
|
||||
"appid" : "wx9d1cbc11c8c40ba7",
|
||||
"setting" : {
|
||||
"urlCheck" : false,
|
||||
"es6" : true,
|
||||
|
||||
@@ -1,320 +1,329 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template #headerright>
|
||||
<view class="btn mar_ri10">
|
||||
<image
|
||||
src="@/static/icon/collect3.png"
|
||||
v-if="!companyInfo.isCollection"
|
||||
@click="companyCollection"
|
||||
></image>
|
||||
<image src="@/static/icon/collect2.png" v-else @click="companyCollection"></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content">
|
||||
<view class="content-top">
|
||||
<view class="companyinfo-left">
|
||||
<image src="@/static/icon/companyIcon.png" mode=""></image>
|
||||
</view>
|
||||
<view class="companyinfo-right">
|
||||
<view class="row1">{{ companyInfo?.name }}</view>
|
||||
<view class="row2">
|
||||
<dict-tree-Label
|
||||
v-if="companyInfo?.industry"
|
||||
dictType="industry"
|
||||
:value="companyInfo?.industry"
|
||||
></dict-tree-Label>
|
||||
<span v-if="companyInfo?.industry"> </span>
|
||||
<dict-Label dictType="scale" :value="companyInfo?.scale"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||
<view class="info-title">公司介绍</view>
|
||||
<view class="info-desirption">{{ companyInfo.description }}</view>
|
||||
<!-- <view class="info-title title2">公司地址</view>
|
||||
<view class="locationCompany"></view> -->
|
||||
</view>
|
||||
<view class="expand" @click="expand">
|
||||
<text>{{ isExpanded ? '收起' : '展开' }}</text>
|
||||
<image
|
||||
class="expand-img"
|
||||
:class="{ 'expand-img-active': !isExpanded }"
|
||||
src="@/static/icon/downs.png"
|
||||
></image>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view" @scrolltolower="getJobsList('add')">
|
||||
<view class="views">
|
||||
<view class="Detail-title"><text class="title">在招职位</text></view>
|
||||
<renderJobs
|
||||
v-if="pageState.list.length"
|
||||
:list="pageState.list"
|
||||
:longitude="longitudeVal"
|
||||
:latitude="latitudeVal"
|
||||
></renderJobs>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template #headerright>
|
||||
<view class="btn mar_ri10">
|
||||
<image
|
||||
src="@/static/icon/collect3.png"
|
||||
v-if="!companyInfo.isCollection"
|
||||
></image>
|
||||
<image src="@/static/icon/collect2.png" v-else></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content">
|
||||
<view class="content-top">
|
||||
<view class="companyinfo-left">
|
||||
<image src="@/static/icon/companyIcon.png" mode=""></image>
|
||||
</view>
|
||||
</AppLayout>
|
||||
<view class="companyinfo-right">
|
||||
<view class="row1">{{ companyInfo?.companyName }}</view>
|
||||
<view class="row2">
|
||||
{{ companyInfo?.scale }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||
<view class="info-title">公司介绍</view>
|
||||
<view class="info-desirption">{{
|
||||
companyInfo.companyIntroduction
|
||||
}}</view>
|
||||
<!-- <view class="info-title title2">公司地址</view>
|
||||
<view class="locationCompany"></view> -->
|
||||
</view>
|
||||
<view class="expand" @click="expand">
|
||||
<text>{{ isExpanded ? "收起" : "展开" }}</text>
|
||||
<image
|
||||
class="expand-img"
|
||||
:class="{ 'expand-img-active': !isExpanded }"
|
||||
src="@/static/icon/downs.png"
|
||||
></image>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view">
|
||||
<view class="views">
|
||||
<view class="Detail-title"><text class="title">在招职位</text></view>
|
||||
<template v-if="companyInfo.jobInfoList.length != 0">
|
||||
<view v-for="job in companyInfo.jobInfoList" :key="job.id">
|
||||
<view class="cards" @click="navTo(`/packageA/pages/post/post?jobId=${JSON.stringify(job)}`)">
|
||||
<view class="card-company">
|
||||
<text class="company">{{ job.jobTitle }}</text>
|
||||
<view class="salary"> {{ job.salaryRange }}元 </view>
|
||||
</view>
|
||||
<view class="card-companyName">{{ job.companyName }}</view>
|
||||
<view class="card-companyName">{{ job.jobDescription }}</view>
|
||||
<view class="card-tags">
|
||||
<view class="tag">
|
||||
{{ job.educationRequirement }}
|
||||
</view>
|
||||
<view class="tag">
|
||||
{{ job.experienceRequirement }}
|
||||
</view>
|
||||
<!-- <view class="tag">
|
||||
{{ vacanciesTo(job.vacancies) }}
|
||||
</view> -->
|
||||
<view class="tag" v-if="job.jobRequirement">
|
||||
{{ job.jobRequirement }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-bottom">
|
||||
<view>{{ job.postingDate }}</view>
|
||||
<view>
|
||||
<convert-distance
|
||||
:alat="job.latitude"
|
||||
:along="job.longitude"
|
||||
:blat="latitude"
|
||||
:blong="longitude"
|
||||
></convert-distance>
|
||||
<dict-Label
|
||||
class="mar_le10"
|
||||
dictType="area"
|
||||
:value="job.jobLocationAreaCode"
|
||||
></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import point from '@/static/icon/point.png';
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
import point from "@/static/icon/point.png";
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from "vue";
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import dictLabel from "@/components/dict-Label/dict-Label.vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useLocationStore from "@/stores/useLocationStore";
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
const { $api, navTo, vacanciesTo, navBack } = inject('globalFunction');
|
||||
const { $api, navTo, vacanciesTo, navBack } = inject("globalFunction");
|
||||
|
||||
const isExpanded = ref(false);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 10,
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
const companyInfo = ref({});
|
||||
|
||||
onLoad((options) => {
|
||||
console.log(options);
|
||||
getCompanyInfo(options.companyId || options.bussinessId);
|
||||
companyInfo.value = JSON.parse(options.job);
|
||||
console.log(companyInfo.value, "companyInfo.value");
|
||||
});
|
||||
|
||||
function companyCollection() {
|
||||
const companyId = companyInfo.value.companyId;
|
||||
if (companyInfo.value.isCollection) {
|
||||
$api.createRequest(`/app/company/collection/${companyId}`, {}, 'DELETE').then((resData) => {
|
||||
getCompanyInfo(companyId);
|
||||
$api.msg('取消收藏成功');
|
||||
});
|
||||
} else {
|
||||
$api.createRequest(`/app/company/collection/${companyId}`, {}, 'POST').then((resData) => {
|
||||
getCompanyInfo(companyId);
|
||||
$api.msg('收藏成功');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getCompanyInfo(id) {
|
||||
$api.createRequest(`/app/company/${id}`).then((resData) => {
|
||||
companyInfo.value = resData.data;
|
||||
getJobsList();
|
||||
});
|
||||
}
|
||||
|
||||
function getJobsList(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 1;
|
||||
}
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
let params = {
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
};
|
||||
$api.createRequest(`/app/company/job/${companyInfo.value.companyId}`, params).then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = pageState.list.length;
|
||||
const reslist = rows;
|
||||
pageState.list.splice(str, end, ...reslist);
|
||||
} else {
|
||||
pageState.list = rows;
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
});
|
||||
}
|
||||
|
||||
function expand() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
isExpanded.value = !isExpanded.value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
.btnback {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.content{
|
||||
height: 100%
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
.content-top{
|
||||
padding: 28rpx
|
||||
padding-top: 50rpx
|
||||
display: flex
|
||||
flex-direction: row
|
||||
flex-wrap: nowrap
|
||||
.companyinfo-left{
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx
|
||||
}
|
||||
.companyinfo-right{
|
||||
|
||||
.row1{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.row2{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
line-height: 45rpx;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.content-top {
|
||||
padding: 28rpx;
|
||||
padding-top: 50rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.companyinfo-left {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
.conetent-info{
|
||||
padding: 0 28rpx
|
||||
overflow: hidden;
|
||||
max-height: 0rpx;
|
||||
transition: max-height 0.3s ease;
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.info-desirption{
|
||||
margin-top: 12rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
text-align: justified;
|
||||
}
|
||||
.title2{
|
||||
margin-top: 48rpx
|
||||
}
|
||||
}
|
||||
.expanded {
|
||||
max-height: 1000rpx; // 足够显示完整内容
|
||||
}
|
||||
.expand{
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
white-space: nowrap
|
||||
justify-content: center
|
||||
margin-top: 20rpx
|
||||
margin-bottom: 28rpx
|
||||
|
||||
.companyinfo-right {
|
||||
.row1 {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.row2 {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
.expand-img{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.expand-img-active{
|
||||
transform: rotate(180deg)
|
||||
}
|
||||
color: #6C7282;
|
||||
line-height: 45rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.Detailscroll-view{
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.conetent-info {
|
||||
padding: 0 28rpx;
|
||||
overflow: hidden;
|
||||
background: #F4F4F4;
|
||||
.views{
|
||||
padding: 28rpx
|
||||
.Detail-title{
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
.title{
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
.Detail-title::before{
|
||||
position: absolute
|
||||
content: '';
|
||||
left: -14rpx
|
||||
bottom: 0
|
||||
height: 16rpx;
|
||||
width: 108rpx;
|
||||
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
|
||||
border-radius: 8rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.cards{
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
margin-top: 22rpx;
|
||||
.card-company{
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
align-items: flex-start
|
||||
.company{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.salary{
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #4C6EFB;
|
||||
white-space: nowrap
|
||||
line-height: 48rpx
|
||||
}
|
||||
}
|
||||
.card-companyName{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
.card-tags{
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
.tag{
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
white-space: nowrap
|
||||
margin-right: 20rpx
|
||||
}
|
||||
}
|
||||
.card-bottom{
|
||||
margin-top: 32rpx
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
max-height: 0rpx;
|
||||
transition: max-height 0.3s ease;
|
||||
|
||||
.info-title {
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.info-desirption {
|
||||
margin-top: 12rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
text-align: justified;
|
||||
}
|
||||
|
||||
.title2 {
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.expanded {
|
||||
max-height: 1000rpx; // 足够显示完整内容
|
||||
}
|
||||
|
||||
.expand {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 28rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
|
||||
.expand-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.expand-img-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Detailscroll-view {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: #F4F4F4;
|
||||
|
||||
.views {
|
||||
padding: 28rpx;
|
||||
|
||||
.Detail-title {
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.Detail-title::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
left: -14rpx;
|
||||
bottom: 0;
|
||||
height: 16rpx;
|
||||
width: 108rpx;
|
||||
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
|
||||
border-radius: 8rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cards {
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
margin-top: 22rpx;
|
||||
|
||||
.card-company {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
|
||||
.company {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.salary {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #4C6EFB;
|
||||
white-space: nowrap;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card-companyName {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
|
||||
.card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.tag {
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
white-space: nowrap;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card-bottom {
|
||||
margin-top: 32rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
<template>
|
||||
<AppLayout
|
||||
title="添加工作经历"
|
||||
border
|
||||
back-gorund-color="#ffffff"
|
||||
:show-bg-image="false"
|
||||
>
|
||||
<template #headerleft>
|
||||
<view class="btn mar_le20 button-click" @click="navBack">取消</view>
|
||||
</template>
|
||||
<template #headerright>
|
||||
<view class="btn mar_ri20 button-click" @click="handleConfirm">确认</view>
|
||||
</template>
|
||||
<view class="page-container">
|
||||
<view class="content">
|
||||
<view class="content-input">
|
||||
<view class="input-titile">公司名称</view>
|
||||
@@ -44,8 +33,12 @@
|
||||
<textarea class="textarea-con" v-model="formData.description" placeholder-style="font-size: 16px" maxlength="500" placeholder="请输入工作描述"/>
|
||||
</view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
|
||||
|
||||
<!-- 底部确认按钮 -->
|
||||
<view class="bottom-confirm-btn">
|
||||
<view class="confirm-btn" @click="handleConfirm">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -206,7 +199,6 @@
|
||||
console.log('页面类型:', pageType.value);
|
||||
|
||||
let resData;
|
||||
alert(editData.value.id)
|
||||
// 根据页面类型调用不同的接口
|
||||
if (pageType.value === 'edit' && editData.value?.id) {
|
||||
// 编辑模式:调用更新接口
|
||||
@@ -234,12 +226,18 @@
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background-color: #ffffff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content{
|
||||
padding: 28rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start
|
||||
height: calc(100% - 120rpx)
|
||||
justify-content: flex-start;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
.content-input
|
||||
margin-bottom: 52rpx
|
||||
@@ -328,6 +326,30 @@
|
||||
line-height: 20rpx
|
||||
display: flex
|
||||
align-items: center
|
||||
|
||||
// 底部确认按钮样式
|
||||
.bottom-confirm-btn
|
||||
position: fixed
|
||||
bottom: 0
|
||||
left: 0
|
||||
right: 0
|
||||
background-color: #ffffff
|
||||
padding: 20rpx 28rpx
|
||||
border-top: 2rpx solid #EBEBEB
|
||||
z-index: 999
|
||||
|
||||
.confirm-btn
|
||||
width: 100%
|
||||
height: 90rpx
|
||||
background: #256BFA
|
||||
border-radius: 12rpx
|
||||
font-weight: 500
|
||||
font-size: 32rpx
|
||||
color: #FFFFFF
|
||||
text-align: center
|
||||
line-height: 90rpx
|
||||
button-click: true
|
||||
|
||||
// .content-sex
|
||||
// height: 110rpx;
|
||||
// display: flex
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<input
|
||||
class="input-con triangle"
|
||||
disabled
|
||||
v-if="!state.jobsText.length"
|
||||
v-if="!state.jobsText || !state.jobsText.length"
|
||||
placeholder="请选择您的求职岗位"
|
||||
/>
|
||||
<view class="input-nx" @click="changeJobs" v-else>
|
||||
@@ -40,6 +40,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<SelectJobs ref="selectJobsModel"></SelectJobs>
|
||||
<SelectPopup ref="selectPopupRef"></SelectPopup>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
@@ -47,16 +48,24 @@
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import SelectJobs from '@/components/selectJobs/selectJobs.vue';
|
||||
import SelectPopup from '@/components/selectPopup/selectPopup.vue';
|
||||
const { $api, navTo, navBack, config } = inject('globalFunction');
|
||||
const openSelectPopup = inject('openSelectPopup');
|
||||
|
||||
// 创建本地的 openSelectPopup 函数
|
||||
const openSelectPopup = (config) => {
|
||||
if (selectPopupRef.value) {
|
||||
selectPopupRef.value.open(config);
|
||||
}
|
||||
};
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
const { getUserResume } = useUserStore();
|
||||
const { dictLabel, oneDictData } = useDictStore();
|
||||
const { dictLabel, oneDictData, getDictData } = useDictStore();
|
||||
|
||||
const selectJobsModel = ref();
|
||||
const selectPopupRef = ref();
|
||||
const percent = ref('0%');
|
||||
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
|
||||
const state = reactive({
|
||||
@@ -72,7 +81,9 @@ const fromValue = reactive({
|
||||
area: '',
|
||||
jobTitleId: [],
|
||||
});
|
||||
onLoad(() => {
|
||||
onLoad(async () => {
|
||||
// 初始化字典数据
|
||||
await getDictData();
|
||||
initLoad();
|
||||
});
|
||||
const confirm = () => {
|
||||
@@ -99,8 +110,12 @@ function initLoad() {
|
||||
fromValue.jobTitleId = userInfo.value.jobTitleId;
|
||||
// 回显
|
||||
state.areaText = dictLabel('area', Number(userInfo.value.area));
|
||||
state.salayText = `${userInfo.value.salaryMin}-${userInfo.value.salaryMax}`;
|
||||
state.jobsText = userInfo.value.jobTitle;
|
||||
if (userInfo.value.salaryMin && userInfo.value.salaryMax) {
|
||||
state.salayText = `${userInfo.value.salaryMin}-${userInfo.value.salaryMax}`;
|
||||
} else {
|
||||
state.salayText = '';
|
||||
}
|
||||
state.jobsText = userInfo.value.jobTitle || [];
|
||||
const result = getFormCompletionPercent(fromValue);
|
||||
percent.value = result;
|
||||
}
|
||||
@@ -123,7 +138,8 @@ const changeSalary = () => {
|
||||
const copyri = JSON.parse(JSON.stringify(salay));
|
||||
const [lf, ri] = e.detail.value;
|
||||
const risalay = copyri.slice(lf, copyri.length);
|
||||
this.setColunm(1, risalay);
|
||||
// 更新右侧选项
|
||||
state.risalay = risalay;
|
||||
leftIndex = salayData[0];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -122,28 +122,23 @@
|
||||
</view>
|
||||
|
||||
<!-- 4. 新增:简历上传区域(固定在页面底部) -->
|
||||
<view class="resume-upload-section">
|
||||
<!-- 上传按钮 -->
|
||||
<!-- <view class="resume-upload-section">
|
||||
<button class="upload-btn" @click="handleResumeUpload" :loading="isUploading" :disabled="isUploading">
|
||||
<uni-icons type="cloud-upload" size="20"></uni-icons>
|
||||
<!-- <image class="upload-icon" src="/static/icons/upload-file.png" mode="widthFix"></image> -->
|
||||
<text class="upload-text">
|
||||
{{ uploadedResumeName || '上传简历' }}
|
||||
</text>
|
||||
<!-- 已上传时显示“重新上传”文字 -->
|
||||
<text class="reupload-text" v-if="uploadedResumeName">(重新上传)</text>
|
||||
</button>
|
||||
|
||||
<!-- 上传说明 -->
|
||||
<text class="upload-tip">支持 PDF、Word 格式,文件大小不超过 20MB</text>
|
||||
|
||||
<!-- 已上传文件信息(可选) -->
|
||||
<view class="uploaded-file-info" v-if="uploadedResumeName">
|
||||
<image class="file-icon" src="/static/icons/file-icon.png" mode="widthFix"></image>
|
||||
<text class="file-name">{{ uploadedResumeName }}</text>
|
||||
<button class="delete-file-btn" size="mini" @click.stop="handleDeleteResume">删除</button>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -16,27 +16,29 @@
|
||||
</template>
|
||||
<view class="content" v-show="!isEmptyObject(jobInfo)">
|
||||
<view class="content-top btn-feel">
|
||||
<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>
|
||||
<view class="info-text">
|
||||
<dict-Label dictType="experience" :value="jobInfo.experience"></dict-Label>
|
||||
<view style="background: #ffffff;padding: 24rpx;box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);border-radius: 20rpx 20rpx 20rpx 20rpx;position: relative;overflow: hidden;">
|
||||
<view class="top-salary">
|
||||
<Salary-Expectation
|
||||
:max-salary="jobInfo.maxSalary"
|
||||
:min-salary="jobInfo.minSalary"
|
||||
:is-month="true"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
<view class="info-img mar_le20"><image src="/static/icon/post13.png"></image></view>
|
||||
<view class="info-text">
|
||||
<dict-Label dictType="education" :value="jobInfo.education"></dict-Label>
|
||||
<view class="top-name">{{ jobInfo.jobTitle }}</view>
|
||||
<view class="top-info">
|
||||
<view class="info-img"><image src="/static/icon/post12.png"></image></view>
|
||||
<view class="info-text">
|
||||
<dict-Label dictType="experience" :value="jobInfo.experience"></dict-Label>
|
||||
</view>
|
||||
<view class="info-img mar_le20"><image src="/static/icon/post13.png"></image></view>
|
||||
<view class="info-text">
|
||||
<dict-Label dictType="education" :value="jobInfo.education"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
<view class="position-source">
|
||||
<text>来源 </text>
|
||||
{{ jobInfo.dataSource }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="position-source">
|
||||
<text>来源 </text>
|
||||
{{ jobInfo.dataSource }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="ai-explain" v-if="jobInfo.isExplain">
|
||||
@@ -98,7 +100,7 @@
|
||||
></map>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-card" v-if="!userInfo.isCompanyUser">
|
||||
<view class="content-card" v-if="currentUserType !== 0">
|
||||
<view class="card-title">
|
||||
<text class="title">竞争力分析</text>
|
||||
</view>
|
||||
@@ -191,6 +193,12 @@ import RadarMap from './component/radarMap.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
// 与首页一致的用户类型获取:优先store,兜底缓存
|
||||
const currentUserType = computed(() => {
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedIsCompanyUser = (uni.getStorageSync('userInfo') || {}).isCompanyUser;
|
||||
return Number(storeIsCompanyUser !== undefined ? storeIsCompanyUser : cachedIsCompanyUser);
|
||||
});
|
||||
const { $api, navTo, getLenPx, parseQueryParams, navBack, isEmptyObject } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
const matchingDegree = ref(['一般', '良好', '优秀', '极好']);
|
||||
@@ -263,11 +271,11 @@ function seeExplain() {
|
||||
function getDetail(jobId) {
|
||||
return new Promise((reslove, reject) => {
|
||||
$api.createRequest(`/app/job/${jobId}`).then((resData) => {
|
||||
const { latitude, longitude, companyName, companyId, isCompanyUser } = resData.data;
|
||||
const { latitude, longitude, companyName, companyId } = resData.data;
|
||||
jobInfo.value = resData.data;
|
||||
reslove(resData.data);
|
||||
getCompanyIsAJobs(companyId);
|
||||
if (isCompanyUser) {
|
||||
if (currentUserType.value !== 0) {
|
||||
getCompetivetuveness(jobId);
|
||||
}
|
||||
// getCompetivetuveness(jobId);
|
||||
@@ -503,11 +511,11 @@ for i in 0..100
|
||||
.content{
|
||||
padding: 0 28rpx
|
||||
height: 100%
|
||||
padding-top: 28rpx
|
||||
.content-top{
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
padding: 52rpx 32rpx 34rpx 32rpx
|
||||
padding: 24rpx
|
||||
position: relative
|
||||
overflow: hidden
|
||||
.top-salary{
|
||||
|
||||
559
packageB/jobFair/detail.vue
Normal file
@@ -0,0 +1,559 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content">
|
||||
<view class="content-top">
|
||||
<view class="companyinfo-left">
|
||||
<image src="@/static/icon/companyIcon.png" mode=""></image>
|
||||
</view>
|
||||
<view class="companyinfo-right">
|
||||
<view class="row1 line_2">{{ fairInfo?.name }}</view>
|
||||
<view class="row2">
|
||||
<text>{{ fairInfo.location }}</text>
|
||||
<convert-distance
|
||||
:alat="fairInfo.latitude"
|
||||
:along="fairInfo.longitude"
|
||||
:blat="latitudeVal"
|
||||
:blong="longitudeVal"
|
||||
></convert-distance>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="locations">
|
||||
<image class="location-img" src="/static/icon/mapLine.png"></image>
|
||||
<view class="location-info">
|
||||
<view class="info">
|
||||
<text class="info-title">{{ fairInfo.address }}</text>
|
||||
<text class="info-text">位置</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||
<view class="info-title">内容描述</view>
|
||||
<view class="info-desirption">{{ fairInfo.description }}</view>
|
||||
<!-- <view class="info-title title2">公司地址</view>
|
||||
<view class="locationCompany"></view> -->
|
||||
<view class="company-times">
|
||||
<view class="info-title">内容描述</view>
|
||||
<view class="card-times">
|
||||
<view class="time-left">
|
||||
<view class="left-date">{{ parseDateTime(fairInfo.startTime).time }}</view>
|
||||
<view class="left-dateDay">{{ parseDateTime(fairInfo.startTime).date }}</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="time-center">
|
||||
<view class="center-date">
|
||||
{{ getTimeStatus(fairInfo.startTime, fairInfo.endTime).statusText }}
|
||||
</view>
|
||||
<view class="center-dateDay">
|
||||
{{ getHoursBetween(fairInfo.startTime, fairInfo.endTime) }}小时
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="time-right">
|
||||
<view class="left-date">{{ parseDateTime(fairInfo.endTime).time }}</view>
|
||||
<view class="left-dateDay">{{ parseDateTime(fairInfo.endTime).date }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="expand" @click="expand">
|
||||
<text>{{ isExpanded ? '收起' : '展开' }}</text>
|
||||
<image
|
||||
class="expand-img"
|
||||
:class="{ 'expand-img-active': !isExpanded }"
|
||||
src="@/static/icon/downs.png"
|
||||
></image>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view">
|
||||
<view class="views">
|
||||
<view class="Detail-title">
|
||||
<text class="title">参会单位({{ companyList.length }})</text>
|
||||
</view>
|
||||
<renderCompanys
|
||||
v-if="companyList.length"
|
||||
:list="companyList"
|
||||
:longitude="longitudeVal"
|
||||
:latitude="latitudeVal"
|
||||
></renderCompanys>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<template #footer>
|
||||
<view class="footer" v-if="hasnext">
|
||||
<view
|
||||
class="btn-wq button-click"
|
||||
:class="{ 'btn-desbel': fairInfo.isCollection }"
|
||||
@click="applyExhibitors"
|
||||
>
|
||||
{{ fairInfo.isCollection ? '已预约招聘会' : '预约招聘会' }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import point from '@/static/icon/point.png';
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
const { $api, navTo, vacanciesTo, navBack } = inject('globalFunction');
|
||||
import { storeToRefs } from 'pinia';
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
|
||||
const isExpanded = ref(false);
|
||||
const fairInfo = ref({});
|
||||
const companyList = ref([]);
|
||||
const hasnext = ref(true);
|
||||
onLoad((options) => {
|
||||
getCompanyInfo(options.jobFairId);
|
||||
});
|
||||
|
||||
function getCompanyInfo(id) {
|
||||
$api.createRequest(`/app/fair/${id}`).then((resData) => {
|
||||
fairInfo.value = resData.data;
|
||||
companyList.value = resData.data.companyList;
|
||||
hasAppointment();
|
||||
});
|
||||
}
|
||||
|
||||
const hasAppointment = () => {
|
||||
const isTimePassed = (timeStr) => {
|
||||
const targetTime = new Date(timeStr.replace(/-/g, '/')).getTime(); // 兼容格式
|
||||
const now = Date.now();
|
||||
return now < targetTime;
|
||||
};
|
||||
|
||||
hasnext.value = isTimePassed(fairInfo.value.startTime);
|
||||
};
|
||||
|
||||
function openMap(lat, lng, name = '位置') {
|
||||
const isConfirmed = window.confirm('是否打开地图查看位置?');
|
||||
if (!isConfirmed) return;
|
||||
|
||||
// 使用高德地图或百度地图的 H5 链接打开
|
||||
const url = `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(name)}`;
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
function expand() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
}
|
||||
|
||||
// 取消/收藏岗位
|
||||
function applyExhibitors() {
|
||||
const fairId = fairInfo.value.jobFairId;
|
||||
if (fairInfo.value.isCollection) {
|
||||
// $api.createRequest(`/app/fair/collection/${fairId}`, {}, 'DELETE').then((resData) => {
|
||||
// getCompanyInfo(fairId);
|
||||
// $api.msg('取消预约成功');
|
||||
// });
|
||||
$api.msg('已预约成功');
|
||||
} else {
|
||||
$api.createRequest(`/app/fair/collection/${fairId}`, {}, 'POST').then((resData) => {
|
||||
getCompanyInfo(fairId);
|
||||
$api.msg('预约成功');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toIOSDate(input) {
|
||||
if (!input) return null;
|
||||
if (input instanceof Date) return isNaN(input.getTime()) ? null : input;
|
||||
if (typeof input === 'number') {
|
||||
const d = new Date(input);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
if (typeof input !== 'string') return null;
|
||||
let s = input.trim();
|
||||
if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}(:\d{2})?$/.test(s)) {
|
||||
s = s.replace(' ', 'T');
|
||||
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(s)) {
|
||||
s = s + ':00';
|
||||
}
|
||||
}
|
||||
const d = new Date(s);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
function parseDateTime(datetimeStr) {
|
||||
if (!datetimeStr) return { time: '', date: '' };
|
||||
|
||||
const dateObj = toIOSDate(datetimeStr);
|
||||
|
||||
if (isNaN(dateObj.getTime())) return { time: '', date: '' }; // 无效时间
|
||||
|
||||
const year = dateObj.getFullYear();
|
||||
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(dateObj.getDate()).padStart(2, '0');
|
||||
const hours = String(dateObj.getHours()).padStart(2, '0');
|
||||
const minutes = String(dateObj.getMinutes()).padStart(2, '0');
|
||||
|
||||
return {
|
||||
time: `${hours}:${minutes}`,
|
||||
date: `${year}年${month}月${day}日`,
|
||||
};
|
||||
}
|
||||
|
||||
function getTimeStatus(startTimeStr, endTimeStr) {
|
||||
const now = new Date();
|
||||
const startTime = toIOSDate(startTimeStr);
|
||||
const endTime = toIOSDate(endTimeStr);
|
||||
|
||||
if (!startTime || !endTime) {
|
||||
return { status: 1, statusText: '时间异常' };
|
||||
}
|
||||
|
||||
let status = 0;
|
||||
let statusText = '开始中';
|
||||
if (now < startTime) {
|
||||
status = 2;
|
||||
statusText = '待开始';
|
||||
} else if (now > endTime) {
|
||||
status = 1;
|
||||
statusText = '已过期';
|
||||
} else {
|
||||
status = 0;
|
||||
statusText = '进行中';
|
||||
}
|
||||
return { status, statusText };
|
||||
}
|
||||
|
||||
function getHoursBetween(startTimeStr, endTimeStr) {
|
||||
const start = toIOSDate(startTimeStr);
|
||||
const end = toIOSDate(endTimeStr);
|
||||
if (!start || !end) return 0;
|
||||
const diffMs = end - start;
|
||||
const diffHours = diffMs / (1000 * 60 * 60);
|
||||
return +diffHours.toFixed(2);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.content{
|
||||
height: 100%
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
.content-top{
|
||||
padding: 28rpx
|
||||
padding-top: 50rpx
|
||||
display: flex
|
||||
flex-direction: row
|
||||
flex-wrap: nowrap
|
||||
.companyinfo-left{
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx
|
||||
}
|
||||
.companyinfo-right{
|
||||
flex: 1
|
||||
.row1{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
.row2{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
line-height: 45rpx;
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
}
|
||||
}
|
||||
}
|
||||
.locations{
|
||||
padding: 0 28rpx
|
||||
height: 86rpx;
|
||||
position: relative
|
||||
margin-bottom: 36rpx
|
||||
.location-img{
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 2rpx solid #EFEFEF;
|
||||
}
|
||||
.location-info{
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
.info{
|
||||
padding: 0 60rpx
|
||||
height: 100%
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
white-space: nowrap
|
||||
padding-top: rpx
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.info-text{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #9B9B9B;
|
||||
position: relative;
|
||||
padding-right: 20rpx
|
||||
|
||||
}
|
||||
.info-text::before{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 2rpx
|
||||
background: #9B9B9B;
|
||||
transform: translate(0, -75%) rotate(-45deg)
|
||||
}
|
||||
|
||||
.info-text::after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 2rpx
|
||||
background: #9B9B9B;
|
||||
transform: translate(0, -25%) rotate(45deg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.conetent-info{
|
||||
padding: 0 28rpx
|
||||
overflow: hidden;
|
||||
max-height: 0rpx;
|
||||
transition: max-height 0.3s ease;
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.info-desirption{
|
||||
margin-top: 12rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
text-align: justified;
|
||||
}
|
||||
.title2{
|
||||
margin-top: 48rpx
|
||||
}
|
||||
}
|
||||
.company-times{
|
||||
padding-top: 40rpx
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
.expanded {
|
||||
max-height: 1000rpx; // 足够显示完整内容
|
||||
}
|
||||
.expand{
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
white-space: nowrap
|
||||
justify-content: center
|
||||
margin-bottom: 46rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
.expand-img{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.expand-img-active{
|
||||
transform: rotate(180deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
.Detailscroll-view{
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: #F4F4F4;
|
||||
.views{
|
||||
padding: 28rpx
|
||||
.Detail-title{
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
.title{
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
.Detail-title::before{
|
||||
position: absolute
|
||||
content: '';
|
||||
left: -14rpx
|
||||
bottom: 0
|
||||
height: 16rpx;
|
||||
width: 108rpx;
|
||||
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
|
||||
border-radius: 8rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.cards{
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
margin-top: 22rpx;
|
||||
.card-company{
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
align-items: flex-start
|
||||
.company{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.salary{
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #4C6EFB;
|
||||
white-space: nowrap
|
||||
line-height: 48rpx
|
||||
}
|
||||
}
|
||||
.card-companyName{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
.card-tags{
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
.tag{
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
white-space: nowrap
|
||||
margin-right: 20rpx
|
||||
}
|
||||
}
|
||||
.card-bottom{
|
||||
margin-top: 32rpx
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.card-times{
|
||||
display: flex;
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
padding: 24rpx 30rpx 10rpx 30rpx
|
||||
.time-left,
|
||||
.time-right{
|
||||
text-align: center
|
||||
.left-date{
|
||||
font-weight: 500;
|
||||
font-size: 48rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.left-dateDay{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 12rpx
|
||||
}
|
||||
}
|
||||
.line{
|
||||
width: 40rpx;
|
||||
height: 0rpx;
|
||||
border: 2rpx solid #D4D4D4;
|
||||
margin-top: 64rpx
|
||||
}
|
||||
.time-center{
|
||||
text-align: center;
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
align-items: center
|
||||
.center-date{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FF881A;
|
||||
padding-top: 10rpx
|
||||
}
|
||||
.center-dateDay{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 6rpx
|
||||
line-height: 48rpx;
|
||||
width: 104rpx;
|
||||
height: 48rpx;
|
||||
background: #F9F9F9;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11,44,112,0.12);
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
padding: 40rpx 28rpx 20rpx 28rpx
|
||||
.btn-wq{
|
||||
height: 90rpx;
|
||||
background: #256BFA;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
line-height: 90rpx
|
||||
}
|
||||
.btn-desbel{
|
||||
background: #6697FB;
|
||||
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11,44,112,0.12);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
237
packageB/login.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<view class="wrap">
|
||||
<view class="login_index">
|
||||
<input class="input" placeholder="请输入账号" placeholder-class="inputplace" v-model="form.username" />
|
||||
<view class="login_yzm">
|
||||
<input class="input" type="password" placeholder="请输入密码" placeholder-class="inputplace"
|
||||
v-model="form.password" />
|
||||
</view>
|
||||
<view class="login_yzm">
|
||||
<input class="input" placeholder="请输入验证码" placeholder-class="inputplace" v-model="form.code" />
|
||||
<image class="yzm" :src="codeUrl" @click="getCodeImg"></image>
|
||||
</view>
|
||||
|
||||
<button class="com-btn" @click="register">登 录</button>
|
||||
</view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
reactive,
|
||||
inject,
|
||||
watch,
|
||||
ref,
|
||||
onMounted,
|
||||
onUnmounted
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad,
|
||||
onShow
|
||||
} from '@dcloudio/uni-app';
|
||||
const {
|
||||
$api,
|
||||
navTo,
|
||||
vacanciesTo,
|
||||
navBack
|
||||
} = inject("globalFunction");
|
||||
const placeholderStyle = 'font-size:30rpx'
|
||||
const checked = ref(true)
|
||||
const codeUrl = ref('')
|
||||
|
||||
const form = reactive({
|
||||
username: 'langchaojituan',
|
||||
password: 'Aa123456?',
|
||||
rememberMe: false,
|
||||
code: '',
|
||||
uuid: ''
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getCodeImg()
|
||||
})
|
||||
|
||||
function register() {
|
||||
if (!form.username) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请输入用户名'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!form.password) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请输入密码'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!form.uuid) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请输入验证码'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.showLoading({
|
||||
title: '登录中...',
|
||||
mask: true
|
||||
})
|
||||
$api.myRequest('/auth/login',form,'post',10100).then((res) => {
|
||||
console.log(res, 'res')
|
||||
uni.setStorageSync('Padmin-Token', res.data.access_token)
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
codeUrl.value = 'data:image/gif;base64,' + res.img
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '登录失败,请重试'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getCodeImg() {
|
||||
$api.myRequest('/code',{},'get',10100).then((resData) => {
|
||||
codeUrl.value = 'data:image/gif;base64,' + resData.img
|
||||
form.uuid = resData.uuid
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.wrap {
|
||||
background-color: #ffffff;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
|
||||
.lg-head {
|
||||
height: 480rpx;
|
||||
background: #46ca98;
|
||||
position: relative;
|
||||
|
||||
.view_logo {
|
||||
text-align: center;
|
||||
|
||||
.login_logo {
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
margin-top: 100rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.bg-cover {
|
||||
position: absolute;
|
||||
bottom: -4rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 30rpx;
|
||||
background-size: 100% 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login_index {
|
||||
font-size: 36rpx;
|
||||
font-weight: 500;
|
||||
width: 596rpx;
|
||||
margin: 0 auto;
|
||||
|
||||
::v-deep .is-input-border {
|
||||
border: 0;
|
||||
border-bottom: 1px solid #dcdfe6 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
::v-deep .uni-input-input {
|
||||
font-size: 32rpx;
|
||||
padding-left: 10rpx;
|
||||
}
|
||||
|
||||
::v-deep .uniui-contact-filled:before {
|
||||
color: #46ca98;
|
||||
font-size: 50rpx;
|
||||
}
|
||||
|
||||
::v-deep .uniui-locked-filled:before {
|
||||
color: #46ca98;
|
||||
font-size: 50rpx;
|
||||
}
|
||||
|
||||
.login_yzm {
|
||||
margin-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.yzm {
|
||||
width: 200rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.com-btn {
|
||||
height: 100rpx;
|
||||
background: #46ca98;
|
||||
border-radius: 50rpx;
|
||||
color: #fff;
|
||||
margin-top: 100rpx;
|
||||
}
|
||||
|
||||
.login_wt {
|
||||
margin: 0 auto;
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: rgba(134, 134, 136, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.lg-bottom {
|
||||
position: absolute;
|
||||
bottom: -3px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
.bottom-svg {
|
||||
position: absolute;
|
||||
bottom: -3px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.login_tongyi {
|
||||
|
||||
font-size: 26rpx;
|
||||
color: rgba(196, 196, 196, 1);
|
||||
width: 620rpx;
|
||||
margin: 32rpx auto;
|
||||
text-align: center;
|
||||
|
||||
text {
|
||||
color: rgba(86, 176, 236, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: 0 30rpx 0 80rpx;
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.inputplace {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
}
|
||||
</style>
|
||||
138
packageB/train/index.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<!-- <AppLayout title=""> -->
|
||||
<view class="tab-container">
|
||||
<image src="../../static/images/train/bj.jpg" mode=""></image>
|
||||
<view>
|
||||
<view class="btns" @click="jumps('/packageB/train/video/videoList')">
|
||||
<image src="/static/images/train/spxx-k.png" mode=""></image>
|
||||
<view>
|
||||
<text>培训视频</text>
|
||||
<view class="btn">
|
||||
<text>立即查看</text>
|
||||
<image src="/static/images/train/arrow.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns" @click="jumps('/packageB/train/practice/startPracticing')">
|
||||
<image src="/static/images/train/zxxl-k.png" mode=""></image>
|
||||
<view>
|
||||
<text>专项练习</text>
|
||||
<view class="btn">
|
||||
<text>立即查看</text>
|
||||
<image src="/static/images/train/arrow.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="btns" @click="jumps('')">
|
||||
<image src="/static/images/train/mnks-k.png" mode=""></image>
|
||||
<view>
|
||||
<text>模拟考试</text>
|
||||
<view class="btn">
|
||||
<text>立即查看</text>
|
||||
<image src="/static/images/train/arrow.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="btns" @click="jumps('')">
|
||||
<image src="/static/images/train/ctb-k.png" mode=""></image>
|
||||
<view>
|
||||
<text>错题本 </text>
|
||||
<view class="btn" style="margin-left: 13%;">
|
||||
<text>立即查看</text>
|
||||
<image src="/static/images/train/arrow.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- </AppLayout> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
|
||||
function jumps(url){
|
||||
navTo(url);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tab-container{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
// background: url('@/static/images/train/bj.jpg') center center no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
image{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
view{
|
||||
padding: 100rpx 28rpx 0;
|
||||
.btns{
|
||||
width: 100%
|
||||
height: 170rpx;
|
||||
border-radius: 5rpx
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box
|
||||
color: #000
|
||||
text-align: center
|
||||
margin-bottom: 50rpx
|
||||
position: relative
|
||||
image{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
view{
|
||||
padding: 0 0 0 10%;
|
||||
box-sizing: border-box;
|
||||
position: absolute
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #595959;
|
||||
.btn{
|
||||
margin-left: 8%;
|
||||
background-color: #3A92FF;
|
||||
position: static;
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center
|
||||
width: 140rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 5rpx
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
image{
|
||||
position: static;
|
||||
width: 14rpx;
|
||||
height: 22rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
8
packageB/train/mockExam/examList.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
361
packageB/train/practice/startPracticing.vue
Normal file
@@ -0,0 +1,361 @@
|
||||
<template>
|
||||
<div class="app-box">
|
||||
<image src="../../../static/images/train/bj.jpg" class="bjImg" mode=""></image>
|
||||
<div class="con-box">
|
||||
<div class="header">
|
||||
<div>正确率:0%</div>
|
||||
<div>用时:00:00</div>
|
||||
<div class="headBtn">暂停</div>
|
||||
</div>
|
||||
<div class="problemCard">
|
||||
<div v-for="(item,index) in problemData" :key="index">
|
||||
<template v-if="questionIndex==(index+1)">
|
||||
<div class="problemTitle">
|
||||
<span class="titleType" v-if="item.type=='single'">单选题</span>
|
||||
<span class="titleType" v-if="item.type=='multiple'">多选题</span>
|
||||
<span class="titleType" v-if="item.type=='judge'">判断题</span>
|
||||
<span>{{item.content}}</span>
|
||||
</div>
|
||||
<div class="options" v-if="item.type=='single'">
|
||||
<div class="opt" @click="selected(i)" :class="radio!==''&&i==radio?'active':''" v-for="(val,i) in parseOptions(item.trainChooses)">
|
||||
<div class="optLab">{{indexToLetter(i)}}</div>
|
||||
<span>{{val}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options" v-if="item.type=='multiple'">
|
||||
<div class="opt" @click="selected2(i)" :class="judgment(i)?'active':''" v-for="(val,i) in parseOptions(item.trainChooses)">
|
||||
<div class="optLab">{{indexToLetter(i)}}</div>
|
||||
<span>{{val}}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="options" v-if="item.type=='judge'">
|
||||
<div class="opt" @click="selected3('正确')" :class="radio2=='正确'?'active':''">
|
||||
<span>正确</span>
|
||||
</div>
|
||||
<div class="opt" @click="selected3('错误')" :class="radio2=='错误'?'active':''">
|
||||
<span>错误</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="analysis">
|
||||
<div class="analysisHead correct">
|
||||
<div>回答正确!</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<!-- <div class="analysisHead errors" v-if="judgWhether=='错误'">
|
||||
<div>回答错误!</div>
|
||||
<div></div>
|
||||
</div> -->
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">正确答案:</div>
|
||||
<div class="parse2" v-if="item.type=='single'" style="color: #30A0FF;font-weight: bold;">{{String.fromCharCode(65 + Number(item.answer))}}.</div>
|
||||
<div class="parse2" v-if="item.type=='multiple'" style="color: #30A0FF;font-weight: bold;">
|
||||
<span v-for="(val,i) in parseOptions(item.answer)">{{indexToLetter(val-1)}}.</span>
|
||||
</div>
|
||||
<div class="parse2" v-if="item.type=='judge'" style="color: #30A0FF;font-weight: bold;">{{item.answer}}</div>
|
||||
</div>
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">答案解析:</div>
|
||||
<div class="parse2">{{item.answerDesc}}</div>
|
||||
</div>
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">知识点:</div>
|
||||
<div>
|
||||
<el-tag style="margin-right: 10px;">{{item.knowledgePoint}}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="problemBtns">
|
||||
<div class="events">提交答案</div>
|
||||
<div>下一题</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footerLeft">
|
||||
<div class="zuo events"></div>
|
||||
<div class="you"></div>
|
||||
<div style="text-align: center;font-size: 24rpx;">
|
||||
<div>⭐</div>
|
||||
<div>收藏</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
|
||||
const radio = ref('');
|
||||
const radio2 = ref('');
|
||||
const checkList = ref([]);
|
||||
const questionIndex = ref(1);
|
||||
const correctIndex = ref(0);
|
||||
const errorsIndex = ref(0);
|
||||
const accuracyRate = ref(0);
|
||||
const problemData = reactive([
|
||||
{
|
||||
type:'single',
|
||||
content:"君不见黄河之水天上来,下一句是?",
|
||||
fraction:5,
|
||||
trainChooses:"奔流到海不复回,朝如青丝暮成雪,人生得意须尽欢,莫使金樽空对月",
|
||||
},{
|
||||
type:'multiple',
|
||||
content:"以下哪些是欧姆定律的适用条件?",
|
||||
fraction:8,
|
||||
trainChooses:"线性电阻,恒定温度,金属导体,半导体材料",
|
||||
|
||||
},{
|
||||
type:'judge',
|
||||
content:"功率越大的电器,其电阻值越小",
|
||||
fraction:2,
|
||||
trainChooses:[
|
||||
"正确",
|
||||
"错误",
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
function selected(i){
|
||||
radio.value=i
|
||||
};
|
||||
//多选
|
||||
function selected2(i){
|
||||
let arr=checkList.value.join(",")
|
||||
if(arr.indexOf(i) !== -1){
|
||||
const index = checkList.value.indexOf(i);
|
||||
if (index !== -1) {
|
||||
checkList.value.splice(index, 1);
|
||||
}
|
||||
}else{
|
||||
checkList.value.push(i)
|
||||
}
|
||||
};
|
||||
function judgment(i){
|
||||
let arr=checkList.value.join(",")
|
||||
if(arr.indexOf(i) !== -1){
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
};
|
||||
function selected3(i){
|
||||
radio2.value=i
|
||||
};
|
||||
// 解析选项
|
||||
function parseOptions(options) {
|
||||
if (!options) return [];
|
||||
// 假设options是字符串格式,以分号分隔
|
||||
if (typeof options === 'string') {
|
||||
return options.split(',').filter(opt => opt.trim());
|
||||
}
|
||||
// 如果是数组,直接返回
|
||||
if (Array.isArray(options)) {
|
||||
return options;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
function indexToLetter(index) {
|
||||
// 将索引转换为对应的字母
|
||||
return String.fromCharCode(65 + index);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.app-box{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
.bjImg{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.con-box{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top:0;
|
||||
z-index: 10;
|
||||
padding: 20rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
.header{
|
||||
height: 100rpx;
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: linear-gradient(0deg, #4285EC 0%, #0BBAFB 100%);
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
border-radius: 10rpx
|
||||
.headBtn{
|
||||
background: #499FFF;
|
||||
border-radius: 4px;
|
||||
width: 100rpx;
|
||||
text-align: center;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
}
|
||||
.problemCard{
|
||||
margin-top: 30rpx;
|
||||
.problemTitle{
|
||||
font-size: 30rpx;
|
||||
.titleType{
|
||||
display: inline-block;
|
||||
background-color: #499FFF;
|
||||
border-radius: 10rpx 10rpx 10rpx 0;
|
||||
padding: 8rpx 12rpx;
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
.options{
|
||||
margin-top: 30rpx;
|
||||
.opt{
|
||||
height: 60rpx;
|
||||
/* background-color: #F8F9FA; */
|
||||
border-radius: 5px;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 30rpx;
|
||||
box-sizing: border-box;
|
||||
color: #808080;
|
||||
font-size: 30rpx;
|
||||
.optLab{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
text-align: center;
|
||||
line-height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #8C8C8C;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
background: linear-gradient(90deg, #25A9F5 0%, #B1DBFF 100%);
|
||||
color: #fff!important;
|
||||
font-weight: bold;
|
||||
}
|
||||
.active>view{
|
||||
background-color: #fff!important;
|
||||
color: #25A9F5!important;
|
||||
}
|
||||
}
|
||||
.analysis{
|
||||
margin-top: 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 15rpx;
|
||||
border: 1px solid #10A8FF;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.analysisHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 32rpx;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.correct{
|
||||
color: #67C23A;
|
||||
}
|
||||
.errors{
|
||||
color: #F06A6A;
|
||||
}
|
||||
.analysisCon{
|
||||
margin-top: 30rpx;
|
||||
.parse1{
|
||||
font-size: 30rpx;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: bold;
|
||||
}
|
||||
.parse2{
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.problemBtns{
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
view{
|
||||
width: 140rpx
|
||||
height: 50rpx
|
||||
text-align: center
|
||||
line-height: 50rpx
|
||||
background-color: #10A8FF
|
||||
color: #fff
|
||||
font-size: 28rpx
|
||||
border-radius: 5rpx
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
border-top: 1px solid #ddd
|
||||
position: fixed
|
||||
bottom: 0
|
||||
left: 0
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
.footerLeft{
|
||||
display: flex
|
||||
align-items: center
|
||||
font-size: 30rpx;
|
||||
.zuo{
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-top: 2px solid #666
|
||||
border-left: 2px solid #666
|
||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||
margin-left: 50rpx;
|
||||
}
|
||||
.you{
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-right: 2px solid #666
|
||||
border-bottom: 2px solid #666
|
||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||
margin-left: 30rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.events{
|
||||
pointer-events: none; /* 这会禁用所有指针事件 */
|
||||
opacity: 0.5; /* 可选:改变透明度以视觉上表示不可点击 */
|
||||
cursor: not-allowed; /* 可选:改变鼠标光标样式 */
|
||||
}
|
||||
</style>
|
||||
316
packageB/train/video/videoDetail.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<AppLayout :title="title" :show-bg-image="false" @onScrollBottom="getDataList('add')">
|
||||
<!-- <template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template> -->
|
||||
<template #headContent>
|
||||
<view class="collection-search">
|
||||
<view class="search-content">
|
||||
<view class="header-input button-click">
|
||||
<uni-icons class="iconsearch" color="#6A6A6A" type="search" size="22"></uni-icons>
|
||||
<input
|
||||
class="input"
|
||||
v-model="searchKeyword"
|
||||
@confirm="searchVideo"
|
||||
placeholder="输入视频名称"
|
||||
placeholder-class="inputplace"
|
||||
/>
|
||||
<uni-icons
|
||||
v-if="searchKeyword"
|
||||
class="clear-icon"
|
||||
type="clear"
|
||||
size="24"
|
||||
color="#999"
|
||||
@click="clearSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="main-list">
|
||||
<view class="list-title">
|
||||
<text>视频列表</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="video-grid" v-if="pageState.list.length">
|
||||
<view
|
||||
v-for="video in pageState.list"
|
||||
:key="video.id || video.videoId"
|
||||
class="video-item"
|
||||
:style="getItemBackgroundStyle('video-bg.png')"
|
||||
@click="playVideo(video)"
|
||||
>
|
||||
<view class="video-cover">
|
||||
<image
|
||||
:src="video.coverImage || video.videoCover || '/static/icon/video.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="video-info">
|
||||
{{ video.title || video.videoName || '未命名视频' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, navBack } = inject('globalFunction');
|
||||
|
||||
// state
|
||||
const title = ref('');
|
||||
const searchKeyword = ref('');
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 12,
|
||||
search: {},
|
||||
});
|
||||
const baseUrl = 'http://10.110.145.145/images/train/';
|
||||
const getItemBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl + imageName})`,
|
||||
backgroundSize: 'cover', // 覆盖整个容器
|
||||
backgroundPosition: 'center', // 居中
|
||||
backgroundRepeat: 'no-repeat'
|
||||
});
|
||||
// 模拟视频数据
|
||||
const mockVideoData = [
|
||||
{
|
||||
id: '1',
|
||||
title: '职业技能培训基础课程',
|
||||
coverImage: '/static/icon/server1.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '面试技巧分享',
|
||||
coverImage: '/static/icon/server2.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '简历制作指南',
|
||||
coverImage: '/static/icon/server3.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '职场沟通技巧',
|
||||
coverImage: '/static/icon/server4.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '职业规划讲座',
|
||||
coverImage: '/static/icon/flame.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '行业趋势分析',
|
||||
coverImage: '/static/icon/flame2.png',
|
||||
videoUrl: ''
|
||||
}
|
||||
];
|
||||
|
||||
onLoad(() => {
|
||||
getDataList('refresh');
|
||||
});
|
||||
|
||||
// 搜索视频
|
||||
function searchVideo() {
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 清除搜索内容
|
||||
function clearSearch() {
|
||||
searchKeyword.value = '';
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 获取视频列表
|
||||
function getDataList(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 1;
|
||||
}
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
|
||||
// 模拟API请求延迟
|
||||
setTimeout(() => {
|
||||
// 在实际项目中,这里应该调用真实的API接口
|
||||
// 目前使用模拟数据
|
||||
let filteredList = [...mockVideoData];
|
||||
|
||||
// 如果有搜索关键词,进行过滤
|
||||
if (searchKeyword.value.trim()) {
|
||||
filteredList = filteredList.filter(video =>
|
||||
video.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
const start = 0;
|
||||
const end = pageState.pageSize;
|
||||
const pageData = filteredList.slice(start, end);
|
||||
|
||||
if (type === 'add') {
|
||||
pageState.list = [...pageState.list, ...pageData];
|
||||
} else {
|
||||
pageState.list = pageData;
|
||||
}
|
||||
|
||||
pageState.total = filteredList.length;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 播放视频
|
||||
function playVideo(video) {
|
||||
// 在实际项目中,这里应该导航到视频播放页面
|
||||
// 或者调用视频播放组件
|
||||
console.log('播放视频:', video.title);
|
||||
// 示例:navTo(`/pages/videoPlayer/videoPlayer?id=${video.id}`);
|
||||
$api.msg(`准备播放: ${video.title}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.collection-search{
|
||||
padding: 10rpx 20rpx;
|
||||
.search-content{
|
||||
position: relative
|
||||
display: flex
|
||||
align-items: center
|
||||
padding: 14rpx 0
|
||||
.header-input{
|
||||
padding: 0
|
||||
width: calc(100%);
|
||||
position: relative
|
||||
.iconsearch{
|
||||
position: absolute
|
||||
left: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
}
|
||||
.input{
|
||||
padding: 0 80rpx 0 80rpx
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
border: 2rpx solid #ECECEC
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.clear-icon{
|
||||
position: absolute
|
||||
right: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
cursor: pointer
|
||||
}
|
||||
.inputplace{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-list{
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 20rpx 28rpx 20rpx;
|
||||
margin:10rpx 30rpx ;
|
||||
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.list-title{
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #404040;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.title-line{
|
||||
position: absolute;
|
||||
bottom: -10rpx;
|
||||
left: 36rpx;
|
||||
width: 70rpx;
|
||||
height: 8rpx;
|
||||
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.video-grid{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
.video-item{
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s;
|
||||
padding: 20rpx
|
||||
}
|
||||
.video-item:active{
|
||||
transform: scale(0.98);
|
||||
}
|
||||
.video-cover{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 56.25%; /* 16:9 比例 */
|
||||
background: #f0f0f0;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
.video-cover image{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.video-info{
|
||||
padding: 16rpx 16rpx 0 16rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
.video-title{
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
316
packageB/train/video/videoList.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<AppLayout :title="title" :show-bg-image="false" @onScrollBottom="getDataList('add')">
|
||||
<!-- <template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template> -->
|
||||
<template #headContent>
|
||||
<view class="collection-search">
|
||||
<view class="search-content">
|
||||
<view class="header-input button-click">
|
||||
<uni-icons class="iconsearch" color="#6A6A6A" type="search" size="22"></uni-icons>
|
||||
<input
|
||||
class="input"
|
||||
v-model="searchKeyword"
|
||||
@confirm="searchVideo"
|
||||
placeholder="输入视频名称"
|
||||
placeholder-class="inputplace"
|
||||
/>
|
||||
<uni-icons
|
||||
v-if="searchKeyword"
|
||||
class="clear-icon"
|
||||
type="clear"
|
||||
size="24"
|
||||
color="#999"
|
||||
@click="clearSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="main-list">
|
||||
<view class="list-title">
|
||||
<text>视频列表</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="video-grid" v-if="pageState.list.length">
|
||||
<view
|
||||
v-for="video in pageState.list"
|
||||
:key="video.id || video.videoId"
|
||||
class="video-item"
|
||||
:style="getItemBackgroundStyle('video-bg.png')"
|
||||
@click="playVideo(video)"
|
||||
>
|
||||
<view class="video-cover">
|
||||
<image
|
||||
:src="video.coverImage || video.videoCover || '/static/icon/video.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="video-info">
|
||||
{{ video.title || video.videoName || '未命名视频' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, navBack } = inject('globalFunction');
|
||||
|
||||
// state
|
||||
const title = ref('');
|
||||
const searchKeyword = ref('');
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 12,
|
||||
search: {},
|
||||
});
|
||||
const baseUrl = 'http://10.110.145.145/images/train/';
|
||||
const getItemBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl + imageName})`,
|
||||
backgroundSize: 'cover', // 覆盖整个容器
|
||||
backgroundPosition: 'center', // 居中
|
||||
backgroundRepeat: 'no-repeat'
|
||||
});
|
||||
// 模拟视频数据
|
||||
const mockVideoData = [
|
||||
{
|
||||
id: '1',
|
||||
title: '职业技能培训基础课程',
|
||||
coverImage: '/static/icon/server1.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '面试技巧分享',
|
||||
coverImage: '/static/icon/server2.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '简历制作指南',
|
||||
coverImage: '/static/icon/server3.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '职场沟通技巧',
|
||||
coverImage: '/static/icon/server4.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '职业规划讲座',
|
||||
coverImage: '/static/icon/flame.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '行业趋势分析',
|
||||
coverImage: '/static/icon/flame2.png',
|
||||
videoUrl: ''
|
||||
}
|
||||
];
|
||||
|
||||
onLoad(() => {
|
||||
getDataList('refresh');
|
||||
});
|
||||
|
||||
// 搜索视频
|
||||
function searchVideo() {
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 清除搜索内容
|
||||
function clearSearch() {
|
||||
searchKeyword.value = '';
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 获取视频列表
|
||||
function getDataList(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 1;
|
||||
}
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
|
||||
// 模拟API请求延迟
|
||||
setTimeout(() => {
|
||||
// 在实际项目中,这里应该调用真实的API接口
|
||||
// 目前使用模拟数据
|
||||
let filteredList = [...mockVideoData];
|
||||
|
||||
// 如果有搜索关键词,进行过滤
|
||||
if (searchKeyword.value.trim()) {
|
||||
filteredList = filteredList.filter(video =>
|
||||
video.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
const start = 0;
|
||||
const end = pageState.pageSize;
|
||||
const pageData = filteredList.slice(start, end);
|
||||
|
||||
if (type === 'add') {
|
||||
pageState.list = [...pageState.list, ...pageData];
|
||||
} else {
|
||||
pageState.list = pageData;
|
||||
}
|
||||
|
||||
pageState.total = filteredList.length;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 播放视频
|
||||
function playVideo(video) {
|
||||
// 在实际项目中,这里应该导航到视频播放页面
|
||||
// 或者调用视频播放组件
|
||||
console.log('播放视频:', video.title);
|
||||
// 示例:navTo(`/pages/videoPlayer/videoPlayer?id=${video.id}`);
|
||||
$api.msg(`准备播放: ${video.title}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.collection-search{
|
||||
padding: 10rpx 20rpx;
|
||||
.search-content{
|
||||
position: relative
|
||||
display: flex
|
||||
align-items: center
|
||||
padding: 14rpx 0
|
||||
.header-input{
|
||||
padding: 0
|
||||
width: calc(100%);
|
||||
position: relative
|
||||
.iconsearch{
|
||||
position: absolute
|
||||
left: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
}
|
||||
.input{
|
||||
padding: 0 80rpx 0 80rpx
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
border: 2rpx solid #ECECEC
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.clear-icon{
|
||||
position: absolute
|
||||
right: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
cursor: pointer
|
||||
}
|
||||
.inputplace{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-list{
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 20rpx 28rpx 20rpx;
|
||||
margin:10rpx 30rpx ;
|
||||
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.list-title{
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #404040;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.title-line{
|
||||
position: absolute;
|
||||
bottom: -10rpx;
|
||||
left: 36rpx;
|
||||
width: 70rpx;
|
||||
height: 8rpx;
|
||||
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.video-grid{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
.video-item{
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s;
|
||||
padding: 20rpx
|
||||
}
|
||||
.video-item:active{
|
||||
transform: scale(0.98);
|
||||
}
|
||||
.video-cover{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 56.25%; /* 16:9 比例 */
|
||||
background: #f0f0f0;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
.video-cover image{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.video-info{
|
||||
padding: 16rpx 16rpx 0 16rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
.video-title{
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
340
pages.json
@@ -3,16 +3,18 @@
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "青岛智慧就业平台",
|
||||
// #ifdef H5
|
||||
"navigationBarTitleText": "喀什智慧就业平台",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
// #ifdef H5
|
||||
"navigationStyle": "custom"
|
||||
// #endif
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/mine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
@@ -20,28 +22,32 @@
|
||||
"path": "pages/msglog/msglog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": false
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom",
|
||||
// "enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/careerfair/careerfair",
|
||||
"style": {
|
||||
"navigationBarTitleText": "招聘会"
|
||||
"navigationBarTitleText": "招聘会",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/complete-info/complete-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补全信息"
|
||||
"navigationBarTitleText": "补全信息",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/complete-info/company-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "企业信息"
|
||||
"navigationBarTitleText": "企业信息",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
@@ -68,30 +74,102 @@
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/test/tabbar-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "TabBar测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/test/homepage-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页内容测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/test/tabbar-user-type-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "TabBar用户类型测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/test/company-search-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "企业搜索功能测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/test/company-mine-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "企业我的页面测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/job/publishJob",
|
||||
"style": {
|
||||
"navigationBarTitleText": "发布岗位",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTitleText": "发布岗位"
|
||||
// "navigationStyle": "custom",
|
||||
// "disableScroll": false,
|
||||
// "enablePullDownRefresh": false,
|
||||
// "onReachBottomDistance": 50,
|
||||
// "backgroundColor": "#f5f5f5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/job/companySearch",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择企业",
|
||||
"navigationStyle": "custom",
|
||||
"disableScroll": false,
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundColor": "#f5f5f5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/chat/chat",
|
||||
"style": {
|
||||
"navigationBarTitleText": "AI+",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#4778EC",
|
||||
"navigationBarTextStyle": "white",
|
||||
"enablePullDownRefresh": false,
|
||||
"enablePullDownRefresh": false
|
||||
// #ifdef H5
|
||||
"navigationStyle": "custom"
|
||||
// "navigationStyle": "custom"
|
||||
//#endif
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/search/search",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTitleText": ""
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/company-mine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/company-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "企业信息",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/edit-company-contacts",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑联系人",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +179,11 @@
|
||||
"pages": [
|
||||
{
|
||||
"path" : "pages/addWorkExperience/addWorkExperience",
|
||||
"style" :
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "添加工作经历",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},{
|
||||
"path": "pages/choiceness/choiceness",
|
||||
@@ -119,41 +198,43 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "职位详情",
|
||||
"navigationBarBackgroundColor": "#4778EC",
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
}, {
|
||||
"path": "pages/UnitDetails/UnitDetails",
|
||||
"style": {
|
||||
"navigationBarTitleText": "单位详情",
|
||||
"navigationBarBackgroundColor": "#4778EC",
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTitleText": "单位详情"
|
||||
// "navigationBarBackgroundColor": "#4778EC",
|
||||
// "navigationBarTextStyle": "white"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
}, {
|
||||
"path": "pages/exhibitors/exhibitors",
|
||||
"style": {
|
||||
"navigationBarTitleText": "参展单位",
|
||||
"navigationBarBackgroundColor": "#4778EC",
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"navigationBarTextStyle": "black"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
}, {
|
||||
}, {
|
||||
"path": "pages/myResume/myResume",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的简历",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
}, {
|
||||
}, {
|
||||
"path": "pages/Intendedposition/Intendedposition",
|
||||
"style": {
|
||||
"navigationBarTitleText": "投递记录",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
}, {
|
||||
}, {
|
||||
"path": "pages/collection/collection",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的收藏",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
@@ -162,6 +243,7 @@
|
||||
"path": "pages/browseJob/browseJob",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的浏览",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
@@ -170,6 +252,7 @@
|
||||
"path": "pages/addPosition/addPosition",
|
||||
"style": {
|
||||
"navigationBarTitleText": "添加岗位",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
@@ -184,6 +267,7 @@
|
||||
"path": "pages/personalInfo/personalInfo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人信息",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
@@ -191,13 +275,15 @@
|
||||
"path": "pages/jobExpect/jobExpect",
|
||||
"style": {
|
||||
"navigationBarTitleText": "求职期望",
|
||||
"navigationStyle": "custom"
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/reservation/reservation",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的预约",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
@@ -205,6 +291,7 @@
|
||||
"path": "pages/choicenessList/choicenessList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "精选企业",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
@@ -213,6 +300,7 @@
|
||||
"path": "pages/newJobPosition/newJobPosition",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新职位推荐",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
@@ -220,6 +308,7 @@
|
||||
"path": "pages/systemNotification/systemNotification",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统通知",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
@@ -235,6 +324,7 @@
|
||||
"path": "pages/moreJobs/moreJobs",
|
||||
"style": {
|
||||
"navigationBarTitleText": "更多岗位",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
@@ -242,6 +332,7 @@
|
||||
"path": "pages/collection/compare",
|
||||
"style": {
|
||||
"navigationBarTitleText": " 岗位对比",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
@@ -249,150 +340,71 @@
|
||||
"path": "pages/myResume/corporateInformation",
|
||||
"style": {
|
||||
"navigationBarTitleText": " 企业详情",
|
||||
"navigationBarTitleTextSize": "30rpx",
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "packageB",
|
||||
"pages": [
|
||||
{
|
||||
"path" : "pages/search/search",
|
||||
"style" : {
|
||||
"navigationBarTitleText" : "生涯规划",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
"root": "packageB",
|
||||
"pages": [
|
||||
{
|
||||
"path" : "jobFair/detail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "招聘会详情",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "login",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "登录",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/job/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "职业库"
|
||||
}
|
||||
"path" : "train/index",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "技能评价",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/job/midList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "职业库-中类"
|
||||
}
|
||||
"path" : "train/practice/startPracticing",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "专项训练",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/job/smallList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "职业库-小类"
|
||||
}
|
||||
"path" : "train/video/videoList",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "视频学习",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/job/details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "职业详情"
|
||||
}
|
||||
"path" : "train/video/videoDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "视频详情",
|
||||
"navigationBarTitleTextSize": "30rpx"
|
||||
// "navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userCenter/personDocument",
|
||||
"style": {
|
||||
"navigationBarTitleText": "生涯档案",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userCenter/careerCompass",
|
||||
"style": {
|
||||
"navigationBarTitleText": "生涯罗盘",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userCenter/learningPlan",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学业规划",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userCenter/smartTarget",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学业规划",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userCenter/fillInInformation",
|
||||
"style": {
|
||||
"navigationBarTitleText": "完善个人信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pagesTest/testList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "生涯测评",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pagesTest/customTestTitle",
|
||||
"style": {
|
||||
"navigationBarTitleText": "自定义测评",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pagesTest/interestTestTitle",
|
||||
"style": {
|
||||
"navigationBarTitleText": "职业兴趣测评",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pagesTest/workValuesTestTitle",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作价值观测评",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pagesTest/personalTestTitle",
|
||||
"style": {
|
||||
"navigationBarTitleText": "人格测评",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testReport/workValuesTestReport",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作价值观测评报告",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testReport/multipleAbilityTestReport",
|
||||
"style": {
|
||||
"navigationBarTitleText": "多元能力测评报告",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testReport/generalCareerTestReport",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通用职业能力测评报告",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testReport/personalTestReport",
|
||||
"style": {
|
||||
"navigationBarTitleText": "人格测评报告",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testReport/interestTestReport",
|
||||
"style": {
|
||||
"navigationBarTitleText": "职业兴趣测评报告",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
},{
|
||||
"root": "packageRc",
|
||||
"pages": [
|
||||
@@ -492,13 +504,14 @@
|
||||
"selectedIconPath": "static/tabbar/mined.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
],
|
||||
},
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"navigationBarTitleTextSize": "18px"
|
||||
// "enablePullDownRefresh": false,
|
||||
// "navigationStyle": "custom"
|
||||
},
|
||||
@@ -508,8 +521,9 @@
|
||||
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
|
||||
"^IconfontIcon$": "@/components/IconfontIcon/IconfontIcon.vue",
|
||||
"^WxAuthLogin$": "@/components/WxAuthLogin/WxAuthLogin.vue",
|
||||
"^AppLayout$": "@/components/AppLayout/AppLayout.vue"
|
||||
"^AppLayout$": "@/components/AppLayout/AppLayout.vue",
|
||||
"^CustomTabBar$": "@/components/CustomTabBar/CustomTabBar.vue"
|
||||
}
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="2" />
|
||||
|
||||
<!-- 微信授权登录弹窗 -->
|
||||
<WxAuthLogin ref="wxAuthLoginRef" @success="handleLoginSuccess"></WxAuthLogin>
|
||||
<!-- 抽屉遮罩层 -->
|
||||
<view v-if="isDrawerOpen" class="overlay" @click="toggleDrawer"></view>
|
||||
|
||||
@@ -71,13 +76,15 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, nextTick, computed } from 'vue';
|
||||
import { ref, inject, nextTick, computed, onMounted, onUnmounted } from 'vue';
|
||||
const { $api, navTo, insertSortData, config } = inject('globalFunction');
|
||||
import { onLoad, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import useChatGroupDBStore from '@/stores/userChatGroupStore';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { tabbarManager } from '@/utils/tabbarManager';
|
||||
import aiPaging from './components/ai-paging.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import WxAuthLogin from '@/components/WxAuthLogin/WxAuthLogin.vue';
|
||||
const { isTyping, tabeList, chatSessionID } = storeToRefs(useChatGroupDBStore());
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
const isDrawerOpen = ref(false);
|
||||
@@ -85,6 +92,7 @@ const scrollIntoView = ref(false);
|
||||
|
||||
const searchText = ref('');
|
||||
const paging = ref(null);
|
||||
const wxAuthLoginRef = ref(null);
|
||||
|
||||
// 实时过滤
|
||||
const filteredList = computed(() => {
|
||||
@@ -103,8 +111,27 @@ onShow(() => {
|
||||
nextTick(() => {
|
||||
paging.value?.closeFile();
|
||||
});
|
||||
// 更新自定义tabbar选中状态
|
||||
tabbarManager.updateSelected(2);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 监听退出登录事件,显示微信登录弹窗
|
||||
uni.$on('showLoginModal', () => {
|
||||
wxAuthLoginRef.value?.open();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('showLoginModal');
|
||||
});
|
||||
|
||||
// 登录成功回调
|
||||
const handleLoginSuccess = () => {
|
||||
console.log('登录成功');
|
||||
// 可以在这里添加登录成功后的处理逻辑
|
||||
};
|
||||
|
||||
onHide(() => {
|
||||
paging.value?.handleTouchCancel();
|
||||
if (isDrawerOpen.value) {
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<template>
|
||||
<view class="chat-container">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="chat-background">
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<view class="chat-background" v-fade:600="!messages.length">
|
||||
<!-- #endif -->
|
||||
<view class="chat-background" v-if="!messages.length">
|
||||
<image class="backlogo" src="/static/icon/backAI.png"></image>
|
||||
<view class="back-rowTitle">嗨!欢迎使用{{ config.appInfo.areaName }}AI智能求职</view>
|
||||
<view class="back-rowText">
|
||||
@@ -24,6 +20,28 @@
|
||||
<view class="message">{{ recognizedText }} {{ lastFinalText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<view class="chat-background" v-if="!messages.length">
|
||||
<image class="backlogo" src="/static/icon/backAI.png"></image>
|
||||
<view class="back-rowTitle">嗨!欢迎使用{{ config.appInfo.areaName }}AI智能求职</view>
|
||||
<view class="back-rowText">
|
||||
我可以根据您的简历和求职需求,帮你精准匹配{{ config.appInfo.areaName }}互联网招聘信息,对比招聘信息的优缺点,提供面试指导等,请把你的任务交给我吧~
|
||||
</view>
|
||||
<view class="back-rowh3">猜你所想</view>
|
||||
<view
|
||||
class="back-rowmsg button-click"
|
||||
v-for="(item, index) in queries"
|
||||
:key="index"
|
||||
@click="sendMessageGuess(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
<view class="chat-item self" v-if="isRecording">
|
||||
<view class="message">{{ recognizedText }} {{ lastFinalText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<scroll-view class="chat-list scrollView" :scroll-top="scrollTop" :scroll-y="true" scroll-with-animation>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="chat-list list-content">
|
||||
@@ -946,19 +964,19 @@ image-margin-top = 40rpx
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.list-content {
|
||||
padding: 0 44rpx 44rpx 44rpx;
|
||||
padding: 0 44rpx 10rpx 44rpx;
|
||||
}
|
||||
.chat-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
margin-bottom: 10rpx;
|
||||
width: 100%;
|
||||
}
|
||||
.chat-item.self {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.message
|
||||
margin-top: 40rpx
|
||||
margin-top: 0rpx
|
||||
// max-width: 80%;
|
||||
width: 100%;
|
||||
word-break: break-word;
|
||||
@@ -1003,10 +1021,12 @@ image-margin-top = 40rpx
|
||||
}
|
||||
.input-area {
|
||||
padding: 32rpx 28rpx 24rpx 28rpx;
|
||||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom) + 40rpx - 40rpx);
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
|
||||
transition: height 2s ease-in-out;
|
||||
z-index: 1001;
|
||||
}
|
||||
.input-area::after
|
||||
position: absolute
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<AppLayout title="企业信息">
|
||||
<AppLayout>
|
||||
<view class="company-info-container">
|
||||
<!-- 头部信息 -->
|
||||
<view class="header-info">
|
||||
@@ -79,7 +79,7 @@
|
||||
<view class="label">是否是就业见习基地</view>
|
||||
<view class="input-content">
|
||||
<text class="input-text" :class="{ placeholder: formData.enterpriseType === null }">
|
||||
{{ formData.enterpriseType === null ? '请选择' : (formData.enterpriseType ? '是' : '否') }}
|
||||
{{ formData.enterpriseType === null ? '请选择' : (formData.enterpriseType === 0 ? '是' : '否') }}
|
||||
</text>
|
||||
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
||||
</view>
|
||||
@@ -131,6 +131,15 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 企业规模 -->
|
||||
<view class="form-item clickable" @click="selectScale">
|
||||
<view class="label">企业规模</view>
|
||||
<view class="input-content">
|
||||
<input class="input-con" v-model="formData.scaleText" disabled placeholder="请选择企业规模" />
|
||||
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系人信息列表 -->
|
||||
<view class="contact-section">
|
||||
<view class="section-title">联系人信息</view>
|
||||
@@ -225,9 +234,11 @@ import { onLoad } from '@dcloudio/uni-app'
|
||||
import AreaCascadePicker from '@/components/area-cascade-picker/area-cascade-picker.vue'
|
||||
import SelectPopup from '@/components/selectPopup/selectPopup.vue'
|
||||
import useDictStore from '@/stores/useDictStore'
|
||||
import useUserStore from '@/stores/useUserStore'
|
||||
|
||||
const { $api } = inject('globalFunction')
|
||||
const dictStore = useDictStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
@@ -241,11 +252,13 @@ const formData = reactive({
|
||||
legalPersonName: '',
|
||||
nature: '', // 企业类型
|
||||
natureText: '', // 企业类型显示文本
|
||||
enterpriseType: null, // 是否是就业见习基地 (true/false/null)
|
||||
enterpriseType: null, // 是否是就业见习基地 (0=是, 1=否, null=未选择)
|
||||
legalIdCard: '', // 法人身份证号
|
||||
legalPhone: '', // 法人联系方式
|
||||
industryType: '', // 是否是本地重点发展产业
|
||||
isLocalCompany: null, // 是否是本地企业 (true/false/null)
|
||||
scale: '', // 企业规模
|
||||
scaleText: '', // 企业规模显示文本
|
||||
companyContactList: [
|
||||
{ contactPerson: '', contactPersonPhone: '' }
|
||||
]
|
||||
@@ -311,7 +324,8 @@ const completionPercentage = computed(() => {
|
||||
formData.legalIdCard,
|
||||
formData.legalPhone,
|
||||
formData.industryType,
|
||||
formData.isLocalCompany !== null ? 'filled' : ''
|
||||
formData.isLocalCompany !== null ? 'filled' : '',
|
||||
formData.scale
|
||||
]
|
||||
|
||||
// 检查联系人信息
|
||||
@@ -445,7 +459,7 @@ const selectEmploymentBase = () => {
|
||||
uni.showActionSheet({
|
||||
itemList: ['是', '否'],
|
||||
success: (res) => {
|
||||
formData.enterpriseType = res.tapIndex === 0
|
||||
formData.enterpriseType = res.tapIndex === 0 ? 0 : 1
|
||||
updateCompletion()
|
||||
$api.msg('选择成功')
|
||||
}
|
||||
@@ -464,6 +478,73 @@ const selectLocalCompany = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 企业规模选项数据从字典中获取
|
||||
const scaleOptions = computed(() => {
|
||||
const scaleData = dictStore.state?.scale || []
|
||||
console.log('企业规模选项数据:', scaleData)
|
||||
return scaleData
|
||||
})
|
||||
|
||||
// 选择企业规模
|
||||
const selectScale = () => {
|
||||
console.log('点击企业规模,当前数据:', scaleOptions.value)
|
||||
console.log('字典store状态:', dictStore.state.scale)
|
||||
|
||||
// 获取企业规模选项,优先使用字典数据,失败时使用备用数据
|
||||
let options = scaleOptions.value
|
||||
|
||||
if (!options || !options.length) {
|
||||
console.log('企业规模数据为空,尝试重新加载')
|
||||
// 尝试重新加载字典数据
|
||||
dictStore.getDictData().then(() => {
|
||||
if (dictStore.state.scale && dictStore.state.scale.length > 0) {
|
||||
selectScale() // 递归调用
|
||||
} else {
|
||||
// 使用备用数据
|
||||
console.log('使用备用企业规模数据')
|
||||
options = fallbackScaleOptions
|
||||
showScaleSelector(options)
|
||||
}
|
||||
}).catch(() => {
|
||||
// 使用备用数据
|
||||
console.log('字典加载失败,使用备用企业规模数据')
|
||||
options = fallbackScaleOptions
|
||||
showScaleSelector(options)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
showScaleSelector(options)
|
||||
}
|
||||
|
||||
// 备用企业规模选项(当字典数据加载失败时使用)
|
||||
const fallbackScaleOptions = [
|
||||
{ label: '1-10人', value: '1' },
|
||||
{ label: '11-50人', value: '2' },
|
||||
{ label: '51-100人', value: '3' },
|
||||
{ label: '101-500人', value: '4' },
|
||||
{ label: '501-1000人', value: '5' },
|
||||
{ label: '1000人以上', value: '6' }
|
||||
]
|
||||
|
||||
// 显示企业规模选择器
|
||||
const showScaleSelector = (options) => {
|
||||
console.log('企业规模选项列表:', options)
|
||||
|
||||
openSelectPopup({
|
||||
title: '企业规模',
|
||||
maskClick: true,
|
||||
data: [options],
|
||||
success: (_, [value]) => {
|
||||
console.log('选择的企业规模:', value)
|
||||
formData.scale = value.value
|
||||
formData.scaleText = value.label
|
||||
updateCompletion()
|
||||
$api.msg('企业规模选择成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 添加联系人
|
||||
const addContact = () => {
|
||||
@@ -573,6 +654,11 @@ const confirm = () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!formData.scale.trim()) {
|
||||
$api.msg('请选择企业规模')
|
||||
return
|
||||
}
|
||||
|
||||
// 验证身份证号格式
|
||||
const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
|
||||
if (!idCardRegex.test(formData.legalIdCard)) {
|
||||
@@ -623,6 +709,7 @@ const confirm = () => {
|
||||
legalPhone: formData.legalPhone,
|
||||
industryType: formData.industryType,
|
||||
isLocalCompany: formData.isLocalCompany,
|
||||
scale: formData.scaleText,
|
||||
companyContactList: formData.companyContactList.filter(contact => contact.contactPerson.trim() && contact.contactPersonPhone.trim())
|
||||
}
|
||||
|
||||
@@ -631,11 +718,30 @@ const confirm = () => {
|
||||
company: companyData
|
||||
}
|
||||
|
||||
$api.createRequest('/app/user/registerUser', submitData, 'post')
|
||||
.then((resData) => {
|
||||
$api.createRequest('/registerUser', submitData, 'post')
|
||||
.then(async (resData) => {
|
||||
uni.hideLoading()
|
||||
$api.msg('企业信息保存成功')
|
||||
|
||||
// 如果接口返回了token,需要重新保存token
|
||||
if (resData.token) {
|
||||
try {
|
||||
await userStore.loginSetToken(resData.token)
|
||||
console.log('Token已更新:', resData.token)
|
||||
} catch (error) {
|
||||
console.error('更新Token失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 保存成功后,重新获取用户信息并更新缓存
|
||||
try {
|
||||
await userStore.getUserResume()
|
||||
console.log('用户信息已更新到缓存')
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error)
|
||||
// 即使获取用户信息失败,也不影响页面跳转
|
||||
}
|
||||
|
||||
// 跳转到首页或企业相关页面
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
@@ -720,10 +826,12 @@ defineExpose({
|
||||
font-size: 28rpx
|
||||
color: #333
|
||||
text-align: right
|
||||
line-height: 1.4
|
||||
|
||||
&::placeholder
|
||||
color: #999
|
||||
font-size: 26rpx
|
||||
font-size: 28rpx
|
||||
line-height: 1.4
|
||||
|
||||
.input-con
|
||||
flex: 1
|
||||
@@ -733,10 +841,12 @@ defineExpose({
|
||||
background: transparent
|
||||
border: none
|
||||
outline: none
|
||||
line-height: 1.4
|
||||
|
||||
&::placeholder
|
||||
color: #999
|
||||
font-size: 26rpx
|
||||
font-size: 28rpx
|
||||
line-height: 1.4
|
||||
|
||||
.input-content
|
||||
flex: 1
|
||||
@@ -752,7 +862,8 @@ defineExpose({
|
||||
|
||||
&.placeholder
|
||||
color: #999
|
||||
font-size: 26rpx
|
||||
font-size: 28rpx
|
||||
line-height: 1.4
|
||||
|
||||
&.intro-text
|
||||
max-height: 80rpx
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<view class="wxaddress">{{ config.appInfo.areaName }}公共就业和人才服务中心</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<view class="content-one">
|
||||
<view>
|
||||
<view class="content-title">
|
||||
@@ -33,17 +33,19 @@
|
||||
<text>/2</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeExperience">
|
||||
<view class="input-titile">工作经验</view>
|
||||
<input
|
||||
class="input-con"
|
||||
v-model="state.experienceText"
|
||||
disabled
|
||||
placeholder="请选择您的工作经验"
|
||||
<view class="content-input" :class="{ 'input-error': nameError }">
|
||||
<view class="input-titile">姓名</view>
|
||||
<input
|
||||
class="input-con2"
|
||||
v-model="fromValue.name"
|
||||
maxlength="18"
|
||||
placeholder="请输入姓名"
|
||||
@input="validateName"
|
||||
/>
|
||||
<view v-if="nameError" class="error-message">{{ nameError }}</view>
|
||||
</view>
|
||||
<view class="content-sex">
|
||||
<view class="sex-titile">求职区域</view>
|
||||
<view class="content-sex" :class="{ 'input-error': sexError }">
|
||||
<view class="sex-titile">性别</view>
|
||||
<view class="sext-ri">
|
||||
<view
|
||||
class="sext-box"
|
||||
@@ -61,6 +63,28 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="sexError" class="error-message">{{ sexError }}</view>
|
||||
<view class="content-input" :class="{ 'input-error': ageError }">
|
||||
<view class="input-titile">年龄</view>
|
||||
<input
|
||||
class="input-con2"
|
||||
v-model="fromValue.age"
|
||||
maxlength="3"
|
||||
placeholder="请输入年龄"
|
||||
@input="validateAge"
|
||||
/>
|
||||
<view v-if="ageError" class="error-message">{{ ageError }}</view>
|
||||
</view>
|
||||
<view class="content-input" :class="{ 'input-error': experienceError }" @click="changeExperience">
|
||||
<view class="input-titile">工作经验</view>
|
||||
<input
|
||||
class="input-con"
|
||||
v-model="state.workExperience"
|
||||
disabled
|
||||
placeholder="请选择您的工作经验"
|
||||
/>
|
||||
<view v-if="experienceError" class="error-message">{{ experienceError }}</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeEducation">
|
||||
<view class="input-titile">学历</view>
|
||||
<input class="input-con" v-model="state.educationText" disabled placeholder="本科" />
|
||||
@@ -69,19 +93,19 @@
|
||||
<view class="input-titile">身份证</view>
|
||||
<input
|
||||
class="input-con2"
|
||||
v-model="fromValue.idcard"
|
||||
v-model="fromValue.idCard"
|
||||
maxlength="18"
|
||||
placeholder="请输入身份证号码"
|
||||
@input="validateIdCard"
|
||||
/>
|
||||
<view v-if="idCardError" class="error-message">{{ idCardError }}</view>
|
||||
<view v-if="fromValue.idcard && !idCardError" class="success-message">✓ 身份证格式正确</view>
|
||||
<view v-if="fromValue.idCard && !idCardError" class="success-message">✓ 身份证格式正确</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="next-btn" @tap="nextStep">下一步</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<view class="next-btn" @tap="nextStep">下一步</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<view class="content-one">
|
||||
<view>
|
||||
<view class="content-title">
|
||||
@@ -115,6 +139,27 @@
|
||||
<view class="nx-item" v-for="item in state.jobsText">{{ item }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeSkillLevel">
|
||||
<view class="input-titile">技能等级</view>
|
||||
<input
|
||||
class="input-con"
|
||||
v-model="state.skillLevelText"
|
||||
disabled
|
||||
placeholder="请选择您的技能等级"
|
||||
/>
|
||||
</view>
|
||||
<view class="content-input" @click="changeSkills">
|
||||
<view class="input-titile">技能名称</view>
|
||||
<input
|
||||
class="input-con"
|
||||
disabled
|
||||
v-if="!state.skillsText.length"
|
||||
placeholder="请选择您的技能名称"
|
||||
/>
|
||||
<view class="input-nx" @click="changeSkills" v-else>
|
||||
<view class="nx-item" v-for="(item, index) in state.skillsText" :key="index">{{ item }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeSalay">
|
||||
<view class="input-titile">期望薪资</view>
|
||||
<input
|
||||
@@ -178,23 +223,33 @@ const state = reactive({
|
||||
risalay: JSON.parse(JSON.stringify(salay)),
|
||||
areaText: '',
|
||||
educationText: '',
|
||||
experienceText: '',
|
||||
workExperience: '',
|
||||
salayText: '',
|
||||
jobsText: [],
|
||||
skillLevelText: '',
|
||||
skillsText: [],
|
||||
});
|
||||
const fromValue = reactive({
|
||||
sex: 1,
|
||||
sex: null,
|
||||
education: '4',
|
||||
salaryMin: 2000,
|
||||
salaryMax: 2000,
|
||||
area: 0,
|
||||
jobTitleId: '',
|
||||
experience: '1',
|
||||
idcard: '',
|
||||
workExperience: '1',
|
||||
idCard: '',
|
||||
name: '',
|
||||
age: '',
|
||||
skillLevel: '',
|
||||
skills: '',
|
||||
});
|
||||
|
||||
// 身份证校验相关
|
||||
// 输入校验相关
|
||||
const idCardError = ref('');
|
||||
const nameError = ref('');
|
||||
const ageError = ref('');
|
||||
const sexError = ref('');
|
||||
const experienceError = ref('');
|
||||
|
||||
onLoad((parmas) => {
|
||||
getTreeselect();
|
||||
@@ -204,11 +259,40 @@ onMounted(() => {});
|
||||
|
||||
function changeSex(sex) {
|
||||
fromValue.sex = sex;
|
||||
// 选择后清除性别错误
|
||||
sexError.value = '';
|
||||
}
|
||||
|
||||
// 姓名实时校验(中文2-18或英文2-30)
|
||||
function validateName() {
|
||||
const name = (fromValue.name || '').trim();
|
||||
if (!name) {
|
||||
nameError.value = '请输入姓名';
|
||||
return;
|
||||
}
|
||||
const cn = /^[\u4e00-\u9fa5·]{2,18}$/;
|
||||
const en = /^[A-Za-z\s]{2,30}$/;
|
||||
nameError.value = cn.test(name) || en.test(name) ? '' : '姓名格式不正确';
|
||||
}
|
||||
|
||||
// 年龄实时校验(16-65的整数)
|
||||
function validateAge() {
|
||||
const ageStr = String(fromValue.age || '').trim();
|
||||
if (!ageStr) {
|
||||
ageError.value = '请输入年龄';
|
||||
return;
|
||||
}
|
||||
const num = Number(ageStr);
|
||||
if (!/^\d{1,3}$/.test(ageStr) || Number.isNaN(num)) {
|
||||
ageError.value = '年龄必须为数字';
|
||||
return;
|
||||
}
|
||||
ageError.value = num >= 16 && num <= 65 ? '' : '年龄需在16-65之间';
|
||||
}
|
||||
|
||||
// 身份证实时校验
|
||||
function validateIdCard() {
|
||||
const idCard = fromValue.idcard.trim();
|
||||
const idCard = (fromValue.idCard || '').trim();
|
||||
|
||||
// 如果为空,清除错误信息
|
||||
if (!idCard) {
|
||||
@@ -231,8 +315,10 @@ function changeExperience() {
|
||||
maskClick: true,
|
||||
data: [oneDictData('experience')],
|
||||
success: (_, [value]) => {
|
||||
fromValue.experience = value.value;
|
||||
state.experienceText = value.label;
|
||||
fromValue.workExperience = value.value;
|
||||
state.workExperience = value.label;
|
||||
// 选择后清除工作经验错误
|
||||
experienceError.value = '';
|
||||
},
|
||||
change(_, [value]) {
|
||||
// this.setColunm(1, [123, 123]);
|
||||
@@ -300,20 +386,153 @@ function changeJobs() {
|
||||
});
|
||||
}
|
||||
|
||||
// 技能等级选择
|
||||
function changeSkillLevel() {
|
||||
const skillLevels = [
|
||||
{ label: '初级', value: '1' },
|
||||
{ label: '中级', value: '2' },
|
||||
{ label: '高级', value: '3' }
|
||||
];
|
||||
|
||||
openSelectPopup({
|
||||
title: '技能等级',
|
||||
maskClick: true,
|
||||
data: [skillLevels],
|
||||
success: (_, [value]) => {
|
||||
fromValue.skillLevel = value.value;
|
||||
state.skillLevelText = value.label;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 技能名称选择
|
||||
function changeSkills() {
|
||||
const skills = [
|
||||
// 前端开发
|
||||
{ label: 'HTML', value: 'html' },
|
||||
{ label: 'CSS', value: 'css' },
|
||||
{ label: 'JavaScript', value: 'javascript' },
|
||||
{ label: 'TypeScript', value: 'typescript' },
|
||||
{ label: 'React', value: 'react' },
|
||||
{ label: 'Vue', value: 'vue' },
|
||||
{ label: 'Angular', value: 'angular' },
|
||||
{ label: 'jQuery', value: 'jquery' },
|
||||
{ label: 'Bootstrap', value: 'bootstrap' },
|
||||
{ label: 'Sass/Less', value: 'sass' },
|
||||
{ label: 'Webpack', value: 'webpack' },
|
||||
{ label: 'Vite', value: 'vite' },
|
||||
|
||||
// 后端开发
|
||||
{ label: 'Java', value: 'java' },
|
||||
{ label: 'Python', value: 'python' },
|
||||
{ label: 'Node.js', value: 'nodejs' },
|
||||
{ label: 'PHP', value: 'php' },
|
||||
{ label: 'C#', value: 'csharp' },
|
||||
{ label: 'Go', value: 'go' },
|
||||
{ label: 'Ruby', value: 'ruby' },
|
||||
{ label: 'Spring Boot', value: 'springboot' },
|
||||
{ label: 'Django', value: 'django' },
|
||||
{ label: 'Express', value: 'express' },
|
||||
{ label: 'Laravel', value: 'laravel' },
|
||||
|
||||
// 数据库
|
||||
{ label: 'MySQL', value: 'mysql' },
|
||||
{ label: 'PostgreSQL', value: 'postgresql' },
|
||||
{ label: 'MongoDB', value: 'mongodb' },
|
||||
{ label: 'Redis', value: 'redis' },
|
||||
{ label: 'Oracle', value: 'oracle' },
|
||||
{ label: 'SQL Server', value: 'sqlserver' },
|
||||
|
||||
// 移动开发
|
||||
{ label: 'React Native', value: 'reactnative' },
|
||||
{ label: 'Flutter', value: 'flutter' },
|
||||
{ label: 'iOS开发', value: 'ios' },
|
||||
{ label: 'Android开发', value: 'android' },
|
||||
{ label: '微信小程序', value: 'miniprogram' },
|
||||
{ label: 'uni-app', value: 'uniapp' },
|
||||
|
||||
// 云计算与运维
|
||||
{ label: 'Docker', value: 'docker' },
|
||||
{ label: 'Kubernetes', value: 'kubernetes' },
|
||||
{ label: 'AWS', value: 'aws' },
|
||||
{ label: '阿里云', value: 'aliyun' },
|
||||
{ label: 'Linux', value: 'linux' },
|
||||
{ label: 'Nginx', value: 'nginx' },
|
||||
|
||||
// 设计工具
|
||||
{ label: 'Photoshop', value: 'photoshop' },
|
||||
{ label: 'Figma', value: 'figma' },
|
||||
{ label: 'Sketch', value: 'sketch' },
|
||||
{ label: 'Adobe XD', value: 'adobexd' },
|
||||
|
||||
// 其他技能
|
||||
{ label: 'Git', value: 'git' },
|
||||
{ label: 'Jenkins', value: 'jenkins' },
|
||||
{ label: 'Jira', value: 'jira' },
|
||||
{ label: '项目管理', value: 'projectmanagement' },
|
||||
{ label: '数据分析', value: 'dataanalysis' },
|
||||
{ label: '人工智能', value: 'ai' },
|
||||
{ label: '机器学习', value: 'machinelearning' }
|
||||
];
|
||||
|
||||
// 获取当前已选中的技能
|
||||
const currentSelectedValues = fromValue.skills ? fromValue.skills.split(',') : [];
|
||||
|
||||
openSelectPopup({
|
||||
title: '技能名称',
|
||||
maskClick: true,
|
||||
data: [skills],
|
||||
multiSelect: true,
|
||||
rowLabel: 'label',
|
||||
rowKey: 'value',
|
||||
defaultValues: currentSelectedValues,
|
||||
success: (selectedValues, selectedItems) => {
|
||||
const selectedSkills = selectedItems.map(item => item.value);
|
||||
const selectedLabels = selectedItems.map(item => item.label);
|
||||
fromValue.skills = selectedSkills.join(',');
|
||||
state.skillsText = selectedLabels;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function nextStep() {
|
||||
// 校验身份证号码
|
||||
const idCard = fromValue.idcard.trim();
|
||||
if (!idCard) {
|
||||
$api.msg('请输入身份证号码');
|
||||
// 统一必填与格式校验
|
||||
validateName();
|
||||
validateAge();
|
||||
validateIdCard();
|
||||
|
||||
if (fromValue.sex !== 0 && fromValue.sex !== 1) {
|
||||
sexError.value = '请选择性别';
|
||||
}
|
||||
|
||||
// 工作经验校验
|
||||
if (!state.workExperience) {
|
||||
experienceError.value = '请选择您的工作经验';
|
||||
} else {
|
||||
experienceError.value = '';
|
||||
}
|
||||
|
||||
// 学历校验
|
||||
if (!state.educationText) {
|
||||
$api.msg('请选择您的学历');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = IdCardValidator.validate(idCard);
|
||||
|
||||
// 检查所有错误状态
|
||||
if (nameError.value) return;
|
||||
if (sexError.value) return;
|
||||
if (ageError.value) return;
|
||||
if (experienceError.value) return;
|
||||
if (idCardError.value || !fromValue.idCard) {
|
||||
if (!fromValue.idCard) $api.msg('请输入身份证号码');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = IdCardValidator.validate(fromValue.idCard);
|
||||
if (!result.valid) {
|
||||
$api.msg(result.message);
|
||||
return;
|
||||
}
|
||||
|
||||
tabCurrent.value += 1;
|
||||
}
|
||||
|
||||
@@ -359,16 +578,65 @@ function loginTest() {
|
||||
}
|
||||
|
||||
function complete() {
|
||||
const result = IdCardValidator.validate(fromValue.idcard);
|
||||
const result = IdCardValidator.validate(fromValue.idCard);
|
||||
if (result.valid) {
|
||||
$api.createRequest('/app/user/resume', fromValue, 'post').then((resData) => {
|
||||
// 构建 experiencesList 数组
|
||||
const experiencesList = [];
|
||||
if (fromValue.skills && fromValue.skillLevel) {
|
||||
const skillsArray = fromValue.skills.split(',');
|
||||
skillsArray.forEach(skill => {
|
||||
if (skill.trim()) {
|
||||
experiencesList.push({
|
||||
name: skill.trim(),
|
||||
levels: fromValue.skillLevel
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 构建符合要求的请求数据(experiencesList 与 appUser 同级)
|
||||
const requestData = {
|
||||
appUser: {
|
||||
name: fromValue.name,
|
||||
isCompanyUser: 1,
|
||||
age: fromValue.age,
|
||||
sex: fromValue.sex,
|
||||
workExperience: fromValue.workExperience,
|
||||
education: fromValue.education,
|
||||
idCard: fromValue.idCard,
|
||||
area: fromValue.area,
|
||||
jobTitleId: fromValue.jobTitleId,
|
||||
salaryMin: fromValue.salaryMin,
|
||||
salaryMax: fromValue.salaryMax
|
||||
},
|
||||
experiencesList: experiencesList
|
||||
};
|
||||
|
||||
$api.createRequest('/registerUser', requestData, 'post').then(async (resData) => {
|
||||
$api.msg('完成');
|
||||
// 获取用户信息并存储到store中
|
||||
getUserResume().then((userInfo) => {
|
||||
console.log('用户信息已存储到store:', userInfo);
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
|
||||
// 如果接口返回了token,需要重新保存token
|
||||
if (resData.token) {
|
||||
try {
|
||||
await loginSetToken(resData.token);
|
||||
console.log('Token已更新:', resData.token);
|
||||
} catch (error) {
|
||||
console.error('更新Token失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存成功后,重新获取用户信息并更新缓存
|
||||
try {
|
||||
await getUserResume();
|
||||
console.log('用户信息已更新到缓存');
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
// 即使获取用户信息失败,也不影响页面跳转
|
||||
}
|
||||
|
||||
// 跳转到首页
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -403,32 +671,22 @@ function complete() {
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
.nx-item
|
||||
padding: 20rpx 28rpx
|
||||
padding: 16rpx 24rpx
|
||||
width: fit-content
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
border: 2rpx solid #E8EAEE;
|
||||
margin-right: 24rpx
|
||||
margin-top: 24rpx
|
||||
.nx-item::before
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 60rpx;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 18rpx;
|
||||
border-radius: 2rpx
|
||||
background: #697279;
|
||||
transform: translate(0, -50%) rotate(-45deg) ;
|
||||
.nx-item::after
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 61rpx;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 18rpx;
|
||||
border-radius: 2rpx
|
||||
background: #697279;
|
||||
transform: rotate(45deg)
|
||||
border-radius: 20rpx
|
||||
border: 2rpx solid #E8EAEE
|
||||
background-color: #f8f9fa
|
||||
margin-right: 16rpx
|
||||
margin-top: 16rpx
|
||||
font-size: 28rpx
|
||||
color: #333333
|
||||
transition: all 0.2s ease
|
||||
|
||||
&:hover
|
||||
background-color: #e9ecef
|
||||
border-color: #256bfa
|
||||
color: #256bfa
|
||||
// 移除技能标签的箭头样式,因为技能标签不需要箭头指示
|
||||
.container
|
||||
// background: linear-gradient(#4778EC, #002979);
|
||||
width: 100%;
|
||||
|
||||
@@ -5,18 +5,53 @@
|
||||
<image class="mp-background" src="/static/icon/background2.png" mode="aspectFill"></image>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 企业账号显示卡片 -->
|
||||
<view class="enterprise-card btn-feel" v-if="shouldShowCompanyCard" @click="goToCompanyInfo">
|
||||
<view class="card-content">
|
||||
<!-- 企业图标 -->
|
||||
<view class="company-icon">
|
||||
<image
|
||||
v-if="companyInfo.avatar"
|
||||
:src="companyInfo.avatar"
|
||||
class="logo-image"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view v-else class="default-logo">
|
||||
<uni-icons type="home-filled" size="32" color="#256BFA"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 企业信息 -->
|
||||
<view class="company-info">
|
||||
<view class="company-name">{{ companyInfo.name || '企业名称' }}</view>
|
||||
<view class="company-details">
|
||||
<text class="industry">{{ companyInfo.industry || '互联网' }}</text>
|
||||
<text class="separator">·</text>
|
||||
<text class="size">{{ companyInfo.scale || '100-999人' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="nav-hidden hidden-animation"
|
||||
:class="{ 'hidden-height': shouldHideTop }"
|
||||
>
|
||||
<view class="container-search">
|
||||
<view class="container-search" v-if="shouldShowJobSeekerContent">
|
||||
<view class="search-input button-click" @click="navTo('/pages/search/search')">
|
||||
<uni-icons class="iconsearch" color="#666666" type="search" size="18"></uni-icons>
|
||||
<text class="inpute">职位名称、薪资要求等</text>
|
||||
</view>
|
||||
<!-- 直播入口按钮 -->
|
||||
<view class="live-button press-button" @click="handleLiveClick">
|
||||
<view class="live-icon">
|
||||
<uni-icons type="videocam-filled" size="16" color="#FFFFFF"></uni-icons>
|
||||
</view>
|
||||
<view class="live-text">直播</view>
|
||||
</view>
|
||||
<!-- <view class="chart button-click">职业图谱</view> -->
|
||||
</view>
|
||||
<view class="cards" v-if="userInfo.userType !== 0">
|
||||
<view class="cards" v-if="shouldShowJobSeekerContent">
|
||||
<view class="card press-button" @click="handleNearbyClick">
|
||||
<view class="card-title">附近工作</view>
|
||||
<view class="card-text">好岗职等你来</view>
|
||||
@@ -27,9 +62,8 @@
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 服务功能网格 -->
|
||||
<view class="service-grid" v-if="userInfo.userType !== 0">
|
||||
<view class="service-grid" v-if="shouldShowJobSeekerContent">
|
||||
<view class="service-item press-button" @click="handleServiceClick('service-guidance')">
|
||||
<view class="service-icon service-icon-1">
|
||||
<uni-icons type="auth-filled" size="32" color="#FFFFFF"></uni-icons>
|
||||
@@ -84,6 +118,66 @@
|
||||
</view>
|
||||
<view class="service-title">AI智能面试</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('ai-interview')">
|
||||
<view class="service-icon service-icon-9">
|
||||
<IconfontIcon name="Graduation-simple-" :size="32" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title" style="overflow:none">高校毕业生<br/>智慧就业服务</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="navToTestPage">
|
||||
<view class="service-icon service-icon-10">
|
||||
<uni-icons type="gear-filled" size="32" color="#FFFFFF"></uni-icons>
|
||||
</view>
|
||||
<view class="service-title">测试页面</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('public-recruitment')">
|
||||
<view class="service-icon service-icon-2">
|
||||
<IconfontIcon name="zhengfulou" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">事业单位招录</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('resume-creation')">
|
||||
<view class="service-icon service-icon-3">
|
||||
<IconfontIcon name="jianli" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">简历制作</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('labor-policy')">
|
||||
<view class="service-icon service-icon-4">
|
||||
<IconfontIcon name="zhengce" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">劳动政策指引</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('skill-training')">
|
||||
<view class="service-icon service-icon-5">
|
||||
<IconfontIcon name="jinengpeixun" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">技能培训信息</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('skill-evaluation')">
|
||||
<view class="service-icon service-icon-6">
|
||||
<IconfontIcon name="jinengpingjia" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">技能评价指引</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('question-bank')">
|
||||
<view class="service-icon service-icon-7">
|
||||
<IconfontIcon name="suzhicepingtiku" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">题库和考试</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('quality-assessment')">
|
||||
<view class="service-icon service-icon-8">
|
||||
<IconfontIcon name="suzhicepingtiku" :size="48" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">素质测评</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="handleServiceClick('ai-interview')">
|
||||
<view class="service-icon service-icon-9">
|
||||
<IconfontIcon name="ai" :size="68" color="#FFFFFF" />
|
||||
</view>
|
||||
<view class="service-title">AI智能面试</view>
|
||||
</view>
|
||||
<view class="service-item press-button" @click="navTo('/packageB/pages/search/search')">
|
||||
<view class="service-icon service-icon-9">
|
||||
<IconfontIcon name="ai" :size="68" color="#FFFFFF" />
|
||||
@@ -92,11 +186,47 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 企业用户内容 -->
|
||||
<!-- <view class="company-content" v-if="shouldShowCompanyContent">
|
||||
<view class="company-header">
|
||||
<text class="company-title">企业服务</text>
|
||||
<text class="company-subtitle">为您提供专业的企业招聘服务</text>
|
||||
</view>
|
||||
|
||||
<view class="company-grid">
|
||||
<view class="company-item press-button" @click="navTo('/pages/job/publishJob')">
|
||||
<view class="company-icon company-icon-1">
|
||||
<uni-icons type="plus-filled" size="32" color="#FFFFFF"></uni-icons>
|
||||
</view>
|
||||
<view class="company-title">发布岗位</view>
|
||||
</view>
|
||||
<view class="company-item press-button" @click="handleServiceClick('company-management')">
|
||||
<view class="company-icon company-icon-2">
|
||||
<uni-icons type="settings-filled" size="32" color="#FFFFFF"></uni-icons>
|
||||
</view>
|
||||
<view class="company-title">企业管理</view>
|
||||
</view>
|
||||
<view class="company-item press-button" @click="handleServiceClick('recruitment-data')">
|
||||
<view class="company-icon company-icon-3">
|
||||
<uni-icons type="bar-chart-filled" size="32" color="#FFFFFF"></uni-icons>
|
||||
</view>
|
||||
<view class="company-title">招聘数据</view>
|
||||
</view>
|
||||
<view class="company-item press-button" @click="handleServiceClick('talent-pool')">
|
||||
<view class="company-icon company-icon-4">
|
||||
<uni-icons type="person-filled" size="32" color="#FFFFFF"></uni-icons>
|
||||
</view>
|
||||
<view class="company-title">人才库</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 吸顶筛选区域占位 -->
|
||||
<view class="filter-placeholder" v-if="shouldStickyFilter && userInfo.userType !== 0"></view>
|
||||
<view class="filter-placeholder" v-if="shouldStickyFilter && shouldShowJobSeekerContent"></view>
|
||||
|
||||
|
||||
<view class="nav-filter" :class="{ 'sticky-filter': shouldStickyFilter }" v-if="userInfo.userType !== 0">
|
||||
<view class="nav-filter" :class="{ 'sticky-filter': shouldStickyFilter }" v-if="shouldShowJobSeekerContent">
|
||||
<view class="filter-top" @touchmove.stop.prevent>
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||
<view class="jobs-left">
|
||||
@@ -328,7 +458,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted, onUnmounted, watchEffect, nextTick } from 'vue';
|
||||
import { reactive, inject, watch, ref, onMounted, onUnmounted, watchEffect, nextTick, computed } from 'vue';
|
||||
import img from '@/static/icon/filter.png';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||
@@ -336,6 +466,81 @@ import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { userInfo, hasLogin, token } = storeToRefs(useUserStore());
|
||||
|
||||
// 计算是否显示求职者内容
|
||||
const shouldShowJobSeekerContent = computed(() => {
|
||||
// 未登录时默认显示求职者内容
|
||||
if (!hasLogin.value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 优先从store获取,如果为空则从缓存获取
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
|
||||
|
||||
// 获取用户类型:优先使用store中的isCompanyUser,如果store中没有,使用缓存中的isCompanyUser
|
||||
// 缓存中的值可能是字符串,需要转换为数值类型
|
||||
const userType = storeIsCompanyUser !== undefined ? Number(storeIsCompanyUser) : Number(cachedIsCompanyUser);
|
||||
|
||||
// 企业用户(isCompanyUser=0)不显示求职者内容,其他用户类型显示
|
||||
return userType !== 0;
|
||||
});
|
||||
|
||||
// 企业信息数据
|
||||
const companyInfo = reactive({
|
||||
name: '',
|
||||
avatar: '',
|
||||
industry: '',
|
||||
scale: '',
|
||||
isVerified: false
|
||||
});
|
||||
|
||||
// 计算是否显示企业卡片
|
||||
const shouldShowCompanyCard = computed(() => {
|
||||
// 未登录时不显示
|
||||
if (!hasLogin.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 优先从store获取,如果为空则从缓存获取
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
|
||||
|
||||
// 获取用户类型:优先使用store中的isCompanyUser,如果store中没有,使用缓存中的isCompanyUser
|
||||
// 缓存中的值可能是字符串,需要转换为数值类型
|
||||
const userType = storeIsCompanyUser !== undefined ? Number(storeIsCompanyUser) : Number(cachedIsCompanyUser);
|
||||
|
||||
// 只有企业用户(isCompanyUser=0)才显示企业卡片
|
||||
if (userType !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查企业信息是否已完善
|
||||
return companyInfo.name && companyInfo.name.trim() !== '';
|
||||
});
|
||||
|
||||
// 计算是否显示企业用户内容
|
||||
const shouldShowCompanyContent = computed(() => {
|
||||
// 未登录时不显示企业内容
|
||||
if (!hasLogin.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 优先从store获取,如果为空则从缓存获取
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
|
||||
|
||||
// 获取用户类型:优先使用store中的isCompanyUser,如果store中没有,使用缓存中的isCompanyUser
|
||||
// 缓存中的值可能是字符串,需要转换为数值类型
|
||||
const userType = storeIsCompanyUser !== undefined ? Number(storeIsCompanyUser) : Number(cachedIsCompanyUser);
|
||||
|
||||
// 只有企业用户(isCompanyUser=0)才显示企业内容
|
||||
return userType === 0;
|
||||
});
|
||||
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { getTransformChildren, oneDictData } = useDictStore();
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
@@ -345,6 +550,7 @@ import { useScrollDirection } from '@/hook/useScrollDirection';
|
||||
import { useColumnCount } from '@/hook/useColumnCount';
|
||||
import WxAuthLogin from '@/components/WxAuthLogin/WxAuthLogin.vue';
|
||||
import IconfontIcon from '@/components/IconfontIcon/IconfontIcon.vue'
|
||||
// 企业卡片组件已内联到模板中
|
||||
// 滚动状态管理
|
||||
const shouldHideTop = ref(false);
|
||||
const shouldStickyFilter = ref(false);
|
||||
@@ -352,7 +558,6 @@ const lastScrollTop = ref(0);
|
||||
const scrollTop = ref(0);
|
||||
// 当用户与筛选/导航交互时,临时锁定头部显示状态,避免因数据刷新导致回弹显示
|
||||
const isInteractingWithFilter = ref(false);
|
||||
|
||||
// 滚动阈值配置
|
||||
const HIDE_THRESHOLD = 50; // 隐藏顶部区域的滚动阈值(降低阈值,更容易触发)
|
||||
const SHOW_THRESHOLD = 5; // 显示顶部区域的滚动阈值(接近顶部)
|
||||
@@ -421,21 +626,101 @@ const rangeOptions = ref([
|
||||
{ value: 3, text: '疆外' },
|
||||
]);
|
||||
const isLoaded = ref(false);
|
||||
const isInitialized = ref(false); // 添加初始化标志
|
||||
|
||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
pageState.pageSize = 10 * (columnCount.value - 1);
|
||||
getJobRecommend('refresh');
|
||||
|
||||
// 只在首次初始化时调用,避免重复调用
|
||||
if (!isInitialized.value) {
|
||||
isInitialized.value = true;
|
||||
getJobRecommend('refresh');
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
useLocationStore().getLocation();
|
||||
});
|
||||
});
|
||||
|
||||
// 获取企业信息
|
||||
const getCompanyInfo = () => {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
console.log('缓存中的userInfo:', cachedUserInfo);
|
||||
|
||||
// 重置企业信息
|
||||
companyInfo.name = '';
|
||||
companyInfo.avatar = '';
|
||||
companyInfo.industry = '';
|
||||
companyInfo.scale = '';
|
||||
companyInfo.isVerified = false;
|
||||
|
||||
// 检查是否有company字段
|
||||
if (cachedUserInfo.company) {
|
||||
const company = cachedUserInfo.company;
|
||||
|
||||
// 基本信息
|
||||
companyInfo.name = company.name || '';
|
||||
companyInfo.avatar = company.avatar || '';
|
||||
companyInfo.industry = company.industryType || '互联网';
|
||||
companyInfo.scale = company.scale || '100-999人';
|
||||
|
||||
// 判断是否实名:legalIdCard字段有值则表示已实名
|
||||
companyInfo.isVerified = !!(company.legalIdCard && company.legalIdCard.trim());
|
||||
|
||||
console.log('企业信息已更新:', {
|
||||
name: companyInfo.name,
|
||||
industry: companyInfo.industry,
|
||||
size: companyInfo.scale,
|
||||
isVerified: companyInfo.isVerified
|
||||
});
|
||||
} else {
|
||||
console.log('缓存中没有company字段,企业信息已重置');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取企业信息失败:', error);
|
||||
// 重置为默认值
|
||||
companyInfo.name = '';
|
||||
companyInfo.avatar = '';
|
||||
companyInfo.industry = '';
|
||||
companyInfo.scale = '';
|
||||
companyInfo.isVerified = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到企业信息详情页面
|
||||
const goToCompanyInfo = () => {
|
||||
navTo('/pages/mine/company-info');
|
||||
};
|
||||
|
||||
// 组件初始化时加载数据
|
||||
onMounted(() => {
|
||||
getJobRecommend('refresh');
|
||||
// 获取企业信息
|
||||
getCompanyInfo();
|
||||
|
||||
// 监听退出登录事件,显示微信登录弹窗
|
||||
uni.$on('showLoginModal', () => {
|
||||
wxAuthLoginRef.value?.open();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('showLoginModal');
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
// 获取最新的企业信息
|
||||
getCompanyInfo();
|
||||
});
|
||||
|
||||
// 监听用户信息变化,当登录状态改变时重新获取企业信息
|
||||
watch([hasLogin, userInfo], () => {
|
||||
if (hasLogin.value) {
|
||||
getCompanyInfo();
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 登录检查函数
|
||||
const checkLogin = () => {
|
||||
const tokenValue = uni.getStorageSync('token') || '';
|
||||
@@ -451,6 +736,9 @@ const checkLogin = () => {
|
||||
const handleLoginSuccess = () => {
|
||||
// 登录成功后刷新数据
|
||||
getJobRecommend('refresh');
|
||||
|
||||
// 重新获取企业信息
|
||||
getCompanyInfo();
|
||||
};
|
||||
|
||||
// 处理附近工作点击
|
||||
@@ -467,6 +755,16 @@ const handleServiceClick = (serviceType) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 处理直播按钮点击
|
||||
const handleLiveClick = () => {
|
||||
$api.msg('该功能正在开发中');
|
||||
};
|
||||
|
||||
// 跳转到测试页面
|
||||
const navToTestPage = () => {
|
||||
navTo('/pages/test/homepage-test');
|
||||
};
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
@@ -478,7 +776,9 @@ async function loadData() {
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
loadmoreRef.value.change('loading');
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||
loadmoreRef.value.change('loading');
|
||||
}
|
||||
if (state.tabIndex === 'all') {
|
||||
getJobRecommend();
|
||||
} else {
|
||||
@@ -556,7 +856,7 @@ function navToService(serviceType) {
|
||||
'resume-creation': '/packageA/pages/myResume/myResume',
|
||||
'labor-policy': '/pages/service/labor-policy',
|
||||
'skill-training': '/pages/service/skill-training',
|
||||
'skill-evaluation': '/pages/service/skill-evaluation',
|
||||
// 'skill-evaluation': '/pages/service/skill-evaluation',
|
||||
'question-bank': '/pages/service/question-bank',
|
||||
'quality-assessment': '/pages/service/quality-assessment',
|
||||
'ai-interview': '/pages/chat/chat',
|
||||
@@ -566,7 +866,8 @@ function navToService(serviceType) {
|
||||
'company-info': '/pages/service/company-info',
|
||||
'interview-tips': '/pages/service/interview-tips',
|
||||
'employment-news': '/pages/service/employment-news',
|
||||
'more-services': '/pages/service/more-services'
|
||||
'more-services': '/pages/service/more-services',
|
||||
'skill-evaluation': '/packageB/train/index'
|
||||
};
|
||||
|
||||
const route = serviceRoutes[serviceType];
|
||||
@@ -655,6 +956,7 @@ function getJobRecommend(type = 'add') {
|
||||
sessionId: useUserStore().seesionId,
|
||||
...pageState.search,
|
||||
...conditionSearch.value,
|
||||
isPublish: 1,
|
||||
};
|
||||
let comd = { recommend: true, jobCategory: '', tip: '确认你的兴趣,为您推荐更多合适的岗位' };
|
||||
$api.createRequest('/app/job/recommend', params).then((resData) => {
|
||||
@@ -882,13 +1184,14 @@ defineExpose({ loadData });
|
||||
padding: 16rpx 24rpx
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
.search-input
|
||||
display: flex
|
||||
align-items: center;
|
||||
width: 100%
|
||||
flex: 1
|
||||
height: 80rpx;
|
||||
line-height: 80rpx
|
||||
margin-right: 24rpx
|
||||
margin-right: 16rpx
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
.iconsearch
|
||||
@@ -899,6 +1202,35 @@ defineExpose({ loadData });
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
width: 100%
|
||||
.live-button
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: 90rpx
|
||||
height: 42rpx
|
||||
background: linear-gradient(135deg, #FF6B6B 0%, #FF8E8E 100%)
|
||||
border-radius: 40rpx
|
||||
box-shadow: 0 3rpx 8rpx rgba(255, 107, 107, 0.2)
|
||||
transition: all 0.2s ease
|
||||
flex-shrink: 0
|
||||
|
||||
&:active
|
||||
transform: scale(0.96)
|
||||
box-shadow: 0 2rpx 6rpx rgba(255, 107, 107, 0.25)
|
||||
|
||||
.live-icon
|
||||
margin-right: 8rpx
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
|
||||
.live-text
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif
|
||||
font-weight: 500
|
||||
font-size: 24rpx
|
||||
color: #FFFFFF
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
.chart
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
width: 170rpx;
|
||||
@@ -1021,13 +1353,9 @@ defineExpose({ loadData });
|
||||
.service-icon-10
|
||||
background: linear-gradient(135deg, #9C27B0 0%, #BA68C8 100%)
|
||||
position: relative
|
||||
&::before
|
||||
content: '🔍'
|
||||
position: absolute
|
||||
top: 50%
|
||||
left: 50%
|
||||
transform: translate(-50%, -50%)
|
||||
font-size: 32rpx
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
.service-icon-11
|
||||
background: linear-gradient(135deg, #FF9800 0%, #FFB74D 100%)
|
||||
position: relative
|
||||
@@ -1100,6 +1428,8 @@ defineExpose({ loadData });
|
||||
text-overflow: ellipsis
|
||||
width: 100%
|
||||
max-width: 100%
|
||||
.service-title-special
|
||||
overflow: none;
|
||||
|
||||
// 吸顶筛选区域占位
|
||||
.filter-placeholder
|
||||
@@ -1346,6 +1676,71 @@ defineExpose({ loadData });
|
||||
background-size contain
|
||||
pointer-events none
|
||||
filter: blur(3rpx)
|
||||
// 企业用户内容样式
|
||||
.company-content
|
||||
padding: 40rpx 30rpx
|
||||
background: #ffffff
|
||||
margin: 20rpx 30rpx
|
||||
border-radius: 20rpx
|
||||
box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(0, 0, 0, 0.1)
|
||||
|
||||
.company-header
|
||||
text-align: center
|
||||
margin-bottom: 40rpx
|
||||
|
||||
.company-title
|
||||
font-size: 36rpx
|
||||
font-weight: bold
|
||||
color: #333333
|
||||
display: block
|
||||
margin-bottom: 10rpx
|
||||
|
||||
.company-subtitle
|
||||
font-size: 24rpx
|
||||
color: #666666
|
||||
display: block
|
||||
|
||||
.company-grid
|
||||
display: grid
|
||||
grid-template-columns: 1fr 1fr
|
||||
gap: 30rpx
|
||||
|
||||
.company-item
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
padding: 30rpx 20rpx
|
||||
background: #f8f9fa
|
||||
border-radius: 15rpx
|
||||
transition: all 0.3s ease
|
||||
|
||||
&:active
|
||||
transform: scale(0.95)
|
||||
background: #e9ecef
|
||||
|
||||
.company-icon
|
||||
width: 60rpx
|
||||
height: 60rpx
|
||||
border-radius: 50%
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
margin-bottom: 15rpx
|
||||
|
||||
&.company-icon-1
|
||||
background: #256BFA
|
||||
&.company-icon-2
|
||||
background: #52c41a
|
||||
&.company-icon-3
|
||||
background: #fa8c16
|
||||
&.company-icon-4
|
||||
background: #eb2f96
|
||||
|
||||
.company-title
|
||||
font-size: 24rpx
|
||||
color: #333333
|
||||
font-weight: 500
|
||||
|
||||
.recommend-card
|
||||
padding 36rpx 24rpx
|
||||
background: linear-gradient( 360deg, #DFE9FF 0%, #FFFFFF 52%, #FFFFFF 100%);
|
||||
@@ -1424,4 +1819,133 @@ defineExpose({ loadData });
|
||||
.isBut{
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
// 企业账号显示卡片样式
|
||||
.enterprise-card
|
||||
margin: 20rpx 28rpx
|
||||
padding: 28rpx
|
||||
background: rgba(255, 255, 255, 0.9)
|
||||
backdrop-filter: blur(20rpx)
|
||||
-webkit-backdrop-filter: blur(20rpx)
|
||||
border-radius: 24rpx
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.4)
|
||||
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.08), 0 2rpx 8rpx rgba(0, 0, 0, 0.04)
|
||||
position: relative
|
||||
overflow: hidden
|
||||
cursor: pointer
|
||||
transition: all 0.3s ease
|
||||
|
||||
&:active
|
||||
transform: scale(0.98)
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.12), 0 1rpx 4rpx rgba(0, 0, 0, 0.08)
|
||||
|
||||
// 玻璃态效果 - 更强烈的渐变
|
||||
&::before
|
||||
content: ''
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
background: linear-gradient(135deg,
|
||||
rgba(255, 255, 255, 0.2) 0%,
|
||||
rgba(255, 255, 255, 0.1) 50%,
|
||||
rgba(255, 255, 255, 0.05) 100%)
|
||||
border-radius: 24rpx
|
||||
pointer-events: none
|
||||
z-index: 0
|
||||
|
||||
// 添加微妙的边框高光
|
||||
&::after
|
||||
content: ''
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
border-radius: 24rpx
|
||||
padding: 1rpx
|
||||
background: linear-gradient(135deg,
|
||||
rgba(255, 255, 255, 0.6) 0%,
|
||||
rgba(255, 255, 255, 0.2) 100%)
|
||||
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)
|
||||
mask-composite: xor
|
||||
-webkit-mask-composite: xor
|
||||
pointer-events: none
|
||||
z-index: 1
|
||||
|
||||
.card-content
|
||||
display: flex
|
||||
align-items: center
|
||||
position: relative
|
||||
z-index: 2
|
||||
|
||||
.company-icon
|
||||
width: 88rpx
|
||||
height: 88rpx
|
||||
border-radius: 18rpx
|
||||
background: linear-gradient(135deg, #256BFA 0%, #4A90E2 100%)
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
margin-right: 28rpx
|
||||
flex-shrink: 0
|
||||
box-shadow: 0 6rpx 16rpx rgba(37, 107, 250, 0.25)
|
||||
position: relative
|
||||
|
||||
// 添加图标内部高光
|
||||
&::before
|
||||
content: ''
|
||||
position: absolute
|
||||
top: 4rpx
|
||||
left: 4rpx
|
||||
right: 4rpx
|
||||
height: 20rpx
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.3) 0%, transparent 100%)
|
||||
border-radius: 18rpx 18rpx 0 0
|
||||
pointer-events: none
|
||||
|
||||
.default-logo
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
color: #ffffff
|
||||
|
||||
.company-info
|
||||
flex: 1
|
||||
min-width: 0
|
||||
z-index: 2
|
||||
position: relative
|
||||
|
||||
.company-name
|
||||
font-size: 34rpx
|
||||
font-weight: 600
|
||||
color: #000000
|
||||
line-height: 1.3
|
||||
margin-bottom: 10rpx
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif
|
||||
|
||||
.company-details
|
||||
display: flex
|
||||
align-items: center
|
||||
font-size: 26rpx
|
||||
color: #666666
|
||||
line-height: 1.2
|
||||
|
||||
.industry
|
||||
color: #666666
|
||||
font-weight: 400
|
||||
|
||||
.separator
|
||||
margin: 0 10rpx
|
||||
color: #CCCCCC
|
||||
font-weight: 300
|
||||
|
||||
.size
|
||||
color: #666666
|
||||
font-weight: 400
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
<IndexOne @onShowTabbar="changeShowTabbar" />
|
||||
</view>
|
||||
|
||||
<!-- 统一使用系统tabBar -->
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="0" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -18,11 +19,17 @@ import IndexOne from './components/index-one.vue';
|
||||
// import IndexTwo from './components/index-two.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
import { tabbarManager } from '@/utils/tabbarManager';
|
||||
const { unreadCount } = storeToRefs(useReadMsg());
|
||||
|
||||
onLoad(() => {
|
||||
// useReadMsg().fetchMessages();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
// 更新自定义tabbar选中状态
|
||||
tabbarManager.updateSelected(0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
474
pages/job/companySearch.vue
Normal file
@@ -0,0 +1,474 @@
|
||||
<template>
|
||||
<view class="company-search-page">
|
||||
<!-- 头部导航 -->
|
||||
<view class="header">
|
||||
<view class="header-left" @click="goBack">
|
||||
<view class="back-arrow"><uni-icons type="search" size="32" color="#FFFFFF"></uni-icons>‹</view>
|
||||
</view>
|
||||
<view class="header-title">选择企业</view>
|
||||
<view class="header-right"></view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-container">
|
||||
<view class="search-box">
|
||||
<view class="search-icon">🔍</view>
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="请输入企业名称进行搜索"
|
||||
v-model="searchKeyword"
|
||||
@input="onSearchInput"
|
||||
/>
|
||||
<view class="clear-btn" v-if="searchKeyword" @click="clearSearch">
|
||||
<view class="clear-icon">✕</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果 -->
|
||||
<scroll-view class="content" scroll-y="true" :style="{ height: scrollViewHeight }">
|
||||
<!-- 搜索提示 -->
|
||||
<view class="search-tip" v-if="!searchKeyword">
|
||||
<text class="tip-text">请输入企业名称进行搜索</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading-container" v-if="loading">
|
||||
<view class="loading-text">搜索中...</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果列表 -->
|
||||
<view class="result-list" v-if="searchResults.length > 0">
|
||||
<view
|
||||
class="result-item"
|
||||
v-for="(company, index) in searchResults"
|
||||
:key="company.companyId"
|
||||
@click="selectCompany(company)"
|
||||
>
|
||||
<view class="company-info">
|
||||
<view class="company-name">{{ company.name }}</view>
|
||||
<view class="company-location" v-if="company.location">
|
||||
<text class="location-icon">📍</text>
|
||||
<text class="location-text">{{ company.location }}</text>
|
||||
</view>
|
||||
<view class="company-scale" v-if="company.scale">
|
||||
<text class="scale-label">规模:</text>
|
||||
<text class="scale-text">{{ getScaleText(company.scale) }}</text>
|
||||
</view>
|
||||
<view class="company-nature" v-if="company.nature">
|
||||
<text class="nature-label">性质:</text>
|
||||
<text class="nature-text">{{ getNatureText(company.nature) }}</text>
|
||||
</view>
|
||||
<view class="company-description" v-if="company.description">
|
||||
<text class="desc-text">{{ company.description }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="select-icon">
|
||||
<view class="arrow-icon">›</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 无结果提示 -->
|
||||
<view class="no-result" v-if="searchKeyword && !loading && searchResults.length === 0">
|
||||
<view class="empty-icon">📭</view>
|
||||
<view class="no-result-text">未找到相关企业</view>
|
||||
<view class="no-result-tip">请尝试其他关键词</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部安全区域 -->
|
||||
<view class="bottom-safe-area"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { createRequest } from '@/utils/request';
|
||||
|
||||
// 搜索关键词
|
||||
const searchKeyword = ref('');
|
||||
// 搜索结果
|
||||
const searchResults = ref([]);
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
// 防抖定时器
|
||||
let debounceTimer = null;
|
||||
|
||||
// 滚动视图高度
|
||||
const scrollViewHeight = ref('calc(100vh - 200rpx)');
|
||||
|
||||
// 计算滚动视图高度
|
||||
const calculateScrollViewHeight = () => {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const windowHeight = systemInfo.windowHeight;
|
||||
const headerHeight = 100; // 头部高度
|
||||
const searchHeight = 120; // 搜索框高度
|
||||
const scrollHeight = windowHeight - headerHeight - searchHeight;
|
||||
scrollViewHeight.value = `${scrollHeight}px`;
|
||||
};
|
||||
|
||||
// 页面加载时计算高度
|
||||
onMounted(() => {
|
||||
calculateScrollViewHeight();
|
||||
});
|
||||
|
||||
// 搜索输入处理(防抖)
|
||||
const onSearchInput = () => {
|
||||
// 清除之前的定时器
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
|
||||
// 设置新的定时器
|
||||
debounceTimer = setTimeout(() => {
|
||||
if (searchKeyword.value.trim()) {
|
||||
searchCompanies();
|
||||
} else {
|
||||
searchResults.value = [];
|
||||
}
|
||||
}, 500); // 500ms 防抖延迟
|
||||
};
|
||||
|
||||
// 搜索企业
|
||||
const searchCompanies = async () => {
|
||||
if (!searchKeyword.value.trim()) {
|
||||
searchResults.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
const response = await createRequest('/app/company/likeList', {
|
||||
name: searchKeyword.value.trim()
|
||||
}, 'get', false);
|
||||
|
||||
if (response.code === 200) {
|
||||
searchResults.value = response.rows || [];
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || '搜索失败',
|
||||
icon: 'none'
|
||||
});
|
||||
searchResults.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索企业失败:', error);
|
||||
uni.showToast({
|
||||
title: '搜索失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
searchResults.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 清除搜索
|
||||
const clearSearch = () => {
|
||||
searchKeyword.value = '';
|
||||
searchResults.value = [];
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取企业规模文本
|
||||
const getScaleText = (scale) => {
|
||||
const scaleMap = {
|
||||
'1': '1-20人',
|
||||
'2': '21-50人',
|
||||
'3': '51-100人',
|
||||
'4': '101-200人',
|
||||
'5': '201-500人',
|
||||
'6': '500人以上'
|
||||
};
|
||||
return scaleMap[scale] || '未知';
|
||||
};
|
||||
|
||||
// 获取企业性质文本
|
||||
const getNatureText = (nature) => {
|
||||
const natureMap = {
|
||||
'1': '有限责任公司',
|
||||
'2': '股份有限公司',
|
||||
'3': '个人独资企业',
|
||||
'4': '合伙企业',
|
||||
'5': '外商投资企业',
|
||||
'6': '其他'
|
||||
};
|
||||
return natureMap[nature] || '未知';
|
||||
};
|
||||
|
||||
// 选择企业
|
||||
const selectCompany = (company) => {
|
||||
// 返回上一页并传递选中的企业信息
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
success: () => {
|
||||
// 通过事件总线或全局状态传递数据
|
||||
uni.$emit('companySelected', {
|
||||
id: company.companyId,
|
||||
name: company.name,
|
||||
address: company.location
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.company-search-page {
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
.header-left {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.back-arrow {
|
||||
font-size: 40rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
width: 60rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.search-container {
|
||||
padding: 20rpx 30rpx;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 80rpx;
|
||||
|
||||
.search-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.clear-btn {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 20rpx;
|
||||
|
||||
.clear-icon {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.search-tip {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 400rpx;
|
||||
|
||||
.tip-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 200rpx;
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.result-list {
|
||||
background: #fff;
|
||||
|
||||
.result-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.company-info {
|
||||
flex: 1;
|
||||
|
||||
.company-name {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 15rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.company-location {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.location-icon {
|
||||
font-size: 20rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.location-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.company-scale, .company-nature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.scale-label, .nature-label {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.scale-text, .nature-text {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.company-description {
|
||||
margin-top: 10rpx;
|
||||
|
||||
.desc-text {
|
||||
font-size: 22rpx;
|
||||
color: #888;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.arrow-icon {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-result {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 400rpx;
|
||||
|
||||
.empty-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.no-result-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.no-result-tip {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-safe-area {
|
||||
height: 120rpx;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
@@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<view class="tab-container">
|
||||
<view class="uni-margin-wrap">
|
||||
<swiper
|
||||
class="swiper"
|
||||
:current="current"
|
||||
:circular="false"
|
||||
:indicator-dots="false"
|
||||
:autoplay="false"
|
||||
:duration="500"
|
||||
>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab0"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab1"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab2"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab3"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab3"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab4"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab5"></slot>
|
||||
</swiper-item>
|
||||
<swiper-item @touchmove.stop="false">
|
||||
<slot name="tab6"></slot>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'tab',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
props: {
|
||||
current: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tab-container
|
||||
// flex: 1
|
||||
height: 100%
|
||||
width: 100%
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
flex-direction: row
|
||||
.uni-margin-wrap
|
||||
width: 100%
|
||||
height: 100%
|
||||
.swiper
|
||||
width: 100%
|
||||
height: 100%
|
||||
.swiper-item
|
||||
display: block;
|
||||
width: 100%
|
||||
height: 100%
|
||||
</style>
|
||||
@@ -1,490 +0,0 @@
|
||||
<template>
|
||||
<AppLayout title="AI+就业服务程序">
|
||||
<tabcontrolVue :current="tabCurrent">
|
||||
<template v-slot:tab0>
|
||||
<view class="login-content">
|
||||
<image class="logo" src="@/static/logo.png"></image>
|
||||
<view class="logo-title">就业</view>
|
||||
</view>
|
||||
<view class="btns">
|
||||
<button class="wxlogin" @click="loginTest">内测登录</button>
|
||||
<view class="wxaddress">{{ config.appInfo.areaName }}公共就业和人才服务中心</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-slot:tab1>
|
||||
<view class="content-one">
|
||||
<view>
|
||||
<view class="content-title">
|
||||
<view class="title-lf">
|
||||
<view class="lf-h1">请您完善求职名片</view>
|
||||
<view class="lf-text">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="title-ri">
|
||||
<text style="color: #256bfa">1</text>
|
||||
<text>/2</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeExperience">
|
||||
<view class="input-titile">工作经验</view>
|
||||
<input
|
||||
class="input-con"
|
||||
v-model="state.experienceText"
|
||||
disabled
|
||||
placeholder="请选择您的工作经验"
|
||||
/>
|
||||
</view>
|
||||
<view class="content-sex">
|
||||
<view class="sex-titile">求职区域</view>
|
||||
<view class="sext-ri">
|
||||
<view
|
||||
class="sext-box"
|
||||
:class="{ 'sext-boxactive': fromValue.sex === 0 }"
|
||||
@click="changeSex(0)"
|
||||
>
|
||||
男
|
||||
</view>
|
||||
<view
|
||||
class="sext-box"
|
||||
:class="{ 'sext-boxactive': fromValue.sex === 1 }"
|
||||
@click="changeSex(1)"
|
||||
>
|
||||
女
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeEducation">
|
||||
<view class="input-titile">学历</view>
|
||||
<input class="input-con" v-model="state.educationText" disabled placeholder="本科" />
|
||||
</view>
|
||||
<view class="content-input">
|
||||
<view class="input-titile">身份证</view>
|
||||
<input class="input-con2" v-model="fromValue.idcard" maxlength="18" placeholder="本科" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="next-btn" @tap="nextStep">下一步</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-slot:tab2>
|
||||
<view class="content-one">
|
||||
<view>
|
||||
<view class="content-title">
|
||||
<view class="title-lf">
|
||||
<view class="lf-h1">请您完善求职名片</view>
|
||||
<view class="lf-text">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="title-ri">
|
||||
<text style="color: #256bfa">2</text>
|
||||
<text>/2</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeArea">
|
||||
<view class="input-titile">求职区域</view>
|
||||
<input
|
||||
class="input-con"
|
||||
v-model="state.areaText"
|
||||
disabled
|
||||
placeholder="请选择您的求职区域"
|
||||
/>
|
||||
</view>
|
||||
<view class="content-input" @click="changeJobs">
|
||||
<view class="input-titile">求职岗位</view>
|
||||
<input
|
||||
class="input-con"
|
||||
disabled
|
||||
v-if="!state.jobsText.length"
|
||||
placeholder="请选择您的求职岗位"
|
||||
/>
|
||||
<view class="input-nx" @click="changeJobs" v-else>
|
||||
<view class="nx-item" v-for="item in state.jobsText">{{ item }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-input" @click="changeSalay">
|
||||
<view class="input-titile">期望薪资</view>
|
||||
<input
|
||||
class="input-con"
|
||||
v-model="state.salayText"
|
||||
disabled
|
||||
placeholder="请选择您的期望薪资"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="next-btn" @tap="complete">开启求职之旅</view>
|
||||
</view>
|
||||
</template>
|
||||
</tabcontrolVue>
|
||||
<SelectJobs ref="selectJobsModel"></SelectJobs>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import tabcontrolVue from './components/tabcontrol.vue';
|
||||
import SelectJobs from '@/components/selectJobs/selectJobs.vue';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { $api, navTo, config, IdCardValidator } = inject('globalFunction');
|
||||
const { loginSetToken, getUserResume } = useUserStore();
|
||||
const { getDictSelectOption, oneDictData } = useDictStore();
|
||||
const openSelectPopup = inject('openSelectPopup');
|
||||
// console.log(config.appInfo.areaName);
|
||||
// status
|
||||
const selectJobsModel = ref();
|
||||
const tabCurrent = ref(0);
|
||||
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
|
||||
const state = reactive({
|
||||
station: [],
|
||||
stationCateLog: 1,
|
||||
lfsalay: [2, 5, 10, 15, 20, 25, 30, 50],
|
||||
risalay: JSON.parse(JSON.stringify(salay)),
|
||||
areaText: '',
|
||||
educationText: '',
|
||||
experienceText: '',
|
||||
salayText: '',
|
||||
jobsText: [],
|
||||
});
|
||||
const fromValue = reactive({
|
||||
sex: 1,
|
||||
education: '4',
|
||||
salaryMin: 2000,
|
||||
salaryMax: 2000,
|
||||
area: 0,
|
||||
jobTitleId: '',
|
||||
experience: '1',
|
||||
idcard: '',
|
||||
});
|
||||
|
||||
onLoad((parmas) => {
|
||||
getTreeselect();
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
function changeSex(sex) {
|
||||
fromValue.sex = sex;
|
||||
}
|
||||
function changeExperience() {
|
||||
openSelectPopup({
|
||||
title: '工作经验',
|
||||
maskClick: true,
|
||||
data: [oneDictData('experience')],
|
||||
success: (_, [value]) => {
|
||||
fromValue.experience = value.value;
|
||||
state.experienceText = value.label;
|
||||
},
|
||||
change(_, [value]) {
|
||||
// this.setColunm(1, [123, 123]);
|
||||
console.log(this);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function changeEducation() {
|
||||
openSelectPopup({
|
||||
title: '学历',
|
||||
maskClick: true,
|
||||
data: [oneDictData('education')],
|
||||
success: (_, [value]) => {
|
||||
fromValue.area = value.value;
|
||||
state.educationText = value.label;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function changeArea() {
|
||||
openSelectPopup({
|
||||
title: '区域',
|
||||
maskClick: true,
|
||||
data: [oneDictData('area')],
|
||||
success: (_, [value]) => {
|
||||
fromValue.area = value.value;
|
||||
state.areaText = config.appInfo.areaName + '-' + value.label;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function changeSalay() {
|
||||
let leftIndex = 0;
|
||||
openSelectPopup({
|
||||
title: '薪资',
|
||||
maskClick: true,
|
||||
data: [state.lfsalay, state.risalay],
|
||||
unit: 'k',
|
||||
success: (_, [min, max]) => {
|
||||
fromValue.salaryMin = min.value * 1000;
|
||||
fromValue.salaryMax = max.value * 1000;
|
||||
state.salayText = `${fromValue.salaryMin}-${fromValue.salaryMax}`;
|
||||
},
|
||||
change(e) {
|
||||
const salayData = e.detail.value;
|
||||
if (leftIndex !== salayData[0]) {
|
||||
const copyri = JSON.parse(JSON.stringify(salay));
|
||||
const [lf, ri] = e.detail.value;
|
||||
const risalay = copyri.slice(lf, copyri.length);
|
||||
this.setColunm(1, risalay);
|
||||
leftIndex = salayData[0];
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function changeJobs() {
|
||||
selectJobsModel.value?.open({
|
||||
title: '添加岗位',
|
||||
success: (ids, labels) => {
|
||||
fromValue.jobTitleId = ids;
|
||||
state.jobsText = labels.split(',');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function nextStep() {
|
||||
tabCurrent.value += 1;
|
||||
}
|
||||
|
||||
// 获取职位
|
||||
function getTreeselect() {
|
||||
$api.createRequest('/app/common/jobTitle/treeselect', {}, 'GET').then((resData) => {
|
||||
state.station = resData.data;
|
||||
});
|
||||
}
|
||||
|
||||
// 登录
|
||||
function loginTest() {
|
||||
// uni.share({
|
||||
// provider: 'weixin',
|
||||
// scene: 'WXSceneSession',
|
||||
// type: 2,
|
||||
// imageUrl: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni@2x.png',
|
||||
// success: function (res) {
|
||||
// console.log('success:' + JSON.stringify(res));
|
||||
// },
|
||||
// fail: function (err) {
|
||||
// console.log('fail:' + JSON.stringify(err));
|
||||
// },
|
||||
// });
|
||||
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: '/packageRc/pages/daiban/daiban',
|
||||
});
|
||||
} else {
|
||||
nextStep();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function complete() {
|
||||
const result = IdCardValidator.validate(fromValue.idcard);
|
||||
if (result.valid) {
|
||||
$api.createRequest('/app/user/resume', fromValue, 'post').then((resData) => {
|
||||
$api.msg('完成');
|
||||
// 获取用户信息并存储到store中
|
||||
getUserResume().then((userInfo) => {
|
||||
console.log('用户信息已存储到store:', userInfo);
|
||||
uni.reLaunch({
|
||||
url: '/packageRc/pages/daiban/daiban',
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$api.msg('身份证校验失败');
|
||||
console.log('验证失败:', result.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.input-nx
|
||||
position: relative
|
||||
border-bottom: 2rpx solid #EBEBEB
|
||||
padding-bottom: 30rpx
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
.nx-item
|
||||
padding: 20rpx 28rpx
|
||||
width: fit-content
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
border: 2rpx solid #E8EAEE;
|
||||
margin-right: 24rpx
|
||||
margin-top: 24rpx
|
||||
.nx-item::before
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 60rpx;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 18rpx;
|
||||
border-radius: 2rpx
|
||||
background: #697279;
|
||||
transform: translate(0, -50%) rotate(-45deg) ;
|
||||
.nx-item::after
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 61rpx;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 18rpx;
|
||||
border-radius: 2rpx
|
||||
background: #697279;
|
||||
transform: rotate(45deg)
|
||||
.container
|
||||
// background: linear-gradient(#4778EC, #002979);
|
||||
width: 100%;
|
||||
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
position: fixed;
|
||||
background: url('@/static/icon/background2.png') 0 0 no-repeat;
|
||||
background-size: 100% 728rpx;
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
.container-hader
|
||||
height: 88rpx;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
color: #000000;
|
||||
font-weight: bold
|
||||
font-size: 32rpx
|
||||
|
||||
.login-content
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 40%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex-wrap: nowrap;
|
||||
.logo
|
||||
width: 266rpx;
|
||||
height: 182rpx;
|
||||
.logo-title
|
||||
font-size: 88rpx;
|
||||
color: #22c984;
|
||||
width: 180rpx;
|
||||
.btns
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0)
|
||||
.wxlogin
|
||||
width: 562rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 70rpx;
|
||||
background-color: #13C57C;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
line-height: 140rpx;
|
||||
font-size: 70rpx;
|
||||
.wxaddress
|
||||
color: #BBBBBB;
|
||||
margin-top: 70rpx;
|
||||
text-align: center;
|
||||
.content-one
|
||||
padding: 60rpx 28rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between
|
||||
height: calc(100% - 120rpx)
|
||||
.content-title
|
||||
display: flex
|
||||
justify-content: space-between;
|
||||
align-items: center
|
||||
margin-bottom: 70rpx
|
||||
.title-lf
|
||||
font-size: 44rpx;
|
||||
color: #000000;
|
||||
font-weight: 600;
|
||||
.lf-text
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
.title-ri
|
||||
font-size: 36rpx;
|
||||
color: #000000;
|
||||
font-weight: 600;
|
||||
.content-input
|
||||
margin-bottom: 52rpx
|
||||
.input-titile
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6A6A6A;
|
||||
.input-con2
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
line-height: 80rpx;
|
||||
height: 80rpx;
|
||||
border-bottom: 2rpx solid #EBEBEB
|
||||
.input-con
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
line-height: 80rpx;
|
||||
height: 80rpx;
|
||||
border-bottom: 2rpx solid #EBEBEB
|
||||
position: relative;
|
||||
.input-con::before
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: calc(50% - 2rpx);
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 18rpx;
|
||||
border-radius: 2rpx
|
||||
background: #697279;
|
||||
transform: translate(0, -50%) rotate(-45deg) ;
|
||||
.input-con::after
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 50%;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 18rpx;
|
||||
border-radius: 2rpx
|
||||
background: #697279;
|
||||
transform: rotate(45deg)
|
||||
.content-sex
|
||||
height: 110rpx;
|
||||
display: flex
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
border-bottom: 2rpx solid #EBEBEB
|
||||
margin-bottom: 52rpx
|
||||
.sex-titile
|
||||
line-height: 80rpx;
|
||||
.sext-ri
|
||||
display: flex
|
||||
align-items: center;
|
||||
.sext-box
|
||||
height: 76rpx;
|
||||
width: 152rpx;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx
|
||||
border: 2rpx solid #E8EAEE;
|
||||
margin-left: 28rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
.sext-boxactive
|
||||
color: #256BFA
|
||||
background: rgba(37,107,250,0.1);
|
||||
border: 2rpx solid #256BFA;
|
||||
.next-btn
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
background: #256BFA;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
line-height: 90rpx
|
||||
</style>
|
||||
363
pages/mine/company-info.vue
Normal file
@@ -0,0 +1,363 @@
|
||||
<template>
|
||||
<AppLayout back-gorund-color="#F4F4F4">
|
||||
<!-- 编辑头像 -->
|
||||
<view class="avatar-section btn-feel" @click="editAvatar">
|
||||
<view class="avatar-label">编辑信息</view>
|
||||
<view class="avatar-container">
|
||||
<image class="company-avatar" :src="companyInfo.avatar || '/static/imgs/avatar.jpg'"></image>
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 企业详细信息 -->
|
||||
<view class="info-section">
|
||||
<view class="info-item btn-feel" @click="editInfo('name')">
|
||||
<view class="info-label">企业名称</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ companyInfo.name || '暂无公司名称' }}</text>
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item btn-feel" @click="editInfo('code')">
|
||||
<view class="info-label">统一社会代码</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ companyInfo.socialCode || '暂无统一社会代码' }}</text>
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item btn-feel" @click="editInfo('location')">
|
||||
<view class="info-label">企业注册地点</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ companyInfo.location || '暂无注册地点' }}</text>
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item btn-feel" @click="editInfo('description')">
|
||||
<view class="info-label">企业信息介绍</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ companyInfo.description || '暂无企业介绍' }}</text>
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item btn-feel" @click="editInfo('legalPerson')">
|
||||
<view class="info-label">企业法人姓名</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ companyInfo.legalPerson || '暂无法人信息' }}</text>
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 企业联系人管理 -->
|
||||
<view class="contact-management-section">
|
||||
<view class="contact-section-header">
|
||||
<view class="contact-section-title">企业联系人</view>
|
||||
<view class="edit-contacts-btn btn-feel" @click="editContacts">
|
||||
<uni-icons type="compose" size="16" color="#256BFA"></uni-icons>
|
||||
<text class="edit-text">编辑联系人</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系人列表展示 -->
|
||||
<view v-for="(contact, index) in companyInfo.companyContactList" :key="contact.id || index" class="contact-display-item">
|
||||
<view class="contact-display-title">联系人{{ index + 1 }}</view>
|
||||
<view class="contact-display-content">
|
||||
<view class="contact-field">
|
||||
<text class="field-label">姓名:</text>
|
||||
<text class="field-value">{{ contact.contactPerson || '暂无' }}</text>
|
||||
</view>
|
||||
<view class="contact-field">
|
||||
<text class="field-label">电话:</text>
|
||||
<text class="field-value">{{ contact.contactPersonPhone || '暂无' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 如果没有联系人,显示提示 -->
|
||||
<view v-if="!companyInfo.companyContactList || companyInfo.companyContactList.length === 0" class="no-contacts">
|
||||
<text class="no-contacts-text">暂无联系人信息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import AppLayout from '@/components/AppLayout/AppLayout.vue';
|
||||
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
|
||||
// 企业信息数据
|
||||
const companyInfo = reactive({
|
||||
name: '',
|
||||
avatar: '/static/imgs/avatar.jpg',
|
||||
completeness: '65%',
|
||||
socialCode: '',
|
||||
location: '',
|
||||
description: '',
|
||||
legalPerson: '',
|
||||
companyContactList: [], // 企业联系人列表
|
||||
isVerified: false // 实名状态
|
||||
});
|
||||
|
||||
function editAvatar() {
|
||||
// 编辑头像逻辑
|
||||
// uni.chooseImage({
|
||||
// count: 1,
|
||||
// success: (res) => {
|
||||
// // 上传头像
|
||||
// uploadAvatar(res.tempFilePaths[0]);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
function uploadAvatar(filePath) {
|
||||
// 上传头像到服务器
|
||||
uni.uploadFile({
|
||||
url: '/api/upload/avatar',
|
||||
filePath: filePath,
|
||||
name: 'avatar',
|
||||
success: (res) => {
|
||||
const data = JSON.parse(res.data);
|
||||
if (data.success) {
|
||||
companyInfo.avatar = data.data.url;
|
||||
uni.showToast({
|
||||
title: '头像更新成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function editInfo(type) {
|
||||
// 根据类型跳转到不同的编辑页面
|
||||
const editPages = {
|
||||
name: '/pages/mine/edit-company-name',
|
||||
code: '/pages/mine/edit-company-code',
|
||||
location: '/pages/mine/edit-company-location',
|
||||
description: '/pages/mine/edit-company-description',
|
||||
legalPerson: '/pages/mine/edit-legal-person'
|
||||
};
|
||||
|
||||
if (editPages[type]) {
|
||||
navTo(editPages[type]);
|
||||
}
|
||||
}
|
||||
|
||||
function editContacts() {
|
||||
// 跳转到联系人编辑页面
|
||||
navTo('/pages/mine/edit-company-contacts');
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
// 获取企业信息
|
||||
getCompanyInfo();
|
||||
});
|
||||
|
||||
// 从缓存获取公司信息
|
||||
function getCompanyInfo() {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
console.log('缓存中的userInfo:', cachedUserInfo);
|
||||
|
||||
// 检查是否有company字段
|
||||
if (cachedUserInfo.company) {
|
||||
const company = cachedUserInfo.company;
|
||||
|
||||
// 基本信息
|
||||
companyInfo.name = company.name || '';
|
||||
companyInfo.socialCode = company.code || '';
|
||||
companyInfo.location = company.registeredAddress || '';
|
||||
companyInfo.description = company.description || '';
|
||||
companyInfo.legalPerson = company.legalPerson || '';
|
||||
|
||||
// 联系人信息 - 直接使用companyContactList数组
|
||||
companyInfo.companyContactList = company.companyContactList || [];
|
||||
|
||||
// 判断是否实名:legalIdCard字段有值则表示已实名
|
||||
companyInfo.isVerified = !!(company.legalIdCard && company.legalIdCard.trim());
|
||||
|
||||
console.log('公司名称:', companyInfo.name);
|
||||
console.log('实名状态:', companyInfo.isVerified);
|
||||
console.log('legalIdCard值:', company.legalIdCard);
|
||||
} else {
|
||||
console.log('缓存中没有company字段');
|
||||
// 保持默认值
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取公司信息失败:', error);
|
||||
// 保持默认值
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.avatar-label {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.company-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-section {
|
||||
background: #FFFFFF;
|
||||
margin: 0 20rpx 40rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #F5F5F5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
min-width: 200rpx;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
.info-value {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
margin-right: 16rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-feel {
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.contact-management-section {
|
||||
border-top: 20rpx solid #F4F4F4;
|
||||
|
||||
.contact-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #F8F8F8;
|
||||
border-bottom: 1rpx solid #F5F5F5;
|
||||
|
||||
.contact-section-title {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.edit-contacts-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8rpx 16rpx;
|
||||
background: #E6F7FF;
|
||||
border-radius: 8rpx;
|
||||
|
||||
.edit-text {
|
||||
font-size: 24rpx;
|
||||
color: #256BFA;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contact-display-item {
|
||||
padding: 20rpx 30rpx;
|
||||
border-bottom: 1rpx solid #F5F5F5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.contact-display-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.contact-display-content {
|
||||
.contact-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.field-label {
|
||||
font-size: 26rpx;
|
||||
color: #6C7282;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
.field-value {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-contacts {
|
||||
padding: 40rpx 30rpx;
|
||||
text-align: center;
|
||||
|
||||
.no-contacts-text {
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
285
pages/mine/company-mine.vue
Normal file
@@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<AppLayout back-gorund-color="#F4F4F4">
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="4" />
|
||||
|
||||
<!-- 企业信息卡片 -->
|
||||
<view class="company-info-card btn-feel" @click="goToCompanyInfo">
|
||||
<view class="company-avatar">
|
||||
<image class="company-avatar-img" :src="companyInfo.avatar || '/static/imgs/avatar.jpg'"></image>
|
||||
</view>
|
||||
<view class="company-details">
|
||||
<view class="company-name">{{ companyInfo.name || '暂无公司名称' }}</view>
|
||||
<view class="company-completeness">
|
||||
信息完整度 {{ companyInfo.completeness || '100%' }}
|
||||
<text class="verification-status" :class="{ 'verified': companyInfo.isVerified, 'unverified': !companyInfo.isVerified }">
|
||||
{{ companyInfo.isVerified ? '已实名' : '未实名' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="company-arrow">
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 服务专区 -->
|
||||
<view class="service-zone-card">
|
||||
<view class="service-title">服务专区</view>
|
||||
<view class="service-item btn-feel">
|
||||
<view class="service-left">
|
||||
<uni-icons type="contact" size="20" color="#256BFA"></uni-icons>
|
||||
<text class="service-text">实名认证</text>
|
||||
</view>
|
||||
<view class="service-status" :class="{ 'verified': companyInfo.isVerified, 'unverified': !companyInfo.isVerified }">
|
||||
{{ companyInfo.isVerified ? '已通过' : '未认证' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="service-item btn-feel">
|
||||
<view class="service-left">
|
||||
<uni-icons type="notification" size="20" color="#256BFA"></uni-icons>
|
||||
<text class="service-text">通知与提醒</text>
|
||||
</view>
|
||||
<view class="service-status">已开启</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<view class="logout-btn btn-feel" @click="logOut">
|
||||
退出登录
|
||||
</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>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, ref, onMounted, onUnmounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
const popup = ref(null);
|
||||
|
||||
// 企业信息数据
|
||||
const companyInfo = reactive({
|
||||
name: '',
|
||||
avatar: '/static/imgs/avatar.jpg',
|
||||
completeness: '100%',
|
||||
isVerified: false // 实名状态
|
||||
});
|
||||
|
||||
function goToCompanyInfo() {
|
||||
navTo('/pages/mine/company-info');
|
||||
}
|
||||
|
||||
function logOut() {
|
||||
popup.value.open();
|
||||
}
|
||||
|
||||
function close() {
|
||||
popup.value.close();
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
// 调用退出登录
|
||||
useUserStore().logOut();
|
||||
// 关闭弹窗
|
||||
popup.value.close();
|
||||
// 跳转到首页
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
// 获取企业信息
|
||||
getCompanyInfo();
|
||||
});
|
||||
|
||||
// 监听退出登录事件,显示微信登录弹窗
|
||||
onMounted(() => {
|
||||
uni.$on('showLoginModal', () => {
|
||||
// 这里可以显示微信登录弹窗
|
||||
// 由于这个页面没有 WxAuthLogin 组件,我们跳转到首页让首页处理
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('showLoginModal');
|
||||
});
|
||||
|
||||
// 从缓存获取公司信息
|
||||
function getCompanyInfo() {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
console.log('缓存中的userInfo:', cachedUserInfo);
|
||||
|
||||
// 检查是否有company字段
|
||||
if (cachedUserInfo.company) {
|
||||
companyInfo.name = cachedUserInfo.company.name || '';
|
||||
// 判断是否实名:legalIdCard字段有值则表示已实名
|
||||
companyInfo.isVerified = !!(cachedUserInfo.company.legalIdCard && cachedUserInfo.company.legalIdCard.trim());
|
||||
console.log('公司名称:', companyInfo.name);
|
||||
console.log('实名状态:', companyInfo.isVerified);
|
||||
console.log('legalIdCard值:', cachedUserInfo.company.legalIdCard);
|
||||
} else {
|
||||
console.log('缓存中没有company字段');
|
||||
companyInfo.name = '';
|
||||
companyInfo.isVerified = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取公司信息失败:', error);
|
||||
companyInfo.name = '';
|
||||
companyInfo.isVerified = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.company-info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.company-avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-right: 24rpx;
|
||||
|
||||
.company-avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.company-details {
|
||||
flex: 1;
|
||||
|
||||
.company-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.company-completeness {
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
|
||||
.verification-status {
|
||||
font-size: 24rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
|
||||
&.verified {
|
||||
background-color: #E8F5E8;
|
||||
color: #52C41A;
|
||||
}
|
||||
|
||||
&.unverified {
|
||||
background-color: #FFF2E8;
|
||||
color: #FA8C16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.company-arrow {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.service-zone-card {
|
||||
background: #FFFFFF;
|
||||
margin: 0 20rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
padding: 32rpx;
|
||||
|
||||
.service-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #000000;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.service-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 0;
|
||||
border-bottom: 1rpx solid #F5F5F5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.service-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.service-text {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.service-status {
|
||||
font-size: 28rpx;
|
||||
color: #6E6E6E;
|
||||
|
||||
&.verified {
|
||||
color: #52C41A;
|
||||
}
|
||||
|
||||
&.unverified {
|
||||
color: #FA8C16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
height: 96rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 0 20rpx 40rpx;
|
||||
border-radius: 20rpx;
|
||||
text-align: center;
|
||||
line-height: 96rpx;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.btn-feel {
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
470
pages/mine/edit-company-contacts.vue
Normal file
@@ -0,0 +1,470 @@
|
||||
<template>
|
||||
<AppLayout back-gorund-color="#F4F4F4">
|
||||
|
||||
<!-- 联系人列表 -->
|
||||
<view class="contacts-section">
|
||||
<view v-for="(contact, index) in contactList" :key="contact.tempId || contact.id" class="contact-item">
|
||||
<view class="contact-header">
|
||||
<text class="contact-title">联系人{{ index + 1 }}</text>
|
||||
<view class="contact-actions" v-if="contactList.length > 1">
|
||||
<view class="action-btn delete-btn" @click="deleteContact(index)">
|
||||
<uni-icons type="trash" size="16" color="#FF4D4F"></uni-icons>
|
||||
<text class="action-text">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="contact-form">
|
||||
<view class="form-item">
|
||||
<view class="form-label">联系人姓名</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="contact.contactPerson"
|
||||
placeholder="请输入联系人姓名"
|
||||
@blur="validateContactName(index)"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">联系电话</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="contact.contactPersonPhone"
|
||||
placeholder="请输入联系电话"
|
||||
type="number"
|
||||
@blur="validateContactPhone(index)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 添加联系人按钮 -->
|
||||
<view class="add-contact-section" v-if="contactList.length < 3">
|
||||
<view class="add-contact-btn btn-feel" @click="addContact">
|
||||
<uni-icons type="plus" size="20" color="#256BFA"></uni-icons>
|
||||
<text class="add-text">添加联系人</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<view class="save-section">
|
||||
<view class="save-btn btn-feel" @click="saveContacts">
|
||||
<text class="save-text">保存联系人</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<view class="tips-section">
|
||||
<view class="tips-title">温馨提示</view>
|
||||
<view class="tips-content">
|
||||
<text class="tips-item">• 至少需要保留一个联系人,最多可添加3个联系人</text>
|
||||
<text class="tips-item">• 联系人姓名和电话为必填项</text>
|
||||
<text class="tips-item">• 联系电话请填写正确的手机号码</text>
|
||||
</view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import AppLayout from '@/components/AppLayout/AppLayout.vue';
|
||||
import { createRequest } from '@/utils/request.js';
|
||||
|
||||
const { navTo } = inject('globalFunction');
|
||||
|
||||
// 联系人列表数据
|
||||
const contactList = reactive([]);
|
||||
let tempIdCounter = 0; // 用于生成临时ID
|
||||
|
||||
// 页面加载时获取联系人数据
|
||||
onLoad((options) => {
|
||||
// 从缓存获取企业联系人信息
|
||||
loadContactsFromCache();
|
||||
});
|
||||
|
||||
// 从缓存加载联系人数据
|
||||
function loadContactsFromCache() {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
if (cachedUserInfo.company && cachedUserInfo.company.companyContactList) {
|
||||
const contacts = cachedUserInfo.company.companyContactList;
|
||||
|
||||
// 如果联系人列表为空,至少添加一个空联系人
|
||||
if (contacts.length === 0) {
|
||||
contactList.push(createEmptyContact());
|
||||
} else {
|
||||
// 为每个联系人添加临时ID(如果没有ID的话)
|
||||
contacts.forEach(contact => {
|
||||
if (!contact.tempId) {
|
||||
contact.tempId = `temp_${++tempIdCounter}`;
|
||||
}
|
||||
contactList.push({ ...contact });
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 如果没有联系人数据,创建一个空联系人
|
||||
contactList.push(createEmptyContact());
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载联系人数据失败:', error);
|
||||
// 出错时至少创建一个空联系人
|
||||
contactList.push(createEmptyContact());
|
||||
}
|
||||
}
|
||||
|
||||
// 创建空联系人
|
||||
function createEmptyContact() {
|
||||
return {
|
||||
id: '',
|
||||
contactPerson: '',
|
||||
contactPersonPhone: '',
|
||||
tempId: `temp_${++tempIdCounter}`
|
||||
};
|
||||
}
|
||||
|
||||
// 添加联系人
|
||||
function addContact() {
|
||||
if (contactList.length >= 3) {
|
||||
uni.showToast({
|
||||
title: '最多只能添加3个联系人',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
contactList.push(createEmptyContact());
|
||||
}
|
||||
|
||||
// 删除联系人
|
||||
function deleteContact(index) {
|
||||
if (contactList.length <= 1) {
|
||||
uni.showToast({
|
||||
title: '至少需要保留一个联系人',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这个联系人吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
contactList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 验证联系人姓名
|
||||
function validateContactName(index) {
|
||||
const contact = contactList[index];
|
||||
if (!contact.contactPerson || contact.contactPerson.trim() === '') {
|
||||
uni.showToast({
|
||||
title: '请输入联系人姓名',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 验证联系人电话
|
||||
function validateContactPhone(index) {
|
||||
const contact = contactList[index];
|
||||
if (!contact.contactPersonPhone || contact.contactPersonPhone.trim() === '') {
|
||||
uni.showToast({
|
||||
title: '请输入联系电话',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// 简单的手机号验证
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(contact.contactPersonPhone)) {
|
||||
uni.showToast({
|
||||
title: '请输入正确的手机号码',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 验证所有联系人
|
||||
function validateAllContacts() {
|
||||
for (let i = 0; i < contactList.length; i++) {
|
||||
if (!validateContactName(i) || !validateContactPhone(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 保存联系人
|
||||
async function saveContacts() {
|
||||
// 验证所有联系人信息
|
||||
if (!validateAllContacts()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '保存中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 获取companyId
|
||||
const companyId = getCompanyIdFromCache();
|
||||
if (!companyId) {
|
||||
uni.showToast({
|
||||
title: '获取企业信息失败,请重新登录',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 准备API数据,移除临时ID,添加companyId
|
||||
const apiData = contactList.map(contact => ({
|
||||
id: contact.id || '',
|
||||
contactPerson: contact.contactPerson.trim(),
|
||||
contactPersonPhone: contact.contactPersonPhone.trim(),
|
||||
companyId: companyId
|
||||
}));
|
||||
|
||||
// 调用API保存联系人
|
||||
const response = await createRequest(
|
||||
'/app/companycontact/batchInsertUpdate',
|
||||
{
|
||||
companyContactList: apiData
|
||||
},
|
||||
'POST',
|
||||
false
|
||||
);
|
||||
|
||||
if (response.code === 200) {
|
||||
// 保存成功,更新本地缓存
|
||||
updateLocalCache(apiData);
|
||||
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 延迟返回上一页
|
||||
setTimeout(() => {
|
||||
goBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存联系人失败:', error);
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 从缓存获取companyId
|
||||
function getCompanyIdFromCache() {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
if (cachedUserInfo.company && cachedUserInfo.company.companyId) {
|
||||
return cachedUserInfo.company.companyId;
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('获取companyId失败:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新本地缓存
|
||||
function updateLocalCache(contactData) {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
if (cachedUserInfo.company) {
|
||||
cachedUserInfo.company.companyContactList = contactData;
|
||||
uni.setStorageSync('userInfo', cachedUserInfo);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新本地缓存失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.save-section {
|
||||
margin: 0 20rpx 20rpx;
|
||||
|
||||
.save-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 88rpx;
|
||||
background: #256BFA;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(37, 107, 250, 0.3);
|
||||
|
||||
.save-text {
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contacts-section {
|
||||
margin: 20rpx;
|
||||
|
||||
.contact-item {
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.contact-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx 30rpx 20rpx;
|
||||
border-bottom: 1rpx solid #F5F5F5;
|
||||
|
||||
.contact-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.contact-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
|
||||
&.delete-btn {
|
||||
background: #FFF2F0;
|
||||
|
||||
.action-text {
|
||||
font-size: 24rpx;
|
||||
color: #FF4D4F;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
padding: 20rpx 30rpx 30rpx;
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 26rpx;
|
||||
color: #6C7282;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: #F8F9FA;
|
||||
border: 1rpx solid #E9ECEF;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus {
|
||||
border-color: #256BFA;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-contact-section {
|
||||
margin: 0 20rpx 20rpx;
|
||||
|
||||
.add-contact-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 88rpx;
|
||||
background: #FFFFFF;
|
||||
border: 2rpx dashed #256BFA;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.add-text {
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips-section {
|
||||
margin: 0 20rpx 40rpx;
|
||||
padding: 30rpx;
|
||||
background: #F8F9FA;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.tips-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tips-content {
|
||||
.tips-item {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-feel {
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,23 @@
|
||||
<template>
|
||||
<AppLayout title="我的" back-gorund-color="#F4F4F4">
|
||||
<view class="mine-userinfo btn-feel" @click="seeDetail">
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="4" />
|
||||
<!-- 企业用户信息卡片 -->
|
||||
<view v-if="userType === 0" class="company-info-card btn-feel" @click="seeDetail">
|
||||
<view class="company-avatar">
|
||||
<image class="company-avatar-img" :src="companyInfo.avatar || '/static/icon/company-default.png'"></image>
|
||||
</view>
|
||||
<view class="company-details">
|
||||
<view class="company-name">{{ companyInfo.name || '科里喀什分公司' }}</view>
|
||||
<view class="company-completeness">信息完整度 {{ companyInfo.completeness || '100%' }}</view>
|
||||
</view>
|
||||
<view class="company-arrow">
|
||||
<uni-icons color="#A2A2A2" type="right" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 求职者用户信息卡片 -->
|
||||
<view v-else class="mine-userinfo btn-feel" @click="seeDetail">
|
||||
<view class="userindo-head">
|
||||
<image class="userindo-head-img" v-if="userInfo.sex === '0'" src="/static/icon/boy.png"></image>
|
||||
<image class="userindo-head-img" v-else src="/static/icon/girl.png"></image>
|
||||
@@ -83,7 +100,8 @@
|
||||
<view class="row-right">已开启</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-back button-click" @click="logOut">退出登录</view>
|
||||
<view v-if="userType === 2" class="card-help button-click" @click="goToJobHelper">求职帮</view>
|
||||
<view class="card-back button-click" @click="logOut">退出登录</view>
|
||||
<uni-popup ref="popup" type="dialog">
|
||||
<uni-popup-dialog
|
||||
mode="base"
|
||||
@@ -103,19 +121,56 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { reactive, inject, watch, ref, onMounted, onUnmounted, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { tabbarManager } from '@/utils/tabbarManager';
|
||||
const popup = ref(null);
|
||||
const { userInfo, Completion } = storeToRefs(useUserStore());
|
||||
const counts = ref({});
|
||||
|
||||
// 获取用户类型,参考首页的实现方式
|
||||
const userType = computed(() => {
|
||||
// 优先从store获取,如果为空则从缓存获取
|
||||
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
|
||||
|
||||
// 获取用户类型:优先使用store中的isCompanyUser,如果store中没有,使用缓存中的isCompanyUser
|
||||
// 缓存中的值可能是字符串,需要转换为数值类型
|
||||
return storeIsCompanyUser !== undefined ? Number(storeIsCompanyUser) : Number(cachedIsCompanyUser);
|
||||
});
|
||||
|
||||
// 企业信息数据
|
||||
const companyInfo = reactive({
|
||||
name: '科里喀什分公司',
|
||||
avatar: '/static/icon/company-avatar.png',
|
||||
completeness: '100%'
|
||||
});
|
||||
function logOut() {
|
||||
popup.value.open();
|
||||
}
|
||||
onShow(() => {
|
||||
getUserstatistics();
|
||||
// 更新自定义tabbar选中状态
|
||||
tabbarManager.updateSelected(4);
|
||||
});
|
||||
|
||||
// 监听退出登录事件,显示微信登录弹窗
|
||||
onMounted(() => {
|
||||
uni.$on('showLoginModal', () => {
|
||||
// 这里可以显示微信登录弹窗
|
||||
// 由于这个页面没有 WxAuthLogin 组件,我们跳转到首页让首页处理
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('showLoginModal');
|
||||
});
|
||||
|
||||
function close() {
|
||||
@@ -135,12 +190,19 @@ function getUserstatistics() {
|
||||
});
|
||||
}
|
||||
function seeDetail() {
|
||||
if (userInfo.isCompanyUser) {
|
||||
navTo('/packageA/pages/myResume/corporateInformation');
|
||||
if (userType === 0) {
|
||||
// 企业用户跳转到企业信息页面
|
||||
navTo('/pages/mine/company-info');
|
||||
} else {
|
||||
// 求职者用户跳转到简历页面
|
||||
navTo('/packageA/pages/myResume/myResume');
|
||||
}
|
||||
}
|
||||
|
||||
function goToJobHelper() {
|
||||
// 跳转到求职者信息补全页面
|
||||
navTo('/pages/complete-info/complete-info');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@@ -240,6 +302,16 @@ function seeDetail() {
|
||||
margin: 0
|
||||
}
|
||||
}
|
||||
.card-help{
|
||||
height: 96rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
text-align: center;
|
||||
line-height: 96rpx;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.card-back{
|
||||
height: 96rpx;
|
||||
background: #FFFFFF;
|
||||
@@ -321,4 +393,48 @@ function seeDetail() {
|
||||
border-radius: 2rpx
|
||||
background: #A2A2A2;
|
||||
transform: rotate(45deg)
|
||||
|
||||
// 企业信息卡片样式
|
||||
.company-info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.company-avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-right: 24rpx;
|
||||
|
||||
.company-avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.company-details {
|
||||
flex: 1;
|
||||
|
||||
.company-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.company-completeness {
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
|
||||
.company-arrow {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,34 +21,45 @@
|
||||
<component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<ReadComponent v-show="currentIndex === 0" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<UnreadComponent v-show="currentIndex === 1" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<ReadComponent v-show="state.current === 0" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<UnreadComponent v-show="state.current === 1" :ref="(el) => handelComponentsRef(el, index)" />
|
||||
<!-- #endif -->
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="3" />
|
||||
|
||||
<!-- 微信授权登录弹窗 -->
|
||||
<WxAuthLogin ref="wxAuthLoginRef" @success="handleLoginSuccess"></WxAuthLogin>
|
||||
|
||||
<!-- 统一使用系统tabBar -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { reactive, inject, watch, ref, onMounted, onUnmounted } 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';
|
||||
import { tabbarManager } from '@/utils/tabbarManager';
|
||||
import WxAuthLogin from '@/components/WxAuthLogin/WxAuthLogin.vue';
|
||||
const loadedMap = reactive([false, false]);
|
||||
const swiperRefs = [ref(null), ref(null)];
|
||||
const components = [ReadComponent, UnreadComponent];
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
const { unreadCount } = storeToRefs(useReadMsg());
|
||||
const wxAuthLoginRef = ref(null);
|
||||
|
||||
onShow(() => {
|
||||
// 获取消息列表
|
||||
useReadMsg().fetchMessages();
|
||||
// 更新自定义tabbar选中状态
|
||||
tabbarManager.updateSelected(3);
|
||||
});
|
||||
const state = reactive({
|
||||
current: 0,
|
||||
@@ -57,8 +68,23 @@ const state = reactive({
|
||||
|
||||
onMounted(() => {
|
||||
handleTabChange(state.current);
|
||||
|
||||
// 监听退出登录事件,显示微信登录弹窗
|
||||
uni.$on('showLoginModal', () => {
|
||||
wxAuthLoginRef.value?.open();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('showLoginModal');
|
||||
});
|
||||
|
||||
// 登录成功回调
|
||||
const handleLoginSuccess = () => {
|
||||
console.log('登录成功');
|
||||
// 可以在这里添加登录成功后的处理逻辑
|
||||
};
|
||||
|
||||
const handelComponentsRef = (el, index) => {
|
||||
if (el) {
|
||||
swiperRefs[index].value = el;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<scroll-view scroll-y class="main-scroll">
|
||||
<view class="scrollmain">
|
||||
<!-- 消息列表 -->
|
||||
<view
|
||||
class="list-card press-button"
|
||||
v-for="(item, index) in msgList"
|
||||
@@ -35,6 +36,13 @@
|
||||
<view class="info-text line_2">{{ item.subTitle || '消息' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 暂无消息提示 -->
|
||||
<view class="empty-state" v-if="msgList.length === 0">
|
||||
<image class="empty-icon" src="/static/icon/empty.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无消息</text>
|
||||
<text class="empty-desc">您还没有收到任何消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
@@ -146,4 +154,26 @@ defineExpose({ loadData });
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
margin-top: 4rpx;
|
||||
|
||||
// 空状态样式
|
||||
.empty-state
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 40rpx;
|
||||
.empty-icon
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.6;
|
||||
.empty-text
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16rpx;
|
||||
.empty-desc
|
||||
font-size: 28rpx;
|
||||
color: #CCCCCC;
|
||||
font-weight: 400;
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<scroll-view scroll-y class="main-scroll">
|
||||
<view class="scrollmain">
|
||||
<!-- 未读消息列表 -->
|
||||
<view
|
||||
class="list-card press-button"
|
||||
v-for="(item, index) in unreadMsgList"
|
||||
@@ -33,6 +34,13 @@
|
||||
<view class="info-text line_2">{{ item.subTitle || '消息' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 暂无未读消息提示 -->
|
||||
<view class="empty-state" v-if="unreadMsgList.length === 0">
|
||||
<image class="empty-icon" src="/static/icon/empty.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无未读消息</text>
|
||||
<text class="empty-desc">您没有未读的消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
@@ -132,4 +140,26 @@ defineExpose({ loadData });
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
margin-top: 4rpx;
|
||||
|
||||
// 空状态样式
|
||||
.empty-state
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 40rpx;
|
||||
.empty-icon
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.6;
|
||||
.empty-text
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16rpx;
|
||||
.empty-desc
|
||||
font-size: 28rpx;
|
||||
color: #CCCCCC;
|
||||
font-weight: 400;
|
||||
</style>
|
||||
|
||||
156
pages/test/company-mine-test.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<AppLayout title="企业我的页面测试" back-gorund-color="#F4F4F4">
|
||||
<view class="test-container">
|
||||
<view class="test-section">
|
||||
<view class="section-title">用户类型切换测试</view>
|
||||
<view class="button-group">
|
||||
<button class="test-btn" @click="switchToCompany">切换到企业用户</button>
|
||||
<button class="test-btn" @click="switchToJobSeeker">切换到求职者</button>
|
||||
</view>
|
||||
<view class="current-type">
|
||||
当前用户类型:{{ getCurrentTypeLabel() }} ({{ currentUserType }})
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<view class="section-title">页面跳转测试</view>
|
||||
<view class="button-group">
|
||||
<button class="test-btn" @click="goToCompanyMine">企业我的页面</button>
|
||||
<button class="test-btn" @click="goToCompanyInfo">企业信息页面</button>
|
||||
<button class="test-btn" @click="goToMine">普通我的页面</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<view class="section-title">用户信息显示</view>
|
||||
<view class="info-display">
|
||||
<text>用户类型:{{ userInfo.isCompanyUser }}</text>
|
||||
<text>用户名:{{ userInfo.name || '未设置' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userInfo } = storeToRefs(userStore);
|
||||
|
||||
const userTypes = [
|
||||
{ value: 0, label: '企业用户' },
|
||||
{ value: 1, label: '求职者' },
|
||||
{ value: 2, label: '网格员' },
|
||||
{ value: 3, label: '政府人员' }
|
||||
];
|
||||
|
||||
const currentUserType = computed(() => userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : 1);
|
||||
|
||||
const switchToCompany = () => {
|
||||
userInfo.value.isCompanyUser = 0;
|
||||
userInfo.value.name = '科里喀什分公司';
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
uni.showToast({
|
||||
title: '已切换到企业用户',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const switchToJobSeeker = () => {
|
||||
userInfo.value.isCompanyUser = 1;
|
||||
userInfo.value.name = '求职者用户';
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
uni.showToast({
|
||||
title: '已切换到求职者',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const getCurrentTypeLabel = () => {
|
||||
const type = userTypes.find(t => t.value === currentUserType.value);
|
||||
return type ? type.label : '未知';
|
||||
};
|
||||
|
||||
const goToCompanyMine = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mine/company-mine'
|
||||
});
|
||||
};
|
||||
|
||||
const goToCompanyInfo = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mine/company-info'
|
||||
});
|
||||
};
|
||||
|
||||
const goToMine = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mine/mine'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.test-container {
|
||||
padding: 40rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.test-section {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.test-btn {
|
||||
background: #256BFA;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.current-type {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.info-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
padding: 10rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
170
pages/test/company-search-test.vue
Normal file
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<view class="test-page">
|
||||
<view class="header">
|
||||
<text class="title">企业搜索功能测试</text>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<view class="section-title">功能说明</view>
|
||||
<view class="description">
|
||||
<text class="desc-text">• 企业用户(isCompanyUser=0):招聘公司输入框为普通输入框</text>
|
||||
<text class="desc-text">• 网格员(isCompanyUser=2):招聘公司输入框为选择器,点击跳转到搜索页面</text>
|
||||
<text class="desc-text">• 搜索页面支持防抖节流,500ms延迟</text>
|
||||
<text class="desc-text">• 搜索接口:/app/company/likeList,参数:name</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<view class="section-title">当前用户类型</view>
|
||||
<view class="user-type-info">
|
||||
<text class="type-label">用户类型:</text>
|
||||
<text class="type-value">{{ getCurrentTypeLabel() }} ({{ currentUserType }})</text>
|
||||
</view>
|
||||
<view class="user-type-info">
|
||||
<text class="type-label">是否企业用户:</text>
|
||||
<text class="type-value">{{ isCompanyUser ? '是' : '否' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<view class="section-title">测试操作</view>
|
||||
<view class="button-group">
|
||||
<button class="test-btn" @click="switchToCompany">切换到企业用户</button>
|
||||
<button class="test-btn" @click="switchToGrid">切换到网格员</button>
|
||||
<button class="test-btn" @click="goToPublishJob">进入发布岗位页面</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userInfo } = storeToRefs(userStore);
|
||||
|
||||
const userTypes = [
|
||||
{ value: 0, label: '企业用户' },
|
||||
{ value: 1, label: '求职者' },
|
||||
{ value: 2, label: '网格员' },
|
||||
{ value: 3, label: '政府人员' }
|
||||
];
|
||||
|
||||
const currentUserType = computed(() => userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : 1);
|
||||
|
||||
const isCompanyUser = computed(() => {
|
||||
return currentUserType.value === 0;
|
||||
});
|
||||
|
||||
const getCurrentTypeLabel = () => {
|
||||
const type = userTypes.find(t => t.value === currentUserType.value);
|
||||
return type ? type.label : '未知';
|
||||
};
|
||||
|
||||
const switchToCompany = () => {
|
||||
userInfo.value.isCompanyUser = 0;
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
uni.showToast({
|
||||
title: '已切换到企业用户',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const switchToGrid = () => {
|
||||
userInfo.value.isCompanyUser = 2;
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
uni.showToast({
|
||||
title: '已切换到网格员',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const goToPublishJob = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/job/publishJob'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.test-page {
|
||||
padding: 40rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.test-section {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.description {
|
||||
.desc-text {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.user-type-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.type-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.type-value {
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
|
||||
.test-btn {
|
||||
height: 80rpx;
|
||||
background: #256BFA;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
|
||||
&:active {
|
||||
background: #1e5ce6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
296
pages/test/homepage-test.vue
Normal file
@@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<view class="homepage-test">
|
||||
<view class="header">
|
||||
<text class="title">首页内容测试</text>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<view class="user-info">
|
||||
<text class="label">当前用户类型:</text>
|
||||
<text class="value">{{ getCurrentUserTypeLabel() }}</text>
|
||||
</view>
|
||||
|
||||
<view class="login-status">
|
||||
<text class="label">登录状态:</text>
|
||||
<text class="value" :class="{ 'logged-in': hasLogin, 'not-logged-in': !hasLogin }">
|
||||
{{ hasLogin ? '已登录' : '未登录' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="debug-info">
|
||||
<text class="label">调试信息:</text>
|
||||
<text class="value">userType: {{ userInfo?.userType ?? 'undefined' }}</text>
|
||||
<text class="value">hasLogin: {{ hasLogin }}</text>
|
||||
<text class="value">shouldShowJobSeeker: {{ shouldShowJobSeekerContent }}</text>
|
||||
<text class="value">shouldShowCompany: {{ shouldShowCompanyContent }}</text>
|
||||
<text class="value">完整userInfo: {{ JSON.stringify(userInfo) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="content-preview">
|
||||
<text class="section-title">首页内容预览:</text>
|
||||
|
||||
<view class="content-item" v-if="shouldShowJobSeekerContent">
|
||||
<text class="content-label">✅ 求职者内容</text>
|
||||
<text class="content-desc">• 附近工作卡片</text>
|
||||
<text class="content-desc">• 服务功能网格</text>
|
||||
<text class="content-desc">• 职位筛选器</text>
|
||||
</view>
|
||||
|
||||
<view class="content-item" v-if="shouldShowCompanyContent">
|
||||
<text class="content-label">✅ 企业用户内容</text>
|
||||
<text class="content-desc">• 企业服务标题</text>
|
||||
<text class="content-desc">• 发布岗位按钮</text>
|
||||
<text class="content-desc">• 企业管理功能</text>
|
||||
</view>
|
||||
|
||||
<view class="content-item" v-if="!shouldShowJobSeekerContent && !shouldShowCompanyContent">
|
||||
<text class="content-label">❌ 无内容显示</text>
|
||||
<text class="content-desc">请检查用户类型设置</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="test-buttons">
|
||||
<button @click="testLoginAsJobSeeker" class="test-btn">模拟求职者登录</button>
|
||||
<button @click="testLoginAsCompany" class="test-btn">模拟企业用户登录</button>
|
||||
<button @click="testLogout" class="test-btn" v-if="hasLogin">模拟登出</button>
|
||||
<button @click="forceRefreshUserInfo" class="test-btn">强制刷新用户信息</button>
|
||||
<button @click="clearUserInfo" class="test-btn">清除用户信息</button>
|
||||
<button @click="refreshTabBar" class="test-btn">刷新TabBar</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="0" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { tabbarManager } from '@/utils/tabbarManager';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userInfo, hasLogin } = storeToRefs(userStore);
|
||||
|
||||
const userTypes = [
|
||||
{ value: 0, label: '企业用户' },
|
||||
{ value: 1, label: '求职者' },
|
||||
{ value: 2, label: '网格员' },
|
||||
{ value: 3, label: '政府人员' }
|
||||
];
|
||||
|
||||
const currentUserType = computed(() => userInfo.value?.userType || 1);
|
||||
|
||||
const getCurrentUserTypeLabel = () => {
|
||||
const type = userTypes.find(t => t.value === currentUserType.value);
|
||||
return type ? type.label : '未知';
|
||||
};
|
||||
|
||||
// 计算是否显示求职者内容
|
||||
const shouldShowJobSeekerContent = computed(() => {
|
||||
if (!hasLogin.value) {
|
||||
return true;
|
||||
}
|
||||
const userType = userInfo.value?.isCompanyUser;
|
||||
return userType !== 0;
|
||||
});
|
||||
|
||||
// 计算是否显示企业用户内容
|
||||
const shouldShowCompanyContent = computed(() => {
|
||||
if (!hasLogin.value) {
|
||||
return false;
|
||||
}
|
||||
const userType = userInfo.value?.isCompanyUser;
|
||||
return userType === 0;
|
||||
});
|
||||
|
||||
const testLoginAsJobSeeker = () => {
|
||||
const mockUserInfo = {
|
||||
userType: 1,
|
||||
name: '求职者用户',
|
||||
id: 'jobseeker123'
|
||||
};
|
||||
userInfo.value = mockUserInfo;
|
||||
userStore.hasLogin = true;
|
||||
uni.setStorageSync('userInfo', mockUserInfo);
|
||||
uni.showToast({
|
||||
title: '模拟求职者登录成功',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const testLoginAsCompany = () => {
|
||||
const mockUserInfo = {
|
||||
userType: 0,
|
||||
name: '企业用户',
|
||||
id: 'company123'
|
||||
};
|
||||
userInfo.value = mockUserInfo;
|
||||
userStore.hasLogin = true;
|
||||
uni.setStorageSync('userInfo', mockUserInfo);
|
||||
uni.showToast({
|
||||
title: '模拟企业用户登录成功',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const testLogout = () => {
|
||||
userStore.logOut(false);
|
||||
uni.showToast({
|
||||
title: '模拟登出成功',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const forceRefreshUserInfo = () => {
|
||||
// 从本地存储重新加载用户信息
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo');
|
||||
if (cachedUserInfo) {
|
||||
userInfo.value = cachedUserInfo;
|
||||
userStore.hasLogin = true;
|
||||
uni.showToast({
|
||||
title: '用户信息已刷新',
|
||||
icon: 'success'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '未找到用户信息',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const clearUserInfo = () => {
|
||||
// 清除所有用户信息
|
||||
uni.removeStorageSync('userInfo');
|
||||
uni.removeStorageSync('token');
|
||||
userInfo.value = {};
|
||||
userStore.hasLogin = false;
|
||||
uni.showToast({
|
||||
title: '用户信息已清除',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const refreshTabBar = () => {
|
||||
// 刷新tabbar
|
||||
tabbarManager.refreshTabBar();
|
||||
uni.showToast({
|
||||
title: 'TabBar已刷新',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.homepage-test {
|
||||
padding: 40rpx;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.content {
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.user-info, .login-status, .debug-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 20rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.debug-info .value {
|
||||
font-size: 20rpx;
|
||||
color: #666;
|
||||
margin: 5rpx 0;
|
||||
display: block;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.logged-in {
|
||||
color: #52c41a !important;
|
||||
}
|
||||
|
||||
.not-logged-in {
|
||||
color: #ff4d4f !important;
|
||||
}
|
||||
|
||||
.content-preview {
|
||||
margin: 30rpx 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.content-item {
|
||||
background: #f8f9fa;
|
||||
padding: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.content-label {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.content-desc {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
margin: 5rpx 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.test-buttons {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.test-btn {
|
||||
margin: 10rpx 0;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #256BFA;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
293
pages/test/tabbar-test.vue
Normal file
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<view class="tabbar-test">
|
||||
<view class="header">
|
||||
<text class="title">自定义TabBar测试页面</text>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<view class="user-info">
|
||||
<text class="label">当前用户类型:</text>
|
||||
<text class="value">{{ getCurrentUserTypeLabel() }}</text>
|
||||
</view>
|
||||
|
||||
<view class="login-status">
|
||||
<text class="label">登录状态:</text>
|
||||
<text class="value" :class="{ 'logged-in': hasLogin, 'not-logged-in': !hasLogin }">
|
||||
{{ hasLogin ? '已登录' : '未登录' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="debug-info">
|
||||
<text class="label">调试信息:</text>
|
||||
<text class="value">userType: {{ userInfo?.userType ?? 'undefined' }}</text>
|
||||
<text class="value">hasLogin: {{ hasLogin }}</text>
|
||||
<text class="value">shouldShowJobSeeker: {{ shouldShowJobSeekerContent }}</text>
|
||||
<text class="value">shouldShowCompany: {{ shouldShowCompanyContent }}</text>
|
||||
</view>
|
||||
|
||||
<view class="switch-section">
|
||||
<text class="section-title">切换用户类型:</text>
|
||||
<view class="switch-buttons">
|
||||
<button
|
||||
v-for="(type, index) in userTypes"
|
||||
:key="index"
|
||||
@click="switchUserType(type.value)"
|
||||
:class="{ active: currentUserType === type.value }"
|
||||
class="switch-btn"
|
||||
>
|
||||
{{ type.label }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="description">
|
||||
<text class="desc-title">功能说明:</text>
|
||||
<text class="desc-text">• 未登录状态:默认显示求职者tabbar(职位 + 招聘会 + AI+ + 消息 + 我的)</text>
|
||||
<text class="desc-text">• 企业用户(userType=0):显示"发布岗位"导航,隐藏"招聘会"</text>
|
||||
<text class="desc-text">• 求职者用户(userType=1,2,3):显示"招聘会"导航</text>
|
||||
<text class="desc-text">• 登录后根据用户角色自动切换对应的tabbar</text>
|
||||
<text class="desc-text">• 系统默认tabbar已被隐藏,使用自定义tabbar</text>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<text class="section-title">测试功能:</text>
|
||||
<button @click="testHideTabBar" class="test-btn">检查系统TabBar状态</button>
|
||||
<button @click="testShowTabBar" class="test-btn">临时显示系统TabBar</button>
|
||||
<button @click="testLogin" class="test-btn" v-if="!hasLogin">模拟登录</button>
|
||||
<button @click="testLogout" class="test-btn" v-if="hasLogin">模拟登出</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义tabbar -->
|
||||
<CustomTabBar :currentPage="0" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userInfo, hasLogin } = storeToRefs(userStore);
|
||||
|
||||
const userTypes = [
|
||||
{ value: 0, label: '企业用户' },
|
||||
{ value: 1, label: '求职者' },
|
||||
{ value: 2, label: '网格员' },
|
||||
{ value: 3, label: '政府人员' }
|
||||
];
|
||||
|
||||
const currentUserType = computed(() => userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : 0);
|
||||
|
||||
const switchUserType = (userType) => {
|
||||
console.log('切换用户类型:', userType);
|
||||
userInfo.value.isCompanyUser = userType;
|
||||
// 更新到本地存储
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
};
|
||||
|
||||
const getCurrentUserTypeLabel = () => {
|
||||
const type = userTypes.find(t => t.value === currentUserType.value);
|
||||
return type ? type.label : '未知';
|
||||
};
|
||||
|
||||
// 计算是否显示求职者内容
|
||||
const shouldShowJobSeekerContent = computed(() => {
|
||||
if (!hasLogin.value) {
|
||||
return true;
|
||||
}
|
||||
const userType = userInfo.value?.isCompanyUser;
|
||||
return userType !== 0;
|
||||
});
|
||||
|
||||
// 计算是否显示企业用户内容
|
||||
const shouldShowCompanyContent = computed(() => {
|
||||
if (!hasLogin.value) {
|
||||
return false;
|
||||
}
|
||||
const userType = userInfo.value?.isCompanyUser;
|
||||
return userType === 0;
|
||||
});
|
||||
|
||||
const testHideTabBar = () => {
|
||||
uni.hideTabBar();
|
||||
uni.showToast({
|
||||
title: '系统TabBar已隐藏',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const testShowTabBar = () => {
|
||||
uni.showTabBar();
|
||||
uni.showToast({
|
||||
title: '系统TabBar已显示(测试用)',
|
||||
icon: 'none'
|
||||
});
|
||||
// 3秒后自动隐藏
|
||||
setTimeout(() => {
|
||||
uni.hideTabBar();
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
const testLogin = () => {
|
||||
// 模拟登录,设置用户信息
|
||||
const mockUserInfo = {
|
||||
userType: 1, // 默认设置为求职者
|
||||
name: '测试用户',
|
||||
id: 'test123'
|
||||
};
|
||||
userInfo.value = mockUserInfo;
|
||||
userStore.hasLogin = true;
|
||||
uni.setStorageSync('userInfo', mockUserInfo);
|
||||
uni.showToast({
|
||||
title: '模拟登录成功',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const testLogout = () => {
|
||||
// 模拟登出,清除用户信息
|
||||
userStore.logOut(false);
|
||||
uni.showToast({
|
||||
title: '模拟登出成功',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabbar-test {
|
||||
padding: 40rpx;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.content {
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.user-info, .login-status, .debug-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 20rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.debug-info .value {
|
||||
font-size: 20rpx;
|
||||
color: #666;
|
||||
margin: 5rpx 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.switch-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.switch-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.switch-btn {
|
||||
padding: 20rpx 30rpx;
|
||||
background: #f0f0f0;
|
||||
border: none;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.switch-btn.active {
|
||||
background: #256BFA;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.description {
|
||||
background: #f8f9fa;
|
||||
padding: 30rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.desc-title {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.desc-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.test-section {
|
||||
margin-top: 40rpx;
|
||||
background: #f8f9fa;
|
||||
padding: 30rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.test-btn {
|
||||
margin: 10rpx 0;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #256BFA;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logged-in {
|
||||
color: #52c41a !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.not-logged-in {
|
||||
color: #ff4d4f !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
232
pages/test/tabbar-user-type-test.vue
Normal file
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<view class="test-page">
|
||||
<view class="header">
|
||||
<text class="title">TabBar用户类型切换测试</text>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<view class="current-info">
|
||||
<text class="label">当前用户类型:</text>
|
||||
<text class="value">{{ getCurrentTypeLabel() }} ({{ currentUserType }})</text>
|
||||
</view>
|
||||
|
||||
<view class="type-switcher">
|
||||
<text class="section-title">切换用户类型:</text>
|
||||
<view class="buttons">
|
||||
<button
|
||||
v-for="(type, index) in userTypes"
|
||||
:key="index"
|
||||
:class="['btn', { active: currentUserType === type.value }]"
|
||||
@click="switchUserType(type.value)"
|
||||
>
|
||||
{{ type.label }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="tabbar-preview">
|
||||
<text class="section-title">TabBar预览:</text>
|
||||
<view class="tabbar-container">
|
||||
<view
|
||||
v-for="(item, index) in tabbarConfig"
|
||||
:key="index"
|
||||
class="tabbar-item"
|
||||
>
|
||||
<text class="tabbar-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="description">
|
||||
<text class="desc-title">功能说明:</text>
|
||||
<text class="desc-text">• 企业用户(userType=0):显示"发布岗位"导航</text>
|
||||
<text class="desc-text">• 求职者(userType=1):显示"招聘会"导航</text>
|
||||
<text class="desc-text">• 网格员(userType=2):显示"招聘会"导航</text>
|
||||
<text class="desc-text">• 政府人员(userType=3):显示"招聘会"导航</text>
|
||||
<text class="desc-text">• 切换用户类型后,底部导航栏会自动更新</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
|
||||
const userTypes = [
|
||||
{ value: 0, label: '企业用户' },
|
||||
{ value: 1, label: '求职者' },
|
||||
{ value: 2, label: '网格员' },
|
||||
{ value: 3, label: '政府人员' }
|
||||
];
|
||||
|
||||
const currentUserType = computed(() => userInfo.value?.isCompanyUser !== undefined ? userInfo.value.isCompanyUser : 1);
|
||||
|
||||
const switchUserType = (userType) => {
|
||||
console.log('切换用户类型:', userType);
|
||||
userInfo.value.isCompanyUser = userType;
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
uni.showToast({
|
||||
title: `已切换到${getCurrentTypeLabel()}`,
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const getCurrentTypeLabel = () => {
|
||||
const type = userTypes.find(t => t.value === currentUserType.value);
|
||||
return type ? type.label : '未知';
|
||||
};
|
||||
|
||||
const tabbarConfig = computed(() => {
|
||||
const baseItems = [
|
||||
{ text: '职位' },
|
||||
{ text: currentUserType.value === 0 ? '发布岗位' : '招聘会' },
|
||||
{ text: 'AI+' },
|
||||
{ text: '消息' },
|
||||
{ text: '我的' }
|
||||
];
|
||||
return baseItems;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.test-page {
|
||||
padding: 40rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.current-info {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #256BFA;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.type-switcher {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
min-width: 140rpx;
|
||||
height: 80rpx;
|
||||
background: #f8f9fa;
|
||||
border: 2rpx solid #e9ecef;
|
||||
border-radius: 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.active {
|
||||
background: #256BFA;
|
||||
border-color: #256BFA;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabbar-preview {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tabbar-container {
|
||||
display: flex;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
|
||||
.tabbar-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx 10rpx;
|
||||
|
||||
.tabbar-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.desc-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.desc-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -54,6 +54,18 @@
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">gxbys</div>
|
||||
<div class="code-name">&#xe63f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">个人中心</div>
|
||||
<div class="code-name">&#xe60f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">素质测评</div>
|
||||
@@ -120,9 +132,9 @@
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1760941852498') format('woff2'),
|
||||
url('iconfont.woff?t=1760941852498') format('woff'),
|
||||
url('iconfont.ttf?t=1760941852498') format('truetype');
|
||||
src: url('iconfont.woff2?t=1761826914823') format('woff2'),
|
||||
url('iconfont.woff?t=1761826914823') format('woff'),
|
||||
url('iconfont.ttf?t=1761826914823') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
@@ -148,6 +160,24 @@
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-Graduation-simple-"></span>
|
||||
<div class="name">
|
||||
gxbys
|
||||
</div>
|
||||
<div class="code-name">.icon-Graduation-simple-
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-gerenzhongxin"></span>
|
||||
<div class="name">
|
||||
个人中心
|
||||
</div>
|
||||
<div class="code-name">.icon-gerenzhongxin
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-suzhicepingtiku"></span>
|
||||
<div class="name">
|
||||
@@ -247,6 +277,22 @@
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-Graduation-simple-"></use>
|
||||
</svg>
|
||||
<div class="name">gxbys</div>
|
||||
<div class="code-name">#icon-Graduation-simple-</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-gerenzhongxin"></use>
|
||||
</svg>
|
||||
<div class="name">个人中心</div>
|
||||
<div class="code-name">#icon-gerenzhongxin</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-suzhicepingtiku"></use>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 5044714 */
|
||||
src: url('iconfont.woff2?t=1760941852498') format('woff2'),
|
||||
url('iconfont.woff?t=1760941852498') format('woff'),
|
||||
url('iconfont.ttf?t=1760941852498') format('truetype');
|
||||
src: url('iconfont.woff2?t=1761826914823') format('woff2'),
|
||||
url('iconfont.woff?t=1761826914823') format('woff'),
|
||||
url('iconfont.ttf?t=1761826914823') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,14 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-Graduation-simple-:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-gerenzhongxin:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-suzhicepingtiku:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
1
static/iconfont/iconfont.js
Normal file
@@ -5,6 +5,20 @@
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "5122382",
|
||||
"name": "gxbys",
|
||||
"font_class": "Graduation-simple-",
|
||||
"unicode": "e63f",
|
||||
"unicode_decimal": 58943
|
||||
},
|
||||
{
|
||||
"icon_id": "6311925",
|
||||
"name": "个人中心",
|
||||
"font_class": "gerenzhongxin",
|
||||
"unicode": "e60f",
|
||||
"unicode_decimal": 58895
|
||||
},
|
||||
{
|
||||
"icon_id": "28808301",
|
||||
"name": "素质测评",
|
||||
|
||||
BIN
static/images/train/arrow.png
Normal file
|
After Width: | Height: | Size: 219 B |
BIN
static/images/train/bj.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
static/images/train/ctb-k.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
static/images/train/mnks-k.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
static/images/train/spxx-k.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
static/images/train/video-bg.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
static/images/train/video-bj.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
static/images/train/video-bj2.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
static/images/train/video-gd.png
Normal file
|
After Width: | Height: | Size: 309 B |
BIN
static/images/train/video-jt.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
static/images/train/video-kc.png
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
static/images/train/video-sc.png
Normal file
|
After Width: | Height: | Size: 455 B |
BIN
static/images/train/wsc.png
Normal file
|
After Width: | Height: | Size: 632 B |
BIN
static/images/train/xl.png
Normal file
|
After Width: | Height: | Size: 242 B |
BIN
static/images/train/zs.png
Normal file
|
After Width: | Height: | Size: 297 B |
BIN
static/images/train/zxxl-k.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
static/imgs/avatar.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
@@ -48,31 +48,22 @@ export const useReadMsg = defineStore('readMsg', () => {
|
||||
const count = unreadCount.value
|
||||
const index = 3
|
||||
const countVal = count > 99 ? '99+' : String(count)
|
||||
if (count === 0) {
|
||||
uni.removeTabBarBadge({
|
||||
index
|
||||
}) // 替换为你消息页面的 TabBar index
|
||||
badges.value[index] = {
|
||||
count: 0
|
||||
}
|
||||
} else {
|
||||
badges.value[index] = {
|
||||
count: countVal
|
||||
}
|
||||
uni.setTabBarBadge({
|
||||
index,
|
||||
text: countVal
|
||||
})
|
||||
|
||||
// 更新徽章数据,不直接调用 uni.removeTabBarBadge 和 uni.setTabBarBadge
|
||||
// 因为项目使用的是自定义 TabBar,这些方法只能在原生 TabBar 页面使用
|
||||
badges.value[index] = {
|
||||
count: count === 0 ? 0 : countVal
|
||||
}
|
||||
|
||||
// 如果需要使用原生 TabBar 的徽章功能,需要确保在 TabBar 页面中调用
|
||||
// 这里只更新数据,让自定义 TabBar 组件根据数据来显示徽章
|
||||
}
|
||||
|
||||
|
||||
// 拉取消息列表
|
||||
async function fetchMessages() {
|
||||
try {
|
||||
$api.createRequest('/app/notice/info', {
|
||||
isRead: 1
|
||||
}, "GET").then((res) => {
|
||||
$api.createRequest('/app/notice/info', {}, "GET").then((res) => {
|
||||
msgList.value = res.data || []
|
||||
updateTabBarBadge()
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ const useUserStore = defineStore("user", () => {
|
||||
});
|
||||
}
|
||||
|
||||
const logOut = (redirect = true) => {
|
||||
const logOut = (showLoginModal = true) => {
|
||||
hasLogin.value = false;
|
||||
token.value = ''
|
||||
resume.value = {}
|
||||
@@ -73,11 +73,10 @@ const useUserStore = defineStore("user", () => {
|
||||
uni.removeStorageSync('userInfo')
|
||||
uni.removeStorageSync('token')
|
||||
|
||||
// 只有在明确需要跳转时才跳转到登录页
|
||||
if (redirect) {
|
||||
uni.redirectTo({
|
||||
url: '/pages/complete-info/complete-info',
|
||||
});
|
||||
// 如果需要显示登录弹窗,则通过事件通知页面显示微信登录弹窗
|
||||
if (showLoginModal) {
|
||||
// 通过 uni.$emit 发送全局事件,通知页面显示登录弹窗
|
||||
uni.$emit('showLoginModal');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,9 +116,9 @@ const useUserStore = defineStore("user", () => {
|
||||
hasLogin.value = true;
|
||||
|
||||
// 模拟添加用户类型字段,实际项目中应该从接口获取
|
||||
if (!userInfo.value.userType) {
|
||||
userInfo.value.userType = 0; // 默认设置为企业用户
|
||||
}
|
||||
// if (!userInfo.value.userType) {
|
||||
// userInfo.value.userType = 1; // 默认设置为求职者用户
|
||||
// }
|
||||
|
||||
// 持久化存储用户信息到本地缓存
|
||||
uni.setStorageSync('userInfo', values.data);
|
||||
|
||||
@@ -229,7 +229,13 @@ export default {
|
||||
query
|
||||
.select(`#waterfalls_flow_column_${i}`)
|
||||
.boundingClientRect((data) => {
|
||||
heightArr.push({ column: i, height: data.height });
|
||||
// 添加 null 检查,防止 data 为 null 时访问 height 属性
|
||||
if (data && data.height !== undefined) {
|
||||
heightArr.push({ column: i, height: data.height });
|
||||
} else {
|
||||
// 如果元素不存在或高度未定义,使用默认高度 0
|
||||
heightArr.push({ column: i, height: 0 });
|
||||
}
|
||||
})
|
||||
.exec(() => {
|
||||
if (this.data.column <= heightArr.length) {
|
||||
|
||||
BIN
unpackage/.DS_Store
vendored
BIN
unpackage/dist/.DS_Store
vendored
BIN
unpackage/dist/build/.DS_Store
vendored
15
unpackage/dist/cache/.vite/deps/_metadata.json
vendored
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"hash": "92569f0a",
|
||||
"configHash": "2d3ccd01",
|
||||
"lockfileHash": "63211de0",
|
||||
"browserHash": "8f10a447",
|
||||
"optimized": {
|
||||
"element-plus": {
|
||||
"src": "../../../../../../../node_modules/element-plus/es/index.mjs",
|
||||
"file": "element-plus.js",
|
||||
"fileHash": "beb69334",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
"chunks": {}
|
||||
}
|
||||
3
unpackage/dist/cache/.vite/deps/package.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
35
unpackage/dist/dev/mp-weixin/project.config.json
vendored
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"description": "项目配置文件。",
|
||||
"packOptions": {
|
||||
"ignore": []
|
||||
"ignore": [],
|
||||
"include": []
|
||||
},
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
@@ -9,28 +10,20 @@
|
||||
"postcss": true,
|
||||
"minified": true,
|
||||
"newFeature": true,
|
||||
"bigPackageSizeSupport": true
|
||||
"bigPackageSizeSupport": true,
|
||||
"babelSetting": {
|
||||
"ignore": [],
|
||||
"disablePlugins": [],
|
||||
"outputPath": ""
|
||||
}
|
||||
},
|
||||
"compileType": "miniprogram",
|
||||
"libVersion": "3.5.7",
|
||||
"appid": "wxc0f37e549415bb4e",
|
||||
"libVersion": "3.10.3",
|
||||
"appid": "wx9d1cbc11c8c40ba7",
|
||||
"projectname": "qingdao-employment-service",
|
||||
"condition": {
|
||||
"search": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
},
|
||||
"conversation": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
},
|
||||
"game": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
},
|
||||
"miniprogram": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
}
|
||||
"condition": {},
|
||||
"editorSetting": {
|
||||
"tabIndent": "insertSpaces",
|
||||
"tabSize": 2
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
{
|
||||
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
|
||||
"projectname": "qingdao-employment-service",
|
||||
"setting": {
|
||||
"compileHotReLoad": true,
|
||||
"autoAudits": false
|
||||
},
|
||||
"condition": {
|
||||
"miniprogram": {
|
||||
"list": [
|
||||
{
|
||||
"name": "packageRc/pages/personalList/personalList",
|
||||
"pathName": "packageRc/pages/personalList/personalList",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageRc/pages/daiban/daiban",
|
||||
"pathName": "packageRc/pages/daiban/daiban",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageRc/pages/index/index",
|
||||
"pathName": "packageRc/pages/index/index",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/userCenter/personDocument",
|
||||
"pathName": "packageB/pages/userCenter/personDocument",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/testReport/personalTestReport",
|
||||
"pathName": "packageB/pages/testReport/personalTestReport",
|
||||
"query": "year=2025",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/testReport/interestTestReport",
|
||||
"pathName": "packageB/pages/testReport/interestTestReport",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/testReport/multipleAbilityTestReport",
|
||||
"pathName": "packageB/pages/testReport/multipleAbilityTestReport",
|
||||
"query": "id=969306",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/testReport/workValuesTestReport",
|
||||
"pathName": "packageB/pages/testReport/workValuesTestReport",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/userCenter/personDocument",
|
||||
"pathName": "packageB/pages/userCenter/personDocument",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/pagesTest/testList",
|
||||
"pathName": "packageB/pages/pagesTest/testList",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "packageB/pages/search/search",
|
||||
"pathName": "packageB/pages/search/search",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
412
utils/request.js
@@ -166,67 +166,67 @@ export function packageRcPost(config) {
|
||||
// ======================================
|
||||
|
||||
export function request({
|
||||
url,
|
||||
method = 'GET',
|
||||
data = {},
|
||||
load = false,
|
||||
header = {}
|
||||
url,
|
||||
method = 'GET',
|
||||
data = {},
|
||||
load = false,
|
||||
header = {}
|
||||
} = {}) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (load) {
|
||||
uni.showLoading({
|
||||
title: '请稍候',
|
||||
mask: true
|
||||
});
|
||||
}
|
||||
let Authorization = ''
|
||||
if (useUserStore().token) {
|
||||
Authorization = `${useUserStore().userInfo.token}${useUserStore().token}`
|
||||
}
|
||||
uni.request({
|
||||
url: config.baseUrl + url,
|
||||
method,
|
||||
data: data,
|
||||
header: {
|
||||
'Authorization': Authorization || '',
|
||||
},
|
||||
success: resData => {
|
||||
// 响应拦截
|
||||
if (resData.statusCode === 200) {
|
||||
const {
|
||||
code,
|
||||
msg
|
||||
} = resData.data
|
||||
if (code === 200) {
|
||||
resolve(resData.data)
|
||||
return
|
||||
}
|
||||
uni.showToast({
|
||||
title: msg,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
if (resData.data?.code === 401 || resData.data?.code === 402) {
|
||||
useUserStore().logOut()
|
||||
uni.showToast({
|
||||
title: '登录过期,请重新登录',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
const err = new Error('请求出现异常,请联系工作人员')
|
||||
err.error = resData
|
||||
reject(err)
|
||||
},
|
||||
fail: err => reject(err),
|
||||
complete() {
|
||||
if (load) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
if (load) {
|
||||
uni.showLoading({
|
||||
title: '请稍候',
|
||||
mask: true
|
||||
});
|
||||
}
|
||||
let Authorization = ''
|
||||
if (useUserStore().token) {
|
||||
Authorization = `${useUserStore().userInfo.token}${useUserStore().token}`
|
||||
}
|
||||
uni.request({
|
||||
url: config.baseUrl + url,
|
||||
method,
|
||||
data: data,
|
||||
header: {
|
||||
'Authorization': Authorization || '',
|
||||
},
|
||||
success: resData => {
|
||||
// 响应拦截
|
||||
if (resData.statusCode === 200) {
|
||||
const {
|
||||
code,
|
||||
msg
|
||||
} = resData.data
|
||||
if (code === 200) {
|
||||
resolve(resData.data)
|
||||
return
|
||||
}
|
||||
uni.showToast({
|
||||
title: msg,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
if (resData.data?.code === 401 || resData.data?.code === 402) {
|
||||
useUserStore().logOut()
|
||||
uni.showToast({
|
||||
title: '登录过期,请重新登录',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
const err = new Error('请求出现异常,请联系工作人员')
|
||||
err.error = resData
|
||||
reject(err)
|
||||
},
|
||||
fail: err => reject(err),
|
||||
complete() {
|
||||
if (load) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -239,146 +239,172 @@ export function request({
|
||||
* @returns promise
|
||||
**/
|
||||
export function createRequest(url, data = {}, method = 'GET', loading = false, headers = {}) {
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
title: '请稍后',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
let Authorization = ''
|
||||
if (useUserStore().token) {
|
||||
Authorization = `${useUserStore().token}`
|
||||
}
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
title: '请稍后',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
let Authorization = ''
|
||||
if (useUserStore().token) {
|
||||
Authorization = `${useUserStore().token}`
|
||||
}
|
||||
|
||||
const header = headers || {};
|
||||
header["Authorization"] = encodeURIComponent(Authorization);
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: config.baseUrl + url,
|
||||
method: method,
|
||||
data: data,
|
||||
header,
|
||||
success: resData => {
|
||||
// 响应拦截
|
||||
if (resData.statusCode === 200) {
|
||||
const {
|
||||
code,
|
||||
msg
|
||||
} = resData.data
|
||||
if (code === 200) {
|
||||
resolve(resData.data)
|
||||
return
|
||||
}
|
||||
// 处理业务错误
|
||||
if (resData.data?.code === 401 || resData.data?.code === 402) {
|
||||
useUserStore().logOut()
|
||||
}
|
||||
// 显示具体的错误信息
|
||||
const errorMsg = msg || '请求出现异常,请联系工作人员'
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none'
|
||||
})
|
||||
const err = new Error(errorMsg)
|
||||
err.error = resData
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
// HTTP状态码不是200的情况
|
||||
const err = new Error('网络请求失败,请检查网络连接')
|
||||
err.error = resData
|
||||
reject(err)
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
complete: () => {
|
||||
if (loading) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
const header = headers || {};
|
||||
header["Authorization"] = encodeURIComponent(Authorization);
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: config.baseUrl + url,
|
||||
method: method,
|
||||
data: data,
|
||||
header,
|
||||
success: resData => {
|
||||
// 响应拦截
|
||||
if (resData.statusCode === 200) {
|
||||
const {
|
||||
code,
|
||||
msg
|
||||
} = resData.data
|
||||
if (code === 200) {
|
||||
resolve(resData.data)
|
||||
return
|
||||
}
|
||||
// 处理业务错误
|
||||
if (resData.data?.code === 401 || resData.data?.code === 402) {
|
||||
useUserStore().logOut()
|
||||
}
|
||||
// 显示具体的错误信息
|
||||
const errorMsg = msg || '请求出现异常,请联系工作人员'
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none'
|
||||
})
|
||||
const err = new Error(errorMsg)
|
||||
err.error = resData
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
// HTTP状态码不是200的情况
|
||||
const err = new Error('网络请求失败,请检查网络连接')
|
||||
err.error = resData
|
||||
reject(err)
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
complete: () => {
|
||||
if (loading) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function uploadFile(tempFilePaths, loading = false) {
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
title: '请稍后',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
let Authorization = ''
|
||||
if (useUserStore().token) {
|
||||
Authorization = `${useUserStore().token}`
|
||||
}
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
title: '请稍后',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
let Authorization = ''
|
||||
if (useUserStore().token) {
|
||||
Authorization = `${useUserStore().token}`
|
||||
}
|
||||
|
||||
const header = {};
|
||||
header["Authorization"] = encodeURIComponent(Authorization);
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: config.baseUrl + '/app/file/upload',
|
||||
filePath: tempFilePaths,
|
||||
name: 'file',
|
||||
header,
|
||||
success: (uploadFileRes) => {
|
||||
if (uploadFileRes.statusCode === 200) {
|
||||
return resolve(uploadFileRes.data)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
complete: () => {
|
||||
if (loading) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
const header = {};
|
||||
header["Authorization"] = encodeURIComponent(Authorization);
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: config.baseUrl + '/app/file/upload',
|
||||
filePath: tempFilePaths,
|
||||
name: 'file',
|
||||
header,
|
||||
success: (uploadFileRes) => {
|
||||
if (uploadFileRes.statusCode === 200) {
|
||||
return resolve(uploadFileRes.data)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
complete: () => {
|
||||
if (loading) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 主包的GET请求函数 - 调用request函数,使用动态token和配置的baseURL
|
||||
// 此函数已经集成到主包中,与主包其他请求函数保持一致的行为
|
||||
// 封装GET请求
|
||||
export function get(config) {
|
||||
if (typeof config === 'string') {
|
||||
// 兼容旧的调用方式: get(url, params, options)
|
||||
const params = arguments[1] || {};
|
||||
const options = arguments[2] || {};
|
||||
return request({
|
||||
url: config,
|
||||
method: 'GET',
|
||||
data: params,
|
||||
...options
|
||||
})
|
||||
}
|
||||
// 支持配置对象的调用方式: get({url, data, ...})
|
||||
return request({
|
||||
method: 'GET',
|
||||
...config
|
||||
})
|
||||
export function myRequest(url, data = {}, method = 'GET', port = 9100, headers = {}, loading = false) {
|
||||
let LCBaseUrl = config.LCBaseUrl
|
||||
if (port != 9100) {
|
||||
LCBaseUrl = config.LCBaseUrlInner
|
||||
}
|
||||
const header = headers || {};
|
||||
// 上下文
|
||||
// /jobfair-api/jobfair/public 招聘会
|
||||
// /dashboard-api/dashboard 用户登录相关
|
||||
// /dashboard-api 获取验证码、登录
|
||||
if (loading) {
|
||||
uni.showLoading({
|
||||
title: '请稍后',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: LCBaseUrl + url,
|
||||
method: method,
|
||||
data: data,
|
||||
header,
|
||||
success: resData => {
|
||||
if(url=='/dashboard/auth/heart'){
|
||||
resolve(resData.data)
|
||||
return
|
||||
}else{
|
||||
// 响应拦截
|
||||
if (resData.statusCode === 200) {
|
||||
const {
|
||||
code,
|
||||
msg
|
||||
} = resData.data
|
||||
if (code === 200) {
|
||||
resolve(resData.data)
|
||||
return
|
||||
}
|
||||
// 处理业务错误
|
||||
if (resData.data?.code === 401 || resData.data?.code === 402) {
|
||||
useUserStore().logOut()
|
||||
}
|
||||
// 显示具体的错误信息
|
||||
const errorMsg = msg || '请求出现异常,请联系工作人员'
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none'
|
||||
})
|
||||
const err = new Error(errorMsg)
|
||||
err.error = resData
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
// HTTP状态码不是200的情况
|
||||
const err = new Error('网络请求失败,请检查网络连接')
|
||||
err.error = resData
|
||||
reject(err)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
complete: () => {
|
||||
if (loading) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 主包的POST请求函数 - 调用request函数,使用动态token和配置的baseURL
|
||||
// 此函数已经集成到主包中,与主包其他请求函数保持一致的行为
|
||||
// 封装POST请求
|
||||
export function post(config) {
|
||||
if (typeof config === 'string') {
|
||||
// 兼容旧的调用方式: post(url, data, options)
|
||||
const data = arguments[1] || {};
|
||||
const options = arguments[2] || {};
|
||||
return request({
|
||||
url: config,
|
||||
method: 'POST',
|
||||
data,
|
||||
...options
|
||||
})
|
||||
}
|
||||
// 支持配置对象的调用方式: post({url, data, ...})
|
||||
return request({
|
||||
method: 'POST',
|
||||
...config
|
||||
})
|
||||
}
|
||||
45
utils/tabbarManager.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// 自定义tabbar管理器
|
||||
export const tabbarManager = {
|
||||
// 显示tabbar
|
||||
showTabBar() {
|
||||
if (typeof getTabBar === 'function' && getTabBar()) {
|
||||
getTabBar().setData({
|
||||
selected: 0
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 更新tabbar选中状态
|
||||
updateSelected(index) {
|
||||
if (typeof getTabBar === 'function' && getTabBar()) {
|
||||
getTabBar().setData({
|
||||
selected: index
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 根据用户类型更新tabbar
|
||||
updateTabBarByUserType() {
|
||||
if (typeof getTabBar === 'function' && getTabBar()) {
|
||||
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||
const userType = userInfo.isCompanyUser !== undefined ? userInfo.isCompanyUser : 1;
|
||||
getTabBar().generateTabbarList(userType);
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化tabbar
|
||||
initTabBar() {
|
||||
// 延迟初始化自定义tabbar
|
||||
setTimeout(() => {
|
||||
this.updateTabBarByUserType();
|
||||
}, 200);
|
||||
},
|
||||
|
||||
// 强制刷新tabbar(登录后调用)
|
||||
refreshTabBar() {
|
||||
// 延迟刷新,确保用户信息已更新
|
||||
setTimeout(() => {
|
||||
this.updateTabBarByUserType();
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||