优化租户管理文件上传功能,支持FormData格式提交营业执照

This commit is contained in:
WUSIJIAN
2025-12-10 11:27:22 +08:00
parent 112994ac5b
commit 06ca1d227d
2 changed files with 42 additions and 8 deletions

View File

@@ -20,19 +20,25 @@ export function getTenant(id: number) {
// 新增租户 // 新增租户
export function addTenant(data: object) { export function addTenant(data: object) {
// 如果是 FormData需要让浏览器自动设置 Content-Type包含 boundary
const isFormData = data instanceof FormData;
return request({ return request({
url: '/api/v1/system/tenant/add', url: '/api/v1/system/tenant/add',
method: 'post', method: 'post',
data: data, data: data,
headers: isFormData ? { 'Content-Type': undefined } : undefined,
}); });
} }
// 修改租户 // 修改租户
export function editTenant(data: object) { export function editTenant(data: object) {
// 如果是 FormData需要让浏览器自动设置 Content-Type包含 boundary
const isFormData = data instanceof FormData;
return request({ return request({
url: '/api/v1/system/tenant/edit', url: '/api/v1/system/tenant/edit',
method: 'put', method: 'put',
data: data, data: data,
headers: isFormData ? { 'Content-Type': undefined } : undefined,
}); });
} }

View File

@@ -76,11 +76,11 @@
class="avatar-uploader" class="avatar-uploader"
action="#" action="#"
:auto-upload="false" :auto-upload="false"
:on-change="handleFileChange"
:show-file-list="false" :show-file-list="false"
:on-change="handleAvatarSuccess"
:before-upload="beforeAvatarUpload" :before-upload="beforeAvatarUpload"
> >
<img v-if="ruleForm.businessLicense" :src="ruleForm.businessLicense" class="avatar" /> <img v-if="ruleForm.businessLicense" :src="getUpFileUrl(ruleForm.businessLicense)" class="avatar" />
<div v-else class="upload-placeholder"> <div v-else class="upload-placeholder">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon> <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
<span class="upload-text">点击上传营业执照</span> <span class="upload-text">点击上传营业执照</span>
@@ -108,6 +108,7 @@ import { ElMessage, UploadProps } from 'element-plus';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { addTenant, editTenant } from '/@/api/system/tenant'; import { addTenant, editTenant } from '/@/api/system/tenant';
import { pcTextArr,provinceAndCityData } from 'element-china-area-data'; import { pcTextArr,provinceAndCityData } from 'element-china-area-data';
import { getUpFileUrl } from '/@/utils/gfast';
// 定义父组件传递的事件 // 定义父组件传递的事件
const emit = defineEmits(['getTenantList']); const emit = defineEmits(['getTenantList']);
@@ -117,6 +118,9 @@ const formRef = ref<HTMLElement | null>(null);
// 省市数据(使用 element-china-area-data // 省市数据(使用 element-china-area-data
const cityOptions = ref<any[]>([]); const cityOptions = ref<any[]>([]);
// 单独定义文件对象避免reactive深层代理导致FormData识别错误
const fileRaw = ref<any>(null);
const initCityData = () => { const initCityData = () => {
const data = JSON.parse(JSON.stringify(provinceAndCityData)); const data = JSON.parse(JSON.stringify(provinceAndCityData));
cityOptions.value = data.map((item: any) => { cityOptions.value = data.map((item: any) => {
@@ -285,8 +289,25 @@ const onSubmit = () => {
submitForm.city = ''; submitForm.city = '';
} }
// 转换为FormData
const formData = new FormData();
for (const key in submitForm) {
// 如果是文件字段,跳过(后面单独处理)
if (key === 'businessLicense') continue;
formData.append(key, submitForm[key]);
}
// 添加文件
if (fileRaw.value) {
// 【重要】必须append raw file(二进制文件流)不能是element-plus的uploadFile包装对象
// 否则后端接收到的会是 { uid: ..., status: ... } 这样的json结构
formData.append('businessLicense', fileRaw.value);
} else if (submitForm.businessLicense && !submitForm.businessLicense.startsWith('blob:')) {
// 如果没有新文件且原值不是blob预览地址则传递原url字符串
formData.append('businessLicense', submitForm.businessLicense);
}
if (state.ruleForm.id === 0) { if (state.ruleForm.id === 0) {
addTenant(submitForm).then(() => { addTenant(formData).then(() => {
ElMessage.success('添加成功'); ElMessage.success('添加成功');
closeDialog(); closeDialog();
emit('getTenantList'); emit('getTenantList');
@@ -294,8 +315,11 @@ const onSubmit = () => {
} else { } else {
// 过滤掉密码字段,或者后端接口决定是否更新密码 // 过滤掉密码字段,或者后端接口决定是否更新密码
// 根据需求,修改时不能修改密码 // 根据需求,修改时不能修改密码
const { password, confirmPassword, tenantAccount, ...rest } = submitForm; if (formData.has('password')) formData.delete('password');
editTenant({ ...rest, id: state.ruleForm.id }).then(() => { if (formData.has('confirmPassword')) formData.delete('confirmPassword');
if (formData.has('tenantAccount')) formData.delete('tenantAccount');
editTenant(formData).then(() => {
ElMessage.success('修改成功'); ElMessage.success('修改成功');
closeDialog(); closeDialog();
emit('getTenantList'); emit('getTenantList');
@@ -319,11 +343,15 @@ const resetForm = () => {
businessLicense: '', businessLicense: '',
}; };
state.passwordStrength = 0; state.passwordStrength = 0;
fileRaw.value = null;
}; };
// 模拟上传图片 // 文件改变时触发
const handleAvatarSuccess: UploadProps['onChange'] = (uploadFile) => { const handleFileChange: UploadProps['onChange'] = (uploadFile) => {
state.ruleForm.businessLicense = URL.createObjectURL(uploadFile.raw!); if (uploadFile.raw) {
fileRaw.value = uploadFile.raw;
state.ruleForm.businessLicense = URL.createObjectURL(uploadFile.raw);
}
}; };
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => { const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {