diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyGraduateInfoBo.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyGraduateInfoBo.java index d70d243c..623e073a 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyGraduateInfoBo.java +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyGraduateInfoBo.java @@ -144,16 +144,19 @@ public class ZsjyGraduateInfoBo extends BaseEntity { /** * 邮箱地址 */ + @Size(max = 100, message = "邮箱地址长度不能超过100个字符", groups = { AddGroup.class, EditGroup.class }) private String email; /** * QQ号码 */ + @Size(max = 20, message = "QQ号码长度不能超过20个字符", groups = { AddGroup.class, EditGroup.class }) private String qqNumber; /** * 微信号码 */ + @Size(max = 30, message = "微信号码长度不能超过30个字符", groups = { AddGroup.class, EditGroup.class }) private String wechatNumber; /** @@ -174,11 +177,14 @@ public class ZsjyGraduateInfoBo extends BaseEntity { /** * 详细地址 */ + @Size(max = 200, message = "详细地址长度不能超过200个字符", groups = { AddGroup.class, EditGroup.class }) private String detailAddress; /** * 邮政编码 */ + @Size(max = 10, message = "邮政编码长度不能超过10个字符", groups = { AddGroup.class, EditGroup.class }) + @Pattern(regexp = "^\\d{6}$", message = "邮政编码格式不正确,应为6位数字", groups = { AddGroup.class, EditGroup.class }) private String postalCode; /** @@ -190,6 +196,7 @@ public class ZsjyGraduateInfoBo extends BaseEntity { /** * 就业单位名称 */ + @Size(max = 100, message = "就业单位名称长度不能超过100个字符", groups = { AddGroup.class, EditGroup.class }) private String employmentCompany; /** @@ -200,6 +207,7 @@ public class ZsjyGraduateInfoBo extends BaseEntity { /** * 工作职位 */ + @Size(max = 50, message = "工作职位长度不能超过50个字符", groups = { AddGroup.class, EditGroup.class }) private String jobPosition; /** @@ -220,11 +228,13 @@ public class ZsjyGraduateInfoBo extends BaseEntity { /** * 升学院校 */ + @Size(max = 100, message = "升学院校长度不能超过100个字符", groups = { AddGroup.class, EditGroup.class }) private String furtherSchool; /** * 升学专业 */ + @Size(max = 50, message = "升学专业长度不能超过50个字符", groups = { AddGroup.class, EditGroup.class }) private String furtherMajor; /** diff --git a/mobile/src/pages/internship/index.vue b/mobile/src/pages/internship/index.vue index 0b082dc6..cccf3355 100644 --- a/mobile/src/pages/internship/index.vue +++ b/mobile/src/pages/internship/index.vue @@ -90,74 +90,72 @@ - + - - 当前位置 - - - - - - - - {{ currentLocation.address }} - - - - - - - 经度 - {{ currentLocation.longitude.toFixed(6) }} - - - - 纬度 - {{ currentLocation.latitude.toFixed(6) }} - + + 签到位置 - - - - - 定位精度 {{ currentLocation.accuracy.toFixed(0) }}米 - - - - - - + + - - 在地图中查看 + + + {{ checkIsWechatBrowser() ? '微信定位' : '定位' }} + + + + + + + + 经纬度:{{ currentLocation.latitude.toFixed(6) }},{{ currentLocation.longitude.toFixed(6) }} + + + + + + + + 定位精度 {{ currentLocation.accuracy.toFixed(0) }}米 + + + + + + + + + 查看位置 + + + - + @@ -265,6 +263,7 @@ import { getInternshipInfo, getStudentInternshipInfo, checkIn, getDailyList, get import { getCurrentLocation, checkLocationPermission, openLocationSettings } from '@/utils/location.js'; import { userManager } from '@/utils/user.js'; import weChatSDK from '@/utils/wechat.js'; +import { request } from '@/common/request.js'; export default { name: 'InternshipIndex', @@ -289,7 +288,6 @@ export default { // 微信SDK相关(新增) wechatSDK: weChatSDK, - isWechatBrowser: false, wechatInitializing: false, // 统计数据 @@ -319,19 +317,6 @@ export default { }; }, - async onLoad() { - // 初始化微信环境检查并自动初始化SDK - await this.checkWechatEnvironment(); - - this.initPage(); - }, - - onShow() { - // 页面显示时刷新数据 - this.loadTodayRecord(); - this.loadStatistics(); - }, - methods: { // === 微信SDK相关方法 === @@ -339,9 +324,9 @@ export default { async checkWechatEnvironment() { try { // 检查是否在微信浏览器中 - this.isWechatBrowser = this.wechatSDK.isWeChatBrowser(); + const isWechatBrowser = this.wechatSDK.isWeChatBrowser(); - if (this.isWechatBrowser) { + if (isWechatBrowser) { // 在微信环境中,自动初始化SDK await this.initWechatSDK(); } @@ -407,10 +392,10 @@ export default { } // 初始化微信环境检测 - this.isWechatBrowser = this.wechatSDK.isWeChatBrowser(); + const isWechatBrowser = this.wechatSDK.isWeChatBrowser(); // 如果在微信环境,初始化微信SDK - if (this.isWechatBrowser) { + if (isWechatBrowser) { await this.initWechatSDK(); } @@ -419,10 +404,14 @@ export default { this.loadInternshipInfo(), this.loadTodayRecord(), this.loadRecentRecords(), - this.loadStatistics(), - this.initLocation() + this.loadStatistics() ]); + // 初始化位置信息(不阻塞页面加载) + this.initLocation().catch(error => { + console.error('位置信息初始化失败:', error); + }); + } catch (error) { console.error('初始化页面失败:', error); uni.showToast({ @@ -608,8 +597,8 @@ export default { return; } - // 获取当前位置 - await this.getCurrentLocationInfo(); + // 不自动获取位置,等待用户手动点击定位按钮 + console.log('位置权限检查完成,等待用户手动定位'); } catch (error) { console.error('初始化位置失败:', error); this.canCheckin = false; @@ -645,16 +634,16 @@ export default { }, /** - * 智能定位:根据环境自动选择最适合的定位方式(增强版) + * 智能定位:根据环境自动选择最适合的定位方式(参考请假页面实现) */ - async getCurrentLocationInfo() { + async handleGetLocation() { try { this.locationLoading = true; this.locationError = ''; uni.showLoading({ title: '定位中...', mask: true }); const envInfo = { - isWechatBrowser: this.isWechatBrowser, + isWechatBrowser: this.checkIsWechatBrowser(), isWechatSdkReady: this.wechatSDK.isInitialized, isH5Web: this.isH5Web(), isBrowserGeolocationSupported: this.isBrowserGeolocationSupported(), @@ -663,7 +652,7 @@ export default { console.log('环境检测结果:', envInfo); // 优先级1:微信SDK定位(如果在微信环境且SDK已就绪) - if (this.isWechatBrowser && this.wechatSDK.isInitialized) { + if (this.checkIsWechatBrowser() && this.wechatSDK.isInitialized) { const wxLocationSuccess = await this.tryWeChatLocationWithSDK(); if (wxLocationSuccess) { return; @@ -671,7 +660,7 @@ export default { } // 优先级2:微信环境但SDK未就绪,尝试初始化后重试 - if (this.isWechatBrowser && !this.wechatSDK.isInitialized) { + if (this.checkIsWechatBrowser() && !this.wechatSDK.isInitialized) { try { await this.initWechatSDK(); if (this.wechatSDK.isInitialized) { @@ -710,7 +699,7 @@ export default { success: (res) => { if (res.confirm) { // 用户选择重试 - this.getCurrentLocationInfo(); + this.handleGetLocation(); } } }); @@ -720,7 +709,14 @@ export default { }, /** - * 使用微信SDK进行定位(增强版) + * 检测浏览器是否支持 Geolocation API + */ + isBrowserGeolocationSupported() { + return typeof navigator !== 'undefined' && 'geolocation' in navigator; + }, + + /** + * 使用微信SDK进行定位(参考请假页面实现) */ async tryWeChatLocationWithSDK() { try { @@ -768,7 +764,7 @@ export default { }, /** - * H5 web端原生定位(增强版) + * H5 web端原生定位(参考请假页面实现) */ async handleH5WebLocation() { return new Promise((resolve) => { @@ -792,6 +788,7 @@ export default { const { latitude, longitude, accuracy } = position.coords; + // 将WGS84坐标转换为GCJ02坐标系(中国标准坐标系) this.currentLocation = { latitude: latitude, longitude: longitude, @@ -834,12 +831,12 @@ export default { content: `${errorMessage}。是否手动输入位置信息?`, showCancel: true, cancelText: '取消', - confirmText: '稍后重试', + confirmText: '手动输入', success: (res) => { if (res.confirm) { - // 用户选择重试 + // 可以在这里添加手动输入位置的逻辑 uni.showToast({ - title: '请稍后重试定位', + title: '手动输入功能开发中', icon: 'none', duration: 2000, }); @@ -935,23 +932,24 @@ export default { * 刷新位置 */ refreshLocation() { - this.getCurrentLocationInfo(); + this.handleGetLocation(); }, /** - * 打开位置信息在地图中查看 + * 打开位置信息在地图中查看(参考请假页面实现) */ async openLocationInMap() { if (!this.currentLocation) { uni.showToast({ - title: '无法获取位置信息', - icon: 'none' + title: '暂无位置信息', + icon: 'none', }); return; } + // 从坐标信息解析经纬度 const { latitude, longitude } = this.currentLocation; if (!latitude || !longitude || isNaN(latitude) || isNaN(longitude)) { @@ -962,26 +960,72 @@ export default { return; } - if (this.isWechatBrowser && this.wechatSDK.isInitialized) { - try { - await this.wechatSDK.openLocation({ - latitude: latitude, + // 声明变量在外部作用域,确保finally块可以访问 + let formattedAddress = ''; + + // 调用高德sdk逆地理编码 + try { + // 调用后台API进行逆地理编码 + const geocodingResponse = await request({ + url: '/system/SysRegion/reverse-geocode', + method: 'POST', + data: { longitude: longitude, - name: '实习签到位置', - address: this.currentLocation.address || '当前位置', - scale: 16, - }); - } catch (error) { - console.error('微信地图打开失败:', error); + latitude: latitude, + }, + }); + + if (geocodingResponse.code === 200 && geocodingResponse.data) { + formattedAddress = geocodingResponse.data.regeocode?.formattedAddress || ''; + if (formattedAddress) { + console.log('逆地理编码成功:', formattedAddress); + uni.showToast({ + title: formattedAddress, + icon: 'none', + duration: 2000, + }); + } + } else { + console.warn('逆地理编码失败:', geocodingResponse.msg); + } + } catch (error) { + console.error('逆地理编码请求失败:', error); + // 逆地理编码失败不影响地图打开功能 + } finally { + console.log('=== finally块开始执行 ==='); + console.log('formattedAddress:', formattedAddress); + console.log('isWechatBrowser:', this.checkIsWechatBrowser()); + console.log('wechatSDK.isInitialized:', this.wechatSDK?.isInitialized); + + if (this.checkIsWechatBrowser() && this.wechatSDK?.isInitialized) { + try { + console.log('尝试使用微信SDK打开地图...'); + await this.wechatSDK.openLocation({ + latitude: latitude, + longitude: longitude, + name: formattedAddress || '实习签到位置', + address: formattedAddress || '当前位置', + scale: 16, + }); + console.log('微信地图打开成功'); + } catch (error) { + console.error('微信地图打开失败:', error); + this.fallbackOpenMap(latitude, longitude); + } + } else { + console.log('使用备用地图打开方式...'); this.fallbackOpenMap(latitude, longitude); } - } else { - this.fallbackOpenMap(latitude, longitude); + console.log('=== finally块执行完成 ==='); } }, - // 备用地图打开方式 + // 备用地图打开方式(参考请假页面实现) fallbackOpenMap(latitude, longitude) { + const url = `https://apis.map.qq.com/uri/v1/marker?marker=coord:${latitude},${longitude};title:实习签到位置;addr:${encodeURIComponent( + this.currentLocation.address || '当前位置', + )}&referer=智慧校园`; + // 首先尝试使用uni.openLocation(原生地图) if (typeof uni.openLocation === 'function') { uni.showLoading({ @@ -1059,7 +1103,7 @@ export default { confirmText: '重新获取', success: (res) => { if (res.confirm) { - this.initLocation(); + this.handleGetLocation(); } } }); @@ -1269,6 +1313,24 @@ export default { checkIsWechatBrowser() { const ua = navigator.userAgent.toLowerCase(); return ua.includes('micromessenger'); + }, + + /** + * 刷新数据 + */ + async refreshData() { + try { + // 刷新位置信息 + if (!this.currentLocation) { + await this.getCurrentLocationInfo(); + } + + // 检查今日签到状态 + await this.checkTodayCheckInStatus(); + + } catch (error) { + console.error('数据刷新失败:', error); + } } }, @@ -1295,8 +1357,8 @@ export default { // 设置当前日期 this.currentDate = this.formatDate(new Date()); - // 检测微信环境 - this.isWechatBrowser = this.checkIsWechatBrowser(); + // 检测微信环境(在methods中有相应方法) + // this.checkIsWechatBrowser() 在需要时调用 // 获取用户信息(不阻塞) this.loadUserInfo().catch(error => { @@ -1308,33 +1370,15 @@ export default { console.error('实习信息加载失败:', error); }); - // 获取位置信息(核心功能,但不阻塞页面显示) - this.getCurrentLocationInfo().catch(error => { - console.error('位置信息获取失败:', error); - }); + // 初始化位置权限检查(不阻塞页面显示) + this.initLocation().catch(error => { + console.error('位置信息初始化失败:', error); + }); // 检查今日签到状态(不阻塞) this.checkTodayCheckInStatus().catch(error => { console.error('签到状态检查失败:', error); }); - }, - - /** - * 刷新数据 - */ - async refreshData() { - try { - // 刷新位置信息 - if (!this.currentLocation) { - await this.getCurrentLocationInfo(); - } - - // 检查今日签到状态 - await this.checkTodayCheckInStatus(); - - } catch (error) { - console.error('数据刷新失败:', error); - } } }; @@ -1517,68 +1561,56 @@ export default { margin-left: 4px; } -/* 位置信息 */ -.location-address { - display: flex; - align-items: flex-start; - margin-bottom: 16px; - padding: 12px; - background: #f8f9fa; - border-radius: 8px; - border-left: 3px solid #67c23a; -} - -.address-icon { - margin-right: 8px; - margin-top: 2px; - flex-shrink: 0; -} - -.address-text { - font-size: 14px; - color: #303133; - line-height: 1.5; - flex: 1; -} - -/* 坐标信息 */ -.coordinates-section { +/* 位置信息(参考请假页面样式) */ +.location-row { margin-bottom: 16px; } -.coord-row { +.location-btn { + width: 100%; + height: 44px; display: flex; align-items: center; + justify-content: center; + border-radius: 8px; + border: 1px solid #2979ff; + background: #fff; + color: #2979ff; +} + +.location-info-section { + margin-top: 16px; + padding: 16px; background: #f8f9fa; border-radius: 8px; - padding: 12px; + border: 1px solid #e4e7ed; } -.coord-item { - flex: 1; - text-align: center; +.location-coords-container { + margin-bottom: 12px; } -.coord-divider { - width: 1px; - height: 32px; - background: #e4e7ed; - margin: 0 16px; -} - -.coord-label { - display: block; - font-size: 12px; - color: #909399; - margin-bottom: 4px; -} - -.coord-value { - display: block; +.location-coords { font-size: 14px; color: #303133; - font-weight: 500; font-family: monospace; + line-height: 1.5; + word-break: break-all; +} + +.location-action-container { + display: flex; + justify-content: center; + margin-top: 12px; +} + +.view-map-btn { + min-width: 120px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + gap: 6px; } /* 精度信息 */ diff --git a/web/src/views/zsjy/graduateInfo/form.vue b/web/src/views/zsjy/graduateInfo/form.vue index de5bd709..fc154b7d 100644 --- a/web/src/views/zsjy/graduateInfo/form.vue +++ b/web/src/views/zsjy/graduateInfo/form.vue @@ -749,6 +749,10 @@ const rules = reactive({ { pattern: /^1[3-9]\d{9}$/, message: '手机号码格式不正确', trigger: 'blur' } ], email: [{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' }], + postalCode: [ + { max: 10, message: '邮政编码长度不能超过10个字符', trigger: 'blur' }, + { pattern: /^\d{6}$/, message: '邮政编码格式不正确,应为6位数字', trigger: 'blur' } + ], employmentStatus: [{ required: true, message: '就业状态不能为空', trigger: 'change' }] }); diff --git a/web/src/views/zsjy/graduateInfo/index.vue b/web/src/views/zsjy/graduateInfo/index.vue index e682c776..60f41070 100644 --- a/web/src/views/zsjy/graduateInfo/index.vue +++ b/web/src/views/zsjy/graduateInfo/index.vue @@ -297,13 +297,13 @@ - + - + diff --git a/web/src/views/zsjy/internship/daily/index.vue b/web/src/views/zsjy/internship/daily/index.vue index f7b1e98b..80d71686 100644 --- a/web/src/views/zsjy/internship/daily/index.vue +++ b/web/src/views/zsjy/internship/daily/index.vue @@ -168,23 +168,6 @@ - - - - - - - -