This commit is contained in:
李志鹏
2026-04-13 14:35:12 +08:00
parent 5e77348913
commit 74d8723ecd
10 changed files with 516 additions and 22 deletions

View File

@@ -0,0 +1,166 @@
<template>
<a-modal
class="image-clip-dialog generalModel"
v-model:visible="show"
:footer="null"
width="70%"
:maskClosable="false"
:centered="true"
:closable="false"
wrapClassName="#app"
:keyboard="false"
>
<div class="image-clip-dialog-box">
<div class="header">
<div class="title">{{ data.title }}</div>
<div class="right">
<div class="submit" v-if="!data.isPreview" @click="onSubmit">
<svg-icon name="seller-dui" size="24" />
</div>
<button @click="onCancel">Cancel</button>
</div>
</div>
<div class="content">
<image-clip
ref="imageClipRef"
:ratio="data.ratio"
:url="data.url"
@change="(v) => (data.preview_url = v)"
/>
<div class="preview" v-if="data.isPreview">
<div class="title">
<span class="icon"><svg-icon name="seller-preview" size="24" /></span>
<span class="label">Crop Preview</span>
</div>
<img :src="data.preview_url" />
<div class="submit" @click="onSubmit">
<svg-icon name="seller-dui" size="24" />
</div>
</div>
</div>
</div>
</a-modal>
</template>
<script setup>
import { ref } from "vue"
import ImageClip from "./image-clip.vue"
const data = reactive({
url: "",
title: "Crop Image",
preview_url: "",
ratio: [1, 1],
isPreview: true,
callback: null
})
const show = ref(false)
const open = (url, callback, options) => {
if (!url || !callback) return
data.url = url
data.callback = callback
data.ratio = [1, 1]
data.isPreview = true
data.preview_url = ""
data.title = "Crop Image"
if (options) {
if (options.hasOwnProperty("isPreview")) data.isPreview = options.isPreview
if (options.hasOwnProperty("ratio")) data.ratio = options.ratio
if (options.hasOwnProperty("title")) data.title = options.title
}
show.value = true
}
const onCancel = () => {
show.value = false
}
const imageClipRef = ref(null)
const onSubmit = () => {
imageClipRef.value.getCropBlob().then((blob) => {
if (data.callback) data.callback(blobToFile(blob, "image.png"))
onCancel()
})
}
// 将blob转换为file对象
const blobToFile = (blob, fileName) => {
return new File([blob], fileName, { type: blob.type })
}
defineExpose({
open
})
</script>
<style scoped lang="less">
.image-clip-dialog-box {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
.submit {
width: 4rem;
height: 4rem;
border-radius: 50%;
background: #262626;
color: #fff;
cursor: pointer;
}
> .header {
display: flex;
justify-content: space-between;
margin-bottom: 5rem;
> .title {
font-family: pingfang_heavy;
font-size: 2.4rem;
color: #595959;
}
> .right {
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
> button {
width: 10rem;
height: 4.8rem;
border-radius: 4rem;
border: none;
background: #e4e5eb;
font-family: pingfang_heavy;
font-size: 1.6rem;
color: #000;
}
}
}
> .content {
flex: 1;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
> .image-clip {
flex: 1;
}
> .preview {
margin-left: 6rem;
width: 28rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 2.4rem;
> .title {
display: flex;
align-items: center;
justify-content: center;
gap: 1.2rem;
> .label {
font-family: pingfang_heavy;
font-size: 1.6rem;
}
}
> img {
width: 100%;
height: auto;
margin-bottom: 3rem;
}
}
}
}
</style>