feat:更新上传图片和视频组件

This commit is contained in:
2026-02-04 22:24:39 +08:00
parent e5e1e5e2b3
commit 45342fb55c
17 changed files with 328 additions and 107 deletions

1
.env
View File

@@ -1 +0,0 @@
VITE_API_HOST=43.225.157.27

1
.env.development Normal file
View File

@@ -0,0 +1 @@
VITE_API_ALIST_PATH=/local/test

1
.env.production Normal file
View File

@@ -0,0 +1 @@
VITE_API_ALIST_PATH=/local

View File

@@ -12,8 +12,8 @@
<el-card class="record-card"> <el-card class="record-card">
<span class="record-content">完成人{{ item.person }}</span> <span class="record-content">完成人{{ item.person }}</span>
<el-image v-if="item.imageUrl" <el-image v-if="item.imageUrl"
:src="AListPath + item.imageUrl" :src="AListUrl + item.imageUrl"
:preview-src-list="[AListPath + item.imageUrl]" :preview-src-list="[AListUrl + item.imageUrl]"
fit="contain" alt="暂无图片" class="record-image"/> fit="contain" alt="暂无图片" class="record-image"/>
</el-card> </el-card>
</el-timeline-item> </el-timeline-item>
@@ -25,7 +25,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useFoodStore } from '@/store/food.ts' import { useFoodStore } from '@/store/food.ts'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
import { SvgIcon } from 'vue3-common' import { SvgIcon } from 'vue3-common'
const foodStore = useFoodStore() const foodStore = useFoodStore()

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="life-record-card card-item"> <div class="life-record-card card-item">
<el-image v-if="props.foodItem?.recordList.length > 0" <el-image v-if="props.foodItem?.recordList.length > 0"
:src="AListPath + props.foodItem?.recordList[0].imageUrl" :src="AListUrl + props.foodItem?.recordList[0].imageUrl"
:preview-src-list="previewImageList" :preview-src-list="previewImageList"
:initial-index="0" :initial-index="0"
show-progress show-progress
@@ -68,7 +68,7 @@ import { IFoodRecipe } from '@/types/food.ts'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { formatDate } from 'vue3-common/utils/dateUtil' import { formatDate } from 'vue3-common/utils/dateUtil'
import { commonElMessageBox } from 'vue3-common/utils/elUtil' import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
const router = useRouter() const router = useRouter()
const foodStore = useFoodStore() const foodStore = useFoodStore()
@@ -90,7 +90,7 @@ onMounted(() => {
}) })
const previewImageList = computed(() => { const previewImageList = computed(() => {
return props.foodItem?.recordList.map((item) => `${AListPath}${item.imageUrl}`) return props.foodItem?.recordList.map((item) => `${AListUrl}${item.imageUrl}`)
}) })
const editFoodRecipeClick = async () => { const editFoodRecipeClick = async () => {

View File

@@ -37,8 +37,8 @@
<!-- 单媒体内容图片优先于视频 --> <!-- 单媒体内容图片优先于视频 -->
<el-image <el-image
v-if="props.item?.imageUrl" v-if="props.item?.imageUrl"
:src="AListPath + props.item?.imageUrl" :src="AListUrl + props.item?.imageUrl"
:preview-src-list="[AListPath + props.item?.imageUrl]" :preview-src-list="[AListUrl + props.item?.imageUrl]"
fit="contain" fit="contain"
class="media-content"/> class="media-content"/>
@@ -46,7 +46,7 @@
v-if="props.item?.videoUrl" v-if="props.item?.videoUrl"
controls controls
class="media-content"> class="media-content">
<source :src="AListPath + props.item?.videoUrl" type="video/mp4"> <source :src="AListUrl + props.item?.videoUrl" type="video/mp4">
</video> </video>
<!-- 展开/收起按钮 --> <!-- 展开/收起按钮 -->
@@ -76,7 +76,7 @@ import { deepCopyObject } from 'vue3-common/utils/dataUtil'
import { useJournalStore } from '@/store/journal.ts' import { useJournalStore } from '@/store/journal.ts'
import { useAppStore } from '@/store/app.ts' import { useAppStore } from '@/store/app.ts'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
const props = defineProps({ const props = defineProps({
item: { item: {

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="life-record-card card-item"> <div class="life-record-card card-item">
<el-image :src="AListPath + props.productItem?.imageUrl" <el-image :src="AListUrl + props.productItem?.imageUrl"
:preview-src-list="[AListPath + props.productItem?.imageUrl]" :preview-src-list="[AListUrl + props.productItem?.imageUrl]"
fit="contain" alt="暂无成果"> fit="contain" alt="暂无成果">
<template #error> <template #error>
<div class="image-slot"> <div class="image-slot">
@@ -42,11 +42,6 @@
<i class="fa-solid fa-chart-line" style="color: #FFA500"></i> <i class="fa-solid fa-chart-line" style="color: #FFA500"></i>
{{ props.productItem.averagePrice }}/ {{ props.productItem.averagePrice }}/
</div> </div>
<div class="info-item">
<i class="fa-solid fa-location-dot"></i>
{{ props.productItem.channel }}
</div>
</div> </div>
<div class="info-list"> <div class="info-list">
<div class="info-item"> <div class="info-item">
@@ -70,7 +65,7 @@ import { defineProps, onMounted, PropType } from 'vue'
import { commonElMessageBox } from 'vue3-common/utils/elUtil' import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { IProduct } from '@/types/product.ts' import { IProduct } from '@/types/product.ts'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
const productStore = useProductStore() const productStore = useProductStore()
const router = useRouter() const router = useRouter()

View File

@@ -12,13 +12,13 @@
<el-card class="record-card"> <el-card class="record-card">
<span class="record-content">旅行人{{ item.persons.join('-') }}</span> <span class="record-content">旅行人{{ item.persons.join('-') }}</span>
<el-image v-for="(image, index) in item.imageList" :key="index" <el-image v-for="(image, index) in item.imageList" :key="index"
:src="AListPath + image" :src="AListUrl + image"
:preview-src-list="[AListPath + image]" :preview-src-list="[AListUrl + image]"
fit="contain" alt="暂无图片" class="record-image"/> fit="contain" alt="暂无图片" class="record-image"/>
<video v-for="(video, index) in item.videoList" <video v-for="(video, index) in item.videoList"
:key="index" controls style="width: 60%;min-height: 200px;"> :key="index" controls style="width: 60%;min-height: 200px;">
<source :src="AListPath + video" type="video/mp4"> <source :src="AListUrl + video" type="video/mp4">
您的浏览器不支持 HTML5 视频 您的浏览器不支持 HTML5 视频
</video> </video>
@@ -41,7 +41,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SvgIcon } from 'vue3-common' import { SvgIcon } from 'vue3-common'
import { useTravelStore } from '@/store/travel.ts' import { useTravelStore } from '@/store/travel.ts'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
const travelStore = useTravelStore() const travelStore = useTravelStore()
</script> </script>

View File

@@ -3,7 +3,7 @@
<el-carousel v-if="props.travelItem?.recordList.length > 0" <el-carousel v-if="props.travelItem?.recordList.length > 0"
arrow="always" @change="changeTravelEvent"> arrow="always" @change="changeTravelEvent">
<el-carousel-item v-for="(item, index) in props.travelItem?.recordList" :key="index"> <el-carousel-item v-for="(item, index) in props.travelItem?.recordList" :key="index">
<el-image :src="AListPath + item.imageList[0]" <el-image :src="AListUrl + item.imageList[0]"
fit="contain" alt="暂无图片"> fit="contain" alt="暂无图片">
<template #error> <template #error>
<div class="image-slot"> <div class="image-slot">
@@ -70,7 +70,7 @@ import { useRouter } from 'vue-router'
import { formatDate } from 'vue3-common/utils/dateUtil' import { formatDate } from 'vue3-common/utils/dateUtil'
import { ITravelSpot } from '@/types/travel.ts' import { ITravelSpot } from '@/types/travel.ts'
import { commonElMessageBox } from 'vue3-common/utils/elUtil' import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
import { parsePerson } from '@/utils/home/travelUtil.ts' import { parsePerson } from '@/utils/home/travelUtil.ts'
const router = useRouter() const router = useRouter()

View File

@@ -1,8 +1,9 @@
import { ElLoading, ElMessage, UploadRawFile, UploadRequestOptions } from 'element-plus' import { ElLoading, ElMessage } from 'element-plus'
import { getFileExtension, getFileHashName, validateImage } from '@/utils/home/file.ts' import type { UploadRawFile, UploadRequestOptions } from 'element-plus'
import { getFileExtension, getFileHashName, validateImage, compressOptions, validateVideo } from '@/utils/file.ts'
import { compressImage } from 'vue3-common/utils/fileUtil' import { compressImage } from 'vue3-common/utils/fileUtil'
import { compressOptions } from '@/utils'
import { uploadAListFileApi } from '@/apis/file.ts' import { uploadAListFileApi } from '@/apis/file.ts'
import { AListPath } from '@/utils'
export const beforeUploadImage = (rawFile: UploadRawFile): boolean => { export const beforeUploadImage = (rawFile: UploadRawFile): boolean => {
const maxFileMax = 1024 * 1024 * 10 const maxFileMax = 1024 * 1024 * 10
@@ -23,7 +24,27 @@ export const beforeUploadImage = (rawFile: UploadRawFile): boolean => {
return true return true
} }
export const httpRequestFile = async (basePath: string, options: UploadRequestOptions) => { export const beforeUploadVideo = (rawFile: UploadRawFile): boolean => {
const maxFileMax = 1024 * 1024 * 200
const fileType = rawFile.type
const fileName = rawFile.name
const fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
if (!validateVideo(fileType, fileExtension)) {
ElMessage.error('请上传视频')
return false
}
if (rawFile.size > maxFileMax) {
ElMessage.error('请上传200M以内的文件!')
return false
}
return true
}
export const httpRequestFile = async (basePath: string,
options: UploadRequestOptions, isCompress = true) => {
const loading = ElLoading.service({ const loading = ElLoading.service({
lock: true, lock: true,
text: '文件上传中 请等待', text: '文件上传中 请等待',
@@ -31,11 +52,15 @@ export const httpRequestFile = async (basePath: string, options: UploadRequestOp
}) })
try { try {
const filePath = `/local/${basePath}/${getFileHashName(options.file.name)}.${getFileExtension(options.file.name)}` const filePath = `${AListPath}/${basePath}/${getFileHashName(options.file)}.${getFileExtension(options.file.name)}`
const compressFile = await compressImage(options.file, compressOptions)
const data = new FormData() const data = new FormData()
data.append('file', compressFile)
if (isCompress) {
const compressFile = await compressImage(options.file, compressOptions)
data.append('file', compressFile)
} else {
data.append('file', options.file)
}
data.append('filePath', filePath) data.append('filePath', filePath)
const result = await uploadAListFileApi(data) const result = await uploadAListFileApi(data)

View File

@@ -1,15 +1,17 @@
import { hashSHA256 } from 'vue3-common/utils/cryptoUtil' import { hashSHA256 } from 'vue3-common/utils/cryptoUtil'
export const getFileHashName = (name: string) => { export const getFileHashName = (file: File) => {
return hashSHA256(name) return hashSHA256(`${file.name}_${file.lastModified}`)
} }
export const getFileExtension = (name: string) => { export const getFileExtension = (name: string) => {
return name.substring(name.lastIndexOf('.') + 1).toLowerCase() return name.substring(name.lastIndexOf('.') + 1).toLowerCase()
} }
export const getFilePath = (basePath: string, name: string) => { export const compressOptions = {
return `/local/${basePath}/${getFileHashName(name)}.${getFileExtension(name)}` quality: 0.7,
maxHeight: 800,
maxWidth: 600
} }
export const validateExcel = (fileType: string, fileExtension: string): boolean => { export const validateExcel = (fileType: string, fileExtension: string): boolean => {
@@ -29,6 +31,8 @@ export const validateExcel = (fileType: string, fileExtension: string): boolean
export const acceptImageTypes = '.jpg,.jpeg,.png,.gif,.webp,.bmp,.JPG,.JPEG,.PNG,.GIF,.WEBP,.BMP' export const acceptImageTypes = '.jpg,.jpeg,.png,.gif,.webp,.bmp,.JPG,.JPEG,.PNG,.GIF,.WEBP,.BMP'
export const acceptVideoTypes = '.mp4,.mov,.avi,.wmv,.flv,.webm,.mpeg,.mpg,.m4v,.3gp,.3g2,.mkv,.ts,.mts,.m2ts'
export const validateImage = (fileType: string, fileExtension: string): boolean => { export const validateImage = (fileType: string, fileExtension: string): boolean => {
// 常见的图片 MIME 类型 // 常见的图片 MIME 类型
const imageMimeTypes = [ const imageMimeTypes = [

View File

@@ -0,0 +1,17 @@
export const journalCategoryTypeList = ['生活', '工作', '其他']
export const journalWeatherTypeList = [{
value: 'sunny',
label: '晴'
}, {
value: 'rainy',
label: '雨'
}, {
value: 'snowy',
label: '雪'
}, {
value: 'cloudy',
label: '阴'
}]
export const journalMoodTypeList = ['😀', '🙁', '😡']

View File

@@ -28,13 +28,9 @@ export const fileServiceUrl = '/home-api/file'
*/ */
export const serviceFileRootPath = '/home-api/' export const serviceFileRootPath = '/home-api/'
export const AListPath = '/alist-api/' export const AListUrl = '/alist-api/'
export const compressOptions = { export const AListPath = import.meta.env.VITE_API_ALIST_PATH
quality: 0.7,
maxHeight: 800,
maxWidth: 600
}
/** /**
* 获取assets静态资源 * 获取assets静态资源

View File

@@ -71,11 +71,11 @@ import { ref, reactive, onMounted } from 'vue'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox, FormRules, UploadProps, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus' import { ElMessage, ElMessageBox, FormRules, UploadProps, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'
import { foodRecordRules } from '@/utils/element/elRules.ts' import { foodRecordRules } from '@/utils/element/elRules.ts'
import { AListPath } from '@/utils' import { AListUrl } from '@/utils'
import { commonElMessageBox } from 'vue3-common/utils/elUtil' import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { useAppStore } from '@/store/app.ts' import { useAppStore } from '@/store/app.ts'
import { beforeUploadImage, httpRequestFile } from '@/utils/element/elUpload.ts' import { beforeUploadImage, httpRequestFile } from '@/utils/element/elUpload.ts'
import { acceptImageTypes } from '@/utils/home/file.ts' import { acceptImageTypes } from '@/utils/file.ts'
const rules = reactive<FormRules>(foodRecordRules) const rules = reactive<FormRules>(foodRecordRules)
@@ -97,7 +97,7 @@ const initImageFileList = () => {
if (imageUrl) { if (imageUrl) {
imageFileList.value.push({ imageFileList.value.push({
name: 'image', name: 'image',
url: `${AListPath}${imageUrl}` url: `${AListUrl}${imageUrl}`
}) })
} }
} }
@@ -107,11 +107,11 @@ const beforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
} }
const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => { const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
await httpRequestFile(foodStore.foodImagePath, options) return await httpRequestFile(foodStore.foodImagePath, options)
} }
const handleSuccess = (response: string) => { const handleSuccess = (response: string) => {
foodStore.currentFoodRecord.imageUrl = `p/${response}` foodStore.currentFoodRecord.imageUrl = `p${response}`
} }
const handleExceed: UploadProps['onExceed'] = () => { const handleExceed: UploadProps['onExceed'] = () => {
@@ -133,6 +133,7 @@ const confirmClick = () => {
formRef.value.validate().then(() => { formRef.value.validate().then(() => {
foodStore.handleFoodRecordApi(foodStore.currentFoodRecord) foodStore.handleFoodRecordApi(foodStore.currentFoodRecord)
history.back() history.back()
appStore.isShowMobileBack = false
}) })
} }

View File

@@ -36,7 +36,7 @@
<el-radio-group v-model="journalStore.currentJournal.category" <el-radio-group v-model="journalStore.currentJournal.category"
placeholder="请选择分类" clearable> placeholder="请选择分类" clearable>
<el-radio <el-radio
v-for="(item, index) in categoryTypeList" v-for="(item, index) in journalCategoryTypeList"
:key="index" :label="item" :value="item" :key="index" :label="item" :value="item"
/> />
</el-radio-group> </el-radio-group>
@@ -46,7 +46,7 @@
<el-radio-group v-model="journalStore.currentJournal.weather" <el-radio-group v-model="journalStore.currentJournal.weather"
placeholder="请选择天气" clearable> placeholder="请选择天气" clearable>
<el-radio <el-radio
v-for="(item, index) in weatherTypeList" v-for="(item, index) in journalWeatherTypeList"
:key="index" :value="item.value" :key="index" :value="item.value"
> >
<template #default> <template #default>
@@ -60,27 +60,53 @@
<el-radio-group v-model="journalStore.currentJournal.mood" <el-radio-group v-model="journalStore.currentJournal.mood"
placeholder="请选择心情" clearable> placeholder="请选择心情" clearable>
<el-radio <el-radio
v-for="(item, index) in moodTypeList" v-for="(item, index) in journalMoodTypeList"
:key="index" :value="item" :label="item" :key="index" :value="item" :label="item"
/> />
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="图片"> <el-form-item label="图片">
<upload-image v-model="journalStore.currentJournal.imageUrl" <el-upload
:service-url="fileServiceUrl" v-model:file-list="imageFileList"
:image-limit="1" list-type="picture-card"
:service-file-root-path="serviceFileRootPath" :accept="acceptImageTypes"
:image-path="journalStore.journalImagePath"/> :limit="1"
:before-upload="beforeImageUpload"
:http-request="httpImageRequest"
:on-success="handleImageSuccess"
:on-exceed="handleImageExceed"
:before-remove="beforeRemove"
:on-remove="handleImageRemove"
>
<el-icon><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
请上传小于10M的图片
</div>
</template>
</el-upload>
</el-form-item> </el-form-item>
<el-form-item label="视频"> <el-form-item label="视频">
<upload-video v-model="journalStore.currentJournal.videoUrl" <el-upload
:service-url="fileServiceUrl" v-model:file-list="videoFileList"
:image-limit="1" :accept="acceptVideoTypes"
:service-file-root-path="serviceFileRootPath" :limit="1"
:video-path="journalStore.journalVideoPath" :before-upload="beforeVideoUpload"
style="width: 100%;"/> :http-request="httpVideoRequest"
:on-success="handleVideoSuccess"
:on-exceed="handleVideoExceed"
:before-remove="beforeRemove"
:on-remove="handleVideoRemove"
>
<el-button type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">
请上传小于200M的视频
</div>
</template>
</el-upload>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -95,43 +121,97 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Location } from '@element-plus/icons-vue' import { Location, Plus } from '@element-plus/icons-vue'
import { useJournalStore } from '@/store/journal.ts' import { useJournalStore } from '@/store/journal.ts'
import { useAppStore } from '@/store/app.ts' import { useAppStore } from '@/store/app.ts'
import { FormRules } from 'element-plus' import { ElMessage, ElMessageBox, FormRules, UploadProps, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'
import { journalRules } from '@/utils/element/elRules.ts' import { journalRules } from '@/utils/element/elRules.ts'
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
import { commonElMessageBox } from 'vue3-common/utils/elUtil' import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { fileServiceUrl, serviceFileRootPath } from '@/utils' import { AListUrl } from '@/utils'
import { UploadImage, UploadVideo, SvgIcon } from 'vue3-common' import { SvgIcon } from 'vue3-common'
import { acceptImageTypes, acceptVideoTypes } from '@/utils/file.ts'
import { beforeUploadImage, beforeUploadVideo, httpRequestFile } from '@/utils/element/elUpload.ts'
import { journalCategoryTypeList, journalMoodTypeList, journalWeatherTypeList } from '@/utils/home/journalUtil.ts'
const formRef = ref() const formRef = ref()
const rules = reactive<FormRules>(journalRules) const rules = reactive<FormRules>(journalRules)
const journalStore = useJournalStore() const journalStore = useJournalStore()
const appStore = useAppStore() const appStore = useAppStore()
const categoryTypeList = ['生活', '工作', '其他'] const imageFileList = ref<UploadUserFile[]>([])
const videoFileList = ref<UploadUserFile[]>([])
const weatherTypeList = [{
value: 'sunny',
label: '晴'
}, {
value: 'rainy',
label: '雨'
}, {
value: 'snowy',
label: '雪'
}, {
value: 'cloudy',
label: '阴'
}]
const moodTypeList = ['😀', '🙁', '😡']
onMounted(async () => { onMounted(async () => {
appStore.isShowMobileBack = true appStore.isShowMobileBack = true
initFileList()
}) })
const initFileList = () => {
imageFileList.value = []
videoFileList.value = []
const { imageUrl, videoUrl } = journalStore.currentJournal
if (imageUrl) {
imageFileList.value.push({
name: 'image',
url: `${AListUrl}${imageUrl}`
})
}
if (videoUrl) {
videoFileList.value.push({
name: 'video',
url: `${AListUrl}${videoUrl}`
})
}
}
const beforeImageUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
return beforeUploadImage(rawFile)
}
const httpImageRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
return await httpRequestFile(journalStore.journalImagePath, options)
}
const handleImageSuccess = (response: string) => {
journalStore.currentJournal.imageUrl = `p${response}`
}
const handleImageExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('最多上传1张图片')
}
const handleImageRemove: UploadProps['onRemove'] = () => {
journalStore.currentJournal.imageUrl = ''
}
const beforeRemove: UploadProps['beforeRemove'] = () => {
return ElMessageBox.confirm('确认删除该文件?').then(() => true, () => false)
}
const beforeVideoUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
return beforeUploadVideo(rawFile)
}
const httpVideoRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
return await httpRequestFile(journalStore.journalImagePath, options, false)
}
const handleVideoSuccess = (response: string) => {
journalStore.currentJournal.videoUrl = `p${response}`
}
const handleVideoExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('最多上传1个视频')
}
const handleVideoRemove: UploadProps['onRemove'] = () => {
journalStore.currentJournal.videoUrl = ''
}
/** /**
* 点击确认按钮 * 点击确认按钮
*/ */

View File

@@ -47,19 +47,25 @@
</el-form-item> </el-form-item>
<el-form-item label="图片"> <el-form-item label="图片">
<upload-image v-model="ledgerStore.currentLedgerRecord.imageUrl" <el-upload
:image-limit="1" v-model:file-list="imageFileList"
:service-url="fileServiceUrl" list-type="picture-card"
:service-file-root-path="serviceFileRootPath" :accept="acceptImageTypes"
:image-path="ledgerStore.ledgerImagePath"/> :limit="1"
:before-upload="beforeUpload"
<el-image :http-request="httpRequest"
v-if="ledgerStore.currentLedgerRecord.imageUrl" :on-success="handleSuccess"
:src="serviceFileRootPath + ledgerStore.currentLedgerRecord.imageUrl" :on-exceed="handleExceed"
:preview-src-list="[serviceFileRootPath + ledgerStore.currentLedgerRecord.imageUrl]" :before-remove="beforeRemove"
show-progress :on-remove="handleRemove"
fit="cover" >
/> <el-icon><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
请上传小于10M的图片
</div>
</template>
</el-upload>
</el-form-item> </el-form-item>
<el-form-item label="备注"> <el-form-item label="备注">
@@ -80,25 +86,66 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { UploadImage } from 'vue3-common'
import { AmountInput } from 'vue3-common' import { AmountInput } from 'vue3-common'
import { useLedgerStore } from '@/store/ledger.ts' import { useLedgerStore } from '@/store/ledger.ts'
import { useAppStore } from '@/store/app.ts' import { useAppStore } from '@/store/app.ts'
import { FormRules } from 'element-plus' import { ElMessage, ElMessageBox, FormRules, UploadProps, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'
import { ledgerRules } from '@/utils/element/elRules.ts' import { ledgerRules } from '@/utils/element/elRules.ts'
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
import { commonElMessageBox } from 'vue3-common/utils/elUtil' import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { fileServiceUrl, serviceFileRootPath } from '@/utils' import { AListUrl } from '@/utils'
import { acceptImageTypes } from '@/utils/file.ts'
import { Plus } from '@element-plus/icons-vue'
import { beforeUploadImage, httpRequestFile } from '@/utils/element/elUpload.ts'
const formRef = ref() const formRef = ref()
const rules = reactive<FormRules>(ledgerRules) const rules = reactive<FormRules>(ledgerRules)
const imageFileList = ref<UploadUserFile[]>([])
const ledgerStore = useLedgerStore() const ledgerStore = useLedgerStore()
const appStore = useAppStore() const appStore = useAppStore()
onMounted(async () => { onMounted(async () => {
appStore.isShowMobileBack = true appStore.isShowMobileBack = true
initImageFileList()
}) })
const initImageFileList = () => {
imageFileList.value = []
const { imageUrl } = ledgerStore.currentLedgerRecord
if (imageUrl) {
imageFileList.value.push({
name: 'image',
url: `${AListUrl}${imageUrl}`
})
}
}
const beforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
return beforeUploadImage(rawFile)
}
const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
return await httpRequestFile(ledgerStore.ledgerImagePath, options)
}
const handleSuccess = (response: string) => {
ledgerStore.currentLedgerRecord.imageUrl = `p${response}`
}
const handleExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('最多上传1张图片')
}
const handleRemove: UploadProps['onRemove'] = () => {
ledgerStore.currentLedgerRecord.imageUrl = ''
}
const beforeRemove: UploadProps['beforeRemove'] = () => {
return ElMessageBox.confirm('确认删除该文件?').then(() => true, () => false)
}
/** /**
* 点击确认按钮 * 点击确认按钮
*/ */

View File

@@ -61,11 +61,25 @@
</el-form-item> </el-form-item>
<el-form-item label="物品图片"> <el-form-item label="物品图片">
<upload-image v-model="productStore.currentProduct.imageUrl" <el-upload
:image-limit="1" v-model:file-list="imageFileList"
:service-url="fileServiceUrl" list-type="picture-card"
:service-file-root-path="serviceFileRootPath" :accept="acceptImageTypes"
:image-path="productStore.productImagePath"/> :limit="1"
:before-upload="beforeUpload"
:http-request="httpRequest"
:on-success="handleSuccess"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-icon><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
请上传小于10M的图片
</div>
</template>
</el-upload>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -77,23 +91,64 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { UploadImage } from 'vue3-common'
import { useProductStore } from '@/store/product.ts' import { useProductStore } from '@/store/product.ts'
import { useAppStore } from '@/store/app.ts' import { useAppStore } from '@/store/app.ts'
import { FormRules } from 'element-plus' import { ElMessage, ElMessageBox, FormRules, UploadProps, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'
import { productRules } from '@/utils/element/elRules.ts' import { productRules } from '@/utils/element/elRules.ts'
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
import { fileServiceUrl, serviceFileRootPath } from '@/utils' import { AListUrl } from '@/utils'
import { acceptImageTypes } from '@/utils/file.ts'
import { Plus } from '@element-plus/icons-vue'
import { beforeUploadImage, httpRequestFile } from '@/utils/element/elUpload.ts'
const formRef = ref() const formRef = ref()
const rules = reactive<FormRules>(productRules) const rules = reactive<FormRules>(productRules)
const productStore = useProductStore() const productStore = useProductStore()
const appStore = useAppStore() const appStore = useAppStore()
const imageFileList = ref<UploadUserFile[]>([])
onMounted(async () => { onMounted(async () => {
appStore.isShowMobileBack = true appStore.isShowMobileBack = true
initImageFileList()
}) })
const beforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
return beforeUploadImage(rawFile)
}
const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
return await httpRequestFile(productStore.productImagePath, options)
}
const handleSuccess = (response: string) => {
productStore.currentProduct.imageUrl = `p${response}`
}
const handleExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('最多上传1张图片')
}
const handleRemove: UploadProps['onRemove'] = () => {
productStore.currentProduct.imageUrl = ''
}
const beforeRemove: UploadProps['beforeRemove'] = () => {
return ElMessageBox.confirm('确认删除该文件?').then(() => true, () => false)
}
const initImageFileList = () => {
imageFileList.value = []
const { imageUrl } = productStore.currentProduct
if (imageUrl) {
imageFileList.value.push({
name: 'image',
url: `${AListUrl}${imageUrl}`
})
}
}
/** /**
* 点击确认按钮 * 点击确认按钮
*/ */