Files
t/pages2/editCms/editSetting.vue
T
root 3117146281 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 构建失败
2026-09-12 01:02:45 +08:00

405 lines
9.8 KiB
Vue

<template>
<view>
<uni-nav-bar
title="文章设置"
leftText="取消"
left-icon="left"
right-text="预览"
backgroundColor="#ffffff"
color="#000000"
@clickRight="toPreview()"
@clickLeft="back()">
</uni-nav-bar>
<uni-forms-item label="兵种">
<u-picker
:show="p_show"
:columns="pItems"
keyName="text"
@close="p_close"
@cancel="p_close"
@confirm="p_select"
closeOnClickOverlay="true">
</u-picker>
<view class="" @click="p_open()" style="margin-right: 50rpx;">
<u-input
v-model="pItems[0][p_index].text"
placeholder="请选择"
disabled
suffixIcon="arrow-right"/>
</view>
</uni-forms-item>
<uni-forms-item label="文章分类">
<u-picker
:show="tag_show"
:columns="tags"
keyName="text"
@close="tag_close()"
@cancel="tag_close()"
@confirm="tag_select"
closeOnClickOverlay="true">
</u-picker>
<view class="" @click="tag_open()" style="margin-right: 50rpx;">
<u-input
v-model="tags[0][tag_index].text"
placeholder="请选择"
disabled
suffixIcon="arrow-right"/>
</view>
</uni-forms-item>
<uni-section title="文章封面" type="line">
<view class="uni-px-5 uni-pb-5">
<uni-data-checkbox
@change="thumbnailChange"
v-model="thumbMode"
:localdata="thumbnailType">
</uni-data-checkbox>
</view>
<view class="" v-if="thumbMode === 1">
<view class="container" @click="updateImage(0)">
<view v-if="!thumbnail[0]">
<view class="cross-line horizontal"></view>
<view class="cross-line vertical"></view>
</view>
<cloud-image v-else width="200rpx" height="200rpx" mode="scaleToFill" :src="thumbnail[0]">
</cloud-image>
</view>
</view>
<view class="parent-container" v-if="thumbMode === 3">
<view class="container"
@click="updateImage(index)"
v-for="(item, index) in thumbnail" :key="index">
<view v-if="!thumbnail[index] || !thumbnail[index]">
<view class="cross-line horizontal"></view>
<view class="cross-line vertical"></view>
</view>
<cloud-image v-else width="200rpx" height="200rpx" mode="scaleToFill" :src="thumbnail[index]">
</cloud-image>
</view>
</view>
</uni-section>
</view>
</template>
<script>
import { ref, reactive, onMounted } from 'vue'
import { onHide, onUnload } from '@dcloudio/uni-app'
import uPicker from "@/uni_modules/uview-ui/components/u-picker/u-picker.vue"
import uInput from "@/uni_modules/uview-ui/components/u-input/u-input.vue"
import cloudImage from "@/components/cloud-image.vue"
export default {
components: {
uPicker,
uInput,
cloudImage
},
setup() {
const saveInterval = ref(null)
const tag_index = ref(0)
const category_id = ref("")
const tag_show = ref(false)
const tags = ref([])
const thumbMode = ref(0)
const p_show = ref(false)
const p_type = ref("1")
const p_index = ref(0)
const thumbnailType = ref([
{ text: "无封面", value: 0 },
{ text: "单图模式", value: 1 },
{ text: "三图模式", value: 3 },
])
const thumbnail = reactive(["", "", ""])
const pItems = ref([
[
{ text: "空军", value: "1" },
{ text: "海军", value: "2" },
{ text: "陆军", value: "3" },
{ text: "地勤保障", value: "4" },
{ text: "武警", value: "5" },
]
])
onHide(() => {
clearInterval(saveInterval.value)
})
onUnload(() => {
clearInterval(saveInterval.value)
clearTimeout(saveInterval.value)
})
onMounted(async () => {
saveInterval.value = setInterval(save, 10000)
let cms = uni.getStorageSync("cms")
let res = await uniCloud.importObject("uni-cms-categories").getTags()
if (res.code === "200") {
tags.value = [res.tags]
}
if (cms.category_id && tags.value[0]) {
category_id.value = cms.category_id
for (let i = 0; i < tags.value[0].length; i++) {
if (category_id.value === tags.value[0][i].value) {
tag_index.value = i
break
}
}
} else if (tags.value[0] && tags.value[0].length) {
category_id.value = tags.value[0][0].value
tag_index.value = 0
}
if (cms.thumbnail) {
thumbMode.value = cms.thumbnail.length
if (thumbMode.value === 0) {
thumbnail[0] = ""
thumbnail[1] = ""
thumbnail[2] = ""
thumbMode.value = 0
} else if (thumbMode.value === 1) {
thumbnail[0] = typeof cms.thumbnail[0] === 'string' ? cms.thumbnail[0] : (cms.thumbnail[0]?.src || '')
thumbnail[1] = ""
thumbnail[2] = ""
thumbMode.value = 1
} else if (thumbMode.value === 3) {
thumbnail[0] = typeof cms.thumbnail[0] === 'string' ? cms.thumbnail[0] : (cms.thumbnail[0]?.src || '')
thumbnail[1] = typeof cms.thumbnail[1] === 'string' ? cms.thumbnail[1] : (cms.thumbnail[1]?.src || '')
thumbnail[2] = typeof cms.thumbnail[2] === 'string' ? cms.thumbnail[2] : (cms.thumbnail[2]?.src || '')
thumbMode.value = 3
}
}
if (cms.p_type) {
p_type.value = cms.p_type
for (let i = 0; i < pItems.value[0].length; i++) {
if (p_type.value === pItems.value[0][i].value) {
p_index.value = i
break
}
}
}
})
function getFileInfo(path) {
const parts = path.split('/').pop()
const [filename, ...extParts] = parts.split('.')
const ext = extParts.length ? extParts.pop() : ''
return { name: filename, extname: ext }
}
function formatBytes(bytes) {
if (bytes === 0) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
if (i >= sizes.length) return '> 1 TB'
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
function thumbnailChange(e) {
console.log(e)
}
async function updateImage(index) {
uni.chooseImage({
type: "image",
count: 1,
success: async (res) => {
if (res.tempFilePaths.length > 0) {
let filePath = res.tempFilePaths[0]
let { name, extname } = getFileInfo(filePath)
const uniCloudStorageExtCo = uniCloud.importObject("ext-storage-co")
const uploadFileOptionsRes = await uniCloudStorageExtCo.getUploadFileOptions({
cloudPath: `thumbnail/${name}_${Math.random().toString(36).substr(2,6)}`
})
await uniCloud.uploadFile({
...uploadFileOptionsRes.uploadFileOptions,
filePath: filePath,
cloudPath: uploadFileOptionsRes.cloudPath,
success: () => {
const res2 = {
cloudPath: uploadFileOptionsRes.cloudPath,
fileID: uploadFileOptionsRes.fileID,
fileURL: uploadFileOptionsRes.fileURL
}
thumbnail[index] = res2.fileID
},
fail: (err) => {
console.log("上传失败", err)
}
})
}
}
})
}
function tag_close() {
tag_show.value = false
}
function tag_open() {
tag_show.value = true
}
function tag_select(e) {
let index = e.indexs[0]
let { text, value } = e.value[0]
tag_index.value = index
category_id.value = value
tag_close()
}
function p_select(e) {
let index = e.indexs[0]
let { text, value } = e.value[0]
p_index.value = index
p_type.value = value
p_close()
}
function p_close() {
p_show.value = false
}
function p_open() {
p_show.value = true
}
function save() {
let cms = uni.getStorageSync("cms")
cms.category_id = category_id.value
cms.p_type = p_type.value
if (thumbMode.value === 0) {
cms.thumbnail = []
} else if (thumbMode.value === 1) {
cms.thumbnail = [thumbnail[0]]
} else if (thumbMode.value === 3) {
let thumb = []
for (let i = 0; i < 3; i++) {
if (thumbnail[i]) {
thumb.push(thumbnail[i])
}
}
cms.thumbnail = thumb.filter(Boolean)
}
uni.setStorageSync("cms", cms)
}
function back() {
save()
try {
uni.navigateBack({ delta: 1 })
} catch (e) {
uni.switchTab({ url: "/uni_modules/uni-cms-article/pages/list/list" })
}
}
function toPreview() {
const cms = uni.getStorageSync("cms") || { cmsLst: [] }
cms.category_id = category_id.value
cms.p_type = p_type.value
if (!cms.p_type) {
uni.showToast({ title: '兵种不能为空', icon: 'none' })
return
}
if (!cms.category_id) {
uni.showToast({ title: '分类不能为空', icon: 'none' })
return
}
if (thumbMode.value === 0) {
cms.thumbnail = []
} else if (thumbMode.value === 1) {
cms.thumbnail = thumbnail[0] ? [thumbnail[0]] : []
} else {
cms.thumbnail = thumbnail.slice(0, 3).filter(Boolean)
}
if (thumbMode.value > 0 && cms.thumbnail.length !== thumbMode.value) {
uni.showToast({ title: '封面图不能为空', icon: 'none' })
return
}
uni.setStorageSync("cms", cms)
uni.navigateTo({ url: "/pages2/editCms/preview" })
}
return {
saveInterval,
tag_index,
category_id,
tag_show,
tags,
thumbMode,
thumbnailType,
thumbnail,
p_show,
p_type,
p_index,
pItems,
getFileInfo,
formatBytes,
thumbnailChange,
updateImage,
tag_close,
tag_open,
tag_select,
p_select,
p_close,
p_open,
save,
back,
toPreview
}
}
}
</script>
<style>
.parent-container {
display: flex;
gap: 20rpx;
justify-content: flex-start;
}
.container {
position: relative;
flex-shrink: 0;
width: 200rpx;
height: 200rpx;
border: 1rpx solid #ccc;
}
.cross-line {
position: absolute;
background-color: #ccc;
left: 50%;
top: 50%;
}
.horizontal {
width: 30rpx;
height: 5rpx;
border-radius: 2rpx;
transform: translate(-50%, -50%);
}
.vertical {
height: 30rpx;
width: 5rpx;
border-radius: 2rpx;
transform: translate(-50%, -50%);
}
</style>