瀏覽代碼

feat: 更新聊天,留言板等功能代码

yezhihao 4 月之前
父節點
當前提交
5a4d9276de

+ 1 - 0
App.vue

@@ -156,6 +156,7 @@ export default {
 
             uni.setStorageSync("messageCount", messageCount);
 
+			uni.$emit('chatUnreadCount', chatCount || 0)
             let num = chatCount + messageCount;
             if (num == 0) {
               uni.removeTabBarBadge({

+ 271 - 0
components/load-card.vue

@@ -0,0 +1,271 @@
+<template>
+	<view class="load-container">
+		<view class="loading-card">
+			<view class="loading-animation">
+				<view class="ring ring-1"></view>
+				<view class="ring ring-2"></view>
+				<view class="ring ring-3"></view>
+
+				<view class="center-ball">
+					<view class="highlight"></view>
+					<!-- 核心:绑定计算出的弦长宽度 -->
+					<view class="horizontal-highlight"
+						:style="{ top: 100 - progress + '%', width: chordWidth + '%', height: chordHeight + '%' }"></view>
+				</view>
+
+				<view class="floating-dots">
+					<view class="dot dot-green"></view>
+					<view class="dot dot-yellow"></view>
+					<view class="dot dot-blue"></view>
+				</view>
+			</view>
+
+			<view class="progress-text">{{ progress }}%</view>
+			<view class="status-text">{{ statusText }}</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			progress: {
+				type: Number,
+				default: 50
+			},
+			statusText: {
+				type: String,
+				default: '正在分析您的简历...'
+			}
+		},
+		data() {
+			return {
+				show: true
+			}
+		},
+		computed: {
+			// 核心修正:用圆的弦长公式计算宽度
+			chordWidth() {
+				const ballRadius = 130; // 光球半径(260rpx / 2)
+				const ballDiameter = 260; // 光球直径
+				// 计算高光带的y坐标(rpx)
+				const highlightY = ((100 - this.progress) / 100) * ballDiameter;
+				// 计算圆心到高光带的垂直距离d
+				const d = Math.abs(highlightY - ballRadius);
+
+				// 当d >= 半径时,弦长为0(高光带在圆外)
+				if (d >= ballRadius) return 0;
+
+				// 计算弦长(rpx)
+				const chordLength = 2 * Math.sqrt(Math.pow(ballRadius, 2) - Math.pow(d, 2));
+				// 转化为百分比
+				return (chordLength / ballDiameter) * 100;
+			},
+			chordHeight() {
+				if (this.progress < 20 || this.progress > 80) {
+					let height = 0
+					if (this.progress < 25) {
+						height = this.progress
+					} else {
+						height = 100 - this.progress
+					}
+					return height
+				} else {
+					return 20
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.load-container {
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		background: rgba(0, 0, 0, 0.5);
+	}
+	
+	/* 原有样式不变,仅保证horizontal-highlight的定位正确 */
+	.horizontal-highlight {
+		position: absolute;
+		top: 0%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		width: 0%;
+		height: 0%;
+		border-radius: 50%;
+		background: radial-gradient(ellipse at center,
+				rgba(255, 255, 255, 0.7) 0%,
+				rgba(255, 255, 255, 0.3) 50%,
+				transparent 100%);
+		pointer-events: none;
+		z-index: 100;
+		transition: width 0.8s ease, top 0.8s ease;
+	}
+
+	/* 其他样式保持不变 */
+	.loading-card {
+		width: 560rpx;
+		padding: 60rpx 40rpx;
+		background: #fff;
+		border-radius: 24rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.05);
+	}
+
+	.loading-animation {
+		position: relative;
+		width: 320rpx;
+		height: 320rpx;
+		margin-bottom: 30rpx;
+	}
+
+	.ring {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		border-radius: 50%;
+		background: rgba(255, 215, 186, 0.3);
+	}
+
+	.ring-1 {
+		width: 100%;
+		height: 100%;
+		opacity: 0.8;
+	}
+
+	.ring-2 {
+		width: 120%;
+		height: 120%;
+		opacity: 0.5;
+	}
+
+	.ring-3 {
+		width: 140%;
+		height: 140%;
+		opacity: 0.3;
+	}
+
+	.center-ball {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		width: 260rpx;
+		height: 260rpx;
+		border-radius: 50%;
+		box-shadow: 0px 7px 37px 0px rgba(239, 181, 157, 0.62);
+		background: linear-gradient(159.89deg, rgba(236, 241, 252, 1) -2.225%, rgba(255, 249.54, 246.5, 1) 17.355%, rgba(255, 166, 130, 1) 69.089%, rgba(253.94, 184.19, 155.54, 1) 90.285%);
+		overflow: hidden;
+	}
+
+	.highlight {
+		position: absolute;
+		top: 10%;
+		left: 20%;
+		width: 60%;
+		height: 60%;
+		border-radius: 50%;
+		background: radial-gradient(circle at center, rgba(255, 255, 255, 0.8) 0%, transparent 70%);
+		pointer-events: none;
+	}
+
+	.floating-dots {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		pointer-events: none;
+	}
+
+	.dot {
+		position: absolute;
+		width: 12rpx;
+		height: 12rpx;
+		border-radius: 50%;
+		opacity: 0.8;
+	}
+
+	.dot-green {
+		background: #4ade80;
+		animation: floatGreen 12s ease-in-out infinite;
+	}
+
+	.dot-yellow {
+		background: #fbbf24;
+		animation: floatYellow 15s ease-in-out infinite;
+	}
+
+	.dot-blue {
+		background: #60a5fa;
+		animation: floatBlue 10s ease-in-out infinite;
+	}
+
+	@keyframes floatGreen {
+		0% {
+			transform: translate(40rpx, 60rpx);
+		}
+
+		50% {
+			transform: translate(60rpx, 40rpx);
+		}
+
+		100% {
+			transform: translate(40rpx, 60rpx);
+		}
+	}
+
+	@keyframes floatYellow {
+		0% {
+			transform: translate(300rpx, 140rpx);
+		}
+
+		50% {
+			transform: translate(280rpx, 80rpx);
+		}
+
+		100% {
+			transform: translate(300rpx, 140rpx);
+		}
+	}
+
+	@keyframes floatBlue {
+		0% {
+			transform: translate(280rpx, 240rpx);
+		}
+
+		50% {
+			transform: translate(240rpx, 280rpx);
+		}
+
+		100% {
+			transform: translate(280rpx, 240rpx);
+		}
+	}
+
+	.progress-text {
+		width: 100%;
+		font-size: 48rpx;
+		font-weight: bold;
+		text-align: center;
+		color: #ff7d45;
+		margin-bottom: 12rpx;
+	}
+
+	.status-text {
+		font-size: 28rpx;
+		color: #666;
+		text-align: center;
+		line-height: 1.5;
+	}
+</style>

+ 309 - 0
components/resume/position-card.vue

@@ -0,0 +1,309 @@
+<template>
+	<view class="gwList-box-item flex justify-center">
+		<view class="gwList-box-item-box">
+			<!-- 标题-薪资 -->
+			<view class="gwList-box-item-box-title flex justify-between align-center">
+				<view class="title-left flex align-center">
+					<view class="job-title-text"
+						style="max-width: 450rpx;overflow:hidden;white-space: nowrap;text-overflow: ellipsis;-o-text-overflow:ellipsis;">
+						<template>
+							{{ data.ruleClassifyName }}
+						</template>
+					</view>
+					<view v-if="data.isDue == 1" class="salary-text-box">
+						<image src="../../static/images/index/jipinIcom.svg"
+							class="jipin-icon" />
+						<text class="jipin-text">急聘</text>
+					</view>
+				</view>
+				<view>
+					<text class="clip-color">{{ data.salaryRange }}</text>
+					<text class="clip-color"> · </text>
+					<text class="clip-color">{{ data.salaryTimes }}</text>
+				</view>
+			</view>
+			<!-- 公司名称-公司人数 -->
+			<view class="flex align-center justify-between">
+				<view class="gwList-box-item-box-name flex align-center">
+					<text class="company-name company-name-overflow">{{ data.company ?
+						data.company.companyName : '' }}</text>
+					<text class="company-people" v-if="data.company">{{ data.company ?
+						data.company.companyPeople : '0人' }}</text>
+				</view>
+				<view class="experience">
+					<text>{{ data.experience }}</text>
+					<text>{{ data.education }}</text>
+				</view>
+			</view>
+			<!-- 福利标签 -->
+			<view class="benefits" v-if="data.welfareTag">{{ parseWelfare(data.welfareTag) }}</view>
+			<!-- 职位标签 -->
+			<view class="gwList-box-item-box-label flex align-center flex-wrap">
+				<text class="job-tag" v-for="(ite, ind) in parseSkills(data.positionTag)"
+					:key="ind">{{ ite }}</text>
+			</view>
+			<!-- 公司简介-位置 -->
+			<view class="gwList-box-item-box-info flex justify-between align-center">
+				<view class="gwList-box-item-box-info-l flex align-center">
+					<view class="user-image">
+						<image
+							:src="data.hr && data.hr.hrImg ? data.hr.hrImg : '../../static/images/logo.jpg'" class="hr-avatar">
+						</image>
+						<view class="online-status"
+							:style="{ 'background-color': data.user && data.user.onlineStatus == 'ONLINE' ? '#00DD9A' : '#999' }">
+						</view>
+					</view>
+					<view class="company-info-text">
+						{{ data.user && data.user.userName || '未知' }}·{{ data.hr &&
+							data.hr.hrPosition || '未知' }}
+					</view>
+					<view v-if="data.respondTime" class="reply-time">{{ data.respondTime }}
+					</view>
+				</view>
+				<view class="location-text">
+					{{ data.distance }} {{ data.county }}
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			data: {
+				type: Object,
+				default: () => {
+					return {}
+				}
+			}
+		},
+		data() {
+			return {}
+		},
+		methods: {
+			parseWelfare(str) {
+				if (!str) return ''
+				return str?.replace(/;/g, ' | ')
+			},
+			parseSkills(str) {
+				if (!str) return []
+				return str?.split(',') || []
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.title-left {
+		display: flex;
+		align-items: center;
+		gap: 8rpx;
+	}
+	
+	.job-title-text {
+		color: rgba(23, 23, 37, 1);
+		font-family: DM Sans;
+		font-size: 32rpx;
+		font-weight: bold;
+		line-height: 48rpx;
+		letter-spacing: 0.5%;
+		text-align: left;
+	}
+	
+	.salary-text-box {
+		border-radius: 24rpx;
+		background: #FEE2E3;
+		display: flex;
+		justify-content: flex-start;
+		align-items: center;
+		padding: 0 16rpx;
+	
+		.jipin-icon {
+			width: 20rpx;
+			height: 20rpx;
+			margin-right: 8rpx;
+		}
+	
+		.jipin-text {
+			color: rgba(237, 66, 69, 1);
+			font-family: DM Sans;
+			font-size: 16rpx;
+			font-weight: 400;
+			line-height: 40rpx;
+			letter-spacing: 0.5%;
+			text-align: left;
+		}
+	}
+	
+	.clip-color {
+		font-size: 24rpx;
+		font-weight: bold;
+		line-height: 40rpx;
+		background-image: linear-gradient(90.00deg, rgba(13, 39, 247, 1),rgba(19, 193, 234, 1));
+		-webkit-background-clip: text;
+		color: transparent;
+		background-clip: text;
+	}
+	
+	.company-name,
+	.company-people {
+		color: rgba(156, 164, 171, 1);
+		font-family: DM Sans;
+		font-size: 24rpx;
+		font-weight: 400;
+		line-height: 40rpx;
+		letter-spacing: 0.5%;
+		text-align: left;
+	}
+	
+	.job-tag {
+		padding: 8rpx;
+		border-radius: 8rpx;
+		background: rgba(198, 198, 198, 0.1);
+		margin-right: 8rpx;
+		margin-bottom: 8rpx;
+		color: rgba(153, 153, 153, 1);
+		font-size: 20rpx;
+		line-height: 1;
+	}
+	
+	.company-info-text,
+	.location-text {
+		color: rgba(156, 164, 171, 1);
+		font-family: DM Sans;
+		font-size: 20rpx;
+		font-weight: 400;
+		line-height: 40rpx;
+		letter-spacing: 0.5%;
+		text-align: left;
+	}
+	
+	.reply-time {
+		display: flex;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 4rpx 8rpx;
+		font-family: DM Sans;
+		font-size: 16rpx;
+		font-weight: 400;
+		line-height: 20rpx;
+		letter-spacing: 0.5%;
+		text-align: left;
+		border-radius: 12rpx;
+		background: #ECE1FD;
+		color: #8858C5;
+	}
+	
+	.user-image {
+		position: relative;
+	
+		.online-status {
+			width: 12rpx;
+			height: 12rpx;
+			position: absolute;
+			bottom: 0rpx;
+			right: 0rpx;
+			border-radius: 50%;
+			box-sizing: border-box;
+			border: 0.5px solid rgba(255, 255, 255, 1);
+		}
+		.hr-avatar {
+			display: block;
+			width: 40rpx;
+			height: 40rpx;
+			border: 0.5px solid rgba(240, 240, 240, 1);
+			border-radius: 20rpx;
+		}
+	}
+	
+	.gwList-box-item {
+		width: 712rpx;
+		background-color: #ffffff;
+		border-radius: 12rpx;
+		box-shadow: 0px 2rpx 4rpx 0px rgba(0, 0, 0, 0.1);
+		background: rgba(253, 253, 253, 1);
+		margin-bottom: 12rpx;
+		padding: 16rpx 36rpx;
+	}
+		
+	.gwList-box-item-box {
+		width: 100%;
+		.gwList-box-item-box-title {
+			margin-bottom: 12rpx;
+		}
+		
+		.gwList-box-item-box-label {
+			margin-top: 14rpx;
+		}
+		
+		.gwList-box-item-box-name {
+			color: rgba(156, 164, 171, 1);
+			font-size: 24rpx;
+			font-weight: 400;
+			line-height: 40rpx;
+			
+			.company-name-overflow {
+				max-width: 360rpx;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+				margin-right: 8rpx;
+			}
+		}
+		.experience {
+			font-size: 24rpx;
+			line-height: 32rpx;
+			color: rgba(1, 107, 246, 1);
+			text {
+				margin-left: 12rpx;
+			}
+		}
+		
+		.benefits {
+			width: 640rpx;
+			font-size: 20rpx;
+			line-height: 28rpx;
+			color: rgba(153, 153, 153, 1);
+			overflow: hidden;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+			margin-top: 12rpx;
+		}
+		
+		.gwList-box-item-box-line {
+			width: 100%;
+			border: 1rpx solid #E6E6E6;
+			margin-top: 30rpx;
+			margin-bottom: 20rpx;
+		}
+		
+		.gwList-box-item-box-info {
+			font-size: 26rpx;
+			margin-top: 10rpx;
+		
+			.gwList-box-item-box-info-l {
+				color: #1A1A1A;
+				display: flex;
+				align-items: center;
+				gap: 12rpx;
+		
+				.people {
+					max-width: 110rpx;
+					overflow: hidden; //超出的文本隐藏
+					text-overflow: ellipsis; //溢出用省略号显示
+					white-space: nowrap; // 默认不换行;
+				}
+			}
+		
+			.gwList-box-item-box-info-r {
+				color: #999999;
+				max-width: 50%;
+				overflow: hidden; //超出的文本隐藏
+				text-overflow: ellipsis; //溢出用省略号显示
+				white-space: nowrap; // 默认不换行;
+			}
+		}
+	}
+</style>

+ 83 - 68
components/resume/preview-resume.vue

@@ -14,11 +14,14 @@
 			</view>
 			<view class="flex sub-info">
 				<image src="@/static/images/svg/gray-briefcase.svg" class="icon"></image>
-				{{ currentCompanyName }} · {{ currentPositionName }}
+				<template v-if="currentCompanyName && currentPositionName">{{ currentCompanyName }} · {{ currentPositionName }}</template>
+				<template v-else>--</template>
 			</view>
 			<view class="sub-info">{{ jobStatusName }}</view>
 			<view class="tags">
-				<view class="tag" v-for="(tag, index) in baseInfoList" :key="index">{{ tag }}</view>
+				<template v-for="(tag, index) in baseInfoList">
+					<view class="tag" v-if="tag" :key="index">{{ tag }}</view>
+				</template>
 			</view>
 			<view class="advantages">{{ adv }}</view>
 			<!-- <view class="resume-tag">
@@ -49,7 +52,7 @@
 				工作经历
 			</view>
 			
-			<view class="common-section">
+			<view class="common-section" v-if="showWrokExpList && showWrokExpList.length">
 				<view class="work-item" v-for="work in showWrokExpList" :key="work.workExpId">
 					<view class="company-name-title">
 						<view class="company-name">{{ work.companyName }}</view>
@@ -145,6 +148,11 @@
 		},
 		mounted() {
 			if (this.resumesId) {
+				const resumeDetailData = this.$queue.getData('resumeDetailData')
+				if (resumeDetailData) {
+					this.setDetail(resumeDetailData)
+					return
+				}
 				this.getOhterResume()
 			} else {
 				this.getData()
@@ -156,7 +164,6 @@
 				this.$Request
 					.getT('/app/userFirst/getUserResumes')
 					.then((res) => {
-						console.log(res)
 						if (res.code === 0) {
 							const data = res.data
 							this.userName = data.userEntity.userName
@@ -176,7 +183,7 @@
 								this.baseInfoList.push(this.$queue.getHighestEducation(data.eduList))
 							}
 							// 添加年龄
-							if (data.userEntity) {
+							if (data.userEntity && data.userEntity.age) {
 								this.baseInfoList.push(`${data.userEntity.age}岁`)
 							}
 							this.adv = data.resumeList?.adv
@@ -205,7 +212,6 @@
 								work.isCrossCompany = isCrossCompany
 								return work
 							})
-							console.log(this.workExpList);
 							
 							// 教育经历
 							this.eduList = data.eduList.map(edu => {
@@ -219,6 +225,11 @@
 							
 							// 资质证书
 							this.certificates = data.certificates
+							
+							if (data?.resumeList?.resumesId) {
+								// 将简历id回传给父页面
+								uni.$emit('getResumeIdByComponent', data.resumeList.resumesId)
+							}
 						}
 					})
 			},
@@ -247,68 +258,7 @@
 					companyId: uni.getStorageSync('companyId'),
 				}).then(res => {
 					if (res.code == 0) {
-						const data = res.data
-						this.userName = data.resumesListDtoList?.userName
-						this.sex = data.resumesListDtoList?.userSex
-						this.avatarUrl = data.resumesListDtoList?.userAvatar
-						this.jobStatus = data.resumesStatus
-						if (data.workExpList.length) {
-							this.currentCompanyName = data.workExpList[0].companyName
-						}
-						this.currentPositionName = data.industryName
-						// 添加工作年限
-						if (data.resumesWorkExperience) {
-							this.baseInfoList.push(data.resumesWorkExperience)
-						}
-						// 添加学历
-						if (data.eduList) {
-							this.baseInfoList.push(this.$queue.getHighestEducation(data.eduList))
-						}
-						// 添加年龄
-						if (data.resumesListDtoList) {
-							this.baseInfoList.push(`${data.resumesListDtoList.userAge}岁`)
-						}
-						this.adv = data.resumesListDtoList?.adv
-						
-						// 求职期望
-						this.intentions = data.intentionList.map(item => {
-							item.industry = data.resumesListDtoList.intentIndustry
-							return item
-						})
-						
-						// 工作经历
-						this.workExpList = data?.workExpList.map(work => {
-							// 判断是否是跨境公司
-							let isCrossCompany = false
-							if (work.type && JSON.parse(work.type)?.[0] == 0) {
-								isCrossCompany = true
-							}
-							work.isCrossCompany = isCrossCompany
-							
-							work.workExpDetailList = work.workExpDetailList.map(item => {
-								item.startTime = item.startTime?.slice(0, 10)
-								item.endTime = item.endTime?.slice(0, 10)
-								item.skills = JSON.parse(item.skills)
-								return item
-							})
-							return work
-						})
-						
-						// 教育经历
-						this.eduList = data.eduList.map(edu => {
-							let time = ''
-							if (edu.startTime && edu.endTime) {
-								time = `${edu.startTime.split('-')[0]}-${edu.endTime.split('-')[0]}`
-							}
-							edu.time = time
-							return edu
-						})
-						
-						// 资质证书
-						this.certificates = data.certificates
-						
-						// 观看记录
-						this.browseTag = data.resumesListDtoList?.browseTag
+						this.setDetail(res.data)
 					} else {
 						uni.hideLoading()
 						uni.showModal({
@@ -323,6 +273,71 @@
 				}).finally(() => {
 					uni.hideLoading()
 				})
+			},
+			
+			// 设置请求的数据
+			setDetail(data) {
+				this.userName = data.resumesListDtoList?.userName
+				this.sex = data.resumesListDtoList?.userSex
+				this.avatarUrl = data.resumesListDtoList?.userAvatar
+				this.jobStatus = data.resumesStatus
+				if (data.workExpList.length) {
+					this.currentCompanyName = data.workExpList[0].companyName
+				}
+				this.currentPositionName = data.industryName
+				// 添加工作年限
+				if (data.resumesWorkExperience) {
+					this.baseInfoList.push(data.resumesWorkExperience)
+				}
+				// 添加学历
+				if (data.eduList) {
+					this.baseInfoList.push(this.$queue.getHighestEducation(data.eduList))
+				}
+				// 添加年龄
+				if (data.resumesListDtoList) {
+					this.baseInfoList.push(`${data.resumesListDtoList.userAge}岁`)
+				}
+				this.adv = data.resumesListDtoList?.adv
+				
+				// 求职期望
+				this.intentions = data.intentionList.map(item => {
+					item.industry = data.resumesListDtoList.intentIndustry
+					return item
+				})
+				
+				// 工作经历
+				this.workExpList = data?.workExpList.map(work => {
+					// 判断是否是跨境公司
+					let isCrossCompany = false
+					if (work.type && JSON.parse(work.type)?.[0] == 0) {
+						isCrossCompany = true
+					}
+					work.isCrossCompany = isCrossCompany
+					
+					work.workExpDetailList = work.workExpDetailList.map(item => {
+						item.startTime = item.startTime?.slice(0, 10)
+						item.endTime = item.endTime?.slice(0, 10)
+						item.skills = JSON.parse(item.skills)
+						return item
+					})
+					return work
+				})
+				
+				// 教育经历
+				this.eduList = data.eduList.map(edu => {
+					let time = ''
+					if (edu.startTime && edu.endTime) {
+						time = `${edu.startTime.split('-')[0]}-${edu.endTime.split('-')[0]}`
+					}
+					edu.time = time
+					return edu
+				})
+				
+				// 资质证书
+				this.certificates = data.certificates
+				
+				// 观看记录
+				this.browseTag = data.resumesListDtoList?.browseTag
 			}
 		}
 	}

+ 59 - 3
components/resume/resume-card.vue

@@ -3,7 +3,7 @@
 		<view class="top-section flex justify-between">
 			<view class="flex user-info">
 				<view class="avatar-container">
-					<image :src="avatar ? avatar : '/static/images/logo.jpg'" class="avatar"></image>
+					<image :src="avatar ? avatar : '/static/images/logo.jpg'" class="avatar" mode="aspectFill"></image>
 					<image src="@/static/images/svg/male.svg" class="sex-icon" v-if="sex == 1"></image>
 					<image src="@/static/images/svg/female.svg" class="sex-icon" v-else-if="sex == 2"></image>
 				</view>
@@ -41,6 +41,18 @@
 	import { formatNumberToK } from '@/utils/util.js'
 	
 	export default {
+		props: {
+			showImportData: {
+				type: Boolean,
+				default: false
+			},
+			resumeData: {
+				type: Object,
+				default: () => {
+					return {}
+				}
+			}
+		},
 		data() {
 			return {
 				avatar: '',
@@ -70,7 +82,11 @@
 			}
 		},
 		mounted() {
-			this.getData()
+			if (this.showImportData) {
+				this.initData()
+			} else {
+				this.getData()
+			}
 		},
 		methods: {
 			// 获取数据
@@ -102,7 +118,13 @@
 							this.companyName = data.companyName
 							this.positionName = data.position
 							this.ruleClassifyName = data.ruleClassifyName
-							// this.skills
+							this.companyTime = data.resumesWorkExperience
+							if (data.skills && Array.isArray((JSON.parse(data.skills)))) {
+								this.skills = JSON.parse(data.skills)
+							}
+							if (data.type && Array.isArray((JSON.parse(data.type)))) {
+								this.isCrossCompany = JSON.parse(data.type).includes('0')
+							}
 						}
 						console.log(res)
 					})
@@ -114,6 +136,39 @@
 				}
 				return ''
 			},
+			initData() {
+				console.log(JSON.parse(JSON.stringify(this.resumeData)))
+				const data = this.resumeData
+				if (data) {
+					this.avatar = data?.avatar
+					this.sex = data?.resumesListDtoList?.userSex
+					this.userName = data?.userName
+					if (data?.resumesListDtoList?.minSalary && data?.resumesListDtoList?.maxSalary) {
+						this.salaryRange = `${formatNumberToK(data.resumesListDtoList.minSalary)}-${formatNumberToK(data.resumesListDtoList.maxSalary)}`
+					}
+					// 设置年龄、工龄、学历
+					if (data?.resumesListDtoList?.userAge) {
+						this.baseInfoArr.push(`${data.resumesListDtoList.userAge}岁`)
+					}
+					if (data?.resumesListDtoList?.resumesWorkExperience) {
+						this.baseInfoArr.push(data.resumesListDtoList.resumesWorkExperience)
+					}
+					if (data?.resumesListDtoList?.degree) {
+						this.baseInfoArr.push(data.resumesListDtoList.degree)
+					}
+					
+					this.companyName = data?.resumesListDtoList?.companyName
+					this.positionName = data?.resumesListDtoList?.lastWorkPosition
+					this.ruleClassifyName = data?.intentionRuleClassifyName
+					this.skills = data?.intentionExprence
+					this.companyTime = data?.resumesWorkExperience
+					
+					// 判断是否是跨境公司
+					if (data?.resumesListDtoList?.workType) {
+						this.isCrossCompany = JSON.parse(data.resumesListDtoList.workType)[0] == '0'
+					}
+				}
+			}
 		}
 	}
 </script>
@@ -123,6 +178,7 @@
 		background: #fff;
 		border-radius: 12rpx;
 		padding: 16rpx 36rpx;
+		box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.1);
 
 		.top-section {
 			margin-bottom: 12rpx;

+ 4 - 3
manifest.json

@@ -29,7 +29,8 @@
             "Push" : {},
             "Geolocation" : {},
             "Camera" : {},
-            "Record" : {}
+            "Record" : {},
+            "Barcode" : {}
         },
         /* 应用发布信息 */
         "distribute" : {
@@ -202,8 +203,8 @@
                 "JPUSH_OPPO_APPSECRET" : "2ea0bcc32e734f5fa164437d5680e146",
                 "JPUSH_VIVO_APPID" : "106001691",
                 "JPUSH_VIVO_APPKEY" : "13f76ac11331bc7a7d04eb01fd739e45",
-                "JPUSH_XIAOMI_APPID" : "",
-                "JPUSH_XIAOMI_APPKEY" : "",
+                "JPUSH_XIAOMI_APPID" : "2882303761520460008",
+                "JPUSH_XIAOMI_APPKEY" : "5662046062008",
                 "__plugin_info__" : {
                     "name" : "极光推送 JPush 官方 SDK",
                     "description" : "极光推送JPush官方SDK HBuilder插件版本",

+ 7 - 1
my/renzheng/companyWelfare.vue

@@ -76,7 +76,7 @@
 			
 			<!-- 福利弹窗 -->
 			<u-popup v-model="showWelfarePopup" :mask-close-able="false" mode="top" border-radius="14">
-				<view class="welfare-popup">
+				<view class="welfare-popup" :style="{ paddingTop: BarHeight + 'px' }">
 					<view class="tags-wrapper">
 						<view class="welfare-popup-title">公司福利标签</view>
 						<view class="welfare-tip">选择公司提供的福利信息,以吸引更多求职者</view>
@@ -119,6 +119,7 @@
 		},
 		data() {
 			return {
+				BarHeight: 0,
 				companyId: '',
 				startWorkTime: '',
 				endWorkTime: '',
@@ -153,6 +154,11 @@
 			}
 		},
 		onLoad() {
+			// #ifdef APP-PLUS
+			let systemInfo = uni.getSystemInfoSync();
+			this.BarHeight = systemInfo.statusBarHeight;
+			// #endif
+			
 			this.initTimeList()
 			this.getCompanyInfo()
 		},

+ 1 - 1
package/jobIntention/addAddress.vue

@@ -136,7 +136,7 @@ export default {
 			district,
 			latitude: this.latitude || '',
 			longitude: this.longitude || '',
-			fullText: `${this.province || ''}${city}${district}${address}`
+			fullText: `${city}${district}${address}`
 		};
 
 		// 回传上一页

+ 1 - 1
package/jobIntention/companyImg.vue

@@ -208,7 +208,7 @@
 									this.companyLegalPerson = data.data.companyLegalPerson
 									this.companyLegalPerson = data.data.companyLegalPerson
 								}
-								let imgUrl = url ? data.data.src : data.data
+								let imgUrl = data.data.src ? data.data.src : data.data
 								resolve(imgUrl);
 							} else {
 								reject(data.msg || '上传失败');

+ 3 - 1
package/jobIntention/completeMsg.vue

@@ -100,7 +100,6 @@ export default {
 	},
 	onShow() {
 		this.getPositionInfo()
-		this.getmypost()
 		this.getcompanystatus()
 	},
 	methods: {
@@ -293,6 +292,9 @@ export default {
 						this.email = res.data.HrEntity.hrEmail
 					}
 				})
+				.finally(() => {
+					this.getmypost()
+				})
 		},
 		
 		handleConfirm() {

+ 286 - 0
package/my/feedback/index.vue

@@ -0,0 +1,286 @@
+<template>
+	<view class="page-container">
+		<nav-bar title="我要留言"></nav-bar>
+		
+		<view class="content">
+			<scroll-view
+				:scroll-y="true"
+				class="scroll-view"
+				:refresher-threshold="80"
+				:refresher-enabled="true"
+				:refresher-triggered="isRefreshing"
+				scroll-with-animation="true"
+				@refresherrefresh="handleRefresh"
+				@scrolltolower="loadMore">
+				<view class="list" v-if="list.length">
+					<view class="item-card" v-for="item in list" :key="item.messageId">
+						<view class="text">{{ item.content }}</view>
+						<view class="time">{{ item.createTime }}</view>
+						<view>
+							<view class="tag" v-if="setStatusText(item.status)">{{ setStatusText(item.status) }}</view>
+						</view>
+						<view class="buttons">
+							<view class="button" @click="handleDelete(item)">删除</view>
+						</view>
+					</view>
+				</view>
+				<view class="empty" v-else>暂无留言内容</view>
+			</scroll-view>
+		</view>
+		
+		<c-modal :value="showConfirmModal" title="提示" @cancel="showConfirmModal = false" @confirm="deleteMessage">
+			您是否确定删除该留言?
+		</c-modal>
+		
+		<c-modal :value="showModal" title="请留言" @cancel="showModal = false" @confirm="handleSubmit">
+			<textarea
+				v-model="message"
+				placeholder="请提交您想要反馈的留言"
+				class="textarea"
+				placeholder-class="placeholder-class"
+				maxlength="1000">
+			</textarea>
+		</c-modal>
+		
+		<view class="button-section">
+			<view class="submit-btn" @click="showModal = true">我要留言</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navBar from '@/components/nav-bar/index.vue'
+	import cModal from '@/components/c-modal.vue'
+	export default {
+		components: {
+			navBar,
+			cModal
+		},
+		data() {
+			return {
+				showConfirmModal: false,
+				showModal: false,
+				loading: false,
+				updating: false,
+				message: '',
+				list: [],
+				deleteMessageId: '',
+				total: 0,
+				page: 1,
+				limit: 10,
+				isRefreshing: false,
+			}
+		},
+		watch: {
+			showModal(value) {
+				if (!value) {
+					this.message = ''
+				}
+			}
+		},
+		onLoad() {
+			if (this.$queue.getData('token')) {
+				this.getList()
+			}
+		},
+		methods: {
+			// 设置状态文案
+			setStatusText(value) {
+				switch (value) {
+					case 0:
+						return '已留言'
+					case 1: 
+						return '已采纳'
+				}
+				return ''
+			},
+			// 获取留言数据
+			getList() {
+				if (this.loading) return
+				
+				this.loading = true
+				uni.showLoading({ title: '加载中' })
+				this.$Request
+					.getT('/app/messageBoard/selectMessageBoardList', {
+						page: this.page,
+						limit: this.limit
+					})
+					.then(res => {
+						if (res.code === 0) {
+							this.list = this.page == 1 ? res.data.records : [...this.list, ...res.data.records],
+							this.total = res.data.total
+						}
+					})
+					.finally(() => {
+						this.isRefreshing = false
+						this.loading = false
+						uni.hideLoading()
+					})
+			},
+			
+			handleDelete(item) {
+				this.deleteMessageId = item.messageId
+				this.showConfirmModal = true
+			},
+			
+			// 删除留言
+			deleteMessage() {
+				if (this.updating) return
+				
+				this.updating = true
+				uni.showLoading({ title: '删除中' })
+				this.$Request
+					.getT('/app/messageBoard/deleteMessageBoard', {
+						messageBoardId: this.deleteMessageId
+					})
+					.then(res => {
+						if (res.code === 0) {
+							this.$queue.showToast('删除成功')
+							this.showConfirmModal = false
+							this.page = 1
+							this.getList()
+						}
+					})
+					.finally(() => {
+						this.updating = false
+						uni.hideLoading()
+					})
+			},
+			
+			// 提交留言
+			handleSubmit() {
+				if (this.updating) return
+				if (!this.message) {
+					this.$queue.showToast('请输入留言内容')
+					return
+				}
+				
+				this.updating = true
+				uni.showLoading({ title: '留言中' })
+				this.$Request
+					.postJson('/app/messageBoard/updateMessageBoard', {
+						messageId: '',
+						content: this.message
+					})
+					.then(res => {
+						if (res.code == 0) {
+							this.$queue.showToast('留言成功')
+							this.showModal = false
+							this.page = 1
+							this.getList()
+						}
+					})
+					.finally(() => {
+						this.updating = false
+						uni.hideLoading()
+					})
+			},
+			
+			// 刷新
+			handleRefresh() {
+				if (this.isRefreshing) return
+				this.isRefreshing = true
+				this.page = 1
+				this.getList()
+			},
+			
+			// 加载更多
+			loadMore() {
+				if (this.loading || this.list.length >= this.total) return
+				this.page++
+				this.getList()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import '@/common.scss';
+	
+	.page-container {
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		height: 100vh;
+		font-family: DM Sans;
+		font-style: Regular;
+		
+		.content {
+			flex: 1;
+			padding: 0 40rpx;
+			overflow: hidden;
+			.scroll-view {
+				width: 100%;
+				height: 100%;
+			}
+			.list {
+				padding: 20rpx 0;
+			}
+			.item-card {
+				padding: 16rpx 36rpx;
+				box-sizing: border-box;
+				border: 1px solid rgba(227, 231, 236, 1);
+				border-radius: 6px;
+				background: rgba(255, 255, 255, 1);
+				margin-bottom: 20rpx;
+				.text {
+					color: rgba(23, 23, 37, 1);
+					font-size: 28rpx;
+					font-weight: 400;
+					line-height: 44rpx;
+					margin-bottom: 8rpx;
+					word-break: break-all;
+				}
+				.time {
+					color: rgba(156, 164, 171, 1);
+					font-size: 20rpx;
+					font-weight: 400;
+					line-height: 40rpx;
+				}
+				.tag {
+					display: inline-block;
+					padding: 8rpx;
+					border-radius: 8rpx;
+					background: rgba(1, 107, 246, 0.1);
+					color: rgba(1, 107, 246, 1);
+					font-size: 20rpx;
+					font-weight: 400;
+					line-height: 1;
+					margin: 8rpx 0;
+				}
+				.button {
+					width: 190rpx;
+					height: 60rpx;
+					border: 1px solid rgba(232, 232, 232, 1);
+					border-radius: 60rpx;
+					text-align: center;
+					line-height: 58rpx;
+					color: rgba(153, 153, 153, 1);
+					font-size: 24rpx;
+					font-weight: 500;
+				}
+			}
+			
+			.empty {
+				padding: 50rpx;
+				text-align: center;
+				color: #999;
+			}
+		}
+		
+		.textarea {
+			width: 100%;
+			box-sizing: border-box;
+			border: 1px solid rgba(242, 242, 242, 1);
+			border-radius: 6px;
+			background: rgba(250, 250, 250, 1);
+			padding: 26rpx 20rpx;
+			font-size: 28rpx;
+			line-height: 40rpx;
+			color: rgba(158, 161, 168, 1);
+		}
+		.placeholder-class {
+			color: rgba(158, 161, 168, 1);
+		}
+	}
+</style>

+ 16 - 2
package/my/previewResume/index.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="preview-resume">
 		<nav-bar title="简历预览" color="#000" class="nav-bar">
-			<view class="import-btn" slot="right">导出</view>
+			<view class="import-btn" slot="right" v-if="resumeId" @click="getResumePDF">导出</view>
 		</nav-bar>
 		
 		<view class="tabs">
@@ -24,6 +24,7 @@
 	import previewResume from '@/components/resume/preview-resume.vue';
 	import indexCard from '@/components/resume/index-card.vue';
 	import chatCard from '@/components/resume/chat-card.vue';
+	import { exportResumePdf } from '@/utils/util'
 		
 	export default {
 		components: {
@@ -45,7 +46,9 @@
 						name: '沟通卡片'
 					}
 				],
-				activeIndex: 0
+				activeIndex: 0,
+				resumeId: null,
+				loading: false,
 			}
 		},
 		onLoad(options) {
@@ -57,10 +60,21 @@
 					this.activeIndex = 2
 				}
 			}
+			
+			uni.$on('getResumeIdByComponent', (id) => {
+				this.resumeId = id
+			})
+		},
+		onUnload() {
+			uni.$off('getResumeIdByComponent')
 		},
 		methods: {
 			handleChangeTab(index) {
 				this.activeIndex = index
+			},
+			// 获取简历并导出
+			getResumePDF() {
+				exportResumePdf(this.resumeId)
 			}
 		}
 	}

+ 93 - 0
package/my/scan/index.vue

@@ -0,0 +1,93 @@
+<template>
+	<view class="page-container">
+		<nav-bar title="扫码登录"></nav-bar>
+		<view class="content">
+			<view class="wrapper">
+				<image src="/static/invite.png" class="slogan-img"></image>
+				<view class="tip">是否确认登录网页端</view>
+				<view class="button" @click="handleConfirmLogin">确认登录</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navBar from '@/components/nav-bar/index.vue'
+	export default {
+		components: {
+			navBar
+		},
+		data() {
+			return {
+				scanToken: '',
+				loading: false,
+			}
+		},
+		onLoad(options) {
+			if (options.token) {
+				this.scanToken = options.token
+			}
+		},
+		methods: {
+			// 确认登录
+			handleConfirmLogin() {
+				if (this.loading) return
+				
+				this.loading = true
+				uni.showLoading({ title: '登录中' })
+				this.$Request
+					.post('/app/Login/confirm', {
+						token: this.scanToken
+					})
+					.then(res => {
+						if (res.code === 0) {
+							this.$queue.showToast('登录成功')
+							setTimeout(() => {
+								uni.switchTab({
+									url: '/pages/my/index'
+								})
+							}, 1500)
+						}
+					})
+					.finally(() => {
+						this.loading = false
+						uni.hideLoading()
+					})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.page-container {
+		.content {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			.wrapper {
+				padding-top: 120rpx;
+			}
+			.slogan-img {
+				display: block;
+				width: 400rpx;
+				height: 400rpx;
+				margin: 0 auto 20rpx;
+			}
+			.tip {
+				text-align: center;
+				margin-bottom: 40rpx;
+			}
+			.button {
+				width: 400rpx;
+				height: 80rpx;
+				border: 80rpx;
+				text-align: center;
+				color: #fff;
+				font-size: 32rpx;
+				line-height: 80rpx;
+				border-radius: 100px;
+				background: linear-gradient(90.00deg, rgba(13, 39, 247, 1),rgba(19, 193, 234, 1));
+			}
+		}
+	}       
+</style>

+ 101 - 65
package/records/records.vue

@@ -1,5 +1,6 @@
 <template>
   <view>
+	  <nav-bar title="求职记录"></nav-bar>
     <view class="qz-record">
       <view class="qz-title">求职记录</view>
       <view class="qz-desc">当前记录仅自己可见,招聘者无法看到你所浏览过或投递过的
@@ -11,9 +12,12 @@
         <view class="gwList-box-item flex justify-center" @click="gotoInfo(item)" v-for="(item, index) in dataList"
           :key="index">
           <view class="gwList-box-item-box">
-            <view v-if="item" class="gwList-box-item-box-title flex justify-between align-center">
+            <view v-if="item && title != '面试记录'" class="gwList-box-item-box-title flex justify-between align-center">
               <text>{{ item.ruleClassifyName || item.postPush && item.postPush.ruleClassifyName }}</text>
-              <text>{{ item.salaryRange || item.postPush && item.postPush.salaryRange }}</text>
+              <text>
+				{{ item.salaryRange || item.postPush && item.postPush.salaryRange }}
+				<template v-if="item.salaryTimes || (item.postPush && item.postPush.salaryTimes)"> · {{ item.salaryTimes || item.postPush.salaryTimes }}</template>
+			</text>
             </view>
             <block v-if="title == '我的收藏'">
               <view class="gwList-box-item-box-name">
@@ -23,18 +27,18 @@
               <view class="gwList-box-item-box-label flex align-center flex-wrap">
                 <view class="gw-tag" v-if="item.company && item.company.workRestTime">{{ item.company.workRestTime }}
                 </view>
-                <view class="gw-tag" v-for="(ite, ind) in item.welfareTag ? item.welfareTag.split(';') : []" :key="ind">
+                <view class="gw-tag" v-for="(ite, ind) in formatWelfare(item, 'welfareTag', ';')" :key="ind">
                   {{
                     ite }}</view>
               </view>
               <view class="gwList-box-item-box-info flex justify-between align-center">
                 <view class="gwList-box-item-box-info-l flex align-center">
-                  <image :src="item.companyLogo ? item.companyLogo : '../../static/logo.png'" class="user-info-img"
-                    mode=""></image>
-                  <text v-if="item.companyLegalPerson" class="user-info-name">{{ item.companyLegalPerson }}·创始人</text>
+                  <image :src="item.hrAvatar ? item.hrAvatar : '/static/logo.png'" class="user-info-img"
+                    mode="aspectFill"></image>
+                  <text class="user-info-name">{{ item.hrName }}·{{ item.hrPosition }}</text>
                   <!-- <view class="info-tag" v-if="item.salaryTimes">{{ item.salaryTimes }}</view> -->
                 </view>
-                <view class="gwList-box-item-box-info-r">
+                <view class="gwList-box-item-box-info-r address-text">
                   <!-- {{ item.county }} -->
                   {{ item.address }}
                 </view>
@@ -48,7 +52,7 @@
               <view class="gwList-box-item-box-label flex align-center flex-wrap">
                 <view class="gw-tag" v-if="item.company && item.company.workRestTime">{{ item.company.workRestTime }}
                 </view>
-                <view class="gw-tag" v-for="(ite, ind) in (item.welfareTag ? item.welfareTag.split(';') : [])"
+                <view class="gw-tag" v-for="(ite, ind) in formatWelfare(item, 'welfareTag', ';')"
                   :key="ind">
                   {{
                     ite }}</view>
@@ -74,7 +78,7 @@
               <view class="gwList-box-item-box-label flex align-center flex-wrap">
                 <view class="gw-tag" v-if="item.company && item.company.workRestTime">{{ item.company.workRestTime }}
                 </view>
-                <view class="gw-tag" v-for="(ite, ind) in (item.postPush ? item.postPush.welfareTag.split(';') : [])"
+                <view class="gw-tag" v-for="(ite, ind) in (item.postPush && item.postPush.welfareTag ? item.postPush.welfareTag.split(';') : [])"
                   :key="ind">{{
                     ite }}</view>
               </view>
@@ -98,11 +102,11 @@
             <block v-else-if="title == '面试记录'">
 
               <view class="gwList-box-item-box-info flex justify-between align-center padding0">
-                <view class="gwList-box-item-box-info-l flex align-center">
-                  <image
-                    :src="item.company && item.company.companyLogo ? item.company.companyLogo : '../../static/logo.png'"
-                    class="company-info-img" mode=""></image>
-                </view>
+				<view class="logo-wrapper flex align-center justify-center">
+				  <image
+					:src="item.company && item.company.companyLogo ? item.company.companyLogo : '../../static/logo.png'"
+					class="company-info-img" mode=""></image>						
+				</view>
                 <view class="companyRight">
                   <view class="gwList-box-item-box-info-l flex justify-between align-center">
 
@@ -111,11 +115,16 @@
                       {{ item.status == 1 ? '待接受' : (item.status == 2 ? '已同意' : (item.status == 3 ? '已拒绝' : '已过期')) }}
                     </view>
                   </view>
-                  <view class="gwList-box-item-box-name">
+                  <view class="position-base-info">
                     <text>{{ item.postPush && item.postPush.ruleClassifyName ? item.postPush.ruleClassifyName : "匿名"
                     }}</text>·<text>{{ item.postPush && item.postPush.salaryRange }}</text>
                   </view>
-                  <view class="gwList-box-item-box-label flex align-center flex-wrap">
+				  <view class="main-tip-text">
+					  {{ item.interviewDateTime && item.interviewDateTime.substring(0, 10) || '' }}
+					  <text>{{ item.detailTime }}</text>
+				  </view>
+				  <view class="main-tip-text">{{ item.address }}</view>
+                 <!-- <view class="gwList-box-item-box-label flex align-center flex-wrap">
                     <view class="gw-tag" v-if="item.company && item.company.workRestTime">{{ item.company.workRestTime
                     }}
                     </view>
@@ -123,15 +132,14 @@
                       v-for="(ite, ind) in (item.company && item.company.welfare ? item.company.welfare.split(';') : [])"
                       :key="ind">{{
                         ite }}</view>
-                  </view>
-                  <view class="gwList-box-item-box-info-r">
+                  </view> -->
+                  <!-- <view class="gwList-box-item-box-info-r">
                     {{ item.interviewDateTime && item.interviewDateTime.substring(0, 10) || '' }}
                     <text>{{ item.detailTime }}</text>
-                  </view>
-                  <view class="gwList-box-item-box-info-r">
-                    <!-- {{ item.county }}  -->
+                  </view> -->
+                  <!-- <view class="gwList-box-item-box-info-r">
                     {{ item.address }}
-                  </view>
+                  </view> -->
                 </view>
               </view>
             </block>
@@ -143,20 +151,20 @@
               <view class="gwList-box-item-box-label flex align-center flex-wrap">
                 <view class="gw-tag" v-if="item.company && item.company.workRestTime">{{ item.company.workRestTime }}
                 </view>
-                <view class="gw-tag" v-for="(ite, ind) in (item.welfareTag ? item.welfareTag.split(';') : [])"
+                <view class="gw-tag" v-for="(ite, ind) in formatWelfare(item, 'welfareTag', ';')"
                   :key="ind">
                   {{ ite }}
                 </view>
               </view>
               <view class="gwList-box-item-box-info flex justify-between align-center">
                 <view class="gwList-box-item-box-info-l flex align-center">
-                  <image :src="item.companyLogo ? item.companyLogo : '../../static/logo.png'" class="user-info-img"
-                    mode=""></image>
-                  <text v-if="item.companyLegalPerson" class="user-info-name">{{ item.companyLegalPerson }}·创始人</text>
+                  <image :src="item.hrAvatar ? item.hrAvatar : '/static/logo.png'" class="user-info-img"
+                    mode="aspectFill"></image>
+                  <text class="user-info-name">{{ item.hrName }}·{{ item.hrPosition }}</text>
 
                   <!-- <view class="info-tag" v-if="item.salaryTimes">{{ item.salaryTimes }}</view> -->
                 </view>
-                <view class="gwList-box-item-box-info-r">
+                <view class="gwList-box-item-box-info-r address-text">
                   <!-- {{ item.county }} -->
                   {{ item.address }}
                 </view>
@@ -180,9 +188,11 @@
 
 <script>
 import empty from "../../components/empty.vue";
+import navBar from '@/components/nav-bar/index.vue'
 export default {
   components: {
     empty,
+	navBar
   },
   data() {
     return {
@@ -200,14 +210,11 @@ export default {
         industry: "", //行业
       },
       list: [
-        {
-          name: "我看过",
-        },
         {
           name: "沟通过",
         },
         {
-          name: "投递",
+          name: "投递",
         },
         {
           name: "面试",
@@ -257,8 +264,6 @@ export default {
     this.page = 1;
     if (this.title == "我的收藏") {
       this.getMyCollectionList();
-    } else if (this.title == "浏览记录") {
-      this.getDataList();
     } else if (this.title == "投递记录") {
       this.getDataLists();
     } else if (this.title == "沟通记录") {
@@ -276,19 +281,16 @@ export default {
     },
     tabClick(e) {
       this.tabIndex = e;
-      if (this.tabIndex == 4) {
+      if (this.tabIndex == 3) {
         this.title = "我的收藏"
         this.getMyCollectionList();
-      } else if (this.tabIndex == 0) {
-        this.title = "浏览记录"
-        this.getDataList();
-      } else if (this.tabIndex == 2) {
+      } else if (this.tabIndex == 1) {
         this.title = "投递记录"
         this.getDataLists();
-      } else if (this.tabIndex == 1) {
+      } else if (this.tabIndex == 0) {
         this.title = "沟通记录"
         this.getDataLists(1);
-      } else if (this.tabIndex == 3) {
+      } else if (this.tabIndex == 2) {
         this.title = "面试记录"
         this.getDataLists(3);
       }
@@ -335,19 +337,16 @@ export default {
         this.filter.companyPeople = ""; //公司规模
       }
       if (this.title == "我的收藏") {
-        this.tabIndex = 4
+        this.tabIndex = 3
         this.getMyCollectionList();
-      } else if (this.title == "浏览记录") {
-        this.tabIndex = 0
-        this.getDataList();
       } else if (this.title == "投递记录") {
-        this.tabIndex = 2
+        this.tabIndex = 1
         this.getDataLists();
       } else if (this.title == "沟通记录") {
-        this.tabIndex = 1
+        this.tabIndex = 0
         this.getDataLists(1);
       } else if (this.title == "面试记录") {
-        this.tabIndex = 3
+        this.tabIndex = 2
         this.getDataLists(3);
       }
     },
@@ -370,7 +369,7 @@ export default {
         if (res.code == 0) {
           res.data.records.map((item) => {
             if (item.positionWelfare) {
-              item.positionWelfare = item.positionWelfare ? item.positionWelfare.split(",") : [];
+              item.positionWelfare = this.formatWelfare(item);
             }
           });
           this.pages = res.data.pages;
@@ -382,6 +381,10 @@ export default {
         }
       });
     },
+	formatWelfare(data, key = 'positionWelfare', s = ',') {
+		if (!data?.positionWelfare) return []
+		return data[positionWelfare]?.split(s) || []
+	},
     gotoInfo(item) {
       if (this.title == "面试记录") {
         if (item.status != 2)
@@ -432,7 +435,7 @@ export default {
         if (res.code == 0) {
           res.data.records.map((item) => {
             if (item.positionWelfare) {
-              item.positionWelfare = item.positionWelfare ? item.positionWelfare.split(",") : [];
+              item.positionWelfare = this.formatWelfare(item);
             }
           });
           this.pages = res.data.pages;
@@ -461,7 +464,7 @@ export default {
         if (res.code == 0) {
           res.data.records.map((item) => {
             if (item.positionWelfare) {
-              item.positionWelfare = item.positionWelfare.split(",");
+              item.positionWelfare = this.formatWelfare(item)
             } else {
               item.positionWelfare = [];
             }
@@ -618,15 +621,26 @@ page {
           .user-info-name {
             white-space: nowrap;
           }
-
-          .company-info-img {
-            width: 100rpx;
-            height: 100rpx;
-            border: 1rpx solid rgba(240, 240, 240, 1);
-            border-radius: 50%;
-            margin-right: 30rpx;
-          }
         }
+		.address-text {
+			text-align: right;
+		}
+		
+		.logo-wrapper {
+			align-self: flex-start;
+			width: 96rpx;
+			height: 96rpx;
+			border-radius: 8px;
+			background: rgba(246, 246, 246, 1);
+			margin-right: 20rpx;
+			
+			.company-info-img {
+			  width: 80rpx;
+			  height: 80rpx;
+			  border: 1px solid rgba(240, 240, 240, 1);
+			  border-radius: 50%;
+			}
+		}
 
         .gwList-box-item-box-info-r {
           // max-width: 340rpx;
@@ -634,6 +648,7 @@ page {
           white-space: nowrap;
           text-overflow: ellipsis;
           flex: 1;
+		  margin-left: 30rpx;
 
           text {
             margin-left: 10rpx
@@ -641,13 +656,32 @@ page {
         }
 
         .companyRight {
-          width: 100%;
+          // width: 100%;
+		  flex: 1;
 
           .companyName {
-            font-size: 26rpx;
-            color: #353535;
             margin-right: 20rpx;
+			color: rgba(23, 23, 37, 1);
+			font-size: 28rpx;
+			font-weight: 400;
+			line-height: 44rpx;
           }
+		  .position-base-info {
+			  color: rgba(120, 130, 138, 1);
+			  font-size: 28rpx;
+			  font-weight: 400;
+			  line-height: 36rpx;
+			  margin-top: 8rpx;
+		  }
+		  .main-tip-text {
+			  color: rgba(1, 107, 246, 1);
+			  font-family: DM Sans;
+			  font-style: Regular;
+			  font-size: 24rpx;
+			  font-weight: 400;
+			  line-height: 32rpx;
+			  margin-top: 8rpx;
+		  }
         }
       }
 
@@ -663,10 +697,12 @@ page {
   box-sizing: border-box;
 
   .qz-title {
-    font-family: DM Sans;
-    font-size: 60rpx;
-    color: rgba(51, 51, 51, 1);
-    font-weight: 800;
+	color: rgba(51, 51, 51, 1);
+	font-family: DM Sans;
+	font-style: Bold;
+	font-size: 48rpx;
+	font-weight: 700;
+	line-height: 60rpx;
   }
 
   .qz-desc {

+ 17 - 4
pages.json

@@ -232,7 +232,7 @@
 			"path": "pages/msg/index",
 			"style": {
 				"navigationBarTitleText": "消息",
-				"enablePullDownRefresh": true,
+				// "enablePullDownRefresh": true,
 				"navigationStyle": "custom"
 			}
 		},
@@ -897,9 +897,8 @@
 					"path": "records/records",
 					"style": {
 						"navigationBarTitleText": "求职记录",
-						"enablePullDownRefresh": true
-						// ,
-						// "navigationStyle": "custom"
+						"enablePullDownRefresh": true,
+						"navigationStyle": "custom"
 					}
 				},
 				{
@@ -959,6 +958,20 @@
 						"enablePullDownRefresh": false,
 						"navigationStyle": "custom"
 					}
+				},
+				{
+					"path": "my/feedback/index",
+					"style": {
+						"navigationBarTitleText": "我要留言",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "my/scan/index",
+					"style": {
+						"navigationBarTitleText": "扫码确认",
+						"navigationStyle": "custom"
+					}
 				}
 			]
 		},

+ 19 - 11
pages/index/index.vue

@@ -371,7 +371,7 @@
 							</view>
 							
 							<view class="topbg-search-r flex align-center">
-								<view class="topbg-search-item topbg-search-item__active flex align-center" @click="getLocalJobs('go')">
+								<view class="topbg-search-item topbg-search-item__active flex align-center" @click="getLocalJobs('go', true)">
 									<text class="topbg-search-item__text">{{ county ? county : city ? city : '选择地区'
 									}}</text>
 									<u-icon name="arrow-down"></u-icon>
@@ -599,6 +599,7 @@ export default {
 			recommendPositions: [], // 精选职位
 			loadingRecommendPosition: false,
 			RPPage: 1,
+			currentPostionCity: '', // 当前岗位城市(招聘端限制城市使用)
 		};
 	},
 	onShareAppMessage(res) {
@@ -1049,6 +1050,7 @@ export default {
 			this.currentJobSx = index
 			this.currentRuleClassifyId = job.ruleClassifyId
 			this.positionTag = this.positionTagMap[job.ruleClassifyId] || [{ id: '不限', name: '不限' }]
+			this.currentPostionCity = job.city
 			this.getDomWidth()
 		},
 		//下拉过程
@@ -1110,7 +1112,8 @@ export default {
 			})
 		},
 		// 
-		async getLocalJobs(go = 'go') {
+		async getLocalJobs(go = 'go', isBusiness = false) {
+			// isBusiness:判断是否是招聘端,如果是则限制选择城市,以公司城市为准
 			let that = this;
 			// #ifdef APP
 			const hasLocation = await this.$queue.checkPermission(
@@ -1120,15 +1123,15 @@ export default {
 			);
 			if (!hasLocation) return that.goNav('/package/screen/city?city=' + that.city + '&county=' + that.county);
 			// #endif
-			that.getCity(go)
+			that.getCity(go, isBusiness)
 		},
 
-		getCity(go = '') {
+		getCity(go = '', isBusiness = false) {
 			var that = this
 			// 权限通过,调用定位API
 			uni.getLocation({
 				type: 'wgs84', //wgs84  gcj02
-				success: function (res) {
+				success: (res) => {
 					console.log(res, '地理位置');
 					that.latitude = res.latitude;
 					that.longitude = res.longitude;
@@ -1142,10 +1145,11 @@ export default {
 					} else {
 						that.getCompanyClassify()
 					}
-					// console.log(uni.getStorageSync('city') == '', '22222222222')
-					if (!uni.getStorageSync('city') || uni.getStorageSync('city') == '' || uni
-						.getStorageSync(
-							'city') == null) {
+					if (isBusiness && this.currentPostionCity) {
+						that.goNav(`/package/screen/city?city=${that.currentPostionCity}&county=${that.county}&type=search&onlyShowOneCity=true`)
+						return
+					}
+					if (!uni.getStorageSync('city') || uni.getStorageSync('city') == '' || uni.getStorageSync('city') == null) {
 						// #ifdef APP-PLUS
 						if (res.address) {
 							that.city = res.address.city
@@ -1164,7 +1168,7 @@ export default {
 					} else {
 						that.city = uni.getStorageSync('city')
 						if (go == 'go') {
-							that.goNav(`/package/screen/city?city=${that.city}&county=${that.county}&type=search&onlyShowOneCity=true`)
+							that.goNav(`/package/screen/city?city=${that.city}&county=${that.county}&type=search&onlyShowOneCity=${ this.userType == 2 ? 'true' : '' }`)
 						}
 					}
 				},
@@ -1590,7 +1594,11 @@ export default {
 							id: item.postPushId,
 							projectName: item.ruleClassifyName,
 							name: item.ruleClassifyName,
-							ruleClassifyId: item.ruleClassifyId
+							ruleClassifyId: item.ruleClassifyId,
+							city: item.city
+						}
+						if (!this.currentPostionCity) {
+							this.currentPostionCity = item.city
 						}
 						arr.push(obj)
 

+ 6 - 3
pages/jobManagement/jobManagement.vue

@@ -209,8 +209,9 @@ export default {
       if (this.isLoading) return; // 正在加载时,阻止重复请求
       this.isLoading = true;
       
+	  let status = this.tabIndex == 0 ? '' : this.tabs[this.tabIndex].status
       let data = {
-        status: this.tabIndex == 0 ? '' : this.tabIndex,
+        status,
         page: this.page,
         limit: this.limit,
         companyId: this.companyId
@@ -234,7 +235,7 @@ export default {
             } else if (ret.status == 5) {
               ret.statusName = '已关闭'
             }
-			ret.positionTags = ret.positionTag.split(',')
+			ret.positionTags = ret.positionTag?.split(',')
             this.jobList.push(ret)
           })
           this.count = res.data.total; // 更新总条数
@@ -454,8 +455,10 @@ export default {
 	
 	handleConfirm() {
 		if (this.tipType == 3) {
+			const companyId = this.companyInfo?.companyId
+			const companyName = this.companyInfo?.companyAllName
 			uni.navigateTo({
-				url: '/pages/my/businessLicense',
+				url: `/package/jobIntention/companyImg?companyId=${companyId}&companyName=${encodeURIComponent(companyName)}`,
 				success: () => {
 					this.showTipModal = false
 				}

文件差異過大導致無法顯示
+ 31 - 7
pages/msg/css/style.scss


文件差異過大導致無法顯示
+ 376 - 479
pages/msg/im.vue


+ 692 - 213
pages/msg/index.vue

@@ -1,22 +1,149 @@
 <template>
-	<view class="msg-box" :style="{ paddingTop: BarHeight + 'px' }">
-		<!-- 顶部导航栏 -->
-		<view class="nav-header">
-			<view class="nav-left" @click="goSearch">
-				<u-icon name="search" color="rgba(56, 58, 63, 1)" size="40"></u-icon>
+	<view>
+		<view class="msg-box" :style="{ paddingTop: BarHeight + 'px' }">
+		<!-- <view class="msg-box"> -->
+			<!-- 顶部导航栏 -->
+			<view class="nav-header">
+				<view class="nav-left">
+					<!-- <u-icon name="search" color="rgba(56, 58, 63, 1)" size="40"></u-icon> -->
+				</view>
+				<view class="nav-center">
+					<text class="nav-title">消息</text>
+				</view>
+				<view class="nav-right">
+					<!-- <u-icon name="bell" color="rgba(56, 58, 63, 1)" size="40" style="margin-right: 20rpx;"></u-icon> -->
+					<u-icon name="setting" color="rgba(56, 58, 63, 1)" size="40" v-if="isLogin" @click="showSettingsModal"></u-icon>
+				</view>
 			</view>
-			<view class="nav-center">
-				<text class="nav-title">消息</text>
+			
+			<!-- 系统通知 -->
+			<view class="system-message-wrapper flex align-center" @click="goMsg">
+				<view class="system-message-image flex align-center justify-center">
+					<image src="/static/im/letter.svg" class="letter-icon"></image>
+				</view>
+				<view class="system-message-wrapper-r flex align-center justify-between">
+					<view class="flex align-center">
+						<text class="message-text">系统消息</text>
+						<text class="message-count" v-if="systemCount">{{ systemCount }}</text>					
+					</view>
+					<view class="system-message-time" v-if="systemCount">{{ systemMessageTime || '' }}</view>
+				</view>
 			</view>
-			<view class="nav-right">
-				<u-icon name="bell" color="rgba(56, 58, 63, 1)" size="40" style="margin-right: 20rpx;"></u-icon>
-				<u-icon name="setting" color="rgba(56, 58, 63, 1)" size="40" @click="showSettingsModal"></u-icon>
+			
+			<!-- 搜索栏 -->
+			<view class="search-bar flex align-center" v-if="isLogin" @click="goSearch">
+				<image src="@/static/images/svg/search.svg" class="search-icon"></image>
+				搜索聊天记录
+			</view>
+			
+			<!-- tabs -->
+			<view class="tabs-wrapper flex align-center justify-between" v-if="isLogin">
+				<view
+					class="tab"
+					v-for="(tab, index) in prevTabs"
+					:class="{ 'active-tab': selectedTab == tab.type }"
+					:key="tab.type + index"
+					@click="changeTab(tab.type, 'fixed')">
+						{{ tab.name }}
+						<template v-if="userType == 1 && unreadCount && tab.type == 'unread'">({{ unreadCount }})</template>
+					</view>
+				<view
+					class="tab"
+					v-for="(tab, index) in midTabs"
+					:class="{ 'active-tab': selectedTab == tab.type }"
+					:key="tab.type + index"
+					@click="changeTab(tab.type)">{{ tab.name }}</view>
+				<view class="icon-wrapper">
+					<image src="/static/im/more.svg" class="more-icon" @click="showTabModal = true"></image>
+					<u-mask :show="showTabModal" @click="showTabModal = false">
+						<view class="tabs-list" :style="{ top: `calc(${BarHeight}px + 370rpx)` }">
+							<view class="tab-item" v-for="(tab, index) in endTabs" :key="tab.type + index" @click.stop="changeTab(tab.type)">{{ tab.name }}</view>
+						</view>						
+					</u-mask>
+				</view>
 			</view>
+			
+			<!-- 聊天列表 -->
+			<template v-if="chatList.length">
+				<scroll-view
+					class="scroll-view"
+					:style="{ height: `calc(100vh - 480rpx - ${BarHeight}px)` }"
+					:scroll-y="true"
+					:refresher-threshold="100"
+					:refresher-enabled="true"
+					:refresher-triggered="isRefreshing"
+					scroll-with-animation="true"
+					@refresherrefresh="handleRefresh">
+					<view class="list">
+						<view
+							class="chat-item flex justify-between"
+							v-for="item in chatList"
+							:key="item.chatConversationId"
+							@click="goIM(item)"
+							@longpress="confirmDelete(item)">
+							<view class="avatar-wrapper">
+								<image :src="item.avatar || '/static/logo.png'" mode="aspectFill" class="avatar"></image>
+								<view class="online-dot" v-if="item.onlineStatus == 'ONLINE'"></view>
+							</view>
+							<view class="chat-info-wrapper flex justify-between">
+								<view class="chat-info-wrapper-l">
+									<view class="chat-info-wrapper-l-t flex align-center">
+										<view class="user-name">{{ item.userName }}</view>
+										<view class="tip-wrapper">
+											<text class="text-tip" v-if="item.companyName">{{ item.companyName }}</text>
+											<text class="text-tip" style="margin: 0 6rpx;" v-if="item.companyName && item.stationName"> | </text>
+											<text class="text-tip" v-if="item.stationName">{{ item.stationName }}</text>
+										</view>
+									</view>
+									<view class="chat-info-wrapper-l-b">
+										<template v-if="item.messageType == 1">{{item.content}}</template>
+										<template v-else-if="item.messageType == 10">简历已发送</template>
+										<template v-else-if="item.messageType == 18">位置</template>
+										<template v-else-if="item.messageType == 9">简历请求</template>
+										<template v-else-if="item.messageType == 6">微信请求</template>
+										<template v-else-if="item.messageType == 5">手机号请求</template>
+										<template v-else-if="item.messageType == 2">[图片]</template>
+										<template v-else-if="item.messageType == 3">[语音]</template>
+										<template v-else-if="item.messageType == 7">[交换手机]</template>
+										<template v-else-if="item.messageType == 8">[交换微信]</template>
+										<template v-else-if="item.messageType == 12">{{item.content}}已拒绝</template>
+										<template v-else-if="item.messageType == 4">
+											<image
+												class="chat-listitem-text"
+												v-if="item.content && item.messageType === 4"
+												:src="ossUrl +item.content"
+												style="height: 40rpx;width: 40rpx;"
+											></image>
+										</template>
+										<template v-else-if="item.messageType == 20">[视频通话]</template>
+										<template v-else-if="item.messageType == 21">[语音通话]</template>
+										<template v-else-if="item.messageType == 99">[面试邀约]</template>
+										<template v-else-if="item.messageType == 98">[{{item.content}}]</template>
+										<template v-else-if="item.messageType == 96 || item.messageType == 97">[{{item.content}}]</template>
+										<template v-else>[其他消息类型]</template>
+									</view>
+								</view>
+								<view class="chat-info-wrapper-r">
+									<view class="chat-info-wrapper-r-t">
+										<image src="/static/im/toUp.svg" class="up-icon" v-if="showIsTop(item)"></image>
+									</view>
+									<view class="chat-time" v-if="item.messageTime">{{ getMonthOrDay(item.messageTime) }}</view>
+									<view class="count-wrapper">
+										<view class="count" v-if="item.contentCount">{{ item.contentCount }}</view>
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+				</scroll-view>
+			</template>
+			
+			<empty v-if="!chatList.length" content='暂无消息'></empty>
 		</view>
 		
-		<view class="chat-title">聊天</view>
+		<!-- <view class="chat-title">聊天</view> -->
 		
-		<view v-if="msgList.length" class="margin-topW">
+		<!-- <view v-if="msgList.length" class="margin-topW">
 			<view class="flex padding-tb radius padding-lr-sm bg" @click="goMsg" v-for="(item,index) in msgList"
 				:key='index'>
 				<view>
@@ -36,35 +163,14 @@
 					</view>
 				</view>
 			</view>
-		</view>
-		<!-- <view class="margin-topW">
-			<view class="flex padding-tb radius padding-lr-sm bg" @click="goChat">
-				<view>
-					<image style="width: 80rpx;height: 80rpx;border-radius: 80rpx;"
-						src="../../static/images/msg/msgs.png"></image>
-				</view>
-				<view class="flex-sub margin-left-sm">
-					<view class="flex justify-between">
-						<view class="text-white">在线客服</view>
-						<view v-if="userCount>0"
-							style="height: 32rpx;width: 32rpx;border-radius: 100rpx;background-color: red;color: #FFF;text-align: center;">
-							{{userCount}}
-						</view>
-					</view>
-					<view>
-						<view class="text-grey">联系在线客服</view>
-					</view>
-				</view>
-			</view>
 		</view> -->
 
-		<view v-if="chatList.length" class="margin-top-sm  content ">
+		<!-- <view v-if="chatList.length" class="margin-top-sm  content ">
 			<view class="radius padding-lr-sm bg" style="margin-top: 4rpx;" @click="goIM(item)" @longpress="confirmDelete(item)"
 				v-for="(item,index) in chatList" :key='index'>
 				<view class="flex padding-tb ">
 					<view class="avatar-container">
 						<u-image shape="circle" width='80rpx' height="80rpx" :src="item.avatar"></u-image>
-						<!-- <view class="online-dot"></view> -->
 					</view>
 					<view class="flex-sub margin-left-sm" style="overflow: hidden;">
 						<view class="flex justify-between align-center">
@@ -110,33 +216,10 @@
 						</view>
 					</view>
 				</view>
-				<!-- <view class="flex padding-tb" v-else>
-					<view>
-						<u-image shape="circle" width='80rpx' height="80rpx" :src="item.avatar"></u-image>
-					</view>
-					<view class="flex-sub margin-left-sm">
-						<view class="flex justify-between">
-							<view class="text-white">{{item.userName}}</view>
-							<view class="text-grey">{{item.messageTime?item.messageTime:''}}</view>
-						</view>
-						<view class="flex justify-between">
-							<view class="text-grey" v-if="item.messageType == 1">{{item.content}}</view>
-							<view class="text-grey" v-else-if="item.messageType == 18">位置</view>
-							<view class="text-grey" v-else-if="item.messageType == 9">简历请求</view>
-							<view class="text-grey" v-else-if="item.messageType == 6">微信请求</view>
-							<view class="text-grey" v-else-if="item.messageType == 5">手机号请求</view>
-							<view class="text-grey" v-else>[图片]</view>
-							<view v-if="item.contentCount"
-								style="height: 32rpx;width: 32rpx;border-radius: 100rpx;background-color: red;color: #FFF;text-align: center;">
-								{{item.contentCount}}
-							</view>
-						</view>
-					</view>
-				</view> -->
 			</view>
-		</view>
+		</view> -->
 
-		<empty v-if="!chatList.length" content='暂无消息'></empty>
+		<!-- <empty v-if="!chatList.length" content='暂无消息'></empty> -->
 		
 		<!-- 消息设置弹窗 -->
 		<u-popup v-model="showSettings" mode="bottom" :mask-close-able="true" border-radius="20">
@@ -188,62 +271,172 @@
 <script>
 	import empty from '../../components/empty.vue'
 	import configData from '../../common/config.js'
+
+	// 求职端tabs
+	// 显示:全部(固定)、未读(固定)、新招呼、仅沟通、有交换、有面试
+	const JobApplicationTab = [
+		{
+			type: '',
+			name: '全部'
+		},
+		{
+			type: 'unread',
+			name: '未读'
+		},
+		{
+			type: 'new',
+			name: '新招呼'
+		},
+		{
+			type: 'communicating',
+			name: '仅沟通'
+		},
+		{
+			type: 'exchanged',
+			name: '有交换'
+		},
+		{
+			type: 'interview',
+			name: '有面试'
+		},
+	]
+	
+	// 招聘端tabs
+	// 显示:全部(固定)、新招呼(固定)、沟通中、已约面、已获取简历、已交换电话、已交换微信、收藏
+	const RecruitmentTab = [
+		{
+			type: '',
+			name: '全部'
+		},
+		{
+			type: 'new',
+			name: '新招呼'
+		},
+		{
+			type: 'communicating',
+			name: '沟通中'
+		},
+		{
+			type: 'interview',
+			name: '已约面'
+		},
+		{
+			type: 'gotResume',
+			name: '已获取简历'
+		},
+		{
+			type: 'gotPhone',
+			name: '已交换电话'
+		},
+		{
+			type: 'gotWx',
+			name: '已交换微信'
+		},
+		{
+			type: 'collected',
+			name: '收藏'
+		},
+	] 
+	
 	export default {
 		components: {
 			empty
 		},
 		data() {
 			return {
-				BarHeight:'',
+				BarHeight: 0,
 				page: 1,
 				limit: 100,
 				chatList: [],
-				userId: '',
 				msgList: [],
 				time: '',
 				messageCount: 0,
-				userCount: 0,
+				// userCount: 0,
 				arr: [],
 				showModal: true,
 				showSettings: false, // 控制设置弹窗显示
 				notificationEnabled: true, // 消息通知开关状态
-				ossUrl:configData.ossUrl
-			}
-		},
-		onLoad() {
-			if (uni.getStorageSync('userId')) {
-				this.getChatList()
+				ossUrl:configData.ossUrl,
+				tabs: [],
+				selectedTab: '',
+				isRefreshing: false,
+				total: 0,
+				userType: null,
+				showTabModal: false,
+				systemCount: 0, // 系统消息数量
+				systemMessageTime: '', // 系统消息时间
+				refreshTime: '', // 更新时间戳
+				isLogin: false,
+				unreadCount: 0
 			}
-
 		},
-		//下拉刷新
-		onPullDownRefresh() {
-			let that = this
-			if (uni.getStorageSync('token')) {
-				that.getweiduMsg();
-				that.getChatList()
-				that.getMsgList()
-				that.$nextTick(function() {
-					that.messageCount = uni.getStorageSync('messageCount')
-				})
+		computed: {
+			prevTabs() {
+				return this.tabs.slice(0, 2)
+			},
+			midTabs() {
+				return this.tabs.slice(2, 4)
+			},
+			endTabs() {
+				return this.tabs.slice(4)
 			}
 		},
-		onShow() {
+		onLoad() {
 			// #ifdef APP-PLUS
 			let systemInfo = uni.getSystemInfoSync();
 			this.BarHeight = systemInfo.statusBarHeight;
 			// #endif
-			let that = this
-			that.userId = uni.getStorageSync('userId')
-			if (that.userId) {
-				that.time = setInterval(function() {
-					that.getweiduMsg();
-					that.getChatList()
-					that.getMsgList()
-					that.$nextTick(function() {
-						that.messageCount = uni.getStorageSync('messageCount')
-					})
 
+			uni.$on('chatUnreadCount', (data) => {
+				if (this.userType === 1) {
+					this.unreadCount = data
+				}
+			})
+		},
+		onUnload() {
+			uni.$off('chatUnreadCount')
+		},
+		// //下拉刷新
+		// onPullDownRefresh() {
+		// 	let that = this
+		// 	if (uni.getStorageSync('token')) {
+		// 		that.getweiduMsg();
+		// 		that.getChatList()
+		// 		that.getMsgList()
+		// 		that.$nextTick(function() {
+		// 			that.messageCount = uni.getStorageSync('messageCount')
+		// 		})
+		// 	}
+		// },
+		onShow() {
+			if (uni.getStorageSync('token')) {
+				const userType = uni.getStorageSync('userType') || null
+				if (this.userType != userType) {
+					this.userType = userType
+					this.init()
+				} else {
+					// if (this.userType == 1) {
+					// 	this.getUnreadCount()
+					// }
+					this.getChatList()
+					this.getMsgList()
+				}
+				
+				this.isLogin = true
+				this.time = setInterval(() => {
+					const newTime = (new Date()).getTime()
+					// 判断上一次请求是否大于3s
+					if (this.refreshTime + 3000 < newTime) {
+						// this.getweiduMsg();
+						// if (this.userType == 1) {
+						// 	this.getUnreadCount()
+						// }
+						this.getChatList()
+						this.getMsgList()
+						this.$nextTick(() => {
+							this.messageCount = uni.getStorageSync('messageCount')
+						})
+					}
 				}, 3000)
 				this.$Request.getT('/app/common/type/310').then(res => { //消息未读提醒
 					if (res.code == 0) {
@@ -266,20 +459,57 @@
 						}
 					}
 				})
-				// #ifdef MP-WEIXIN
-				if (this.showModal) {
-					this.openMsg()
-				}
-				// #endif
+				// // #ifdef MP-WEIXIN
+				// if (this.showModal) {
+				// 	this.openMsg()
+				// }
+				// // #endif
 			} else {
-				that.chatList = []
-				that.msgList = []
+				this.isLogin = false
+				this.chatList = []
+				this.msgList = []
 			}
 		},
 		onHide() {
 			clearInterval(this.time)
 		},
 		methods: {
+			// 初始化
+			init() {
+				// if (this.userType == 1) {
+				// 	this.getUnreadCount()
+				// }
+				this.setTabs()
+				this.getChatList()
+				this.getMsgList()
+			},
+			
+			// 设置tabs
+			setTabs() {
+				const userType = this.$queue.getData('userType')
+				if (userType == 1) {
+					this.tabs = JobApplicationTab
+				} else if (userType == 2) {
+					this.tabs = RecruitmentTab
+				}
+			},
+			
+			changeTab(type, isFixed = '') {
+				if (!isFixed) {
+					const index = this.tabs.findIndex(tab => tab.type == type)
+					if (index > -1) {
+						const tabItem = this.tabs.splice(index, 1)
+						this.tabs.splice(2, 0, ...tabItem)
+					}
+				}
+				if (this.showTabModal) {
+					this.showTabModal = false
+				}
+				this.selectedTab = type
+				this.page = 1
+				this.getChatList()
+			},
+			
 			confirmDelete(item){
 				uni.showModal({
 					title: '提示',
@@ -305,6 +535,15 @@
 					}
 				});
 			},
+			// 显示置顶
+			showIsTop(item) {
+				if (this.userType == 1) {
+					return Boolean(item.isTop)
+				} else if (this.userType == 2) {
+					return Boolean(item.isTopQiye)
+				}
+				return false
+			},
 			//把时间转换为月日
 			getMonthOrDay(data) {
 				// 1️⃣ 手动解析字符串,避免 iOS 时区问题
@@ -349,69 +588,69 @@
 							
 				return result;
 			},
-			// 开启订阅消息
-			openMsg() {
-				console.log('订阅消息')
-				var that = this
-				uni.getSetting({
-					withSubscriptions: true, //是否获取用户订阅消息的订阅状态,默认false不返回
-					success(ret) {
-						console.log(ret.subscriptionsSetting.itemSettings, '*************************************')
-						// if (ret.subscriptionsSetting.itemSettings && Object.keys(ret.subscriptionsSetting.itemSettings).length == 2) {
-						if (ret.subscriptionsSetting.itemSettings) {
-							uni.setStorageSync('sendMsg', true)
-							uni.openSetting({ // 打开设置页 
-								success(rea) {
-									console.log(rea.authSetting)
-								}
-							});
-						} else { // 用户没有点击“总是保持以上,不再询问”则每次都会调起订阅消息
-							uni.setStorageSync('sendMsg', false)
-							uni.showModal({
-								title: '提示',
-								content: '为了更好的体验,请绑定消息推送',
-								confirmText: '确定',
-								cancelText: '取消',
-								confirmColor: '#016BF6',
-								success: function(res) {
-									if (res.confirm) {
-										wx.requestSubscribeMessage({
-											tmplIds: that.arr,
-											success(re) {
-												console.log(JSON.stringify(re),
-													'++++++++++++++')
-												var datas = JSON.stringify(re);
-												if (datas.indexOf("accept") != -1) {
-													console.log(re)
-													// uni.setStorageSync('sendMsg', true)
-												}
-											},
-											fail: (res) => {
-												console.log(res)
-											}
-										})
-										// uni.setStorageSync('sendMsg', true)
-										console.log('确认')
-										that.showModal = false
-									} else if (res.cancel) {
-										console.log('取消')
-										// uni.setStorageSync('sendMsg', false)
-										that.showModal = true
-									}
-								}
-							})
-						}
-					}
-				})
-			},
-			getweiduMsg() {
-				this.$Request.get("/app/chats/userCount").then(res => {
-					uni.stopPullDownRefresh()
-					if (res.code == 0) {
-						this.userCount = res.data
-					}
-				});
-			},
+			// // 开启订阅消息
+			// openMsg() {
+			// 	console.log('订阅消息')
+			// 	var that = this
+			// 	uni.getSetting({
+			// 		withSubscriptions: true, //是否获取用户订阅消息的订阅状态,默认false不返回
+			// 		success(ret) {
+			// 			console.log(ret.subscriptionsSetting.itemSettings, '*************************************')
+			// 			// if (ret.subscriptionsSetting.itemSettings && Object.keys(ret.subscriptionsSetting.itemSettings).length == 2) {
+			// 			if (ret.subscriptionsSetting.itemSettings) {
+			// 				uni.setStorageSync('sendMsg', true)
+			// 				uni.openSetting({ // 打开设置页 
+			// 					success(rea) {
+			// 						console.log(rea.authSetting)
+			// 					}
+			// 				});
+			// 			} else { // 用户没有点击“总是保持以上,不再询问”则每次都会调起订阅消息
+			// 				uni.setStorageSync('sendMsg', false)
+			// 				uni.showModal({
+			// 					title: '提示',
+			// 					content: '为了更好的体验,请绑定消息推送',
+			// 					confirmText: '确定',
+			// 					cancelText: '取消',
+			// 					confirmColor: '#016BF6',
+			// 					success: function(res) {
+			// 						if (res.confirm) {
+			// 							wx.requestSubscribeMessage({
+			// 								tmplIds: that.arr,
+			// 								success(re) {
+			// 									console.log(JSON.stringify(re),
+			// 										'++++++++++++++')
+			// 									var datas = JSON.stringify(re);
+			// 									if (datas.indexOf("accept") != -1) {
+			// 										console.log(re)
+			// 										// uni.setStorageSync('sendMsg', true)
+			// 									}
+			// 								},
+			// 								fail: (res) => {
+			// 									console.log(res)
+			// 								}
+			// 							})
+			// 							// uni.setStorageSync('sendMsg', true)
+			// 							console.log('确认')
+			// 							that.showModal = false
+			// 						} else if (res.cancel) {
+			// 							console.log('取消')
+			// 							// uni.setStorageSync('sendMsg', false)
+			// 							that.showModal = true
+			// 						}
+			// 					}
+			// 				})
+			// 			}
+			// 		}
+			// 	})
+			// },
+			// getweiduMsg() {
+			// 	this.$Request.get("/app/chats/userCount").then(res => {
+			// 		uni.stopPullDownRefresh()
+			// 		if (res.code == 0) {
+			// 			this.userCount = res.data
+			// 		}
+			// 	});
+			// },
 			//在线客服
 			goChat() {
 				// uni.navigateTo({
@@ -480,21 +719,29 @@
 
 			},
 			getChatList() {
+				this.refreshTime = (new Date()).getTime()
 				this.$Request.get("/app/chat/selectChatConversationPage", {
 					page: this.page,
-					limit: this.limit
+					limit: this.limit,
+					type: this.selectedTab
 				}).then(res => {
-					uni.stopPullDownRefresh()
+					// uni.stopPullDownRefresh()
 					if (res.code == 0) {
-						this.chatList = res.data.list
+						this.chatList = this.page != 1 ? [...this.chatList, ...res.data.list] : res.data.list
+						this.total = res.data.totalCount
 					}
+				}).finally(() => {
+					this.refreshTime = (new Date()).getTime()
+					this.isRefreshing = false
 				});
 			},
 			getMsgList() {
-				this.$Request.get("/app/message/selectMessageByUserIdLimit1").then(res => {
-					uni.stopPullDownRefresh()
+				this.$Request.get("/app/message/selectMessageCountByUserId").then(res => {
+					// uni.stopPullDownRefresh()
 					if (res.code == 0) {
-						this.msgList = res.data.list
+						// this.msgList = res.data.list
+						this.systemCount = res.data.count
+						this.systemMessageTime = res.data.lastTime
 					}
 				});
 			},
@@ -519,7 +766,6 @@
 				// #endif
 				let userId = '';
 				let userType = uni.getStorageSync('userType')
-				console.log(e, 'aaaaaaaaa')
 				if (userType == 2) { //当前登录用户为企业
 					userId = e.userId
 				} else { //当前登录用户为用户
@@ -539,24 +785,7 @@
 
 			},
 			goMsg() {
-				// #ifdef MP-WEIXIN
-				if (uni.getStorageSync('sendMsg')) {
-					// console.log('授权+1')
-					wx.requestSubscribeMessage({
-						tmplIds: this.arr,
-						success(re) {
-							// console.log(JSON.stringify(re), 111111111111)
-							var datas = JSON.stringify(re);
-							if (datas.indexOf("accept") != -1) {
-								// console.log(re)
-							}
-						},
-						fail: (res) => {
-							// console.log(res)
-						}
-					})
-				}
-				// #endif
+				if (!this.isLogin) return
 				uni.navigateTo({
 					url: '/pages/msg/message'
 				})
@@ -591,14 +820,44 @@
 				uni.navigateTo({
 					url: '/pages/msg/search'
 				})
-			}
+			},
+			// 刷新
+			handleRefresh() {
+				if (!uni.getStorageSync('token')) {
+					return this.isRefreshing = false
+				}
+				if (this.isRefreshing) return
+				this.isRefreshing = true
+				this.page = 1
+				this.getChatList()
+				this.getMsgList()
+			},
+			// // 加载更多
+			// loadMore() {
+			// 	console.log('加载更多')
+			// 	if (this.loading || this.chatList.length >= this.total || !uni.getStorageSync('token')) return
+			// 	this.page++
+			// 	this.getChatList()
+			// },
+			
+			// // 获取未读消息数量
+			// getUnreadCount() {
+			// 	this.$Request.getT('/app/message/selectMessageCountByUserId')
+			// 		.then(res => {
+			// 			if (res.code == 0) {
+			// 				this.unreadCount = res.data.count
+			// 			}
+			// 		})
+			// }
 		}
 	}
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
 	.msg-box {
-		// padding-top: 80rpx;
+		display: flex;
+		flex-direction: column;
+		font-family: DM Sans;
 
 		.chat-title {
 			background: linear-gradient(180deg, rgba(13, 39, 247, 1) 0%, rgb(191, 194, 201) 100%);
@@ -651,35 +910,255 @@
 			justify-content: flex-end;
 			align-items: center;
 		}
-
-		.bg {
-			background: #FFFFFF;
+		
+		// 系统通知
+		.system-message-wrapper {
+			padding: 10rpx 0 0 32rpx;
+			.system-message-image {
+				width: 80rpx;
+				height: 80rpx;
+				background: linear-gradient(90.00deg, rgba(13, 39, 247, 1),rgba(19, 193, 234, 1));
+				border-radius: 50%;
+				margin-right: 32rpx;
+				.letter-icon {
+					width: 36rpx;
+					height: 28rpx;
+				}
+			}
+			.system-message-wrapper-r {
+				flex: 1;
+				height: 100%;
+				padding: 20rpx 32rpx 20rpx 16rpx;
+				border-bottom: 1px solid rgba(235, 236, 240, 1);
+				.message-text {
+					color: rgba(21, 22, 26, 1);
+					font-size: 32rpx;
+					font-weight: 400;
+				}
+				.message-count {
+					min-width: 32rpx;
+					height: 32rpx;
+					line-height: 32rpx;
+					padding: 0 10rpx;
+					color: #fff;
+					font-size: 20rpx;
+					background: rgba(240, 35, 35, 1);
+					border-radius: 32rpx;
+					box-sizing: border-box;
+					margin-left: 20rpx;
+				}
+				.system-message-time {
+					color: rgba(189, 191, 198, 1);
+					font-size: 20rpx;
+					font-weight: 400;
+				}
+			}
 		}
-
-		.userNameleng {
-			// width: 80%;
-			flex: 1;
-			overflow: hidden;
-			white-space: nowrap;
-			text-overflow: ellipsis;
-			-o-text-overflow: ellipsis;
+		
+		// 搜索栏
+		.search-bar {
+			border: 1px solid rgba(231, 230, 228, 1);
+			border-radius: 12rpx;
+			background: rgba(237, 237, 237, 1);
+			padding: 16rpx 24rpx;
+			color: rgba(188, 188, 188, 1);
+			font-size: 28rpx;
+			margin: 24rpx 32rpx 24rpx;
+			.search-icon {
+				width: 32rpx;
+				height: 32rpx;
+				margin-right: 16rpx;
+			}
 		}
-
-		.avatar-container {
-			position: relative;
-			display: inline-block;
+		
+		// tabs
+		.tabs-wrapper {
+			padding: 8rpx 32rpx;
+			margin-bottom: 16rpx;
+			.tab {
+				padding: 8rpx 24rpx;
+				border-radius: 50rpx;
+				background: rgba(0, 0, 0, 0.04);
+				color: rgba(102, 102, 102, 1);
+				font-size: 24rpx;
+				font-weight: 400;
+				line-height: 28rpx;
+				&.active-tab {
+					font-weight: 500;
+					color: rgba(1, 107, 246, 1);
+					background: rgba(1, 107, 246, 0.1);
+				}
+			}
+			.icon-wrapper {
+				position: relative;
+				padding: 8rpx;
+				.more-icon {
+					width: 36rpx;
+					height: 36rpx;
+				}
+				.tabs-list {
+					position: absolute;
+					right: 30rpx;
+					width: 268rpx;
+					background: #fff;
+					border-radius: 4px;
+					box-shadow: 0px 3px 6px -4px rgba(0, 0, 0, 0.12),0px 6px 16px 0px rgba(0, 0, 0, 0.08),0px 9px 28px 8px rgba(0, 0, 0, 0.05);
+					z-index: 10;
+					.tab-item {
+						text-align: center;
+						color: rgba(102, 102, 102, 1);
+						font-size: 14px;
+						font-weight: 400;
+						line-height: 34px;
+					}
+				}
+			}
 		}
-
-		.online-dot {
-			position: absolute;
-			bottom: 2rpx;
-			right: 2rpx;
-			width: 20rpx;
-			height: 20rpx;
-			background-color: #00FF00;
-			border-radius: 50%;
-			border: 2rpx solid #FFFFFF;
+		
+		// 聊天列表
+		.scroll-view {
+			.chat-item {
+				padding-left: 32rpx;
+				padding-bottom: 16rpx;
+				margin-bottom: 20rpx;
+				.avatar-wrapper {
+					position: relative;
+					width: 96rpx;
+					height: 128rpx;
+					margin-right: 16rpx;
+					padding-top: 32rpx;
+					.avatar {
+						display: block;
+						width: 100%;
+						height: 100%;
+						border: 1px solid #eee;
+						border-radius: 50%;
+					}
+					.online-dot {
+						position: absolute;
+						right: 8rpx;
+						bottom: 0;
+						width: 16rpx;
+						height: 16rpx;
+						border: 1px solid rgba(255, 255, 255, 1);
+						background: rgba(0, 180, 42, 1);
+						border-radius: 50%;
+					}
+				}
+				
+				.chat-info-wrapper {
+					flex: 1;
+					padding-right: 32rpx;
+					padding-bottom: 24rpx;
+					border-bottom: 1px solid rgba(235, 236, 240, 1);
+					.chat-info-wrapper-l {
+						flex: 1;
+						width: 400rpx;
+						padding-top: 28rpx;
+					}
+					.user-name {
+						// max-width: 130rpx;
+						max-width: 70%;
+						color: rgba(21, 22, 26, 1);
+						font-size: 32rpx;
+						font-weight: 400;
+						margin-right: 16rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+					.tip-wrapper {
+						max-width: 70%;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+					.text-tip {
+						color: rgba(117, 119, 124, 1);
+						font-size: 20rpx;
+						font-weight: 400;
+					}
+					.chat-info-wrapper-l-b {
+						width: 100%;
+						color: rgba(117, 119, 124, 1);
+						font-size: 24rpx;
+						font-weight: 400;
+						line-height: 36rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+					
+					.chat-info-wrapper-r-t {
+						display: flex;
+						justify-content: flex-end;
+						width: 100%;
+						height: 40rpx;
+						.up-icon {
+							display: block;
+							width: 40rpx;
+							height: 40rpx;
+						}
+					}
+					.chat-time {
+						color: rgba(189, 191, 198, 1);
+						font-size: 24rpx;
+						font-weight: 400;
+						line-height: 40rpx;
+					}
+					.count-wrapper {
+						display: flex;
+						justify-content: flex-end;
+						width: 100%;
+						height: 32rpx;
+						.count {
+							min-width: 32rpx;
+							line-height: 32rpx;
+							border-radius: 32rpx;
+							color: #fff;
+							font-size: 20rpx;
+							padding: 0 10rpx;
+							background: rgba(245, 63, 63, 1);
+						}
+					}
+				}
+				
+				&:last-child {
+					.chat-info-wrapper {
+						border-bottom: 0;
+					}
+				}
+			}
 		}
+
+		// .bg {
+		// 	background: #FFFFFF;
+		// }
+
+		// .userNameleng {
+		// 	// width: 80%;
+		// 	flex: 1;
+		// 	overflow: hidden;
+		// 	white-space: nowrap;
+		// 	text-overflow: ellipsis;
+		// 	-o-text-overflow: ellipsis;
+		// }
+
+		// .avatar-container {
+		// 	position: relative;
+		// 	display: inline-block;
+		// }
+
+		// .online-dot {
+		// 	position: absolute;
+		// 	bottom: 2rpx;
+		// 	right: 2rpx;
+		// 	width: 20rpx;
+		// 	height: 20rpx;
+		// 	background-color: #00FF00;
+		// 	border-radius: 50%;
+		// 	border: 2rpx solid #FFFFFF;
+		// }
 	}
 	
 	// 设置弹窗样式

+ 69 - 31
pages/msg/search.vue

@@ -18,14 +18,13 @@
 				<input 
 					v-model="searchKeyword" 
 					class="search-input" 
-					placeholder="您好" 
-					placeholder-style="color: #999999; font-size: 16px;"
-					@input="onSearchInput"
+					placeholder="请输入搜索内容" 
+					placeholder-style="color: #999; font-size: 14px;"
 					@confirm="onSearchConfirm"
 				/>
 			</view>
-			<view class="cancel-btn" @click="goBack">
-				<text class="cancel-text">取消</text>
+			<view class="cancel-btn" @click="onSearchConfirm">
+				<text class="confirm-text">搜索</text>
 			</view>
 		</view>
 		
@@ -42,7 +41,7 @@
 					<view class="flex padding-tb">
 						<view class="avatar-container">
 							<u-image shape="circle" width='80rpx' height="80rpx" :src="item.avatar"></u-image>
-							<view class="online-dot"></view>
+							<view class="online-dot" v-if="item.onlineStatus == 'ONLINE'"></view>
 						</view>
 						<view class="flex-sub margin-left-sm">
 							<view class="flex justify-between align-center">
@@ -50,26 +49,35 @@
 									<view class="text-white" style="font-size: 28rpx;">
 										{{item.userName}}
 									</view>
-									<text class="text-grey"
-										style="font-size: 22rpx;margin-left: 10rpx;">{{item.stationName}}
+									<text class="text-grey" style="font-size: 22rpx;margin-left: 10rpx;">
+										<template v-if="userType == 2">
+											{{ item.companyName }}
+											<text> | </text>
+											{{ item.hrPosition }}
+										</template>
+										<template v-else>{{ item.stationName }}</template>
 									</text>
 								</view>
-								<view class="text-grey">{{item.messageTime ? getMonthOrDay(item.messageTime) : ''}}</view>
+								<view class="text-grey">{{item.createTime ? getMonthOrDay(item.createTime) : ''}}</view>
 							</view>
 							<view class="flex justify-between" style="margin-top: 10rpx;">
 								<view class="text-grey" v-if="item.messageType == 1">{{item.content}}</view>
-								<view class="text-grey" v-else-if="item.messageType == 18">位置</view>
-								<view class="text-grey" v-else-if="item.messageType == 9">简历请求</view>
-								<view class="text-grey" v-else-if="item.messageType == 6">微信请求</view>
-								<view class="text-grey" v-else-if="item.messageType == 5">手机号请求</view>
 								<view class="text-grey" v-else-if="item.messageType == 2">[图片]</view>
+								<view class="text-grey" v-else-if="item.messageType == 3">[语音]</view>
 								<view class="text-grey" v-else-if="item.messageType == 4">[表情]</view>
+								<view class="text-grey" v-else-if="item.messageType == 5">手机号请求</view>
+								<view class="text-grey" v-else-if="item.messageType == 6">微信请求</view>
+								<view class="text-grey" v-else-if="item.messageType == 7">[交换手机]</view>
+								<view class="text-grey" v-else-if="item.messageType == 8">[交换微信]</view>
+								<view class="text-grey" v-else-if="item.messageType == 9">简历请求</view>
+								<view class="text-grey" v-else-if="item.messageType == 10">简历已发送</view>
+								<view class="text-grey" v-else-if="item.messageType == 12">{{item.content}}已拒绝</view>
+								<view class="text-grey" v-else-if="item.messageType == 18">位置</view>
 								<view class="text-grey" v-else-if="item.messageType == 20">[视频通话]</view>
 								<view class="text-grey" v-else-if="item.messageType == 21">[语音通话]</view>
-								<view v-if="item.contentCount"
-									style="height: 32rpx;width: 32rpx;border-radius: 100rpx;background-color: red;color: #FFF;text-align: center;">
-									{{item.contentCount}}
-								</view>
+								<view class="text-grey" v-else-if="item.messageType == 96 || item.messageType == 97 || item.messageType == 98">[{{item.content}}]</view>
+								<view class="text-grey" v-else-if="item.messageType == 99">[面试邀约]</view>
+								<view v-else>[其他消息类型]</view>
 							</view>
 						</view>
 					</view>
@@ -83,7 +91,7 @@
 		</view>
 		
 		<!-- 默认状态 -->
-		<view class="default-state" v-if="!searchKeyword && !loading">
+		<view class="default-state" v-if="!searchKeyword && !loading && !searchResults.length">
 			<text class="default-text">请输入关键词搜索消息</text>
 		</view>
 	</view>
@@ -98,9 +106,11 @@ export default {
 			searchResults: [],
 			allChatList: [], // 存储所有聊天记录
 			page: 1,
-			limit: 100,
+			limit: 10,
+			total: 0,
 			loading: false,
-			hasMore: true
+			hasMore: true,
+			userType: null
 		}
 	},
 	onLoad() {
@@ -108,13 +118,14 @@ export default {
 		let systemInfo = uni.getSystemInfoSync();
 		this.statusBarHeight = systemInfo.statusBarHeight || 0;
 		// 页面加载时获取聊天记录
-		this.getChatList()
+		// this.getChatList()
+		this.userType = this.$queue.getData('userType') || null
 	},
 	// 下拉刷新
 	onPullDownRefresh() {
 		this.page = 1
 		this.hasMore = true
-		this.getChatList()
+		// this.getChatList()
 		setTimeout(() => {
 			uni.stopPullDownRefresh()
 		}, 1000)
@@ -123,12 +134,16 @@ export default {
 		goBack() {
 			uni.navigateBack()
 		},
-		onSearchInput(e) {
-			this.searchKeyword = e.detail.value
-			this.performSearch()
-		},
+		// onSearchInput(e) {
+		// 	this.searchKeyword = e.detail.value
+		// 	this.performSearch()
+		// },
 		onSearchConfirm() {
-			this.performSearch()
+			// this.performSearch()
+			if (!this.searchKeyword.trim()) {
+				return this.$queue.showToast('请输入搜索内容')
+			}
+			this.getChatRecord()
 		},
 		// 获取聊天记录列表
 		getChatList() {
@@ -193,6 +208,25 @@ export default {
 			uni.navigateTo({
 				url: `/pages/msg/im?chatConversationId=${item.chatConversationId}&byUserId=${item.focusedUserId}&postPushId=${item.postPushId}&resumesId=${item.resumesId}`
 			})
+		},
+		getChatRecord() {
+			if (this.loading) return
+			
+			this.loading = true
+			uni.showLoading({ title: '加载中' })
+			this.$Request.getT('/app/chat/searchConversation', {
+				page: this.page,
+				limit: this.limit,
+				key: this.searchKeyword.toLowerCase()
+			}).then(res => {
+				console.log(res)
+				if (res.code == 0) {
+					this.searchResults = this.page == 1 ? res.data.records : [...this.searchResults, ...res.data.records]
+				}
+			}).finally(() => {
+				this.loading = false
+				uni.hideLoading()
+			})
 		}
 	}
 }
@@ -267,8 +301,8 @@ export default {
 	.cancel-btn {
 		padding: 10rpx 20rpx;
 		
-		.cancel-text {
-            color: rgba(153, 153, 153, 1);
+		.confirm-text {
+            color: rgba(1, 107, 246, 1);
             font-family: DM Sans;
             font-size: 14px;
             font-weight: 500;
@@ -295,6 +329,8 @@ export default {
 		
 		.avatar-container {
 			position: relative;
+			width: 80rpx;
+			height: 80rpx;
 			margin-right: 30rpx;
 			
 			.avatar {
@@ -305,7 +341,7 @@ export default {
 			
 			.online-dot {
 				position: absolute;
-				bottom: 5rpx;
+				bottom: 0rpx;
 				right: 5rpx;
 				width: 20rpx;
 				height: 20rpx;
@@ -420,11 +456,13 @@ export default {
 
 .avatar-container {
 	position: relative;
+	width: 80rpx;
+	height: 80rpx;
 }
 
 .online-dot {
 	position: absolute;
-	bottom: 5rpx;
+	bottom: 0rpx;
 	right: 5rpx;
 	width: 20rpx;
 	height: 20rpx;

+ 98 - 13
pages/my/index.vue

@@ -12,10 +12,11 @@
 				<view class="user-top">
 					<view class="info-box-btn flex justify-end align-center" style="padding-right: 32rpx;"
 						v-if="token && XCXIsSelect != '否'">
-						<image src="@/static/images/jobApplicant/qiehuan.svg" mode="scaleToFill"
-							style="margin-top: 40rpx;margin-right:30rpx" @click="goNav('switchRoles')" />
-						<image src="@/static/images/jobApplicant/shezhi.svg" mode="scaleToFill"
-							style="margin-top: 40rpx;" @click="goNav('/pages/my/setup')" />
+						<!-- #ifdef APP-PLUS -->
+						<image src="@/static/images/svg/scan.svg" @click="handleScan"></image>
+						<!-- #endif -->
+						<image src="@/static/images/jobApplicant/qiehuan.svg" @click="goNav('switchRoles')" />
+						<image src="@/static/images/jobApplicant/shezhi.svg" @click="goNav('/pages/my/setup')" />
 					</view>
 				</view>
 				<view class="user-content">
@@ -151,6 +152,10 @@
 								<image src="@/static/images/svg/building.svg" class="function-icon"></image>
 								<text class="function-text">屏蔽管理</text>
 							</view>
+							<view class="function-item" @click="goNav('/package/my/feedback/index')">
+								<image src="@/static/images/svg/edit.svg" class="function-icon"></image>
+								<text class="function-text">我要留言</text>
+							</view>
 						</view>
 					</view>
 					<view class="beian">客服电话 400-000-0100 工作时间08:00-22:00</view>
@@ -166,10 +171,11 @@
 					<view class="info flex justify-center">
 						<view class="info-box">
 							<view v-if="XCXIsSelect != '否'" class="info-box-btn flex justify-end align-center">
-								<image src="@/static/images/jobApplicant/qiehuan.svg" mode="scaleToFill"
-									style="margin-top: 40rpx;margin-right:30rpx" @click="goNav('switchRoles')" />
-								<image src="@/static/images/jobApplicant/shezhi.svg" mode="scaleToFill"
-									style="margin-top: 40rpx;" @click="goNav('/pages/my/setup')" />
+								<!-- #ifdef APP-PLUS -->
+								<image src="@/static/images/svg/scan.svg" @click="handleScan"></image>
+								<!-- #endif -->
+								<image src="@/static/images/jobApplicant/qiehuan.svg" @click="goNav('switchRoles')" />
+								<image src="@/static/images/jobApplicant/shezhi.svg" @click="goNav('/pages/my/setup')" />
 							</view>
 							<view class="info-box-header flex align-center" @click="goNav('/pages/my/userinfo')">
 								<view class="info-box-header-l">
@@ -309,6 +315,13 @@
 											我的客服
 										</view>
 									</view>
+									<view class="util-item" @click="goNav('/package/my/feedback/index')">
+										<image src="@/static/images/svg/edit.svg"
+											style="width: 54rpx; height: 54rpx" mode=""></image>
+										<view class="" style="color: #1a1a1a; font-size: 24rpx; margin-top: 15rpx">
+											我要留言
+										</view>
+									</view>
 								</view>
 							</view>
 						</view>
@@ -352,6 +365,12 @@
 		<c-modal :value="auditModal" title="提示" @cancel="auditModal = false" @confirm="handleAudit">
 			{{ modalMessage }}
 		</c-modal>
+		
+		<u-popup mode="top" ref="permission">
+			<view class="popup-content">
+				<view class="popup-text-permission">扫码需要相机权限</view>
+			</view>
+		</u-popup>
 	</view>
 </template>
 
@@ -424,6 +443,7 @@ export default {
 			showNotice:false,
 			score: 0, // 简历完善度
 			auditModal: false,
+			unverified: false,
 			modalMessage: '',
 		};
 	},
@@ -456,6 +476,13 @@ export default {
 			return false
 		},		
 	},
+	watch: {
+		auditModal(value) {
+			if (!value) {
+				this.unverified = false
+			}
+		}
+	},
 	onLoad(e) {
 		this.XCXIsSelect = this.$queue.getData("XCXIsSelect");
 		var that = this
@@ -1076,7 +1103,7 @@ export default {
 				}
 				// 跳转判断是否完成了认证信息完善
 				if (e == '/pages/my/myCompany') {
-					if (!this.checkUnAdminStatus({ unFinishCompanyInfo: true })) return
+					if (!this.checkUnAdminStatus({ notAudit: true, unFinishCompanyInfo: true })) return
 				}
 				uni.navigateTo({
 					url: e,
@@ -1344,8 +1371,9 @@ export default {
 					return false
 				}
 				// 企业认证信息未完善
-				if (options && options.unFinishCompanyInfo) {
+				if (options && options.unFinishCompanyInfo && !this.companyInfo?.companyDutyParagraph) {
 					this.modalMessage = '没有进行企业认证,是否立即认证!'
+					this.unverified = true
 					this.auditModal = true
 					return false
 				}
@@ -1361,12 +1389,67 @@ export default {
 		
 		// 重新提交审核
 		handleAudit() {
+			const companyId = this.companyInfo?.companyId
+			const companyName = this.companyInfo?.companyAllName
+			let url = this.unverified ? `/package/jobIntention/companyImg?companyId=${companyId}&companyName=${encodeURIComponent(companyName)}` : '/pages/my/businessLicense'
 			uni.navigateTo({
-				url: '/pages/my/businessLicense',
+				url,
 				success: () => {
 					this.auditModal = false
 				}
 			})
+		},
+		
+		// 扫码登录记录
+		handleScanRecord(scanToken) {
+			uni.showLoading({ title: '加载中' })
+			this.$Request
+				.post('/app/Login/scan', {
+					token: scanToken
+				})
+				.then(res => {
+					if (res.code == 0) {
+						uni.navigateTo({
+							url: `/package/my/scan/index?token=${scanToken}`
+						})
+					} else {
+						this.$queue.showToast(res.msg || '扫码失败,请重试')
+					}
+				})
+				.finally(() => {
+					uni.hideLoading()
+				})
+		},
+		
+		// 扫码
+		async handleScan() {
+			if (!this.token) {
+				this.noLogin()
+				return
+			}
+			
+			const hasPermission = await this.$queue.checkPermission(
+				'camera',
+				'扫码需要相机权限',
+				this,
+			);
+			console.log('hasPermission: ', hasPermission)
+			
+			// 2. 如果未授权或者用户拒绝,显示提示
+			if (!hasPermission) {
+				return;
+			}
+			
+			uni.scanCode({
+				success: (res) => {
+					console.log('success', res)
+					this.handleScanRecord(res.result)
+				},
+				fail: (err) => {
+					console.log('err', err)
+					this.$queue.showToast(err || '扫码失败了,请重新尝试')
+				}
+			})
 		}
 	},
 };
@@ -1708,9 +1791,11 @@ page {
 	box-sizing: border-box;
 
 	image {
-		width: 60rpx;
-		height: 60rpx;
+		width: 52rpx;
+		height: 52rpx;
 		padding: 9rpx;
+		margin-top: 40rpx;
+		margin-left:30rpx
 	}
 }
 

+ 72 - 48
pages/my/onlineResume.vue

@@ -296,7 +296,7 @@
 					<view class="close-button flex align-center justify-center" @click="showResumesAnalysis = false">
 						<u-icon name="close" color="#fff" size="22" />
 					</view>
-					<view class="title">从附件简历中解析出<text>5段</text>有效信息</view>
+					<view class="title">从附件简历中解析出<text>{{ validInfoCount }}段</text>有效信息</view>
 					<view class="tip">无需手动填写,可直接添加到在线简历中</view>
 					<view class="info-list">
 						<view class="info-item flex align-center" v-for="(item, index) in analysisList" :key="index">
@@ -305,7 +305,7 @@
 							<view class="content">{{ item.value }}</view>
 						</view>
 					</view>
-					<view class="button">立即同步</view>
+					<view class="button" @click="handleSync">立即同步</view>
 				</view>
 			</u-popup>
 		</view>
@@ -317,6 +317,7 @@ import navBar from "@/components/nav-bar/index.vue";
 import { companyType } from '@/constants/common.js';
 import asyncSwitch from '@/components/async-switch.vue';
 var intentionId = 0
+let AIResumeData = {}
 export default {
 	components: {
 		navBar,
@@ -359,24 +360,26 @@ export default {
 			controlStatus: false,
 			score: -1,
 			showResumesAnalysis: false,
+			validInfoCount: 0, // 有效信息数量
 			analysisList: [
 				{
 					title: '基本信息',
-					value: '噶撒旦发生的噶手动阀手动阀手动阀噶撒旦发生的噶撒旦发生的噶手动阀手动阀手动阀噶撒旦发生的',
+					value: '',
 				},
 				{
 					title: '工作经历',
-					value: '噶撒旦发生的噶手动阀手动阀手动阀噶撒旦发生的',
+					value: '',
 				},
 				{
 					title: '教育经历',
-					value: '无法覆盖噶撒旦发生',
+					value: '',
 				},
 				{
 					title: '个人优势',
-					value: '刚刚噶士大夫撒打赏',
+					value: '',
 				},
-			]
+			],
+			loading: false
 		}
 	},
 	computed: {
@@ -413,7 +416,7 @@ export default {
 		}
 		// 判断是否有fileId,如果有则是从上传简历文件页面跳转
 		if (options.fileId) {
-			// this.getAiResumesAnalysis(options.fileId)
+			this.getAiResumesAnalysis(options.fileId)
 		}
 		this.getData()
 		var that = this
@@ -471,7 +474,6 @@ export default {
 					this.score = res.data?.resumeList?.score || 0
 
 					res.data.workExps.forEach(function (item) {
-						console.log(item.type);
 						try {
 							if (typeof item.type === 'string' && (item.type.startsWith('[') || item
 								.type.startsWith('{'))) {
@@ -507,8 +509,6 @@ export default {
 					// 设置是否对外展示简历
 					this.showChecked = res.data.resumeList?.isRecommend === 1
 
-					console.log('最终数据')
-					console.log(res.data.workExps);
 					that.detail.workExps = res.data.workExps
 				} else {
 					uni.showToast({
@@ -737,45 +737,69 @@ export default {
 		},
 		
 		// 获取简历解析数据
-		getAiResumesAnalysis(fileId) {
-			uni.showLoading({
-				title: '解析中'
-			})
-			// this.$Request
-			// 	.postT('/app/resumes/aiResumesAnalysis', {
-			// 		workflowId: '7594327567932309547',
-			// 		fileId
-			// 	}, '', 240000)
-			// 	.then(res => {
-			// 		console.log(res)
-			// 		uni.hideLoading()
-			// 	})
-			// 	.catch(err => {
-			// 		console.log(err)
-			// 		uni.hideLoading()
-			// 	})
-			uni.request({
-				url: 'https://yizhizan.edccc.cn/sqx_fast/app/resumes/aiResumesAnalysis',
-				header: {
-					'content-type': 'application/x-www-form-urlencoded', // 模拟 form-data
-					token: uni.getStorageSync("token"),
-				},
-				method: 'post',
-				data: {
-					workflowId: '7594327567932309547',
-					fileId
-				},
-				timeout: 120000,
-				success: (res) => {
+		getAiResumesAnalysis() {
+			const data = this.$queue.getData('AI_Resume_Data')
+			AIResumeData = data || {}
+			if (data) {
+				this.showResumesAnalysis = true
+				// 基本信息
+				if (data.name || data.age || data.email) {
+					this.validInfoCount++
+					let dataArray = []
+					if (data.name) {
+						dataArray.push(data.name)
+					}
+					if (data.age) {
+						dataArray.push(data.age)
+					}
+					if (data.email) {
+						dataArray.push(data.email)
+					}
+					this.analysisList[0].value = dataArray.join('、')
+				}
+				
+				// 工作经历
+				if (data.workExperience?.length) {
+					this.validInfoCount++
+					let dataArray = data.workExperience.map(item => item.company)
+					this.analysisList[1].value = dataArray.join('、')
+				}
+				
+				// 教育经历
+				if (data.education?.length) {
+					this.validInfoCount++
+					let dataArray = data.education.map(item => item.school)
+					this.analysisList[2].value = dataArray.join('、')
+				}
+				
+				// 个人优势
+				if (data.selfEvaluation) {
+					this.validInfoCount++
+					this.analysisList[3].value = data.selfEvaluation
+				}
+			}
+		},
+		
+		// 同步简历数据
+		handleSync() {
+			if (this.loading) return
+			
+			uni.showLoading({ title: '同步中' })
+			this.loading = true
+			this.$Request
+				.postJson('/app/resumes/syncResumess', AIResumeData)
+				.then(res => {
 					console.log(res)
+					if (res.code === 0) {
+						this.showResumesAnalysis = false
+						this.$queue.showToast('同步成功')
+						this.getData()
+					}
+				})
+				.finally(() => {
+					this.loading = false
 					uni.hideLoading()
-				},
-				fail: (err) => {
-					console.log('0000000000')
-					console.log(err)
-					uni.hideLoading()
-				}
-			})
+				})
 		}
 	},
 	watch: {

+ 7 - 1
pages/my/setup.vue

@@ -16,8 +16,14 @@
 		<view class="usermain">
 
 			<!-- 我的公司 -->
+			<!-- <view class="usermain-item item-padding" @click="goNavNoLogin('/my/setting/mimi')">
+				<view class="usermain-item-title">推送通知</view>
+				<view>
+					<u-switch size="40" v-model="checked"></u-switch>
+				</view>
+			</view> -->
 			<view class="usermain-item item-padding" @click="goNavNoLogin('/my/setting/mimi')">
-				<view class="usermain-item-title">隐私协议11</view>
+				<view class="usermain-item-title">隐私协议</view>
 				<view>
 					<u-icon name="arrow-right"></u-icon>
 				</view>

+ 100 - 7
pages/my/userinfo.vue

@@ -14,8 +14,8 @@
 				<view class="avatar-wrapper flex align-center" @click="uploadImg()">
 					<!-- #ifndef MP-WEIXIN -->
 					<view>
-						<image src="../../static/logo.png" v-if="avatar == null" mode=""
-							style="width: 78rpx;height: 78rpx;border-radius: 50%;"></image>
+						<image src="../../static/logo.png" v-if="avatar == null"
+							style="width: 78rpx;height: 78rpx;border-radius: 50%;" mode="aspectFill"></image>
 						<image v-else :src="avatar" mode="" style="width: 78rpx;height: 78rpx;border-radius: 50%;">
 						</image>
 					</view>
@@ -47,14 +47,31 @@
 					</view>
 				</view>
 			</view>
-			<view class="usermain-item item-padding ">
+			<!-- <view class="usermain-item item-padding ">
 				<view class="usermain-item-title">年龄</view>
 				<view>
 					<view class="cu-form-group">
 						<input v-model="age" />
 					</view>
 				</view>
+			</view> -->
+			
+			<!-- 出生年月 -->
+			<view class="form-item">
+				<view class="form-label">
+					<text class="required-mark">*</text>
+					<text>出生年月</text>
+				</view>
+				<view class="date-picker" @click="showDatePicker = true">
+					<text class="date-text" v-if="birthDateText">{{ birthDateText }}</text>
+					<text class="placeholder-text" v-else>请选择出生年月</text>
+					<u-icon name="arrow-down" color="#999" size="24"></u-icon>
+				</view>
+			
+				<u-picker :default-time="birthDateText" v-model="showDatePicker" mode="time" :params="dateParams"
+					@confirm="onDateConfirm"></u-picker>
 			</view>
+			
 			<view class="usermain-item item-padding contact-structure">
 				<view class="usermain-item-title">联系方式</view>
 				<view class="contact-wrapper">
@@ -159,7 +176,13 @@ export default {
 			hrInfo: {},
 			hrPosition: '',
 			hrEmail: '',
-			inputKey: ''
+			inputKey: '',
+			birthDateText: '', // 显示的日期文本
+			showDatePicker: false, // 控制日期选择器显示
+			dateParams: {
+				year: true,
+				month: true
+			},
 		};
 	},
 	computed: {
@@ -226,6 +249,16 @@ export default {
 			// 这里可以跳转到职务选择页面或显示职务选择弹窗
 			console.log('选择职务');
 		},
+		// 日期选择确认
+		onDateConfirm(e) {
+			const {
+				year,
+				month,
+				day
+			} = e;
+			this.birthDateText = `${year}-${String(month).padStart(2, '0')}`;
+			this.showDatePicker = false;
+		},
 		onChooseAvatar(e) {
 			let that = this;
 			let token = uni.getStorageSync('token');
@@ -350,7 +383,10 @@ export default {
 		},
 		getUserInfo() {
 			let userId = uni.getStorageSync('userId')
-			this.$Request.get("/app/user/selectUserById").then(res => {
+			// /app/user/selectUserById
+			// /app/user/getUserInfo
+			// this.$Request.get("/app/user/selectUserById").then(res => {
+			this.$Request.get("/app/user/getUserInfo").then(res => {
 				if (res.code == 0) {
 					this.$queue.setData('avatar', res.data.avatar);
 					this.$queue.setData('userId', res.data.userId);
@@ -364,6 +400,7 @@ export default {
 					this.phone = res.data.phone;
 					this.avatar = res.data.avatar;
 					this.userName = res.data.userName;
+					this.birthDateText = res.data?.birthday || '';
 					if (this.userName == null) {
 						this.userName = res.data.nickName;
 					} else {
@@ -389,6 +426,8 @@ export default {
 					title: "联系电话不能为空",
 					icon: "none"
 				})
+			} else if (!this.birthDateText) {
+				this.$queue.showToast('请选择出生年月');
 			} else {
 				let that = this
 				uni.showModal({
@@ -398,12 +437,13 @@ export default {
 						if (e.confirm) {
 							let phone = that.$queue.getData('newPhone') ? this.$queue.getData('newPhone') :
 								that.phone
-							that.$Request.postJson("/app/user/updateUser", {
+							that.$Request.postJson("/app/user/updateUserInfo", {
 								userName: that.userName,
 								avatar: that.avatar,
 								phone,
 								sex: that.sex,
-								age: that.age,
+								// age: that.age,
+								birthday: this.birthDateText,
 								weChatNum: that.weChatNum
 							}).then(res => {
 								if (res.code === 0) {
@@ -693,4 +733,57 @@ button {
 	background: #f5f7fa !important;
 	transform: scale(0.99);
 }
+
+.form-item {
+	margin: 0 40rpx 20rpx;
+
+	.form-label {
+		color: var(--Neutral/100, rgba(31, 44, 55, 1));
+		font-family: DM Sans;
+		font-size: 28rpx;
+		font-weight: 500;
+		line-height: 44rpx;
+		letter-spacing: 0.5%;
+		text-align: left;
+		display: flex;
+		align-items: center;
+		margin-bottom: 16rpx;
+
+		.required-mark {
+			color: #FF3B30;
+			font-size: 18px;
+			font-weight: 600;
+			margin-right: 8rpx;
+		}
+	}
+
+
+	// 日期选择器样式
+	.date-picker {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		height: 75rpx;
+		font-size: 14px;
+		border: 1px solid rgba(227, 231, 236, 1);
+		border-radius: 24px;
+		color: rgba(23, 23, 37, 1);
+		padding: 12px 16px;
+
+		.date-text {
+			color: rgba(23, 23, 37, 1);
+			font-family: DM Sans;
+			font-size: 14px;
+			font-weight: 400;
+			line-height: 22px;
+			letter-spacing: 0%;
+			text-align: left;
+		}
+	}
+	
+	// 出生年月placeholder样式
+	.placeholder-text {
+		color: #999;
+	}
+}
 </style>

+ 1 - 1
pages/my/workExperience.vue

@@ -452,7 +452,7 @@ export default {
 					that.formData.companyName = res.workExp.companyName
 					that.formData.businessTypes = JSON.parse(res.workExp.type)
 					// 设置公司业务类型回显
-					if (this.formData.businessTypes.length) {
+					if (this.formData.businessTypes?.length) {
 						for (let i = 0; i < this.formData.businessTypes.length; i++) {
 							for (let opt = 0; i < this.businessTypeOptions.length; opt++) {
 								const option = this.businessTypeOptions[opt]

+ 72 - 3
pages/public/improvePrompt.vue

@@ -29,6 +29,8 @@
 				<view class="white-btn" @click="handlUploadFile">附件简历一键识别</view>
 			</template>
 		</view>
+		
+		<load-card :progress="progress" v-if="showLoadCard"></load-card>
 	</view>
 </template>
 
@@ -36,10 +38,19 @@
 	// #ifdef APP-PLUS
 	import { chooseFileFromModule } from '@/uni_modules/sr-file-choose'
 	// #endif
+	import loadCard from '@/components/load-card.vue'
+	import config from '@/common/config'
+	
 	export default {
+		components: {
+			loadCard
+		},
 		data() {
 			return {
 				scene: 0, // 0正常进入  1邀请进入
+				progress: 0,
+				showLoadCard: false,
+				timer: null
 			};
 		},
 		onLoad(options) {
@@ -47,6 +58,11 @@
 				this.scene = options.scene
 			}
 		},
+		onUnload() {
+			if (this.timer) {
+				clearInterval(this.timer)
+			}
+		},
 		methods: {
 			toOnlineResume() {
 				uni.navigateTo({
@@ -113,13 +129,66 @@
 					name: 'file'
 				}, (res) => {
 					if (res && res.code === 0) {
-						uni.reLaunch({
-							url: `/pages/my/onlineResume?fileId=${res.data.id}`
-						})
+						const id = res.data?.id
+						if (id) {
+							this.getAiResumesAnalysis(id)
+						}
+						// uni.reLaunch({
+						// 	url: `/pages/my/onlineResume?fileId=${res.data.id}`
+						// })
 					} else {
 						this.$queue.showToast(res ? res.msg : '文件上传失败')
 					}
 				})
+			},
+			// 获取简历解析数据
+			getAiResumesAnalysis(fileId) {
+				if (this.timer) {
+					clearInterval(this.timer)
+					this.progress = 0
+				}
+				
+				this.showLoadCard = true
+				this.timer = setInterval(() => {
+					if (this.progress < 99) {
+						this.progress++
+					}
+				}, 900)
+				uni.request({
+					url: config.APIHOST + '/app/resumes/aiResumesAnalysis',
+					header: {
+						'content-type': 'application/x-www-form-urlencoded', // 模拟 form-data
+						token: uni.getStorageSync('token'),
+					},
+					method: 'post',
+					data: {
+						workflowId: '7594327567932309547',
+						fileId
+					},
+					timeout: 180000,
+					success: (res) => {
+						this.stopLoadStatus()
+						
+						if (res.data?.code == 0) {
+							const data = res.data.data.data
+							this.$queue.setData('AI_Resume_Data', data.output)
+							
+							uni.reLaunch({
+								url: `/pages/my/onlineResume?fileId=${fileId}`
+							})
+						}
+					},
+					fail: (err) => {
+						this.$queue.showToast('解析失败,请稍后重试')
+						this.stopLoadStatus()
+					}
+				})
+			},
+			
+			stopLoadStatus() {
+				this.showLoadCard = false
+				this.progress = 0
+				clearInterval(this.timer)
 			}
 		}
 	}

+ 9 - 14
pages/public/loginV2.vue

@@ -55,6 +55,7 @@
 
 <script>
 	import { jVerificationLogin, closeVerifyView } from '@/utils/jVerificationLogin'
+	import { membershipExpirationReminder } from '@/utils/login'
 	export default {
 		data() {
 			return {
@@ -266,21 +267,15 @@
 							url: '/pages/my/index',
 							success: closeVerifyView
 						})
-					// } else if (this.isFirst) {
-					// 	// 首次登录,跳转至基本详情页
-					// 	uni.reLaunch({
-					// 		url: '/package/jobIntention/basicInfo',
-					// 		success: closeVerifyView
-					// 	})
+						
+						if (res.userVip) {
+							membershipExpirationReminder(res.userVip)
+						}
 					} else {
-						// uni.reLaunch({
-						// 	url: '/pages/my/jobApplicant/guidePage',
-						// 	success: closeVerifyView
-						// })
-							uni.reLaunch({
-								url: '/package/jobIntention/basicInfo',
-								success: closeVerifyView
-							})
+						uni.reLaunch({
+							url: '/package/jobIntention/basicInfo',
+							success: closeVerifyView
+						})
 					}
 				} else {
 					uni.showToast({

+ 11 - 0
pages/public/loginphone.vue

@@ -47,6 +47,7 @@
 
 <script>
 	import navBar from "@/components/nav-bar/index.vue";
+	import { membershipExpirationReminder } from '@/utils/login'
 	export default {
 		data() {
 			return {
@@ -222,6 +223,11 @@
 													// 原有的。判断第一次根据userType  ==null
 													uni.reLaunch({
 														url: "/pages/my/index",
+														success: () => {
+															if (res.userVip) {
+																membershipExpirationReminder(res.userVip)
+															}
+														}
 													});
 													// 这里判断一下看是否是第一次登录如果是就跳到引导页,如果不是就正常跳
 													// let firstLogin = uni.getStorageSync("firstLogin") || false;
@@ -237,6 +243,11 @@
 												} else if (res.user.userType == 1) {
 													uni.reLaunch({
 														url: "/pages/my/index",
+														success: () => {
+															if (res.userVip) {
+																membershipExpirationReminder(res.userVip)
+															}
+														}
 													});
 													// 这里判断一下看是否是第一次登录如果是就跳到引导页,如果不是就正常跳
 													// let firstLogin = uni.getStorageSync("firstLogin") || false;

+ 9 - 3
pages/talentSearch/resumeDetail.vue

@@ -18,7 +18,7 @@
 			</view>
 		</view>
 
-		<view style="margin-top: 20px; border-top: 20rpx solid rgba(241, 245, 248, 1);">
+		<view style="margin-top: 20px; border-top: 20rpx solid rgba(241, 245, 248, 1);" v-if="!loading">
 			<previewResume :resumesId="resumesId" :postPushId="postPushId"></previewResume>
 		</view>
 
@@ -53,7 +53,8 @@ export default {
 			resumesStatus: ['离职&随时到岗', '在职&月内到岗', '在职&考虑机会', '在职&暂不考虑'],
 			isShowBtn:0,
 			resumesId: '',
-			postPushId: ''
+			postPushId: '',
+			loading: true
 		}
 	},
 	onLoad(option) {
@@ -91,6 +92,9 @@ export default {
 			this.isShowBtn = option.isShowBtn
 		}
 	},
+	onUnload() {
+		this.$queue.remove('resumeDetailData')
+	},
 	methods: {
 		/**
 		 * 收藏简历
@@ -161,7 +165,7 @@ export default {
 					// this.skills = data.skills
 					this.skills = data.skillList
 					this.workExpList = data.workExpList
-
+					this.$queue.setData('resumeDetailData', res.data)
 				} else {
 					uni.hideLoading()
 					uni.showModal({
@@ -173,6 +177,8 @@ export default {
 						}
 					})
 				}
+			}).finally(() => {
+				this.loading = false
 			})
 		},
 		//使用岗位名称查询出企业正在招聘的该岗位拿到对应的岗位id

+ 3 - 0
static/im/letter.svg

@@ -0,0 +1,3 @@
+<svg viewBox="0 0 17.8203 14" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17.820312" height="14.000000" fill="none" customFrame="#000000">
+	<path id="Vector" d="M8.91046 10.2012L8.91017 10.2009L8.90989 10.2012L0 3.11923L0 14L17.8203 14L17.8203 3.11925L8.91046 10.2012ZM17.8203 1.33591L17.8203 0L0 0L0 1.33591L8.91013 8.41817L17.8203 1.33591Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
+</svg>

+ 9 - 0
static/im/mianshi.svg

@@ -0,0 +1,9 @@
+<svg viewBox="0 0 22.3999 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="22.399902" height="24.000000" fill="none" customFrame="#000000">
+	<defs>
+		<linearGradient id="paint_linear_1" x1="0" x2="22.3999977" y1="12.000001" y2="12.000001" gradientUnits="userSpaceOnUse">
+			<stop stop-color="rgb(13,39,247)" offset="0" stop-opacity="1" />
+			<stop stop-color="rgb(19,193,234)" offset="1" stop-opacity="1" />
+		</linearGradient>
+	</defs>
+	<path id="矢量 58" d="M0 19.8464C0 22.1536 1.8048 24 4.0592 24L18.3408 24C20.5968 24 22.4 22.1536 22.4 19.8464L22.4 8.6144L0 8.6144L0 19.8464ZM6.0128 14.9232C6.3136 14.616 6.9152 14.616 7.216 14.9232L9.6208 17.384L14.8832 11.8464C15.184 11.5392 15.7856 11.384 16.0864 11.8464C16.3872 12.1536 16.5376 12.7696 16.0864 13.0784L10.2224 19.2304C10.072 19.384 9.7712 19.5392 9.6208 19.5392C9.3216 19.5392 9.1712 19.384 9.0208 19.2304L6.0128 16C5.712 15.8464 5.712 15.384 6.0128 14.9232ZM19.8448 2.4608L16.5376 2.4608L16.5376 1.232C16.5376 0.616 15.936 0 15.3344 0C14.7328 0 14.1312 0.616 14.1312 1.232L14.1312 2.4608L7.968 2.4608L7.968 1.232C7.968 0.616 7.3664 0 6.7648 0C6.1632 0 5.5632 0.616 5.5632 1.232L5.5632 2.4608L2.4048 2.4608C1.0528 2.4608 0 3.5392 0 4.9232L0 7.0768L22.2496 7.0768L22.2496 4.9232C22.2496 3.5392 21.1968 2.4608 19.8448 2.4608L19.8448 2.4608Z" fill="url(#paint_linear_1)" fill-rule="nonzero" />
+</svg>

+ 3 - 0
static/im/more.svg

@@ -0,0 +1,3 @@
+<svg viewBox="0 0 17.5 17.5" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17.500000" height="17.500000" fill="none" customFrame="#000000">
+	<path id="矢量 85" d="M8.75 0C3.92578 0 0 3.92578 0 8.75C0 13.5742 3.92578 17.5 8.75 17.5C13.5742 17.5 17.5 13.5742 17.5 8.75C17.5 3.92578 13.5742 0 8.75 0ZM8.75 16.1445C4.67188 16.1445 1.35547 12.8281 1.35547 8.75C1.35547 4.67187 4.67188 1.35547 8.75 1.35547C12.8281 1.35547 16.1445 4.67188 16.1445 8.75C16.1445 12.8281 12.8281 16.1445 8.75 16.1445ZM4.7207 7.26758C3.90234 7.26758 3.23828 7.93359 3.23828 8.75C3.23828 9.14648 3.39258 9.51953 3.67188 9.79883C3.95117 10.0781 4.32422 10.2344 4.7207 10.2344C5.53711 10.2344 6.20312 9.57031 6.20312 8.75195C6.20312 7.93164 5.53711 7.26758 4.7207 7.26758L4.7207 7.26758ZM8.75 7.26758C7.93164 7.26758 7.26758 7.93359 7.26758 8.75C7.26758 9.56836 7.93359 10.2324 8.75 10.2324C9.56836 10.2324 10.2324 9.56641 10.2324 8.75C10.2324 7.93164 9.56836 7.26758 8.75 7.26758ZM12.7793 7.26758C11.9609 7.26758 11.2969 7.93359 11.2969 8.75C11.2969 9.56836 11.9629 10.2324 12.7793 10.2324C13.5957 10.2324 14.2617 9.56641 14.2617 8.75C14.2617 7.93164 13.5977 7.26758 12.7793 7.26758Z" fill="rgb(102,102,102)" fill-rule="nonzero" />
+</svg>

文件差異過大導致無法顯示
+ 7 - 0
static/im/qiudianhua.svg


+ 19 - 0
static/im/toUp.svg

@@ -0,0 +1,19 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20.000000" height="20.000000" fill="none" customFrame="url(#clipPath_0)">
+	<defs>
+		<linearGradient id="paint_linear_0" x1="0" x2="19.9999981" y1="10.000001" y2="10.000001" gradientUnits="userSpaceOnUse">
+			<stop stop-color="rgb(13,39,247)" offset="0" stop-opacity="1" />
+			<stop stop-color="rgb(19,193,234)" offset="1" stop-opacity="1" />
+		</linearGradient>
+		<clipPath id="clipPath_0">
+			<rect width="20.000000" height="20.000000" x="0.000000" y="0.000000" rx="4.000000" fill="rgb(255,255,255)" />
+		</clipPath>
+		<clipPath id="clipPath_1">
+			<rect width="16.000000" height="16.000000" x="2.000000" y="2.000000" fill="rgb(255,255,255)" />
+		</clipPath>
+	</defs>
+	<rect id="tag标签_线框" width="20.000000" height="20.000000" x="0.000000" y="0.000000" rx="4.000000" fill="url(#paint_linear_0)" fill-opacity="0.75" />
+	<g id="svg 77" clip-path="url(#clipPath_1)" customFrame="url(#clipPath_1)">
+		<rect id="svg 77" width="16.000000" height="16.000000" x="2.000000" y="2.000000" />
+		<path id="矢量 69" d="M5.99999 4C5.85921 4 5.72203 4.04457 5.60813 4.12732C5.49424 4.21007 5.40946 4.32676 5.36595 4.46066C5.32245 4.59455 5.32245 4.73878 5.36595 4.87268C5.40946 5.00657 5.49424 5.12326 5.60813 5.20601C5.72203 5.28876 5.85921 5.33333 5.99999 5.33333L14 5.33333C14.1408 5.33333 14.2779 5.28876 14.3918 5.20601C14.5057 5.12326 14.5905 5.00657 14.634 4.87268C14.6775 4.73878 14.6775 4.59455 14.634 4.46066C14.5905 4.32676 14.5057 4.21007 14.3918 4.12732C14.2779 4.04457 14.1408 4 14 4L5.99999 4ZM9.99999 7.21867L6.55199 10.6667L8.66666 10.6667L8.66666 12.6667C8.66666 12.8075 8.62209 12.9446 8.53934 13.0585C8.45658 13.1724 8.3399 13.2572 8.206 13.3007C8.07211 13.3442 7.92788 13.3442 7.79398 13.3007C7.66008 13.2572 7.5434 13.1724 7.46065 13.0585C7.37789 12.9446 7.33332 12.8075 7.33332 12.6667L7.33332 12L6.55199 12C5.36466 12 4.76933 10.564 5.60932 9.724L9.05732 6.276C9.22281 6.11056 9.42893 5.99159 9.65496 5.93103C9.881 5.87048 10.119 5.87048 10.345 5.93103C10.5711 5.99159 10.7772 6.11056 10.9427 6.276L14.3907 9.724C15.2307 10.564 14.6353 12 13.448 12L12.6667 12L12.6667 15.3333C12.6667 15.5674 12.605 15.7973 12.488 16C12.371 16.2027 12.2027 16.371 12 16.488C11.7973 16.6051 11.5674 16.6667 11.3333 16.6667L8.66666 16.6667C8.43261 16.6667 8.20268 16.6051 7.99999 16.488C7.7973 16.371 7.62898 16.2027 7.51196 16C7.39493 15.7973 7.33332 15.5674 7.33332 15.3333C7.33332 15.1925 7.37789 15.0554 7.46065 14.9415C7.5434 14.8276 7.66008 14.7428 7.79398 14.6993C7.92788 14.6558 8.07211 14.6558 8.206 14.6993C8.3399 14.7428 8.45658 14.8276 8.53934 14.9415C8.62209 15.0554 8.66666 15.1925 8.66666 15.3333L11.3333 15.3333L11.3333 10.6667L13.448 10.6667L9.99999 7.21867Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
+	</g>
+</svg>

+ 5 - 0
static/images/svg/edit.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none">
+	<rect id="svg 81" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
+	<path id="矢量 87" d="M18.2251 19.4437C18.2251 19.7766 17.9462 20.0484 17.6017 20.0484L4.65713 20.0484C4.3126 20.0484 4.03369 19.7766 4.03369 19.4437L4.03369 6.66328C4.03369 6.33047 4.3126 6.05859 4.65713 6.05859L12.9704 6.05859L12.9704 4.46484L4.65713 4.46484C3.43369 4.46484 2.43994 5.45156 2.43994 6.66328L2.43994 19.4437C2.43994 20.6555 3.43369 21.6422 4.65713 21.6422L17.6017 21.6422C18.8251 21.6422 19.8188 20.6555 19.8188 19.4437L19.8188 11.2078L18.2251 11.2078L18.2251 19.4437Z" fill="rgb(0,0,0)" fill-rule="nonzero" />
+	<path id="矢量 88" d="M21.4311 5.06943L20.2545 3.86709L19.76 3.36084L19.0779 2.6624C18.9279 2.51006 18.7217 2.42334 18.5084 2.42334C18.2928 2.42334 18.0889 2.51006 17.9389 2.66475L17.2873 3.33272L17.2287 3.39365L10.085 10.7226C10.0756 10.7319 10.0662 10.7413 10.0568 10.753C10.0475 10.7647 10.0381 10.7741 10.0287 10.7858C10.0264 10.7882 10.0264 10.7905 10.024 10.7929C10.017 10.8022 10.01 10.8116 10.0029 10.8233C10.0006 10.8257 10.0006 10.828 9.99824 10.8304C9.99121 10.8421 9.98418 10.8515 9.97715 10.8632C9.97715 10.8655 9.9748 10.8655 9.9748 10.8679L9.94668 10.9171L7.19746 16.139C7.0334 16.4507 7.09433 16.8327 7.34512 17.0788C7.49746 17.2288 7.69902 17.3062 7.90293 17.3062C8.03418 17.3062 8.16777 17.2733 8.28965 17.2054L13.392 14.3812C13.3943 14.3788 13.399 14.3765 13.4014 14.3765C13.4107 14.3718 13.4178 14.3671 13.4271 14.3601C13.4318 14.3577 13.4365 14.353 13.4412 14.3507C13.4482 14.346 13.4553 14.3413 13.4646 14.3366C13.4693 14.3343 13.474 14.3296 13.4787 14.3272C13.4857 14.3226 13.4928 14.3179 13.4998 14.3108C13.5045 14.3062 13.5092 14.3038 13.5139 14.2991C13.5209 14.2944 13.5279 14.2874 13.535 14.2827C13.5396 14.278 13.5443 14.2757 13.5467 14.271L13.5678 14.2499L13.5771 14.2405L20.3998 7.24209L20.7818 6.85068L21.4334 6.18271C21.7334 5.87334 21.7334 5.37881 21.4311 5.06943L21.4311 5.06943ZM19.2584 6.13115C19.2514 6.13818 19.2303 6.15693 19.1904 6.15693C19.1646 6.15693 19.1154 6.1499 19.0662 6.09834L18.0795 5.08818C17.9998 5.00615 17.9975 4.88897 18.049 4.83506L18.4311 4.44365C18.4381 4.43662 18.4568 4.41553 18.499 4.41553C18.5248 4.41553 18.574 4.42256 18.6232 4.47412L19.61 5.48428C19.6896 5.56631 19.692 5.6835 19.6404 5.7374L19.6029 5.7749L19.2584 6.13115ZM16.8326 6.08428C16.8654 6.12412 16.9006 6.16631 16.9381 6.20381L17.9248 7.21397C17.9717 7.26084 18.0209 7.30537 18.0701 7.34756L13.0053 12.5437L11.7678 11.278L16.8326 6.08428L16.8326 6.08428ZM9.84824 14.5218L10.849 12.6187L11.7045 13.4952L9.84824 14.5218Z" fill="rgb(0,0,0)" fill-rule="nonzero" />
+</svg>

+ 6 - 0
static/images/svg/more.svg

@@ -0,0 +1,6 @@
+<svg viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="26.000000" height="26.000000" fill="none">
+	<rect id="更多1" width="26.000000" height="26.000000" x="0.000000" y="0.000000" />
+	<circle id="circle" cx="13" cy="6.5" r="1.625" fill="rgb(51,51,51)" />
+	<circle id="circle" cx="13" cy="13" r="1.625" fill="rgb(51,51,51)" />
+	<circle id="circle" cx="13" cy="19.5" r="1.625" fill="rgb(51,51,51)" />
+</svg>

+ 3 - 0
static/images/svg/scan.svg

@@ -0,0 +1,3 @@
+<svg viewBox="0 0 14.1816 14.1816" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.181641" height="14.181641" fill="none" customFrame="#000000">
+	<path id="矢量 86" d="M3.81817 13.0909C4.10909 13.0909 4.36364 13.3454 4.36364 13.6364C4.36364 13.9273 4.10909 14.1818 3.81817 14.1818L2 14.1818C0.909094 14.1818 1.78814e-07 13.2727 1.78814e-07 12.1818L1.78814e-07 10.3636C1.78814e-07 10.0727 0.254531 9.81817 0.545453 9.81817C0.836375 9.81817 1.09091 10.0727 1.09091 10.3636L1.09091 12.1818C1.09091 12.6909 1.49091 13.0909 2 13.0909L3.81817 13.0909ZM13.0909 10.3636C13.0909 10.0727 13.3454 9.81817 13.6364 9.81817C13.9273 9.81817 14.1818 10.0727 14.1818 10.3636L14.1818 12.1818C14.1818 13.2727 13.2727 14.1818 12.1818 14.1818L10.3636 14.1818C10.0727 14.1818 9.81817 13.9273 9.81817 13.6364C9.81817 13.3454 10.0727 13.0909 10.3636 13.0909L12.1818 13.0909C12.6909 13.0909 13.0909 12.6909 13.0909 12.1818L13.0909 10.3636ZM10.3636 1.09091C10.0727 1.09091 9.81817 0.836375 9.81817 0.545438C9.81817 0.2545 10.0727 0 10.3636 0L12.1818 0C13.2727 0 14.1818 0.909094 14.1818 2L14.1818 4.18181C14.1818 4.47272 13.9273 4.72728 13.6364 4.72728C13.3454 4.72728 13.0909 4.4727 13.0909 4.1818L13.0909 2C13.0909 1.49091 12.6909 1.09091 12.1818 1.09091L10.3636 1.09091ZM1.09091 3.81817C1.09091 4.10909 0.836375 4.36364 0.545438 4.36364C0.2545 4.36364 0 4.10909 0 3.81817L0 2C0 0.909094 0.909094 1.78814e-07 2 1.78814e-07L3.81817 1.78814e-07C4.10909 1.78814e-07 4.36364 0.254531 4.36364 0.545453C4.36364 0.836375 4.10909 1.09091 3.81817 1.09091L2 1.09091C1.49091 1.09091 1.09091 1.49091 1.09091 2L1.09091 3.81817ZM3.45455 7.63637C3.16364 7.63637 2.90908 7.38184 2.90908 7.09092C2.90908 6.8 3.16364 6.54545 3.45455 6.54545L10.7273 6.54545C11.0182 6.54545 11.2727 6.80001 11.2727 7.09092C11.2727 7.38183 11.0182 7.63639 10.7273 7.63639L3.45455 7.63639L3.45455 7.63637Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
+</svg>

+ 14 - 0
utils/login.js

@@ -99,3 +99,17 @@ function getIsVip() {
 		}
 	});
 }
+
+/**
+ * 会员登录到期提醒
+ */
+export function membershipExpirationReminder(data) {
+	if (data?.daysLeft) {
+		setTimeout(() => {
+			uni.showModal({
+				title: '会员到期提醒',
+				content: data.remind
+			})
+		}, 1000)
+	}
+}

+ 150 - 29
utils/util.js

@@ -1,32 +1,153 @@
+import httpRequest from '@/common/httpRequest'
+
 // 金额格式化成K格式
 export const formatNumberToK = (param) => {
-    // 1. 异常处理:空值(null/undefined)直接返回空字符串
-    if (param === null || param === undefined) {
-        return '';
-    }
-
-    // 2. 统一预处理:无论参数是数字/字符串,都转为字符串并去除首尾空格
-    let numStr = String(param).trim();
-    
-    // 3. 空字符串情况直接返回
-    if (numStr === '') {
-        return '';
-    }
-
-    // 4. 将处理后的字符串转为数字
-    const num = Number(numStr);
-    
-    // 5. 非有效数字的情况,返回原始参数的字符串形式(保持输入原貌)
-    if (isNaN(num)) {
-        return String(param);
-    }
-
-    // 6. 小于1000的数字,返回整数形式的字符串(无小数)
-    if (num < 1000) {
-        return String(Math.floor(num));
-    }
-
-    // 7. 大于等于1000的数字,除以1000取整后拼接K
-    const kNum = Math.floor(num / 1000);
-    return `${kNum}K`;
+	// 1. 异常处理:空值(null/undefined)直接返回空字符串
+	if (param === null || param === undefined) {
+		return '';
+	}
+
+	// 2. 统一预处理:无论参数是数字/字符串,都转为字符串并去除首尾空格
+	let numStr = String(param).trim();
+
+	// 3. 空字符串情况直接返回
+	if (numStr === '') {
+		return '';
+	}
+
+	// 4. 将处理后的字符串转为数字
+	const num = Number(numStr);
+
+	// 5. 非有效数字的情况,返回原始参数的字符串形式(保持输入原貌)
+	if (isNaN(num)) {
+		return String(param);
+	}
+
+	// 6. 小于1000的数字,返回整数形式的字符串(无小数)
+	if (num < 1000) {
+		return String(Math.floor(num));
+	}
+
+	// 7. 大于等于1000的数字,除以1000取整后拼接K
+	const kNum = Math.floor(num / 1000);
+	return `${kNum}K`;
 };
+
+// 导出简历文件
+let loading = false
+export const exportResumePdf = (resumesId) => {
+	if (loading) return
+	const baseUrl = httpRequest.config('APIHOST')
+	const url = baseUrl + '/app/resumes/exportPdf'
+
+	const token = uni.getStorageSync('token')
+
+	uni.showLoading({ title: '导出中' })
+	loading = true
+
+	// #ifdef APP-PLUS
+	// App 端(尤其 iOS)用 downloadFile 最稳定
+	const downloadUrl = `${url}?resumesId=${encodeURIComponent(resumesId)}`
+	uni.downloadFile({
+		url: downloadUrl,
+		header: { token },
+		success: (dRes) => {
+			if (dRes.statusCode !== 200) {
+				uni.showToast({ title: '导出失败:' + dRes.statusCode, icon: 'none' })
+				return
+			}
+			if (!dRes.tempFilePath) {
+				uni.showToast({ title: '导出失败,未获取到文件', icon: 'none' })
+				return
+			}
+			uni.openDocument({
+				filePath: dRes.tempFilePath,
+				showMenu: true,
+				fail: (e) => {
+					console.error('openDocument fail', e)
+					uni.showToast({ title: '无法打开文件', icon: 'none' })
+				}
+			})
+		},
+		fail: (err) => {
+			console.error('downloadFile fail', err)
+			uni.showToast({ title: '下载失败', icon: 'none' })
+		},
+		complete: () => {
+			uni.hideLoading()
+			loading = false
+		}
+	})
+	return
+	// #endif
+	uni.request({
+		url,
+		method: 'GET',
+		data: {
+			resumesId
+		},
+		header: {
+			'content-type': 'application/pdf',
+			token
+		},
+		responseType: 'arraybuffer',
+		success: (res) => {
+			// 1. 先校验
+			if (res.statusCode !== 200) {
+				uni.showToast({
+					title: '导出失败:' + res.statusCode,
+					icon: 'none'
+				})
+				return
+			}
+			if (!res.data || (res.data.byteLength !== undefined && res.data.byteLength === 0)) {
+				uni.showToast({
+					title: '导出失败,返回内容为空',
+					icon: 'none'
+				})
+				return
+			}
+
+			const mime = 'application/pdf'
+
+			// #ifdef H5
+			try {
+				const blob = new Blob([res.data], {
+					type: mime
+				})
+				const downloadUrl = window.URL.createObjectURL(blob)
+				const link = document.createElement('a')
+				link.href = downloadUrl
+				link.download = '简历.pdf'
+				link.click()
+				window.URL.revokeObjectURL(downloadUrl)
+				uni.showToast({
+					title: '文件下载成功',
+					icon: 'success'
+				})
+			} catch (e) {
+				console.error('H5 下载异常', e, res)
+				uni.showToast({
+					title: 'H5下载失败:' + e.message,
+					icon: 'none'
+				})
+			}
+			// #endif
+
+			// #ifdef APP-PLUS
+			// App 端已在上方使用 uni.downloadFile 处理,这里不再执行
+			// #endif
+		},
+		fail: (err) => {
+			console.error('exportResumePdf 请求失败', err)
+			uni.showToast({
+				title: '请求失败:' + err.errMsg,
+				icon: 'none'
+			})
+		},
+		complete: () => {
+			uni.hideLoading()
+			loading = false
+		}
+	})
+}

部分文件因文件數量過多而無法顯示