wuzhen update

This commit is contained in:
wuzhen committed 2025-08-15 22:49:51 +08:00
1 parent cbfe6be210
commit 2150f54555
7 files changed
+716 -155

No files matched your search

@@ -99,4 +99,22 @@ public class ZsjyInternshipDailyController extends BaseController {
return dailyService.getStatistics(queryBo); return dailyService.getStatistics(queryBo);
} }
/**
* 获取学生个人月度考勤统计(移动端专用)
*/
@Operation(summary = "获取学生月度统计", description = "获取指定学生的月度考勤统计数据")
@SaCheckPermission("zsjy:internshipdaily:statistics")
@GetMapping("/monthly-statistics")
public R<Map<String, Object>> getStudentMonthlyStatistics(
@Parameter(description = "学生ID", required = true) @RequestParam Long studentId,
@Parameter(description = "年份", required = true) @RequestParam Integer year,
@Parameter(description = "月份", required = true) @RequestParam Integer month) {
log.info("=== Controller层调试 ===");
log.info("接口被调用: /zsjy/internship/daily/monthly-statistics");
log.info("学生ID: {}, 年月: {}-{}", studentId, year, month);
return dailyService.getStudentMonthlyStatistics(studentId, year, month);
}
} }
@@ -61,6 +61,18 @@ public interface ZsjyInternshipDailyMapper extends BaseMapper<ZsjyInternshipDail
boolean existsByStudentAndDate(@Param("studentId") Long studentId, boolean existsByStudentAndDate(@Param("studentId") Long studentId,
@Param("checkDate") Date checkDate); @Param("checkDate") Date checkDate);
/**
* 获取学生个人月度考勤统计
*
* @param studentId 学生ID
* @param year 年份
* @param month 月份
* @return 学生月度统计数据
*/
Map<String, Object> selectStudentMonthlyStatistics(@Param("studentId") Long studentId,
@Param("year") Integer year,
@Param("month") Integer month);
/** /**
* 统计班主任管理的班级数量 * 统计班主任管理的班级数量
* *
@@ -61,4 +61,14 @@ public interface IZsjyInternshipDailyService {
*/ */
R<Map<String, Object>> getStatistics(ZsjyInternshipDailyQueryBo queryBo); R<Map<String, Object>> getStatistics(ZsjyInternshipDailyQueryBo queryBo);
/**
* 获取学生个人月度考勤统计
*
* @param studentId 学生ID
* @param year 年份
* @param month 月份
* @return 学生月度统计数据
*/
R<Map<String, Object>> getStudentMonthlyStatistics(Long studentId, Integer year, Integer month);
} }
@@ -216,6 +216,54 @@ public class ZsjyInternshipDailyServiceImpl implements IZsjyInternshipDailyServi
} }
} }
/**
* 获取学生个人月度考勤统计
*/
@Override
public R<Map<String, Object>> getStudentMonthlyStatistics(Long studentId, Integer year, Integer month) {
try {
// 1. 参数校验
if (ObjectUtil.isNull(studentId)) {
return R.fail("学生ID不能为空");
}
if (ObjectUtil.isNull(year) || ObjectUtil.isNull(month)) {
return R.fail("年月参数不能为空");
}
if (year < 2020 || year > 2030) {
return R.fail("年份参数不合法");
}
if (month < 1 || month > 12) {
return R.fail("月份参数不合法");
}
// 2. 查询学生月度统计数据
Map<String, Object> statistics = baseMapper.selectStudentMonthlyStatistics(studentId, year, month);
// 3. 补充默认值
if (ObjectUtil.isNull(statistics)) {
statistics = new HashMap<>();
statistics.put("totalDays", 0);
statistics.put("checkedDays", 0);
statistics.put("missedDays", 0);
statistics.put("exceptionDays", 0);
}
// 4. 确保数据类型正确
statistics.put("totalDays", ObjectUtil.defaultIfNull(statistics.get("totalDays"), 0));
statistics.put("checkedDays", ObjectUtil.defaultIfNull(statistics.get("checkedDays"), 0));
statistics.put("missedDays", ObjectUtil.defaultIfNull(statistics.get("missedDays"), 0));
statistics.put("exceptionDays", ObjectUtil.defaultIfNull(statistics.get("exceptionDays"), 0));
log.info("学生{}的{}-{}月度统计: {}", studentId, year, month, statistics);
return R.ok(statistics);
} catch (Exception e) {
log.error("获取学生月度统计数据失败: studentId={}, year={}, month={}, error={}",
studentId, year, month, e.getMessage(), e);
return R.fail("获取学生月度统计数据失败: " + e.getMessage());
}
}
/** /**
* 设置数据权限(班主任只能查看自己班级的学生数据) * 设置数据权限(班主任只能查看自己班级的学生数据)
*/ */
@@ -184,6 +184,44 @@
) as attendanceRate ) as attendanceRate
</select> </select>
<!-- 获取学生个人月度考勤统计 -->
<select id="selectStudentMonthlyStatistics" resultType="java.util.Map">
<![CDATA[
SELECT
-- 本月工作日总天数(简化计算,按22天计算)
22 as totalDays,
-- 已签到天数
(SELECT COUNT(*)
FROM zsjy_internship_daily
WHERE student_id = #{studentId}
AND deleted = 0
AND YEAR(check_date) = #{year}
AND MONTH(check_date) = #{month}
AND check_in_time IS NOT NULL) as checkedDays,
-- 异常天数
(SELECT COUNT(*)
FROM zsjy_internship_daily
WHERE student_id = #{studentId}
AND deleted = 0
AND YEAR(check_date) = #{year}
AND MONTH(check_date) = #{month}
AND is_exception = '1') as exceptionDays,
-- 未签到天数(22 - 已签到 - 异常)
(22 -
(SELECT COUNT(*)
FROM zsjy_internship_daily
WHERE student_id = #{studentId}
AND deleted = 0
AND YEAR(check_date) = #{year}
AND MONTH(check_date) = #{month}
AND (check_in_time IS NOT NULL OR is_exception = '1'))
) as missedDays
]]>
</select>
<!-- 检查学生当日是否已签到 --> <!-- 检查学生当日是否已签到 -->
<select id="existsByStudentAndDate" resultType="boolean"> <select id="existsByStudentAndDate" resultType="boolean">
SELECT COUNT(*) > 0 SELECT COUNT(*) > 0
+1 -1
View File
@@ -63,7 +63,7 @@ export const getCalendarData = (studentId, year, month) => {
*/ */
export const getStatistics = (params) => { export const getStatistics = (params) => {
return request({ return request({
url: '/zsjy/internship/daily/statistics', url: '/zsjy/internship/daily/monthly-statistics',
method: 'GET', method: 'GET',
params params
}); });
+589 -154
View File
@@ -90,7 +90,7 @@
</view> </view>
<!-- 位置信息卡片 --> <!-- 位置信息卡片 -->
<view class="location-card" v-if="currentLocation"> <view class="location-card" v-if="currentLocation" style="display: none;">
<view class="card-header"> <view class="card-header">
<view class="header-left"> <view class="header-left">
<u-icon name="map-pin" size="18" color="#f56c6c"></u-icon> <u-icon name="map-pin" size="18" color="#f56c6c"></u-icon>
@@ -204,7 +204,7 @@
<!-- 考勤统计 --> <!-- 考勤统计 -->
<view class="statistics-card"> <view class="statistics-card">
<view class="card-header"> <view class="card-header">
<u-icon name="bar-chart" size="18" color="#e6a23c"></u-icon> <u-icon size="18" color="#e6a23c"></u-icon>
<text class="card-title">本月考勤</text> <text class="card-title">本月考勤</text>
</view> </view>
<view class="stats-grid"> <view class="stats-grid">
@@ -228,7 +228,7 @@
</view> </view>
<!-- 最近签到记录 --> <!-- 最近签到记录 -->
<view class="records-card"> <view class="records-card" style="display: none;">
<view class="card-header"> <view class="card-header">
<u-icon name="list" size="18" color="#909399"></u-icon> <u-icon name="list" size="18" color="#909399"></u-icon>
<text class="card-title">最近签到</text> <text class="card-title">最近签到</text>
@@ -264,6 +264,7 @@
import { getInternshipInfo, getStudentInternshipInfo, checkIn, getDailyList, getStatistics } from '@/api/internship.js'; import { getInternshipInfo, getStudentInternshipInfo, checkIn, getDailyList, getStatistics } from '@/api/internship.js';
import { getCurrentLocation, checkLocationPermission, openLocationSettings } from '@/utils/location.js'; import { getCurrentLocation, checkLocationPermission, openLocationSettings } from '@/utils/location.js';
import { userManager } from '@/utils/user.js'; import { userManager } from '@/utils/user.js';
import weChatSDK from '@/utils/wechat.js';
export default { export default {
name: 'InternshipIndex', name: 'InternshipIndex',
@@ -281,11 +282,16 @@ export default {
checkinTips: '', checkinTips: '',
todayRecord: null, todayRecord: null,
// 位置信息 // 位置信息(增强版)
currentLocation: null, currentLocation: null,
locationLoading: false, locationLoading: false,
locationError: '', locationError: '',
// 微信SDK相关(新增)
wechatSDK: weChatSDK,
isWechatBrowser: false,
wechatInitializing: false,
// 统计数据 // 统计数据
monthStats: { monthStats: {
totalDays: 0, totalDays: 0,
@@ -313,7 +319,10 @@ export default {
}; };
}, },
onLoad() { async onLoad() {
// 初始化微信环境检查并自动初始化SDK
await this.checkWechatEnvironment();
this.initPage(); this.initPage();
}, },
@@ -324,8 +333,62 @@ export default {
}, },
methods: { methods: {
// === 微信SDK相关方法 ===
// 检查微信环境并自动初始化SDK
async checkWechatEnvironment() {
try {
// 检查是否在微信浏览器中
this.isWechatBrowser = this.wechatSDK.isWeChatBrowser();
if (this.isWechatBrowser) {
// 在微信环境中,自动初始化SDK
await this.initWechatSDK();
}
} catch (error) {
console.error('微信环境检查失败:', error);
}
},
// 初始化微信SDK
async initWechatSDK() {
if (this.wechatInitializing) {
return;
}
this.wechatInitializing = true;
try {
// 使用微信SDK工具类进行初始化
await this.wechatSDK.init({
debug: process.env.NODE_ENV === 'development',
jsApiList: ['chooseImage', 'previewImage', 'getLocation', 'openLocation'],
});
// 检查关键API支持情况
try {
const apiCheckResult = await this.wechatSDK.checkJsApi([
'chooseImage',
'getLocation',
]);
} catch (apiError) {
console.warn('API支持检查失败:', apiError.message);
}
} catch (error) {
console.error('微信SDK初始化失败:', error);
} finally {
this.wechatInitializing = false;
}
},
// 重新初始化微信SDK
async reinitWechatSDK() {
this.wechatSDK.isInitialized = false;
await this.initWechatSDK();
},
/** /**
* 初始化页面 * 初始化页面(增强版)
*/ */
async initPage() { async initPage() {
try { try {
@@ -343,6 +406,14 @@ export default {
return; return;
} }
// 初始化微信环境检测
this.isWechatBrowser = this.wechatSDK.isWeChatBrowser();
// 如果在微信环境,初始化微信SDK
if (this.isWechatBrowser) {
await this.initWechatSDK();
}
// 并行加载数据 // 并行加载数据
await Promise.all([ await Promise.all([
this.loadInternshipInfo(), this.loadInternshipInfo(),
@@ -360,6 +431,40 @@ export default {
}); });
} }
}, },
/**
* 初始化微信SDK(新增)
*/
async initWechatSDK() {
if (this.wechatInitializing) {
return;
}
this.wechatInitializing = true;
try {
// 使用微信SDK工具类进行初始化
await this.wechatSDK.init({
debug: process.env.NODE_ENV === 'development',
jsApiList: ['getLocation', 'openLocation'],
});
console.log('微信SDK初始化成功,支持定位和地图功能');
} catch (error) {
console.error('微信SDK初始化失败:', error);
// 不影响正常功能,继续使用其他定位方案
} finally {
this.wechatInitializing = false;
}
},
/**
* 重新初始化微信SDK(新增)
*/
async reinitWechatSDK() {
this.wechatSDK.isInitialized = false;
await this.initWechatSDK();
},
/** /**
* 加载实习信息 * 加载实习信息
@@ -540,188 +645,243 @@ export default {
}, },
/** /**
* 获取当前位置信息 - 增强版多重定位方案 * 智能定位:根据环境自动选择最适合的定位方式(增强版)
*/ */
async getCurrentLocationInfo() { async getCurrentLocationInfo() {
this.locationLoading = true;
this.locationError = '';
try { try {
// 方案1: 微信定位(微信浏览器环境) this.locationLoading = true;
if (this.isWechatBrowser()) { this.locationError = '';
try { uni.showLoading({ title: '定位中...', mask: true });
uni.showToast({
title: '正在微信定位...', const envInfo = {
icon: 'loading', isWechatBrowser: this.isWechatBrowser,
duration: 2000 isWechatSdkReady: this.wechatSDK.isInitialized,
}); isH5Web: this.isH5Web(),
const wechatLocation = await this.getWechatLocation(); isBrowserGeolocationSupported: this.isBrowserGeolocationSupported(),
if (wechatLocation) { };
this.currentLocation = wechatLocation;
this.updateLocationSuccess();
uni.showToast({
title: '微信定位成功',
icon: 'success',
duration: 1500
});
return;
}
} catch (error) {
console.log('微信定位失败,尝试其他方案:', error);
}
}
// 方案2: 浏览器HTML5定位(H5环境) console.log('环境检测结果:', envInfo);
if (this.isH5Web() && this.isBrowserGeolocationSupported()) {
try { // 优先级1:微信SDK定位(如果在微信环境且SDK已就绪)
uni.showToast({ if (this.isWechatBrowser && this.wechatSDK.isInitialized) {
title: '正在浏览器定位...', const wxLocationSuccess = await this.tryWeChatLocationWithSDK();
icon: 'loading', if (wxLocationSuccess) {
duration: 2000
});
const browserLocation = await this.getBrowserLocation();
if (browserLocation) {
this.currentLocation = browserLocation;
this.updateLocationSuccess();
uni.showToast({
title: '浏览器定位成功',
icon: 'success',
duration: 1500
});
return;
}
} catch (error) {
console.log('浏览器定位失败,尝试其他方案:', error);
}
}
// 方案3: uni-app定位(通用回退方案)
try {
uni.showToast({
title: '正在系统定位...',
icon: 'loading',
duration: 2000
});
const uniLocation = await this.getUniappLocation();
if (uniLocation) {
this.currentLocation = uniLocation;
this.updateLocationSuccess();
uni.showToast({
title: '定位成功',
icon: 'success',
duration: 1500
});
return; return;
} }
} catch (error) {
console.log('uni-app定位失败:', error);
} }
// 所有定位方案都失败 // 优先级2:微信环境但SDK未就绪,尝试初始化后重试
this.updateLocationError('定位失败,请检查网络连接和位置权限'); if (this.isWechatBrowser && !this.wechatSDK.isInitialized) {
try {
await this.initWechatSDK();
if (this.wechatSDK.isInitialized) {
const wxLocationSuccess = await this.tryWeChatLocationWithSDK();
if (wxLocationSuccess) {
return;
}
}
} catch (error) {
console.error('微信SDK初始化失败:', error);
}
}
// 优先级3:H5 web端原生定位
if (this.isH5Web() && this.isBrowserGeolocationSupported()) {
const h5LocationSuccess = await this.handleH5WebLocation();
if (h5LocationSuccess) {
return;
}
}
// 优先级4:uni-app通用定位(最后的回退方案)
await this.handleFallbackLocation();
} catch (error) { } catch (error) {
console.error('获取位置失败:', error); console.error('智能定位流程出错:', error);
this.updateLocationError(error.message || '获取位置失败'); this.updateLocationError(error.message || '定位失败');
uni.hideLoading();
uni.showModal({
title: '定位失败',
content: '定位功能暂时不可用,您可以手动输入位置信息或稍后重试。',
showCancel: true,
cancelText: '取消',
confirmText: '重试',
success: (res) => {
if (res.confirm) {
// 用户选择重试
this.getCurrentLocationInfo();
}
}
});
} finally { } finally {
this.locationLoading = false; this.locationLoading = false;
} }
}, },
/** /**
* 微信定位 * 使用微信SDK进行定位(增强版)
*/ */
async getWechatLocation() { async tryWeChatLocationWithSDK() {
return new Promise((resolve, reject) => { try {
// 检查微信环境 console.log('=== 开始微信SDK定位 ===');
if (!this.isWechatBrowser()) { const result = await this.wechatSDK.getLocation({
reject(new Error('不在微信环境中')); type: 'gcj02', // 火星坐标系,适合国内地图
});
if (result.latitude && result.longitude) {
this.currentLocation = {
latitude: parseFloat(result.latitude),
longitude: parseFloat(result.longitude),
accuracy: result.accuracy || 50,
address: `${parseFloat(result.latitude).toFixed(6)}, ${parseFloat(result.longitude).toFixed(6)}`
};
this.updateLocationSuccess();
uni.hideLoading();
uni.showToast({
title: '微信定位成功',
icon: 'success',
duration: 2000,
});
return true;
} else {
console.warn('微信定位返回数据无效:', result);
return false;
}
} catch (error) {
console.error('微信SDK定位失败:', error);
// 根据错误类型提供更友好的提示
if (error.message && error.message.includes('denied')) {
uni.showModal({
title: '定位权限',
content: '需要获取位置信息来记录打卡地点,请在微信中允许位置权限。',
showCancel: false,
confirmText: '知道了',
});
}
return false;
}
},
/**
* H5 web端原生定位(增强版)
*/
async handleH5WebLocation() {
return new Promise((resolve) => {
if (!this.isBrowserGeolocationSupported()) {
console.log('浏览器不支持原生定位API');
resolve(false);
return; return;
} }
// 微信JSSDK定位 console.log('=== 使用H5原生Geolocation API定位 ===');
if (typeof wx !== 'undefined' && wx.getLocation) {
wx.getLocation({ const options = {
type: 'gcj02', enableHighAccuracy: true, // 启用高精度定位
success: (res) => { timeout: 15000, // 15秒超时
if (res.latitude && res.longitude) { maximumAge: 300000, // 缓存5分钟
resolve({ };
latitude: res.latitude,
longitude: res.longitude,
accuracy: res.accuracy || 50,
address: `${res.latitude.toFixed(6)}, ${res.longitude.toFixed(6)}`
});
} else {
reject(new Error('微信定位返回数据无效'));
}
},
fail: (error) => {
console.error('微信定位失败:', error);
reject(new Error('微信定位失败'));
}
});
} else {
reject(new Error('微信JSSDK未初始化'));
}
});
},
/**
* 浏览器HTML5定位
*/
async getBrowserLocation() {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
(position) => { (position) => {
console.log('H5原生定位成功:', position);
const { latitude, longitude, accuracy } = position.coords; const { latitude, longitude, accuracy } = position.coords;
resolve({
this.currentLocation = {
latitude: latitude, latitude: latitude,
longitude: longitude, longitude: longitude,
accuracy: accuracy || 100, accuracy: accuracy || 100,
address: `${latitude.toFixed(6)}, ${longitude.toFixed(6)}` address: `${latitude.toFixed(6)}, ${longitude.toFixed(6)}`
};
this.updateLocationSuccess();
uni.hideLoading();
uni.showToast({
title: `定位成功 (精度: ${Math.round(accuracy)}m)`,
icon: 'success',
duration: 2000,
}); });
resolve(true);
}, },
(error) => { (error) => {
let errorMsg = '浏览器定位失败'; console.error('H5原生定位失败:', error);
let errorMessage = '定位失败';
switch (error.code) { switch (error.code) {
case error.PERMISSION_DENIED: case error.PERMISSION_DENIED:
errorMsg = '位置权限被拒绝'; errorMessage = '用户拒绝了定位请求';
break; break;
case error.POSITION_UNAVAILABLE: case error.POSITION_UNAVAILABLE:
errorMsg = '位置信息不可用'; errorMessage = '位置信息不可用';
break; break;
case error.TIMEOUT: case error.TIMEOUT:
errorMsg = '定位超时'; errorMessage = '定位请求超时';
break;
default:
errorMessage = '定位出现未知错误';
break; break;
} }
reject(new Error(errorMsg));
// 显示友好的错误提示
uni.showModal({
title: '定位失败',
content: `${errorMessage}。是否手动输入位置信息?`,
showCancel: true,
cancelText: '取消',
confirmText: '稍后重试',
success: (res) => {
if (res.confirm) {
// 用户选择重试
uni.showToast({
title: '请稍后重试定位',
icon: 'none',
duration: 2000,
});
}
},
});
resolve(false);
}, },
{ options,
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 60000
}
); );
}); });
}, },
/** /**
* uni-app定位 * uni-app通用定位(回退方案)
*/ */
async getUniappLocation() { async handleFallbackLocation() {
return new Promise((resolve, reject) => { return new Promise((resolve) => {
console.log('=== 使用uni-app通用定位 ===');
uni.getLocation({ uni.getLocation({
type: 'gcj02', type: 'gcj02',
geocode: true, geocode: true,
success: (res) => { success: (res) => {
resolve({ this.currentLocation = {
latitude: res.latitude, latitude: res.latitude,
longitude: res.longitude, longitude: res.longitude,
accuracy: res.accuracy || 100, accuracy: res.accuracy || 100,
address: res.address || `${res.latitude.toFixed(6)}, ${res.longitude.toFixed(6)}` address: res.address || `${res.latitude.toFixed(6)}, ${res.longitude.toFixed(6)}`
};
this.updateLocationSuccess();
uni.hideLoading();
uni.showToast({
title: '定位成功',
icon: 'success',
duration: 2000
}); });
resolve(true);
}, },
fail: (error) => { fail: (error) => {
console.error('uni-app定位失败:', error);
let errorMsg = 'uni-app定位失败'; let errorMsg = 'uni-app定位失败';
if (error.errMsg) { if (error.errMsg) {
if (error.errMsg.includes('auth deny')) { if (error.errMsg.includes('auth deny')) {
@@ -730,12 +890,24 @@ export default {
errorMsg = '定位失败,请检查GPS设置'; errorMsg = '定位失败,请检查GPS设置';
} }
} }
reject(new Error(errorMsg));
} this.updateLocationError(errorMsg);
uni.hideLoading();
uni.showToast({
title: errorMsg,
icon: 'none',
duration: 3000
});
resolve(false);
},
}); });
}); });
}, },
/** /**
* 更新定位成功状态 * 更新定位成功状态
*/ */
@@ -766,10 +938,12 @@ export default {
this.getCurrentLocationInfo(); this.getCurrentLocationInfo();
}, },
/** /**
* 打开位置信息在地图中查看 * 打开位置信息在地图中查看
*/ */
openLocationInMap() { async openLocationInMap() {
if (!this.currentLocation) { if (!this.currentLocation) {
uni.showToast({ uni.showToast({
title: '无法获取位置信息', title: '无法获取位置信息',
@@ -779,23 +953,83 @@ export default {
} }
const { latitude, longitude } = this.currentLocation; const { latitude, longitude } = this.currentLocation;
const name = this.currentLocation.address || '当前位置';
if (!latitude || !longitude || isNaN(latitude) || isNaN(longitude)) {
// 使用uni.openLocation打开系统地图 uni.showToast({
uni.openLocation({ title: '位置信息无效',
latitude: latitude, icon: 'none',
longitude: longitude, });
name: name, return;
address: this.currentLocation.address || `${latitude.toFixed(6)}, ${longitude.toFixed(6)}`, }
success: () => {
console.log('打开地图成功'); if (this.isWechatBrowser && this.wechatSDK.isInitialized) {
}, try {
fail: (error) => { await this.wechatSDK.openLocation({
console.error('打开地图失败:', error); latitude: latitude,
uni.showToast({ longitude: longitude,
title: '打开地图失败', name: '实习签到位置',
icon: 'none' address: this.currentLocation.address || '当前位置',
scale: 16,
}); });
} catch (error) {
console.error('微信地图打开失败:', error);
this.fallbackOpenMap(latitude, longitude);
}
} else {
this.fallbackOpenMap(latitude, longitude);
}
},
// 备用地图打开方式
fallbackOpenMap(latitude, longitude) {
// 首先尝试使用uni.openLocation(原生地图)
if (typeof uni.openLocation === 'function') {
uni.showLoading({
title: '打开地图中...'
});
uni.openLocation({
latitude: Number(latitude),
longitude: Number(longitude),
name: '实习签到位置',
address: this.currentLocation.address || '当前位置',
scale: 16,
success: () => {
console.log('使用uni.openLocation打开地图成功');
uni.hideLoading();
},
fail: (error) => {
console.error('uni.openLocation打开地图失败:', error);
uni.hideLoading();
this.showCopyCoordinatesOption(latitude, longitude);
}
});
} else {
// 如果uni.openLocation不可用,显示复制坐标选项
this.showCopyCoordinatesOption(latitude, longitude);
}
},
// 显示复制坐标选项
showCopyCoordinatesOption(latitude, longitude) {
uni.showModal({
title: '无法打开地图',
content: '当前环境不支持地图功能,是否复制坐标到剪贴板?\n您可以在其他地图应用中粘贴坐标查看位置。',
showCancel: true,
cancelText: '取消',
confirmText: '复制坐标',
success: (res) => {
if (res.confirm) {
uni.setClipboardData({
data: `${latitude.toFixed(6)},${longitude.toFixed(6)}`,
success: () => {
uni.showToast({
title: '坐标已复制',
icon: 'success'
});
}
});
}
} }
}); });
}, },
@@ -980,6 +1214,126 @@ export default {
} else { } else {
return { text: '低精度', type: 'warning' }; return { text: '低精度', type: 'warning' };
} }
},
/**
* 加载用户信息
*/
async loadUserInfo() {
try {
const userInfo = userManager.getUserInfo();
if (userInfo) {
this.userInfo = userInfo;
console.log('用户信息加载成功:', userInfo);
} else {
console.warn('未获取到用户信息');
// 尝试重新获取
await userManager.refreshUserInfo();
this.userInfo = userManager.getUserInfo() || {};
}
} catch (error) {
console.error('加载用户信息失败:', error);
this.userInfo = {};
}
},
/**
* 检查今日签到状态
*/
async checkTodayCheckInStatus() {
try {
if (!this.internshipInfo?.internshipId) {
return;
}
const today = this.formatDate(new Date());
// 这里可以调用API检查今日签到状态
// const result = await checkTodayStatus(this.internshipInfo.internshipId, today);
// this.todayRecord = result.data;
// 暂时设置为未签到状态
this.todayRecord = null;
this.canCheckin = true;
console.log('今日签到状态检查完成');
} catch (error) {
console.error('检查今日签到状态失败:', error);
this.todayRecord = null;
this.canCheckin = true;
}
},
/**
* 检查是否在微信浏览器环境
*/
checkIsWechatBrowser() {
const ua = navigator.userAgent.toLowerCase();
return ua.includes('micromessenger');
}
},
/**
* 页面加载时
*/
onLoad() {
console.log('实习页面加载');
this.initPage();
},
/**
* 页面显示时
*/
onShow() {
console.log('实习页面显示');
this.refreshData();
},
/**
* 初始化页面
*/
async initPage() {
// 设置当前日期
this.currentDate = this.formatDate(new Date());
// 检测微信环境
this.isWechatBrowser = this.checkIsWechatBrowser();
// 获取用户信息(不阻塞)
this.loadUserInfo().catch(error => {
console.error('用户信息加载失败:', error);
});
// 获取实习信息(不阻塞)
this.loadInternshipInfo().catch(error => {
console.error('实习信息加载失败:', error);
});
// 获取位置信息(核心功能,但不阻塞页面显示)
this.getCurrentLocationInfo().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);
} }
} }
}; };
@@ -1047,12 +1401,16 @@ export default {
margin-bottom: 16px; margin-bottom: 16px;
padding-bottom: 12px; padding-bottom: 12px;
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
min-height: 32px; /* 确保最小高度 */
gap: 8px; /* 确保元素之间有间距 */
} }
.header-left { .header-left {
display: flex; display: flex;
align-items: center; align-items: center;
flex: 1; flex: 1;
min-width: 0; /* 允许flex子项收缩 */
margin-right: 12px; /* 与右侧按钮保持距离 */
} }
.card-title { .card-title {
@@ -1060,10 +1418,15 @@ export default {
font-weight: bold; font-weight: bold;
margin-left: 8px; margin-left: 8px;
color: #303133; color: #303133;
white-space: nowrap; /* 防止文字换行 */
overflow: hidden; /* 隐藏溢出文字 */
text-overflow: ellipsis; /* 显示省略号 */
flex-shrink: 1; /* 允许收缩 */
} }
.refresh-btn { .refresh-btn {
flex-shrink: 0; flex-shrink: 0;
min-width: 70px; /* 确保按钮最小宽度 */
} }
.date-text { .date-text {
@@ -1253,16 +1616,88 @@ export default {
.location-actions { .location-actions {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-top: 4px; /* 与上方内容保持间距 */
} }
.map-btn { .map-btn {
min-width: 140px; min-width: 140px;
width: 100%; /* 在小屏幕上占满宽度 */
max-width: 200px; /* 最大宽度限制 */
} }
.btn-text { .btn-text {
margin-left: 6px; margin-left: 6px;
} }
/* 小屏幕适配 */
@media screen and (max-width: 375px) {
.card-header {
flex-wrap: nowrap; /* 保持单行,避免换行 */
gap: 4px;
min-height: 36px; /* 稍微增加高度 */
}
.header-left {
min-width: 0; /* 允许完全收缩 */
flex: 1;
margin-right: 6px;
}
.card-title {
font-size: 15px; /* 稍微减小字体 */
max-width: 100px; /* 限制最大宽度 */
}
.refresh-btn {
min-width: 58px; /* 小屏幕下减小按钮宽度 */
font-size: 12px; /* 减小按钮字体 */
}
.map-btn {
min-width: 120px;
font-size: 14px;
}
}
/* 极小屏幕适配(iPhone SE等) */
@media screen and (max-width: 320px) {
.card-header {
gap: 2px;
}
.header-left {
margin-right: 4px;
}
.card-title {
font-size: 14px;
max-width: 80px;
}
.refresh-btn {
min-width: 50px;
font-size: 11px;
padding: 4px 8px;
}
.location-address {
padding: 10px;
}
.address-text {
font-size: 13px;
}
.coord-row {
padding: 10px;
}
.map-btn {
min-width: 100px;
font-size: 13px;
}
}
/* 位置获取失败提示 */ /* 位置获取失败提示 */
.location-error-card { .location-error-card {
background: #fffbe6; background: #fffbe6;