Files
aiot-platform-ui/apps/web-antd/src/views/mp/draft/modules/cover-select.vue

152 lines
4.0 KiB
Vue
Raw Normal View History

2025-11-05 17:01:42 +08:00
<script lang="ts" setup>
import type { UploadFile } from 'ant-design-vue';
2025-11-19 11:12:09 +08:00
import type { MpDraftApi } from '#/api/mp/draft';
2025-11-05 17:01:42 +08:00
import { computed, inject, reactive, ref } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { useAccessStore } from '@vben/stores';
import { Button, Image, message, Modal, Upload } from 'ant-design-vue';
import { UploadType, useBeforeUpload } from '#/utils/useUpload';
2025-11-21 18:19:42 +08:00
import WxMaterialSelect from '#/views/mp/components/wx-material-select/wx-material-select.vue';
2025-11-05 17:01:42 +08:00
const props = defineProps<{
isFirst: boolean;
2025-11-19 11:12:09 +08:00
modelValue: MpDraftApi.NewsItem;
2025-11-05 17:01:42 +08:00
}>();
const emit = defineEmits<{
2025-11-19 11:12:09 +08:00
(e: 'update:modelValue', v: MpDraftApi.NewsItem): void;
2025-11-05 17:01:42 +08:00
}>();
const UPLOAD_URL = `${import.meta.env.VITE_BASE_URL}/admin-api/mp/material/upload-permanent`; // 上传永久素材的地址
const HEADERS = { Authorization: `Bearer ${useAccessStore().accessToken}` };
2025-11-19 11:12:09 +08:00
const newsItem = computed<MpDraftApi.NewsItem>({
2025-11-05 17:01:42 +08:00
get() {
return props.modelValue;
},
set(val) {
emit('update:modelValue', val);
},
});
2025-11-12 16:56:18 +08:00
const dialogVisible = ref(false);
2025-11-05 17:01:42 +08:00
const accountId = inject<number>('accountId');
const fileList = ref<UploadFile[]>([]);
interface UploadData {
type: UploadType;
accountId: number;
}
const uploadData: UploadData = reactive({
type: UploadType.Image,
accountId: accountId!,
});
2025-11-12 16:56:18 +08:00
function handleOpenDialog() {
dialogVisible.value = true;
}
/** 素材选择完成事件 */
2025-11-05 17:01:42 +08:00
function onMaterialSelected(item: any) {
2025-11-12 16:56:18 +08:00
dialogVisible.value = false;
2025-11-05 17:01:42 +08:00
newsItem.value.thumbMediaId = item.mediaId;
newsItem.value.thumbUrl = item.url;
}
2025-11-12 16:56:18 +08:00
/** 上传前校验 */
2025-11-05 17:01:42 +08:00
const onBeforeUpload = (file: UploadFile) =>
useBeforeUpload(UploadType.Image, 2)(file as any);
2025-11-12 16:56:18 +08:00
/** 上传错误处理 */
2025-11-05 17:01:42 +08:00
function onUploadChange(info: any) {
2025-11-12 16:56:18 +08:00
if (info.file.status === 'error') {
2025-11-05 17:01:42 +08:00
onUploadError(info.file.error || new Error('上传失败'));
}
}
2025-11-12 16:56:18 +08:00
/** 上传成功处理 */
2025-11-05 17:01:42 +08:00
function onUploadSuccess(res: any) {
if (res.code !== 0) {
message.error(`上传出错:${res.msg}`);
return false;
}
// 重置上传文件的表单
fileList.value = [];
// 设置草稿的封面字段
newsItem.value.thumbMediaId = res.data.mediaId;
newsItem.value.thumbUrl = res.data.url;
}
2025-11-12 16:56:18 +08:00
/** 上传失败处理 */
2025-11-05 17:01:42 +08:00
function onUploadError(err: Error) {
message.error(`上传失败: ${err.message}`);
}
</script>
<template>
<div>
<p>封面:</p>
2025-11-12 16:56:18 +08:00
<div class="flex w-full flex-col items-center justify-center text-center">
2025-11-05 17:01:42 +08:00
<Image
v-if="newsItem.thumbUrl"
2025-11-12 16:56:18 +08:00
class="max-h-[300px] w-[300px]"
2025-11-05 17:01:42 +08:00
:src="newsItem.thumbUrl"
:preview="false"
/>
<IconifyIcon
v-else
2025-11-07 19:06:34 +08:00
icon="lucide:plus"
2025-11-12 16:56:18 +08:00
class="border border-[#d9d9d9] text-center text-[28px] leading-[120px] text-[#8c939d]"
:class="isFirst ? 'h-[120px] w-[230px]' : 'h-[120px] w-[120px]'"
2025-11-05 17:01:42 +08:00
/>
2025-11-12 16:56:18 +08:00
<div class="m-[5px]">
2025-11-05 17:01:42 +08:00
<div class="flex items-center justify-center">
<Upload
:action="UPLOAD_URL"
:headers="HEADERS"
:file-list="fileList"
:data="{ ...uploadData }"
:before-upload="onBeforeUpload"
2025-11-12 16:56:18 +08:00
@success="onUploadSuccess"
2025-11-05 17:01:42 +08:00
@change="onUploadChange"
>
<template #default>
<Button size="small" type="primary">本地上传</Button>
</template>
</Upload>
<Button
size="small"
type="primary"
2025-11-12 16:56:18 +08:00
class="ml-[5px]"
@click="handleOpenDialog"
2025-11-05 17:01:42 +08:00
>
素材库选择
</Button>
</div>
2025-11-12 16:56:18 +08:00
<div class="ml-[5px] mt-[5px] text-xs text-[#999]">
2025-11-05 17:01:42 +08:00
支持 bmp/png/jpeg/jpg/gif 格式大小不超过 2M
</div>
</div>
<Modal
2025-11-12 16:56:18 +08:00
v-model:open="dialogVisible"
title="图片选择"
width="65%"
:footer="null"
2025-11-05 17:01:42 +08:00
>
2025-11-21 18:19:42 +08:00
<WxMaterialSelect
2025-11-05 17:01:42 +08:00
type="image"
:account-id="accountId!"
@select-material="onMaterialSelected"
/>
</Modal>
</div>
</div>
</template>