From 8ef6a6693eaa671ec289ddbbf6543e6bf33272ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B7=A6=E5=93=A5?= <17630302050@163.com> Date: Mon, 21 Jul 2025 22:24:05 +0800 Subject: [PATCH] sdsd --- api/ocr.js | 56 +++++++++++++- pages/followUp/index.js | 149 ++++++++++++++++++++++++++++---------- pages/followUp/index.wxml | 54 ++++++++++---- pages/followUp/ocrDate.js | 0 4 files changed, 203 insertions(+), 56 deletions(-) create mode 100644 pages/followUp/ocrDate.js diff --git a/api/ocr.js b/api/ocr.js index 025c223..ecb5659 100644 --- a/api/ocr.js +++ b/api/ocr.js @@ -28,7 +28,7 @@ export const getOcr = (url) => { }] }, success(res) { - const data = parseMarkdownTable(res.data.choices[0].message.content) + const data = parseOcrResult(res.data.choices[0].message.content) resolve(data); }, fail(err) { @@ -62,4 +62,58 @@ function parseMarkdownTable(md) { }); return result; +} + +/** + * 解析类似 ```json ... ``` 格式的字符串,提取检测项目数组 + * @param {string} str + * @returns {Array} + */ +function parseJsonBlock(str) { + // 去除包裹的代码块标记 + const jsonStr = str.replace(/^[\s`]*```json[\s`]*|```$/g, '').replace(/↵/g, '\n').trim(); + + // 用正则提取所有 "key": "value" + const regex = /"([^"]+)":\s*"([^"]*)"/g; + const pairs = []; + let match; + while ((match = regex.exec(jsonStr)) !== null) { + pairs.push([match[1], match[2]]); + } + + // 按“序号”分组 + const items = []; + let current = {}; + const itemFields = ['序号', '项目名称', '缩写', '结果', '单位', '参考区间', '测定方法']; + pairs.forEach(([key, value]) => { + if (key === '序号' && Object.keys(current).length > 0) { + items.push({ ...current }); + current = {}; + } + if (itemFields.includes(key)) { + current[key] = value; + } + }); + if (Object.keys(current).length > 0) { + items.push({ ...current }); + } + return items; +} + +/** + * 自动判断OCR返回内容格式并调用对应解析方法 + * @param {string} content + * @returns {Array} + */ +function parseOcrResult(content) { + // 判断是否为JSON代码块 + if (/^```json/.test(content.trim())) { + return parseJsonBlock(content); + } + // 判断是否为Markdown表格(以|开头,且有---分隔行) + if (/\|.*\|/.test(content) && /\|[\s\-:|]+\|/.test(content)) { + return parseMarkdownTable(content); + } + // 其它情况返回空数组或原始内容 + return []; } \ No newline at end of file diff --git a/pages/followUp/index.js b/pages/followUp/index.js index 40144b5..5d0d80b 100644 --- a/pages/followUp/index.js +++ b/pages/followUp/index.js @@ -13,7 +13,7 @@ Page({ form: { follow_name: '', - liver_function_image:[], + liver_function_image: [], b_mode_image: [], blood_routine_image: [], coagulation_function_image: [], @@ -126,7 +126,7 @@ Page({ onInput(e) { const { key, tips } = e.currentTarget.dataset; - if(e.detail.value){ + if (e.detail.value) { this.setData({ [tips]: true, [`form.${key}`]: e.detail.value @@ -137,12 +137,12 @@ Page({ [`form.${key}`]: e.detail.value }) } - - + + }, - onInputTime(e){ + onInputTime(e) { const { tips } = e.currentTarget.dataset; - if(e.detail.value){ + if (e.detail.value) { this.setData({ [tips]: true, }); @@ -162,7 +162,7 @@ Page({ }, onPickerChange(e) { - if(e.detail.value){ + if (e.detail.value) { this.setData({ isTime: true, ['form.follow_date']: e.detail.value @@ -173,7 +173,7 @@ Page({ ['form.follow_date']: e.detail.value }) } - + }, handleSuccess(e) { const { files } = e.detail; @@ -193,46 +193,46 @@ Page({ console.log(e.detail.file); }, - planId:'', + planId: '', questionnaire_id: '', async toQuestionnaire() { let valid = true; // 必填项校验 - if(!this.data.form.follow_name){ + if (!this.data.form.follow_name) { this.setData({ isName: false }); valid = false; } - if(!this.data.form.follow_date){ + if (!this.data.form.follow_date) { this.setData({ isTime: false }); valid = false; } - if(!this.data.form.follow_hospital){ + if (!this.data.form.follow_hospital) { this.setData({ isDoctor: false }); valid = false; } - if(!this.data.form.height){ + if (!this.data.form.height) { this.setData({ isHeight: false }); valid = false; } - if(!this.data.form.weight){ + if (!this.data.form.weight) { this.setData({ isWeight: false }); valid = false; } - if(!valid) return + if (!valid) return const data = this.data.form data.liver_function_image = data.liver_function_image.length > 0 ? data.liver_function_image.join(',') : '' data.b_mode_image = data.b_mode_image.length > 0 ? data.b_mode_image.join(',') : '', - data.blood_routine_image = data.blood_routine_image.length > 0 ? data.blood_routine_image.join(',') : '', - data.coagulation_function_image = data.coagulation_function_image.length > 0 ? data.coagulation_function_image.join(',') : '', - data.mdt_image = data.mdt_image.length > 0 ? data.mdt_image.join(',') : '', - data.nutritional_indicator_image = data.nutritional_indicator_image.length > 0 ? data.nutritional_indicator_image.join(',') : '' + data.blood_routine_image = data.blood_routine_image.length > 0 ? data.blood_routine_image.join(',') : '', + data.coagulation_function_image = data.coagulation_function_image.length > 0 ? data.coagulation_function_image.join(',') : '', + data.mdt_image = data.mdt_image.length > 0 ? data.mdt_image.join(',') : '', + data.nutritional_indicator_image = data.nutritional_indicator_image.length > 0 ? data.nutritional_indicator_image.join(',') : '' data.is_have_cyst = data.is_have_cyst ? Number(data.is_have_cyst) : 0 data.is_have_ascites = data.is_have_ascites ? Number(data.is_have_ascites) : 0 - await request('patient/follow_questionnaire', 'post',{plan_id: Number(this.planId), questionnaire_id: Number(this.questionnaire_id), ...data}) + await request('patient/follow_questionnaire', 'post', { plan_id: Number(this.planId), questionnaire_id: Number(this.questionnaire_id), ...data }) wx.showToast({ title: '提交成功', icon: 'success', - duration: 2000, + duration: 2000, complete: () => { wx.navigateBack({ delta: 1 @@ -248,11 +248,11 @@ Page({ }, //上传文件方法 async uploadFileToOSS(file, callback) { - + const policyData = await request('admin/policy_token', 'post') const res = JSON.parse(policyData.token) - + const fileNameWithExt = file.tempFilePath.split('/').pop(); // hello.png const fileName = fileNameWithExt.split('.').slice(0, -1).join('.'); // hello @@ -270,7 +270,7 @@ Page({ // return // 发送请求上传文件 wx.uploadFile({ - url: 'https://image-fudan.oss-cn-beijing.aliyuncs.com/', + url: 'https://image-fudan.oss-cn-beijing.aliyuncs.com/', method: 'put', filePath: file.tempFilePath, name: 'file', //固定值为file @@ -278,7 +278,7 @@ Page({ success(res) { console.log('上传响应:', res); if (res.statusCode === 200) { - callback(null, 'https://image-fudan.oss-cn-beijing.aliyuncs.com/upload_file/'+ fileName); // 上传成功 + callback(null, 'https://image-fudan.oss-cn-beijing.aliyuncs.com/upload_file/' + fileName); // 上传成功 } else { console.error('上传失败,状态码:', res.statusCode); console.error('失败响应:', res); @@ -291,11 +291,11 @@ Page({ callback(err); // 调用回调处理错误 } }); - + }, handleUpload(e) { const { mode } = e.currentTarget.dataset; - if(this.data.form[mode].length >= 9){ + if (this.data.form[mode].length >= 9) { wx.showToast({ title: '最多上传9张图片!', icon: 'none' }); return } @@ -308,7 +308,7 @@ Page({ wx.showToast({ title: '文件上传中,请稍等!', icon: 'none' }); console.log('选择的文件:', res.tempFiles); // 输出选择的文件信息 if (res.tempFiles.length > 0) { - const tempFilePath = res.tempFiles[0]; + const tempFilePath = res.tempFiles[0]; console.log('选择的文件路径:', tempFilePath); // 输出文件路径 this.uploadFileToOSS(tempFilePath, (error, data) => { if (error) { @@ -316,14 +316,18 @@ Page({ console.error('上传失败:', error); // 输出具体的错误信息 } else { // getOcr(data) - wx.showToast({ title: '上传成功!', icon: 'success' }); + wx.showToast({ title: '上传成功,正在识别内容!', icon: 'success' }); const { mode } = e.currentTarget.dataset; let arr = this.data.form[mode] arr.unshift(data) this.setData({ [`form.${mode}`]: arr }) - getOcr(data) + getOcr(data).then(ocrRes => { + console.log(ocrRes) + wx.showToast({ title: '识别完成!', icon: 'success' }) + this.setFormData(ocrRes, mode) + }) console.log('上传成功:', data); // 输出上传成功后的数据 } }); @@ -338,8 +342,8 @@ Page({ }); }, - imageKey:'', - handleImagePreview(e){ + imageKey: '', + handleImagePreview(e) { const { mode, index } = e.currentTarget.dataset; this.imageKey = mode console.log(this.data.form[mode]) @@ -349,12 +353,12 @@ Page({ imageVisible: true }) }, - onClose(){ + onClose() { this.setData({ imageVisible: false - }) + }) }, - handleDelete(e){ + handleDelete(e) { const { mode, index } = e.currentTarget.dataset; let arr = this.data.form[mode] arr.splice(index, 1) @@ -363,7 +367,7 @@ Page({ }) }, - onDelete(e){ + onDelete(e) { console.log(e) let arr = this.data.form[this.imageKey] arr.splice(e.detail.index, 1) @@ -388,13 +392,13 @@ Page({ ['form.follow_date']: options.time }) console.log(options) - if(options.questionnaire_id != 0){ + if (options.questionnaire_id != 0) { this.getDetail() } }, - async getDetail(){ - const res = await request('patient/questionnaire_info', 'post',{patient_id : 0, questionnaire_id: Number(this.questionnaire_id)}) + async getDetail() { + const res = await request('patient/questionnaire_info', 'post', { patient_id: 0, questionnaire_id: Number(this.questionnaire_id) }) const data = res data.liver_function_image = data.liver_function_image ? data.liver_function_image.split(',') : [] data.b_mode_image = data.b_mode_image ? data.b_mode_image.split(',') : [] @@ -402,11 +406,76 @@ Page({ data.coagulation_function_image = data.coagulation_function_image ? data.coagulation_function_image.split(',') : [] data.mdt_image = data.mdt_image ? data.mdt_image.split(',') : [] data.nutritional_indicator_image = data.nutritional_indicator_image ? data.nutritional_indicator_image.split(',') : [] - + this.setData({ form: data }) }, + + // 遍历识别结果,填充字段 + setFormData(ocrs, mode) { + console.log(ocrs, mode) + ocrs.forEach(ocr => { + console.log(ocr['项目名称'], ocr['结果']) + // 血常规 + if (mode == 'blood_routine_image') { + if (ocr['项目名称'] == '血红蛋白') { + this.setData({ + [`form.hemoglobin`]: ocr['结果'] + }) + } + } + // 凝血功能 + if (mode == 'coagulation_function_image') { + + if (ocr['项目名称'] == '凝血酶原时间') { + this.setData({ + [`form.pt`]: ocr['结果'] + }) + } + if (ocr['项目名称'] == '凝血酶原活动度') { + this.setData({ + [`form.pta`]: ocr['结果'] + }) + } + if (ocr['项目名称'] == '国际标准化比值') { + this.setData({ + [`form.inr`]: ocr['结果'] + }) + } + if (ocr['项目名称'] == '活化部分凝血活酶时间') { + this.setData({ + [`form.aptt`]: ocr['结果'] + }) + } + if (ocr['项目名称'] == '凝血酶时间') { + this.setData({ + [`form.tt`]: ocr['结果'] + }) + } + if (ocr['项目名称'] == '纤维蛋白原') { + this.setData({ + [`form.fib`]: ocr['结果'] + }) + } + } + + // 肝功能 + if (mode == 'liver_function_image') { + + } + // 营养指数 + if (mode == 'nutritional_indicator_image') { + + } + // B超 + if (mode == 'b_mode_image') { + + } + + }) + }, + /** * 生命周期函数--监听页面初次渲染完成 */ diff --git a/pages/followUp/index.wxml b/pages/followUp/index.wxml index 8bb6f96..3db102e 100644 --- a/pages/followUp/index.wxml +++ b/pages/followUp/index.wxml @@ -91,7 +91,7 @@ - 总胆红素(µmol/L) + 总胆红素(µmol/L) @@ -100,7 +100,7 @@ - 直接胆红素(µmol/L) + 直接胆红素(µmol/L) @@ -354,7 +354,7 @@ - 25(OH)D3 (ng/ml) + 25(OH)D3(ng/ml) @@ -362,7 +362,7 @@ - 25(OH)D2 (ng/ml) + 25(OH)D2(ng/ml) @@ -370,7 +370,7 @@ - 25(OH)D (ng/ml) + 25(OH)D(ng/ml) @@ -378,7 +378,7 @@ - 维生素A (ng/ml) + 维生素A(ng/ml) @@ -386,7 +386,7 @@ - 维生素K (ng/ml) + 维生素K(ng/ml) @@ -394,7 +394,7 @@ - 维生素E (ng/ml) + 维生素E(ng/ml) @@ -433,7 +433,7 @@ - 肝肋下(mm) + 肝肋下(mm) @@ -441,7 +441,7 @@ - 肝剑突下(mm) + 肝剑突下(mm) @@ -449,7 +449,7 @@ - 脾肋下(mm) + 脾肋下(mm) @@ -457,7 +457,7 @@ - 门静脉主干内径(mm) + 门静脉主干内径(mm) @@ -473,7 +473,7 @@ - 胆囊大小(mm) + 胆囊大小(mm) @@ -481,7 +481,7 @@ - 胆总管(mm) + 胆总管(mm) @@ -489,7 +489,7 @@ - 纤维块大小(mm) + 纤维块大小(mm) @@ -532,6 +532,30 @@ + + + + 弹性成像最小值(kPa) + + + + + + + + 弹性成像最大值(kPa) + + + + + + + + 弹性成像中位数(kPa) + + + +