This commit is contained in:
2026-02-24 10:07:07 +08:00
37 changed files with 5969 additions and 688 deletions

View File

@@ -4,15 +4,18 @@
class="tabbar-item"
v-for="(item, index) in tabbarList"
:key="index"
:class="{ 'center-item': item.centerItem }"
@click.stop="switchTab(item, index)"
@tap.stop="switchTab(item, index)"
>
<view class="tabbar-icon">
<view class="icon-container">
<image
:src="currentItem === item.id ? item.selectedIconPath : item.iconPath"
mode="aspectFit"
/>
</view>
</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 }}
@@ -59,22 +62,13 @@ const generateTabbarList = () => {
},
{
id: 2,
text: '智能客服',
path: '/pages/chat/chat',
iconPath: '/static/tabbar/logo3.png',
selectedIconPath: '/static/tabbar/logo3.png',
text: '',
path: '/packageA/pages/chat/chat',
iconPath: '/static/tabbar/robot2.png',
selectedIconPath: '/static/tabbar/robot2.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: '我的',
@@ -126,7 +120,8 @@ const generateTabbarList = () => {
// #endif
}
if (userType === 0) {
baseItems.splice(2, 0, {
// 企业用户将招聘会添加到第1个位置AI图标保持在中间
baseItems.splice(1, 0, {
id: 5,
text: '招聘会',
path: '/pages/careerfair/careerfair',
@@ -135,6 +130,14 @@ const generateTabbarList = () => {
centerItem: false,
badge: 0,
});
// 调整AI图标的位置到中间索引2
const aiItem = baseItems.find(item => item.id === 2);
if (aiItem) {
// 移除AI图标
baseItems.splice(baseItems.indexOf(aiItem), 1);
// 将AI图标插入到中间位置
baseItems.splice(2, 0, aiItem);
}
}
return baseItems;
};
@@ -200,12 +203,12 @@ const switchTab = (item, index) => {
// 判断企业信息字段company是否为null或undefined
if (!currentUserInfo.company || currentUserInfo.company === null) {
// 企业信息为空,跳转到企业信息补全页面
uni.navigateTo({
uni.redirectTo({
url: '/packageA/pages/complete-info/company-info',
});
} else {
// 企业信息完整,跳转到发布岗位页面
uni.navigateTo({
uni.redirectTo({
url: '/packageA/pages/job/publishJob',
});
}
@@ -234,7 +237,7 @@ const switchTab = (item, index) => {
}
// 跳转到对应的页面
uni.navigateTo({
uni.redirectTo({
url: targetPath,
});
@@ -243,26 +246,10 @@ const switchTab = (item, index) => {
}
}
// 判断是否为 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 避免页面栈溢出
// 所有页面都使用 redirectTo 避免页面栈溢出
uni.redirectTo({
url: item.path,
});
} else {
// 非 TabBar 页面使用 navigateTo
uni.navigateTo({
url: item.path,
});
}
currentItem.value = item.id;
};
@@ -275,6 +262,34 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
/* 动画定义 */
@keyframes pulse {
0% {
transform: scale(1.6);
box-shadow: 0 0 10rpx #256BFA;
border-color: #256BFA;
}
50% {
transform: scale(1.7);
box-shadow: 0 0 20rpx #256BFA, 0 0 30rpx rgba(37, 107, 250, 0.5);
border-color: #4A89FF;
}
100% {
transform: scale(1.6);
box-shadow: 0 0 10rpx #256BFA;
border-color: #256BFA;
}
}
@keyframes bounce {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
}
.custom-tabbar {
position: fixed;
bottom: 0;
@@ -282,7 +297,7 @@ onMounted(() => {
right: 0;
height: 100rpx;
background-color: #ffffff;
border-top: 1rpx solid #e5e5e5;
// border-top: 1rpx solid #e5e5e5;
display: flex;
align-items: center;
padding-bottom: env(safe-area-inset-bottom);
@@ -304,6 +319,10 @@ onMounted(() => {
cursor: pointer;
pointer-events: auto;
-webkit-tap-highlight-color: transparent;
.icon-container{
width: 50rpx;
height: 50rpx;
}
}
.tabbar-icon {
@@ -346,11 +365,29 @@ onMounted(() => {
}
/* 中间按钮特殊样式 */
.tabbar-item:has(.center-item) {
.tabbar-item.center-item {
.tabbar-icon {
width: 68rpx;
height: 68rpx;
width: 60rpx;
height: 60rpx;
margin-bottom: 0;
}
.tabbar-icon image {
// margin-top: -25rpx;
width: 80%;
animation: bounce 2s ease-in-out infinite;
}
.icon-container{
width: 50rpx;
height: 50rpx;
text-align: center;
border-radius: 50%;
border: 2rpx solid #256BFA;
box-shadow: 0 0 10rpx #256BFA;
transform: scale(1.6);
position: relative;
top: 5rpx;
animation: pulse 2s ease-in-out infinite;
}
}
</style>

View File

@@ -76,7 +76,7 @@ const generateTabbarList = () => {
{
id: 2,
text: 'AI+',
path: '/pages/chat/chat',
path: '/packageA/pages/chat/chat',
iconPath: '../../static/tabbar/logo3.png',
selectedIconPath: '../../static/tabbar/logo3.png',
centerItem: true,
@@ -148,7 +148,7 @@ const changeItem = (item) => {
const tabBarPages = [
'/pages/index/index',
'/pages/careerfair/careerfair',
'/pages/chat/chat',
'/packageA/pages/chat/chat',
'/pages/msglog/msglog',
'/pages/mine/mine'
];

View File

@@ -103,12 +103,19 @@
</view>
<!-- 用户协议 -->
<!-- <view class="auth-agreement">
<text>登录即表示同意</text>
<text class="link" @click="openAgreement('user')">用户协议</text>
<text></text>
<text class="link" @click="openAgreement('privacy')">隐私政策</text>
</view> -->
<view class="auth-agreement">
<view class="agreement-checkbox" @click="toggleAgreement">
<uni-icons
:type="agreedToAgreement ? 'checkbox-filled' : 'circle'"
size="20"
:color="agreedToAgreement ? '#256BFA' : '#999'"
></uni-icons>
<text class="agreement-text">我已阅读并同意</text>
</view>
<text class="link" @click="openAgreement('user')">隐私协议</text>
<!-- <text></text>
<text class="link" @click="openAgreement('privacy')">隐私政策</text> -->
</view>
</view>
</view>
</uni-popup>
@@ -128,6 +135,7 @@ const popup = ref(null);
const userType = ref(null); // 用户角色1-求职者0-企业
const orgType = ref(null); // 机构类型
const orgTypeOptions = ref([]); // 机构类型选项
const agreedToAgreement = ref(false); // 是否同意用户协议
const emit = defineEmits(['success', 'cancel']);
// 获取机构类型字典
@@ -159,6 +167,10 @@ const open = () => {
popup.value?.open();
userType.value = null; // 重置角色选择
orgType.value = null; // 重置机构类型选择
// 检查是否已同意协议
const agreed = uni.getStorageSync('agreedToUserAgreement');
agreedToAgreement.value = !!agreed;
};
// 关闭弹窗
@@ -191,26 +203,25 @@ const validateRole = () => {
return false;
}
// 验证是否同意用户协议
if (!agreedToAgreement.value) {
$api.msg('请先阅读并同意隐私协议');
return false;
}
return true;
};
const getPhoneNumber = (e) => {
console.log('获取手机号:', e);
console.log('userType.value', userType.value)
// 验证角色是否已选择
// 验证角色、机构类型和隐私协议
if (!validateRole()) {
return;
}
if (e.detail.errMsg === 'getPhoneNumber:ok') {
if (userType.value === null) {
$api.msg('请先选择您的角色');
return true;
}
// 验证机构类型是否已选择(仅单位角色)
if (userType.value === 0 && orgType.value === null) {
$api.msg('请选择机构类型');
return true;
}
uni.login({
provider: 'weixin',
success: (loginRes) => {
@@ -363,6 +374,11 @@ const wxLogin = () => {
// 测试账号登录(仅开发环境)
const testLogin = () => {
// 验证角色、机构类型和隐私协议
if (!validateRole()) {
return;
}
uni.showLoading({ title: '登录中...' });
const params = {
@@ -409,18 +425,21 @@ const testLogin = () => {
});
};
// 切换协议同意状态
const toggleAgreement = () => {
agreedToAgreement.value = !agreedToAgreement.value;
};
// 打开用户协议
const openAgreement = (type) => {
const urls = {
user: '/pages/agreement/user',
privacy: '/pages/agreement/privacy'
user: '/packageA/pages/agreement/user',
privacy: '/packageA/pages/agreement/privacy'
};
if (urls[type]) {
uni.navigateTo({
url: urls[type]
});
}
};
// 暴露方法供父组件调用
@@ -596,10 +615,23 @@ defineExpose({
margin-left: 12rpx
.auth-agreement
text-align: center
display: flex
align-items: center
justify-content: center
font-size: 24rpx
color: #999999
line-height: 1.6
flex-wrap: wrap
gap: 8rpx
.agreement-checkbox
display: flex
align-items: center
cursor: pointer
.agreement-text
margin-left: 8rpx
color: #666666
.link
color: #256BFA

View File

@@ -4,5 +4,8 @@
"dayjs": "^1.11.19",
"mp-html": "^2.5.2",
"sm-crypto": "^0.3.13"
},
"devDependencies": {
"crypto-js": "^4.2.0"
}
}

View File

@@ -1,16 +1,11 @@
<template>
<AppLayout title="" :use-scroll-view="false">
<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">
@@ -22,6 +17,10 @@
{{ getScaleLabel(companyInfo?.scale) }}
</view>
</view>
<view class="companyinfo-collect" @click="toggleCollection">
<image src="@/static/icon/collect3.png" v-if="!companyInfo?.isCollection"></image>
<image src="@/static/icon/collect2.png" v-else></image>
</view>
</view>
<view class="conetent-info" :class="{ expanded: isExpanded }">
<view class="info-title">公司介绍</view>
@@ -372,6 +371,37 @@
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(jobId)}`);
}
}
// 收藏和取消收藏企业
function toggleCollection() {
const companyId = companyInfo.value.id || companyInfo.value.companyId;
if (!companyId) {
$api.msg('获取公司信息失败,无法操作');
return;
}
const isCollection = companyInfo.value.isCollection;
const method = isCollection ? 'DELETE' : 'POST';
const apiUrl = `/app/company/collection/${companyId}`;
uni.showLoading({
title: '操作中'
});
$api.createRequest(apiUrl, {}, method).then((resData) => {
uni.hideLoading();
if (resData && resData.code === 200) {
companyInfo.value.isCollection = !isCollection;
$api.msg(isCollection ? '取消收藏成功' : '收藏成功');
} else {
$api.msg((resData && resData.msg) || (isCollection ? '取消收藏失败' : '收藏失败'));
}
}).catch((error) => {
uni.hideLoading();
console.error('API error when toggling collection:', error);
$api.msg('网络请求失败,请检查网络连接');
});
}
</script>
<style lang="stylus" scoped>
@@ -404,6 +434,7 @@
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
.companyinfo-left {
width: 96rpx;
@@ -412,6 +443,8 @@
}
.companyinfo-right {
flex: 1;
.row1 {
font-weight: 500;
font-size: 32rpx;
@@ -425,6 +458,17 @@
line-height: 45rpx;
}
}
.companyinfo-collect {
width: 52rpx;
height: 52rpx;
margin-left: 20rpx;
image {
width: 100%;
height: 100%;
}
}
}
.conetent-info {

View File

@@ -0,0 +1,248 @@
<template>
<view class="agreement-page">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="nav-left" @click="goBack">
<uni-icons type="back" size="28" color="#333"></uni-icons>
</view>
<view class="nav-title">隐私政策</view>
<view class="nav-right"></view>
</view>
<!-- 内容区域 -->
<scroll-view class="content" scroll-y>
<view class="agreement-content">
<!-- 协议标题 -->
<view class="agreement-title">隐私政策</view>
<!-- 重要提示 -->
<view class="important-tip">
在您注册登录使用本小程序服务之前请您务必审慎阅读充分理解本协议各条款内容特别是以加粗形式提示您注意的关于免除或限制责任争议解决及法律适用的条款一旦您以任何方式访问使用本小程序即表示您已同意接受本协议及我们另行发布的隐私政策的全部内容约束如您不同意本协议的任何内容请立即停止使用本小程序
</view>
<view class="important-tip">
如果您未满18周岁请在法定监护人的陪同下阅读和判断是否同意本协议并特别注意未成年人使用条款
</view>
<!-- 第二部分隐私政策 -->
<view class="section">
<view class="section-title">第二部分隐私政策</view>
<view class="section-content">
<view class="paragraph-text">
我们深知个人信息对您的重要性并致力于保护您的隐私安全本政策将说明我们如何收集使用存储和共享您的个人信息
</view>
</view>
<!-- 我们如何收集和使用您的信息 -->
<view class="section-subtitle"> 我们如何收集和使用您的信息</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">1.1 微信授权信息</view>
<view class="paragraph-text">当您使用微信登录时我们会收集您的微信头像昵称地区及OpenID用于为您创建账号识别用户身份并提供核心服务拒绝提供该信息将使您无法使用本小程序的核心功能</view>
</view>
<view class="paragraph">
<view class="paragraph-title">1.2 您主动提供的信息</view>
<view class="paragraph-text">根据您使用的服务类型您可能会主动向我们提供 例如手机号码收货地址实名认证信息发布的内容上传的图片等 我们将严格按本政策约定使用这些信息</view>
</view>
<view class="paragraph">
<view class="paragraph-title">1.3 设备与日志信息</view>
<view class="paragraph-text">为保障运营安全与质量我们会自动收集您的设备型号操作系统版本唯一设备标识符IP地址访问时间在小程序内的操作行为等日志信息</view>
</view>
<view class="paragraph">
<view class="paragraph-title">1.4 位置信息如需</view>
<view class="paragraph-text">对于 例如本地服务地图导航 类小程序在获得您的授权后我们可能会收集您的精确或粗略位置信息以提供相关服务</view>
</view>
</view>
<!-- 我们如何使用Cookie和同类技术 -->
<view class="section-subtitle"> 我们如何使用Cookie和同类技术</view>
<view class="section-content">
<view class="paragraph-text">
我们可能使用Cookie和本地存储来记录您的偏好登录状态以优化您的使用体验您可以在微信或设备设置中清除这些数据但这可能会导致部分服务功能无法正常使用
</view>
</view>
<!-- 我们如何共享转让公开披露您的信息 -->
<view class="section-subtitle"> 我们如何共享转让公开披露您的信息</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">3.1 共享</view>
<view class="paragraph-text">我们不会与任何公司组织和个人共享您的个人信息但以下情况除外</view>
</view>
<view class="paragraph-text">
* 事先获得您的明确授权<br>
* 根据法律法规司法程序或政府机关的要求<br>
* 为保护我们我们的关联方或公众的财产和安全免遭损害而有必要提供
</view>
<view class="paragraph">
<view class="paragraph-title">3.2 转让与公开披露</view>
<view class="paragraph-text">我们不会将您的个人信息转让给任何公司组织和个人也不会公开披露您的个人信息除非获得您的单独同意或法律法规的强制性要求</view>
</view>
</view>
<!-- 我们如何存储和保护您的信息 -->
<view class="section-subtitle"> 我们如何存储和保护您的信息</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">4.1 </view>
<view class="paragraph-text">我们在中华人民共和国境内运营您的个人信息将存储于中国境内我们会采取符合行业标准的安全技术和管理措施如数据加密访问控制来保护您的信息防止其被未经授权的访问使用或泄露</view>
</view>
<view class="paragraph">
<view class="paragraph-title">4.2 </view>
<view class="paragraph-text">我们仅会在达成本政策所述目的所需的期限内保留您的个人信息除非法律有强制的留存要求</view>
</view>
</view>
<!-- 您的权利 -->
<view class="section-subtitle"> 您的权利</view>
<view class="section-content">
<view class="paragraph-text">
您有权
</view>
<view class="paragraph-text">
访问更正删除您的个人信息<br>
改变您授权同意的范围<br>
注销您的账号
</view>
<view class="paragraph-text">
您可以通过小程序内的"联系客服"或发送邮件至 您的客服邮箱 来行使上述权利我们将在15个工作日内响应您的请求
</view>
</view>
<!-- 未成年人保护 -->
<view class="section-subtitle"> 未成年人保护</view>
<view class="section-content">
<view class="paragraph-text">
我们非常重视对未成年人个人信息的保护若您是18周岁以下的未成年人请在您的监护人指导下使用我们的服务如果我们发现在未获得监护人同意的情况下收集了未成年人的个人信息我们会设法尽快删除相关数据
</view>
</view>
<!-- 政策更新 -->
<view class="section-subtitle"> 政策更新</view>
<view class="section-content">
<view class="paragraph-text">
我们可能会适时更新本政策更新后我们会在本小程序发布最新版本并通过显著方式提醒您请您定期查阅
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const goBack = () => {
uni.navigateBack();
};
</script>
<style lang="stylus" scoped>
.agreement-page
min-height: 100vh
background: #f5f5f5
.nav-bar
height: 88rpx
background: #fff
display: flex
align-items: center
justify-content: space-between
padding: 0 32rpx
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05)
position: sticky
top: 0
z-index: 10
.nav-left
.nav-right
width: 80rpx
height: 88rpx
display: flex
align-items: center
.nav-left
justify-content: flex-start
.nav-right
justify-content: flex-end
.nav-title
font-size: 32rpx
font-weight: 600
color: #333
.content
flex: 1
.agreement-content
padding: 32rpx
background: #fff
margin: 20rpx
border-radius: 16rpx
.agreement-title
font-size: 36rpx
font-weight: 700
color: #333
text-align: center
margin-bottom: 40rpx
.important-tip
background: #f0f5ff
border-left: 8rpx solid #256bfa
padding: 24rpx
margin-bottom: 40rpx
font-size: 28rpx
line-height: 1.6
color: #333
.section
margin-bottom: 48rpx
.section-title
font-size: 32rpx
font-weight: 600
color: #333
margin-bottom: 32rpx
padding-bottom: 16rpx
border-bottom: 2rpx solid #f0f0f0
.section-subtitle
font-size: 28rpx
font-weight: 600
color: #333
margin-bottom: 24rpx
.section-content
margin-bottom: 32rpx
.paragraph
display: flex
margin-bottom: 24rpx
.paragraph-title
font-weight: 500
color: #333
min-width: 120rpx
flex-shrink: 0
.paragraph-text
font-size: 26rpx
line-height: 1.6
color: #666
flex: 1
.paragraph:last-child
margin-bottom: 0
</style>

View File

@@ -0,0 +1,322 @@
<template>
<view class="agreement-page">
<!-- 顶部导航栏 -->
<!-- <view class="nav-bar">
<view class="nav-left" @click="goBack">
<uni-icons type="back" size="28" color="#333"></uni-icons>
</view>
<view class="nav-title">用户协议</view>
<view class="nav-right"></view>
</view> -->
<!-- 内容区域 -->
<scroll-view class="content" scroll-y>
<view class="agreement-content">
<!-- 协议标题 -->
<!-- <view class="agreement-title">用户协议与隐私政策</view> -->
<!-- 重要提示 -->
<view class="important-tip">
在您注册登录使用本小程序服务之前请您务必审慎阅读充分理解本协议各条款内容特别是以加粗形式提示您注意的关于免除或限制责任争议解决及法律适用的条款一旦您以任何方式访问使用本小程序即表示您已同意接受本协议及我们另行发布的隐私政策的全部内容约束如您不同意本协议的任何内容请立即停止使用本小程序
</view>
<view class="important-tip">
如果您未满18周岁请在法定监护人的陪同下阅读和判断是否同意本协议并特别注意未成年人使用条款
</view>
<!-- 第一部分用户服务协议 -->
<view class="section">
<view class="section-title">第一部分用户服务协议</view>
<!-- 服务定义与变更 -->
<view class="section-subtitle"> 服务定义与变更</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">1.1 服务内容</view>
<view class="paragraph-text">本小程序是喀什地区人社局为您提供的的平台服务具体服务内容可能因版本更新而调整</view>
</view>
<view class="paragraph">
<view class="paragraph-title">1.2 服务变更与中断</view>
<view class="paragraph-text">为保障服务质量我们有权随时对服务内容功能操作界面等进行调整变更或中断恕不另行单独通知对于因服务调整中断或终止对用户或任何第三方造成的损失除法律明确规定外不承担任何责任</view>
</view>
</view>
<!-- 账号管理与安全 -->
<view class="section-subtitle"> 账号管理与安全</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">2.1 账号注册</view>
<view class="paragraph-text">您需要通过微信授权登录来使用本小程序的核心功能该授权将帮助我们获取您的微信头像昵称地区等基本信息您知悉并同意该授权行为即视为您已完成账号注册</view>
</view>
<view class="paragraph">
<view class="paragraph-title">2.2 账号安全</view>
<view class="paragraph-text">您的微信账号由您自行保管并承担安全责任您应妥善保管与微信账号相关的一切信息并对您账号下发生的一切活动包括但不限于言论发表信息发布服务购买等承担全部法律责任如发现任何未经授权的账号使用行为应立即通知我们我们将对前述情况采取合理的行动但除因我们的过错外我们不承担由此导致的任何损失</view>
</view>
</view>
<!-- 用户行为规范 -->
<view class="section-subtitle"> 用户行为规范</view>
<view class="section-content">
<view class="paragraph-text">您承诺并保证在使用本小程序服务时遵守中华人民共和国法律法规社会公德并不得从事以下行为</view>
<view class="paragraph">
<view class="paragraph-title">3.1 </view>
<view class="paragraph-text">上传发布传播或分享任何反对宪法所确定的基本原则危害国家安全泄露国家秘密颠覆国家政权破坏国家统一损害国家荣誉和利益煽动民族仇恨民族歧视破坏民族团结破坏国家宗教政策宣扬邪教和封建迷信淫秽色情赌博暴力凶杀恐怖或者教唆犯罪等法律行政法规禁止的内容</view>
</view>
<view class="paragraph">
<view class="paragraph-title">3.2 </view>
<view class="paragraph-text">侵犯他人知识产权商业秘密肖像权隐私权等合法权益</view>
</view>
<view class="paragraph">
<view class="paragraph-title">3.3 </view>
<view class="paragraph-text">发布任何虚假骚扰性侮辱性诽谤性恐吓性庸俗淫秽或任何其他非法信息</view>
</view>
<view class="paragraph">
<view class="paragraph-title">3.4 </view>
<view class="paragraph-text">利用技术手段恶意爬取干扰破坏本小程序的正常运营或增加服务器负载</view>
</view>
<view class="paragraph">
<view class="paragraph-title">3.5 </view>
<view class="paragraph-text">未经许可从事任何形式的商业广告行为或利用本小程序进行传销金字塔骗局等非法营销活动</view>
</view>
<view class="paragraph">
<view class="paragraph-title">3.6 </view>
<view class="paragraph-text">其他任何违反法律规定或干扰本小程序正常运营的行为</view>
</view>
<view class="paragraph-text">若用户违反上述规定我们有权单方面判断采取中断服务限制功能封禁账号等措施并保留追究法律责任的权利</view>
</view>
<!-- 知识产权声明 -->
<view class="section-subtitle"> 知识产权声明</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">4.1 </view>
<view class="paragraph-text">本公司独立拥有或与相关内容提供者共同拥有本小程序及相关软件技术代码文档页面设计Logo商标信息内容等的知识产权</view>
</view>
<view class="paragraph">
<view class="paragraph-title">4.2 </view>
<view class="paragraph-text">未经本公司或相关权利人书面许可任何单位和个人不得以任何方式包括但不限于非法复制传播展示修改创建衍生作品等使用上述知识产权否则我们将依法追究其法律责任</view>
</view>
</view>
<!-- 免责与责任限制 -->
<view class="section-subtitle"> 免责与责任限制</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">5.1 "现状"提供</view>
<view class="paragraph-text">本小程序的服务按"现状""可得到"的状态提供在法律允许的最大范围内我们明确表示不提供任何明示或默示的担保包括但不限于对服务的适用性没有错误或疏漏持续性准确性可靠性适用于某一特定用途</view>
</view>
<view class="paragraph">
<view class="paragraph-title">5.2 不可抗力</view>
<view class="paragraph-text">对于因战争动乱自然灾害政府行为电信线路中断黑客攻击计算机病毒侵入或发作第三方服务瑕疵等不可抗力因素导致的任何服务中断数据丢失或信息泄露等问题我们不承担责任</view>
</view>
<view class="paragraph">
<view class="paragraph-title">5.3 第三方链接与内容</view>
<view class="paragraph-text">本小程序内可能包含由第三方提供的服务或链接该等第三方服务或链接由第三方独立运营和控制我们不对其内容隐私政策或行为承担任何责任您使用任何第三方服务时需受其自身的条款和政策的约束</view>
</view>
</view>
<!-- 协议修改与终止 -->
<view class="section-subtitle"> 协议修改与终止</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">6.1 </view>
<view class="paragraph-text">我们有权根据国家法律法规变化及运营需要随时修改本协议的任何条款更新后的协议将在本小程序上公布并取代旧版本如您继续使用服务即视为接受更新后的协议</view>
</view>
<view class="paragraph">
<view class="paragraph-title">6.2 </view>
<view class="paragraph-text">您有权随时停止使用本小程序服务若我们判断您严重违反本协议我们有权单方面终止向您提供服务并保留追偿损失的权利</view>
</view>
</view>
<!-- 法律适用与争议解决 -->
<view class="section-subtitle"> 法律适用与争议解决</view>
<view class="section-content">
<view class="paragraph">
<view class="paragraph-title">7.1 </view>
<view class="paragraph-text">本协议的订立效力解释履行及争议的解决均适用中华人民共和国大陆地区法律</view>
</view>
<view class="paragraph">
<view class="paragraph-title">7.2 </view>
<view class="paragraph-text">因本协议引起的或与本协议有关的任何争议双方应首先友好协商解决协商不成的您同意将争议提交至 填写您公司所在地 有管辖权的人民法院通过诉讼解决</view>
</view>
</view>
</view>
<!-- 同意按钮 -->
<!-- <view class="agreement-actions">
<button class="agree-btn primary" @click="agreeAgreement">同意并继续</button>
<button class="agree-btn secondary" @click="disagreeAgreement">不同意</button>
</view> -->
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const goBack = () => {
uni.navigateBack();
};
// 同意协议
const agreeAgreement = () => {
// 存储用户同意状态
uni.setStorageSync('agreedToUserAgreement', true);
// 返回上一页
uni.navigateBack();
};
// 不同意协议
const disagreeAgreement = () => {
uni.showModal({
title: '提示',
content: '您需要同意用户协议才能使用本服务',
showCancel: false,
confirmText: '我知道了'
});
};
</script>
<style lang="stylus" scoped>
.agreement-page
height: 100vh
background: #f5f5f5
display: flex
flex-direction: column
.nav-bar
height: 88rpx
background: #fff
display: flex
align-items: center
justify-content: space-between
padding: 0 32rpx
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05)
position: sticky
top: 0
z-index: 10
.nav-left
.nav-right
width: 80rpx
height: 88rpx
display: flex
align-items: center
.nav-left
justify-content: flex-start
.nav-right
justify-content: flex-end
.nav-title
font-size: 32rpx
font-weight: 600
color: #333
.content
flex: 1
height: 0 /* 让flex:1生效 */
.agreement-content
padding: 32rpx
background: #fff
margin: 20rpx
border-radius: 16rpx
.agreement-title
font-size: 36rpx
font-weight: 700
color: #333
text-align: center
margin-bottom: 40rpx
.important-tip
background: #f0f5ff
border-left: 8rpx solid #256bfa
padding: 24rpx
margin-bottom: 40rpx
font-size: 28rpx
line-height: 1.6
color: #333
.section
margin-bottom: 48rpx
.section-title
font-size: 32rpx
font-weight: 600
color: #333
margin-bottom: 32rpx
padding-bottom: 16rpx
border-bottom: 2rpx solid #f0f0f0
.section-subtitle
font-size: 28rpx
font-weight: 600
color: #333
margin-bottom: 24rpx
.section-content
margin-bottom: 32rpx
.paragraph
display: flex
margin-bottom: 24rpx
.paragraph-title
font-weight: 500
color: #333
min-width: 120rpx
flex-shrink: 0
.paragraph-text
font-size: 26rpx
line-height: 1.6
color: #666
flex: 1
.paragraph:last-child
margin-bottom: 0
.agreement-actions
margin-top: 60rpx
padding: 0 32rpx
display: flex
flex-direction: column
gap: 24rpx
.agree-btn
width: 100%
height: 88rpx
border-radius: 44rpx
display: flex
align-items: center
justify-content: center
font-size: 32rpx
font-weight: 500
border: none
&.primary
background: linear-gradient(135deg, #256BFA 0%, #1E5BFF 100%)
color: #FFFFFF
box-shadow: 0 8rpx 20rpx rgba(37, 107, 250, 0.3)
&.secondary
background: #F7F8FA
color: #666666
</style>

View File

@@ -60,8 +60,8 @@
<header class="head">
<view class="main-header">
<image src="/static/icon/Hamburger-button.png" @click="toggleDrawer"></image>
<view class="title">{{ config.appInfo.areaName }}岗位推荐</view>
<!-- <view class="title">智能客服</view> -->
<!-- <view class="title">{{ config.appInfo.areaName }}岗位推荐</view> -->
<!-- <view class="title">{{ config.appInfo.areaName }}岗位推荐</view> -->
<image src="/static/icon/Comment-one.png" @click="addNewDialogue"></image>
</view>
</header>

View File

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

View File

@@ -23,6 +23,7 @@
<!-- 统一社会信用代码 -->
<view class="form-item">
<view class="label">统一社会信用代码</view>
<view class="input-with-button">
<input
class="input-field"
v-model="formData.socialCreditCode"
@@ -30,6 +31,8 @@
maxlength="18"
@input="updateCompletion"
/>
<button class="query-button" @click="queryCompanyByCreditCode">查询</button>
</view>
</view>
<!-- 企业注册地点 -->
@@ -600,6 +603,42 @@ const cancel = () => {
uni.navigateBack()
}
// 根据社会信用代码查询企业信息
const queryCompanyByCreditCode = async () => {
const creditCode = formData.socialCreditCode.trim()
if (!creditCode) {
$api.msg('请输入统一社会信用代码')
return
}
uni.showLoading({ title: '查询中...' })
try {
const response = await $api.createRequest('/app/company/queryCodeCompany', { code: creditCode }, 'get')
uni.hideLoading()
if (response.code === 200 && response.data) {
const companyData = response.data
// 回显企业信息到表单
if (companyData.name) formData.companyName = companyData.name
if (companyData.location) formData.registeredAddress = companyData.location
if (companyData.description) formData.companyIntro = companyData.description
if (companyData.nature) formData.nature = companyData.nature
if (companyData.registeredAddress) formData.registeredAddress = companyData.registeredAddress
if (companyData.legalPerson) formData.legalPersonName = companyData.legalPerson
// 其他字段根据接口返回的数据结构进行映射
updateCompletion()
$api.msg('企业信息查询成功')
} else {
$api.msg('未查询到企业信息')
}
} catch (error) {
uni.hideLoading()
$api.msg('查询失败,请重试')
console.error('查询企业信息失败:', error)
}
}
// 确认提交
const confirm = () => {
// 验证必填字段
@@ -837,6 +876,25 @@ defineExpose({
font-size: 28rpx
line-height: 1.4
.input-with-button
flex: 1
display: flex
align-items: center
gap: 16rpx
.query-button
padding: 8rpx 16rpx
background: #256BFA
color: #fff
font-size: 20rpx
border-radius: 6rpx
border: none
min-width: 100rpx
text-align: center
&:active
background: #1a5cd9
.input-con
flex: 1
font-size: 28rpx

View File

@@ -67,6 +67,7 @@
<view class="Detail-title">
<text class="title">参会单位{{ companyList.length }}</text>
</view>
<view v-if="isCompanyUser">
<view v-for="job in companyList" :key="job.id">
<view class="cards" :style="getItemBackgroundStyle('bj.png')"
@click="navTo('/packageA/pages/UnitDetails/UnitDetails?job='+JSON.stringify(job))">
@@ -101,6 +102,69 @@
</view>
</view>
</view>
<view v-else>
<view class="detail-box">
<view class="" v-for="(item1, index1) in companyList" :key="index1">
<view class="company-header1">
<view class="left">
<image
:src="`${baseUrl}/jobfair/gs.png`"
alt=""
class="company-icon"
/>
<text class="name1">{{ item1.companyName }}</text>
<!-- <div class="header-detail">企业详情 ></div> -->
</view>
</view>
<view
class="detail-item"
v-for="(job, index) in item1.jobInfoList"
:key="index"
>
<view class="gw">
<text>{{ job.jobTitle }}</text>
<view v-if="job.minSalary && job.maxSalary" class="salary">
{{ job.minSalary }}-{{ job.maxSalary }}
</view>
</view>
<view class="bottom">
<view class="tag">
<view class="tag-item">{{ job.industry }}</view>
<view class="tag-item success">{{ job.scale }}</view>
</view>
</view>
<view class="name">
<!-- 应聘状态1已投递2已邀请面试3已录用4不录用 -->
<view class="status" v-if="job.jobFairPersonJob?.status">
<text
:style="{
color: getStatusText(job.jobFairPersonJob?.status)
.color,
}"
>{{
getStatusText(job.jobFairPersonJob?.status).text
}}</text
>
</view>
<view v-else class="btn">
<button
plain
:disabled="deliveringJobs[job.jobId]"
style="color: #1685f7; border-color: #1685f7"
@click="deliverResume(job)"
>
{{
deliveringJobs[job.jobId] ? "投递中..." : "简历投递"
}}
</button>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<template #footer>
@@ -155,84 +219,194 @@
const companyList = ref([]);
const hasnext = ref(true);
const userInfo = ref({});
const signDialogisshow = ref(false)
const signDialogisshow = ref(false);
// 弹窗
const signType = ref(1);
// person个人 ent企业
const signRole = ref('ent');
const CompanySignPopup = ref(null)
const signRole = ref("ent");
const CompanySignPopup = ref(null);
// 报名loading状态
const isLoading = ref(false)
const isLoading = ref(false);
const jobFairId = ref(null)
const baseUrl = config.imgBaseUrl
const getItemBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
backgroundSize: '100% 100%', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
onLoad((options) => {
jobFairId.value=options.jobFairId
const jobFairId = ref(null);
const isCompanyUser = ref(false);
isCompanyUser.value = uni.getStorageSync("userInfo")?.isCompanyUser == 0;
// 获取状态文本
const getStatusText = (status) => {
switch (status) {
case "1":
return {
text: "已投递",
color: "#2aa553",
};
case "2":
return {
text: "已邀请面试",
color: "#409EFF",
};
case "3":
return {
text: "已录用",
color: "#67C23A",
};
case "4":
return {
text: "不录用",
color: "#F56C6C",
};
default:
return {
text: "未知状态",
color: "#2aa553",
};
}
};
const deliveringJobs = reactive({});
// 岗位投递
function deliverResume(job) {
uni.showModal({
title: "提示",
content: "请确认是否投递简历?",
showCancel: true,
confirmText: "确定",
cancelText: "取消",
success: (res) => {
if (res.confirm) {
if (deliveringJobs[job.jobId]) return;
deliveringJobs[job.jobId] = true;
const raw = uni.getStorageSync("Padmin-Token");
const token = typeof raw === "string" ? raw.trim() : "";
const headers = token ? {
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`
} : {};
const headers = token? { Authorization: raw.startsWith("Bearer ") ? raw: `Bearer ${token}`,}: {};
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData1) => {
if (resData1.code == 200) {
$api.myRequest(
"/system/user/login/user/info",
{},
"GET",
10100,
headers
)
.then((resData) => {
$api.myRequest(
"/jobfair/public/job-fair-person-job/insert",
{
jobFairId: job.jobFairId, // 招聘会id
personId: resData.info.userId, // 当前登录用户id
enterpriseId: job.companyId, // 企业id
jobId: job.jobId, // 岗位id
idCard: resData.info.personCardNo,
},
"post",
9100,
{
"Content-Type": "application/json",
}
)
.then((data) => {
if (data && data.code === 200) {
$api.msg("简历投递成功");
if (!job.jobFairPersonJob) {
job.jobFairPersonJob = {};
}
job.jobFairPersonJob.status = "1";
getCompanyInfo(userInfo.value.info.userId, jobFairId.value);
} else {
$api.msg((data && data.msg) || "简历投递失败");
}
deliveringJobs[job.jobId] = false;
});
});
} else {
$api.msg("请先登录");
deliveringJobs[job.jobId] = false;
}
})
.catch(() => {
deliveringJobs[job.jobId] = false;
});
}
},
});
}
const baseUrl = config.imgBaseUrl;
const getItemBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
backgroundSize: "100% 100%", // 覆盖整个容器
backgroundPosition: "center", // 居中
backgroundRepeat: "no-repeat",
});
onLoad((options) => {
jobFairId.value = options.jobFairId;
const raw = uni.getStorageSync("Padmin-Token");
const token = typeof raw === "string" ? raw.trim() : "";
const headers = token
? {
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`,
}
: {};
$api
.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers)
.then((resData) => {
if (resData.code == 200) {
$api.myRequest("/system/user/login/user/info", {}, "GET", 10100, {
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
}).then((userinfo) => {
userInfo.value = userinfo
$api
.myRequest("/system/user/login/user/info", {}, "GET", 10100, {
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`,
})
.then((userinfo) => {
userInfo.value = userinfo;
getCompanyInfo(userInfo.value.info.userId, options.jobFairId);
});
} else {
getCompanyInfo('', options.jobFairId);
getCompanyInfo("", options.jobFairId);
}
});
});
function closePopup() {
CompanySignPopup.value.close()
getCompanyInfo(userInfo.value.info.userId, jobFairId.value)
CompanySignPopup.value.close();
getCompanyInfo(userInfo.value.info.userId, jobFairId.value);
}
function getCompanyInfo(userId, id) {
let data={}
if (userInfo.value&&userInfo.value.userType == 'ent') {
let data = {};
if (userInfo.value && userInfo.value.userType == "ent") {
data = {
jobFairId: id,
enterpriseId: userId,
code:userInfo.value.info.entCreditCode
}
}else if(userInfo.value&&userInfo.value.userType == 'ent'){
code: userInfo.value.info.entCreditCode,
};
} else if (userInfo.value && userInfo.value.userType == "ent") {
data = {
jobFairId: id,
personId: userId,
idCard:userInfo.value.info.personCardNo
}
idCard: userInfo.value.info.personCardNo,
};
} else {
data = {
jobFairId: id,
personId: userId
personId: userId,
};
}
}
$api.myRequest('/jobfair/public/jobfair/detail', data).then((resData) => {
$api.myRequest("/jobfair/public/jobfair/detail", data).then((resData) => {
fairInfo.value = resData.data;
});
$api.myRequest('/jobfair/public/jobfair/enterprises-with-jobs-by-job-fair-id', {
jobFairId: id
}).then((resData) => {
$api
.myRequest("/jobfair/public/jobfair/enterprises-with-jobs-by-job-fair-id", {
personId: userInfo.value?.info?.userId,
jobFairId: jobFairId.value,
})
.then((resData) => {
if(resData.code == 200){
companyList.value = resData.data;
}
});
};
}
const hasAppointment = () => {
const isTimePassed = (timeStr) => {
const targetTime = new Date(timeStr.replace(/-/g, '/')).getTime(); // 兼容格式
const targetTime = new Date(timeStr.replace(/-/g, "/")).getTime(); // 兼容格式
const now = Date.now();
return now < targetTime;
};
@@ -240,12 +414,14 @@
hasnext.value = isTimePassed(fairInfo.value.startTime);
};
function openMap(lat, lng, name = '位置') {
const isConfirmed = window.confirm('是否打开地图查看位置?');
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)}`;
const url = `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(
name
)}`;
window.location.href = url;
}
@@ -255,82 +431,96 @@
// 报名招聘会
function applyExhibitors() {
if (isLoading.value) return
if (isLoading.value) return;
if (fairInfo.value.isSignUp == 1) {
$api.msg('请勿重复报名');
return
$api.msg("请勿重复报名");
return;
}
const raw = uni.getStorageSync("Padmin-Token");
const token = typeof raw === "string" ? raw.trim() : "";
const headers = token ? {
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`
} : {};
isLoading.value = true
const headers = token
? {
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`,
}
: {};
isLoading.value = true;
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
$api
.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers)
.then((resData) => {
if (resData.code == 200) {
if (userInfo.value.userType == 'ent') {
if (userInfo.value.userType == "ent") {
// 企业
signType.value = fairInfo.value.jobFairType;
signRole.value = userInfo.userType;
signDialogisshow.value = true
CompanySignPopup.value.open()
isLoading.value = false
signDialogisshow.value = true;
CompanySignPopup.value.open();
isLoading.value = false;
} else {
$api.myRequest("/jobfair/public/job-fair-sign-up-person/sign-up", {
$api
.myRequest(
"/jobfair/public/job-fair-sign-up-person/sign-up",
{
personId: userInfo.value.info.userId,
jobFairId: jobFairId.value,
idCard:userInfo.value.info.personCardNo
}, "POST", 9100, { "Content-Type": "application/json",...headers }).then((res) => {
idCard: userInfo.value.info.personCardNo,
},
"POST",
9100,
{ "Content-Type": "application/json", ...headers }
)
.then((res) => {
if (res.code === 200) {
uni.showToast({
title: '报名成功',
icon: 'success'
title: "报名成功",
icon: "success",
});
fairInfo.value.isSignUp = 1;
getCompanyInfo(userInfo.value.info.userId, jobFairId.value);
} else {
uni.showToast({
title: res.msg || '报名失败',
icon: 'none'
title: res.msg || "报名失败",
icon: "none",
});
}
isLoading.value = false
})
isLoading.value = false;
});
}
} else {
$api.msg('请先登录');
$api.msg("请先登录");
// setTimeout(() => {
// uni.redirectTo({
// url: '/packageB/login'
// })
// }, 1000)
isLoading.value = false
isLoading.value = false;
}
}).catch(() => {
isLoading.value = false
})
.catch(() => {
isLoading.value = false;
});
}
function parseDateTime(datetimeStr) {
if (!datetimeStr) return {
time: '',
date: ''
if (!datetimeStr)
return {
time: "",
date: "",
};
const dateObj = new Date(datetimeStr);
if (isNaN(dateObj.getTime())) return {
time: '',
date: ''
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');
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}`,
@@ -345,25 +535,25 @@
// 判断状态0 开始中1 过期2 待开始
let status = 0;
let statusText = '开始中';
let color = '#13C57C'; // 进行中 - 绿色
let statusText = "开始中";
let color = "#13C57C"; // 进行中 - 绿色
if (now < startTime) {
status = 2; // 待开始
statusText = '待开始';
color = '#015EEA'; // 未开始 - 蓝色
statusText = "待开始";
color = "#015EEA"; // 未开始 - 蓝色
} else if (now > endTime) {
status = 1; // 已过期
statusText = '已过期';
color = '#999999'; // 已过期 - 灰色
statusText = "已过期";
color = "#999999"; // 已过期 - 灰色
} else {
status = 0; // 进行中
statusText = '进行中';
color = '#13C57C'; // 进行中 - 绿色
statusText = "进行中";
color = "#13C57C"; // 进行中 - 绿色
}
return {
status, // 0: 进行中1: 已过期2: 待开始
statusText,
color
color,
};
}
@@ -378,7 +568,7 @@
}
</script>
<style lang="stylus" scoped>
<style lang="scss" scoped>
.popup-content {
width: 90vw;
height: 80vh;
@@ -428,13 +618,14 @@
font-weight: 500;
font-size: 32rpx;
color: #333333;
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
font-family: "PingFangSC-Medium", "PingFang SC", "Helvetica Neue",
Helvetica, Arial, "Microsoft YaHei", sans-serif;
}
.row2 {
font-weight: 400;
font-size: 28rpx;
color: #6C7282;
color: #6c7282;
line-height: 45rpx;
display: flex;
justify-content: space-between;
@@ -451,7 +642,7 @@
.location-img {
border-radius: 8rpx 8rpx 8rpx 8rpx;
border: 2rpx solid #EFEFEF;
border: 2rpx solid #efefef;
}
.location-info {
@@ -479,35 +670,34 @@
.info-text {
font-weight: 400;
font-size: 28rpx;
color: #9B9B9B;
color: #9b9b9b;
position: relative;
padding-right: 20rpx
padding-right: 20rpx;
}
.info-text::before {
position: absolute;
right: 0;
top: 50%;
content: '';
content: "";
width: 4rpx;
height: 16rpx;
border-radius: 2rpx;
background: #9B9B9B;
transform: translate(0, -75%) rotate(-45deg)
background: #9b9b9b;
transform: translate(0, -75%) rotate(-45deg);
}
.info-text::after {
position: absolute;
right: 0;
top: 50%;
content: '';
content: "";
width: 4rpx;
height: 16rpx;
border-radius: 2rpx;
background: #9B9B9B;
transform: translate(0, -25%) rotate(45deg)
background: #9b9b9b;
transform: translate(0, -25%) rotate(45deg);
}
}
}
}
@@ -533,7 +723,7 @@
}
.title2 {
margin-top: 48rpx
margin-top: 48rpx;
}
}
@@ -559,7 +749,7 @@
margin-bottom: 46rpx;
font-weight: 400;
font-size: 28rpx;
color: #256BFA;
color: #256bfa;
.expand-img {
width: 40rpx;
@@ -567,7 +757,7 @@
}
.expand-img-active {
transform: rotate(180deg)
transform: rotate(180deg);
}
}
}
@@ -575,7 +765,7 @@
.Detailscroll-view {
flex: 1;
overflow: hidden;
background: #F4F4F4;
background: #f4f4f4;
.views {
padding: 28rpx;
@@ -597,19 +787,19 @@
.Detail-title::before {
position: absolute;
content: '';
content: "";
left: -14rpx;
bottom: 0;
height: 16rpx;
width: 108rpx;
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
background: linear-gradient(to right, #cbdeff, #ffffff);
border-radius: 8rpx;
z-index: 1;
}
.cards {
padding: 32rpx;
background: #FFFFFF;
background: #ffffff;
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
border-radius: 20rpx 20rpx 20rpx 20rpx;
margin-top: 22rpx;
@@ -630,7 +820,6 @@
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
}
@@ -642,7 +831,7 @@
}
.ris {
background: #53ACFF;
background: #53acff;
color: #fff;
padding: 7rpx 20rpx;
border-radius: 8rpx;
@@ -652,7 +841,7 @@
.card-companyName {
font-weight: 400;
font-size: 28rpx;
color: #6C7282;
color: #6c7282;
}
.card-tags {
@@ -662,7 +851,7 @@
.tag {
width: fit-content;
height: 30rpx;
background: #E0F0FF;
background: #e0f0ff;
border-radius: 4rpx;
padding: 6rpx 26rpx;
line-height: 30rpx;
@@ -689,7 +878,123 @@
display: flex;
justify-content: space-between;
font-size: 28rpx;
color: #6C7282;
color: #6c7282;
}
}
.detail-box {
padding-top: 20rpx;
box-sizing: border-box;
.company-header1 {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 12px;
.name1 {
font-weight: 600;
margin-right: 12px;
font-size: 18px;
}
.company-icon {
width: 20px;
height: 20px;
margin-right: 15px;
}
.left {
display: flex;
align-items: center;
.header-detail {
background: #5599ff;
border-radius: 18px;
padding: 2px 16px;
color: #fff;
font-size: 14px;
}
}
.icon {
margin-right: 6px;
color: #409eff;
}
.booth-no {
color: #909399;
}
}
.detail-item {
margin-top: 16rpx;
background: linear-gradient(to bottom, #deecff 0%, #ffffff 100%);
box-shadow: 0 0 10rpx rgba(0, 95, 169, 0.19);
border-radius: 12rpx;
border: 2rpx solid #ffffff;
padding: 30rpx;
}
.name {
font-size: 32rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 10rpx;
.status {
width: 160rpx;
text-align: center;
margin-left: 24rpx;
font-size: 24rpx;
background-size: 100% 100%;
font-weight: 600;
padding: 6rpx 0;
margin: 18rpx 0;
}
.btn {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
button {
margin: 10rpx;
font-size: 24rpx;
}
}
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
.tag {
width: 100%;
display: flex;
align-items: center;
gap: 16rpx;
flex-wrap: wrap;
.tag-item {
padding: 6rpx 30rpx;
border-radius: 6rpx;
background-color: #e5f1ff;
color: #589bff;
font-size: 28rpx;
&.success {
background-color: #e6f8eb;
color: #21aa5b;
}
}
}
}
.gw {
display: flex;
align-items: center;
justify-content: space-between;
color: #1477f1;
font-weight: 600;
font-size: 30rpx;
}
}
}
@@ -722,7 +1027,7 @@
.line {
width: 40rpx;
height: 0rpx;
border: 2rpx solid #D4D4D4;
border: 2rpx solid #d4d4d4;
margin-top: 64rpx;
}
@@ -736,7 +1041,7 @@
.center-date {
font-weight: 400;
font-size: 28rpx;
color: #FF881A;
color: #ff881a;
}
.center-dateDay {
@@ -747,14 +1052,14 @@
line-height: 48rpx;
width: 104rpx;
height: 48rpx;
background: #F9F9F9;
background: #f9f9f9;
border-radius: 8rpx 8rpx 8rpx 8rpx;
}
}
}
.footer {
background: #FFFFFF;
background: #ffffff;
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11, 44, 112, 0.12);
border-radius: 0rpx 0rpx 0rpx 0rpx;
@@ -762,17 +1067,17 @@
.btn-wq {
height: 90rpx;
background: #256BFA;
background: #256bfa;
border-radius: 12rpx 12rpx 12rpx 12rpx;
font-weight: 500;
font-size: 32rpx;
color: #FFFFFF;
color: #ffffff;
text-align: center;
line-height: 90rpx
line-height: 90rpx;
}
.btn-desbel {
background: #6697FB;
background: #6697fb;
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11, 44, 112, 0.12);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,12 +49,15 @@
code: '',
uuid: ''
})
const jumpUrl=ref('')
onLoad((option) => {
console.log("111")
console.log("111",option)
if(option.flag){
flag.value=option.flag
}
if(option.jump){
jumpUrl.value=option.jump
}
})
onMounted(() => {
@@ -140,8 +143,12 @@
}else if(flag.value=='nw'){
$api.myRequest('/auth/login',form,'post',9100).then((res) => {
uni.setStorageSync('Padmin-Token', res.data.access_token)
// 临时修改,现在有多个跳转页面
// uni.reLaunch({
// url: '/packageB/priority/helpFilter'
// })
uni.reLaunch({
url: '/packageB/priority/helpFilter'
url:jumpUrl.value
})
codeUrl.value = 'data:image/gif;base64,' + res.img
}).catch(() => {

View File

@@ -0,0 +1,358 @@
<template>
<AppLayout :title="title" :show-bg-image="false" >
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>帮扶任务分配</text>
<view class="title-line"></view>
</view>
</view>
<view class="form-container">
<uni-forms ref="formRef" v-model="formData" :rules="rules" validate-trigger="submit" >
<uni-forms-item label="任务名称:" name="taskName" required >
<uni-easyinput v-model="formData.taskName" placeholder="请输入任务名称"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="目标人员:" name="priority" required >
<uni-data-select v-model="formData.priority" placeholder="请选择目标人员" :localdata="followWays" @change="onMethodChange"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="目标人数:" name="content" required>
<uni-easyinput v-model="formData.taskAllocation.goalPersonCount" placeholder="请输入目标人数"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="执行区域:" name="executeDeptId" required >
<uni-data-select v-model="formData.taskAllocation.executeDeptId" placeholder="请选择执行区域" :localdata="followWays" @change="onMethodChange"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="分配说明:" name="allocationNote" required>
<uni-easyinput type="textarea" v-model="formData.taskAllocation.allocationNote" placeholder="请输入分配说明"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="截止时间:" name="deadline" >
<uni-datetime-picker class="picker-value" type="date" placeholder="请选择截止时间" v-model="formData.taskAllocation.deadline" @change="onDateChange" />
</uni-forms-item>
</uni-forms>
<!-- 按钮组 -->
<view class="button-group">
<button class="btn submit-btn" @click="handleSubmit">确定</button>
<button class="btn reset-btn" @click="handleReset">取消</button>
</view>
</view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
const title = ref('');
const formData = reactive({
taskName: '',
taskType: '',
priority: '',
taskAllocation: {
goalPersonCount: null,
executeDeptId: '',
executeDeptName: '',
executeDeptAncestors: '',
allocationStatus: '1',
allocationNote: '',
deadline: null,
goalPersonList: []
}
})
const personInfo=ref({
goalPersonId:'',
name:'',
taskType:'',
task_id:''
})
const followWays = ref([])
const followList = ref([])
const followListNum=ref(0)
// 表单引用
const formRef = ref(null)
// 校验规则
const rules = {
followDate: {
rules: [{
required: true,
errorMessage: '请选择跟进日期'
}]
},
followWay: {
rules: [{
required: true,
errorMessage: '请选择跟进方式'
}]
},
content: {
rules: [{
required: true,
errorMessage: '请填写跟进内容'
}]
},
result: {
rules: [{
required: true,
errorMessage: '请填写跟进结果'
}]
}
}
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const onFollowDateChange = (e)=>{
formData.followDate=e
}
const onMethodChange = (e) => {
formData.followWay=e
}
// 事件处理
const onDateChange = ( e) => {
formData.nextContactDate=e
}
function getFollowList(){
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={
personId:personInfo.value.person_id,
taskId:personInfo.value.task_id
}
$api.myRequest('/dispatch/assist/records/getFollowList', params,'get',9100,header).then((resData) => {
console.log("resData",resData)
if(resData && resData.code == 200){
if(resData.data && resData.data.length>0){
followListNum.value=resData.data.length
resData.data.forEach(item=>{
const obj={
title:item.followDate,
desc:`跟进方式:${getFollowWaysLabelByValue(item.followWay)}\n跟进人${item.createByName}\n跟进内容${item.content}`
}
followList.value.push(obj)
})
}
}
});
}
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/assist_follow_way').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
followWays.value.push(obj)
})
}
});
}
function getFollowWaysLabelByValue(value) {
if (!Array.isArray(followWays.value)) {
return ''
}
const item = followWays.value.find(item => item.value === String(value))
return item ? item.text : '暂无跟进方式'
}
const handleSubmit = () => {
formRef.value?.validate()
.then(() => {
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token')
}
formData.goalPersonId=personInfo.value.goalPersonId
$api.myRequest('/dispatch/assist/records/addRecords', formData,'post',9100,header).then((resData) => {
console.log("resData",resData)
if(resData && resData.code == 200){
handleReset()
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
}else{
uni.showToast({
title: resData.msg,
icon: 'none',
duration: 2000
});
}
});
})
.catch((errors) => {
console.log('校验失败:', errors);
});
};
const handleReset = () => {
formData.followDate = '';
formData.followWay = '';
formData.content = '';
formData.result = '';
formData.nextPlan = '';
formData.nextContactDate = '';
}
onLoad((options) => {
// personInfo.value.person_id=options.person_id
// personInfo.value.name=options.name
// personInfo.value.taskType=options.taskType
// personInfo.value.task_id=options.task_id
// getDictionary()
// getFollowList()
});
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.info-box
margin: 30rpx 30rpx
background: linear-gradient(0deg, #D9ECFF 0%, #F0F7FF 100%)
border-radius: 20rpx
padding: 40rpx 0
display: flex
align-items: center
.info-img
width: 40rpx
height: 40rpx
margin-bottom: 20rpx
.info-line
border-right: 2rpx solid #B7D6FF
.info-item
display: flex
flex-direction: column
align-items: center
justify-content: center
width: 50%
.info-label
font-size: 26rpx
color: #6E7E9B
margin-bottom: 20rpx
.info-value
font-weight: bold
font-size: 28rpx
color: #3D61AC
.main-list
background-color: #ffffff
padding: 20rpx 20rpx 28rpx 20rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 70rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.label
width: 160rpx
font-size: 28rpx
color: #404040
.input,
.picker
flex: 1
.picker-value
color: #666
.list-box
margin-top: 40rpx
.form-container
margin-top: 30rpx
:deep(.uni-forms-item__label)
width: 194rpx !important
font-size: 28rpx;
color: #404040;
.button-group {
display: flex;
justify-content: space-between;
padding: 40rpx 20rpx 20rpx;
}
.btn {
width: 45%;
height: 80rpx;
font-size: 30rpx;
border-radius: 8rpx;
}
.reset-btn {
background-color: #D8E9FF;
color: #1176FF;
}
.submit-btn {
background-color: #368BFF;
color: white;
}
:deep(.uni-steps__column-circle )
width: 24rpx !important
height: 24rpx !important
background: radial-gradient(circle,
#00C0FA 0%,
#015EEA 50%,
#FFFFFF 51%,
#FFFFFF 100%) !important
border-radius: 50%
border: 2rpx solid #015EEA
:deep(.uni-steps__column-title)
font-size: 28rpx !important
color: #006CFF !important
margin-bottom: 24rpx
:deep(.uni-steps__column-desc)
font-size: 28rpx
color: #898989 !important
line-height: 1.5
:deep(.uni-steps__column-text )
padding: 16rpx 0 !important
border: none
:deep(.uni-steps__column-line)
background-color: #368BFF !important
:deep(.uni-steps__column-line--before)
background-color:rgba(0,0,0,0) !important
:deep(.uni-date-x)
background: rgba(0,0,0,0) !important
:deep(.uni-stat-box)
background: rgba(0,0,0,0) !important
:deep(.uni-easyinput__content)
background: rgba(0,0,0,0) !important
</style>

View File

@@ -0,0 +1,473 @@
<template>
<AppLayout :title="title" :show-bg-image="false" >
<view class="page-container" >
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom" lower-threshold="50">
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="task-box">
<text class="task-label">任务</text>
<text class="task-name">{{props.taskName}}</text>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>目标人员列表</text>
<view class="title-line" style="left: 70rpx;"></view>
</view>
<view class="title-total">
目标人数<text class="total-num">{{totalNum}}</text>
</view>
</view>
<view class="list-box" v-if="dataList.length>0">
<view class="con-box" v-for="(item,index) in dataList" :key="index">
<view class="form-title">
<view class="form-name">
{{item.name}}
</view>
</view>
<view class="form-item" v-if="item.idCard">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/person.png'" mode=""></image>
<view class="item-label">
身份证号
</view>
</view>
<view class="item-right">
{{item.idCard}}
</view>
</view>
<view class="form-item" v-if="item.phone">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/tele.png'" mode=""></image>
<view class="item-label">
联系电话
</view>
</view>
<view class="item-right">
{{item.phone}}
</view>
</view>
<view class="form-item" v-if="item.address">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/base.png'" mode=""></image>
<view class="item-label">
住址
</view>
</view>
<view class="item-right">
{{item.address}}
</view>
</view>
<view class="form-item" v-if="item.skills">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
技能特长
</view>
</view>
<view class="item-right">
{{item.skills}}
</view>
</view>
<view class="form-item" v-if="item.tags.length>0">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
人员标签
</view>
</view>
<view class="item-right">
<view class="" v-for="(val,num) in item.tags" :key="num">
{{val}}
</view>
</view>
</view>
<view class="form-item" v-if="item.datasource">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
数据来源
</view>
</view>
<view class="item-right">
{{item.datasource=== '1' ? '自动识别' : '手动添加'}}
</view>
</view>
<view class="form-item" v-if="item.assistStatus">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/help.png'" mode=""></image>
<view class="item-label">
帮扶状态
</view>
</view>
<view class="item-right">
{{item.assistStatus}}
</view>
</view>
<view class="form-item" v-if="item.employmentStatus">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
就业状态
</view>
</view>
<view class="item-right">
{{item.employmentStatus}}
</view>
</view>
<view class="form-item" v-if="item.unemploymentDate">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
失业时间
</view>
</view>
<view class="item-right">
{{item.unemploymentDate}}
</view>
</view>
<view class="form-item" v-if="item.unemploymentRegisterDate">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
失业登记时间
</view>
</view>
<view class="item-right">
{{item.unemploymentRegisterDate}}
</view>
</view>
<view class="form-item" v-if="item.graduateDate">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
毕业时间
</view>
</view>
<view class="item-right">
{{item.graduateDate}}
</view>
</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
</view>
</scroll-view>
<view class="button-group">
<view class="btns">
<button class="btn reset-btn" @click="handleCancel">关闭</button>
</view>
</view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
const props = defineProps({
currentItem:{
type: String,
required: true,
default: ''
},
taskName:{
type: String,
required: true,
default: ''
},
})
const title = ref('');
const pageNum = ref(1)
const pageSize = ref(2)
const currentItem=ref({})
const totalNum=ref(0)
const dataList=ref([])
const personDatabaseStatusOptions=ref([])
const employmentStatusOptions=ref([])
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const emit = defineEmits(['update:showView'])
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/person_database_status').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
personDatabaseStatusOptions.value.push(obj)
})
}
});
$api.myRequest('/system/public/dict/data/type/assist_employment_status').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
employmentStatusOptions.value.push(obj)
})
}
});
}
function getabelByValue(value,arr) {
if (!Array.isArray(arr.value)) {
return ''
}
const item = arr.value.find(item => item.value === String(value))
return item ? item.text : '暂无'
}
const handleCancel = () => {
emit('update:showView', 'main')
}
function getDataList(){
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={
allocationId: props.currentItem,
pageNum: pageNum.value,
pageSize: pageSize.value
}
$api.myRequest('/dispatch/assist/person/database/pageGoalPersonList',params,'get',9100,header).then((resData) => {
resData.rows.forEach(item=>{
item.tags=item.tagName.split(',')
item.assistStatus=getabelByValue(item.assistStatus,personDatabaseStatusOptions)
item.employmentStatus=getabelByValue(item.employmentStatus,employmentStatusOptions)
})
totalNum.value=resData.total
dataList.value=dataList.value.concat(resData.rows)
});
}
function scrollBottom(){
if(pageNum.value<totalNum.value/pageSize.value){
pageNum.value++
getDataList()
}
}
onMounted(() => {
runAsyncTasks()
});
const runAsyncTasks = async () => {
await getDictionary()
await getDataList()
}
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.page-container {
display: flex;
flex-direction: column;
height: calc(100vh - var(--window-top)); /* 如果 AppLayout 有 header需减去 */
/* 或者简单用height: 100vh; */
padding-bottom: 140rpx
}
.nearby-scroll
// 使用flex布局让scroll-view自适应高度占据剩余空间
flex: 1
// overflow: hidden;
.task-box
display: flex
align-items: center
.task-label
font-size: 30rpx
color: #6E7E9B
.task-name
font-weight: bold
font-size: 30rpx
color: #3D61AC
.main-list
background-color: #ffffff
padding: 20rpx 20rpx 28rpx 20rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 70rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.list-box
margin-top: 40rpx
:deep(.uni-forms-item__label)
width: 194rpx !important
font-size: 28rpx;
color: #404040;
.search-container
padding: 20rpx 0rpx 0rpx 0rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.search-item
display: flex
align-items: center
margin-bottom: 30rpx
.label
width: 160rpx
font-size: 28rpx
color: #404040
flex-shrink: 0
.input,
.picker
background: #FFFFFF
flex: 1
min-width: 0
.search-box-btn
border-radius: 32rpx !important
background: #3088FF !important
margin-right: 16rpx
.reset-box-btn
border-radius: 32rpx !important
background: #02B44D
color: #fff
.con-box
background: #fff
padding: 20rpx
box-shadow: 0px 0px 6rpx 0px rgba(0,71,200,0.16)
border-radius: 24rpx
border: 1rpx solid #EDF5FF
margin-top: 30rpx
.form-title
display: flex
align-items: center
.form-name
font-weight: bold
font-size: 30rpx
color: #595959
margin-right:16rpx
.form-type
border-radius: 8rpx;
border: 2rpx solid #FF7D26;
font-size: 24rpx
color: #F1690E
padding: 4rpx 10rpx
.form-item
display: flex
align-items: center
justify-content: space-between
margin-top: 30rpx
.item-left
display: flex
align-items: center
.item-img
width: 26rpx
height: 26rpx
margin-right: 10rpx
.item-label
font-size: 26rpx
color: #B3B3B3
width: 190rpx
.item-right
font-size: 26rpx
color: #737373
// overflow: hidden
// text-overflow: ellipsis
// white-space: nowrap
word-wrap: break-word
overflow-wrap: break-word
white-space: normal
.form-btns
margin-top:30rpx
.form-box-btn
border-radius: 50rpx !important
margin-right: 24rpx
padding: 0rpx 40rpx
.detail-btn
background: #EDF5FF
border: 1px solid #3088FF
font-size: 28rpx
color: #3088FF
.follow-btn
background: #EEF9F3
border: 1px solid #00933E
font-size: 28rpx
color: #00933E
.recommend-btn
background: linear-gradient(92deg, #0DCCFF 0%, #4760FF 100%)
font-size: 28rpx
color: #FFFFFF
.button-group
position: fixed
bottom: 0
left: 0
width: 100%
height: 120rpx
background: #fff
.btns
height: 120rpx
width: 100%
line-height: 120px
display: flex
align-items: center
justify-content: space-between
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1)
.btn {
width: 45%;
height: 80rpx;
font-size: 30rpx;
border-radius: 8rpx;
}
.reset-btn {
background-color: #D8E9FF;
color: #1176FF;
}
.submit-btn {
background-color: #368BFF;
color: white;
}
</style>

View File

@@ -0,0 +1,545 @@
<template>
<AppLayout :title="title" :show-bg-image="false" >
<view class="page-container" >
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom" lower-threshold="50">
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>筛选条件</text>
<view class="title-line"></view>
</view>
<view class="title-right button-sp-area">
<button class="mini-btn search-box-btn" type="primary" size="mini" @click="handleSearch">查询</button>
<button class="mini-btn reset-box-btn" type="default" size="mini" @click="handleReset">重置</button>
</view>
</view>
<view class="search-container">
<view class="search-item">
<text class="label">姓名</text>
<uni-easyinput v-model="formData.name" placeholder="请输入任务名称"></uni-easyinput>
</view>
<view class="search-item">
<text class="label">身份证号</text>
<uni-easyinput v-model="formData.idCard" placeholder="请输入身份证号"></uni-easyinput>
</view>
<view class="search-item">
<text class="label">人员标签</text>
<uni-data-select v-model="formData.tagId" :localdata="personTagOptions" placeholder="请选择人员标签" @change="personTagChange"></uni-data-select>
</view>
<view class="search-item">
<text class="label">所属区域</text>
<uni-data-select v-model="formData.deptTags" :localdata="taskTypeOptions" placeholder="请选择所属区域" @change="onTaskTypeChange"></uni-data-select>
</view>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>目标人员列表</text>
<view class="title-line" style="left: 70rpx;"></view>
</view>
<view class="title-total">
目标人数<text class="total-num">{{totalNum}}</text>
</view>
</view>
<view class="list-box" v-if="dataList.length>0">
<view class="con-box" v-for="(item,index) in dataList" :key="index">
<view class="form-title">
<checkbox :value="item.id" :checked="item.checked" @click="selectItem(item)"/>
<view class="form-name">
{{item.name}}
</view>
</view>
<view class="form-item" v-if="item.idCard">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/person.png'" mode=""></image>
<view class="item-label">
身份证号
</view>
</view>
<view class="item-right">
{{item.idCard}}
</view>
</view>
<view class="form-item" v-if="item.phone">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/tele.png'" mode=""></image>
<view class="item-label">
联系电话
</view>
</view>
<view class="item-right">
{{item.phone}}
</view>
</view>
<view class="form-item" v-if="item.address">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/base.png'" mode=""></image>
<view class="item-label">
住址
</view>
</view>
<view class="item-right">
{{item.address}}
</view>
</view>
<view class="form-item" v-if="item.skills">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
技能特长
</view>
</view>
<view class="item-right">
{{item.skills}}
</view>
</view>
<view class="form-item" v-if="item.tags.length>0">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
人员标签
</view>
</view>
<view class="item-right">
<view class="" v-for="(val,num) in item.tags" :key="num">
{{val}}
</view>
</view>
</view>
<view class="form-item" v-if="item.datasource">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
数据来源
</view>
</view>
<view class="item-right">
{{item.datasource=== '1' ? '自动识别' : '手动添加'}}
</view>
</view>
<view class="form-item" v-if="item.assistStatus">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/help.png'" mode=""></image>
<view class="item-label">
帮扶状态
</view>
</view>
<view class="item-right">
{{item.assistStatus}}
</view>
</view>
<view class="form-item" v-if="item.employmentStatus">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
就业状态
</view>
</view>
<view class="item-right">
{{item.employmentStatus}}
</view>
</view>
<view class="form-item" v-if="item.unemploymentDate">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
失业时间
</view>
</view>
<view class="item-right">
{{item.unemploymentDate}}
</view>
</view>
<view class="form-item" v-if="item.unemploymentRegisterDate">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
失业登记时间
</view>
</view>
<view class="item-right">
{{item.unemploymentRegisterDate}}
</view>
</view>
<view class="form-item" v-if="item.graduateDate">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
毕业时间
</view>
</view>
<view class="item-right">
{{item.graduateDate}}
</view>
</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
</view>
</scroll-view>
<view class="button-group">
<view class="btns">
<button class="btn submit-btn" @click="handlesubmit">确认选择</button>
<button class="btn reset-btn" @click="handleCancel">关闭</button>
</view>
</view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
const title = ref('');
const formData = reactive({
name: '',
idCard: '',
tagId: '',
deptTags: '',
pageNum: 1,
pageSize: 10
})
const totalNum=ref(0)
const dataList=ref([])
const personDatabaseStatusOptions=ref([])
const employmentStatusOptions=ref([])
const personTagOptions=ref([])
const selectedPersonIds=ref([])
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const emit = defineEmits(['update:showView'])
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/person_database_status').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
personDatabaseStatusOptions.value.push(obj)
})
}
});
$api.myRequest('/system/public/dict/data/type/assist_employment_status').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
employmentStatusOptions.value.push(obj)
})
}
});
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={}
$api.myRequest('/dispatch/assist/person/tag/list',params,'get',9100,header).then((resData) => {
console.log("res",resData)
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.id,
text: item.name
}
personTagOptions.value.push(obj)
})
}
});
}
function getabelByValue(value,arr) {
if (!Array.isArray(arr.value)) {
return ''
}
const item = arr.value.find(item => item.value === String(value))
return item ? item.text : '暂无'
}
const handleCancel = () => {
emit('update:showView', 'main')
}
function handleSearch(){
dataList.value=[]
getDataList()
}
function handleReset(){
formData.name=''
formData.idCard=''
formData.tagId=''
formData.deptTags=''
formData.pageNum=1
formData.pageSize=10
dataList.value=[]
getDataList()
}
function getDataList(){
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
$api.myRequest('/dispatch/assist/person/database/pageList',formData,'get',9100,header).then((resData) => {
resData.rows.forEach(item=>{
item.tags=item.tagName.split(',')
item.assistStatus=getabelByValue(item.assistStatus,personDatabaseStatusOptions)
item.employmentStatus=getabelByValue(item.employmentStatus,employmentStatusOptions)
item.checked = false; // 添加这一行
})
totalNum.value=resData.total
dataList.value=dataList.value.concat(resData.rows)
});
}
function selectItem(item) {
const id = item.id; // 假设每条数据有唯一 id 字段
item.checked = !item.checked;
if (item.checked) {
// 如果选中,加入数组(去重)
if (!selectedPersonIds.value.includes(id)) {
selectedPersonIds.value.push(id);
}
} else {
// 如果取消选中,从数组中移除
selectedPersonIds.value = selectedPersonIds.value.filter(v => v !== id);
}
}
// 获取选中的数据
function handlesubmit() {
emit('update:showView', {
showView: 'main',
selectedPersonIds: selectedPersonIds.value
});
}
function personTagChange(e){
formData.tagId=e
}
function scrollBottom(){
if(formData.pageNum<totalNum.value/formData.pageSize){
formData.pageNum++
getDataList()
}
}
onMounted(() => {
runAsyncTasks()
});
const runAsyncTasks = async () => {
await getDictionary()
await getDataList()
}
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.page-container {
display: flex;
flex-direction: column;
height: calc(100vh - var(--window-top)); /* 如果 AppLayout 有 header需减去 */
padding-bottom: 140rpx
/* 或者简单用height: 100vh; */
}
.nearby-scroll
// 使用flex布局让scroll-view自适应高度占据剩余空间
flex: 1
// overflow: hidden;
.task-box
display: flex
align-items: center
.task-label
font-size: 30rpx
color: #6E7E9B
.task-name
font-weight: bold
font-size: 30rpx
color: #3D61AC
.main-list
background-color: #ffffff
padding: 20rpx 20rpx 28rpx 20rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 70rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.list-box
margin-top: 40rpx
:deep(.uni-forms-item__label)
width: 194rpx !important
font-size: 28rpx;
color: #404040;
.search-container
padding: 20rpx 0rpx 0rpx 0rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.search-item
display: flex
align-items: center
margin-bottom: 30rpx
.label
width: 160rpx
font-size: 28rpx
color: #404040
flex-shrink: 0
.input,
.picker
background: #FFFFFF
flex: 1
min-width: 0
.search-box-btn
border-radius: 32rpx !important
background: #3088FF !important
margin-right: 16rpx
.reset-box-btn
border-radius: 32rpx !important
background: #02B44D
color: #fff
.con-box
background: #fff
padding: 20rpx
box-shadow: 0px 0px 6rpx 0px rgba(0,71,200,0.16)
border-radius: 24rpx
border: 1rpx solid #EDF5FF
margin-top: 30rpx
.form-title
display: flex
align-items: center
.form-name
font-weight: bold
font-size: 30rpx
color: #595959
margin-right:16rpx
.form-type
border-radius: 8rpx;
border: 2rpx solid #FF7D26;
font-size: 24rpx
color: #F1690E
padding: 4rpx 10rpx
.form-item
display: flex
align-items: center
justify-content: space-between
margin-top: 30rpx
.item-left
display: flex
align-items: center
.item-img
width: 26rpx
height: 26rpx
margin-right: 10rpx
.item-label
font-size: 26rpx
color: #B3B3B3
width: 190rpx
.item-right
font-size: 26rpx
color: #737373
// overflow: hidden
// text-overflow: ellipsis
// white-space: nowrap
word-wrap: break-word
overflow-wrap: break-word
white-space: normal
.form-btns
margin-top:30rpx
.form-box-btn
border-radius: 50rpx !important
margin-right: 24rpx
padding: 0rpx 40rpx
.detail-btn
background: #EDF5FF
border: 1px solid #3088FF
font-size: 28rpx
color: #3088FF
.follow-btn
background: #EEF9F3
border: 1px solid #00933E
font-size: 28rpx
color: #00933E
.recommend-btn
background: linear-gradient(92deg, #0DCCFF 0%, #4760FF 100%)
font-size: 28rpx
color: #FFFFFF
.button-group
position: fixed
bottom: 0
left: 0
width: 100%
height: 120rpx
background: #fff
.btns
height: 120rpx
width: 100%
line-height: 120px
display: flex
align-items: center
justify-content: space-between
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1)
.btn {
width: 45%;
height: 80rpx;
font-size: 30rpx;
border-radius: 8rpx;
}
.reset-btn {
background-color: #D8E9FF;
color: #1176FF;
}
.submit-btn {
background-color: #368BFF;
color: white;
}
</style>

View File

@@ -0,0 +1,266 @@
<template>
<AppLayout :title="title" :show-bg-image="false" >
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>创建任务</text>
<view class="title-line"></view>
</view>
</view>
<view class="form-container">
<uni-forms ref="formRef" v-model="formData" :rules="rules" validate-trigger="submit" >
<uni-forms-item label="任务名称:" name="taskName" required >
<uni-easyinput v-model="formData.taskName" placeholder="请输入任务名称"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="任务类型:" name="taskType" required >
<uni-data-select v-model="formData.taskType" placeholder="请选择任务类型" :localdata="taskTypeOptions" @change="taskTypeChange"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="优先级:" name="priority" required >
<uni-data-select v-model="formData.priority" placeholder="请选择优先级" :localdata="priorityOptions" @change="priorityChange"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="目标人员:" required >
<button class="choice-btn">从帮扶人员库选择目标人员</button>
</uni-forms-item>
<uni-forms-item label="目标人数:" name="goalPersonCount" required>
<uni-easyinput v-model="formData.taskAllocation.goalPersonCount" ></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="执行区域:" name="executeDeptId" required >
<uni-data-select v-model="formData.taskAllocation.executeDeptId" placeholder="请选择执行区域" :localdata="executeDeptOptions" @change="executeDeptChange"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="截止时间:" name="deadline" required>
<uni-datetime-picker class="picker-value" type="date" placeholder="请选择截止时间" v-model="formData.taskAllocation.deadline" @change="onDateChange" />
</uni-forms-item>
<uni-forms-item label="分配说明:" name="allocationNote" >
<uni-easyinput type="textarea" v-model="formData.taskAllocation.allocationNote" placeholder="请输入分配说明"></uni-easyinput>
</uni-forms-item>
</uni-forms>
<!-- 按钮组 -->
<view class="button-group">
<button class="btn submit-btn" @click="handleSubmit">确定</button>
<button class="btn reset-btn" @click="handleCancel">取消</button>
</view>
</view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
const props = defineProps({
taskTypeOptions: {
type: Array,
required: true,
default: () => []
},
priorityOptions:{
type: Array,
required: true,
default: () => []
},
executeDeptOptions:{
type: Array,
required: true,
default: () => []
},
})
const title = ref('');
const formData = reactive({
taskName: '',
taskType: '',
priority: '',
taskAllocation: {
goalPersonCount: null,
executeDeptId: '',
executeDeptName: '',
executeDeptAncestors: '',
allocationStatus: '1',
allocationNote: '',
deadline: null,
goalPersonList: []
}
})
// 表单引用
const formRef = ref(null)
// 校验规则
const rules = {
taskName: {
rules: [{
required: true,
errorMessage: '请填写任务名称'
}]
},
taskType: {
rules: [{
required: true,
errorMessage: '请选择任务类型'
}]
},
priority: {
rules: [{
required: true,
errorMessage: '请选择优先级'
}]
},
goalPersonCount: {
rules: [{
required: true,
errorMessage: '请选择目标人员'
}]
},
executeDeptId: {
rules: [{
required: true,
errorMessage: '请选择执行区域'
}]
},
deadline:{
rules: [{
required: true,
errorMessage: '请选择截止时间'
}]
},
}
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const emit = defineEmits(['update:showView'])
// 事件处理
function onDateChange(){}
function taskTypeChange(){}
function priorityChange(){}
function executeDeptChange(){}
const handleSubmit = () => {
formRef.value?.validate()
.then(() => {
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token')
}
$api.myRequest('/dispatch/assist/records/addRecords', formData,'post',9100,header).then((resData) => {
console.log("resData",resData)
if(resData && resData.code == 200){
handleReset()
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
}else{
uni.showToast({
title: resData.msg,
icon: 'none',
duration: 2000
});
}
});
})
.catch((errors) => {
console.log('校验失败:', errors);
});
};
const handleCancel = () => {
formData.taskName=''
formData.taskType=''
formData.priority=''
formData.taskAllocation.goalPersonCount=null
formData.taskAllocation.executeDeptId=''
formData.taskAllocation.executeDeptName=''
formData.taskAllocation.executeDeptAncestors=''
formData.taskAllocation.allocationStatus='1'
formData.taskAllocation.allocationNote=''
formData.taskAllocation.deadline=null
formData.taskAllocation.goalPersonList=[]
emit('update:showView', 'main')
}
onLoad((options) => {});
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.main-list
background-color: #ffffff
padding: 20rpx 20rpx 28rpx 20rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 70rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.input,
.picker
flex: 1
.picker-value
color: #666
.form-container
margin-top: 30rpx
:deep(.uni-forms-item__label)
width: 194rpx !important
font-size: 28rpx;
color: #404040;
.button-group {
display: flex;
justify-content: space-between;
padding: 40rpx 20rpx 20rpx;
}
.btn {
width: 45%;
height: 80rpx;
font-size: 30rpx;
border-radius: 8rpx;
}
.reset-btn {
background-color: #D8E9FF;
color: #1176FF;
}
.submit-btn {
background-color: #368BFF;
color: white;
}
.choice-btn{
width: 100%;
height: 70rpx;
font-size: 28rpx;
border-radius: 8rpx;
background-color: #368BFF;
color: white;
margin-left: 0;
}
:deep(.uni-easyinput__content)
background: rgba(0,0,0,0) !important
</style>

View File

@@ -0,0 +1,293 @@
<template>
<AppLayout :title="title" :show-bg-image="false" >
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>帮扶任务详情</text>
<view class="title-line"></view>
</view>
</view>
<view class="form-container">
<view class="form-item">
<view class="item-label">
任务名称
</view>
<view class="item-value">
{{formData.taskName}}
</view>
</view>
<view class="form-item">
<view class="item-label">
任务类型
</view>
<view class="item-value">
<!-- {{getabelByValue(formData.value.taskType,props.taskTypeOptions)}} -->
{{formData.taskType}}
</view>
</view>
<view class="form-item">
<view class="item-label">
优先级
</view>
<view class="item-value">
{{formData.priority}}
</view>
</view>
<view class="form-item">
<view class="item-label">
目标人数
</view>
<view class="item-value">
{{formData.taskAllocation.goalPersonCount}}
</view>
</view>
<view class="form-item">
<view class="item-label">
分配区域
</view>
<view class="item-value">
{{formData.taskAllocation.executeDeptName}}
</view>
</view>
<view class="form-item">
<view class="item-label">
创建时间
</view>
<view class="item-value">
{{formData.createTime}}
</view>
</view>
<view class="form-item">
<view class="item-label">
截止时间
</view>
<view class="item-value">
{{formData.taskAllocation.deadline}}
</view>
</view>
<view class="form-item">
<view class="item-label">
分配状态
</view>
<view class="item-value">
{{formData.allocationStatus}}
</view>
</view>
<view class="form-item">
<view class="item-label">
分配说明
</view>
<view class="item-value">
{{formData.taskAllocation.allocationNote?formData.taskAllocation.allocationNote:'暂无'}}
</view>
</view>
<!-- 按钮组 -->
<view class="button-group">
<button class="btn submit-btn" @click="handleCancel">关闭</button>
</view>
</view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive,onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
const props = defineProps({
taskTypeOptions: {
type: Array,
required: true,
default: () => []
},
priorityOptions:{
type: Array,
required: true,
default: () => []
},
executeDeptOptions:{
type: Array,
required: true,
default: () => []
},
allocationStatusOptions:{
type: Array,
required: true,
default: () => []
},
currentItem:{
type: String,
required: true,
default: ''
},
})
const title = ref('');
const formData = reactive({
taskName: '',
taskType: '',
priority: '',
createTime:'',
allocationStatus:'',
taskAllocation: {
goalPersonCount: null,
executeDeptId: '',
executeDeptName: '',
executeDeptAncestors: '',
allocationStatus: '1',
allocationNote: '',
deadline: null,
goalPersonList: []
}
})
// 表单引用
const formRef = ref(null)
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const emit = defineEmits(['update:showView'])
// 事件处理
function onDateChange(){}
function taskTypeChange(){}
function priorityChange(){}
function executeDeptChange(){}
const handleCancel = () => {
emit('update:showView', 'main')
}
function getDetail(){
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={
id:props.currentItem
}
$api.myRequest('/dispatch/assist/task/getTask',params,'get',9100,header).then((resData) => {
resData.data.taskType=getabelByValue(resData.data.taskType,props.taskTypeOptions)
resData.data.priority=getabelByValue(resData.data.priority,props.priorityOptions)
let allocationStatus=resData.data.taskAllocation.allocationStatus
resData.data.allocationStatus=getabelByValue(allocationStatus,props.allocationStatusOptions)
Object.assign(formData, resData.data)
});
}
function getabelByValue(value,arr) {
if (!Array.isArray(arr)) {
return ''
}
const item = arr.find(item => item.value === String(value))
return item ? item.text : '暂无'
}
onMounted(() => {
getDetail()
});
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.main-list
background-color: #ffffff
padding: 20rpx 20rpx 28rpx 20rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 70rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.input,
.picker
flex: 1
.picker-value
color: #666
.form-container
margin-top: 30rpx
.form-item
display: flex
align-items: center
margin-bottom: 20rpx
.item-label
width:200rpx
text-align: left
font-size: 30rpx
color: #606266
height: 72rpx
padding: 0 24rpx 0 0
vertical-align: middle
flex-shrink: 0
box-sizing: border-box
.item-value
color: #333
font-size: 30rpx
height: 72rpx
padding: 0 24rpx 0 0
vertical-align: middle
flex-shrink: 0
box-sizing: border-box
:deep(.uni-forms-item__label)
width: 194rpx !important
font-size: 28rpx;
color: #404040;
.button-group {
display: flex;
justify-content: space-between;
padding: 40rpx 20rpx 20rpx;
}
.btn {
width: 45%;
height: 80rpx;
font-size: 30rpx;
border-radius: 8rpx;
}
.reset-btn {
background-color: #D8E9FF;
color: #1176FF;
}
.submit-btn {
background-color: #368BFF;
color: white;
}
.choice-btn{
width: 100%;
height: 70rpx;
font-size: 28rpx;
border-radius: 8rpx;
background-color: #368BFF;
color: white;
margin-left: 0;
}
:deep(.uni-easyinput__content)
background: rgba(0,0,0,0) !important
</style>

View File

@@ -241,7 +241,7 @@ onLoad(() => {
getDataList('refresh');
});
}else{
navTo('/packageB/login2');
navTo('/packageB/login2?jump=/packageB/priority/helpFilter');
}
});
function getDictionary(){

192
packageB/priority/index.vue Normal file
View File

@@ -0,0 +1,192 @@
<template>
<!-- <AppLayout title=""> -->
<view class="tab-container">
<image src="/packageB/static/images/train/bj.jpg" mode=""></image>
<view>
<view class="btns" @click="jumps('/packageB/priority/taskAssignment')">
<image src="/packageB/static/images/train/zxxl-k.png" mode=""></image>
<view>
<text>帮扶任务分配</text>
<view class="btn">
<text>立即查看</text>
<image src="/packageB/static/images/train/arrow.png" mode=""></image>
</view>
</view>
</view>
<view class="btns" @click="jumps('/packageB/priority/taskIssue')">
<image src="/packageB/static/images/train/mnks-k.png" mode=""></image>
<view>
<text>帮扶任务下发</text>
<view class="btn">
<text>立即查看</text>
<image src="/packageB/static/images/train/arrow.png" mode=""></image>
</view>
</view>
</view>
<view class="btns" @click="jumps('/packageB/priority/recordsManagement')">
<image src="/packageB/static/images/train/ctb-k.png" mode=""></image>
<view>
<text>帮扶记录管理 </text>
<view class="btn" style="margin-left: 13%;">
<text>立即查看</text>
<image src="/packageB/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';
import CryptoJS from 'crypto-js'
onLoad(() => {
// thirdLogin()
});
async function jumps(url){
let token=uni.getStorageSync('Padmin-Token')
if(token){
navTo(url);
}else{
uni.showToast({
title:'请先登录'
})
setTimeout(() => {
navTo('/packageB/login2?jump='+url);
}, 2000)
}
}
async function thirdLogin(){
let form={}
if (uni.getStorageSync('userInfo').isCompanyUser=='1' || uni.getStorageSync('userInfo').isCompanyUser=='2') {
form={
usertype: '1',
idno: uni.getStorageSync('userInfo').idCard,
name: uni.getStorageSync('userInfo').name,
enterprisecode:"",
enterprisename: "",
contactperson: "",
contactphone: "",
}
let key = '9zS+DFKrzxvosO82mTcPJQ=='
let secretKey = CryptoJS.enc.Utf8.parse(key);//key 为你的秘钥
let srcs = CryptoJS.enc.Utf8.parse(form.idno);
let encrypted = CryptoJS.AES.encrypt(srcs, secretKey, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7}).toString()
form.idno=encrypted
}else if (uni.getStorageSync('userInfo').isCompanyUser=='0') {
form={
usertype: "2",
enterprisecode: uni.getStorageSync('userInfo').idCard,
enterprisename: uni.getStorageSync('userInfo').name,
contactperson: "",
contactphone: "",
idno: "",
name: ""
}
}else{
uni.showToast({
icon: 'none',
title: '请先登录'
})
return false;
}
var resLogin = await $api.myRequest('/auth/login2/ks',form,'post',10100);
if (resLogin.code=='200') {
uni.setStorageSync('Padmin-Token', resLogin.data.access_token)
return true;
}else{
uni.showToast({
icon: 'none',
title: '单点异常'
})
return false;
}
}
</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>

View File

@@ -0,0 +1,526 @@
<template>
<AppLayout :title="title" :show-bg-image="false" @onScrollBottom="getDataList('add')">
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>筛选条件</text>
<view class="title-line"></view>
</view>
<view class="title-right button-sp-area">
<button class="mini-btn search-box-btn" type="primary" size="mini" @click="handleSearch">查询</button>
<button class="mini-btn reset-box-btn" type="default" size="mini" @click="handleReset">重置</button>
</view>
</view>
<view class="search-container">
<!-- 人员姓名 -->
<view class="search-item">
<text class="label">人员姓名</text>
<uni-easyinput v-model="formData.name" placeholder="请输入人员姓名"></uni-easyinput>
</view>
<!-- 身份证号 -->
<view class="search-item">
<text class="label">身份证号</text>
<uni-easyinput v-model="formData.idCard" placeholder="请输入身份证号"></uni-easyinput>
</view>
<!-- 帮扶类型下拉选择 -->
<view class="search-item">
<text class="label">帮扶类型</text>
<uni-data-select v-model="formData.taskType" :localdata="taskTypeOptions" placeholder="请选择帮扶类型" @change="onTaskTypeChange"></uni-data-select>
</view>
<!-- 帮扶人员 -->
<view class="search-item">
<text class="label">帮扶人员</text>
<uni-easyinput v-model="formData.createByName" placeholder="请输入帮扶人员姓名"></uni-easyinput>
</view>
<!-- 所属区域下拉选择 -->
<view class="search-item">
<text class="label">所属区域</text>
<uni-data-picker ref="picker" class="picker" placeholder="请选择所属区域" popup-title="请选择所属区域" :localdata="regions" v-model="formData.deptTags"
@change="onchange" >
</uni-data-picker>
</view>
<!-- 开始时间 -->
<view class="search-item" v-if="false">
<text class="label">开始时间</text>
<uni-datetime-picker type="date" placeholder="请选择开始时间" v-model="formData.startTime" @maskClick="onStartTimeChange" />
</view>
<!-- 结束时间 -->
<view class="search-item" v-if="false">
<text class="label">结束时间</text>
<uni-datetime-picker type="date" placeholder="请选择结束时间" v-model="formData.endTime" @maskClick="onEndTimeChange" />
</view>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>帮扶记录列表</text>
<view class="title-line" style="left: 70rpx;"></view>
</view>
<view class="title-total">
<text class="total-num">{{totalNum}}</text>条记录
</view>
</view>
<view class="list-box" v-if="dataList.length>0">
<view class="con-box" v-for="(item,index) in dataList" :key="index">
<view class="form-title">
<view class="form-name">
{{item.name}}
</view>
<view class="form-type">
{{getTaskTypeLabelByValue(item.task_type)}}
</view>
</view>
<view class="form-item" v-if="item.phone">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/tele.png'" mode=""></image>
<view class="item-label">
联系电话
</view>
</view>
<view class="item-right">
{{item.phone}}
</view>
</view>
<view class="form-item" v-if="item.id_card">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
身份证号
</view>
</view>
<view class="item-right">
{{item.id_card}}
</view>
</view>
<view class="form-item" v-if="item.dept_name">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/base.png'" mode=""></image>
<view class="item-label">
所属区域
</view>
</view>
<view class="item-right">
{{item.dept_name}}
</view>
</view>
<view class="form-item" v-if="item.create_by_name">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/person.png'" mode=""></image>
<view class="item-label">
帮扶人员
</view>
</view>
<view class="item-right">
{{item.create_by_name}}
</view>
</view>
<view class="form-item" v-if="item.create_by_dept_name">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/help.png'" mode=""></image>
<view class="item-label">
帮扶单位
</view>
</view>
<view class="item-right">
{{item.create_by_dept_name}}
</view>
</view>
<view class="form-item" v-if="item.follow_date">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
帮扶日期
</view>
</view>
<view class="item-right">
{{item.follow_date}}
</view>
</view>
<view class="form-item" v-if="item.next_contact_date">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
下次联系
</view>
</view>
<view class="item-right">
{{item.next_contact_date}}
</view>
</view>
<view class="form-btns">
<button class="mini-btn form-box-btn detail-btn" size="mini" v-if="false">详情</button>
<button class="mini-btn form-box-btn follow-btn" size="mini" @click="goFollow(item)">跟进</button>
<button class="mini-btn form-box-btn recommend-btn" size="mini" @click="goRecommend(item)">智能推荐</button>
</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive,onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
// state
const title = ref('');
const initialForm = {
name: '',
idCard: '',
taskType: '',
createByName: '',
// helpArea: [],
// startTime: '',
// endTime: '',
// deptId:'',
deptTags:''
}
const formData = reactive({ ...initialForm });
const taskTypeOptions=ref([])
const dataList=ref([])
const pageSize=ref(10)
const pageNum=ref(1)
const totalNum=ref(0)
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const trainVideoImgUrl=config.trainVideoImgUrl
const picker = ref(null)
// 所属区域选项(可根据实际替换为动态数据)
const regions = ref([])
// 事件处理
const onTaskTypeChange = (e) => {
formData.taskType=e
}
const onStartTimeChange = (e) => {
formData.startTime = e.detail.value
}
const onEndTimeChange = (e) => {
formData.endTime = e.detail.value
}
const handleSearch = () => {
// 在这里调用接口进行搜索
getDataList('refresh')
}
const handleReset = () =>{
Object.assign(formData, initialForm);
getDataList('refresh')
}
onMounted(async () => {
// await loadLevelData('201');
});
onLoad(() => {
// let token=uni.getStorageSync('fourLevelLinkage-token')
// if(token){
// $api.myRequest("/system/user/login/user/info", {}, "GET", 9100, {
// Authorization: `Bearer ${uni.getStorageSync("fourLevelLinkage-token")}`
// }).then(async (resData) => {
// await loadLevelData(resData.sysUser.dept.deptId);
// getDictionary()
// getDataList('refresh');
// });
// }else{
// navTo('/packageB/login2');
// }
});
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/assist_task_type').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
taskTypeOptions.value.push(obj)
})
}
});
}
function getTaskTypeLabelByValue(value) {
if (!Array.isArray(taskTypeOptions.value)) {
return ''
}
const item = taskTypeOptions.value.find(item => item.value === String(value))
return item ? item.text : '暂无帮扶类型'
}
// 加载某一级的数据parentId 为空表示根)
async function loadLevelData(parentId,node) {
let header = {
'Authorization': uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
};
let params = { parentId };
try {
const resData = await $api.myRequest('/dispatch/dept/list', params, 'get', 9100, header);
if(resData.data.length==0){
picker.value.hide()
return
}
const formatted = (resData.data || []).map(item => ({
text: item.deptName,
value: item.tags,
deptId: item.deptId,
children: []
}));
if(node){
injectChildren(parentId, formatted);
}else{
regions.value=formatted
}
} catch (error) {
console.error("加载部门数据失败:", error);
uni.showToast({ title: '加载失败', icon: 'none' });
}
}
// 将子级数据注入到对应的父节点
function injectChildren(parentValue, childrenData) {
const findAndInject = (nodes) => {
for (let node of nodes) {
if (node.deptId === parentValue) {
// 如果 children 已存在且非空,避免重复加载
if (!node.children || node.children.length === 0) {
node.children = childrenData;
}
return true;
}
if (node.children && node.children.length > 0) {
if (findAndInject(node.children)) return true;
}
}
return false;
}
findAndInject(regions.value);
// 强制更新
}
// 当用户选择时触发注意change 在每级选择后都会触发)
function onchange(e) {
const selectedValues = e.detail.value;
// formData.deptId=selectedValues.map(item => item.value).join(',');
if (selectedValues.length === 0) return;
// 获取最后一级选中的 value
const lastSelectedValue = selectedValues[selectedValues.length - 1];
// 查找该节点是否有 children如果没有则尝试加载
const node = findNodeByValue(regions.value, lastSelectedValue);
if (node && (!node.children || node.children.length === 0)) {
// 检查接口是否还有下一级(可通过接口返回判断,或先尝试加载)
// 这里我们直接尝试加载下一级
loadLevelData(node.deptId , node);
picker.value.show()
}
}
// 工具函数:根据 value 查找节点
function findNodeByValue(nodes, value) {
for (let node of nodes) {
if (node.value === value.value) {
return node;
}
if (node.children && node.children.length > 0) {
const found = findNodeByValue(node.children, value);
if (found) return found;
}
}
return null;
}
function getDeptOptions(){
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={
parentId:''
}
$api.myRequest('/dispatch/dept/list', params,'get',9100,header).then((resData) => {
});
}
function getDataList(type = 'add') {
let maxPage=Math.ceil(totalNum.value/pageSize.value)
let params=({...formData})
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
}
if (type === 'refresh') {
pageNum.value = 1;
params.pageSize=pageSize.value
params.pageNum=pageNum.value
$api.myRequest('/dispatch/assist/records/pageRecords', params,'get',9100,header).then((resData) => {
if(resData&&resData.code == 200){
dataList.value=resData.rows
totalNum.value=resData.total
}
});
}
if (type === 'add' && pageNum.value < maxPage) {
pageNum.value += 1;
params.pageSize=pageSize.value
params.pageNum=pageNum.value
$api.myRequest('/dispatch/assist/records/pageRecords', params,'get',9100,header).then((resData) => {
dataList.value=dataList.value.concat(resData.rows)
});
}
}
function goFollow(item) {
navTo(`/packageB/priority/helpFollow?task_id=${item.task_id}&person_id=${item.person_id}&&name=${item.name}&&taskType=${getTaskTypeLabelByValue(item.task_type)}`);
}
//智能推荐
const goRecommend = (item) => {
navTo('/packageB/priority/recommend');
}
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.main-list
background-color: #ffffff
padding: 20rpx 30rpx 28rpx 30rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 36rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.search-box-btn
border-radius: 32rpx !important
background: #3088FF !important
margin-right: 16rpx
.reset-box-btn
border-radius: 32rpx !important
background: #02B44D
color: #fff
.search-container
padding: 20rpx 0rpx 0rpx 0rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.search-item
display: flex
align-items: center
margin-bottom: 30rpx
.label
width: 160rpx
font-size: 28rpx
color: #404040
flex-shrink: 0
.input,
.picker
background: #FFFFFF
flex: 1
min-width: 0
.list-box
margin-top: 40rpx
.con-box
background: #fff
padding: 20rpx
box-shadow: 0px 0px 6rpx 0px rgba(0,71,200,0.16)
border-radius: 24rpx
border: 1rpx solid #EDF5FF
margin-top: 30rpx
.form-title
display: flex
align-items: center
.form-name
font-weight: bold
font-size: 32rpx
color: #595959
margin-right:16rpx
.form-type
border-radius: 8rpx;
border: 2rpx solid #FF7D26;
font-size: 24rpx
color: #F1690E
padding: 4rpx 10rpx
.form-item
display: flex
align-items: center
justify-content: space-between
margin-top: 30rpx
.item-left
display: flex
align-items: center
.item-img
width: 26rpx
height: 26rpx
margin-right: 10rpx
.item-label
font-size: 26rpx
color: #B3B3B3
width: 130rpx
.item-right
font-size: 26rpx
color: #737373
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
.form-btns
margin-top:30rpx
.form-box-btn
border-radius: 50rpx !important
margin-right: 24rpx
padding: 0rpx 40rpx
.detail-btn
background: #EDF5FF
border: 1px solid #3088FF
font-size: 28rpx
color: #3088FF
.follow-btn
background: #EEF9F3
border: 1px solid #00933E
font-size: 28rpx
color: #00933E
.recommend-btn
background: linear-gradient(92deg, #0DCCFF 0%, #4760FF 100%)
font-size: 28rpx
color: #FFFFFF
</style>

View File

@@ -0,0 +1,573 @@
<template>
<AppLayout :title="title" :show-bg-image="false" >
<view class="page-container" v-if="showView=='main'">
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom" lower-threshold="50">
<view class="info-box">
<view class="info-item info-line">
<view class="">
<uni-icons type="contact" color="#175CE9" size="34"></uni-icons>
</view>
<view class="info-label">
帮扶任务总数
</view>
<view class="info-value">
{{ stats.taskCount }}
</view>
</view>
<view class="info-item info-line">
<view class="">
<uni-icons type="info" color="#175CE9" size="34"></uni-icons>
</view>
<view class="info-label">
待分配任务
</view>
<view class="info-value">
{{ stats.pendingCount }}
</view>
</view>
<view class="info-item">
<view class="">
<uni-icons type="checkbox" color="#175CE9" size="34"></uni-icons>
</view>
<view class="info-label">
已分配任务
</view>
<view class="info-value">
{{ stats.allocatedCount }}
</view>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>筛选条件</text>
<view class="title-line"></view>
</view>
<view class="title-right button-sp-area">
<button class="mini-btn search-box-btn" type="primary" size="mini" @click="handleSearch">查询</button>
<button class="mini-btn reset-box-btn" type="default" size="mini" @click="handleReset">重置</button>
</view>
</view>
<view class="search-container">
<!-- 人员姓名 -->
<view class="search-item">
<text class="label">任务名称</text>
<uni-easyinput v-model="formData.taskName" placeholder="请输入任务名称"></uni-easyinput>
</view>
<!-- 任务类型 -->
<view class="search-item">
<text class="label">任务类型</text>
<uni-data-select :key="1" v-model="formData.taskType" :localdata="taskTypeOptions" placeholder="请选择任务类型" @change="onTaskTypeChange"></uni-data-select>
</view>
<!-- 优先级 -->
<view class="search-item">
<text class="label">优先级</text>
<uni-data-select :key="2" v-model="formData.priority" :localdata="priorityOptions" placeholder="请选择优先级" @change="onPriorityChange"></uni-data-select>
</view>
<!-- 创建时间 -->
<view class="search-item">
<text class="label">创建时间</text>
<uni-datetime-picker v-model="filterTimeRange" type="datetimerange" rangeSeparator="至" @change="filterTimeRangeChange" />
</view>
<!-- 分配状态 -->
<view class="search-item">
<text class="label">分配状态</text>
<uni-data-select :key="3" v-model="formData.allocationStatus" :localdata="allocationStatusOptions" placeholder="请选择分配状态" @change="onAllocationStatusChange"></uni-data-select>
</view>
<!-- 执行区域 -->
<view class="search-item">
<text class="label">执行区域</text>
<uni-data-select :key="4" v-model="formData.executeDeptId" :localdata="executeDeptOptions" placeholder="请选择区域" @change="onExecuteDeptChange"></uni-data-select>
</view>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="">
<button class="mini-btn search-box-btn" type="primary" size="mini" @click="creatTask">创建任务</button>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>帮扶任务列表</text>
<view class="title-line" style="left: 70rpx;"></view>
</view>
<view class="title-total">
<text class="total-num">{{totalNum}}</text>条记录
</view>
</view>
<view class="list-box" v-if="dataList.length>0">
<view class="con-box" v-for="(item,index) in dataList" :key="index">
<view class="form-title">
<view class="form-name">
{{item.taskName}}
</view>
<view class="form-type">
优先级{{item.priority}}
</view>
</view>
<view class="form-item" >
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/person.png'" mode=""></image>
<view class="item-label">
目标人数
</view>
</view>
<view class="item-right">
{{item.taskAllocation.goalPersonCount}}
</view>
</view>
<view class="form-item">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
任务类型
</view>
</view>
<view class="item-right">
{{item.taskType}}
</view>
</view>
<view class="form-item" >
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
分配状态
</view>
</view>
<view class="item-right">
{{item.taskAllocation.allocationStatus}}
</view>
</view>
<view class="form-item" >
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/base.png'" mode=""></image>
<view class="item-label">
执行区域
</view>
</view>
<view class="item-right">
{{item.taskAllocation.executeDeptName}}
</view>
</view>
<view class="form-item" >
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
创建时间
</view>
</view>
<view class="item-right">
{{item.createTime}}
</view>
</view>
<view class="form-item" >
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
截止时间
</view>
</view>
<view class="item-right">
{{item.taskAllocation.deadline}}
</view>
</view>
<view class="form-btns">
<button class="mini-btn form-box-btn detail-btn" size="mini" @click="goDetail(item)">详情</button>
<button class="mini-btn form-box-btn follow-btn" size="mini" @click="goTarget(item)">目标人员</button>
<button class="mini-btn form-box-btn recommend-btn" size="mini" @click="goRecommend(item)">分配</button>
</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
</view>
</scroll-view>
</view>
<view class="" v-else-if="showView=='add'" >
<task-created :taskTypeOptions="taskTypeOptions" :priorityOptions="priorityOptions" :executeDeptOptions="executeDeptOptions" @update:show-view="handleShowViewChange"></task-created>
</view>
<view class="" v-else-if="showView=='detail'" >
<task-detail :currentItem="currentItem" :taskTypeOptions="taskTypeOptions" :priorityOptions="priorityOptions" :executeDeptOptions="executeDeptOptions" :allocationStatusOptions="allocationStatusOptions" @update:show-view="handleShowViewChange"></task-detail>
</view>
<view class="" v-else-if="showView=='targetPersonnel'" >
<target-personnel :currentItem="currentItem" :taskName="taskName" @update:show-view="handleShowViewChange"></target-personnel>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
import taskCreated from './components/taskCreated.vue';
import taskDetail from './components/taskDetail.vue';
import targetPersonnel from './components/targetPersonnel.vue';
const showView=ref('main')
const title = ref('');
const stats=ref({})
const formData = reactive({
taskName: '',
taskType: '',
priority: '',
createTimeStart: null,
createTimeEnd: null,
allocationStatus: '',
executeDeptId: '',
pageNum: 1,
pageSize: 10
})
const currentItem=ref('')
const taskName=ref('')
const filterTimeRange=ref([])
const totalNum=ref(0)
const dataList=ref([])
const taskTypeOptions=ref([])
const priorityOptions=ref([])
const allocationStatusOptions=ref([])
const executeDeptOptions=ref([])
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
function listNotParam(){
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={}
$api.myRequest('/dispatch/dept/listNotParam',params,'get',9100,header).then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.deptId,
text: item.deptName
}
executeDeptOptions.value.push(obj)
})
}
});
}
function statisticTask(){
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={}
$api.myRequest('/dispatch/assist/task/statisticTask',params,'get',9100,header).then((resData) => {
stats.value=resData.data
});
}
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/assist_task_type').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
taskTypeOptions.value.push(obj)
})
}
});
$api.myRequest('/system/public/dict/data/type/assist_task_priority').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
priorityOptions.value.push(obj)
})
}
});
$api.myRequest('/system/public/dict/data/type/assist_task_allocation_status').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
allocationStatusOptions.value.push(obj)
})
}
});
}
function getabelByValue(value,arr) {
if (!Array.isArray(arr.value)) {
return ''
}
const item = arr.value.find(item => item.value === String(value))
return item ? item.text : '暂无'
}
function onTaskTypeChange(e){
formData.taskType=e
}
function onPriorityChange(e){
formData.priority=e
}
function onAllocationStatusChange(e){
formData.allocationStatus=e
}
function filterTimeRangeChange(e){
formData.createTimeStart=e[0]
formData.createTimeEnd=e[1]
}
function onExecuteDeptChange(e){
formData.executeDeptId=e
}
function handleSearch(){
dataList.value=[]
getDataList()
}
function getDataList(){
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
$api.myRequest('/dispatch/assist/task/pageList',formData,'get',9100,header).then((resData) => {
resData.rows.forEach(item=>{
item.priority=getabelByValue(item.priority,priorityOptions)
item.taskType=getabelByValue(item.taskType,taskTypeOptions)
item.taskAllocation.allocationStatus=getabelByValue(item.taskAllocation.allocationStatus,allocationStatusOptions)
})
totalNum.value=resData.total
dataList.value=dataList.value.concat(resData.rows)
});
}
const handleReset = () => {
dataList.value=[]
formData.taskName=''
formData.taskType=''
formData.priority=''
formData.createTimeStart=null
formData.createTimeEnd=null
formData.allocationStatus=''
formData.executeDeptId=''
formData.pageNum=1
formData.pageSize=10
filterTimeRange.value=[]
getDataList()
}
function handleShowViewChange(newValue) {
showView.value = newValue
}
const creatTask = () => {
showView.value='add'
// navTo('/packageB/priority/taskCreated');
}
const goRecommend = () =>{
navTo('/packageB/priority/allocate');
}
function goDetail(item){
currentItem.value=item.id
showView.value='detail'
}
function goTarget(item){
currentItem.value=item.taskAllocation.id
taskName.value=item.taskName
showView.value='targetPersonnel'
}
function scrollBottom(){
if(formData.pageNum<totalNum.value/formData.pageSize){
formData.pageNum++
getDataList()
}
}
onLoad((options) => {
listNotParam()
statisticTask()
runAsyncTasks(options)
});
const runAsyncTasks = async (options) => {
await getDictionary()
await getDataList()
}
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.page-container {
display: flex;
flex-direction: column;
height: calc(100vh - var(--window-top)); /* 如果 AppLayout 有 header需减去 */
/* 或者简单用height: 100vh; */
}
.nearby-scroll
// 使用flex布局让scroll-view自适应高度占据剩余空间
flex: 1
// overflow: hidden;
.info-box
margin: 30rpx 30rpx
background: linear-gradient(0deg, #D9ECFF 0%, #F0F7FF 100%)
border-radius: 20rpx
padding: 40rpx 0
display: flex
align-items: center
.info-line
border-right: 2rpx solid #B7D6FF
.info-item
display: flex
flex-direction: column
align-items: center
justify-content: center
width: 50%
.info-label
font-size: 26rpx
color: #6E7E9B
margin-bottom: 20rpx
.info-value
font-weight: bold
font-size: 28rpx
color: #3D61AC
.main-list
background-color: #ffffff
padding: 20rpx 20rpx 28rpx 20rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 70rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.list-box
margin-top: 40rpx
:deep(.uni-forms-item__label)
width: 194rpx !important
font-size: 28rpx;
color: #404040;
.search-container
padding: 20rpx 0rpx 0rpx 0rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.search-item
display: flex
align-items: center
margin-bottom: 30rpx
.label
width: 160rpx
font-size: 28rpx
color: #404040
flex-shrink: 0
.input,
.picker
background: #FFFFFF
flex: 1
min-width: 0
.search-box-btn
border-radius: 32rpx !important
background: #3088FF !important
margin-right: 16rpx
.reset-box-btn
border-radius: 32rpx !important
background: #02B44D
color: #fff
.con-box
background: #fff
padding: 20rpx
box-shadow: 0px 0px 6rpx 0px rgba(0,71,200,0.16)
border-radius: 24rpx
border: 1rpx solid #EDF5FF
margin-top: 30rpx
.form-title
display: flex
align-items: center
.form-name
font-weight: bold
font-size: 32rpx
color: #595959
margin-right:16rpx
.form-type
border-radius: 8rpx;
border: 2rpx solid #FF7D26;
font-size: 24rpx
color: #F1690E
padding: 4rpx 10rpx
.form-item
display: flex
align-items: center
justify-content: space-between
margin-top: 30rpx
.item-left
display: flex
align-items: center
.item-img
width: 26rpx
height: 26rpx
margin-right: 10rpx
.item-label
font-size: 26rpx
color: #B3B3B3
width: 130rpx
.item-right
font-size: 26rpx
color: #737373
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
.form-btns
margin-top:30rpx
.form-box-btn
border-radius: 50rpx !important
margin-right: 24rpx
padding: 0rpx 40rpx
.detail-btn
background: #EDF5FF
border: 1px solid #3088FF
font-size: 28rpx
color: #3088FF
.follow-btn
background: #EEF9F3
border: 1px solid #00933E
font-size: 28rpx
color: #00933E
.recommend-btn
background: linear-gradient(92deg, #0DCCFF 0%, #4760FF 100%)
font-size: 28rpx
color: #FFFFFF
</style>

View File

@@ -0,0 +1,526 @@
<template>
<AppLayout :title="title" :show-bg-image="false" @onScrollBottom="getDataList('add')">
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>筛选条件</text>
<view class="title-line"></view>
</view>
<view class="title-right button-sp-area">
<button class="mini-btn search-box-btn" type="primary" size="mini" @click="handleSearch">查询</button>
<button class="mini-btn reset-box-btn" type="default" size="mini" @click="handleReset">重置</button>
</view>
</view>
<view class="search-container">
<!-- 人员姓名 -->
<view class="search-item">
<text class="label">人员姓名</text>
<uni-easyinput v-model="formData.name" placeholder="请输入人员姓名"></uni-easyinput>
</view>
<!-- 身份证号 -->
<view class="search-item">
<text class="label">身份证号</text>
<uni-easyinput v-model="formData.idCard" placeholder="请输入身份证号"></uni-easyinput>
</view>
<!-- 帮扶类型下拉选择 -->
<view class="search-item">
<text class="label">帮扶类型</text>
<uni-data-select v-model="formData.taskType" :localdata="taskTypeOptions" placeholder="请选择帮扶类型" @change="onTaskTypeChange"></uni-data-select>
</view>
<!-- 帮扶人员 -->
<view class="search-item">
<text class="label">帮扶人员</text>
<uni-easyinput v-model="formData.createByName" placeholder="请输入帮扶人员姓名"></uni-easyinput>
</view>
<!-- 所属区域下拉选择 -->
<view class="search-item">
<text class="label">所属区域</text>
<uni-data-picker ref="picker" class="picker" placeholder="请选择所属区域" popup-title="请选择所属区域" :localdata="regions" v-model="formData.deptTags"
@change="onchange" >
</uni-data-picker>
</view>
<!-- 开始时间 -->
<view class="search-item" v-if="false">
<text class="label">开始时间</text>
<uni-datetime-picker type="date" placeholder="请选择开始时间" v-model="formData.startTime" @maskClick="onStartTimeChange" />
</view>
<!-- 结束时间 -->
<view class="search-item" v-if="false">
<text class="label">结束时间</text>
<uni-datetime-picker type="date" placeholder="请选择结束时间" v-model="formData.endTime" @maskClick="onEndTimeChange" />
</view>
</view>
</view>
<view class="main-list" :style="getBackgroundStyle('k.png')">
<view class="list-top">
<view class="list-title">
<text>帮扶记录列表</text>
<view class="title-line" style="left: 70rpx;"></view>
</view>
<view class="title-total">
<text class="total-num">{{totalNum}}</text>条记录
</view>
</view>
<view class="list-box" v-if="dataList.length>0">
<view class="con-box" v-for="(item,index) in dataList" :key="index">
<view class="form-title">
<view class="form-name">
{{item.name}}
</view>
<view class="form-type">
{{getTaskTypeLabelByValue(item.task_type)}}
</view>
</view>
<view class="form-item" v-if="item.phone">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/tele.png'" mode=""></image>
<view class="item-label">
联系电话
</view>
</view>
<view class="item-right">
{{item.phone}}
</view>
</view>
<view class="form-item" v-if="item.id_card">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/num.png'" mode=""></image>
<view class="item-label">
身份证号
</view>
</view>
<view class="item-right">
{{item.id_card}}
</view>
</view>
<view class="form-item" v-if="item.dept_name">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/base.png'" mode=""></image>
<view class="item-label">
所属区域
</view>
</view>
<view class="item-right">
{{item.dept_name}}
</view>
</view>
<view class="form-item" v-if="item.create_by_name">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/person.png'" mode=""></image>
<view class="item-label">
帮扶人员
</view>
</view>
<view class="item-right">
{{item.create_by_name}}
</view>
</view>
<view class="form-item" v-if="item.create_by_dept_name">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/help.png'" mode=""></image>
<view class="item-label">
帮扶单位
</view>
</view>
<view class="item-right">
{{item.create_by_dept_name}}
</view>
</view>
<view class="form-item" v-if="item.follow_date">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/date.png'" mode=""></image>
<view class="item-label">
帮扶日期
</view>
</view>
<view class="item-right">
{{item.follow_date}}
</view>
</view>
<view class="form-item" v-if="item.next_contact_date">
<view class="item-left">
<image class="item-img" :src="baseUrl+'/dispatch/next.png'" mode=""></image>
<view class="item-label">
下次联系
</view>
</view>
<view class="item-right">
{{item.next_contact_date}}
</view>
</view>
<view class="form-btns">
<button class="mini-btn form-box-btn detail-btn" size="mini" v-if="false">详情</button>
<button class="mini-btn form-box-btn follow-btn" size="mini" @click="goFollow(item)">跟进</button>
<button class="mini-btn form-box-btn recommend-btn" size="mini" @click="goRecommend(item)">智能推荐</button>
</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref, reactive,onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
// state
const title = ref('');
const initialForm = {
name: '',
idCard: '',
taskType: '',
createByName: '',
// helpArea: [],
// startTime: '',
// endTime: '',
// deptId:'',
deptTags:''
}
const formData = reactive({ ...initialForm });
const taskTypeOptions=ref([])
const dataList=ref([])
const pageSize=ref(10)
const pageNum=ref(1)
const totalNum=ref(0)
const baseUrl = config.imgBaseUrl
const getBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/dispatch/${imageName})`,
backgroundSize: 'cover', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const trainVideoImgUrl=config.trainVideoImgUrl
const picker = ref(null)
// 所属区域选项(可根据实际替换为动态数据)
const regions = ref([])
// 事件处理
const onTaskTypeChange = (e) => {
formData.taskType=e
}
const onStartTimeChange = (e) => {
formData.startTime = e.detail.value
}
const onEndTimeChange = (e) => {
formData.endTime = e.detail.value
}
const handleSearch = () => {
// 在这里调用接口进行搜索
getDataList('refresh')
}
const handleReset = () =>{
Object.assign(formData, initialForm);
getDataList('refresh')
}
onMounted(async () => {
// await loadLevelData('201');
});
onLoad(() => {
// let token=uni.getStorageSync('fourLevelLinkage-token')
// if(token){
// $api.myRequest("/system/user/login/user/info", {}, "GET", 9100, {
// Authorization: `Bearer ${uni.getStorageSync("fourLevelLinkage-token")}`
// }).then(async (resData) => {
// await loadLevelData(resData.sysUser.dept.deptId);
// getDictionary()
// getDataList('refresh');
// });
// }else{
// navTo('/packageB/login2');
// }
});
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/assist_task_type').then((resData) => {
if(resData && resData.code == 200){
resData.data.forEach(item=>{
const obj = {
value: item.dictValue,
text: item.dictLabel
}
taskTypeOptions.value.push(obj)
})
}
});
}
function getTaskTypeLabelByValue(value) {
if (!Array.isArray(taskTypeOptions.value)) {
return ''
}
const item = taskTypeOptions.value.find(item => item.value === String(value))
return item ? item.text : '暂无帮扶类型'
}
// 加载某一级的数据parentId 为空表示根)
async function loadLevelData(parentId,node) {
let header = {
'Authorization': uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
};
let params = { parentId };
try {
const resData = await $api.myRequest('/dispatch/dept/list', params, 'get', 9100, header);
if(resData.data.length==0){
picker.value.hide()
return
}
const formatted = (resData.data || []).map(item => ({
text: item.deptName,
value: item.tags,
deptId: item.deptId,
children: []
}));
if(node){
injectChildren(parentId, formatted);
}else{
regions.value=formatted
}
} catch (error) {
console.error("加载部门数据失败:", error);
uni.showToast({ title: '加载失败', icon: 'none' });
}
}
// 将子级数据注入到对应的父节点
function injectChildren(parentValue, childrenData) {
const findAndInject = (nodes) => {
for (let node of nodes) {
if (node.deptId === parentValue) {
// 如果 children 已存在且非空,避免重复加载
if (!node.children || node.children.length === 0) {
node.children = childrenData;
}
return true;
}
if (node.children && node.children.length > 0) {
if (findAndInject(node.children)) return true;
}
}
return false;
}
findAndInject(regions.value);
// 强制更新
}
// 当用户选择时触发注意change 在每级选择后都会触发)
function onchange(e) {
const selectedValues = e.detail.value;
// formData.deptId=selectedValues.map(item => item.value).join(',');
if (selectedValues.length === 0) return;
// 获取最后一级选中的 value
const lastSelectedValue = selectedValues[selectedValues.length - 1];
// 查找该节点是否有 children如果没有则尝试加载
const node = findNodeByValue(regions.value, lastSelectedValue);
if (node && (!node.children || node.children.length === 0)) {
// 检查接口是否还有下一级(可通过接口返回判断,或先尝试加载)
// 这里我们直接尝试加载下一级
loadLevelData(node.deptId , node);
picker.value.show()
}
}
// 工具函数:根据 value 查找节点
function findNodeByValue(nodes, value) {
for (let node of nodes) {
if (node.value === value.value) {
return node;
}
if (node.children && node.children.length > 0) {
const found = findNodeByValue(node.children, value);
if (found) return found;
}
}
return null;
}
function getDeptOptions(){
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={
parentId:''
}
$api.myRequest('/dispatch/dept/list', params,'get',9100,header).then((resData) => {
});
}
function getDataList(type = 'add') {
let maxPage=Math.ceil(totalNum.value/pageSize.value)
let params=({...formData})
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
}
if (type === 'refresh') {
pageNum.value = 1;
params.pageSize=pageSize.value
params.pageNum=pageNum.value
$api.myRequest('/dispatch/assist/records/pageRecords', params,'get',9100,header).then((resData) => {
if(resData&&resData.code == 200){
dataList.value=resData.rows
totalNum.value=resData.total
}
});
}
if (type === 'add' && pageNum.value < maxPage) {
pageNum.value += 1;
params.pageSize=pageSize.value
params.pageNum=pageNum.value
$api.myRequest('/dispatch/assist/records/pageRecords', params,'get',9100,header).then((resData) => {
dataList.value=dataList.value.concat(resData.rows)
});
}
}
function goFollow(item) {
navTo(`/packageB/priority/helpFollow?task_id=${item.task_id}&person_id=${item.person_id}&&name=${item.name}&&taskType=${getTaskTypeLabelByValue(item.task_type)}`);
}
//智能推荐
const goRecommend = (item) => {
navTo('/packageB/priority/recommend');
}
</script>
<style lang="stylus" scoped>
image
height: 100%
width: 100%
.main-list
background-color: #ffffff
padding: 20rpx 30rpx 28rpx 30rpx
margin: 30rpx 30rpx
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1)
border-radius: 12px
.list-top
display: flex
align-items: center
justify-content: space-between
.list-title
font-weight: bold
font-size: 36rpx
color: #404040
position: relative
.title-line
position: absolute
bottom: -10rpx
left: 36rpx
width: 70rpx
height: 8rpx
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%)
border-radius: 4rpx
.search-box-btn
border-radius: 32rpx !important
background: #3088FF !important
margin-right: 16rpx
.reset-box-btn
border-radius: 32rpx !important
background: #02B44D
color: #fff
.search-container
padding: 20rpx 0rpx 0rpx 0rpx
.title-total
font-size: 24rpx
color: #999999
.total-num
color: #3088FF
margin-left: 4rpx
margin-right: 4rpx
font-weight: bold
font-size: 26rpx
.search-item
display: flex
align-items: center
margin-bottom: 30rpx
.label
width: 160rpx
font-size: 28rpx
color: #404040
flex-shrink: 0
.input,
.picker
background: #FFFFFF
flex: 1
min-width: 0
.list-box
margin-top: 40rpx
.con-box
background: #fff
padding: 20rpx
box-shadow: 0px 0px 6rpx 0px rgba(0,71,200,0.16)
border-radius: 24rpx
border: 1rpx solid #EDF5FF
margin-top: 30rpx
.form-title
display: flex
align-items: center
.form-name
font-weight: bold
font-size: 32rpx
color: #595959
margin-right:16rpx
.form-type
border-radius: 8rpx;
border: 2rpx solid #FF7D26;
font-size: 24rpx
color: #F1690E
padding: 4rpx 10rpx
.form-item
display: flex
align-items: center
justify-content: space-between
margin-top: 30rpx
.item-left
display: flex
align-items: center
.item-img
width: 26rpx
height: 26rpx
margin-right: 10rpx
.item-label
font-size: 26rpx
color: #B3B3B3
width: 130rpx
.item-right
font-size: 26rpx
color: #737373
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
.form-btns
margin-top:30rpx
.form-box-btn
border-radius: 50rpx !important
margin-right: 24rpx
padding: 0rpx 40rpx
.detail-btn
background: #EDF5FF
border: 1px solid #3088FF
font-size: 28rpx
color: #3088FF
.follow-btn
background: #EEF9F3
border: 1px solid #00933E
font-size: 28rpx
color: #00933E
.recommend-btn
background: linear-gradient(92deg, #0DCCFF 0%, #4760FF 100%)
font-size: 28rpx
color: #FFFFFF
</style>

View File

@@ -878,7 +878,7 @@ function navToService(serviceType) {
// 'skill-evaluation': '/pages/service/skill-evaluation',
"question-bank": "/pages/service/question-bank",
"quality-assessment": "/pages/service/quality-assessment",
"ai-interview": "/pages/chat/chat",
"ai-interview": "/packageA/pages/chat/chat",
"job-search": "/pages/search/search",
"career-planning": "/pages/service/career-planning",
"salary-query": "/pages/service/salary-query",

View File

@@ -36,15 +36,6 @@
"navigationBarTitleText": "搜索职位"
}
},
{
"path": "pages/chat/chat",
"style": {
"navigationBarTitleText": "智能客服",
"navigationBarBackgroundColor": "#4778EC",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": false
}
},
{
"path": "pages/service/career-planning",
"style": {
@@ -319,6 +310,27 @@
"navigationBarTitleText": "取消投递",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/agreement/user",
"style": {
"navigationBarTitleText": "隐私协议"
}
},
{
"path": "pages/agreement/privacy",
"style": {
"navigationBarTitleText": "隐私政策"
}
},
{
"path": "pages/chat/chat",
"style": {
"navigationBarTitleText": "智能客服",
"navigationBarBackgroundColor": "#4778EC",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": false
}
}
]
},
@@ -420,6 +432,36 @@
"style": {
"navigationBarTitleText": "推荐"
}
},
{
"path": "priority/index",
"style": {
"navigationBarTitleText": "帮扶任务"
}
},
{
"path": "priority/taskAssignment",
"style": {
"navigationBarTitleText": "帮扶任务分配"
}
},
{
"path": "priority/taskIssue",
"style": {
"navigationBarTitleText": "帮扶任务下发"
}
},
{
"path": "priority/recordsManagement",
"style": {
"navigationBarTitleText": "帮扶记录管理"
}
},
{
"path": "priority/allocate",
"style": {
"navigationBarTitleText": "任务分配"
}
},
{
"path": "train/wrongAnswer/mistakeNotebook",

View File

@@ -161,6 +161,12 @@
</view>
<view class="service-title">帮扶</view>
</view>
<view class="service-item press-button" v-if="isFourLevelLinkagePurview" @click="helpTaskClick">
<view class="service-icon service-icon-1">
<uni-icons type="shop" size="32" color="#FFFFFF"></uni-icons>
</view>
<view class="service-title">帮扶任务</view>
</view>
<view class="service-item press-button" @click="handleNoticeClick">
<view class="service-icon service-icon-10">
<uni-icons type="sound" size="32" color="#FFFFFF"></uni-icons>
@@ -299,7 +305,7 @@
>
<view v-for="(job, index) in list" :key="index" :slot="`slot${index}`">
<view class="item btn-feel" v-if="!job.recommend">
<view class="falls-card" @click="nextDetail(job)">
<view class="falls-card" :class="{ 'disabled-card': Number(job.jobStatus) === 1 }" @click="nextDetail(job)">
<view class="falls-card-pay">
<view class="pay-text">
<Salary-Expectation
@@ -344,6 +350,17 @@
{{ job.companyName }}
</view>
</view>
<!-- 招聘者显示上下架开关 -->
<view class="falls-card-actions" v-if="isRecruiter">
<view class="job-status-switch" @click.stop="toggleJobStatus(job)">
<view class="switch-track" :class="{ 'active': Number(job.jobStatus) === 0 }">
<view class="switch-thumb" :class="{ 'active': Number(job.jobStatus) === 0 }"></view>
</view>
<view class="switch-label">
{{ Number(job.jobStatus) === 0 ? '已上架' : '已下架' }}
</view>
</view>
</view>
<!-- <view class="falls-card-matchingrate">
<view class=""><matchingDegree :job="job"></matchingDegree></view>
<uni-icons type="star" size="30"></uni-icons>
@@ -376,7 +393,7 @@
>
<template v-slot:default="job">
<view class="item btn-feel" v-if="!job.recommend">
<view class="falls-card" @click="nextDetail(job)">
<view class="falls-card" :class="{ 'disabled-card': Number(job.jobStatus) === 1 }" @click="nextDetail(job)">
<view class="falls-card-pay">
<view class="pay-text">
<Salary-Expectation
@@ -421,6 +438,17 @@
{{ job.companyName }}
</view>
</view>
<!-- 招聘者显示上下架开关 -->
<view class="falls-card-actions" v-if="isRecruiter">
<view class="job-status-switch" @click.stop="toggleJobStatus(job)">
<view class="switch-track" :class="{ 'active': Number(job.jobStatus) === 0 }">
<view class="switch-thumb" :class="{ 'active': Number(job.jobStatus) === 0 }"></view>
</view>
<view class="switch-label">
{{ Number(job.jobStatus) === 0 ? '已上架' : '已下架' }}
</view>
</view>
</view>
<!-- <view class="falls-card-matchingrate">
<view class=""><matchingDegree :job="job"></matchingDegree></view>
<uni-icons type="star" size="30"></uni-icons>
@@ -550,6 +578,25 @@ const shouldShowCompanyContent = computed(() => {
return userType === 0;
});
// 判断当前用户是否为招聘者(企业用户)
const isRecruiter = 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, dictLabel: getDictLabel, industryLabel } = useDictStore();
import useLocationStore from '@/stores/useLocationStore';
@@ -656,6 +703,9 @@ const state = reactive({
const helpClick = () => {
navTo('/packageB/priority/helpFilter');
};
const helpTaskClick = () =>{
navTo('/packageB/priority/index');
}
//招聘会模块跳转
const handleJobFairClick = () => {
navTo('/pages/careerfair/careerfair');
@@ -680,7 +730,7 @@ const rangeOptions = ref([
{ value: 0, text: '推荐' },
{ value: 1, text: '最热' },
{ value: 2, text: '最新发布' },
{ value: 3, text: '疆外' },
// { value: 3, text: '疆外' },
{ value: 4, text: '零工市场' }
]);
const isLoaded = ref(false);
@@ -1015,7 +1065,7 @@ function navToService(serviceType) {
// 'skill-evaluation': '/pages/service/skill-evaluation',
'question-bank': '/pages/service/question-bank',
// 'quality-assessment': '/packageCa/search/search',
// 'ai-interview': '/pages/chat/chat',
// 'ai-interview': '/packageA/pages/chat/chat',
'job-search': '/pages/search/search',
'career-planning': '/pages/service/career-planning',
'salary-query': '/pages/service/salary-query',
@@ -1135,6 +1185,9 @@ function getJobRecommend(type = 'add') {
// 只有企业用户(isCompanyUser=0)才添加current字段
if (userType === 0) {
params.current = pageNull.value;
} else {
// 求职者只显示已上架的岗位jobStatus=0
params.jobStatus = 0;
}
let comd = { recommend: true, jobCategory: '', tip: '确认你的兴趣,为您推荐更多合适的岗位' };
$api.createRequest('/app/job/recommend', params).then((resData) => {
@@ -1209,6 +1262,18 @@ function getJobList(type = 'add') {
params.order = 0;
}
// 判断用户类型求职者只显示已上架的岗位jobStatus=0
// 优先从store获取如果为空则从缓存获取
const storeIsCompanyUser = userInfo.value?.isCompanyUser;
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
const cachedIsCompanyUser = cachedUserInfo.isCompanyUser;
const userType = storeIsCompanyUser !== undefined ? Number(storeIsCompanyUser) : Number(cachedIsCompanyUser);
// 如果不是企业用户(求职者),只显示已上架的岗位
if (userType !== 0) {
params.jobStatus = 0;
}
$api.createRequest('/app/job/list', params).then((resData) => {
const { rows, total } = resData;
if (type === 'add') {
@@ -1231,6 +1296,93 @@ function getJobList(type = 'add') {
}
});
}
// 上架岗位
const jobUp = (jobId) => {
if (!checkLogin()) return;
uni.showLoading({
title: '处理中...',
mask: true
});
$api.createRequest(`/app/job/jobUp/${jobId}`, {}, 'PUT', true).then((res) => {
uni.hideLoading();
$api.msg('上架成功');
// 刷新数据
if (state.tabIndex === 'all') {
getJobRecommend('refresh');
} else {
getJobList('refresh');
}
}).catch((err) => {
uni.hideLoading();
console.error('上架失败:', err);
$api.msg('上架失败,请重试');
});
};
// 下架岗位
const jobDown = (jobId) => {
if (!checkLogin()) return;
uni.showLoading({
title: '处理中...',
mask: true
});
$api.createRequest(`/app/job/jobDown/${jobId}`, {}, 'PUT', true).then((res) => {
uni.hideLoading();
$api.msg('下架成功');
// 刷新数据
if (state.tabIndex === 'all') {
getJobRecommend('refresh');
} else {
getJobList('refresh');
}
}).catch((err) => {
uni.hideLoading();
console.error('下架失败:', err);
$api.msg('下架失败,请重试');
});
};
// 切换岗位状态(上架/下架)
const toggleJobStatus = (job) => {
if (!checkLogin()) return;
uni.showLoading({
title: '处理中...',
mask: true
});
// 根据当前状态决定调用哪个接口
const isCurrentlyUp = Number(job.jobStatus) === 0; // 0: 已上架, 1: 已下架
const apiUrl = isCurrentlyUp ? `/app/job/jobDown/${job.jobId}` : `/app/job/jobUp/${job.jobId}`;
$api.createRequest(apiUrl, {}, 'PUT', true).then((res) => {
uni.hideLoading();
$api.msg(isCurrentlyUp ? '下架成功' : '上架成功');
// 更新本地数据状态,避免立即刷新整个列表
const jobIndex = list.value.findIndex(item => item.jobId === job.jobId);
if (jobIndex !== -1) {
// 更新状态
list.value[jobIndex].jobStatus = isCurrentlyUp ? 1 : 0;
}
// 也可以选择刷新数据
// if (state.tabIndex === 'all') {
// getJobRecommend('refresh');
// } else {
// getJobList('refresh');
// }
}).catch((err) => {
uni.hideLoading();
console.error('操作失败:', err);
$api.msg(isCurrentlyUp ? '下架失败,请重试' : '上架失败,请重试');
});
};
const isFourLevelLinkagePurview=ref(false)
const getIsFourLevelLinkagePurview=()=>{
let userInfo = uni.getStorageSync('userInfo')
@@ -2264,4 +2416,54 @@ defineExpose({ loadData });
color: #FFFFFF
text-align: center
white-space: nowrap
// 上下架开关样式
.falls-card-actions
margin-top: 20rpx
.job-status-switch
display: flex
align-items: center
justify-content: space-between
padding: 8rpx 0
.switch-track
width: 80rpx
height: 40rpx
background: #e0e0e0
border-radius: 20rpx
position: relative
transition: all 0.3s ease
cursor: pointer
&.active
background: #52c41a
.switch-thumb
position: absolute
top: 4rpx
left: 4rpx
width: 32rpx
height: 32rpx
background: #ffffff
border-radius: 50%
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2)
transition: all 0.3s ease
&.active
left: 44rpx
.switch-label
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif
font-weight: 500
font-size: 24rpx
color: #666666
margin-left: 16rpx
min-width: 80rpx
text-align: center
// 下架后卡片置灰样式
.disabled-card
opacity: 0.6
filter: grayscale(50%)
background: #f8f8f8 !important
.falls-card-title,
.falls-card-company,
.falls-card-pepleNumber,
.falls-card-company2
color: #999999 !important
</style>

View File

@@ -34,6 +34,15 @@
{{ companyInfo.isVerified ? '已通过' : '未认证' }}
</view>
</view>
<view class="service-item btn-feel" @click="goToMessage">
<view class="service-left">
<uni-icons type="chat" size="20" color="#256BFA"></uni-icons>
<text class="service-text">消息</text>
</view>
<view class="service-status">
<uni-icons type="right" size="14" color="#909090"></uni-icons>
</view>
</view>
<view class="service-item btn-feel">
<view class="service-left">
<uni-icons type="notification" size="20" color="#256BFA"></uni-icons>
@@ -83,6 +92,11 @@ function goToCompanyInfo() {
navTo('/pages/mine/company-info');
}
// 跳转到消息页面
function goToMessage() {
navTo('/pages/msglog/msglog');
}
function logOut() {
popup.value.open();
}

View File

@@ -96,6 +96,15 @@
<uni-icons color="#909090" type="right" size="14"></uni-icons>
</view>
</view>
<view class="main-row btn-feel" @click="goToMessage()">
<view class="row-left">
<image class="left-img" src="@/static/tabbar/chat4.png"></image>
<text class="left-text">消息</text>
</view>
<view class="row-right">
<uni-icons color="#909090" type="right" size="14"></uni-icons>
</view>
</view>
<view class="main-row btn-feel">
<view class="row-left">
<image class="left-img" src="@/static/icon/server4.png"></image>
@@ -218,6 +227,11 @@ function goCaAI(){
navTo(`/packageCa/search/AIAudition?name=${userInfo.name}&userId=${userInfo.idCard}`);
}
// 跳转到消息页面
function goToMessage(){
navTo('/pages/msglog/msglog');
}
</script>
<style lang="stylus" scoped>

BIN
static/tabbar/robot2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB