构建: - 新增 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 构建失败
405 lines
9.8 KiB
Vue
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>
|