diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/ks-app-employment-service.iml b/.idea/ks-app-employment-service.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/ks-app-employment-service.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..331c8ce --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/config.js b/config.js index 08c5c64..088e85f 100644 --- a/config.js +++ b/config.js @@ -5,6 +5,7 @@ export default { LCBaseUrl:'http://10.110.145.145:9100',//招聘、培训、帮扶 LCBaseUrlInner:'http://10.110.145.145:10100',//内网端口 imgBaseUrl:'http://10.110.145.145/images', //图片基础url + trainVideoImgUrl:'http://10.110.145.145:9100/file/file/minio', // sseAI+ // StreamBaseURl: 'http://39.98.44.136:8000', StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai', diff --git a/packageA/pages/myResume/myResume.vue b/packageA/pages/myResume/myResume.vue index 3950683..babf046 100644 --- a/packageA/pages/myResume/myResume.vue +++ b/packageA/pages/myResume/myResume.vue @@ -122,7 +122,7 @@ - + @@ -267,12 +267,202 @@ const handleDeleteItem = async (item, index) => { }; // 简历上传核心逻辑 -const handleResumeUpload = () => {}; +const handleResumeUpload = () => { + // 从缓存获取用户ID(参考首页实现方式) + // 优先从store获取,如果为空则从缓存获取 + const storeUserId = userInfo.value?.userId; + const cachedUserInfo = uni.getStorageSync('userInfo') || {}; + const cachedUserId = cachedUserInfo.userId; + + // 获取用户ID:优先使用store中的userId,如果store中没有,使用缓存中的userId + const userId = storeUserId || cachedUserId; + + if (!userId) { + $api.msg('请先登录'); + return; + } + + // 检查是否正在上传 + if (isUploading.value) { + return; + } + + // 选择文件(微信小程序使用 wx.chooseMessageFile,uni-app 中对应 uni.chooseMessageFile) + uni.chooseMessageFile({ + count: 1, // 只能选择一个文件 + type: 'file', // 选择任意文件类型 + success: (res) => { + // 注意:文件路径在 res.tempFiles[0].path + const file = res.tempFiles[0]; + const tempFilePath = file.path; // 获取临时文件路径 + const fileName = file.name; // 获取文件名 + + // 检查文件大小(20MB = 20 * 1024 * 1024 字节) + const maxSize = 20 * 1024 * 1024; + if (file.size > maxSize) { + $api.msg('文件大小不能超过 20MB'); + return; + } + + // 检查文件类型 + const allowedTypes = ['pdf', 'doc', 'docx']; + const fileExtension = fileName.split('.').pop()?.toLowerCase(); + if (!fileExtension || !allowedTypes.includes(fileExtension)) { + $api.msg('仅支持 PDF、Word 格式'); + return; + } + + // 开始上传 + uploadResumeFile(tempFilePath, fileName, userId); + }, + fail: (err) => { + console.error('选择文件失败:', err); + // 用户取消选择不提示错误 + if (err.errMsg && !err.errMsg.includes('cancel')) { + $api.msg('选择文件失败,请重试'); + } + } + }); +}; + +// 上传简历文件到服务器(使用 wx.uploadFile,uni-app 中对应 uni.uploadFile) +const uploadResumeFile = (filePath, fileName, userId) => { + // 确保 userId 存在且有效 + if (!userId) { + // 如果传入的userId为空,尝试从缓存再次获取 + const cachedUserInfo = uni.getStorageSync('userInfo') || {}; + const cachedUserId = cachedUserInfo.userId; + + if (!cachedUserId) { + $api.msg('用户ID不存在,无法上传'); + return; + } + + // 使用缓存中的userId + userId = cachedUserId; + } + + isUploading.value = true; + + // 获取token(从缓存获取,参考首页实现方式) + let Authorization = ''; + const tokenValue = uni.getStorageSync('token') || ''; + if (tokenValue) { + Authorization = tokenValue; + } else { + // 如果缓存中没有token,尝试从store获取 + const userStore = useUserStore(); + if (userStore.token) { + Authorization = userStore.token; + } + } + + // 根据接口文档,bussinessId 应该作为 Query 参数传递,而不是 formData + // 将 bussinessId 拼接到 URL 上作为查询参数 + const uploadUrl = `${config.baseUrl}/app/file/upload?bussinessId=${encodeURIComponent(String(userId))}`; + + // 打印调试信息 + console.log('上传文件参数:', { + url: uploadUrl, + fileName: fileName, + bussinessId: userId, + userId: userId, + token: Authorization ? '已获取' : '未获取' + }); + + // 上传文件(参考微信小程序 wx.uploadFile API) + uni.uploadFile({ + url: uploadUrl, // 开发者服务器的上传接口(必须是 HTTPS),bussinessId 作为 Query 参数 + filePath: filePath, // 本地文件路径(临时路径) + name: 'file', // 服务器端接收文件的字段名(需与后端一致) + // 注意:根据接口文档,bussinessId 通过 Query 参数传递,不需要 formData + header: { + 'Authorization': encodeURIComponent(Authorization) + }, + success: (uploadRes) => { + try { + // 注意:res.data 是字符串,需转为 JSON(如果后端返回 JSON) + // 参考方案:const result = JSON.parse(data); + let resData; + if (typeof uploadRes.data === 'string') { + resData = JSON.parse(uploadRes.data); + } else { + resData = uploadRes.data; + } + + // 判断上传是否成功 + if (uploadRes.statusCode === 200 && resData.code === 200) { + // 上传成功,处理返回结果 + uploadedResumeName.value = fileName; + uploadedResumeUrl.value = resData.data || resData.msg || resData.url || ''; + $api.msg('简历上传成功'); + console.log('上传成功', resData); + + // 可以在这里保存简历信息到后端(如果需要) + // saveResumeInfo(userId, uploadedResumeUrl.value, fileName); + } else { + // 上传失败 + const errorMsg = resData.msg || resData.message || '上传失败,请重试'; + $api.msg(errorMsg); + console.error('上传失败:', resData); + } + } catch (error) { + // 解析响应数据失败 + console.error('解析上传响应失败:', error); + console.error('原始响应数据:', uploadRes.data); + $api.msg('上传失败,请重试'); + } + }, + fail: (err) => { + // 上传失败 + console.error('上传文件失败:', err); + $api.msg('上传失败,请检查网络连接'); + }, + // 上传进度监听(可选) + progress: (res) => { + const progress = res.progress; // 上传进度(0-100) + console.log('上传进度:', progress + '%'); + // 可以在这里更新进度条 UI(如果需要) + }, + complete: () => { + // 上传完成(无论成功或失败) + isUploading.value = false; + } + }); +}; // 删除已上传的简历 -const handleDeleteResume = () => {}; +const handleDeleteResume = () => { + if (!uploadedResumeName.value) { + return; + } + + uni.showModal({ + title: '确认删除', + content: '确定要删除已上传的简历吗?', + success: (res) => { + if (res.confirm) { + // 清除本地数据 + uploadedResumeName.value = ''; + uploadedResumeUrl.value = ''; + $api.msg('已删除'); + + // 如果需要,可以调用后端接口删除服务器上的文件 + // deleteResumeFile(userId); + } + } + }); +}; + + \ No newline at end of file diff --git a/packageB/train/mockExam/viewGrades.vue b/packageB/train/mockExam/viewGrades.vue new file mode 100644 index 0000000..5bd0ad2 --- /dev/null +++ b/packageB/train/mockExam/viewGrades.vue @@ -0,0 +1,65 @@ + + + + + \ No newline at end of file diff --git a/packageB/train/video/videoDetail.vue b/packageB/train/video/videoDetail.vue index e6b052e..0210e6a 100644 --- a/packageB/train/video/videoDetail.vue +++ b/packageB/train/video/videoDetail.vue @@ -1,316 +1,338 @@ diff --git a/packageB/train/video/videoList.vue b/packageB/train/video/videoList.vue index 6f3d588..90996a5 100644 --- a/packageB/train/video/videoList.vue +++ b/packageB/train/video/videoList.vue @@ -34,9 +34,9 @@ 视频列表 - + - {{ video.title || video.videoName || '未命名视频' }} + {{ video.videoTitle || '未命名视频' }} @@ -67,14 +67,10 @@ import config from "@/config.js" // state const title = ref(''); const searchKeyword = ref(''); -const pageState = reactive({ - page: 0, - list: [], - total: 0, - maxPage: 1, - pageSize: 12, - search: {}, -}); +const dataList=ref([]) +const pageSize=ref(10) +const pageNum=ref(1) +const totalNum=ref(0) const baseUrl = config.imgBaseUrl const getItemBackgroundStyle = (imageName) => ({ backgroundImage: `url(${baseUrl}/train/${imageName})`, @@ -82,45 +78,7 @@ const getItemBackgroundStyle = (imageName) => ({ backgroundPosition: 'center', // 居中 backgroundRepeat: 'no-repeat' }); -// 模拟视频数据 -const mockVideoData = [ - { - id: '1', - title: '职业技能培训基础课程', - coverImage: '/static/icon/server1.png', - videoUrl: '' - }, - { - id: '2', - title: '面试技巧分享', - coverImage: '/static/icon/server2.png', - videoUrl: '' - }, - { - id: '3', - title: '简历制作指南', - coverImage: '/static/icon/server3.png', - videoUrl: '' - }, - { - id: '4', - title: '职场沟通技巧', - coverImage: '/static/icon/server4.png', - videoUrl: '' - }, - { - id: '5', - title: '职业规划讲座', - coverImage: '/static/icon/flame.png', - videoUrl: '' - }, - { - id: '6', - title: '行业趋势分析', - coverImage: '/static/icon/flame2.png', - videoUrl: '' - } -]; +const trainVideoImgUrl=config.trainVideoImgUrl onLoad(() => { getDataList('refresh'); @@ -139,49 +97,46 @@ function clearSearch() { // 获取视频列表 function getDataList(type = 'add') { + let maxPage=Math.ceil(totalNum.value/pageSize.value) + let params={} if (type === 'refresh') { - pageState.page = 1; - pageState.maxPage = 1; + pageNum.value = 1; + params={ + category:'', + hour:'', + level:'', + searchValue:searchKeyword.value, + orderStr:'', + pageSize:pageSize.value, + pageNum:pageNum.value + } + $api.myRequest('/train/public/trainVideo/trainVideoList', params).then((resData) => { + dataList.value=resData.rows + totalNum.value=resData.total + }); } - if (type === 'add' && pageState.page < pageState.maxPage) { - pageState.page += 1; - } - - // 模拟API请求延迟 - setTimeout(() => { - // 在实际项目中,这里应该调用真实的API接口 - // 目前使用模拟数据 - let filteredList = [...mockVideoData]; - - // 如果有搜索关键词,进行过滤 - if (searchKeyword.value.trim()) { - filteredList = filteredList.filter(video => - video.title.toLowerCase().includes(searchKeyword.value.toLowerCase()) - ); - } - - const start = 0; - const end = pageState.pageSize; - const pageData = filteredList.slice(start, end); - - if (type === 'add') { - pageState.list = [...pageState.list, ...pageData]; - } else { - pageState.list = pageData; - } - - pageState.total = filteredList.length; - pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize); - }, 300); + if (type === 'add' && pageNum.value < maxPage) { + pageNum.value += 1; + params={ + category:'', + hour:'', + level:'', + searchValue:searchKeyword.value, + orderStr:'', + pageSize:pageSize.value, + pageNum:pageNum.value + } + $api.myRequest('/train/public/trainVideo/trainVideoList', params).then((resData) => { + dataList.value=dataList.value.concat(resData.rows) + totalNum.value=resData.total + }); + } } + // 播放视频 function playVideo(video) { - // 在实际项目中,这里应该导航到视频播放页面 - // 或者调用视频播放组件 - console.log('播放视频:', video); - navTo(`/packageB/train/video/videoDetail?id=${video.id}`); - // $api.msg(`准备播放: ${video.title}`); + navTo(`/packageB/train/video/videoDetail?id=${video.videoId}`); } @@ -190,13 +145,6 @@ function playVideo(video) { width: 64rpx; height: 64rpx; } -.btn { - display: flex; - justify-content: space-between; - align-items: center; - width: 52rpx; - height: 52rpx; -} image { height: 100%; width: 100%; @@ -264,7 +212,7 @@ image { width: 70rpx; height: 8rpx; background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%); - border-radius: 2px; + border-radius: 4rpx; } .video-grid{ display: grid; diff --git a/packageRc/pages/index/index.vue b/packageRc/pages/index/index.vue index af88c8a..7990425 100644 --- a/packageRc/pages/index/index.vue +++ b/packageRc/pages/index/index.vue @@ -1,7 +1,7 @@