<!-- ImageSizeEditor.vue -->
|
<template>
|
<div class="img-grid">
|
<div
|
v-for="(img, index) in images"
|
:key="getKey(img, index)"
|
class="img-box"
|
:style="getImgBoxStyle(getKey(img, index))"
|
@click="openSizeDialog(img, index)"
|
>
|
<el-image
|
:src="img.imageBase64"
|
:fit="fit"
|
style="width: 100%; height: 100%; display: block;"
|
/>
|
</div>
|
</div>
|
|
<el-dialog
|
v-model="dialogVisible"
|
:title="dialogTitle"
|
width="460px"
|
append-to-body
|
>
|
<div class="form-row">
|
<el-input-number
|
v-model="form.w"
|
:min="minWidth"
|
:max="maxWidth"
|
controls-position="right"
|
/>
|
<span class="mul">×</span>
|
<el-input-number
|
v-model="form.h"
|
:min="minHeight"
|
:max="maxHeight"
|
controls-position="right"
|
/>
|
</div>
|
|
<div class="ops-row">
|
<!-- <el-switch v-model="applyToAll" active-text="应用到全部图片" />-->
|
<div v-if="showHint" class="hint">
|
当前:{{ form.w }} × {{ form.h }} px
|
</div>
|
</div>
|
|
<template #footer>
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
<!-- ✅ 一键全图统一尺寸:不关弹窗,立即应用 -->
|
<el-button @click="applyAllNow" :disabled="!canApply">
|
尺寸相同
|
</el-button>
|
|
<!-- ✅ 确定:如果开关打开,则同样会应用全部,否则只应用当前 -->
|
<el-button type="primary" @click="confirmSize" :disabled="!canApply">
|
确定
|
</el-button>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { computed, reactive, ref, unref } from 'vue'
|
|
const props = defineProps({
|
images: { type: Array, default: () => [] },
|
keyField: { type: String, default: 'orderNumber' }, // 你数据 id=null,推荐 orderNumber
|
srcField: { type: String, default: 'imageBase64' },
|
|
sizeMap: { type: Object, default: () => ({}) },
|
|
defaultWidth: { type: Number, default: 600 },
|
defaultHeight: { type: Number, default: 400 },
|
|
minWidth: { type: Number, default: 50 },
|
maxWidth: { type: Number, default: 3000 },
|
minHeight: { type: Number, default: 50 },
|
maxHeight: { type: Number, default: 3000 },
|
|
fit: { type: String, default: 'contain' },
|
marginX: { type: String, default: '30px' },
|
marginY: { type: String, default: '50px' },
|
dialogTitle: { type: String, default: '设置图片尺寸' },
|
showHint: { type: Boolean, default: true }
|
})
|
|
const emit = defineEmits(['update:sizeMap', 'change', 'changeAll'])
|
|
const sizeStore = computed({
|
get: () => props.sizeMap || {},
|
set: (val) => emit('update:sizeMap', val)
|
})
|
|
const dialogVisible = ref(false)
|
const activeKey = ref(null)
|
|
const form = reactive({
|
w: props.defaultWidth,
|
h: props.defaultHeight
|
})
|
|
const applyToAll = ref(false)
|
|
const canApply = computed(() => {
|
const w = Number(form.w)
|
const h = Number(form.h)
|
return w > 0 && h > 0
|
})
|
|
const getKey = (img, index) => {
|
const k = img?.[props.keyField]
|
return (k !== undefined && k !== null && k !== '') ? String(k) : String(index)
|
}
|
|
const getSrc = (img) => img?.[props.srcField]
|
|
const getSize = (key) => {
|
const s = unref(sizeStore.value?.[key])
|
if (s && s.w && s.h) return { w: Number(s.w), h: Number(s.h) }
|
return { w: props.defaultWidth, h: props.defaultHeight }
|
}
|
|
const getImgBoxStyle = (key) => {
|
const { w, h } = getSize(key)
|
return {
|
width: `${w}px`,
|
height: `${h}px`,
|
marginLeft: props.marginX,
|
marginRight: props.marginX,
|
marginTop: props.marginY,
|
marginBottom: props.marginY
|
}
|
}
|
|
|
const openSizeDialog = (img, index) => {
|
const key = getKey(img, index)
|
activeKey.value = key
|
|
const cur = getSize(key)
|
form.w = cur.w
|
form.h = cur.h
|
|
applyToAll.value = false
|
dialogVisible.value = true
|
}
|
|
// ✅ 应用到当前一张
|
const applyOne = (key, w, h) => {
|
sizeStore.value = { ...sizeStore.value, [key]: { w, h } }
|
emit('change', key, { w, h })
|
}
|
|
// ✅ 一键应用到全部
|
const applyAll = (w, h) => {
|
const next = { ...sizeStore.value }
|
props.images.forEach((img, idx) => {
|
const k = getKey(img, idx)
|
next[k] = { w, h }
|
})
|
sizeStore.value = next
|
emit('changeAll', { w, h })
|
}
|
|
// ✅ footer 按钮:立即统一全图尺寸(不关弹窗)
|
const applyAllNow = () => {
|
if (!canApply.value) return
|
const w = Number(form.w)
|
const h = Number(form.h)
|
applyAll(w, h)
|
}
|
|
// ✅ 确定:如果开关打开 => 全部;否则只改当前
|
const confirmSize = () => {
|
if (!canApply.value) return
|
const w = Number(form.w)
|
const h = Number(form.h)
|
|
if (applyToAll.value) {
|
applyAll(w, h)
|
dialogVisible.value = false
|
return
|
}
|
|
const key = activeKey.value
|
if (key === null || key === undefined) return
|
applyOne(key, w, h)
|
dialogVisible.value = false
|
}
|
</script>
|
|
<style scoped>
|
.img-grid {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 12px;
|
}
|
|
.form-row {
|
display: flex;
|
gap: 12px;
|
align-items: center;
|
}
|
|
.mul {
|
line-height: 32px;
|
}
|
|
.ops-row{
|
margin-top: 12px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
gap: 12px;
|
flex-wrap: wrap;
|
}
|
|
.hint {
|
font-size: 12px;
|
opacity: 0.75;
|
}
|
</style>
|