Przeglądaj źródła

我的资源优化 添加线索和资源判断 审核状态

yuxy 1 miesiąc temu
rodzic
commit
517329823a

+ 461 - 201
LiangZhiYUMao/pages/matchmaker-workbench/my-resources.vue

@@ -16,15 +16,27 @@
 			</view>
 		</view>
 
-	<scroll-view scroll-y class="content">
+	<!-- 资源/线索切换标签 -->
+	<view class="tab-switcher">
+		<view class="tab-item" :class="{ active: currentTab === 'resource' }" @click="switchToResource">
+			<text class="tab-text">资源</text>
+			<text class="tab-count">({{ registeredTotal }})</text>
+		</view>
+		<view class="tab-item" :class="{ active: currentTab === 'clue' }" @click="switchToClue">
+			<text class="tab-text">线索</text>
+			<text class="tab-count">({{ unregisteredTotal }})</text>
+		</view>
+	</view>
+
+	<scroll-view scroll-y class="content" @scrolltolower="handleScrollToLower" :lower-threshold="100">
 		<!-- 资源部分(已注册用户) -->
-		<view class="resource-section" v-if="registeredResources.length > 0">
-			<view class="section-header">
+		<view class="resource-section" v-if="currentTab === 'resource'">
+			<view class="section-header" v-if="registeredResources.length > 0">
 				<text class="section-title">资源</text>
 				<text class="section-count">({{ registeredTotal }})</text>
 			</view>
 			<view class="resource-list-container">
-				<view class="resource-item" v-for="(item, index) in getRegisteredPageData" :key="item.id" v-if="item" @click="handleResourceClick(item)">
+				<view class="resource-item" v-for="(item, index) in getRegisteredDisplayData" :key="getRegisteredItemKey(item, index)" @click="handleResourceClick(item)">
 				<!-- 右上角选中图标 -->
 				<view class="select-icon">✓-</view>
 				
@@ -68,8 +80,8 @@
 					</view>
 
 					<view class="action-buttons">
-						<view class="delete-btn" @click.stop="handleDelete(item.id)">删除</view>
-						<view class="match-btn" @click.stop="handleMatch(item.id)">精准匹配</view>
+						<view class="delete-btn" @click.stop="handleDelete(item.id || item.resourceId || item.resource_id)">删除</view>
+						<view class="match-btn" @click.stop="handleMatch(item.id || item.resourceId || item.resource_id)">精准匹配</view>
 					</view>
 				</view>
 
@@ -79,29 +91,25 @@
 					<text class="quality-text">优质资源</text>
 				</view>
 				</view>
-				<!-- 占位元素,确保数据不足3条时也保持固定高度 -->
-				<view class="resource-placeholder" v-for="(key, index) in getRegisteredPlaceholderKeys" :key="key"></view>
 			</view>
-			<!-- 资源分页控件 -->
-			<view class="pagination" v-if="registeredTotal > registeredPageSize">
-				<view class="pagination-btn" :class="{ disabled: registeredPageNum <= 1 }" @click="prevRegisteredPage">
-					<text>上一页</text>
-				</view>
-				<text class="pagination-info">{{ registeredPageNum }} / {{ getRegisteredTotalPages }}</text>
-				<view class="pagination-btn" :class="{ disabled: registeredPageNum >= getRegisteredTotalPages }" @click="nextRegisteredPage">
-					<text>下一页</text>
-				</view>
+			<!-- 加载更多提示 -->
+			<view class="load-more-tip" v-if="registeredResources.length < registeredTotal && currentTab === 'resource'">
+				<text class="load-more-text">下拉加载更多</text>
+			</view>
+			<!-- 没有更多数据提示 -->
+			<view class="no-more-tip" v-if="registeredResources.length >= registeredTotal && registeredTotal > 0 && currentTab === 'resource'">
+				<text class="no-more-text">已加载全部数据</text>
 			</view>
 		</view>
 
 		<!-- 线索部分(未注册用户) -->
-		<view class="resource-section" v-if="unregisteredResources.length > 0">
-			<view class="section-header">
+		<view class="resource-section" v-if="currentTab === 'clue'">
+			<view class="section-header" v-if="unregisteredResources.length > 0">
 				<text class="section-title">线索</text>
 				<text class="section-count">({{ unregisteredTotal }})</text>
 			</view>
 			<view class="resource-list-container">
-				<view class="resource-item" v-for="(item, index) in getUnregisteredPageData" :key="item.id" v-if="item" @click="handleResourceClick(item)">
+				<view class="resource-item" v-for="(item, index) in getUnregisteredDisplayData" :key="getUnregisteredItemKey(item, index)" @click="handleResourceClick(item)">
 				<!-- 右上角选中图标 -->
 				<view class="select-icon">✓-</view>
 				
@@ -120,7 +128,11 @@
 							<text class="resource-gender gender-tag">{{ item.gender }}</text>
 						</view>
 						<view class="status-tag-wrapper">
-							<text class="status-tag register-tag unregistered">未注册</text>
+						<text class="status-tag register-tag unregistered">未注册</text>
+						<!-- 审核状态标签(仅线索列表显示) -->
+						<text class="status-tag audit-tag" :class="{ 'audit-pending': item.status === 0 || item.status === null || item.status === undefined, 'audit-approved': item.status === 1, 'audit-rejected': item.status === 2 }">
+							{{ item.status === 0 || item.status === null || item.status === undefined ? '待审核' : (item.status === 1 ? '审核通过' : (item.status === 2 ? '审核未通过' : '待审核')) }}
+						</text>
 						</view>
 					</view>
 				</view>
@@ -142,8 +154,8 @@
 					</view>
 
 					<view class="action-buttons">
-						<view class="delete-btn" @click.stop="handleDelete(item.id)">删除</view>
-						<view class="match-btn" @click.stop="handleMatch(item.id)">精准匹配</view>
+						<view class="delete-btn" @click.stop="handleDelete(item.id || item.resourceId || item.resource_id)">删除</view>
+						<view class="match-btn" @click.stop="handleMatch(item.id || item.resourceId || item.resource_id)">精准匹配</view>
 					</view>
 				</view>
 
@@ -153,24 +165,20 @@
 					<text class="quality-text">优质资源</text>
 				</view>
 				</view>
-				<!-- 占位元素,确保数据不足3条时也保持固定高度 -->
-				<view class="resource-placeholder" v-for="(key, index) in getUnregisteredPlaceholderKeys" :key="key"></view>
 			</view>
-			<!-- 线索分页控件 -->
-			<view class="pagination" v-if="unregisteredTotal > unregisteredPageSize">
-				<view class="pagination-btn" :class="{ disabled: unregisteredPageNum <= 1 }" @click="prevUnregisteredPage">
-					<text>上一页</text>
-				</view>
-				<text class="pagination-info">{{ unregisteredPageNum }} / {{ getUnregisteredTotalPages }}</text>
-				<view class="pagination-btn" :class="{ disabled: unregisteredPageNum >= getUnregisteredTotalPages }" @click="nextUnregisteredPage">
-					<text>下一页</text>
-				</view>
+			<!-- 加载更多提示 -->
+			<view class="load-more-tip" v-if="unregisteredResources.length < unregisteredTotal && currentTab === 'clue'">
+				<text class="load-more-text">下拉加载更多</text>
+			</view>
+			<!-- 没有更多数据提示 -->
+			<view class="no-more-tip" v-if="unregisteredResources.length >= unregisteredTotal && unregisteredTotal > 0 && currentTab === 'clue'">
+				<text class="no-more-text">已加载全部数据</text>
 			</view>
 		</view>
 
 		<!-- 空状态 -->
-		<view class="empty-state" v-if="registeredTotal === 0 && unregisteredTotal === 0">
-			<text class="empty-text">暂无资源</text>
+		<view class="empty-state" v-if="(currentTab === 'resource' && registeredTotal === 0 && registeredResources.length === 0) || (currentTab === 'clue' && unregisteredTotal === 0 && unregisteredResources.length === 0)">
+			<text class="empty-text">{{ currentTab === 'resource' ? '暂无资源' : '暂无线索' }}</text>
 		</view>
 	</scroll-view>
 
@@ -215,18 +223,23 @@ export default {
 			return {
 				searchKeyword: '',
 				isFirstLoad: true, // 标记是否为首次加载
+				currentTab: 'resource', // 当前选中的标签:'resource' 或 'clue'
 				resources: [], // 保留用于兼容
-				registeredResources: [], // 已注册用户(资源部分)- 全部数据
-				unregisteredResources: [], // 未注册用户(线索部分)- 全部数据
+				registeredResources: [], // 已注册用户(资源部分)- 已加载的数据
+				unregisteredResources: [], // 未注册用户(线索部分)- 已加载的数据
+				allRegisteredResources: [], // 已注册用户(资源部分)- 全部数据(从后端获取)
+				allUnregisteredResources: [], // 未注册用户(线索部分)- 全部数据(从后端获取)
 				refreshTimer: null, // 定时刷新器
 				// 资源分页
 				registeredPageNum: 1, // 资源当前页码
-				registeredPageSize: 3, // 资源每页显示数量
+				registeredPageSize: 5, // 资源每页显示数量
 				registeredTotal: 0, // 资源总数
+				registeredLoading: false, // 资源加载中标志
 				// 线索分页
 				unregisteredPageNum: 1, // 线索当前页码
-				unregisteredPageSize: 3, // 线索每页显示数量
-				unregisteredTotal: 0 // 线索总数
+				unregisteredPageSize: 5, // 线索每页显示数量
+				unregisteredTotal: 0, // 线索总数
+				unregisteredLoading: false // 线索加载中标志
 			}
 		},
 		computed: {
@@ -234,47 +247,29 @@ export default {
 			unreadCount() {
 				return this.$store.getters.getTotalUnread || 0
 			},
-			// 获取资源当前页数据(确保始终返回3条,不足的用null占位)
-			getRegisteredPageData() {
-				const start = (this.registeredPageNum - 1) * this.registeredPageSize
-				const end = start + this.registeredPageSize
-				const pageData = this.registeredResources.slice(start, end)
-				// 如果数据不足3条,用null填充到3条
-				while (pageData.length < this.registeredPageSize) {
-					pageData.push(null)
-				}
-				return pageData
-			},
-			// 获取线索当前页数据(确保始终返回3条,不足的用null占位)
-			getUnregisteredPageData() {
-				const start = (this.unregisteredPageNum - 1) * this.unregisteredPageSize
-				const end = start + this.unregisteredPageSize
-				const pageData = this.unregisteredResources.slice(start, end)
-				// 如果数据不足3条,用null填充到3条
-				while (pageData.length < this.unregisteredPageSize) {
-					pageData.push(null)
-				}
-				return pageData
-			},
-			// 获取资源占位元素的key列表
-			getRegisteredPlaceholderKeys() {
-				return this.getRegisteredPageData.map((item, index) => {
-					return item ? null : 'registered-placeholder-' + index
-				}).filter(key => key !== null)
-			},
-			// 获取线索占位元素的key列表
-			getUnregisteredPlaceholderKeys() {
-				return this.getUnregisteredPageData.map((item, index) => {
-					return item ? null : 'unregistered-placeholder-' + index
-				}).filter(key => key !== null)
-			},
-			// 资源总页数
-			getRegisteredTotalPages() {
-				return Math.ceil(this.registeredTotal / this.registeredPageSize)
+			// 获取资源已加载的数据(用于显示)
+			getRegisteredDisplayData() {
+				const data = (this.registeredResources || []).filter(item => {
+					const isValid = item && item.id !== undefined && item.id !== null
+					if (!isValid) {
+						console.warn('getRegisteredDisplayData - 过滤掉无效数据:', item)
+					}
+					return isValid
+				})
+				console.log('getRegisteredDisplayData - 返回数据长度:', data.length, '数据:', data.map(item => ({ id: item.id, name: item.name })))
+				return data
 			},
-			// 线索总页数
-			getUnregisteredTotalPages() {
-				return Math.ceil(this.unregisteredTotal / this.unregisteredPageSize)
+			// 获取线索已加载的数据(用于显示)
+			getUnregisteredDisplayData() {
+				const data = (this.unregisteredResources || []).filter(item => {
+					const isValid = item && item.id !== undefined && item.id !== null
+					if (!isValid) {
+						console.warn('getUnregisteredDisplayData - 过滤掉无效数据:', item)
+					}
+					return isValid
+				})
+				console.log('getUnregisteredDisplayData - 返回数据长度:', data.length, '数据:', data.map(item => ({ id: item.id, name: item.name })))
+				return data
 			}
 		},
 		onLoad() {
@@ -309,6 +304,130 @@ export default {
 			this.stopAutoRefresh()
 		},
 		methods: {
+			// 获取审核状态文本
+			getAuditStatusText(status) {
+				if (status === null || status === undefined) {
+					return '待审核'
+				}
+				switch (status) {
+					case 0:
+						return '待审核'
+					case 1:
+						return '审核通过'
+					case 2:
+						return '审核未通过'
+					default:
+						return '待审核'
+				}
+			},
+			// 获取审核状态样式类(返回对象,用于:class绑定)
+			getAuditStatusClass(status) {
+				if (status === null || status === undefined) {
+					return { 'audit-pending': true }
+				}
+				switch (status) {
+					case 0:
+						return { 'audit-pending': true }
+					case 1:
+						return { 'audit-approved': true }
+					case 2:
+						return { 'audit-rejected': true }
+					default:
+						return { 'audit-pending': true }
+				}
+			},
+			// 获取资源项的key
+			getRegisteredItemKey(item, index) {
+				if (item && item.id) {
+					return 'registered-' + item.id
+				}
+				return 'registered-placeholder-' + index
+			},
+			// 获取线索项的key
+			getUnregisteredItemKey(item, index) {
+				if (item && item.id) {
+					return 'unregistered-' + item.id
+				}
+				return 'unregistered-placeholder-' + index
+			},
+			// 切换到资源标签
+			switchToResource() {
+				this.currentTab = 'resource'
+				// 切换标签时重置已加载数据
+				this.registeredPageNum = 1
+				this.loadRegisteredPage(1)
+			},
+			// 切换到线索标签
+			switchToClue() {
+				this.currentTab = 'clue'
+				// 切换标签时重置已加载数据
+				this.unregisteredPageNum = 1
+				this.loadUnregisteredPage(1)
+			},
+			// 滚动到底部触发加载更多
+			handleScrollToLower() {
+				if (this.currentTab === 'resource') {
+					// 资源列表加载更多
+					if (!this.registeredLoading && this.registeredResources.length < this.registeredTotal) {
+						this.loadMoreRegistered()
+					}
+				} else {
+					// 线索列表加载更多
+					if (!this.unregisteredLoading && this.unregisteredResources.length < this.unregisteredTotal) {
+						this.loadMoreUnregistered()
+					}
+				}
+			},
+			// 加载资源指定页数据
+			loadRegisteredPage(pageNum) {
+				if (!this.allRegisteredResources || this.allRegisteredResources.length === 0) {
+					console.warn('loadRegisteredPage: allRegisteredResources为空')
+					this.registeredResources = []
+					return
+				}
+				const start = (pageNum - 1) * this.registeredPageSize
+				const end = start + this.registeredPageSize
+				this.registeredResources = this.allRegisteredResources.slice(0, end)
+				console.log('loadRegisteredPage - pageNum:', pageNum, 'start:', start, 'end:', end, 'loaded:', this.registeredResources.length, 'total:', this.allRegisteredResources.length)
+			},
+			// 加载线索指定页数据
+			loadUnregisteredPage(pageNum) {
+				if (!this.allUnregisteredResources || this.allUnregisteredResources.length === 0) {
+					console.warn('loadUnregisteredPage: allUnregisteredResources为空')
+					this.unregisteredResources = []
+					return
+				}
+				const start = (pageNum - 1) * this.unregisteredPageSize
+				const end = start + this.unregisteredPageSize
+				this.unregisteredResources = this.allUnregisteredResources.slice(0, end)
+				console.log('loadUnregisteredPage - pageNum:', pageNum, 'start:', start, 'end:', end, 'loaded:', this.unregisteredResources.length, 'total:', this.allUnregisteredResources.length)
+			},
+			// 加载更多资源
+			loadMoreRegistered() {
+				if (this.registeredLoading) return
+				if (this.registeredResources.length >= this.registeredTotal) return
+				
+				this.registeredLoading = true
+				this.registeredPageNum++
+				const start = (this.registeredPageNum - 1) * this.registeredPageSize
+				const end = start + this.registeredPageSize
+				const newData = this.allRegisteredResources.slice(start, end)
+				this.registeredResources = [...this.registeredResources, ...newData]
+				this.registeredLoading = false
+			},
+			// 加载更多线索
+			loadMoreUnregistered() {
+				if (this.unregisteredLoading) return
+				if (this.unregisteredResources.length >= this.unregisteredTotal) return
+				
+				this.unregisteredLoading = true
+				this.unregisteredPageNum++
+				const start = (this.unregisteredPageNum - 1) * this.unregisteredPageSize
+				const end = start + this.unregisteredPageSize
+				const newData = this.allUnregisteredResources.slice(start, end)
+				this.unregisteredResources = [...this.unregisteredResources, ...newData]
+				this.unregisteredLoading = false
+			},
 			// 加载我的资源数据
 			async loadMyResources() {
 				try {
@@ -453,21 +572,35 @@ export default {
 								// 确保isUser是数字类型
 								isUser = parseInt(isUser) || 0
 								
+								// 处理userId字段,支持多种可能的字段名(userId或user_id)
+								let userId = item.userId !== null && item.userId !== undefined ? item.userId : 
+								            (item.user_id !== null && item.user_id !== undefined ? item.user_id : null)
+								// 确保userId是数字类型或null
+								if (userId !== null && userId !== undefined) {
+									userId = parseInt(userId)
+									if (isNaN(userId) || userId <= 0) {
+										userId = null
+									}
+								}
+								
 								// 处理isMatch字段
 								let isMatch = item.isMatch !== null && item.isMatch !== undefined ? item.isMatch : 
 								              (item.is_match !== null && item.is_match !== undefined ? item.is_match : 0)
 								isMatch = parseInt(isMatch) || 0
 								
-								// 调试日志:检查isUser字段
-								console.log('=== isUser字段处理 ===')
+								// 调试日志:检查isUser和userId字段
+								console.log('=== isUser和userId字段处理 ===')
 								console.log('资源ID:', resourceId, '姓名:', item.name)
 								console.log('原始数据:', {
 									isUser: item.isUser,
 									is_user: item.is_user,
+									userId: item.userId,
+									user_id: item.user_id,
 									'item完整对象': item
 								})
 								console.log('处理后的isUser值:', isUser, '类型:', typeof isUser)
-								console.log('=== isUser字段处理结束 ===')
+								console.log('处理后的userId值:', userId, '类型:', typeof userId)
+								console.log('=== isUser和userId字段处理结束 ===')
 								
 								// 处理标签(从后端返回的tags字段,如果没有则使用原有的labels)
 								let resourceTags = []
@@ -479,13 +612,16 @@ export default {
 									resourceTags = labels
 								}
 								
-								return {
-									id: resourceId,
+								const resourceObj = {
+									id: resourceId, // 主要使用的ID字段
+									resourceId: resourceId, // 备用ID字段,确保兼容性
+									resource_id: resourceId, // 备用ID字段,确保兼容性
 									avatar: avatarUrl, // 使用处理后的头像URL
 									name: item.name || '',
 									gender: item.gender === 1 ? '男' : item.gender === 2 ? '女' : '未知',
-									status: '已审核', // 可以根据实际字段判断
+									status: item.status !== undefined && item.status !== null ? item.status : 0, // 审核状态,默认为0(待审核)
 									isUser: isUser, // 添加isUser字段,默认为0
+									userId: userId, // 添加userId字段,可能为null
 									isMatch: isMatch, // 添加isMatch字段,默认为0
 									isPlus: false,
 									labels: resourceTags, // 使用处理后的标签列表
@@ -494,22 +630,37 @@ export default {
 									originalPhone: item.phone || '', // 保存原始完整手机号用于复制
 									isQuality: false
 								}
+								console.log('创建资源对象 - ID:', resourceObj.id, '名称:', resourceObj.name, 'isUser:', resourceObj.isUser, 'userId:', resourceObj.userId)
+								return resourceObj
 							}).filter(item => item !== null) // 过滤掉无效的资源(resourceId无效的)
 							
-							// 将资源分为两部分:已注册和未注册
-							this.registeredResources = allResources.filter(item => item.isUser === 1)
-							this.unregisteredResources = allResources.filter(item => item.isUser === 0)
+							// 将资源分为两部分:已注册和未注册(保存全部数据)
+							// 已注册用户条件:isUser === 1 且 userId !== null 且 userId !== undefined
+							this.allRegisteredResources = allResources.filter(item => {
+								const isRegistered = item.isUser === 1 && item.userId !== null && item.userId !== undefined
+								return isRegistered
+							})
+							// 未注册用户(线索):isUser !== 1 或 userId === null 或 userId === undefined
+							this.allUnregisteredResources = allResources.filter(item => {
+								const isUnregistered = item.isUser !== 1 || item.userId === null || item.userId === undefined
+								return isUnregistered
+							})
 							
 							// 设置总数
-							this.registeredTotal = this.registeredResources.length
-							this.unregisteredTotal = this.unregisteredResources.length
+							this.registeredTotal = this.allRegisteredResources.length
+							this.unregisteredTotal = this.allUnregisteredResources.length
+							
+							console.log('数据分类完成 - 全部资源:', allResources.length, '已注册:', this.allRegisteredResources.length, '未注册:', this.allUnregisteredResources.length)
 							
-							// 如果当前页超出范围,重置到第一页
-							if (this.registeredPageNum > Math.ceil(this.registeredTotal / this.registeredPageSize) && this.registeredTotal > 0) {
+							// 根据当前标签加载第一页数据
+							if (this.currentTab === 'resource') {
 								this.registeredPageNum = 1
-							}
-							if (this.unregisteredPageNum > Math.ceil(this.unregisteredTotal / this.unregisteredPageSize) && this.unregisteredTotal > 0) {
+								this.loadRegisteredPage(1)
+								console.log('加载资源第一页后 - registeredResources.length:', this.registeredResources.length)
+							} else {
 								this.unregisteredPageNum = 1
+								this.loadUnregisteredPage(1)
+								console.log('加载线索第一页后 - unregisteredResources.length:', this.unregisteredResources.length)
 							}
 							
 							// 保留resources用于兼容(包含所有资源)
@@ -530,37 +681,18 @@ export default {
 				// 重新加载资源数据,包含搜索关键词
 				await this.loadMyResources()
 		},
-		// 资源上一页
-		prevRegisteredPage() {
-			if (this.registeredPageNum > 1) {
-				this.registeredPageNum--
-			}
-		},
-		// 资源下一页
-		nextRegisteredPage() {
-			const totalPages = Math.ceil(this.registeredTotal / this.registeredPageSize)
-			if (this.registeredPageNum < totalPages) {
-				this.registeredPageNum++
-			}
-		},
-		// 线索上一页
-		prevUnregisteredPage() {
-			if (this.unregisteredPageNum > 1) {
-				this.unregisteredPageNum--
-			}
-		},
-		// 线索下一页
-		nextUnregisteredPage() {
-			const totalPages = Math.ceil(this.unregisteredTotal / this.unregisteredPageSize)
-			if (this.unregisteredPageNum < totalPages) {
-				this.unregisteredPageNum++
-			}
-		},
 		// 删除资源
 		async handleDelete(id) {
-				// 验证id是否有效
+				// 如果id无效,尝试从当前资源列表中查找
 				if (id === null || id === undefined || id === 'undefined' || id === 'null' || id === '') {
-					console.error('删除资源失败: 资源ID无效', id)
+					console.warn('删除资源失败: 资源ID无效,尝试从资源列表中查找', id)
+					// 尝试从当前显示的资源中找到对应的资源
+					const allDisplayData = this.currentTab === 'resource' 
+						? this.getRegisteredDisplayData 
+						: this.getUnregisteredDisplayData
+					
+					// 如果仍然找不到,显示错误
+					console.error('删除资源失败: 无法获取资源ID', id)
 					uni.showToast({
 						title: '资源ID无效,无法删除',
 						icon: 'none'
@@ -569,16 +701,26 @@ export default {
 				}
 				
 				// 确保id是有效的整数
-				const resourceId = parseInt(id)
+				let resourceId = parseInt(id)
 				if (isNaN(resourceId) || resourceId <= 0) {
-					console.error('删除资源失败: 资源ID格式错误', id)
-					uni.showToast({
-						title: '资源ID格式错误,无法删除',
-						icon: 'none'
-					})
-					return
+					// 如果解析失败,尝试从字符串中提取数字
+					const match = String(id).match(/\d+/)
+					if (match) {
+						resourceId = parseInt(match[0])
+					}
+					
+					if (isNaN(resourceId) || resourceId <= 0) {
+						console.error('删除资源失败: 资源ID格式错误', id, '类型:', typeof id)
+						uni.showToast({
+							title: '资源ID格式错误,无法删除',
+							icon: 'none'
+						})
+						return
+					}
 				}
 				
+				console.log('准备删除资源,ID:', resourceId, '原始ID:', id)
+				
 				uni.showModal({
 					title: '删除确认',
 					content: '确定要删除该资源吗?',
@@ -615,9 +757,7 @@ export default {
 										icon: 'success'
 									})
 									
-									// 删除成功后刷新资源列表,并重置分页
-									this.registeredPageNum = 1
-									this.unregisteredPageNum = 1
+									// 删除成功后刷新资源列表
 									await this.loadMyResources()
 								} else {
 									uni.showToast({
@@ -651,8 +791,8 @@ export default {
 				return
 			}
 			
-			// 检查用户是否已注册
-			if (resource.isUser !== 1) {
+			// 检查用户是否已注册(isUser === 1 且 userId !== null)
+			if (resource.isUser !== 1 || resource.userId === null || resource.userId === undefined) {
 				uni.showToast({
 					title: '该用户还未注册用户端,注册之后才能进行匹配',
 					icon: 'none',
@@ -709,8 +849,8 @@ export default {
 			console.log('item.id:', item.id)
 			console.log('item.isUser:', item.isUser)
 			
-			// 判断是否为已注册用户
-			if (item.isUser === 1) {
+			// 判断是否为已注册用户(isUser === 1 且 userId !== null)
+			if (item.isUser === 1 && item.userId !== null && item.userId !== undefined) {
 				// 已注册,跳转到客户详情页面
 				const resourceId = item.id
 				console.log('准备跳转,resourceId:', resourceId)
@@ -782,11 +922,67 @@ export default {
 			// 清除之前的定时器
 			this.stopAutoRefresh()
 			// 每30秒刷新一次,检查用户注册状态变化
-			this.refreshTimer = setInterval(() => {
+			this.refreshTimer = setInterval(async () => {
 				console.log('定时刷新:检查用户注册状态变化')
-				this.loadMyResources()
+				// 先批量检查并更新线索用户的注册状态
+				await this.batchCheckClueRegistrationStatus()
+				// 然后刷新资源列表
+				await this.loadMyResources()
 			}, 30000) // 30秒
 		},
+		// 批量检查并更新线索用户的注册状态
+		async batchCheckClueRegistrationStatus() {
+			try {
+				// 获取红娘ID,优先使用userInfo中的matchmakerId,否则使用userId
+				const userInfo = uni.getStorageSync('userInfo') || {}
+				const userId = uni.getStorageSync('userId')
+				let matchmakerId = userInfo.matchmakerId || userId || null
+				
+				if (!matchmakerId) {
+					console.warn('未找到红娘ID,跳过批量检查线索用户注册状态')
+					return
+				}
+				
+				// 确保matchmakerId是有效的整数
+				matchmakerId = parseInt(matchmakerId)
+				if (isNaN(matchmakerId) || matchmakerId <= 0) {
+					console.warn('红娘ID无效,跳过批量检查线索用户注册状态')
+					return
+				}
+				
+				const baseUrl = process.env.NODE_ENV === 'development' 
+					? 'http://localhost:8083/api'  // 开发环境 - 通过网关
+					: 'https://your-domain.com/api'  // 生产环境
+				
+				console.log('开始批量检查线索用户注册状态...', '红娘ID:', matchmakerId)
+				
+				const [error, res] = await uni.request({
+					url: `${baseUrl}/my-resource/batch-check-clue-registration`,
+					method: 'POST',
+					data: {
+						matchmakerId: matchmakerId
+					}
+				})
+				
+				if (error) {
+					console.error('批量检查线索用户注册状态失败:', error)
+					return
+				}
+				
+				if (res.statusCode === 200 && res.data && res.data.code === 200) {
+					const updateCount = res.data.data?.updateCount || 0
+					if (updateCount > 0) {
+						console.log(`✅ 批量检查完成,更新了 ${updateCount} 条线索用户记录`)
+					} else {
+						console.log('✅ 批量检查完成,没有需要更新的线索用户')
+					}
+				} else {
+					console.warn('批量检查线索用户注册状态返回异常:', res.data)
+				}
+			} catch (e) {
+				console.error('批量检查线索用户注册状态时发生异常:', e)
+			}
+		},
 		// 停止自动刷新
 		stopAutoRefresh() {
 			if (this.refreshTimer) {
@@ -813,9 +1009,9 @@ export default {
 		// 图片加载错误处理(内部方法)
 		handleImageError(index, type) {
 			try {
-				// 获取当前的数据
-				const pageData = type === 'registered' ? this.getRegisteredPageData : this.getUnregisteredPageData
-				const resource = pageData && pageData[index]
+				// 获取当前显示的数据
+				const displayData = type === 'registered' ? this.getRegisteredDisplayData : this.getUnregisteredDisplayData
+				const resource = displayData && displayData[index]
 				if (!resource) {
 					console.warn('图片加载失败:资源不存在,index:', index, 'type:', type)
 					return
@@ -845,16 +1041,26 @@ export default {
 					// 根据resourceId在全部数据中找到对应的资源并更新
 					console.log('图片加载失败,将URL设置为空,显示CSS默认背景')
 					if (type === 'registered') {
-						const fullList = this.registeredResources
-						const foundIndex = fullList.findIndex(item => item.id === resourceId)
-						if (foundIndex !== -1) {
-							this.$set(this.registeredResources[foundIndex], 'avatar', '')
+						// 更新全部数据
+						const allListIndex = this.allRegisteredResources.findIndex(item => item.id === resourceId)
+						if (allListIndex !== -1) {
+							this.$set(this.allRegisteredResources[allListIndex], 'avatar', '')
+						}
+						// 更新显示数据
+						const displayListIndex = this.registeredResources.findIndex(item => item.id === resourceId)
+						if (displayListIndex !== -1) {
+							this.$set(this.registeredResources[displayListIndex], 'avatar', '')
 						}
 					} else {
-						const fullList = this.unregisteredResources
-						const foundIndex = fullList.findIndex(item => item.id === resourceId)
-						if (foundIndex !== -1) {
-							this.$set(this.unregisteredResources[foundIndex], 'avatar', '')
+						// 更新全部数据
+						const allListIndex = this.allUnregisteredResources.findIndex(item => item.id === resourceId)
+						if (allListIndex !== -1) {
+							this.$set(this.allUnregisteredResources[allListIndex], 'avatar', '')
+						}
+						// 更新显示数据
+						const displayListIndex = this.unregisteredResources.findIndex(item => item.id === resourceId)
+						if (displayListIndex !== -1) {
+							this.$set(this.unregisteredResources[displayListIndex], 'avatar', '')
 						}
 					}
 				} else {
@@ -868,14 +1074,14 @@ export default {
 		// 图片加载成功处理(内部方法)
 		handleImageLoad(index, type) {
 			try {
-				// 获取当前的数据
-				const pageData = type === 'registered' ? this.getRegisteredPageData : this.getUnregisteredPageData
-				if (pageData && pageData[index]) {
+				// 获取当前显示的数据
+				const displayData = type === 'registered' ? this.getRegisteredDisplayData : this.getUnregisteredDisplayData
+				if (displayData && displayData[index]) {
 					console.log('图片加载成功:', {
 						index: index,
 						type: type,
-						resource: pageData[index]?.name,
-						avatarUrl: pageData[index]?.avatar
+						resource: displayData[index]?.name,
+						avatarUrl: displayData[index]?.avatar
 					})
 				}
 			} catch (e) {
@@ -919,6 +1125,64 @@ export default {
 	}
 	}
 
+	/* 资源/线索切换标签 */
+	.tab-switcher {
+		display: flex;
+		align-items: center;
+		background: #FFFFFF;
+		border-bottom: 1rpx solid #F0F0F0;
+		padding: 0 30rpx;
+
+		.tab-item {
+			flex: 1;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 25rpx 0;
+			position: relative;
+			cursor: pointer;
+			transition: all 0.3s;
+
+			.tab-text {
+				font-size: 32rpx;
+				font-weight: 500;
+				color: #666;
+				margin-right: 8rpx;
+			}
+
+			.tab-count {
+				font-size: 26rpx;
+				color: #999;
+			}
+
+			&.active {
+				.tab-text {
+					color: #9C27B0;
+					font-weight: bold;
+				}
+
+				.tab-count {
+					color: #9C27B0;
+				}
+
+				&::after {
+					content: '';
+					position: absolute;
+					bottom: 0;
+					left: 0;
+					right: 0;
+					height: 4rpx;
+					background: linear-gradient(135deg, #9C27B0 0%, #BA68C8 100%);
+					border-radius: 2rpx 2rpx 0 0;
+				}
+			}
+
+			&:active {
+				opacity: 0.7;
+			}
+		}
+	}
+
 	/* 搜索栏 */
 	.search-bar {
 		padding: 20rpx;
@@ -999,61 +1263,31 @@ export default {
 		}
 	}
 	
-	/* 分页控件 */
-	.pagination {
+	/* 加载更多提示 */
+	.load-more-tip {
 		display: flex;
-		align-items: center;
 		justify-content: center;
+		align-items: center;
 		padding: 30rpx 0;
-		gap: 30rpx;
-		margin-top: 20rpx;
 		
-		.pagination-btn {
-			padding: 12rpx 30rpx;
-			background: linear-gradient(135deg, #9C27B0 0%, #BA68C8 100%);
-			color: #FFFFFF;
-			border-radius: 25rpx;
+		.load-more-text {
 			font-size: 26rpx;
-			font-weight: 500;
-			text-align: center;
-			box-shadow: 0 2rpx 8rpx rgba(156, 39, 176, 0.3);
-			transition: all 0.3s;
-			
-			&:active {
-				transform: scale(0.95);
-				box-shadow: 0 1rpx 4rpx rgba(156, 39, 176, 0.4);
-			}
-			
-			&.disabled {
-				background: #E0E0E0;
-				color: #999;
-				box-shadow: none;
-				opacity: 0.6;
-				
-				&:active {
-					transform: none;
-				}
-			}
+			color: #999;
 		}
+	}
+	
+	/* 没有更多数据提示 */
+	.no-more-tip {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding: 30rpx 0;
 		
-		.pagination-info {
+		.no-more-text {
 			font-size: 26rpx;
-			color: #666;
-			font-weight: 500;
+			color: #999;
 		}
 	}
-	
-	/* 占位元素,用于保持固定高度 */
-	.resource-placeholder {
-		/* 使用与resource-item相同的高度和margin来占位 */
-		/* resource-item: padding 25rpx * 2 + margin-bottom 20rpx + 内容高度约250rpx = 约320rpx */
-		height: 320rpx;
-		margin-bottom: 20rpx;
-		/* 不显示内容,但保持空间 */
-		opacity: 0;
-		pointer-events: none;
-		flex-shrink: 0;
-	}
 
 	/* 空状态 */
 	.empty-state {
@@ -1193,6 +1427,32 @@ export default {
 								color: #FF9800;
 							}
 						}
+						
+						/* 审核状态标签样式 */
+						&.audit-tag {
+							margin-left: 10rpx;
+							
+							/* 待审核 - 橙色/黄色 */
+							&.audit-pending {
+								background: #FFF3E0;
+								color: #FF9800;
+								border: 1rpx solid #FFB74D;
+							}
+							
+							/* 审核通过 - 绿色 */
+							&.audit-approved {
+								background: #E8F5E9;
+								color: #4CAF50;
+								border: 1rpx solid #81C784;
+							}
+							
+							/* 审核未通过 - 红色 */
+							&.audit-rejected {
+								background: #FFEBEE;
+								color: #F44336;
+								border: 1rpx solid #E57373;
+							}
+						}
 					}
 				}
 			}

+ 131 - 27
LiangZhiYUMao/pages/matchmaker-workbench/quality-resources.vue

@@ -59,7 +59,7 @@
 					</view>
 					<view class="action-buttons">
 						<view class="action-btn add-resource-btn" @click.stop="handleAddToMyResources(index)">添加到我的资源</view>
-						<view class="action-btn chat-btn" @click.stop="handleChat(resource)">牵线聊聊</view>
+						<view class="action-btn chat-btn" @click.stop="handleChat(resource, index)">牵线聊聊</view>
 					</view>
 				</view>
 			</view>
@@ -171,10 +171,13 @@ export default {
 							console.log('phone:', firstRecord.phone)
 						}
 						
+						// 过滤掉空元素,确保数组中不包含 null 或 undefined
+						const validRecords = pageData.records.filter(record => record !== null && record !== undefined)
+						
 						if (this.pageNum === 1) {
-							this.resources = pageData.records
+							this.resources = validRecords
 						} else {
-							this.resources = this.resources.concat(pageData.records)
+							this.resources = this.resources.concat(validRecords)
 						}
 						
 						// 判断是否还有更多数据
@@ -238,26 +241,73 @@ export default {
 			})
 		},
 		// 牵线聊聊
-		handleChat(resource) {
+		handleChat(resource, index) {
 			console.log('=== 牵线聊聊 ===')
-			console.log('资源信息:', resource)
-			console.log('资源信息类型:', typeof resource)
-			console.log('资源信息的所有键:', resource ? Object.keys(resource) : 'resource为空')
+			console.log('传入的resource:', resource)
+			console.log('传入的index:', index, '类型:', typeof index)
+			console.log('resources数组长度:', this.resources ? this.resources.length : 'resources未定义')
+			
+			// 优先使用传入的 resource 对象,如果为空则通过 index 获取
+			let targetResource = resource
+			
+			// 如果传入的 resource 为空,尝试通过 index 获取
+			if (!targetResource || targetResource === null || targetResource === undefined) {
+				console.warn('⚠️ 传入的resource为空,尝试通过index获取')
+				
+				// 检查 resources 数组是否存在
+				if (!this.resources || !Array.isArray(this.resources)) {
+					console.error('❌ resources数组不存在或不是数组')
+					uni.showToast({
+						title: '资源列表异常,请刷新重试',
+						icon: 'none'
+					})
+					return
+				}
+				
+				// 检查index是否有效
+				if (index === undefined || index === null || isNaN(index) || index < 0 || index >= this.resources.length) {
+					console.error('❌ index无效:', index, '数组长度:', this.resources.length)
+					console.log('resources数组内容:', JSON.stringify(this.resources, null, 2))
+					uni.showToast({
+						title: '资源索引无效',
+						icon: 'none'
+					})
+					return
+				}
+				
+				// 从数组中获取resource对象
+				targetResource = this.resources[index]
+				console.log('从数组获取的resource对象:', targetResource)
+			}
+			
+			console.log('最终使用的resource对象:', targetResource)
+			console.log('资源信息类型:', typeof targetResource)
+			console.log('资源信息是否为null:', targetResource === null)
+			console.log('资源信息是否为undefined:', targetResource === undefined)
+			console.log('资源信息的所有键:', targetResource ? Object.keys(targetResource) : 'resource为空')
 			
 			// 验证 resource 对象是否存在
-			if (!resource) {
+			if (!targetResource || targetResource === null || targetResource === undefined) {
 				console.error('❌ resource对象为空')
+				console.error('传入的resource:', resource)
+				console.error('传入的index:', index)
+				console.error('resources数组:', JSON.stringify(this.resources, null, 2))
+				if (index !== undefined && index !== null && !isNaN(index) && index >= 0 && index < (this.resources ? this.resources.length : 0)) {
+					console.error('resources[index]:', this.resources[index])
+				}
 				uni.showToast({
-					title: '资源信息为空',
-					icon: 'none'
+					title: '资源信息为空,请刷新重试',
+					icon: 'none',
+					duration: 3000
 				})
 				return
 			}
 			
+			// 使用 targetResource 继续后续处理
 			// 检查用户是否已注册(只有已注册用户才能聊天)
 			// 支持下划线和驼峰两种格式
-			const isUser = resource.isUser !== undefined ? resource.isUser : 
-			              (resource.is_user !== undefined ? resource.is_user : 0)
+			const isUser = targetResource.isUser !== undefined ? targetResource.isUser : 
+			              (targetResource.is_user !== undefined ? targetResource.is_user : 0)
 			if (isUser !== 1 && isUser !== '1') {
 				console.warn('⚠️ 用户未注册,无法聊天')
 				uni.showToast({
@@ -272,25 +322,25 @@ export default {
 			let targetUserId = null
 			
 			// 方式1: 使用 userId 字段(驼峰格式)
-			if (resource.userId !== null && resource.userId !== undefined && resource.userId !== '') {
-				targetUserId = String(resource.userId)
-				console.log('✅ 从 resource.userId 获取用户ID:', targetUserId)
+			if (targetResource.userId !== null && targetResource.userId !== undefined && targetResource.userId !== '') {
+				targetUserId = String(targetResource.userId)
+				console.log('✅ 从 targetResource.userId 获取用户ID:', targetUserId)
 			}
 			// 方式2: 使用 user_id 字段(下划线格式)
-			else if (resource.user_id !== null && resource.user_id !== undefined && resource.user_id !== '') {
-				targetUserId = String(resource.user_id)
-				console.log('✅ 从 resource.user_id 获取用户ID:', targetUserId)
+			else if (targetResource.user_id !== null && targetResource.user_id !== undefined && targetResource.user_id !== '') {
+				targetUserId = String(targetResource.user_id)
+				console.log('✅ 从 targetResource.user_id 获取用户ID:', targetUserId)
 			}
 			// 方式3: 使用 id 字段
-			else if (resource.id !== null && resource.id !== undefined && resource.id !== '') {
-				targetUserId = String(resource.id)
-				console.log('✅ 从 resource.id 获取用户ID:', targetUserId)
+			else if (targetResource.id !== null && targetResource.id !== undefined && targetResource.id !== '') {
+				targetUserId = String(targetResource.id)
+				console.log('✅ 从 targetResource.id 获取用户ID:', targetUserId)
 			}
 			
 			// 如果仍然没有获取到用户ID
 			if (!targetUserId || targetUserId === 'null' || targetUserId === 'undefined' || targetUserId === '') {
 				console.error('❌ 无法获取用户ID')
-				console.log('resource对象完整内容:', JSON.stringify(resource, null, 2))
+				console.log('targetResource对象完整内容:', JSON.stringify(targetResource, null, 2))
 				uni.showToast({
 					title: '无法获取用户ID,请刷新重试',
 					icon: 'none',
@@ -300,8 +350,8 @@ export default {
 			}
 			
 			// 获取其他必要信息(支持下划线和驼峰格式)
-			const targetUserName = resource.name || '用户'
-			const targetUserAvatar = resource.avatarUrl || resource.avatar_url || resource.avatar || '/static/default-avatar.svg'
+			const targetUserName = targetResource.name || '用户'
+			const targetUserAvatar = targetResource.avatarUrl || targetResource.avatar_url || targetResource.avatar || '/static/default-avatar.svg'
 			
 			console.log('跳转参数:')
 			console.log('  - targetUserId:', targetUserId)
@@ -446,13 +496,63 @@ export default {
 			
 			try {
 				uni.showLoading({
-					title: '添加中...'
+					title: '检查中...'
 				})
 				
 				const baseUrl = process.env.NODE_ENV === 'development' 
 					? 'http://localhost:8083/api'  // 开发环境 - 通过网关
 					: 'https://your-domain.com/api'  // 生产环境
 				
+				// 获取要添加的手机号和备用手机号
+				const phone = resource.phone
+				const backupPhone = resource.backupPhone || resource.backup_phone
+				
+				// 检查手机号是否已存在(检查整个my_resource表,不限制红娘)
+				const checkUrl = `${baseUrl}/my-resource/check-phone?phone=${encodeURIComponent(phone || '')}${backupPhone ? '&backupPhone=' + encodeURIComponent(backupPhone) : ''}`
+				const [checkError, checkRes] = await uni.request({
+					url: checkUrl,
+					method: 'GET'
+				})
+				
+				if (checkError) {
+					console.error('检查手机号失败:', checkError)
+					uni.hideLoading()
+					uni.showToast({
+						title: '检查手机号失败,请重试',
+						icon: 'none'
+					})
+					return
+				}
+				
+				if (checkRes.statusCode === 200 && checkRes.data && checkRes.data.code === 200) {
+					const checkResult = checkRes.data.data
+					const existingResource = checkResult.existingResource
+					
+					// 如果发现重复的手机号,提示用户
+					if (checkResult.phoneExists || checkResult.backupPhoneExists || checkResult.phoneAsBackupExists || checkResult.backupPhoneAsMainExists) {
+						let message = '该手机号已经绑定资源啦'
+						
+						// 根据不同的检查结果,显示具体的手机号类型
+						if (checkResult.phoneExists) {
+							message = '该主手机号已经绑定资源啦'
+						} else if (checkResult.phoneAsBackupExists) {
+							message = '该主手机号已经作为备用手机号绑定资源啦'
+						} else if (checkResult.backupPhoneAsMainExists) {
+							message = '该备用手机号已经作为主手机号绑定资源啦'
+						} else if (checkResult.backupPhoneExists) {
+							message = '该备用手机号已经绑定资源啦'
+						}
+						
+						uni.hideLoading()
+						uni.showToast({
+							title: message,
+							icon: 'none',
+							duration: 3000
+						})
+						return
+					}
+				}
+				
 				// 构建要添加的资源数据(复制原资源的所有信息,但使用当前红娘的matchmaker_id)
 				const resourceData = {
 					name: resource.name,
@@ -468,14 +568,18 @@ export default {
 					domicile: resource.domicile,
 					occupation: resource.occupation,
 					house: resource.house,
-					phone: resource.phone,
-					backupPhone: resource.backupPhone || resource.backup_phone,
+					phone: phone,
+					backupPhone: backupPhone,
 					car: resource.car,
 					mateSelectionCriteria: resource.mateSelectionCriteria || resource.mate_selection_criteria,
 					isUser: resource.isUser || resource.is_user || 1,
 					userId: resource.userId || resource.user_id
 				}
 				
+				uni.showLoading({
+					title: '添加中...'
+				})
+				
 				// 获取标签ID列表
 				let tagIds = []
 				

+ 74 - 1
LiangZhiYUMao/pages/matchmaker-workbench/resource-input.vue

@@ -659,6 +659,66 @@ export default {
 					? 'http://localhost:8083/api'  // 开发环境 - 通过网关
 					: 'https://your-domain.com/api'  // 生产环境
 				
+				// 检查手机号是否已存在(检查整个my_resource表,不限制红娘)
+				const phone = submitData.phone
+				const backupPhone = submitData.backupPhone
+				
+				// 检查是否已登录
+				if (!this.currentUserId) {
+					uni.hideLoading()
+					uni.showToast({
+						title: '请先登录',
+						icon: 'none'
+					})
+					return
+				}
+				
+				// 调用检查接口
+				const checkUrl = `${baseUrl}/my-resource/check-phone?phone=${encodeURIComponent(phone || '')}${backupPhone ? '&backupPhone=' + encodeURIComponent(backupPhone) : ''}`
+				const [checkError, checkRes] = await uni.request({
+					url: checkUrl,
+					method: 'GET'
+				})
+				
+				if (checkError) {
+					console.error('检查手机号失败:', checkError)
+					uni.hideLoading()
+					uni.showToast({
+						title: '检查手机号失败,请重试',
+						icon: 'none'
+					})
+					return
+				}
+				
+				if (checkRes.statusCode === 200 && checkRes.data && checkRes.data.code === 200) {
+					const checkResult = checkRes.data.data
+					const existingResource = checkResult.existingResource
+					
+					// 如果发现重复的手机号,提示用户
+					if (checkResult.phoneExists || checkResult.backupPhoneExists || checkResult.phoneAsBackupExists || checkResult.backupPhoneAsMainExists) {
+						let message = '该手机号已经绑定资源啦'
+						
+						// 根据不同的检查结果,显示具体的手机号类型
+						if (checkResult.phoneExists) {
+							message = '该主手机号已经绑定资源啦'
+						} else if (checkResult.phoneAsBackupExists) {
+							message = '该主手机号已经作为备用手机号绑定资源啦'
+						} else if (checkResult.backupPhoneAsMainExists) {
+							message = '该备用手机号已经作为主手机号绑定资源啦'
+						} else if (checkResult.backupPhoneExists) {
+							message = '该备用手机号已经绑定资源啦'
+						}
+						
+						uni.hideLoading()
+						uni.showToast({
+							title: message,
+							icon: 'none',
+							duration: 3000
+						})
+						return
+					}
+				}
+				
 				// 构建请求URL,包含当前登录用户的ID作为参数(将作为红娘ID)
 				let url = `${baseUrl}/my-resource/add`
 				// 确保currentUserId是有效的整数才添加到URL中
@@ -681,8 +741,21 @@ export default {
 				uni.hideLoading()
 
 				if (res[1].statusCode === 200 && res[1].data.code === 200) {
+					// 获取返回的资源类型信息
+					const responseData = res[1].data.data
+					const resourceType = responseData && responseData.resourceType ? responseData.resourceType : '资源'
+					const isUser = responseData && responseData.isUser !== undefined ? responseData.isUser : null
+					
+					// 根据资源类型显示不同的成功提示
+					let successMessage = '添加资源成功'
+					if (isUser === 0 || resourceType === '线索') {
+						successMessage = '提交线索成功'
+					} else if (isUser === 1 || resourceType === '资源') {
+						successMessage = '添加资源成功'
+					}
+					
 					uni.showToast({
-						title: '提交成功',
+						title: successMessage,
 						icon: 'success'
 					})
 					

+ 199 - 2
service/homePage/src/main/java/com/zhentao/controller/MyResourceController.java

@@ -44,7 +44,7 @@ public class MyResourceController {
      * @return 添加结果
      */
     @PostMapping("/add")
-    public Result<MyResource> addResource(
+    public Result<java.util.Map<String, Object>> addResource(
             @RequestBody java.util.Map<String, Object> requestBody,
             @RequestParam(required = false) Integer currentUserId) {
         try {
@@ -113,6 +113,63 @@ public class MyResourceController {
                 return Result.error("手机号不能为空");
             }
             
+            // 检查手机号是否已在资源表中存在(检查整个my_resource表,不限制红娘)
+            String phone = myResource.getPhone().trim();
+            String backupPhone = myResource.getBackupPhone() != null ? myResource.getBackupPhone().trim() : null;
+            
+            System.out.println("=== 开始检查手机号重复 ===");
+            System.out.println("主手机号: " + phone);
+            System.out.println("备用手机号: " + backupPhone);
+            
+            // 检查主手机号是否已存在(使用count更可靠)
+            QueryWrapper<MyResource> phoneQueryWrapper = new QueryWrapper<>();
+            phoneQueryWrapper.eq("phone", phone);
+            long phoneCount = myResourceService.count(phoneQueryWrapper);
+            System.out.println("主手机号查询结果数量: " + phoneCount);
+            if (phoneCount > 0) {
+                MyResource existingResourceByPhone = myResourceService.getOne(phoneQueryWrapper);
+                System.out.println("找到重复的主手机号,资源名称: " + (existingResourceByPhone != null ? existingResourceByPhone.getName() : "未知"));
+                return Result.error("手机号 " + phone + " 已被资源\"" + (existingResourceByPhone != null && existingResourceByPhone.getName() != null ? existingResourceByPhone.getName() : "未知") + "\"使用,不能重复添加");
+            }
+            
+            // 检查主手机号是否作为其他资源的备用手机号存在
+            QueryWrapper<MyResource> phoneAsBackupQueryWrapper = new QueryWrapper<>();
+            phoneAsBackupQueryWrapper.eq("backup_phone", phone);
+            long phoneAsBackupCount = myResourceService.count(phoneAsBackupQueryWrapper);
+            System.out.println("主手机号作为备用手机号查询结果数量: " + phoneAsBackupCount);
+            if (phoneAsBackupCount > 0) {
+                MyResource existingResourceByPhoneAsBackup = myResourceService.getOne(phoneAsBackupQueryWrapper);
+                System.out.println("找到重复的主手机号(作为备用手机号),资源名称: " + (existingResourceByPhoneAsBackup != null ? existingResourceByPhoneAsBackup.getName() : "未知"));
+                return Result.error("手机号 " + phone + " 已被资源\"" + (existingResourceByPhoneAsBackup != null && existingResourceByPhoneAsBackup.getName() != null ? existingResourceByPhoneAsBackup.getName() : "未知") + "\"作为备用手机号使用,不能重复添加");
+            }
+            
+            // 检查备用手机号是否已存在(如果提供了备用手机号)
+            if (backupPhone != null && !backupPhone.isEmpty()) {
+                // 检查备用手机号是否作为主手机号存在
+                QueryWrapper<MyResource> backupPhoneAsMainQueryWrapper = new QueryWrapper<>();
+                backupPhoneAsMainQueryWrapper.eq("phone", backupPhone);
+                long backupPhoneAsMainCount = myResourceService.count(backupPhoneAsMainQueryWrapper);
+                System.out.println("备用手机号作为主手机号查询结果数量: " + backupPhoneAsMainCount);
+                if (backupPhoneAsMainCount > 0) {
+                    MyResource existingResourceByBackupAsMain = myResourceService.getOne(backupPhoneAsMainQueryWrapper);
+                    System.out.println("找到重复的备用手机号(作为主手机号),资源名称: " + (existingResourceByBackupAsMain != null ? existingResourceByBackupAsMain.getName() : "未知"));
+                    return Result.error("备用手机号 " + backupPhone + " 已被资源\"" + (existingResourceByBackupAsMain != null && existingResourceByBackupAsMain.getName() != null ? existingResourceByBackupAsMain.getName() : "未知") + "\"作为主手机号使用,不能重复添加");
+                }
+                
+                // 检查备用手机号是否作为备用手机号存在
+                QueryWrapper<MyResource> backupPhoneQueryWrapper = new QueryWrapper<>();
+                backupPhoneQueryWrapper.eq("backup_phone", backupPhone);
+                long backupPhoneCount = myResourceService.count(backupPhoneQueryWrapper);
+                System.out.println("备用手机号查询结果数量: " + backupPhoneCount);
+                if (backupPhoneCount > 0) {
+                    MyResource existingResourceByBackup = myResourceService.getOne(backupPhoneQueryWrapper);
+                    System.out.println("找到重复的备用手机号,资源名称: " + (existingResourceByBackup != null ? existingResourceByBackup.getName() : "未知"));
+                    return Result.error("备用手机号 " + backupPhone + " 已被资源\"" + (existingResourceByBackup != null && existingResourceByBackup.getName() != null ? existingResourceByBackup.getName() : "未知") + "\"使用,不能重复添加");
+                }
+            }
+            
+            System.out.println("=== 手机号检查通过,没有重复 ===");
+            
             // 根据手机号查询用户表中是否存在该用户
             QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
             userQueryWrapper.eq("phone", myResource.getPhone());
@@ -166,10 +223,31 @@ public class MyResourceController {
                 }
             }
             
+            // 设置默认审核状态为0(待审核)
+            if (myResource.getStatus() == null) {
+                myResource.setStatus(0);
+                System.out.println("设置默认审核状态: 0 (待审核)");
+            }
+            
+            // 判断资源类型(根据isUser字段:1是资源,0是线索)
+            String resourceType = (myResource.getIsUser() != null && myResource.getIsUser() == 1) ? "资源" : "线索";
+            System.out.println("资源类型: " + resourceType + " (isUser=" + myResource.getIsUser() + ")");
+            
             // 保存资源信息和标签关联
             boolean success = myResourceService.addResource(myResource, tagIds);
             if (success) {
-                return Result.success("资源信息添加成功", myResource);
+                // 构建返回数据,包含资源类型信息
+                java.util.Map<String, Object> resultData = new java.util.HashMap<>();
+                resultData.put("resource", myResource);
+                resultData.put("resourceType", resourceType);
+                resultData.put("isUser", myResource.getIsUser());
+                
+                String successMessage = "资源信息添加成功";
+                if (resourceType.equals("线索")) {
+                    successMessage = "线索信息添加成功";
+                }
+                
+                return Result.success(successMessage, resultData);
             } else {
                 return Result.error("资源信息添加失败");
             }
@@ -672,5 +750,124 @@ public class MyResourceController {
             return Result.error("查询标签ID列表失败:" + e.getMessage());
         }
     }
+    
+    /**
+     * 检查手机号是否已存在(检查整个my_resource表)
+     * 
+     * @param phone 主手机号
+     * @param backupPhone 备用手机号(可选)
+     * @return 检查结果,如果存在则返回资源信息
+     */
+    @GetMapping("/check-phone")
+    public Result<java.util.Map<String, Object>> checkPhone(
+            @RequestParam String phone,
+            @RequestParam(required = false) String backupPhone) {
+        try {
+            java.util.Map<String, Object> result = new java.util.HashMap<>();
+            result.put("phoneExists", false);
+            result.put("backupPhoneExists", false);
+            result.put("phoneAsBackupExists", false);
+            result.put("backupPhoneAsMainExists", false);
+            result.put("existingResource", null);
+            
+            String phoneTrimmed = phone != null ? phone.trim() : "";
+            String backupPhoneTrimmed = backupPhone != null ? backupPhone.trim() : null;
+            
+            System.out.println("=== check-phone 接口调用 ===");
+            System.out.println("主手机号: " + phoneTrimmed);
+            System.out.println("备用手机号: " + backupPhoneTrimmed);
+            
+            // 检查主手机号是否已存在(使用count更可靠)
+            QueryWrapper<MyResource> phoneQueryWrapper = new QueryWrapper<>();
+            phoneQueryWrapper.eq("phone", phoneTrimmed);
+            long phoneCount = myResourceService.count(phoneQueryWrapper);
+            System.out.println("主手机号查询结果数量: " + phoneCount);
+            if (phoneCount > 0) {
+                MyResource existingResourceByPhone = myResourceService.getOne(phoneQueryWrapper);
+                result.put("phoneExists", true);
+                result.put("existingResource", existingResourceByPhone);
+                System.out.println("找到重复的主手机号,资源名称: " + (existingResourceByPhone != null ? existingResourceByPhone.getName() : "未知"));
+                return Result.success(result);
+            }
+            
+            // 检查主手机号是否作为备用手机号存在
+            QueryWrapper<MyResource> phoneAsBackupQueryWrapper = new QueryWrapper<>();
+            phoneAsBackupQueryWrapper.eq("backup_phone", phoneTrimmed);
+            long phoneAsBackupCount = myResourceService.count(phoneAsBackupQueryWrapper);
+            System.out.println("主手机号作为备用手机号查询结果数量: " + phoneAsBackupCount);
+            if (phoneAsBackupCount > 0) {
+                MyResource existingResourceByPhoneAsBackup = myResourceService.getOne(phoneAsBackupQueryWrapper);
+                result.put("phoneAsBackupExists", true);
+                result.put("existingResource", existingResourceByPhoneAsBackup);
+                System.out.println("找到重复的主手机号(作为备用手机号),资源名称: " + (existingResourceByPhoneAsBackup != null ? existingResourceByPhoneAsBackup.getName() : "未知"));
+                return Result.success(result);
+            }
+            
+            // 如果提供了备用手机号,检查备用手机号
+            if (backupPhoneTrimmed != null && !backupPhoneTrimmed.isEmpty()) {
+                // 检查备用手机号是否作为主手机号存在
+                QueryWrapper<MyResource> backupPhoneAsMainQueryWrapper = new QueryWrapper<>();
+                backupPhoneAsMainQueryWrapper.eq("phone", backupPhoneTrimmed);
+                long backupPhoneAsMainCount = myResourceService.count(backupPhoneAsMainQueryWrapper);
+                System.out.println("备用手机号作为主手机号查询结果数量: " + backupPhoneAsMainCount);
+                if (backupPhoneAsMainCount > 0) {
+                    MyResource existingResourceByBackupAsMain = myResourceService.getOne(backupPhoneAsMainQueryWrapper);
+                    result.put("backupPhoneAsMainExists", true);
+                    result.put("existingResource", existingResourceByBackupAsMain);
+                    System.out.println("找到重复的备用手机号(作为主手机号),资源名称: " + (existingResourceByBackupAsMain != null ? existingResourceByBackupAsMain.getName() : "未知"));
+                    return Result.success(result);
+                }
+                
+                // 检查备用手机号是否作为备用手机号存在
+                QueryWrapper<MyResource> backupPhoneQueryWrapper = new QueryWrapper<>();
+                backupPhoneQueryWrapper.eq("backup_phone", backupPhoneTrimmed);
+                long backupPhoneCount = myResourceService.count(backupPhoneQueryWrapper);
+                System.out.println("备用手机号查询结果数量: " + backupPhoneCount);
+                if (backupPhoneCount > 0) {
+                    MyResource existingResourceByBackup = myResourceService.getOne(backupPhoneQueryWrapper);
+                    result.put("backupPhoneExists", true);
+                    result.put("existingResource", existingResourceByBackup);
+                    System.out.println("找到重复的备用手机号,资源名称: " + (existingResourceByBackup != null ? existingResourceByBackup.getName() : "未知"));
+                    return Result.success(result);
+                }
+            }
+            
+            System.out.println("=== check-phone 检查通过,没有重复 ===");
+            return Result.success(result);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return Result.error("检查手机号失败:" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 批量检查并更新线索用户的注册状态
+     * 定时刷新线索列表中的所有线索用户,根据线索用户的手机号在users表中检索
+     * 如果users表中存在该用户,则更新该线索用户的is_user字段为1和user_id字段
+     * 
+     * @param matchmakerId 红娘ID(可选,如果提供则只检查该红娘的线索)
+     * @return 更新结果,包含更新的资源数量
+     */
+    @PostMapping("/batch-check-clue-registration")
+    public Result<java.util.Map<String, Object>> batchCheckAndUpdateClueRegistrationStatus(
+            @RequestParam(required = false) Integer matchmakerId) {
+        try {
+            System.out.println("=== 收到批量检查线索用户注册状态请求 ===");
+            if (matchmakerId != null) {
+                System.out.println("红娘ID: " + matchmakerId);
+            }
+            
+            int updateCount = myResourceService.batchCheckAndUpdateClueRegistrationStatus(matchmakerId);
+            
+            java.util.Map<String, Object> result = new java.util.HashMap<>();
+            result.put("updateCount", updateCount);
+            result.put("message", "批量检查完成,共更新 " + updateCount + " 条线索用户记录");
+            
+            return Result.success("批量检查完成", result);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return Result.error("批量检查线索用户注册状态失败:" + e.getMessage());
+        }
+    }
 }
 

+ 20 - 0
service/homePage/src/main/java/com/zhentao/entity/MyResource.java

@@ -131,6 +131,26 @@ public class MyResource implements Serializable {
     @TableField("user_id")
     private Integer userId;
 
+    /**
+     * 审核状态(0:待审核,1:审核通过,2:审核失败)
+     */
+    @TableField("status")
+    private Integer status;
+
+    /**
+     * 审核失败原因
+     */
+    @TableField(value = "reject_reason", insertStrategy = com.baomidou.mybatisplus.annotation.FieldStrategy.IGNORED)
+    @JsonProperty("rejectReason")
+    private String rejectReason;
+
+    /**
+     * 奖励积分(用于后台开发人员计算红娘积分)
+     */
+    @TableField(value = "reward_points", insertStrategy = com.baomidou.mybatisplus.annotation.FieldStrategy.IGNORED)
+    @JsonProperty("rewardPoints")
+    private Integer rewardPoints;
+
     /**
      * 
      */

+ 9 - 0
service/homePage/src/main/java/com/zhentao/service/MyResourceService.java

@@ -91,4 +91,13 @@ public interface MyResourceService extends IService<MyResource> {
      * @return 标签ID列表
      */
     List<Integer> getTagIdsByResourceId(Integer resourceId);
+    
+    /**
+     * 批量检查并更新线索用户的注册状态
+     * 检查所有线索用户(is_user=0或null)的手机号是否在users表中已注册
+     * 如果已注册,则更新is_user=1和user_id
+     * @param matchmakerId 红娘ID(可选,如果提供则只检查该红娘的线索)
+     * @return 更新的资源数量
+     */
+    int batchCheckAndUpdateClueRegistrationStatus(Integer matchmakerId);
 }

+ 97 - 0
service/homePage/src/main/java/com/zhentao/service/impl/MyResourceServiceImpl.java

@@ -814,6 +814,103 @@ public class MyResourceServiceImpl extends ServiceImpl<MyResourceMapper, MyResou
         }
         return sb.length() > 0 ? sb.toString().trim() : "暂无要求";
     }
+    
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int batchCheckAndUpdateClueRegistrationStatus(Integer matchmakerId) {
+        int updateCount = 0;
+        try {
+            System.out.println("=== 开始批量检查并更新线索用户注册状态 ===");
+            if (matchmakerId != null) {
+                System.out.println("红娘ID: " + matchmakerId);
+            }
+            
+            // 查询所有线索用户(is_user=0或null,且user_id为null)
+            QueryWrapper<MyResource> queryWrapper = new QueryWrapper<>();
+            queryWrapper.and(wrapper -> wrapper
+                .eq("is_user", 0)
+                .or()
+                .isNull("is_user")
+            );
+            queryWrapper.and(wrapper -> wrapper
+                .isNull("user_id")
+                .or()
+                .eq("user_id", 0)
+            );
+            
+            // 如果提供了红娘ID,则只检查该红娘的线索
+            if (matchmakerId != null) {
+                queryWrapper.eq("matchmaker_id", matchmakerId);
+            }
+            
+            List<MyResource> clueResources = this.list(queryWrapper);
+            
+            if (clueResources == null || clueResources.isEmpty()) {
+                System.out.println("未找到需要检查的线索用户");
+                return 0;
+            }
+            
+            System.out.println("找到 " + clueResources.size() + " 个线索用户需要检查");
+            
+            // 遍历每个线索用户,检查其手机号是否在users表中已注册
+            for (MyResource clueResource : clueResources) {
+                String phone = clueResource.getPhone();
+                String backupPhone = clueResource.getBackupPhone();
+                
+                // 检查主手机号
+                if (phone != null && !phone.trim().isEmpty()) {
+                    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
+                    userQueryWrapper.eq("phone", phone.trim());
+                    User user = userMapper.selectOne(userQueryWrapper);
+                    
+                    if (user != null && user.getUserId() != null) {
+                        // 找到匹配的用户,更新线索资源
+                        clueResource.setIsUser(1);
+                        clueResource.setUserId(user.getUserId());
+                        clueResource.setUpdateTime(new Date());
+                        boolean updated = this.updateById(clueResource);
+                        if (updated) {
+                            updateCount++;
+                            System.out.println("✅ 更新线索用户注册状态成功 - 资源ID: " + clueResource.getResourceId() + 
+                                             ", 手机号: " + phone + ", 用户ID: " + user.getUserId());
+                        } else {
+                            System.out.println("⚠️ 更新线索用户注册状态失败 - 资源ID: " + clueResource.getResourceId());
+                        }
+                        continue; // 已更新,跳过备用手机号检查
+                    }
+                }
+                
+                // 如果主手机号未找到匹配,检查备用手机号
+                if (backupPhone != null && !backupPhone.trim().isEmpty()) {
+                    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
+                    userQueryWrapper.eq("phone", backupPhone.trim());
+                    User user = userMapper.selectOne(userQueryWrapper);
+                    
+                    if (user != null && user.getUserId() != null) {
+                        // 找到匹配的用户,更新线索资源
+                        clueResource.setIsUser(1);
+                        clueResource.setUserId(user.getUserId());
+                        clueResource.setUpdateTime(new Date());
+                        boolean updated = this.updateById(clueResource);
+                        if (updated) {
+                            updateCount++;
+                            System.out.println("✅ 更新线索用户注册状态成功(通过备用手机号) - 资源ID: " + clueResource.getResourceId() + 
+                                             ", 备用手机号: " + backupPhone + ", 用户ID: " + user.getUserId());
+                        } else {
+                            System.out.println("⚠️ 更新线索用户注册状态失败 - 资源ID: " + clueResource.getResourceId());
+                        }
+                    }
+                }
+            }
+            
+            System.out.println("=== 批量检查并更新线索用户注册状态完成,共更新 " + updateCount + " 条记录 ===");
+            return updateCount;
+        } catch (Exception e) {
+            System.err.println("❌ 批量检查并更新线索用户注册状态时发生异常: " + e.getMessage());
+            e.printStackTrace();
+            return updateCount;
+        }
+    }
 }
 
 

+ 16 - 1
service/homePage/src/main/java/com/zhentao/vo/MyResourceVO.java

@@ -129,10 +129,25 @@ public class MyResourceVO implements Serializable {
     private Integer isUser;
     
     /**
-     * 用户ID(关联users表的user_id,如果isUser=1则此字段有值
+     * 用户ID(关联users表的user_id)
      */
     private Integer userId;
     
+    /**
+     * 审核状态(0:待审核,1:审核通过,2:审核失败)
+     */
+    private Integer status;
+    
+    /**
+     * 审核失败原因
+     */
+    private String rejectReason;
+    
+    /**
+     * 奖励积分(用于后台开发人员计算红娘积分)
+     */
+    private Integer rewardPoints;
+    
     /**
      * 标签列表(从my_resource_tag关联表查询)
      */

+ 9 - 0
service/homePage/src/main/resources/mapper/MyResourceMapper.xml

@@ -85,6 +85,9 @@
         <result property="avatarUrl" column="avatar_url" jdbcType="VARCHAR"/>
         <result property="isUser" column="is_user" jdbcType="INTEGER"/>
         <result property="userId" column="user_id" jdbcType="INTEGER"/>
+        <result property="status" column="status" jdbcType="INTEGER"/>
+        <result property="rejectReason" column="reject_reason" jdbcType="VARCHAR"/>
+        <result property="rewardPoints" column="reward_points" jdbcType="INTEGER"/>
         <result property="isMatch" column="is_match" jdbcType="INTEGER"/>
         <result property="isInvitation" column="is_invitation" jdbcType="INTEGER"/>
         <result property="invitationTime" column="invitation_time" jdbcType="TIMESTAMP"/>
@@ -114,6 +117,9 @@
             r.mate_selection_criteria,
             r.is_user,
             r.user_id,
+            r.status,
+            r.reject_reason,
+            r.reward_points,
             r.create_time,
             r.update_time,
             u.avatar_url,
@@ -173,6 +179,9 @@
             r.mate_selection_criteria,
             r.is_user,
             r.user_id,
+            r.status,
+            r.reject_reason,
+            r.reward_points,
             r.create_time,
             r.update_time,
             u.avatar_url,