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:
2026-09-12 01:02:45 +08:00
parent 4f5893f87a
commit 3117146281
26 changed files with 2043 additions and 337 deletions
+65 -61
View File
@@ -310,32 +310,29 @@
sourceType: ["album", "camera"],
count: 1,
success: async (res) => {
if (cms.cmsLst[index] && cms.cmsLst[index].image.src) {
await uniCloudStorageExtCo.deleteFile({ fileList: [cms.cmsLst[index].image.src] })
}
if (res.tempFilePaths.length > 0) {
let filePath = res.tempFilePaths[0]
let { name, extname } = getFileInfo(filePath)
const uploadFileOptionsRes = await uniCloudStorageExtCo.getUploadFileOptions({
cloudPath: `cms/image/${name}_${Math.random().toString(36).substr(2,6)}`
})
await uniCloud.uploadFile({
...uploadFileOptionsRes.uploadFileOptions,
filePath: filePath,
cloudPath: uploadFileOptionsRes.cloudPath,
success: async () => {
const res2 = {
cloudPath: uploadFileOptionsRes.cloudPath,
fileID: uploadFileOptionsRes.fileID,
fileURL: uploadFileOptionsRes.fileURL
}
const selectedMedia = { src: res2.fileID, alt: name }
cms.cmsLst[index].image.src = selectedMedia.src
},
fail: (err) => {
console.log("上传失败", err)
}
if (!res.tempFilePaths || !res.tempFilePaths.length) return
const oldSrc = cms.cmsLst[index]?.image?.src || ''
try {
const filePath = res.tempFilePaths[0]
const { name } = getFileInfo(filePath)
const options = await uniCloudStorageExtCo.getUploadFileOptions({
cloudPath: `cms/image/${name}_${Math.random().toString(36).substr(2, 6)}`
})
const uploaded = await new Promise((resolve, reject) => uniCloud.uploadFile({
...options.uploadFileOptions,
filePath,
cloudPath: options.cloudPath,
success: resolve,
fail: reject
}))
cms.cmsLst[index].image = { ...cms.cmsLst[index].image, src: uploaded.fileID }
uni.setStorageSync('cms', JSON.parse(JSON.stringify(cms)))
if (oldSrc && editingId.value) {
try { await uniCloudStorageExtCo.deleteFile({ fileList: [oldSrc], article_id: editingId.value }) } catch (e) { console.warn('旧图片清理失败', e) }
}
} catch (err) {
console.error('图片替换失败', err)
uni.showToast({ title: '图片上传失败', icon: 'none' })
}
}
})
@@ -343,15 +340,25 @@
async function delItem() {
let index = selectIndex.value
if (index >= 0 && index < cms.cmsLst.length) {
if (cms.cmsLst[index].type === "image" && cms.cmsLst[index].image.src) {
await uniCloudStorageExtCo.deleteFile({ fileList: [cms.cmsLst[index].image.src] })
} else if (cms.cmsLst[index].type === "video" && (cms.cmsLst[index].video.src || cms.cmsLst[index].video.poster)) {
await uniCloudStorageExtCo.deleteFile({
fileList: [cms.cmsLst[index].video.src, cms.cmsLst[index].video.poster]
})
if (index >= 0 && index < cms.cmsLst.length) {
if (cms.cmsLst[index].type === "image" && editingId.value && cms.cmsLst[index].image?.src) {
try {
await uniCloudStorageExtCo.deleteFile({ fileList: [cms.cmsLst[index].image.src], article_id: editingId.value })
} catch (e) {
console.warn('旧图片清理失败', e)
}
} else if (cms.cmsLst[index].type === "video" && editingId.value && (cms.cmsLst[index].video?.src || cms.cmsLst[index].video?.poster)) {
try {
await uniCloudStorageExtCo.deleteFile({
fileList: [cms.cmsLst[index].video.src, cms.cmsLst[index].video.poster],
article_id: editingId.value
})
} catch (e) {
console.warn('旧视频清理失败', e)
}
}
cms.cmsLst.splice(index, 1)
uni.setStorageSync('cms', JSON.parse(JSON.stringify(cms)))
}
delPopup.value.close()
}
@@ -439,6 +446,10 @@
function to(type, index) {
if (type === 'vote') {
toVote(index)
} else if (type === 'title') {
uni.setStorageSync('selectIndex', index)
saveCms()
uni.navigateTo({ url: '/pages2/editCms/smallTitle' })
} else {
toeditText(index)
}
@@ -470,32 +481,20 @@
uni.navigateTo({ url: "/pages2/editCms/smallTitle" })
}
async function dialogClose() {
let storedCms = uni.getStorageSync("cms")
if (storedCms && storedCms.cmsLst) {
for (let i = 0; i < storedCms.cmsLst.length; i++) {
if (storedCms.cmsLst[i].type === "image" && storedCms.cmsLst[i].image && storedCms.cmsLst[i].image.src) {
await uniCloudStorageExtCo.deleteFile({ fileList: [storedCms.cmsLst[i].image.src] })
} else if (storedCms.cmsLst[i].type === "video" && storedCms.cmsLst[i].video) {
let fileList = [storedCms.cmsLst[i].video.src].filter(Boolean)
if (storedCms.cmsLst[i].video.poster) fileList.push(storedCms.cmsLst[i].video.poster)
if (fileList.length) await uniCloudStorageExtCo.deleteFile({ fileList })
}
}
}
await uni.setStorageSync("cms", { cmsLst: [], title: "", title_html: "", title_delta: {} })
// 放弃草稿只清理本地状态;媒体删除由服务端按文章引用关系处理
async function discardDraft() {
uni.setStorageSync("cms", { cmsLst: [], title: "", title_html: "", title_delta: {} })
Object.assign(cms, uni.getStorageSync("cms"))
alertDialog.value.close()
alertDialog.value?.close()
}
async function dialogClose() {
await discardDraft()
}
// 「编辑草稿」:保留本地草稿(onShow 已把内容灌进 cms),直接进入编辑
async function dialogConfirm() {
alertDialog.value.close()
}
// 「放弃草稿」:清空本地草稿并重置编辑器
async function dialogClose() {
await discardDraft()
alertDialog.value?.close()
}
async function addItem(type) {
@@ -555,11 +554,7 @@
uni.chooseVideo({
sourceType: ['album', 'camera'],
success: async (res) => {
if (cms.cmsLst[index] && cms.cmsLst[index].video.src) {
await uniCloudStorageExtCo.deleteFile({
fileList: [cms.cmsLst[index].video.src, cms.cmsLst[index].video.poster]
})
}
const oldVideo = { ...(cms.cmsLst[index]?.video || {}) }
let filePath = res.tempFilePath
let { name, extname } = getFileInfo(filePath)
let duration = res.duration
@@ -589,8 +584,17 @@
text: text,
video: { src: selectedMedia.src, poster: cover, duration: duration, html: html, delta: delta }
}
cms.cmsLst[index] = item
close()
cms.cmsLst[index] = item
uni.setStorageSync('cms', JSON.parse(JSON.stringify(cms)))
if (editingId.value && (oldVideo.src || oldVideo.poster)) {
try {
await uniCloudStorageExtCo.deleteFile({
fileList: [oldVideo.src, oldVideo.poster],
article_id: editingId.value
})
} catch (e) { console.warn('旧视频清理失败', e) }
}
close()
},
fail: (err) => {
console.log("上传失败", err)
@@ -715,7 +719,7 @@
}
.edit_item {
width: 100wv;
width: 100vw;
height: 200rpx;
display: flex;