初始化项目 #1
BIN
pc/public.zip
Normal file
BIN
pc/public.zip
Normal file
Binary file not shown.
54
pc/src/api/resource.js
Normal file
54
pc/src/api/resource.js
Normal file
@ -0,0 +1,54 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 上传附件
|
||||
* @param {File} file 文件对象
|
||||
* @returns {Promise} 返回包含fileId和fileName的Promise
|
||||
*/
|
||||
export function uploadAttachment(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: '/resource/attachment/uploadAttachment',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载附件
|
||||
* @param {string} fileId 文件ID
|
||||
* @returns {Promise} 返回文件流的Promise
|
||||
*/
|
||||
export function downloadAttachment(fileId) {
|
||||
return request({
|
||||
url: `/resource/attachment/downloadAttachment?fileId=${fileId}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除附件
|
||||
* @param {Array} fileIds 文件ID数组
|
||||
* @returns {Promise} 返回操作结果的Promise
|
||||
*/
|
||||
export function batchDeleteAttachment(fileIds) {
|
||||
return request({
|
||||
url: '/resource/attachment/batchDeleteAttachment',
|
||||
method: 'post',
|
||||
data: fileIds
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个附件
|
||||
* @param {string} fileId 文件ID
|
||||
* @returns {Promise} 返回操作结果的Promise
|
||||
*/
|
||||
export function deleteAttachment(fileId) {
|
||||
return batchDeleteAttachment([fileId])
|
||||
}
|
@ -11,13 +11,36 @@ Vue.config.productionTip = false
|
||||
|
||||
// 添加下载方法
|
||||
Vue.prototype.download = function(res, fileName) {
|
||||
// 创建blob链接
|
||||
const blob = new Blob([res])
|
||||
// 检查响应类型
|
||||
if (res.type && (res.type === 'application/vnd.ms-excel' ||
|
||||
res.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
|
||||
res.type.includes('excel') ||
|
||||
res.type === 'application/octet-stream')) {
|
||||
// 如果已经是Blob类型且是Excel类型,直接使用
|
||||
const blob = res
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = fileName
|
||||
link.click()
|
||||
URL.revokeObjectURL(link.href)
|
||||
} else {
|
||||
// 如果不是Blob类型或无法确定类型,根据文件扩展名处理
|
||||
let blob
|
||||
if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) {
|
||||
// Excel文件需要使用二进制格式
|
||||
blob = new Blob([res], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
})
|
||||
} else {
|
||||
// 其他类型使用默认处理
|
||||
blob = new Blob([res])
|
||||
}
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = fileName
|
||||
link.click()
|
||||
URL.revokeObjectURL(link.href)
|
||||
}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
|
@ -188,6 +188,17 @@
|
||||
<el-descriptions-item label="可招商面积">{{ detail.availableArea }}㎡</el-descriptions-item>
|
||||
<el-descriptions-item label="总房源数量">{{ detail.totalRooms }}</el-descriptions-item>
|
||||
<el-descriptions-item label="可招商房源数量">{{ detail.availableRooms }}</el-descriptions-item>
|
||||
<el-descriptions-item label="项目标签" :span="2">
|
||||
<el-tag
|
||||
v-for="tag in projectTagList"
|
||||
:key="tag.id"
|
||||
type="success"
|
||||
size="medium"
|
||||
style="margin-right: 8px; margin-bottom: 5px;">
|
||||
{{ tag.tagName }}
|
||||
</el-tag>
|
||||
<span v-if="!projectTagList || projectTagList.length === 0">暂无标签</span>
|
||||
</el-descriptions-item>
|
||||
<!-- <el-descriptions-item label="排序值">{{ detail.sort }}</el-descriptions-item> -->
|
||||
<!-- <el-descriptions-item label="竣工时间">{{ detail.completionTime }}</el-descriptions-item> -->
|
||||
<!-- <el-descriptions-item label="标准层高">{{ detail.standardHeight }}m</el-descriptions-item> -->
|
||||
@ -287,6 +298,25 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 项目标签列表,用于在详情页展示
|
||||
projectTagList() {
|
||||
if (!this.detail.projectTags || !this.tagOptions || this.tagOptions.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 将逗号分隔的标签ID字符串转为数组
|
||||
const tagIds = typeof this.detail.projectTags === 'string'
|
||||
? this.detail.projectTags.split(',')
|
||||
: this.detail.projectTags;
|
||||
|
||||
// 根据ID查找标签对象
|
||||
return tagIds.map(tagId => {
|
||||
const tag = this.tagOptions.find(t => t.id === tagId);
|
||||
return tag || { id: tagId, tagName: `标签${tagId}` };
|
||||
});
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
this.getTagOptions()
|
||||
@ -314,14 +344,18 @@ export default {
|
||||
},
|
||||
/** 获取标签选项 */
|
||||
getTagOptions() {
|
||||
return new Promise((resolve) => {
|
||||
getTagByType({ tagType: '项目标签',tagName: '项目标签' }).then(res => {
|
||||
this.tagOptions = res.data
|
||||
this.tagOptions = res.data || [];
|
||||
resolve(this.tagOptions);
|
||||
}).catch(() => {
|
||||
this.tagOptions = [
|
||||
{ id: '1', tagName: '标签1' },
|
||||
{ id: '2', tagName: '标签2' }
|
||||
]
|
||||
})
|
||||
];
|
||||
resolve(this.tagOptions);
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
@ -366,7 +400,12 @@ export default {
|
||||
})
|
||||
},
|
||||
/** 详情按钮操作 */
|
||||
handleDetail(row) {
|
||||
async handleDetail(row) {
|
||||
// 确保标签选项已加载
|
||||
if (this.tagOptions.length === 0) {
|
||||
await this.getTagOptions();
|
||||
}
|
||||
|
||||
getProjectDetail(row.id).then(res => {
|
||||
// 处理项目详情数据,确保标签显示友好
|
||||
const detailData = { ...res.data };
|
||||
|
@ -55,11 +55,11 @@
|
||||
|
||||
</el-descriptions>
|
||||
|
||||
<div class="image-section" v-if="roomDetail.imageUrls && roomDetail.imageUrls.length > 0">
|
||||
<div class="image-section" v-if="roomImageUrls && roomImageUrls.length > 0">
|
||||
<div class="section-title">房源图片</div>
|
||||
<el-carousel :interval="4000" type="card" height="200px">
|
||||
<el-carousel-item v-for="(item, index) in roomDetail.imageUrls" :key="index">
|
||||
<img :src="item" class="carousel-image" />
|
||||
<el-carousel-item v-for="(item, index) in roomImageUrls" :key="index">
|
||||
<img :src="item" class="carousel-image" @click="previewImage(item)" />
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
</div>
|
||||
@ -75,11 +75,11 @@
|
||||
<el-descriptions-item label="工位数量">{{ workstationCountRange }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<div class="image-section" v-if="roomDetail.floorPlanImageUrls && roomDetail.floorPlanImageUrls.length > 0">
|
||||
<div class="image-section" v-if="floorPlanImageUrls && floorPlanImageUrls.length > 0">
|
||||
<div class="section-title">户型图</div>
|
||||
<el-carousel :interval="4000" type="card" height="200px">
|
||||
<el-carousel-item v-for="(item, index) in roomDetail.floorPlanImageUrls" :key="index">
|
||||
<img :src="item" class="carousel-image" />
|
||||
<el-carousel-item v-for="(item, index) in floorPlanImageUrls" :key="index">
|
||||
<img :src="item" class="carousel-image" @click="previewImage(item)" />
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
<div class="floor-plan-description" v-if="roomDetail.floorPlanDesc">
|
||||
@ -89,12 +89,18 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<el-dialog :visible.sync="previewVisible" append-to-body>
|
||||
<img width="100%" :src="previewUrl" alt="预览图片">
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRoom } from '@/api/room'
|
||||
import { getTagByType } from '@/api/project'
|
||||
import { downloadAttachment } from '@/api/resource'
|
||||
|
||||
export default {
|
||||
name: 'DetailView',
|
||||
@ -109,7 +115,11 @@ export default {
|
||||
loading: false,
|
||||
activeTab: 'basic',
|
||||
roomDetail: {},
|
||||
tagOptions: []
|
||||
tagOptions: [],
|
||||
roomImageUrls: [],
|
||||
floorPlanImageUrls: [],
|
||||
previewVisible: false,
|
||||
previewUrl: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -245,6 +255,12 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/** 预览图片 */
|
||||
previewImage(url) {
|
||||
this.previewUrl = url
|
||||
this.previewVisible = true
|
||||
},
|
||||
|
||||
getRoomDetail() {
|
||||
if (!this.roomId) return
|
||||
|
||||
@ -263,14 +279,24 @@ export default {
|
||||
Object.assign(this.roomDetail, response.data.extendInfo)
|
||||
}
|
||||
|
||||
// 处理图片
|
||||
// 处理房源图片
|
||||
this.roomImageUrls = []
|
||||
if (response.data.roomImages && Array.isArray(response.data.roomImages)) {
|
||||
this.roomDetail.imageUrls = response.data.roomImages.map(item => item.imageUrl)
|
||||
response.data.roomImages.forEach(item => {
|
||||
if (item.fileId) {
|
||||
this.roomImageUrls.push(`/resource/attachment/downloadAttachment?fileId=${item.fileId}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理户型图
|
||||
this.floorPlanImageUrls = []
|
||||
if (response.data.floorPlanImages && Array.isArray(response.data.floorPlanImages)) {
|
||||
this.roomDetail.floorPlanImageUrls = response.data.floorPlanImages.map(item => item.imageUrl)
|
||||
response.data.floorPlanImages.forEach(item => {
|
||||
if (item.fileId) {
|
||||
this.floorPlanImageUrls.push(`/resource/attachment/downloadAttachment?fileId=${item.fileId}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理标签
|
||||
@ -311,6 +337,7 @@ export default {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.floor-plan-description {
|
||||
|
@ -258,11 +258,21 @@
|
||||
|
||||
|
||||
</el-row>
|
||||
<el-form-item label="房源图片" prop="imageUrls">
|
||||
<el-upload :action="uploadUrl" list-type="picture-card" :headers="uploadHeaders" :file-list="imageList"
|
||||
:on-preview="handlePictureCardPreview" :on-success="handleImageSuccess" :on-remove="handleImageRemove"
|
||||
<el-form-item label="房源图片" prop="imageFiles">
|
||||
<div class="image-upload-tip" v-if="imageList.length >= 6">最多上传6张房源图片</div>
|
||||
<el-upload
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:file-list="imageList"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleImageRemove"
|
||||
:before-upload="handleBeforeImageUpload"
|
||||
:on-change="handleImageChange"
|
||||
:auto-upload="false"
|
||||
:limit="6"
|
||||
ref="imageUpload"
|
||||
multiple>
|
||||
<i class="el-icon-plus"></i>
|
||||
<i v-if="imageList.length < 6" class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
@ -320,11 +330,20 @@
|
||||
@input="handleInputChange" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="户型图" prop="floorPlanImageUrls">
|
||||
<el-upload :action="uploadUrl" list-type="picture-card" :headers="uploadHeaders"
|
||||
:file-list="floorPlanImageList" :on-preview="handlePictureCardPreview"
|
||||
:on-success="handleFloorPlanImageSuccess" :on-remove="handleFloorPlanImageRemove" multiple>
|
||||
<i class="el-icon-plus"></i>
|
||||
<el-form-item label="户型图" prop="floorPlanImageFiles">
|
||||
<div class="image-upload-tip" v-if="floorPlanImageList.length >= 1">最多上传1张户型图</div>
|
||||
<el-upload
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:file-list="floorPlanImageList"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleFloorPlanImageRemove"
|
||||
:before-upload="handleBeforeFloorPlanUpload"
|
||||
:on-change="handleFloorPlanChange"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
ref="floorPlanUpload">
|
||||
<i v-if="floorPlanImageList.length < 1" class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
@ -345,6 +364,7 @@
|
||||
import { getRoom, addRoom, updateRoom, listProjects, listBuildings, listFloors, listRoomTags, listOwners } from '@/api/room'
|
||||
import { getProjectList,getTagByType } from '@/api/project'
|
||||
import { getBuildingList, getFloorList,getFloorListByBuilding} from '@/api/building'
|
||||
import { uploadAttachment, downloadAttachment, deleteAttachment } from '@/api/resource'
|
||||
export default {
|
||||
name: 'RoomForm',
|
||||
props: {
|
||||
@ -381,8 +401,16 @@ export default {
|
||||
ownerOptions: [],
|
||||
// 房源图片列表
|
||||
imageList: [],
|
||||
// 房源图片文件列表
|
||||
imageFiles: [],
|
||||
// 房源图片IDs
|
||||
imageFileIds: [],
|
||||
// 户型图列表
|
||||
floorPlanImageList: [],
|
||||
// 户型图文件列表
|
||||
floorPlanFiles: [],
|
||||
// 户型图IDs
|
||||
floorPlanFileIds: [],
|
||||
// 上传URL
|
||||
uploadUrl: process.env.VUE_APP_BASE_API + '/room/upload',
|
||||
// 上传请求头
|
||||
@ -411,6 +439,7 @@ export default {
|
||||
loadValue: '',
|
||||
tagIds: [],
|
||||
imageUrls: [],
|
||||
imageFileIds: [],
|
||||
businessStatus: '1', // 默认招商
|
||||
availableDate: '',
|
||||
decorationStatus: '4', // 默认标准交付
|
||||
@ -428,7 +457,8 @@ export default {
|
||||
workstationMin: null,
|
||||
workstationMax: null,
|
||||
floorPlanDesc: '',
|
||||
floorPlanImageUrls: []
|
||||
floorPlanImageUrls: [],
|
||||
floorPlanFileIds: []
|
||||
},
|
||||
// 表单校验规则
|
||||
rules: {
|
||||
@ -497,19 +527,41 @@ export default {
|
||||
|
||||
// 处理图片数据
|
||||
this.form.imageUrls = []
|
||||
this.form.imageFileIds = []
|
||||
this.imageList = []
|
||||
this.imageFiles = []
|
||||
this.imageFileIds = []
|
||||
if (response.data.roomImages && Array.isArray(response.data.roomImages) && response.data.roomImages.length > 0) {
|
||||
this.form.imageUrls = response.data.roomImages.map(item => item.imageUrl)
|
||||
this.imageList = response.data.roomImages.map((item, index) => {
|
||||
return { name: '图片' + (index + 1), url: item.imageUrl }
|
||||
response.data.roomImages.forEach((item, index) => {
|
||||
if (item.fileId) {
|
||||
this.form.imageFileIds.push(item.fileId)
|
||||
this.imageFileIds.push(item.fileId)
|
||||
this.imageList.push({
|
||||
name: '图片' + (index + 1),
|
||||
url: `/resource/attachment/downloadAttachment?fileId=${item.fileId}`,
|
||||
fileId: item.fileId
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理户型图数据
|
||||
this.form.floorPlanImageUrls = []
|
||||
this.form.floorPlanFileIds = []
|
||||
this.floorPlanImageList = []
|
||||
this.floorPlanFiles = []
|
||||
this.floorPlanFileIds = []
|
||||
if (response.data.floorPlanImages && Array.isArray(response.data.floorPlanImages) && response.data.floorPlanImages.length > 0) {
|
||||
this.form.floorPlanImageUrls = response.data.floorPlanImages.map(item => item.imageUrl)
|
||||
this.floorPlanImageList = response.data.floorPlanImages.map((item, index) => {
|
||||
return { name: '户型图' + (index + 1), url: item.imageUrl }
|
||||
response.data.floorPlanImages.forEach((item, index) => {
|
||||
if (item.fileId) {
|
||||
this.form.floorPlanFileIds.push(item.fileId)
|
||||
this.floorPlanFileIds.push(item.fileId)
|
||||
this.floorPlanImageList.push({
|
||||
name: '户型图' + (index + 1),
|
||||
url: `/resource/attachment/downloadAttachment?fileId=${item.fileId}`,
|
||||
fileId: item.fileId
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -664,58 +716,166 @@ export default {
|
||||
this.dialogVisible = true
|
||||
},
|
||||
|
||||
/** 房源图片上传成功 */
|
||||
handleImageSuccess(response, file, fileList) {
|
||||
if (response.code === '0000000000000000') {
|
||||
this.form.imageUrls.push(response.data.imageUrl)
|
||||
this.imageList = fileList.map(file => {
|
||||
if (file.response) {
|
||||
return { name: file.name, url: file.response.data.imageUrl }
|
||||
/** 房源图片上传前检查 */
|
||||
handleBeforeImageUpload(file) {
|
||||
const isImage = file.type.indexOf('image/') === 0
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
|
||||
if (!isImage) {
|
||||
this.$message.error('上传图片只能是图片格式!')
|
||||
return false
|
||||
}
|
||||
if (!isLt5M) {
|
||||
this.$message.error('上传图片大小不能超过 5MB!')
|
||||
return false
|
||||
}
|
||||
|
||||
if (this.imageList.length >= 6) {
|
||||
this.$message.error('最多上传6张房源图片!')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
/** 房源图片变化 */
|
||||
handleImageChange(file, fileList) {
|
||||
this.imageFiles = fileList.filter(item => !item.fileId && item.raw)
|
||||
this.imageList = fileList.map(item => {
|
||||
if (item.response) {
|
||||
return {
|
||||
name: item.name,
|
||||
url: `/resource/attachment/downloadAttachment?fileId=${item.response.data.fileId}`,
|
||||
fileId: item.response.data.fileId
|
||||
}
|
||||
} else {
|
||||
return { name: file.name, url: file.url }
|
||||
return item
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message.error('图片上传失败')
|
||||
}
|
||||
},
|
||||
|
||||
/** 房源图片删除 */
|
||||
handleImageRemove(file, fileList) {
|
||||
const url = file.url || (file.response && file.response.data.url)
|
||||
this.form.imageUrls = this.form.imageUrls.filter(item => item !== url)
|
||||
// 如果是已上传的图片,需要从服务器删除
|
||||
if (file.fileId) {
|
||||
this.imageFileIds = this.imageFileIds.filter(id => id !== file.fileId)
|
||||
deleteAttachment(file.fileId).catch(() => {
|
||||
this.$message.error('删除图片失败')
|
||||
})
|
||||
}
|
||||
// 更新文件列表
|
||||
this.imageFiles = this.imageFiles.filter(item => item.uid !== file.uid)
|
||||
this.imageList = fileList
|
||||
},
|
||||
|
||||
/** 户型图上传成功 */
|
||||
handleFloorPlanImageSuccess(response, file, fileList) {
|
||||
if (response.code === '0000000000000000') {
|
||||
this.form.floorPlanImageUrls.push(response.data.imageUrl)
|
||||
this.floorPlanImageList = fileList.map(file => {
|
||||
if (file.response) {
|
||||
return { name: file.name, url: file.response.data.imageUrl }
|
||||
/** 户型图上传前检查 */
|
||||
handleBeforeFloorPlanUpload(file) {
|
||||
const isImage = file.type.indexOf('image/') === 0
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
|
||||
if (!isImage) {
|
||||
this.$message.error('上传户型图只能是图片格式!')
|
||||
return false
|
||||
}
|
||||
if (!isLt5M) {
|
||||
this.$message.error('上传户型图大小不能超过 5MB!')
|
||||
return false
|
||||
}
|
||||
|
||||
if (this.floorPlanImageList.length >= 1) {
|
||||
this.$message.error('最多上传1张户型图!')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
/** 户型图变化 */
|
||||
handleFloorPlanChange(file, fileList) {
|
||||
this.floorPlanFiles = fileList.filter(item => !item.fileId && item.raw)
|
||||
this.floorPlanImageList = fileList.map(item => {
|
||||
if (item.response) {
|
||||
return {
|
||||
name: item.name,
|
||||
url: `/resource/attachment/downloadAttachment?fileId=${item.response.data.fileId}`,
|
||||
fileId: item.response.data.fileId
|
||||
}
|
||||
} else {
|
||||
return { name: file.name, url: file.url }
|
||||
return item
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message.error('户型图上传失败')
|
||||
}
|
||||
},
|
||||
|
||||
/** 户型图删除 */
|
||||
handleFloorPlanImageRemove(file, fileList) {
|
||||
const url = file.url || (file.response && file.response.data.url)
|
||||
this.form.floorPlanImageUrls = this.form.floorPlanImageUrls.filter(item => item !== url)
|
||||
// 如果是已上传的图片,需要从服务器删除
|
||||
if (file.fileId) {
|
||||
this.floorPlanFileIds = this.floorPlanFileIds.filter(id => id !== file.fileId)
|
||||
deleteAttachment(file.fileId).catch(() => {
|
||||
this.$message.error('删除户型图失败')
|
||||
})
|
||||
}
|
||||
// 更新文件列表
|
||||
this.floorPlanFiles = this.floorPlanFiles.filter(item => item.uid !== file.uid)
|
||||
this.floorPlanImageList = fileList
|
||||
},
|
||||
|
||||
/** 上传图片文件 */
|
||||
async uploadImages() {
|
||||
try {
|
||||
// 修改为串行上传图片,而不是并行上传
|
||||
// 先上传房源图片
|
||||
for (const file of this.imageFiles) {
|
||||
if (file.raw) {
|
||||
try {
|
||||
const response = await uploadAttachment(file.raw)
|
||||
if (response.code === '0000000000000000') {
|
||||
this.imageFileIds.push(response.data.fileId)
|
||||
} else {
|
||||
this.$message.error(`房源图片 ${file.name} 上传失败`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传房源图片失败:', error)
|
||||
this.$message.error(`房源图片 ${file.name} 上传失败`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 再上传户型图
|
||||
for (const file of this.floorPlanFiles) {
|
||||
if (file.raw) {
|
||||
try {
|
||||
const response = await uploadAttachment(file.raw)
|
||||
if (response.code === '0000000000000000') {
|
||||
this.floorPlanFileIds.push(response.data.fileId)
|
||||
} else {
|
||||
this.$message.error(`户型图 ${file.name} 上传失败`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传户型图失败:', error)
|
||||
this.$message.error(`户型图 ${file.name} 上传失败`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('上传图片过程中出错:', error)
|
||||
this.$message.error('上传图片过程中出错,请重试')
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/** 提交表单 */
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
this.$refs.form.validate(async valid => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
// 先上传所有图片文件
|
||||
await this.uploadImages()
|
||||
|
||||
// 准备提交数据
|
||||
const formData = {
|
||||
id: this.form.id,
|
||||
@ -767,27 +927,28 @@ export default {
|
||||
tags: this.form.tagIds ? this.form.tagIds.join(',') : ''
|
||||
},
|
||||
|
||||
// 图片信息
|
||||
roomImages: this.form.imageUrls ? this.form.imageUrls.map((url, index) => {
|
||||
// 图片信息 - 使用上传后获取的fileId
|
||||
roomImages: this.imageFileIds.map((fileId, index) => {
|
||||
return {
|
||||
imageUrl: url,
|
||||
fileId: fileId,
|
||||
imageType: '房源图片',
|
||||
sortOrder: index
|
||||
}
|
||||
}) : [],
|
||||
}),
|
||||
|
||||
// 户型图信息
|
||||
floorPlanImages: this.form.floorPlanImageUrls ? this.form.floorPlanImageUrls.map((url, index) => {
|
||||
// 户型图信息 - 使用上传后获取的fileId
|
||||
floorPlanImages: this.floorPlanFileIds.map((fileId, index) => {
|
||||
return {
|
||||
imageUrl: url,
|
||||
fileId: fileId,
|
||||
imageType: '户型图',
|
||||
sortOrder: index
|
||||
}
|
||||
}) : []
|
||||
})
|
||||
}
|
||||
|
||||
const method = this.isEdit ? updateRoom : addRoom
|
||||
method(formData).then(response => {
|
||||
const response = await method(formData)
|
||||
|
||||
if (response.code === '0000000000000000') {
|
||||
this.$message.success(this.isEdit ? '修改成功' : '新增成功')
|
||||
this.$emit('refreshList')
|
||||
@ -795,10 +956,12 @@ export default {
|
||||
} else {
|
||||
this.$message.error(response.msg || (this.isEdit ? '修改失败' : '新增失败'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交表单失败', error)
|
||||
this.$message.error(this.isEdit ? '修改失败' : '新增失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -879,5 +1042,11 @@ export default {
|
||||
::v-deep .el-input-number .el-input__inner {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.image-upload-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -171,6 +171,7 @@
|
||||
:on-progress="handleFileUploadProgress"
|
||||
:on-success="handleFileSuccess"
|
||||
:auto-upload="false"
|
||||
:http-request="customUploadRequest"
|
||||
drag>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
@ -208,6 +209,7 @@
|
||||
import { listRoom, exportRoom, downloadTemplate, importRoom, listRoomTags, listProjects, listBuildings, listFloors, delRoom } from '@/api/room'
|
||||
import { getProjectList,getTagByType } from '@/api/project'
|
||||
import { getBuildingList,getFloorList,getFloorListByBuilding } from '@/api/building'
|
||||
import axios from 'axios'
|
||||
|
||||
import DetailView from './components/DetailView'
|
||||
import RoomForm from './components/RoomForm'
|
||||
@ -558,14 +560,26 @@ export default {
|
||||
this.upload.isUploading = false
|
||||
this.$refs.upload.clearFiles()
|
||||
this.importOpen = false
|
||||
|
||||
// 检查响应是否为Blob类型(文件流)
|
||||
if (response instanceof Blob) {
|
||||
// 是文件流,直接下载错误文件
|
||||
this.$alert('导入失败,正在下载错误文件', '导入结果', { type: 'error' })
|
||||
this.download(response, `房源导入错误文件_${new Date().getTime()}.xlsx`)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查响应码
|
||||
if (response.code === '0000000000000000') {
|
||||
this.$alert(`response.data.message `, { type: 'success' })
|
||||
this.$alert(response.data.message || '导入成功', '导入结果', { type: 'success' })
|
||||
this.getList()
|
||||
} else {
|
||||
// 如果是文件流,则下载错误文件
|
||||
|
||||
this.$alert(response.msg || '导入失败,正在下载错误文件', '导入结果', { type: 'error' })
|
||||
this.download(response, `房源导入错误文件_${new Date().getTime()}.xlsx`)
|
||||
// 如果是普通错误响应
|
||||
this.$alert(response.msg || '导入失败', '导入结果', { type: 'error' })
|
||||
// 如果有错误文件,下载错误文件
|
||||
if (response.data && response.data.errorFile) {
|
||||
this.download(response.data.errorFile, `房源导入错误文件_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -639,6 +653,62 @@ export default {
|
||||
'5': '元/年'
|
||||
};
|
||||
return unitMap[unitType] || '';
|
||||
},
|
||||
|
||||
/** 自定义上传请求 */
|
||||
customUploadRequest(options) {
|
||||
this.upload.isUploading = true
|
||||
const { file, onSuccess, onError, onProgress } = options
|
||||
|
||||
// 创建FormData
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
// 使用axios发送请求,设置responseType为blob
|
||||
axios.post(this.upload.url, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
...this.upload.headers
|
||||
},
|
||||
responseType: 'blob', // 指定响应类型为blob
|
||||
onUploadProgress: (progressEvent) => {
|
||||
onProgress({
|
||||
percent: (progressEvent.loaded / progressEvent.total * 100).toFixed(2)
|
||||
})
|
||||
}
|
||||
}).then(response => {
|
||||
// 检查响应头,判断是否为Excel文件
|
||||
const contentType = response.headers['content-type']
|
||||
const contentDisposition = response.headers['content-disposition']
|
||||
|
||||
// 如果是Excel文件,表示导入失败,返回错误文件
|
||||
if (contentType && (
|
||||
contentType.includes('excel') ||
|
||||
contentType.includes('spreadsheetml') ||
|
||||
contentType === 'application/octet-stream')) {
|
||||
// 返回Blob对象
|
||||
onSuccess(response.data)
|
||||
} else {
|
||||
// 是JSON响应,需要解析
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
try {
|
||||
const jsonResponse = JSON.parse(reader.result)
|
||||
onSuccess(jsonResponse)
|
||||
} catch (error) {
|
||||
// 如果无法解析为JSON,则视为二进制文件
|
||||
onSuccess(response.data)
|
||||
}
|
||||
}
|
||||
reader.onerror = () => {
|
||||
onError(new Error('解析响应失败'))
|
||||
}
|
||||
reader.readAsText(response.data)
|
||||
}
|
||||
}).catch(error => {
|
||||
onError(error)
|
||||
this.upload.isUploading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ module.exports = {
|
||||
},
|
||||
proxy: {
|
||||
'/': {
|
||||
// target: 'http://192.168.137.3:8082/api',
|
||||
target: 'http://192.168.137.45:8080',
|
||||
target: 'http://192.168.137.3:8080/api/api',
|
||||
// target: 'http://192.168.137.45:8080',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': '/api'
|
||||
|
Loading…
x
Reference in New Issue
Block a user