diff --git a/miniprogram/pages/link-preview/link-preview.js b/miniprogram/pages/link-preview/link-preview.js
index 72cda7b5..ea7a82e2 100644
--- a/miniprogram/pages/link-preview/link-preview.js
+++ b/miniprogram/pages/link-preview/link-preview.js
@@ -1,5 +1,35 @@
const app = getApp()
+function safeDecode(value) {
+ try {
+ return decodeURIComponent(value || '')
+ } catch (_) {
+ return String(value || '')
+ }
+}
+
+function normalizeHttpUrl(raw) {
+ let s = String(raw || '').trim()
+ if (!s) return ''
+ if (/^\/\//.test(s)) return 'https:' + s
+ if (!/^https?:\/\//i.test(s)) s = 'https://' + s.replace(/^\/+/, '')
+ return s
+}
+
+// 为外链补充移动端提示参数:目标站支持时按手机网页输出
+function appendMobileHints(rawUrl) {
+ const url = normalizeHttpUrl(rawUrl)
+ if (!url) return ''
+ const hasQuery = url.indexOf('?') >= 0
+ const hasFrom = /(?:\?|&)from=/i.test(url)
+ const hasView = /(?:\?|&)view=/i.test(url)
+ const extras = []
+ if (!hasFrom) extras.push('from=miniprogram')
+ if (!hasView) extras.push('view=mobile')
+ if (!extras.length) return url
+ return url + (hasQuery ? '&' : '?') + extras.join('&')
+}
+
Page({
data: {
url: '',
@@ -10,8 +40,9 @@ Page({
},
onLoad(options) {
- const url = decodeURIComponent(options.url || '')
- const title = options.title ? decodeURIComponent(options.title) : '链接预览'
+ const rawUrl = safeDecode(options.url || '')
+ const url = appendMobileHints(rawUrl)
+ const title = options.title ? safeDecode(options.title) : '链接预览'
this.setData({
url,
title,
diff --git a/miniprogram/pages/read/read.js b/miniprogram/pages/read/read.js
index a6bc0e42..f65ca150 100644
--- a/miniprogram/pages/read/read.js
+++ b/miniprogram/pages/read/read.js
@@ -1257,6 +1257,22 @@ Page({
wx.showToast({ title: '暂无跳转地址', icon: 'none' })
},
+ // 点击正文普通超链接:用小程序 web-view 打开(微信内置浏览器)
+ onArticleLinkTap(e) {
+ const url = String((e.currentTarget.dataset.url || '')).trim()
+ if (!url) {
+ wx.showToast({ title: '链接地址为空', icon: 'none' })
+ return
+ }
+ const text = String((e.currentTarget.dataset.text || '链接预览')).trim() || '链接预览'
+ wx.navigateTo({
+ url: `/pages/link-preview/link-preview?url=${encodeURIComponent(url)}&title=${encodeURIComponent(text)}`,
+ fail: (err) => {
+ wx.showToast({ title: err.errMsg || '打开失败', icon: 'none' })
+ },
+ })
+ },
+
// 点击正文图片 → 全屏预览
onImageTap(e) {
const src = e.currentTarget.dataset.src
diff --git a/miniprogram/pages/read/read.wxml b/miniprogram/pages/read/read.wxml
index 9626a6df..c279d18b 100644
--- a/miniprogram/pages/read/read.wxml
+++ b/miniprogram/pages/read/read.wxml
@@ -82,7 +82,7 @@
- {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}}
+ {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}}{{seg.text}}
@@ -158,7 +158,7 @@
{{item[0].number}}.•{{item[0].text}}
- {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}}
+ {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}}{{seg.text}}
@@ -251,7 +251,7 @@
{{item[0].number}}.•{{item[0].text}}
- {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}}
+ {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}}{{seg.text}}
diff --git a/miniprogram/pages/read/read.wxss b/miniprogram/pages/read/read.wxss
index 4ee7f9c3..435a5d3e 100644
--- a/miniprogram/pages/read/read.wxss
+++ b/miniprogram/pages/read/read.wxss
@@ -282,6 +282,14 @@
padding: 0 4rpx;
}
+/* 正文内普通超链接(管理端插入 a 标签) */
+.paragraph .article-link {
+ color: #67e8f9;
+ text-decoration: underline;
+ text-underline-offset: 4rpx;
+ font-weight: 500;
+}
+
/* 正文内图片 */
.content-image {
width: 100%;
diff --git a/miniprogram/pages/super-article-detail/super-article-detail.js b/miniprogram/pages/super-article-detail/super-article-detail.js
index 57d491e4..a5b0c7ad 100644
--- a/miniprogram/pages/super-article-detail/super-article-detail.js
+++ b/miniprogram/pages/super-article-detail/super-article-detail.js
@@ -21,6 +21,22 @@ function buildH5ReadUrl(articleId) {
function renderArticleHtml(text) {
const src = String(text || '')
+ const isHtml = /<[a-z][\s\S]*>/i.test(src)
+
+ // 富文本:保留原 HTML,仅统一补充 a 标签样式(可点击 + 高亮)
+ if (isHtml) {
+ return src.replace(/]*)>/gi, (full, attrs) => {
+ if (!/href\s*=/.test(attrs)) return full
+ const hasStyle = /\sstyle\s*=/.test(attrs)
+ const styleText = 'color:#22d3ee;text-decoration:underline;word-break:break-all;'
+ if (hasStyle) {
+ return ` ` style=${q}${s};${styleText}${q}`)}>`
+ }
+ return ``
+ })
+ }
+
+ // 纯文本:高亮 @/# 并自动识别 URL
const escaped = src
.replace(/&/g, '&')
.replace(/$2')
const withLinks = withTags.replace(
/(https?:\/\/[^\s<]+)/g,
- '$1'
+ '$1'
)
return withLinks.replace(/\n/g, '
')
}
diff --git a/miniprogram/utils/contentParser.js b/miniprogram/utils/contentParser.js
index b74bb6cd..db1339bc 100644
--- a/miniprogram/utils/contentParser.js
+++ b/miniprogram/utils/contentParser.js
@@ -6,6 +6,7 @@
* { type: 'text', text }
* { type: 'mention', userId, nickname } — @某人,点击加好友(提交存客宝见 utils/soulBridge.submitCkbLead)
* { type: 'linkTag', label, url, ... } — #链接标签,点击跳转(阅读页 onLinkTagTap:外链→link-preview、小程序→navigateToMiniProgram)
+ * { type: 'link', text, url } — 普通超链接,点击外链预览(阅读页 onArticleLinkTap)
* { type: 'image', src, alt } — 图片
* { type: 'video', src } — 内嵌视频(管理端 rich-video-wrap /