<template>
|
<Modal
|
v-model="visible"
|
title="修改模板信息"
|
width="600"
|
@on-ok="handleOk"
|
@on-cancel="handleCancel"
|
>
|
<div v-if="loading" style="text-align: center; padding: 20px;">
|
<Spin size="large" />
|
<p>加载中...</p>
|
</div>
|
|
<Form ref="form" :model="form" :label-width="100" v-else-if="templateData">
|
<FormItem label="模板ID">
|
<Input v-model="templateData.id" disabled />
|
</FormItem>
|
|
<FormItem label="模板名称">
|
<Input v-model="form.templateName" disabled />
|
</FormItem>
|
|
<!-- 模板图片选择 -->
|
<FormItem
|
v-if="templateData.templateImgs && templateData.templateImgs.length > 0"
|
label="模板图片"
|
>
|
<div class="image-grid">
|
<div
|
v-for="(img, index) in templateData.templateImgs"
|
:key="img.id"
|
class="image-item"
|
:class="{ selected: selectedImageId === img.id }"
|
@click="selectImage(img.id)"
|
>
|
<img :src="getImageUrl(img.imgUrl)" class="image-preview" />
|
<div v-if="selectedImageId === img.id" class="selected-overlay">
|
<Icon type="md-checkmark" size="30" color="#fff" />
|
</div>
|
</div>
|
</div>
|
</FormItem>
|
|
<!-- 动态表单项 -->
|
<div v-if="templateData.templateConstomizeTitles">
|
<FormItem
|
v-for="(item, index) in templateData.templateConstomizeTitles"
|
:key="item.id"
|
:label="item.templateTitle"
|
>
|
<!-- 文本输入 -->
|
<Input
|
v-if="item.contentType === 'TEXT'"
|
v-model="formValues[item.id]"
|
:placeholder="'请输入' + item.templateTitle"
|
/>
|
|
<!-- 图片上传 -->
|
<div v-if="item.contentType === 'IMAGE'" class="image-upload-container">
|
<!-- 图片预览 -->
|
<div v-if="formValues[item.id]" class="image-preview-container">
|
<img :src="getImageUrl(formValues[item.id])" class="uploaded-image" />
|
<Icon
|
type="md-close"
|
class="delete-icon"
|
@click="removeImage(item.id)"
|
/>
|
</div>
|
|
<!-- 上传按钮 -->
|
<div v-else class="upload-btn" @click="uploadImage(item.id)">
|
<Icon type="md-add" size="30" color="#999" />
|
<span>上传图片</span>
|
</div>
|
|
<!-- 文件选择输入框(隐藏) -->
|
<input
|
:ref="'fileInput' + item.id"
|
type="file"
|
accept="image/*"
|
style="display: none"
|
@change="handleFileSelect($event, item.id)"
|
/>
|
</div>
|
</FormItem>
|
</div>
|
|
<!-- 调试信息 -->
|
<!-- <details style="margin-top: 20px; border: 1px solid #eee; padding: 10px;">
|
<summary>调试信息</summary>
|
<pre>{{ JSON.stringify(templateData, null, 2) }}</pre>
|
<p>选中的图片ID: {{ selectedImageId }}</p>
|
<p>表单值: {{ JSON.stringify(formValues, null, 2) }}</p>
|
</details>-->
|
</Form>
|
|
<div v-else>
|
<p>未加载到模板数据</p>
|
</div>
|
|
<div slot="footer">
|
<Button @click="handleCancel">取消</Button>
|
<Button type="primary" @click="handleOk" :loading="loading">确定</Button>
|
</div>
|
</Modal>
|
</template>
|
|
<script>
|
import * as API_Order from "@/api/order";
|
import { getFilePreviewUrl, uploadFileByLmk } from "@/api/common.js";
|
|
export default {
|
name: "EditTemplateModal",
|
props: {
|
value: {
|
type: Boolean,
|
default: false
|
},
|
templateId: {
|
type: [String, Number],
|
default: ""
|
},
|
// 添加订单编号属性
|
orderSn: {
|
type: String,
|
default: ""
|
},
|
// 添加userCheckTemplates属性
|
userCheckTemplates: {
|
type: Array,
|
default: () => []
|
}
|
},
|
data() {
|
return {
|
visible: this.value,
|
loading: false,
|
templateData: null,
|
form: {
|
templateName: ""
|
},
|
formValues: {},
|
selectedImageId: null,
|
selectedImageUrl: null, // 添加选中图片URL的存储
|
currentUploadFieldId: null // 当前正在上传的字段ID
|
};
|
},
|
watch: {
|
value(val) {
|
this.visible = val;
|
if (val) {
|
console.log("EditTemplateModal打开,接收到的参数:", {
|
templateId: this.templateId,
|
orderSn: this.orderSn
|
});
|
this.loadTemplateData();
|
}
|
},
|
visible(val) {
|
this.$emit("input", val);
|
// 当弹窗关闭时,重置选中的图片URL
|
if (!val) {
|
this.selectedImageUrl = null;
|
}
|
}
|
},
|
methods: {
|
// 加载模板数据
|
async loadTemplateData() {
|
// 确保订单编号是必传的
|
if (!this.orderSn) {
|
this.$Message.error("订单编号不能为空");
|
console.error("订单编号为空,当前参数:", {
|
templateId: this.templateId,
|
orderSn: this.orderSn
|
});
|
return;
|
}
|
|
if (!this.templateId) {
|
this.$Message.error("模板ID不能为空");
|
return;
|
}
|
|
try {
|
this.loading = true;
|
console.log("正在加载模板数据,模板ID:", this.templateId, "订单编号:", this.orderSn);
|
const res = await API_Order.getTemplate(this.templateId);
|
console.log("获取到的模板数据:", res);
|
if (res.code==200) {
|
this.templateData = res.data;
|
// 使用 name 字段作为模板名称
|
this.form.templateName = res.data.name || "";
|
|
// 初始化表单值
|
this.formValues = {};
|
// 初始化选中的图片ID
|
this.selectedImageId = null;
|
|
// 处理模板自定义标题字段的回显
|
if (res.data.templateConstomizeTitles) {
|
res.data.templateConstomizeTitles.forEach(item => {
|
// 回显已有的值 - 从userCheckTemplates中获取对应subId的值
|
const userTemplate = this.getUserTemplateBySubId(item.id);
|
if (userTemplate && userTemplate.content !== undefined && userTemplate.content !== null) {
|
this.$set(this.formValues, item.id, userTemplate.content);
|
} else if (item.value !== undefined && item.value !== null) {
|
// 如果没有找到userCheckTemplates中的值,则使用模板默认值
|
this.$set(this.formValues, item.id, item.value);
|
} else {
|
// 初始化表单值(如果没有默认值)
|
this.$set(this.formValues, item.id, "");
|
}
|
});
|
}
|
|
// 处理模板图片的回显
|
if (res.data.templateImgs && res.data.templateImgs.length > 0) {
|
// 如果已有选中的图片ID,则使用该ID,否则默认选中第一张
|
if (res.data.chooseImageId) {
|
this.selectedImageId = res.data.chooseImageId;
|
// 查找选中图片的URL并保存
|
const selectedImage = res.data.templateImgs.find(img => img.id === res.data.chooseImageId);
|
if (selectedImage) {
|
// 修改这里:处理图片URL,只保存相对路径
|
this.selectedImageUrl = this.processImageUrl(selectedImage.imgUrl || '');
|
}
|
} else {
|
// 尝试从userCheckTemplates中获取选中的图片
|
const userTemplate = this.getUserTemplateByType('IMAGE');
|
if (userTemplate && userTemplate.chooseImg) {
|
// 查找对应的图片ID
|
const matchedImage = res.data.templateImgs.find(img => img.imgUrl === userTemplate.chooseImg);
|
if (matchedImage) {
|
this.selectedImageId = matchedImage.id;
|
// 修改这里:处理图片URL,只保存相对路径
|
this.selectedImageUrl = this.processImageUrl(matchedImage.imgUrl || '');
|
} else {
|
this.selectedImageId = res.data.templateImgs[0].id;
|
// 修改这里:处理图片URL,只保存相对路径
|
this.selectedImageUrl = this.processImageUrl(res.data.templateImgs[0].imgUrl || '');
|
}
|
} else {
|
this.selectedImageId = res.data.templateImgs[0].id;
|
// 修改这里:处理图片URL,只保存相对路径
|
this.selectedImageUrl = this.processImageUrl(res.data.templateImgs[0].imgUrl || '');
|
}
|
}
|
} else {
|
// 如果没有模板图片,清空选中状态
|
this.selectedImageId = null;
|
this.selectedImageUrl = null;
|
}
|
|
console.log("处理后的数据:", {
|
templateData: this.templateData,
|
formValues: this.formValues,
|
selectedImageId: this.selectedImageId
|
});
|
} else {
|
this.$Message.error(res.message || "获取模板数据失败");
|
}
|
} catch (error) {
|
this.$Message.error("加载模板数据失败: " + error.message);
|
console.error("加载模板数据失败:", error);
|
} finally {
|
this.loading = false;
|
}
|
},
|
|
// 根据subId获取userCheckTemplates中的对应项
|
getUserTemplateBySubId(subId) {
|
// 从props中获取userCheckTemplates数据
|
if (this.userCheckTemplates && this.userCheckTemplates.length > 0) {
|
// 查找subId匹配的项
|
return this.userCheckTemplates.find(template => template.subId === subId);
|
}
|
return null;
|
},
|
|
// 根据类型获取userCheckTemplates中的对应项
|
getUserTemplateByType(contentType) {
|
if (this.userCheckTemplates && this.userCheckTemplates.length > 0) {
|
// 查找contentType匹配的项
|
return this.userCheckTemplates.find(template => template.contentType === contentType);
|
}
|
return null;
|
},
|
|
// 获取图片URL
|
getImageUrl(fileKey) {
|
// 确保fileKey是字符串类型
|
if (!fileKey || typeof fileKey !== 'string') {
|
console.warn('fileKey is not a valid string:', fileKey);
|
return ''; // 返回空字符串或默认图片
|
}
|
|
// 安全检查startsWith方法是否存在
|
if (fileKey.startsWith && typeof fileKey.startsWith === 'function' &&
|
(fileKey.startsWith("http://") || fileKey.startsWith("https://"))) {
|
return fileKey;
|
}
|
|
// 如果有endpoint配置,使用endpoint拼接URL
|
if (this.$root.endpoint) {
|
// 确保fileKey不以/开头,endpoint不以/结尾
|
const cleanEndpoint = this.$root.endpoint.replace(/\/$/, '');
|
const cleanFileKey = fileKey.replace(/^\//, '');
|
return `${cleanEndpoint}/${cleanFileKey}`;
|
}
|
|
// 如果是相对路径或其他格式,尝试通过getFilePreviewUrl获取完整URL
|
try {
|
return getFilePreviewUrl(fileKey);
|
} catch (error) {
|
console.warn('getFilePreviewUrl failed for fileKey:', fileKey, error);
|
}
|
|
// 否则返回fileKey,让组件自己处理
|
return fileKey;
|
},
|
|
// 选择图片
|
selectImage(imageId) {
|
this.selectedImageId = imageId;
|
|
// 查找选中图片的URL并保存
|
if (this.templateData && this.templateData.templateImgs) {
|
const selectedImage = this.templateData.templateImgs.find(img => img.id === imageId);
|
if (selectedImage) {
|
// 修改这里:处理图片URL,只保存相对路径
|
this.selectedImageUrl = this.processImageUrl(selectedImage.imgUrl || '');
|
} else {
|
this.selectedImageUrl = '';
|
}
|
} else {
|
this.selectedImageUrl = '';
|
}
|
},
|
|
// 上传图片
|
uploadImage(fieldId) {
|
this.currentUploadFieldId = fieldId;
|
// 触发文件选择
|
this.$refs['fileInput' + fieldId][0].click();
|
},
|
|
// 处理文件选择
|
async handleFileSelect(event, fieldId) {
|
const file = event.target.files[0];
|
if (!file) return;
|
|
// 验证文件类型
|
if (file.type && !file.type.startsWith('image/')) {
|
this.$Message.error("请选择图片文件");
|
return;
|
}
|
|
// 验证文件大小(限制为5MB)
|
if (file.size > 5 * 1024 * 1024) {
|
this.$Message.error("图片大小不能超过5MB");
|
return;
|
}
|
|
try {
|
this.loading = true;
|
// 创建FormData对象
|
const formData = new FormData();
|
formData.append('file', file);
|
|
// 上传文件
|
const res = await uploadFileByLmk(formData);
|
console.log('上传文件返回结果:', res); // 添加调试日志
|
if (res.code === 200) {
|
// 上传成功,设置表单值
|
// 修改这里:只保存文件名或相对路径,而不是完整路径
|
let fileKey = '';
|
if (typeof res.data === 'string') {
|
fileKey = res.data;
|
} else if (res.data && typeof res.data === 'object') {
|
// 如果返回的是对象,尝试获取fileKey或url字段
|
fileKey = res.data.fileKey || res.data.url || '';
|
} else {
|
fileKey = String(res.data);
|
}
|
|
// 确保fileKey是字符串类型
|
if (typeof fileKey !== 'string') {
|
fileKey = String(fileKey);
|
}
|
|
// 修改这里:处理文件路径,只保留文件名部分
|
// 如果是完整URL,则只取路径部分;否则保持原样
|
if (fileKey.startsWith('http://') || fileKey.startsWith('https://')) {
|
// 提取URL中的路径部分
|
try {
|
const urlObj = new URL(fileKey);
|
fileKey = urlObj.pathname.substring(1); // 去掉开头的斜杠
|
} catch (e) {
|
// 如果URL解析失败,保持原样
|
console.warn('Failed to parse URL:', fileKey);
|
}
|
}
|
|
this.$set(this.formValues, fieldId, fileKey);
|
|
this.$Message.success("图片上传成功");
|
|
// 强制更新视图以确保图片预览正确显示
|
this.$forceUpdate();
|
} else {
|
this.$Message.error(res.msg || "图片上传失败");
|
}
|
} catch (error) {
|
this.$Message.error("图片上传失败: " + (error.message || error));
|
console.error(error);
|
} finally {
|
this.loading = false;
|
// 清空文件输入框
|
event.target.value = '';
|
}
|
},
|
|
// 移除图片
|
removeImage(fieldId) {
|
this.$set(this.formValues, fieldId, "");
|
},
|
|
// 构造提交参数
|
buildSubmitParams() {
|
const params = {
|
templateId: this.templateId,
|
// 添加订单编号到提交参数
|
sn: this.orderSn,
|
templateName: this.form.templateName,
|
chooseImageId: this.selectedImageId,
|
// 修改这里:处理chooseImage,只保存相对路径
|
chooseImage: this.processImageUrl(this.selectedImageUrl),
|
templateForm: []
|
};
|
|
// 添加表单字段
|
if (this.templateData && this.templateData.templateConstomizeTitles) {
|
this.templateData.templateConstomizeTitles.forEach(item => {
|
params.templateForm.push({
|
id: item.id,
|
templateTitle: item.templateTitle,
|
contentType: item.contentType,
|
// 修改这里:处理value,只保存相对路径
|
value: this.processImageUrl(this.formValues[item.id]) || ""
|
});
|
});
|
}
|
|
console.log("提交参数:", params);
|
return params;
|
},
|
|
// 处理图片URL,只保留相对路径
|
processImageUrl(url) {
|
if (!url || typeof url !== 'string') {
|
return url;
|
}
|
|
// 如果是完整URL,则只取路径部分;否则保持原样
|
if (url.startsWith('http://') || url.startsWith('https://')) {
|
try {
|
const urlObj = new URL(url);
|
return urlObj.pathname.substring(1); // 去掉开头的斜杠
|
} catch (e) {
|
// 如果URL解析失败,保持原样
|
console.warn('Failed to parse URL:', url);
|
return url;
|
}
|
}
|
|
return url;
|
},
|
|
// 确定按钮
|
async handleOk() {
|
if (!this.templateData) {
|
this.$Message.error("没有可提交的模板数据");
|
return;
|
}
|
|
this.loading = true;
|
try {
|
const params = this.buildSubmitParams();
|
const res = await API_Order.editTemplate(params);
|
if (res.code==200) {
|
this.$Message.success("模板信息修改成功");
|
this.visible = false;
|
this.$emit("success");
|
} else {
|
this.$Message.error(res.message || "修改失败");
|
}
|
} catch (error) {
|
this.$Message.error("修改失败: " + error.message);
|
console.error(error);
|
} finally {
|
this.loading = false;
|
}
|
},
|
|
// 取消按钮
|
handleCancel() {
|
this.visible = false;
|
this.$emit("cancel");
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.image-grid {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10px;
|
}
|
|
.image-item {
|
position: relative;
|
width: 100px;
|
height: 100px;
|
border: 1px solid #ddd;
|
border-radius: 4px;
|
cursor: pointer;
|
overflow: hidden;
|
}
|
|
.image-item:hover {
|
border-color: #57a3f3;
|
}
|
|
.image-item.selected {
|
border-color: #57a3f3;
|
box-shadow: 0 0 0 2px rgba(45, 140, 240, 0.2);
|
}
|
|
.image-preview {
|
width: 100%;
|
height: 100%;
|
object-fit: cover;
|
}
|
|
.selected-overlay {
|
position: absolute;
|
top: 0;
|
left: 0;
|
width: 100%;
|
height: 100%;
|
background-color: rgba(0, 0, 0, 0.5);
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.image-upload-container {
|
display: flex;
|
align-items: center;
|
}
|
|
.image-preview-container {
|
position: relative;
|
width: 100px;
|
height: 100px;
|
margin-right: 10px;
|
}
|
|
.uploaded-image {
|
width: 100%;
|
height: 100%;
|
object-fit: cover;
|
border-radius: 4px;
|
}
|
|
.delete-icon {
|
position: absolute;
|
top: -8px;
|
right: -8px;
|
width: 20px;
|
height: 20px;
|
background-color: #ed4014;
|
border-radius: 50%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
cursor: pointer;
|
color: #fff;
|
}
|
|
.upload-btn {
|
width: 100px;
|
height: 100px;
|
border: 1px dashed #dcdee2;
|
border-radius: 4px;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
cursor: pointer;
|
color: #999;
|
}
|
|
.upload-btn:hover {
|
border-color: #57a3f3;
|
color: #57a3f3;
|
}
|
</style>
|