Files
yunzerwebsiteallinone/backend/src/views/apps/cms/friendlink/components/edit.vue
T
2026-06-03 10:09:03 +08:00

303 lines
7.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-dialog
v-model="visible"
:title="title"
width="600px"
destroy-on-close
@close="handleClose"
>
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
>
<el-form-item label="链接名称" prop="link_name">
<el-input v-model="formData.link_name" placeholder="请输入链接名称" />
</el-form-item>
<el-form-item label="链接地址" prop="link_url">
<el-input v-model="formData.link_url" placeholder="请输入链接地址,如:https://www.example.com" />
</el-form-item>
<el-form-item label="Logo" prop="link_logo">
<el-upload
class="image-uploader"
:action="uploadUrl"
:headers="uploadHeaders"
:show-file-list="false"
:on-success="handleImageSuccess"
:on-error="handleImageError"
:before-upload="beforeImageUpload"
accept="image/*"
>
<img
v-if="formData.link_logo"
:src="getImageUrl(formData.link_logo)"
class="image-preview"
/>
<div v-else class="upload-placeholder">
<el-icon class="image-uploader-icon"><Plus /></el-icon>
<div class="el-upload__text">点击上传Logo</div>
</div>
</el-upload>
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary);">
建议尺寸:200x200,支持 jpg、png、gif 格式,大小不超过 2MB
</div>
<el-button
v-if="formData.link_logo"
size="small"
type="danger"
text
@click="handleRemoveImage"
style="margin-top: 8px;"
>
删除图片
</el-button>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input
v-model="formData.description"
type="textarea"
:rows="3"
placeholder="请输入描述"
/>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort" :min="0" :max="999" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { addFriendlink, updateFriendlink } from '@/api/friendlink'
// @ts-ignore
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
title: {
type: String,
default: '添加友情链接'
},
isEdit: {
type: Boolean,
default: false
},
rowData: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['update:modelValue', 'success'])
const visible = ref(false)
const submitLoading = ref(false)
const formRef = ref(null)
// 上传配置
const uploadUrl = ref(API_BASE_URL + "/admin/uploadfiles");
const uploadHeaders = ref({
Authorization: "Bearer " + (localStorage.getItem("token") || ""),
});
// 图片上传前校验
const beforeImageUpload = (file) => {
const isImage = file.type.startsWith('image/');
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isImage) {
ElMessage.error('请上传图片文件!');
return false;
}
if (!isLt2M) {
ElMessage.error('图片大小不能超过 2MB!');
return false;
}
return true;
};
// 图片上传成功
const handleImageSuccess = (response) => {
if (response.code === 200 || response.code === 201) {
formData.link_logo = response.data.url || response.data.path;
ElMessage.success(response.code === 201 ? "文件已存在,直接使用" : "图片上传成功");
} else {
ElMessage.error(response.msg || "图片上传失败");
}
};
// 图片上传失败
const handleImageError = () => {
ElMessage.error("图片上传失败,请重试");
};
// 删除图片
const handleRemoveImage = () => {
formData.link_logo = "";
ElMessage.success("图片已删除");
};
// 获取图片完整URL(用于预览)
const getImageUrl = (imagePath) => {
if (!imagePath) return "";
if (imagePath.startsWith("http")) return imagePath;
return API_BASE_URL + imagePath;
};
const formData = reactive({
link_name: '',
link_url: '',
link_logo: '',
description: '',
sort: 0,
status: 1
})
const formRules = {
link_name: [
{ required: true, message: '请输入链接名称', trigger: 'blur' },
{ max: 100, message: '长度不超过100个字符', trigger: 'blur' }
],
link_url: [
{ required: true, message: '请输入链接地址', trigger: 'blur' },
{ type: 'url', message: '请输入正确的URL地址', trigger: 'blur' }
]
}
// 监听 modelValue 变化
watch(() => props.modelValue, (val) => {
visible.value = val
if (val) {
resetForm()
if (props.isEdit && props.rowData) {
Object.assign(formData, props.rowData)
}
}
})
// 监听 visible 变化
watch(visible, (val) => {
emit('update:modelValue', val)
})
// 重置表单
const resetForm = () => {
formData.link_name = ''
formData.link_url = ''
formData.link_logo = ''
formData.description = ''
formData.sort = 0
formData.status = 1
}
// 关闭
const handleClose = () => {
visible.value = false
}
// 提交
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid) => {
if (valid) {
submitLoading.value = true
try {
let res
if (props.isEdit) {
res = await updateFriendlink(props.rowData.id, formData)
} else {
res = await addFriendlink(formData)
}
if (res.code === 200) {
ElMessage.success(props.isEdit ? '更新成功' : '添加成功')
handleClose()
emit('success')
} else {
ElMessage.error(res.msg || '操作失败')
}
} catch (error) {
console.error('提交失败:', error)
ElMessage.error('操作失败')
} finally {
submitLoading.value = false
}
}
})
}
</script>
<style scoped>
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
/* 图片上传样式 */
.image-uploader {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
width: 120px;
height: 120px;
}
.image-uploader:hover {
border-color: var(--el-color-primary);
}
.upload-placeholder {
width: 120px;
height: 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--el-text-color-secondary);
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
margin-bottom: 8px;
}
.el-upload__text {
font-size: 12px;
}
.image-preview {
width: 120px;
height: 120px;
object-fit: contain;
display: block;
}
</style>