feat: 打通 HBuilderX CLI 构建 + 修复文章闭环静态盲区
构建: - 新增 tools/build.js:junction HBuilderX 工具链,CLI 构建 h5/mp-weixin - vue 指向补丁版 @dcloudio/uni-h5-vue(官方 npm vue 不导出 isInSSRComponentSetup) - 设 HX_APP_ROOT 避免退化成 H5 空壳产物;产物完整性校验 校验工具: - 新增 check-cloud-methods.js:acorn 解析云对象方法,比对 94 处调用点 - 新增 check-android-contract.js:Kotlin 侧云对象契约校验 - audit-project.js 修 downloadFile 误报(注释未剥离);tools/ 排除出扫描 - package.json 声明此前隐式依赖的 acorn 功能: - 补 uni-cms-articles.getPublishedArticles(安卓端依赖但此前不存在) - 修 u-parse <audio> 引用已移除组件导致 H5 构建失败
This commit is contained in:
@@ -14,6 +14,44 @@ const articleDBName = 'uni-cms-articles'
|
||||
// 解锁内容数据库名称
|
||||
const unlockContentDBName = 'uni-cms-unlock-record'
|
||||
|
||||
function cmsLstText(list) {
|
||||
if (!Array.isArray(list)) return ''
|
||||
return list.map(item => {
|
||||
if (!item || typeof item !== 'object') return ''
|
||||
if (item.type === 'text' || item.type === 'title') return item.text || item.html || ''
|
||||
if (item.type === 'video') return item.text || ''
|
||||
if (item.type === 'vote' && item.vote) {
|
||||
return [item.vote.voteTitle, ...(Array.isArray(item.vote.voteLst) ? item.vote.voteLst.map(option => option && option.value) : [])]
|
||||
.filter(Boolean).join(' ')
|
||||
}
|
||||
return ''
|
||||
}).filter(Boolean).join('\n')
|
||||
}
|
||||
|
||||
function cmsLstImages(list) {
|
||||
if (!Array.isArray(list)) return []
|
||||
return list.reduce((images, item) => {
|
||||
if (!item || typeof item !== 'object') return images
|
||||
if (item.type === 'image' && item.image && item.image.src) images.push(item.image.src)
|
||||
if (item.type === 'video' && item.video && item.video.poster) images.push(item.video.poster)
|
||||
return images
|
||||
}, [])
|
||||
}
|
||||
|
||||
function contentText(content, cmsLst) {
|
||||
const deltaText = content && Array.isArray(content.ops)
|
||||
? content.ops.map(op => typeof op.insert === 'string' ? op.insert : '').join(' ')
|
||||
: ''
|
||||
return [deltaText, cmsLstText(cmsLst)].filter(Boolean).join('\n').trim()
|
||||
}
|
||||
|
||||
function contentImages(content, cmsLst) {
|
||||
const deltaImages = content && Array.isArray(content.ops)
|
||||
? content.ops.filter(op => op && op.insert && typeof op.insert.image === 'string').map(op => op.insert.image)
|
||||
: []
|
||||
return [...new Set([...deltaImages, ...cmsLstImages(cmsLst)])]
|
||||
}
|
||||
|
||||
// 安全检测文本内容
|
||||
async function checkContentSec(content, requestId, errorMsg) {
|
||||
// 安全引入内容安全检测模块
|
||||
@@ -123,13 +161,15 @@ module.exports = {
|
||||
if (allowCheckContent && addData.excerpt) {
|
||||
parallel.push(checkContentSec(addData.excerpt, clientInfo.requestId, '摘要存在敏感字,请修改后提交'))
|
||||
}
|
||||
// 检测内容
|
||||
if (allowCheckContent && addData.content) {
|
||||
parallel.push(checkContentSec(JSON.stringify(addData.content), clientInfo.requestId, '内容存在敏感字,请修改后提交'))
|
||||
// 检测内容:兼容标准 Delta 与移动端 cmsLst
|
||||
const text = contentText(addData.content, addData.cmsLst)
|
||||
if (allowCheckContent && text) {
|
||||
parallel.push(checkContentSec(text, clientInfo.requestId, '内容存在敏感字,请修改后提交'))
|
||||
}
|
||||
// 检测封面图
|
||||
if (allowCheckImage && addData.thumbnail) {
|
||||
parallel.push(checkImageSec(addData.thumbnail, clientInfo.requestId, '封面图存在违规,请修改后提交'))
|
||||
// 检测封面、正文图片和视频封面
|
||||
const images = [...(Array.isArray(addData.thumbnail) ? addData.thumbnail : []), ...contentImages(addData.content, addData.cmsLst)]
|
||||
if (allowCheckImage && images.length) {
|
||||
parallel.push(checkImageSec(images, clientInfo.requestId, '图片存在违规,请修改后提交'))
|
||||
}
|
||||
// 等待所有并行检测完成
|
||||
await Promise.all(parallel)
|
||||
@@ -159,13 +199,15 @@ module.exports = {
|
||||
if (allowCheckContent && updateData.excerpt) {
|
||||
parallel.push(checkContentSec(updateData.excerpt, clientInfo.requestId, '摘要存在敏感字,请修改后提交'))
|
||||
}
|
||||
// 检测内容
|
||||
if (allowCheckContent && updateData.content) {
|
||||
parallel.push(checkContentSec(JSON.stringify(updateData.content), clientInfo.requestId, '内容存在敏感字,请修改后提交'))
|
||||
// 检测内容:兼容标准 Delta 与移动端 cmsLst
|
||||
const text = contentText(updateData.content, updateData.cmsLst)
|
||||
if (allowCheckContent && text) {
|
||||
parallel.push(checkContentSec(text, clientInfo.requestId, '内容存在敏感字,请修改后提交'))
|
||||
}
|
||||
// 检测封面图
|
||||
if (allowCheckImage && updateData.thumbnail) {
|
||||
parallel.push(checkImageSec(updateData.thumbnail, clientInfo.requestId, '封面图存在违规,请修改后提交'))
|
||||
// 检测封面、正文图片和视频封面
|
||||
const images = [...(Array.isArray(updateData.thumbnail) ? updateData.thumbnail : []), ...contentImages(updateData.content, updateData.cmsLst)]
|
||||
if (allowCheckImage && images.length) {
|
||||
parallel.push(checkImageSec(images, clientInfo.requestId, '图片存在违规,请修改后提交'))
|
||||
}
|
||||
|
||||
// 等待所有并行检测完成
|
||||
@@ -203,23 +245,33 @@ module.exports = {
|
||||
// 获取文章
|
||||
const article = result.data[0]
|
||||
|
||||
// 如果文章内容不存在,则返回
|
||||
if (!article.content) return
|
||||
// 移动编辑器保留 cmsLst,标准渲染器使用 content;移动文章不依赖 content 才能展示
|
||||
if (article.edit_type === 'mobile') {
|
||||
article.content_images = contentImages(article.content, article.cmsLst)
|
||||
return
|
||||
}
|
||||
|
||||
// 如果文章内容不存在或格式异常,则返回空内容,避免 afterRead 直接抛异常
|
||||
if (!article.content || !Array.isArray(article.content.ops)) {
|
||||
article.content_images = []
|
||||
article.content = { ops: [] }
|
||||
return
|
||||
}
|
||||
|
||||
let needUnlock = false
|
||||
let unlockContent = []
|
||||
|
||||
// 获取文章内容中的图片
|
||||
article.content_images = article.content.ops.reduce((imageBlocks, block) => {
|
||||
if (!block.insert.image) return imageBlocks
|
||||
if (!block || !block.insert || typeof block.insert.image !== 'string') return imageBlocks
|
||||
|
||||
const {attributes} = block
|
||||
const {'data-custom': custom = ""} = attributes || {}
|
||||
const parseCustom = custom.split('&').reduce((obj, item) => {
|
||||
const [key, value] = item.split('=')
|
||||
obj[key] = value
|
||||
if (key) obj[key] = value
|
||||
return obj
|
||||
})
|
||||
}, {})
|
||||
|
||||
return imageBlocks.concat(
|
||||
parseCustom.source ||
|
||||
@@ -228,6 +280,7 @@ module.exports = {
|
||||
}, [])
|
||||
|
||||
for (const op of article.content.ops) {
|
||||
if (!op || !op.insert) continue
|
||||
unlockContent.push(op)
|
||||
// 遍历文章内容,找到解锁内容
|
||||
if (op.insert.unlockContent) {
|
||||
|
||||
Reference in New Issue
Block a user