From 07e0f3083b8f206436ec04b9d2b27ce88c615086 Mon Sep 17 00:00:00 2001
From: francis_fh <13935151924@163.com>
Date: Sat, 24 Jan 2026 16:47:11 +0800
Subject: [PATCH] =?UTF-8?q?AI=E5=9B=9E=E5=A4=8D=E5=86=85=E5=AE=B9=EF=BC=8C?=
=?UTF-8?q?=E5=B2=97=E4=BD=8D=E5=8D=A1=E7=89=87=E7=9A=84=E7=82=B9=E5=87=BB?=
=?UTF-8?q?=E4=BA=8B=E4=BB=B6=E7=BB=91=E5=AE=9A=E9=97=AE=E9=A2=98=E8=A7=A3?=
=?UTF-8?q?=E5=86=B3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/md-render/md-render.vue | 745 ++++++++++++++++++++++++-----
utils/markdownParser.js | 351 ++++++++------
2 files changed, 818 insertions(+), 278 deletions(-)
diff --git a/components/md-render/md-render.vue b/components/md-render/md-render.vue
index 1865468..6a1bd41 100644
--- a/components/md-render/md-render.vue
+++ b/components/md-render/md-render.vue
@@ -2,17 +2,44 @@
-
+
+
+
+
+
+
+
+
+
+ {{ card.jobTitle }}
+ {{ card.salary }}
+
+ {{ card.location }}·{{ card.companyName }}
+
+
+ {{ card.education }}
+ {{ card.experience }}
+
+ 查看详情
+
+
+
+
-
+
diff --git a/utils/markdownParser.js b/utils/markdownParser.js
index 451c4a1..c877742 100644
--- a/utils/markdownParser.js
+++ b/utils/markdownParser.js
@@ -1,157 +1,194 @@
-import MarkdownIt from '@/lib/markdown-it.min.js';
-import hljs from "@/lib/highlight/highlight-uni.min.js";
-import parseHtml from '@/lib/html-parser.js';
-// import DOMPurify from '@/lib/dompurify@3.2.4es.js';
-
-export let codeDataList = []
-export let jobMoreMap = new Map()
-
-const md = new MarkdownIt({
- html: true, // 允许 HTML 标签
- linkify: true, // 自动解析 URL
- typographer: true, // 美化标点符号
- tables: true,
- breaks: true, // 让 \n 自动换行
- langPrefix: 'language-', // 代码高亮前缀
- // 如果结果以
${result.jobTitle}${result.salary}
${result.location}·${result.companyName}
${result.education}
${result.experience}
`
- if (result.data) {
- jobMoreMap.set(jobId, result.data)
- domContext += `查看更多岗位`
- }
- return domContext
- }
- }
- // 代码块
- let preCode = ""
- try {
- preCode = hljs.highlightAuto(str).value
- } catch (err) {
- preCode = md.utils.escapeHtml(str);
- }
- // 以换行进行分割 , 按行拆分代码
- const lines = preCode.split(/\n/).slice(0, -1);
- const html = lines
- .map((line, index) =>
- line ?
- `
${line}` :
- ''
- )
- .join('');
-
- // 代码复制功能
- const cacheIndex = codeDataList.length;
- codeDataList.push(str);
- return `
-
- `;
- }
-})
-
-function extractFirstJson(text) {
- let stack = [];
- let startIndex = -1;
- let endIndex = -1;
-
- for (let i = 0; i < text.length; i++) {
- const char = text[i];
-
- if (char === '{') {
- if (stack.length === 0) startIndex = i; // 记录第一个 '{' 的位置
- stack.push(char);
- } else if (char === '}') {
- stack.pop();
- if (stack.length === 0) {
- endIndex = i; // 找到配对的 '}'
- break;
- }
- }
- }
-
- if (startIndex !== -1 && endIndex !== -1) {
- const jsonString = text.slice(startIndex, endIndex + 1);
- try {
- const jsonObject = JSON.parse(jsonString);
- return jsonObject;
- } catch (e) {
- return null; // 如果不是有效的 JSON
- }
- }
-
- return null; // 如果没有找到有效的 JSON 对象
-}
-
-
-function safeExtractJson(text) {
- try {
- const jsonObject = extractFirstJson(text);
- return jsonObject
- } catch (e) {
- console.error('JSON 解析失败:', e);
- }
- return null;
-}
-
-export function clearJobMoreMap() { // 切换对话清空
- jobMoreMap.clear()
-}
-
-export function parseMarkdown(content) {
- if (!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 || '')
-
- // 在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
+import MarkdownIt from '@/lib/markdown-it.min.js';
+import hljs from "@/lib/highlight/highlight-uni.min.js";
+import parseHtml from '@/lib/html-parser.js';
+// import DOMPurify from '@/lib/dompurify@3.2.4es.js';
+
+export let codeDataList = []
+export let jobMoreMap = new Map()
+export let jobCardsList = []
+
+const md = new MarkdownIt({
+ html: true, // 允许 HTML 标签
+ linkify: true, // 自动解析 URL
+ typographer: true, // 美化标点符号
+ tables: true,
+ breaks: true, // 让 \n 自动换行
+ langPrefix: 'language-', // 代码高亮前缀
+ // 如果结果以 ${result.jobTitle}${result.salary}
${result.location}·${result.companyName}
${result.education}
${result.experience}
`
+ if (result.data) {
+ jobMoreMap.set(jobId, result.data)
+ domContext += `查看更多岗位`
+ }
+ return domContext
+ }
+ }
+ // 代码块
+ let preCode = ""
+ try {
+ preCode = hljs.highlightAuto(str).value
+ } catch (err) {
+ preCode = md.utils.escapeHtml(str);
+ }
+ // 以换行进行分割 , 按行拆分代码
+ const lines = preCode.split(/\n/).slice(0, -1);
+ const html = lines
+ .map((line, index) =>
+ line ?
+ `
${line}` :
+ ''
+ )
+ .join('');
+
+ // 代码复制功能
+ const cacheIndex = codeDataList.length;
+ codeDataList.push(str);
+ return `
+
+ `;
+ }
+})
+
+function extractFirstJson(text) {
+ let stack = [];
+ let startIndex = -1;
+ let endIndex = -1;
+
+ for (let i = 0; i < text.length; i++) {
+ const char = text[i];
+
+ if (char === '{') {
+ if (stack.length === 0) startIndex = i; // 记录第一个 '{' 的位置
+ stack.push(char);
+ } else if (char === '}') {
+ stack.pop();
+ if (stack.length === 0) {
+ endIndex = i; // 找到配对的 '}'
+ break;
+ }
+ }
+ }
+
+ if (startIndex !== -1 && endIndex !== -1) {
+ const jsonString = text.slice(startIndex, endIndex + 1);
+ try {
+ const jsonObject = JSON.parse(jsonString);
+ return jsonObject;
+ } catch (e) {
+ return null; // 如果不是有效的 JSON
+ }
+ }
+
+ return null; // 如果没有找到有效的 JSON 对象
+}
+
+
+function safeExtractJson(text) {
+ try {
+ const jsonObject = extractFirstJson(text);
+ return jsonObject
+ } catch (e) {
+ console.error('JSON 解析失败:', e);
+ }
+ return null;
+}
+
+export function clearJobMoreMap() { // 切换对话清空
+ jobMoreMap.clear()
+}
+
+export function parseMarkdown(content) {
+ if (!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 = []
+ jobCardsList = [] // 清空岗位卡片列表,避免重复
+ const unsafeHtml = md.render(content || '')
+
+ // 在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
+ }
+}