diff --git a/components/md-render/md-render.vue b/components/md-render/md-render.vue index 4cc4e90..1865468 100644 --- a/components/md-render/md-render.vue +++ b/components/md-render/md-render.vue @@ -1,7 +1,12 @@ + + - + + + + @@ -267,7 +272,7 @@ ol { diff --git a/components/wxAuthLogin/WxAuthLogin.vue b/components/wxAuthLogin/WxAuthLogin.vue index d580f71..0664095 100644 --- a/components/wxAuthLogin/WxAuthLogin.vue +++ b/components/wxAuthLogin/WxAuthLogin.vue @@ -11,7 +11,6 @@ 欢迎使用就业服务 - 需要您授权手机号登录 @@ -26,7 +25,7 @@ - 我是求职者 + 个人 - 我是招聘者 + 单位 diff --git a/config.js b/config.js index 972541c..31333da 100644 --- a/config.js +++ b/config.js @@ -6,9 +6,8 @@ */ export default { // baseUrl: 'http://39.98.44.136:8080', // 测试 - baseUrl: 'https://www.xjksly.cn/api/ks', // 测试 - // baseUrl: 'https://www.xjksly.cn/api/ks', // 测试 - // baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // 测试 + // baseUrl: 'https://www.xjksly.cn/api/ks', // 正式环境 + baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // 测试 // LCBaseUrl:'http://10.110.145.145:9100',//内网端口 // LCBaseUrlInner:'http://10.110.145.145:10100',//招聘、培训、帮扶 @@ -20,13 +19,14 @@ export default { trainVideoImgUrl:'https://www.xjksly.cn/prod-api/file/file/minio', // sseAI+ // StreamBaseURl: 'http://39.98.44.136:8000', - StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai', + StreamBaseURl: 'https://www.xjksly.cn/api/ks/app/chat', // StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai/test', // 语音转文字 - // vioceBaseURl: 'ws://39.98.44.136:8080/speech-recognition', - vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/speech-recognition', + vioceBaseURl: 'https://www.xjksly.cn/api/ks/app/speech/asr', + // vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/speech-recognition', // 语音合成 - speechSynthesis: 'wss://qd.zhaopinzao8dian.com/api/speech-synthesis', + speechSynthesis: 'https://www.xjksly.cn/api/ks/app/speech/tts', + // speechSynthesis: 'wss://qd.zhaopinzao8dian.com/api/speech-synthesis', // indexedDB DBversion: 2, // 只使用本地缓寸的数据 diff --git a/hook/useTTSPlayer.js b/hook/useTTSPlayer.js index b11ff3a..24a2689 100644 --- a/hook/useTTSPlayer.js +++ b/hook/useTTSPlayer.js @@ -292,19 +292,14 @@ export function useTTSPlayer(wsUrl) { onHide(cancelAudio) onUnload(cancelAudio) - // 只在支持 AudioContext 的环境中初始化 WebSocket - if (audioContext) { - initWebSocket() - } - - return { - speak, - pause, - resume, - cancelAudio, - isSpeaking, - isPaused, - isComplete + return { + speak, + pause, + resume, + cancelAudio, + isSpeaking, + isPaused, + isComplete } } diff --git a/packageA/pages/UnitDetails/UnitDetails.vue b/packageA/pages/UnitDetails/UnitDetails.vue index 2cf6817..13e4745 100644 --- a/packageA/pages/UnitDetails/UnitDetails.vue +++ b/packageA/pages/UnitDetails/UnitDetails.vue @@ -25,9 +25,7 @@ 公司介绍 - {{ - companyInfo?.description || '暂无公司介绍' - }} + @@ -142,6 +140,8 @@ isCollection: resData.data.isCollection || 0, jobList: resData.data.jobList || [] // 使用正确的jobList字段 }; + // 将职位列表数据赋值给jobInfoList,用于页面渲染 + jobInfoList.value = resData.data.jobList || []; console.log('Company details loaded successfully'); } else { console.error('Failed to load company details:', resData?.msg || 'Unknown error'); @@ -153,6 +153,7 @@ isCollection: 0, jobList: [] }; + jobInfoList.value = []; } }).catch((error) => { console.error('API error when fetching company details:', error); @@ -164,6 +165,7 @@ isCollection: 0, jobList: [] }; + jobInfoList.value = []; }); } @@ -443,8 +445,13 @@ font-size: 28rpx; color: #495265; text-align: justified; + :deep(span) { + background-color: transparent !important; + } + :deep(p > span) { + background-color: transparent !important; + } } - .title2 { margin-top: 48rpx; } diff --git a/packageA/pages/jobExpect/jobExpect.vue b/packageA/pages/jobExpect/jobExpect.vue index 7542a16..708e47c 100644 --- a/packageA/pages/jobExpect/jobExpect.vue +++ b/packageA/pages/jobExpect/jobExpect.vue @@ -67,9 +67,9 @@ const { dictLabel, oneDictData, getDictData } = useDictStore(); const selectJobsModel = ref(); const selectPopupRef = ref(); const percent = ref('0%'); -const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100]; +const salay = [2000, 5000, 10000, 15000, 20000, 25000, 30000, 50000, 80000, 100000]; const state = reactive({ - lfsalay: [2, 5, 10, 15, 20, 25, 30, 50], + lfsalay: [2000, 5000, 10000, 15000, 20000, 25000, 30000, 50000], risalay: JSON.parse(JSON.stringify(salay)), salayText: '', areaText: '', @@ -137,10 +137,10 @@ const changeSalary = () => { title: '薪资', maskClick: true, data: [state.lfsalay, state.risalay], - unit: 'k', + unit: '元', success: (_, [min, max]) => { - fromValue.salaryMin = min.value * 1000; - fromValue.salaryMax = max.value * 1000; + fromValue.salaryMin = min.value; + fromValue.salaryMax = max.value; state.salayText = `${fromValue.salaryMin}-${fromValue.salaryMax}`; }, change(e) { diff --git a/packageA/pages/myResume/myResume.vue b/packageA/pages/myResume/myResume.vue index babf046..1079235 100644 --- a/packageA/pages/myResume/myResume.vue +++ b/packageA/pages/myResume/myResume.vue @@ -51,7 +51,7 @@ 期望薪资: - {{ userInfo.salaryMin / 1000 }}k-{{ userInfo.salaryMax / 1000 }}k + {{ userInfo.salaryMin }}元-{{ userInfo.salaryMax }}元 期望工作地: diff --git a/packageA/pages/post/post.vue b/packageA/pages/post/post.vue index a6a4860..16514e1 100644 --- a/packageA/pages/post/post.vue +++ b/packageA/pages/post/post.vue @@ -107,7 +107,7 @@ 公司信息 单位详情 @@ -289,7 +289,6 @@ onShow(() => { } // #endif }); - function initLoad(option) { const jobId = decodeURIComponent(option.jobId); if (jobId !== jobIdRef.value) { @@ -341,9 +340,14 @@ function getDetail(jobId) { } function getCompanyIsAJobs(companyId) { - $api.createRequest(`/app/company/count/${companyId}`).then((resData) => { - companyCount.value = resData.data; - }); + if (companyId) { + $api.createRequest(`/app/company/count/${companyId}`).then((resData) => { + companyCount.value = resData.data; + }); + } + // $api.createRequest(`/app/company/count/${companyId}`).then((resData) => { + // companyCount.value = resData.data; + // }); } function getTextWidth(text, size = 12) { @@ -413,6 +417,11 @@ function getCompetivetuveness(jobId) { // 申请岗位 function jobApply() { + const tokenValue = uni.getStorageSync('token') || ''; + if (!tokenValue) { + $api.msg('请您先登录'); + return; + } const jobId = jobInfo.value.jobId; $api.createRequest(`/app/job/apply/${jobId}`, {}, 'GET').then((resData) => { getDetail(jobId); @@ -504,6 +513,17 @@ function previewImage(url, index) { function viewResume(userId) { navTo(`/packageA/pages/resumeDetail/resumeDetail?userId=${userId}`); } + +// 处理查看单位详情 +function handleCompanyDetailClick() { + // console.log('----企业ID--', jobInfo.value.company?.companyId) + // console.log('----企业data--', jobInfo.value) + if (jobInfo.value.company?.companyId) { + navTo(`/packageA/pages/UnitDetails/UnitDetails?companyId=${jobInfo.value.company.companyId}`); + } else { + $api.msg('没有企业信息'); + } +} diff --git a/packageB/institution/evaluationAgencyDetail.vue b/packageB/institution/evaluationAgencyDetail.vue new file mode 100644 index 0000000..fd35289 --- /dev/null +++ b/packageB/institution/evaluationAgencyDetail.vue @@ -0,0 +1,256 @@ + + + + + + + {{organ.organName}} + + + + + + 机构联系人:{{organ.contactName}} + 联系方式:{{organ.contactPhone}} + 机构地址:{{organ.address}} + + + + + + 评价流程说明 + + + {{organ.processDescription}} + 暂无数据 + + + + + + 评价项目 + + + {{organ.organContent}} + 暂无数据 + + + + + + 资质证书 + + + + + + + + 暂无数据 + + + + + + + + + \ No newline at end of file diff --git a/packageB/institution/trainingInstitution.vue b/packageB/institution/trainingInstitution.vue new file mode 100644 index 0000000..4a63fe2 --- /dev/null +++ b/packageB/institution/trainingInstitution.vue @@ -0,0 +1,364 @@ + + + + + + + + + {{item.organName}} + + 机构详情 + + + + 机构联系人:{{item.contactName}} + 联系方式:{{item.contactPhone}} + 机构地址:{{item.address}} + + + + + + + + + + + diff --git a/packageB/institution/trainingInstitutionDetail.vue b/packageB/institution/trainingInstitutionDetail.vue new file mode 100644 index 0000000..e5f69b3 --- /dev/null +++ b/packageB/institution/trainingInstitutionDetail.vue @@ -0,0 +1,267 @@ + + + + + + + {{trainOrgan.organName}} + + + + + + 机构联系人:{{trainOrgan.contactName}} + 联系方式:{{trainOrgan.contactPhone}} + 机构地址:{{trainOrgan.address}} + + + + + + 课程介绍 + + + {{item}} + 暂无数据 + + + + + + 师资团队 + + + + {{item.tramName}} + 老师介绍:{{item.tramContent}} + + 暂无数据 + + + + + + 资质证书 + + + + + + + + 暂无数据 + + + + + + + + + \ No newline at end of file diff --git a/packageB/jobFair/detailPerson.vue b/packageB/jobFair/detailPerson.vue index f9e8557..1c44d63 100644 --- a/packageB/jobFair/detailPerson.vue +++ b/packageB/jobFair/detailPerson.vue @@ -323,46 +323,59 @@ const deliveringJobs = reactive({}); // 岗位投递 function deliverResume(job) { - if(deliveringJobs[job.jobId]) return - deliveringJobs[job.jobId] = true - const raw = uni.getStorageSync("Padmin-Token"); - const token = typeof raw === "string" ? raw.trim() : ""; - const headers = token ? { - Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}` - } : {}; - - $api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData1) => { - if (resData1.code == 200) { - $api.myRequest("/system/user/login/user/info", {}, "GET", 10100, headers).then((resData) => { - $api.myRequest("/jobfair/public/job-fair-person-job/insert", { - jobFairId: job.jobFairId, // 招聘会id - personId: resData.info.userId, // 当前登录用户id - enterpriseId: job.companyId, // 企业id - jobId: job.jobId, // 岗位id - idCard:resData.info.personCardNo - }, "post", 9100, { - "Content-Type": "application/json" - }).then((data) => { - if (data && data.code === 200) { - $api.msg("简历投递成功"); - if (!job.jobFairPersonJob) { - job.jobFairPersonJob = {}; - } - job.jobFairPersonJob.status = "1"; - getList(false); + uni.showModal({ + title: "提示", + content: "请确认是否投递简历?", + showCancel: true, + confirmText: "确定", + cancelText: "取消", + success: (res) => { + if(res.confirm){ + if(deliveringJobs[job.jobId]) return + deliveringJobs[job.jobId] = true + const raw = uni.getStorageSync("Padmin-Token"); + const token = typeof raw === "string" ? raw.trim() : ""; + const headers = token ? { + Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}` + } : {}; + + $api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData1) => { + if (resData1.code == 200) { + $api.myRequest("/system/user/login/user/info", {}, "GET", 10100, headers).then((resData) => { + $api.myRequest("/jobfair/public/job-fair-person-job/insert", { + jobFairId: job.jobFairId, // 招聘会id + personId: resData.info.userId, // 当前登录用户id + enterpriseId: job.companyId, // 企业id + jobId: job.jobId, // 岗位id + idCard:resData.info.personCardNo + }, "post", 9100, { + "Content-Type": "application/json" + }).then((data) => { + if (data && data.code === 200) { + $api.msg("简历投递成功"); + if (!job.jobFairPersonJob) { + job.jobFairPersonJob = {}; + } + job.jobFairPersonJob.status = "1"; + getList(false); + } else { + $api.msg((data && data.msg) || "简历投递失败"); + } + deliveringJobs[job.jobId] = false + }); + }); } else { - $api.msg((data && data.msg) || "简历投递失败"); + $api.msg('请先登录'); + deliveringJobs[job.jobId] =false } - deliveringJobs[job.jobId] = false + }).catch(() => { + deliveringJobs[job.jobId] =false; }); - }); - } else { - $api.msg('请先登录'); - deliveringJobs[job.jobId] =false + } + } - }).catch(() => { - deliveringJobs[job.jobId] =false; - }); + }) + } // 提交面试邀请 diff --git a/packageB/notice/detail.vue b/packageB/notice/detail.vue new file mode 100644 index 0000000..1b1af5b --- /dev/null +++ b/packageB/notice/detail.vue @@ -0,0 +1,79 @@ + + + + + {{ dataInfo.title }} + + + 发布日期:{{ dataInfo.publishTime }} + + + + + + + + + + + \ No newline at end of file diff --git a/packageB/notice/index.vue b/packageB/notice/index.vue new file mode 100644 index 0000000..41f8273 --- /dev/null +++ b/packageB/notice/index.vue @@ -0,0 +1,201 @@ + + + + + 培训公告 + + + 评价公告 + + + + + + + {{ item.title }} + + + + + 发布日期:{{ item.publishTime }} + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packageB/priority/recommend.vue b/packageB/priority/recommend.vue index d9fc6f7..a127a6d 100644 --- a/packageB/priority/recommend.vue +++ b/packageB/priority/recommend.vue @@ -93,7 +93,6 @@ {{ item.zcmc }} - {{ item.zclx }} {{ item.zcLevel }} {{ item.sourceUnit }} diff --git a/packageB/train/index.vue b/packageB/train/index.vue index bcef18e..541562b 100644 --- a/packageB/train/index.vue +++ b/packageB/train/index.vue @@ -13,7 +13,7 @@ --> - + 专项练习 diff --git a/packageB/train/mockExam/examList.vue b/packageB/train/mockExam/examList.vue index a8e3a68..8486218 100644 --- a/packageB/train/mockExam/examList.vue +++ b/packageB/train/mockExam/examList.vue @@ -129,6 +129,7 @@ + + diff --git a/packageCa/job/index.vue b/packageCa/job/index.vue index e020249..626bcb2 100644 --- a/packageCa/job/index.vue +++ b/packageCa/job/index.vue @@ -14,7 +14,6 @@ - @@ -72,13 +72,11 @@ {{item.zcmc}} - {{item.zclx}} {{item.zcLevel}} {{item.sourceUnit}} 发布日期:{{item.createTime}} - 浏览数{{item.viewNum}} @@ -92,13 +90,13 @@ const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction import { getPolicyList } from '@/packageRc/apiRc/policy'; let policyList = ref([]) function getPolicy() { - getPolicyList({pageNum: 1, pageSize: 10}).then(res => { + getPolicyList({pageNum: 1, pageSize: 10,zclx:'1'}).then(res => { policyList.value = res.rows }) } function toPolicyList() { - navTo(`/packageRc/pages/policy/policyList`) + navTo(`/packageRc/pages/policy/policyList?zclx=1`) } function toPolicyDetail(item) { navTo(`/packageRc/pages/policy/policyDetail?id=${item.id}`) diff --git a/packageRc/pages/policy/policyList.vue b/packageRc/pages/policy/policyList.vue index ebbaa68..8b1aaed 100644 --- a/packageRc/pages/policy/policyList.vue +++ b/packageRc/pages/policy/policyList.vue @@ -6,23 +6,18 @@ - 共 {{ total }} 条 - {{item.zcmc}} - {{item.zclx}} {{item.zcLevel}} {{item.sourceUnit}} @@ -53,7 +48,6 @@ import { getPolicyList } from "@/packageRc/apiRc/policy"; }, data() { return { - checkData: [], queryParams: { pageNum: 1, pageSize: 10, @@ -64,8 +58,8 @@ import { getPolicyList } from "@/packageRc/apiRc/policy"; loading: false, } }, - onLoad() { - this.getCheckData() + onLoad(options) { + this.queryParams.zclx = options.zclx }, onShow() { this.search(); @@ -76,64 +70,10 @@ import { getPolicyList } from "@/packageRc/apiRc/policy"; url: `/packageRc/pages/policy/policyDetail?id=${item.id}` }) }, - getDictLabel(value, list) { - if (list) { - let arr = list.filter(ele => ele.dictValue == value) - if (arr.length) { - return arr[0].dictLabel - } else { - return '--' - } - } - }, - async getCheckData() { - let workExperienceYears - await this.$getDict('qcjy_gznx').then(res => { - workExperienceYears = res.data - }) - await this.$getDict('qcjy_xqlc').then(res => { - this.currentStatusList = res.data; - console.log(res.data) - }) - this.checkData = [ - { - name: "需求类型", - type: "demandType", - data: [{dictLabel: '求职需求', dictValue: '1'},{dictLabel: '创业需求', dictValue: '3'},{dictLabel: '培训需求', dictValue: '4'},{dictLabel: '其他需求', dictValue: '5'}], - activeIndex: 0, - }, - { - name: "需求状态", - type: "currentStatus", - data: [{ - dictLabel: '全部', - dictValue: '' - }].concat(this.currentStatusList), - activeIndex: 0, - }, - // { - // name: "工作经验", - // type: "workExperienceYears", - // data: [{dictLabel: '全部', dictValue: ''}].concat(workExperienceYears), - // activeIndex: 0, - // }, - - ]; - }, - popupSearch(queryParams) { - queryParams.forEach((item, index) => { - if (item.data[item.activeIndex].dictLabel == "全部") { - this.queryParams[item.type] = ""; - } else { - this.queryParams[item.type] = item.data[item.activeIndex].dictValue; - } - }); - this.search() - }, search() { this.showMorePage = true; this.queryParams.pageNum = 1; - this.queryParams.pageSize = 10; + this.queryParams.pageSize = 20; this.tableData = []; this.total = 0; this.getList(); diff --git a/pages.json b/pages.json index 47cb4c9..f7fa64d 100644 --- a/pages.json +++ b/pages.json @@ -6,6 +6,12 @@ "navigationBarTitleText": "喀什智慧就业平台" } }, + { + "path": "pages/city-select/index", + "style": { + "navigationBarTitleText": "选择城市" + } + }, { "path": "pages/mine/mine", "style": { @@ -342,6 +348,12 @@ "navigationBarTitleText": "技能评价" } }, + { + "path": "train/practice/startPracticingList", + "style": { + "navigationBarTitleText": "专项训练" + } + }, { "path": "train/practice/startPracticing", "style": { @@ -419,6 +431,42 @@ "style": { "navigationBarTitleText": "错题详情" } + }, + { + "path": "notice/index", + "style": { + "navigationBarTitleText": "培训评价公告" + } + }, + { + "path": "notice/detail", + "style": { + "navigationBarTitleText": "公告详情" + } + }, + { + "path": "institution/evaluationAgency", + "style": { + "navigationBarTitleText": "评价机构信息" + } + }, + { + "path": "institution/evaluationAgencyDetail", + "style": { + "navigationBarTitleText": "评价机构信息详情" + } + }, + { + "path": "institution/trainingInstitution", + "style": { + "navigationBarTitleText": "培训机构信息" + } + }, + { + "path": "institution/trainingInstitutionDetail", + "style": { + "navigationBarTitleText": "培训机构信息详情" + } } ] }, diff --git a/pages/careerfair/careerfair.vue b/pages/careerfair/careerfair.vue index db9a562..32d3274 100644 --- a/pages/careerfair/careerfair.vue +++ b/pages/careerfair/careerfair.vue @@ -22,9 +22,65 @@ @click="getFair('refresh')"> + 筛选 + + + + + + + + + + + {{ item.label }} + + + + {{ option.label }} + + + + + + + + + 重置 + 确认 + + + @@ -151,10 +207,57 @@ onShow(() => { // 更新自定义tabbar选中状态 tabbarManager.updateSelected(1); + getoptions(); });// - - - + //筛选 + const filterOptions = ref([]); + const activeTab = ref(''); + const selectFilterModel = ref(null); + const selectedValues = ref(null); + function openFilter() { + selectFilterModel.value?.open(); + } + const scrollTo = (key) => { + activeTab.value = key; + }; + + const handleSelect = (e) => { + selectedValues.value = e.detail.value + }; + function cleanup(){ + selectedValues.value = null + confirm() + } + function confirm(){ + getFair("refresh"); + selectFilterModel.value?.close(); + } + function getoptions() { + let headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + let params = { + dictType:'administrative_division', + dictParentValue:'653100000000', + childFlag:'1', + } + filterOptions.value = [{ + label: '所在区域', + key: 'area', + options: [] + }]; + $api.myRequest('/system/public/dict/data/getByParentValue',params,'POST',9100,headers).then(res=>{ + if (res.code == 200) { + filterOptions.value[0].options = res.data.map(item=>{ + return { + label: item.dictLabel, + value: item.dictValue, + } + }) + } + }) + activeTab.value = 'area'; + } async function thirdLogin(needToast){ let form={} if (uni.getStorageSync('userInfo') && (uni.getStorageSync('userInfo').isCompanyUser=='1' || uni.getStorageSync('userInfo').isCompanyUser=='2')) { @@ -339,11 +442,27 @@ // 正确映射响应为用户信息(优先使用 data 字段) const data = resData?.data ?? resData; userInfo.value = data || {}; + if(data?.info?.entCreditCode && data?.info?.userId){ + updateEnterpriseId({ + unifiedSocialCreditCode: data?.info?.entCreditCode, + userId: data?.info?.userId, + }) + } getFair("refresh"); return userInfo.value; }); } - + function updateEnterpriseId(params){ + const headers = { + 'Content-Type':'application/json' + } + return $api.myRequest("/jobfair/public/job-fair-sign-up-enterprise/update-enterprise-id", params, "POST", 9100, headers).then((resData) => { + if(resData.code == 200 && resData.data !=0){ + state.current = 3 + getMyFair("refresh"); + } + }); + } function getMyFair(type = "add") { if (type === "refresh") { pageState.pageNum = 1; @@ -404,6 +523,7 @@ pageSize: pageState.pageSize, jobFairTitle: pageState.jobFairTitle, jobFairType: state.current, + dictValue: selectedValues.value, }; if (isLogin.value) { if (userInfo.value.userType == "ent") { @@ -561,7 +681,168 @@ return dates; } + diff --git a/pages/city-select/index.vue b/pages/city-select/index.vue new file mode 100644 index 0000000..c62b2ea --- /dev/null +++ b/pages/city-select/index.vue @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + {{ group.letter }} + + {{ item.name }} + + + + + + + + {{ letter }} + + + + + + + + + \ No newline at end of file diff --git a/pages/complete-info/complete-info.vue b/pages/complete-info/complete-info.vue index fbbc7e5..88bcf8a 100644 --- a/pages/complete-info/complete-info.vue +++ b/pages/complete-info/complete-info.vue @@ -268,11 +268,11 @@ const openSelectPopup = (config) => { // #endif }; const tabCurrent = ref(1); -const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100]; +const salay = [2000, 5000, 10000, 15000, 20000, 25000, 30000, 50000, 80000, 100000]; const state = reactive({ station: [], stationCateLog: 1, - lfsalay: [2, 5, 10, 15, 20, 25, 30, 50], + lfsalay: [2000, 5000, 10000, 15000, 20000, 25000, 30000, 50000], risalay: JSON.parse(JSON.stringify(salay)), areaText: '', educationText: '', @@ -614,10 +614,10 @@ function changeSalay() { title: '薪资', maskClick: true, data: [state.lfsalay, state.risalay], - unit: 'k', + unit: '元', success: (_, [min, max]) => { - fromValue.salaryMin = min.value * 1000; - fromValue.salaryMax = max.value * 1000; + fromValue.salaryMin = min.value; + fromValue.salaryMax = max.value; state.salayText = `${fromValue.salaryMin}-${fromValue.salaryMax}`; }, change(e) { diff --git a/pages/index/components/index-one.vue b/pages/index/components/index-one.vue index 0f6e00b..a7aee53 100644 --- a/pages/index/components/index-one.vue +++ b/pages/index/components/index-one.vue @@ -75,15 +75,15 @@ - + + 简历指导 + - @@ -148,12 +148,12 @@ 职业规划推荐 - + @@ -166,6 +166,25 @@ 帮扶 + + + + + 培训评价公告 + + + + + + + 培训机构信息 + + + + + + 评价机构信息 + @@ -231,10 +250,15 @@ + 添加 + + {{ selectedCity.name || '地区' }} + + @@ -298,7 +322,7 @@ {{ config.appInfo.areaName }} - + @@ -375,7 +399,7 @@ {{ config.appInfo.areaName }} - + @@ -590,6 +614,14 @@ const wxAuthLoginRef = ref(null); const state = reactive({ tabIndex: 'all', }); +//帮扶模块跳转 +const helpClick = () => { + navTo('/packageB/priority/helpFilter'); +}; +//招聘会模块跳转 +const handleJobFairClick = () => { + navTo('/pages/careerfair/careerfair'); +}; const list = ref([]); const pageState = reactive({ page: 0, @@ -604,17 +636,20 @@ const inputText = ref(''); const showFilter = ref(false); const selectFilterModel = ref(null); const showModel = ref(false); +// 选中的城市 +const selectedCity = ref({ code: '', name: '' }); const rangeOptions = ref([ { value: 0, text: '推荐' }, { value: 1, text: '最热' }, { value: 2, text: '最新发布' }, { value: 3, text: '疆外' }, + { value: 4, text: '零工市场' } ]); const isLoaded = ref(false); const isInitialized = ref(false); // 添加初始化标志 const { columnCount, columnSpace } = useColumnCount(() => { - pageState.pageSize = 10 * (columnCount.value - 1); + pageState.pageSize = 10 * (columnCount.value - 1) + 10; // 只在首次初始化时调用,避免重复调用 if (!isInitialized.value) { @@ -679,6 +714,7 @@ const goToCompanyInfo = () => { navTo('/pages/mine/company-info'); }; + // 组件初始化时加载数据 onMounted(() => { // 获取企业信息 @@ -694,6 +730,7 @@ onMounted(() => { // 在组件挂载时绑定事件监听,确保只绑定一次 // 先移除可能存在的旧监听,避免重复绑定 uni.$off('showLoginModal'); + uni.$off('citySelected'); // 绑定新的监听 uni.$on('showLoginModal', () => { @@ -702,6 +739,15 @@ onMounted(() => { pageNull.value = 0; }); + // 监听城市选择事件 + uni.$on('citySelected', (city) => { + console.log('收到citySelected事件,选择的城市:', city); + selectedCity.value = city; + // 可以在这里添加根据城市筛选职位的逻辑 + conditionSearch.value.jobLocationAreaCode = city.code; + getJobRecommend('refresh'); + }); + // 获取企业信息 getCompanyInfo(); }); @@ -709,6 +755,7 @@ onMounted(() => { onUnmounted(() => { // 组件销毁时移除事件监听 uni.$off('showLoginModal'); + uni.$off('citySelected'); }); onShow(() => { @@ -746,21 +793,63 @@ const handleLoginSuccess = () => { //四级联动单点及权限 getIsFourLevelLinkagePurview() }; +// H5环境下从URL获取token并自动登录 +onLoad(() => { + // #ifdef H5 + const token = uni.getStorageSync('zkr-token'); + if (token) { + useUserStore().loginSetToken(token); + } + // #endif +}); // 处理附近工作点击 -const handleNearbyClick = () => { +const handleNearbyClick = (options ) => { + // #ifdef MP-WEIXIN if (checkLogin()) { navTo('/pages/nearby/nearby'); } + // #endif + // #ifdef H5 + const token = options.token || uni.getStorageSync('zkr-token'); + if (token) { + navTo('/pages/nearby/nearby'); + } + // #endif }; - +const handleNoticeClick = () =>{ + uni.navigateTo({ + url:'/packageB/notice/index' + }) +} +function handleInstitutionClick(type){ + if(type=='evaluate'){ + uni.navigateTo({ + url:'/packageB/institution/evaluationAgency' + }) + }else if (type=='training'){ + uni.navigateTo({ + url:'/packageB/institution/trainingInstitution' + }) + } + +} // 处理服务功能点击 const handleServiceClick = (serviceType) => { if (checkLogin()) { navToService(serviceType); } }; - +// H5的简历指导跳转 +const handelGoResumeGuide = () => { + const token = uni.getStorageSync('zkr-token'); + // myToken.value = token; + if (token) { + // navTo() + navTo('/pages/resume-guide/resume-guide'); + } + +} // 处理直播按钮点击 const handleLiveClick = () => { // #ifdef MP-WEIXIN @@ -794,17 +883,12 @@ const handleLiveClick = () => { const handleSalaryInfoClick = () => { navTo('/pages/service/salary-info'); }; -const handleJobFairClick = () => { - navTo('/pages/careerfair/careerfair'); -}; + const handleH5SalaryClick = () => { const salaryUrl = "https://www.mohrss.gov.cn/SYrlzyhshbzb/laodongguanxi_/fwyd/202506/t20250627_544623.html"; window.location.assign(salaryUrl); }; -// 处理帮扶 -const helpClick = () => { - navTo('/packageB/priority/helpFilter'); -}; + async function loadData() { try { if (isLoaded.value) return; @@ -878,15 +962,7 @@ function clearfindJob(job) { } function nextDetail(job) { - // 登录检查 - if (checkLogin()) { - // 记录岗位类型,用作数据分析 - if (job.jobCategory) { - const recordData = recommedIndexDb.JobParameter(job); - recommedIndexDb.addRecord(recordData); - } - navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`); - } + navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`); } function navToService(serviceType) { @@ -982,6 +1058,12 @@ function handelHostestSearch(val) { isShowJw.value = val.value; pageState.search.order = val.value; pageState.search.jobType = val.value === 3 ? 1 : 0; + if(val.value === 4) { + pageState.search.type = 4; + } else { + delete pageState.search.type; + } + if (state.tabIndex === 'all') { getJobRecommend('refresh'); } else { @@ -996,12 +1078,16 @@ function getJobRecommend(type = 'add') { if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh(); } let params = { - pageSize: pageState.pageSize, + pageSize: pageState.pageSize + 10, sessionId: useUserStore().seesionId, ...pageState.search, ...conditionSearch.value, isPublish: 1, }; + // 当选中零工市场(4)或疆外(3)时,order参数传递0 + if (pageState.search.order === 3 || pageState.search.order === 4) { + params.order = 0; + } // 优先从store获取,如果为空则从缓存获取 const storeIsCompanyUser = userInfo.value?.isCompanyUser; const cachedUserInfo = uni.getStorageSync('userInfo') || {}; @@ -1080,11 +1166,15 @@ function getJobList(type = 'add') { ...pageState.search, // ...conditionSearch.value, }; + // 当选中零工市场(4)或疆外(3)时,order参数传递0 + if (pageState.search.order === 3 || pageState.search.order === 4) { + params.order = 0; + } $api.createRequest('/app/job/list', params).then((resData) => { const { rows, total } = resData; if (type === 'add') { - const str = pageState.pageSize * (pageState.page - 1); + const str = pageState.pageSize * (pageState.page - 1) + 10; const end = list.value.length; const reslist = dataToImg(rows); list.value.splice(str, end, ...reslist); @@ -1656,6 +1746,9 @@ defineExpose({ loadData }); min-width: 80rpx; padding: 8rpx 12rpx; white-space: nowrap; + .right-sx + width: 28rpx; + height: 28rpx; .filter-bottom display: flex justify-content: space-between @@ -1667,8 +1760,8 @@ defineExpose({ loadData }); font-weight: 400; font-size: 32rpx; color: #666D7F; - margin-right: 24rpx - padding: 0rpx 16rpx + margin-right: 8rpx + padding: 0rpx 6rpx .active font-weight: 500; font-size: 32rpx; diff --git a/pages/index/index.vue b/pages/index/index.vue index b32f937..c903289 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -19,10 +19,11 @@ import IndexOne from './components/index-one.vue'; // import IndexTwo from './components/index-two.vue'; import { storeToRefs } from 'pinia'; import { useReadMsg } from '@/stores/useReadMsg'; +import useUserStore from '@/stores/useUserStore'; import { tabbarManager } from '@/utils/tabbarManager'; const { unreadCount } = storeToRefs(useReadMsg()); - -onLoad(() => { +const userStore = useUserStore(); +onLoad((options) => { // useReadMsg().fetchMessages(); }); diff --git a/pages/login/h5-login.vue b/pages/login/h5-login.vue index cd58ace..41eb30c 100644 --- a/pages/login/h5-login.vue +++ b/pages/login/h5-login.vue @@ -194,7 +194,7 @@ const handleLogin = async () => { icon: 'success' }) // window.location.assign('http://222.80.110.161:11111/mechine-dual-vue/login') - window.location.assign('https://www.xjksly.cn/mechine-single-vue/login') + // window.location.assign('https://www.xjksly.cn/mechine-single-vue/login') // // 跳转到首页 // uni.reLaunch({ // url: '/pages/index/index' diff --git a/pages/mine/company-info.vue b/pages/mine/company-info.vue index 52a71a3..1a6a3c8 100644 --- a/pages/mine/company-info.vue +++ b/pages/mine/company-info.vue @@ -5,7 +5,7 @@ 编辑信息 - + @@ -15,7 +15,7 @@ 企业名称 {{ companyInfo.name || '暂无公司名称' }} - + @@ -23,7 +23,7 @@ 统一社会代码 {{ companyInfo.socialCode || '暂无统一社会代码' }} - + @@ -31,7 +31,7 @@ 企业注册地点 {{ companyInfo.location || '暂无注册地点' }} - + @@ -39,7 +39,7 @@ 企业信息介绍 {{ companyInfo.description || '暂无企业介绍' }} - + @@ -47,7 +47,7 @@ 企业法人姓名 {{ companyInfo.legalPerson || '暂无法人信息' }} - + diff --git a/pages/resume-guide/resume-guide.vue b/pages/resume-guide/resume-guide.vue index 8b1ac4a..1630227 100644 --- a/pages/resume-guide/resume-guide.vue +++ b/pages/resume-guide/resume-guide.vue @@ -49,9 +49,11 @@ + 开始制作简历 + 查看简历示例 diff --git a/static/icon/pxjgxx.png b/static/icon/pxjgxx.png new file mode 100644 index 0000000..f341d35 Binary files /dev/null and b/static/icon/pxjgxx.png differ diff --git a/static/icon/pxpjjg.png b/static/icon/pxpjjg.png new file mode 100644 index 0000000..2bb21e4 Binary files /dev/null and b/static/icon/pxpjjg.png differ diff --git a/static/icon/pxxxcj.png b/static/icon/pxxxcj.png new file mode 100644 index 0000000..75ac2bb Binary files /dev/null and b/static/icon/pxxxcj.png differ diff --git a/stores/userChatGroupStore.js b/stores/userChatGroupStore.js index 9eb330f..ae21f54 100644 --- a/stores/userChatGroupStore.js +++ b/stores/userChatGroupStore.js @@ -107,102 +107,108 @@ const useChatGroupDBStore = defineStore("messageGroup", () => { return await baseDB.db.add(massageName.value, payload); } - async function getStearm(text, fileUrls = [], progress, options = {}) { - - return new Promise((resolve, reject) => { - try { - toggleTyping(true); - const customDataID = 'message_' + UUID.generate() - const params = { - data: text, - sessionId: chatSessionID.value, - dataId: customDataID - }; - if (fileUrls && fileUrls.length) { - params['fileUrl'] = fileUrls.map((item) => item.url); - } - // ------> - const MsgData = { - text: text, - self: true, - displayText: text, - files: fileUrls - }; - addMessage(MsgData); // 添加message数据 - // <------ - const newMsg = { - text: '', // 存储原始结构化内容 - self: false, - displayText: '', // 用于流式渲染展示 - dataId: customDataID - }; - const index = messages.value.length; - messages.value.push(newMsg); - - const rawParts = Array.isArray(text) ? text : [text]; // 统一处理 - - // 用于追加每个部分的流式数据 - let partIndex = 0; - - function handleUnload() { - newMsg.parentGroupId = chatSessionID.value; - baseDB.db.add(massageName.value, newMsg).then((id) => { - messages.value[index] = { - ...newMsg, - id - }; - }); - } - // #ifdef H5 - if (typeof window !== 'undefined') { - window.addEventListener("unload", handleUnload); - } - // #endif - - function onDataReceived(data) { - // 支持追加多个部分 - newMsg.text += data; - newMsg.displayText += data; - messages.value[index] = { - ...newMsg - }; - progress && progress(); - - // 调用外部传入的onDataReceived回调 - if (options.onDataReceived) { - options.onDataReceived(data, newMsg, index); - } - } - - function onError(error) { - msg('服务响应异常'); - reject(error); - } - - function onComplete() { - messages.value[index] = { - ...newMsg - }; - toggleTyping(false); - // #ifdef H5 - if (typeof window !== 'undefined') { - window.removeEventListener("unload", handleUnload); - } - // #endif - handleUnload(); - // 调用外部传入的onComplete回调 - if (options.onComplete) { - options.onComplete(); - } - resolve(); - } - - $api.streamRequest('/chat', params, onDataReceived, onError, onComplete); - } catch (err) { - console.log(err); - reject(err); - } - }); + async function getStearm(text, fileUrls = [], progress, options = {}) { + + return new Promise((resolve, reject) => { + try { + toggleTyping(true); + const customDataID = 'message_' + UUID.generate() + + // 对话历史管理:只保留最近的N条消息,防止token超限 + // 计算消息数量,只保留最近的10条消息(可根据实际情况调整) + const MAX_HISTORY_MESSAGES = 10; + const historyMessages = messages.value.slice(-MAX_HISTORY_MESSAGES); + + const params = { + data: text, + sessionId: chatSessionID.value, + dataId: customDataID + }; + if (fileUrls && fileUrls.length) { + params['fileUrl'] = fileUrls.map((item) => item.url); + } + // ------> + const MsgData = { + text: text, + self: true, + displayText: text, + files: fileUrls + }; + addMessage(MsgData); // 添加message数据 + // <------ + const newMsg = { + text: '', // 存储原始结构化内容 + self: false, + displayText: '', // 用于流式渲染展示 + dataId: customDataID + }; + const index = messages.value.length; + messages.value.push(newMsg); + + const rawParts = Array.isArray(text) ? text : [text]; // 统一处理 + + // 用于追加每个部分的流式数据 + let partIndex = 0; + + function handleUnload() { + newMsg.parentGroupId = chatSessionID.value; + baseDB.db.add(massageName.value, newMsg).then((id) => { + messages.value[index] = { + ...newMsg, + id + }; + }); + } + // #ifdef H5 + if (typeof window !== 'undefined') { + window.addEventListener("unload", handleUnload); + } + // #endif + + function onDataReceived(data) { + // 支持追加多个部分 + newMsg.text += data; + newMsg.displayText += data; + messages.value[index] = { + ...newMsg + }; + progress && progress(); + + // 调用外部传入的onDataReceived回调 + if (options.onDataReceived) { + options.onDataReceived(data, newMsg, index); + } + } + + function onError(error) { + msg('服务响应异常'); + reject(error); + } + + function onComplete() { + messages.value[index] = { + ...newMsg + }; + toggleTyping(false); + // #ifdef H5 + if (typeof window !== 'undefined') { + window.removeEventListener("unload", handleUnload); + } + // #endif + handleUnload(); + // 调用外部传入的onComplete回调 + if (options.onComplete) { + options.onComplete(); + } + resolve(); + } + + $api.streamRequest('/chat', params, onDataReceived, onError, onComplete); + } catch (err) { + console.log(err); + reject(err); + } + }); } // 状态控制 diff --git a/utils/markdownParser.js b/utils/markdownParser.js index 1611be9..451c4a1 100644 --- a/utils/markdownParser.js +++ b/utils/markdownParser.js @@ -19,38 +19,20 @@ const md = new MarkdownIt({ const result = safeExtractJson(str); if (result) { // json解析成功 const jobId = result.appJobUrl.split('jobId=')[1] - let domContext = ` - - - ${result.jobTitle} - ${result.salary} - - ${result.location}·${result.companyName} - - - ${result.education} - ${result.experience} - - 查看详情 - - - ` + let domContext = `${result.jobTitle}${result.salary}${result.location}·${result.companyName}${result.education}${result.experience}查看详情` if (result.data) { jobMoreMap.set(jobId, result.data) - domContext += - `查看更多岗位` + domContext += `查看更多岗位` } return domContext } } - // ${result.location} - // ${result.salary} // 代码块 let preCode = "" try { preCode = hljs.highlightAuto(str).value } catch (err) { - preCode = markdownIt.utils.escapeHtml(str); + preCode = md.utils.escapeHtml(str); } // 以换行进行分割 , 按行拆分代码 const lines = preCode.split(/\n/).slice(0, -1); @@ -58,7 +40,7 @@ const md = new MarkdownIt({ .map((line, index) => line ? `${line}` : - '' + '' ) .join(''); @@ -127,9 +109,49 @@ export function clearJobMoreMap() { // 切换对话清空 export function parseMarkdown(content) { if (!content) { - return //处理特殊情况,比如网络异常导致的响应的 content 的值为空 + return [] //处理特殊情况,比如网络异常导致的响应的 content 的值为空 } + + // 过滤掉标签及其内容,这些是AI内部思考过程,不应该显示给用户 + // 1. 处理原始标签(支持多行) + content = content.replace(/<\s*think\s*>[\s\S]*?<\s*\/\s*think\s*>/gi, '') + // 2. 处理HTML编码的标签 + content = content.replace(/<\s*think\s*>[\s\S]*?<\s*\/\s*think\s*>/gi, '') + // 3. 处理部分编码的标签 + content = content.replace(/<\s*think\s*>/gi, '') + content = content.replace(/<\s*\/\s*think\s*>/gi, '') + codeDataList = [] const unsafeHtml = md.render(content || '') - return unsafeHtml + + // 在markdown渲染后再次过滤,确保没有遗漏 + let filteredHtml = unsafeHtml + // 1. 处理原始标签(支持多行) + filteredHtml = filteredHtml.replace(/<\s*think\s*>[\s\S]*?<\s*\/\s*think\s*>/gi, '') + // 2. 处理HTML编码的标签 + filteredHtml = filteredHtml.replace(/<\s*think\s*>[\s\S]*?<\s*\/\s*think\s*>/gi, '') + // 3. 处理部分编码的标签 + filteredHtml = filteredHtml.replace(/<\s*think\s*>/gi, '') + filteredHtml = filteredHtml.replace(/<\s*\/\s*think\s*>/gi, '') + // 4. 单独处理剩余的think标签对 + filteredHtml = filteredHtml.replace(/<think>/gi, '') + filteredHtml = filteredHtml.replace(/<\/think>/gi, '') + filteredHtml = filteredHtml.replace(//gi, '') + filteredHtml = filteredHtml.replace(/<\/think>/gi, '') + + // 根据平台返回不同的内容格式 + // 微信小程序:返回rich-text组件支持的nodes格式 + // H5:直接返回HTML字符串,避免HTML解析错误 + if (process.env.UNI_PLATFORM === 'mp-weixin') { + try { + return parseHtml(filteredHtml) + } catch (error) { + console.error('HTML解析失败:', error) + // 解析失败时返回空数组,避免页面崩溃 + return [] + } + } else { + // H5端直接返回HTML字符串 + return filteredHtml + } } \ No newline at end of file diff --git a/utils/streamRequest.js b/utils/streamRequest.js index 9a49cef..7073f97 100644 --- a/utils/streamRequest.js +++ b/utils/streamRequest.js @@ -27,6 +27,7 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom return new Promise((resolve, reject) => { let buffer = ''; + let hasReceivedContent = false; const requestTask = uni.request({ url: config.StreamBaseURl + url, @@ -55,15 +56,33 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom try { const decoder = new TextDecoder('utf-8'); const chunk = decoder.decode(new Uint8Array(res.data)); + console.log('📦 收到分块数据:', chunk); buffer += chunk; let lines = buffer.split("\n"); buffer = lines.pop() || ''; // 保留不完整的行 + console.log('📝 解析到行:', lines.length, '行,缓冲区剩余:', buffer.length, '字符'); for (let line of lines) { - if (line.startsWith("data: ")) { - const jsonData = line.slice(6).trim(); + console.log('🔍 处理行:', line); + // 处理重复的 data: 前缀 + let processedLine = line; + // 移除所有开头的 data: 前缀(无论是否有空格),直到只剩下一个或没有 + while (processedLine.startsWith("data:")) { + // 检查是否还有另一个 data: 前缀 + const nextPart = processedLine.slice(5).trimStart(); + if (nextPart.startsWith("data:")) { + processedLine = nextPart; + } else { + break; + } + } + + if (processedLine.startsWith("data: ")) { + const jsonData = processedLine.slice(6).trim(); + console.log('📄 提取的JSON数据:', jsonData); if (jsonData === "[DONE]") { + console.log('✅ 收到结束标记 [DONE]'); onComplete && onComplete(); resolve(); return; @@ -72,11 +91,35 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom if (jsonData && jsonData.trim()) { try { const parsedData = JSON.parse(jsonData); + console.log('🔧 解析后的JSON:', parsedData); + // 检查是否有错误信息 + const finishReason = parsedData?.choices?.[0]?.finish_reason; + if (finishReason === "error") { + let errorContent = parsedData?.choices?.[0]?.delta?.content || "流式请求失败"; + console.error('❌ 收到错误信息:', errorContent); + + // 优化token超限错误提示 + if (errorContent.includes("maximum input ids length")) { + errorContent = "对话历史过长,请尝试清除部分历史记录或简化问题"; + } + + // 只有当未收到正常内容时才显示错误信息 + if (!hasReceivedContent) { + // 显示错误信息给用户 + uni.showToast({ + title: errorContent, + icon: 'none', + duration: 3000 + }); + } + } // 处理标准的choices格式 - if (parsedData?.choices?.[0]?.delta?.content) { + else if (parsedData?.choices?.[0]?.delta?.content) { const content = parsedData.choices[0].delta.content; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(content):', content); onDataReceived && onDataReceived(content); } } @@ -84,6 +127,8 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom else if (parsedData?.choices?.[0]?.delta?.reasoning_content) { const content = parsedData.choices[0].delta.reasoning_content; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(reasoning_content):', content); onDataReceived && onDataReceived(content); } } @@ -91,14 +136,42 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom else if (parsedData?.tool?.response) { const content = parsedData.tool.response; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(tool.response):', content); onDataReceived && onDataReceived(content); } } + // 处理其他可能的内容格式 + else if (parsedData?.content) { + // 直接返回content字段的情况 + const content = parsedData.content; + if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(direct content):', content); + onDataReceived && onDataReceived(content); + } + } + // 处理完整的text字段(非流式) + else if (parsedData?.choices?.[0]?.text) { + const content = parsedData.choices[0].text; + if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(full text):', content); + onDataReceived && onDataReceived(content); + } + } + else { + console.warn('⚠️ 未匹配到任何内容格式:', parsedData); + } } catch (e) { - console.error("JSON 解析失败:", e.message); + console.error("JSON 解析失败:", e.message, "原始数据:", jsonData); } } } + else if (processedLine.trim()) { + // 处理非data:开头的行 + console.warn('⚠️ 收到非data:开头的行:', processedLine); + } } } catch (error) { console.error('处理分块数据失败:', error); @@ -135,6 +208,7 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { let buffer = ""; let retryCount = 0; const maxRetries = 3; + let hasReceivedContent = false; while (true) { const { @@ -157,9 +231,25 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { console.log(`📦 Processing ${lines.length} lines, buffer length: ${buffer.length}`); for (let line of lines) { - if (line.startsWith("data: ")) { - const jsonData = line.slice(6).trim(); + console.log('🔍 处理行:', line); + // 处理重复的 data: 前缀 + let processedLine = line; + // 移除所有开头的 data: 前缀(无论是否有空格),直到只剩下一个或没有 + while (processedLine.startsWith("data:")) { + // 检查是否还有另一个 data: 前缀 + const nextPart = processedLine.slice(5).trimStart(); + if (nextPart.startsWith("data:")) { + processedLine = nextPart; + } else { + break; + } + } + + if (processedLine.startsWith("data: ")) { + const jsonData = processedLine.slice(6).trim(); + console.log('📄 提取的JSON数据:', jsonData); if (jsonData === "[DONE]") { + console.log('✅ 收到结束标记 [DONE]'); onComplete && onComplete(); resolve(); return; @@ -169,11 +259,35 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { // 检查JSON数据是否完整 if (jsonData && jsonData.trim() && jsonData !== "[DONE]") { const parsedData = JSON.parse(jsonData); + console.log('🔧 解析后的JSON:', parsedData); + // 检查是否有错误信息 + const finishReason = parsedData?.choices?.[0]?.finish_reason; + if (finishReason === "error") { + let errorContent = parsedData?.choices?.[0]?.delta?.content || "流式请求失败"; + console.error('❌ 收到错误信息:', errorContent); + + // 优化token超限错误提示 + if (errorContent.includes("maximum input ids length")) { + errorContent = "对话历史过长,请尝试清除部分历史记录或简化问题"; + } + + // 只有当未收到正常内容时才显示错误信息 + if (!hasReceivedContent) { + // 显示错误信息给用户 + uni.showToast({ + title: errorContent, + icon: 'none', + duration: 3000 + }); + } + } // 处理标准的choices格式 - if (parsedData?.choices?.[0]?.delta?.content) { + else if (parsedData?.choices?.[0]?.delta?.content) { const content = parsedData.choices[0].delta.content; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(content):', content); onDataReceived && onDataReceived(content); } } @@ -181,6 +295,8 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { else if (parsedData?.choices?.[0]?.delta?.reasoning_content) { const content = parsedData.choices[0].delta.reasoning_content; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(reasoning_content):', content); onDataReceived && onDataReceived(content); } } @@ -188,6 +304,27 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { else if (parsedData?.tool?.response) { const content = parsedData.tool.response; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(tool.response):', content); + onDataReceived && onDataReceived(content); + } + } + // 处理其他可能的内容格式 + else if (parsedData?.content) { + // 直接返回content字段的情况 + const content = parsedData.content; + if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(direct content):', content); + onDataReceived && onDataReceived(content); + } + } + // 处理完整的text字段(非流式) + else if (parsedData?.choices?.[0]?.text) { + const content = parsedData.choices[0].text; + if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(full text):', content); onDataReceived && onDataReceived(content); } } @@ -201,6 +338,10 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { // 不抛出错误,继续处理下一个数据块 } } + else if (processedLine.trim()) { + // 处理非data:开头的行 + console.warn('⚠️ 收到非data:开头的行:', processedLine); + } } } @@ -209,16 +350,55 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { console.log("📦 Processing remaining buffer:", buffer.substring(0, 100) + "..."); const lines = buffer.split("\n"); for (let line of lines) { - if (line.startsWith("data: ")) { - const jsonData = line.slice(6).trim(); + console.log('🔍 处理剩余缓冲区行:', line); + // 处理重复的 data: 前缀 + let processedLine = line; + // 移除所有开头的 data: 前缀(无论是否有空格),直到只剩下一个或没有 + while (processedLine.startsWith("data:")) { + // 检查是否还有另一个 data: 前缀 + const nextPart = processedLine.slice(5).trimStart(); + if (nextPart.startsWith("data:")) { + processedLine = nextPart; + } else { + break; + } + } + + if (processedLine.startsWith("data: ")) { + const jsonData = processedLine.slice(6).trim(); + console.log('📄 提取的剩余JSON数据:', jsonData); if (jsonData && jsonData !== "[DONE]") { try { const parsedData = JSON.parse(jsonData); + console.log('🔧 解析后的剩余JSON:', parsedData); + // 检查是否有错误信息 + const finishReason = parsedData?.choices?.[0]?.finish_reason; + if (finishReason === "error") { + let errorContent = parsedData?.choices?.[0]?.delta?.content || "流式请求失败"; + console.error('❌ 收到错误信息:', errorContent); + + // 优化token超限错误提示 + if (errorContent.includes("maximum input ids length")) { + errorContent = "对话历史过长,请尝试清除部分历史记录或简化问题"; + } + + // 只有当未收到正常内容时才显示错误信息 + if (!hasReceivedContent) { + // 显示错误信息给用户 + uni.showToast({ + title: errorContent, + icon: 'none', + duration: 3000 + }); + } + } // 处理标准的choices格式 - if (parsedData?.choices?.[0]?.delta?.content) { + else if (parsedData?.choices?.[0]?.delta?.content) { const content = parsedData.choices[0].delta.content; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(content):', content); onDataReceived && onDataReceived(content); } } @@ -226,6 +406,8 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { else if (parsedData?.choices?.[0]?.delta?.reasoning_content) { const content = parsedData.choices[0].delta.reasoning_content; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(reasoning_content):', content); onDataReceived && onDataReceived(content); } } @@ -233,6 +415,27 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { else if (parsedData?.tool?.response) { const content = parsedData.tool.response; if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(tool.response):', content); + onDataReceived && onDataReceived(content); + } + } + // 处理其他可能的内容格式 + else if (parsedData?.content) { + // 直接返回content字段的情况 + const content = parsedData.content; + if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(direct content):', content); + onDataReceived && onDataReceived(content); + } + } + // 处理完整的text字段(非流式) + else if (parsedData?.choices?.[0]?.text) { + const content = parsedData.choices[0].text; + if (content) { + hasReceivedContent = true; + console.log('📤 调用onDataReceived(full text):', content); onDataReceived && onDataReceived(content); } } @@ -241,6 +444,10 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) { } } } + else if (processedLine.trim()) { + // 处理非data:开头的行 + console.warn('⚠️ 收到非data:开头的剩余行:', processedLine); + } } } @@ -295,16 +502,27 @@ export function chatRequest(url, data = {}, method = 'GET', loading = false, hea return } uni.showToast({ - title: msg, + title: msg || '请求失败', icon: 'none' }) + // 拒绝Promise并提供详细错误信息 + const err = new Error(msg || '请求失败,服务器返回错误码: ' + code) + err.error = resData + reject(err) + } else { + // 处理非200状态码 + const errorMsg = `请求失败,HTTP状态码: ${resData.statusCode}` + uni.showToast({ + title: errorMsg, + icon: 'none' + }) + const err = new Error(errorMsg) + err.error = resData + reject(err) } if (resData.data?.code === 401 || resData.data?.code === 402) { useUserStore().logOut() } - const err = new Error('请求出现异常,请联系工作人员') - err.error = resData - reject(err) }, fail: (err) => { reject(err)