mirror of
http://183.237.82.114:10086/kilo/leaser_front.git
synced 2026-10-23 19:35:25 +00:00
fix: 修复项目列表新增/编辑的bug
This commit is contained in:
parent
194e0faa72
commit
ddb35b10f1
4 changed files with 92 additions and 76 deletions
|
|
@ -9,21 +9,21 @@
|
|||
- 支持上传进度显示
|
||||
- 支持图片预览
|
||||
- 支持多文件上传
|
||||
- 上传成功后自动回传URL
|
||||
- 上传成功后自动回传 URL
|
||||
|
||||
## Props
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| modelValue | UploadFile[] | [] | 文件列表,支持v-model |
|
||||
| uploadType | UploadType | - | 上传类型:1合同模版,2图片 |
|
||||
| maxSize | number | 10 * 1024 * 1024 | 最大文件大小(字节) |
|
||||
| ---------- | ------------ | ---------------- | ---------------------------- |
|
||||
| modelValue | UploadFile[] | [] | 文件列表,支持 v-model |
|
||||
| uploadType | UploadType | - | 上传类型:1 合同模版,2 图片 |
|
||||
| maxSize | number | 10 _ 1024 _ 1024 | 最大文件大小(字节) |
|
||||
| maxCount | number | - | 最大上传数量 |
|
||||
|
||||
## Events
|
||||
|
||||
| 事件名 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| ----------------- | -------------------------------------------- | ------------------ |
|
||||
| update:modelValue | (value: UploadFile[]) | 文件列表更新时触发 |
|
||||
| upload-success | (file: UploadFile, response: UploadResponse) | 上传成功时触发 |
|
||||
| upload-error | (error: Error) | 上传失败时触发 |
|
||||
|
|
@ -42,7 +42,8 @@ interface UploadFile {
|
|||
interface UploadResponse {
|
||||
filename: string;
|
||||
size: number;
|
||||
url: string;
|
||||
signedPutURL: string;
|
||||
objectKey?: string;
|
||||
}
|
||||
|
||||
type UploadType = 1 | 2; // 1合同模版,2图片
|
||||
|
|
@ -63,18 +64,18 @@ type UploadType = 1 | 2; // 1合同模版,2图片
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import ImageUpload from '@/components/common/ImageUpload.vue';
|
||||
import { ref } from 'vue';
|
||||
import ImageUpload from '@/components/common/ImageUpload.vue';
|
||||
|
||||
const images = ref([]);
|
||||
const images = ref([]);
|
||||
|
||||
const handleUploadSuccess = (file, response) => {
|
||||
const handleUploadSuccess = (file, response) => {
|
||||
console.log('上传成功:', response.url);
|
||||
};
|
||||
};
|
||||
|
||||
const handleUploadError = (error) => {
|
||||
const handleUploadError = (error) => {
|
||||
console.error('上传失败:', error.message);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -110,6 +111,6 @@ const handleUploadError = (error) => {
|
|||
## 注意事项
|
||||
|
||||
1. 组件会自动处理文件验证,包括文件大小和格式检查
|
||||
2. 上传成功后,文件对象会自动更新URL和状态
|
||||
3. 支持v-model双向绑定,父组件可以直接操作文件列表
|
||||
2. 上传成功后,文件对象会自动更新 URL 和状态
|
||||
3. 支持 v-model 双向绑定,父组件可以直接操作文件列表
|
||||
4. 上传类型必须从父组件传入,用于区分不同的上传场景
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<a-upload
|
||||
:list-type="listType"
|
||||
:accept="'image/*'"
|
||||
accept="image/*"
|
||||
:custom-request="customRequest"
|
||||
:file-list="fileList"
|
||||
:multiple="maxCount > 1"
|
||||
|
|
@ -22,48 +22,52 @@
|
|||
url?: string;
|
||||
status: 'done' | 'uploading' | 'error';
|
||||
percent?: number;
|
||||
objectKey?: string;
|
||||
}
|
||||
|
||||
interface UploadResponse {
|
||||
filename: string;
|
||||
size: number;
|
||||
url: string;
|
||||
signedPutURL: string;
|
||||
objectKey: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string[]; // 只暴露图片url数组
|
||||
objectKeys: string[]; // 提交用的 Key 数组
|
||||
signedPutURL: string[]; // 显示用 URL 数组
|
||||
uploadType: UploadType;
|
||||
maxSize?: number; // 默认10MB
|
||||
maxCount?: number; // 最大上传数量,默认1(单图)
|
||||
listType?: 'text' | 'picture' | 'picture-card'; // 上传样式
|
||||
maxSize?: number;
|
||||
maxCount?: number;
|
||||
listType?: 'text' | 'picture' | 'picture-card';
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string[]): void;
|
||||
(e: 'upload-success', url: string): void;
|
||||
(e: 'update:objectKeys', value: string[]): void;
|
||||
(e: 'update:signedPutURL', value: string[]): void;
|
||||
(
|
||||
e: 'upload-success',
|
||||
payload: { objectKey: string; signedPutURL: string }
|
||||
): void;
|
||||
(e: 'upload-error', error: Error): void;
|
||||
}>();
|
||||
|
||||
const fileList = ref<UploadFile[]>([]);
|
||||
|
||||
// 默认最大上传数:1(单图)
|
||||
const maxCount = props.maxCount ?? 1;
|
||||
|
||||
// listType 默认值
|
||||
const listType = props.listType ?? 'picture-card';
|
||||
|
||||
// 将外部 url[] 映射为 UploadFile[]
|
||||
// 回显处理(编辑/刷新时)
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
fileList.value = (newVal || []).map((url, index) => ({
|
||||
uid: `${index}`,
|
||||
name: `图片-${index + 1}`,
|
||||
url,
|
||||
() => [props.objectKeys, props.signedPutURL],
|
||||
([keys, urls]) => {
|
||||
fileList.value = (keys || []).map((key, idx) => ({
|
||||
uid: `${idx}`,
|
||||
name: key.split('/').pop() || `图片-${idx + 1}`,
|
||||
url: urls[idx] || '',
|
||||
objectKey: key,
|
||||
status: 'done',
|
||||
}));
|
||||
},
|
||||
{ immediate: true }
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
// 自定义上传请求
|
||||
|
|
@ -80,15 +84,12 @@
|
|||
'image/webp',
|
||||
];
|
||||
|
||||
// 文件大小校验
|
||||
if (file.size > maxSize) {
|
||||
onError(
|
||||
new Error(`文件大小不能超过${Math.round(maxSize / 1024 / 1024)}MB`)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 文件类型校验
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
onError(new Error('只支持 JPG、PNG、GIF、WEBP 格式的图片'));
|
||||
return;
|
||||
|
|
@ -114,44 +115,54 @@
|
|||
clearInterval(progressInterval);
|
||||
|
||||
if (code === 200 && data) {
|
||||
const response = data as UploadResponse;
|
||||
|
||||
const res = data as UploadResponse;
|
||||
fileItem.status = 'done';
|
||||
fileItem.url = response.url;
|
||||
fileItem.url = res.signedPutURL;
|
||||
fileItem.objectKey = res.objectKey;
|
||||
onProgress({ percent: 100 });
|
||||
onSuccess(response);
|
||||
onSuccess(res);
|
||||
|
||||
// 新的图片 url
|
||||
let updatedUrls = [...props.modelValue];
|
||||
// 更新父组件两个数组
|
||||
let newKeys = [...props.objectKeys];
|
||||
let newUrls = [...props.signedPutURL];
|
||||
if (maxCount === 1) {
|
||||
updatedUrls = [response.url];
|
||||
newKeys = [res.objectKey];
|
||||
newUrls = [res.signedPutURL];
|
||||
} else {
|
||||
updatedUrls.push(response.url);
|
||||
// 截取至 maxCount
|
||||
updatedUrls = updatedUrls.slice(0, maxCount);
|
||||
newKeys.push(res.objectKey);
|
||||
newUrls.push(res.signedPutURL);
|
||||
newKeys = newKeys.slice(0, maxCount);
|
||||
newUrls = newUrls.slice(0, maxCount);
|
||||
}
|
||||
|
||||
emit('update:modelValue', updatedUrls);
|
||||
emit('upload-success', response.url);
|
||||
emit('update:objectKeys', newKeys);
|
||||
emit('update:signedPutURL', newUrls);
|
||||
emit('upload-success', {
|
||||
objectKey: res.objectKey,
|
||||
signedPutURL: res.signedPutURL,
|
||||
});
|
||||
} else {
|
||||
const error = new Error(message || '上传失败');
|
||||
onError(error);
|
||||
emit('upload-error', error);
|
||||
}
|
||||
} catch (error) {
|
||||
const err = error instanceof Error ? error : new Error('上传失败');
|
||||
} catch (e) {
|
||||
const err = e instanceof Error ? e : new Error('上传失败');
|
||||
onError(err);
|
||||
emit('upload-error', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 同步 fileList(删除时触发)
|
||||
// 删除文件时同步更新父组件
|
||||
const handleChange = (newFileList: UploadFile[]) => {
|
||||
const validUrls = newFileList
|
||||
const newKeys = newFileList
|
||||
.filter((f) => f.status === 'done' && f.objectKey)
|
||||
.map((f) => f.objectKey!);
|
||||
const newUrls = newFileList
|
||||
.filter((f) => f.status === 'done' && f.url)
|
||||
.map((f) => f.url!);
|
||||
|
||||
emit('update:modelValue', validUrls);
|
||||
emit('update:objectKeys', newKeys);
|
||||
emit('update:signedPutURL', newUrls);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -72,15 +72,16 @@ export type ProjectListRes = HttpResponse<{
|
|||
projectsList?: ProjectItem[];
|
||||
}>;
|
||||
export interface CreateProjectParam {
|
||||
id?: number;
|
||||
id?: number | null;
|
||||
type: ProjectType; // 项目类型:1写字楼,2商业综合体,3园区
|
||||
name: string; // 楼栋名称
|
||||
province_id: number | null; // 省份id
|
||||
city_id: number | null; // 城市id
|
||||
district_id: number | null; // 区域id
|
||||
address: string; // 详细地址
|
||||
images: string[]; // 图片数组
|
||||
buildings: BuildingItem[]; // 楼栋数据
|
||||
objectKeys: string[]; // 存储给后端的 key
|
||||
signedPutURL: string[]; // 存储已签名 URL
|
||||
buildings: BuildingItem[];
|
||||
}
|
||||
export interface BuildingInfo extends BaseEntity {
|
||||
projectId: number; // 项目id
|
||||
|
|
|
|||
|
|
@ -104,12 +104,13 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
<a-form-item label="项目图片" field="images">
|
||||
<a-form-item label="项目图片" field="objectKeys">
|
||||
<ImageUpload
|
||||
v-model="form.images"
|
||||
v-model:object-keys="form.objectKeys"
|
||||
v-model:signed-put-u-r-l="form.signedPutURL"
|
||||
:upload-type="2"
|
||||
:max-count="5"
|
||||
:list-type="'picture-card'"
|
||||
list-type="picture-card"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
|
|
@ -214,13 +215,15 @@
|
|||
const formRef = ref<FormInstance>();
|
||||
|
||||
const defaultForm: CreateProjectParam = {
|
||||
id: null,
|
||||
type: 1 as ProjectType, // 项目类型:1写字楼,2商业综合体,3园区
|
||||
name: '', // 楼栋名称
|
||||
province_id: null, // 省份id
|
||||
city_id: null, // 城市id
|
||||
district_id: null, // 区域id
|
||||
address: '', // 详细地址
|
||||
images: [], // 图片数组
|
||||
objectKeys: [], // 图片数组
|
||||
signedPutURL: [], // 图片数组
|
||||
buildings: [createEmptyBuilding()], // 楼栋数据
|
||||
};
|
||||
const form = reactive<CreateProjectParam>({ ...defaultForm });
|
||||
|
|
@ -306,7 +309,7 @@
|
|||
});
|
||||
}
|
||||
if (record?.imageUrls?.length) {
|
||||
record.images = record?.imageUrls;
|
||||
record.objectKeys = record?.imageUrls;
|
||||
}
|
||||
form.name = record.name;
|
||||
Object.keys(form).forEach((key) => {
|
||||
|
|
@ -330,7 +333,6 @@
|
|||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const handleOk = async () => {
|
||||
if (isLoading.value) return;
|
||||
try {
|
||||
|
|
@ -345,9 +347,10 @@
|
|||
id: item?.id,
|
||||
};
|
||||
});
|
||||
const params = {
|
||||
const params: any = {
|
||||
...form,
|
||||
};
|
||||
delete params.signedPutURL;
|
||||
const res = props?.isEdit
|
||||
? await updateProject(params)
|
||||
: await createProject(params);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue