2025-05-07 16:02:10 +08:00

594 lines
21 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>
<div class="app-container">
<!-- 统计数据展示区域 -->
<!-- <el-row :gutter="20" class="statistics-row">
<el-col :span="4">
<div class="stat-card">
<div class="stat-label">管理面积</div>
<div class="stat-value">{{ statistics.managementArea }} </div>
</div>
</el-col>
<el-col :span="4">
<div class="stat-card">
<div class="stat-label">可招商面积</div>
<div class="stat-value">{{ statistics.availableArea }} </div>
</div>
</el-col>
<el-col :span="4">
<div class="stat-card">
<div class="stat-label">可招商占比</div>
<div class="stat-value">{{ statistics.availableRatio }}%</div>
</div>
</el-col>
<el-col :span="4">
<div class="stat-card">
<div class="stat-label">总房源数量</div>
<div class="stat-value">{{ statistics.totalRooms }} </div>
</div>
</el-col>
<el-col :span="4">
<div class="stat-card">
<div class="stat-label">可招商房源数量</div>
<div class="stat-value">{{ statistics.availableRooms }} </div>
</div>
</el-col>
</el-row> ..>
<!-- 搜索区域 -->
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>项目列表</span>
<el-button
style="float: right;"
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd">新增项目</el-button>
</div>
<!-- 搜索表单 -->
<el-form :inline="true" :model="queryParams" class="demo-form-inline">
<el-form-item label="项目名称">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable size="small" />
</el-form-item>
<el-form-item label="项目类型">
<el-select v-model="queryParams.projectType" placeholder="请选择项目类型" clearable size="small">
<el-option label="写字楼" value="写字楼" />
<el-option label="产业园区" value="产业园区" />
<el-option label="商场" value="商场" />
<el-option label="联合办公" value="联合办公" />
<el-option label="公寓" value="公寓" />
<el-option label="小区" value="小区" />
<el-option label="社区养老" value="社区养老" />
</el-select>
</el-form-item>
<!-- <el-form-item label="所属地区">
<region-selector v-model="queryParams.region" :value="queryParams.region" placeholder="请选择所属地区" size="small" @change="handleRegionChange" />
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 表格区域 -->
<el-table v-loading="loading" :data="projectList" border style="width: 100%">
<el-table-column prop="projectName" label="项目名称" />
<el-table-column prop="projectType" label="项目类型" />
<el-table-column prop="region" label="所属地区" />
<el-table-column prop="manageArea" label="管理面积(㎡)" />
<el-table-column prop="availableArea" label="可招商面积(㎡)" />
<el-table-column prop="totalRooms" label="总房源数量" />
<el-table-column prop="availableRooms" label="可招商房源数量" />
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="handleDetail(scope.row)">详情</el-button>
<el-button size="mini" type="text" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryParams.pageNum"
:page-sizes="[10, 20, 50, 100]"
:page-size="queryParams.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
class="pagination">
</el-pagination>
</el-card>
<!-- 新增/编辑对话框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%" @open="onDialogOpen" @close="onDialogClose">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目类型" prop="projectType">
<el-select v-model="form.projectType" placeholder="请选择项目类型" :disabled="form.id !== undefined">
<el-option label="写字楼" value="写字楼" />
<el-option label="产业园区" value="产业园区" />
<el-option label="商场" value="商场" />
<el-option label="联合办公" value="联合办公" />
<el-option label="公寓" value="公寓" />
<el-option label="小区" value="小区" />
<el-option label="社区养老" value="社区养老" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="请输入项目名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目简称" prop="projectShortName">
<el-input v-model="form.projectShortName" placeholder="请输入项目简称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属地区" prop="region">
<region-selector v-model="form.region" placeholder="请选择所属地区" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="详细地址" prop="address">
<el-input v-model="form.address" type="textarea" placeholder="请输入详细地址" />
</el-form-item>
<el-form-item label="项目标签" prop="projectTags">
<el-select v-model="form.projectTags" multiple placeholder="请选择项目标签">
<el-option
v-for="tag in tagOptions"
:key="tag.id"
:label="tag.tagName"
:value="tag.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="项目简介" prop="projectDesc">
<el-input v-model="form.projectDesc" type="textarea" :rows="4" placeholder="请输入项目简介" />
</el-form-item>
<el-form-item label="项目图片" prop="projectImage">
<el-upload
class="avatar-uploader"
action="/api/upload"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload">
<img v-if="form.projectImage" :src="form.projectImage" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</div>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog title="项目详情" :visible.sync="detailVisible" width="50%">
<el-descriptions :column="2" border>
<el-descriptions-item label="项目名称">{{ detail.projectName }}</el-descriptions-item>
<el-descriptions-item label="项目简称">{{ detail.projectShortName }}</el-descriptions-item>
<el-descriptions-item label="项目类型">{{ detail.projectType }}</el-descriptions-item>
<el-descriptions-item label="所属地区">{{ detail.region }}</el-descriptions-item>
<el-descriptions-item label="详细地址">{{ detail.address }}</el-descriptions-item>
<el-descriptions-item label="管理面积">{{ detail.manageArea }}㎡</el-descriptions-item>
<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> -->
<!-- <el-descriptions-item label="物业">{{ detail.property }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="物业费">{{ detail.propertyFee }}元/㎡·月</el-descriptions-item> -->
<!-- <el-descriptions-item label="车位数量">{{ detail.parkingSpaces }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="车位月租金">{{ detail.parkingFee }}元/月</el-descriptions-item> -->
<!-- <el-descriptions-item label="空调">{{ detail.airConditioning }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="空调费">{{ detail.airConditioningFee }}元/㎡·月</el-descriptions-item> -->
<!-- <el-descriptions-item label="空调开放时间">{{ detail.airConditioningTime }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="电梯">{{ detail.elevator }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="网络">{{ detail.network }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="入驻企业">{{ detail.enterprises }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="招商岗位">{{ detail.recruitmentPosition }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="招商部门">{{ detail.recruitmentDepartment }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="VR链接">{{ detail.vrLink }}</el-descriptions-item> -->
<!-- <el-descriptions-item label="招商时间">{{ detail.recruitmentTime }}</el-descriptions-item> -->
<el-descriptions-item label="项目图片" :span="2">
<el-image
v-if="detail.projectImage"
:src="detail.projectImage"
:preview-src-list="[detail.projectImage]"
fit="cover"
style="width: 200px; height: 200px">
</el-image>
</el-descriptions-item>
</el-descriptions>
<div slot="footer" class="dialog-footer">
<el-button @click="detailVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getProjectList, getProjectDetail, addProject, updateProject, deleteProject, getAllProjectStatistics, getTagByType } from '@/api/project'
import RegionSelector from '@/components/RegionSelector'
export default {
name: 'ProjectList',
components: {
RegionSelector
},
data() {
return {
// 遮罩层
loading: false,
// 总条数
total: 0,
// 项目列表
projectList: [],
// 弹出层标题
dialogTitle: '',
// 是否显示弹出层
dialogVisible: false,
// 是否显示详情弹出层
detailVisible: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
projectName: undefined,
projectType: undefined,
region: undefined
},
// 表单参数
form: {},
// 详情数据
detail: {},
// 标签选项
tagOptions: [],
// 表单校验
rules: {
projectType: [
{ required: true, message: '请选择项目类型', trigger: 'change' }
],
projectName: [
{ required: true, message: '请输入项目名称', trigger: 'blur' }
],
projectShortName: [
{ required: true, message: '请输入项目简称', trigger: 'blur' }
],
region: [
{ required: true, message: '请输入所属地区', trigger: 'blur' }
],
address: [
{ required: true, message: '请输入详细地址', trigger: 'blur' }
]
},
// 统计数据
statistics: {
managementArea: '37,234.52',
availableArea: '20,916.2',
availableRatio: '56.17',
totalRooms: '637',
availableRooms: '51'
}
}
},
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()
this.fetchStatistics()
},
methods: {
/** 查询项目列表 */
getList() {
this.loading = true
const params = {
pageNum: this.queryParams.pageNum,
pageSize: this.queryParams.pageSize,
projectName: this.queryParams.projectName,
projectType: this.queryParams.projectType,
region: this.queryParams.region
}
getProjectList(params).then(res => {
this.projectList = res.data.list
this.total = res.data.total
this.loading = false
}).catch(() => {
this.loading = false
})
},
/** 获取标签选项 */
getTagOptions() {
return new Promise((resolve) => {
getTagByType({ tagType: '项目标签',tagName: '项目标签' }).then(res => {
this.tagOptions = res.data || [];
resolve(this.tagOptions);
}).catch(() => {
this.tagOptions = [
{ id: '1', tagName: '标签1' },
{ id: '2', tagName: '标签2' }
];
resolve(this.tagOptions);
});
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
projectName: undefined,
projectType: undefined,
region: undefined
}
this.handleQuery()
},
/** 新增按钮操作 */
handleAdd() {
this.dialogTitle = '新增项目'
// 完全重置表单数据
this.form = {
region: '' // 初始化region为空字符串以确保组件正确绑定
}
this.dialogVisible = true
},
/** 修改按钮操作 */
handleEdit(row) {
this.dialogTitle = '编辑项目'
getProjectDetail(row.id).then(res => {
// 处理从后端返回的项目标签,将逗号分隔的字符串转为数组
const projectData = { ...res.data };
if (typeof projectData.projectTags === 'string' && projectData.projectTags) {
projectData.projectTags = projectData.projectTags.split(',');
} else if (!projectData.projectTags) {
projectData.projectTags = [];
}
this.form = projectData;
this.dialogVisible = true;
})
},
/** 详情按钮操作 */
async handleDetail(row) {
// 确保标签选项已加载
if (this.tagOptions.length === 0) {
await this.getTagOptions();
}
getProjectDetail(row.id).then(res => {
// 处理项目详情数据,确保标签显示友好
const detailData = { ...res.data };
// 如果标签是字符串,则保持原样,用于显示
if (typeof detailData.projectTags === 'string' && detailData.projectTags) {
// 可以在这里处理标签的显示格式,如果需要的话
} else if (Array.isArray(detailData.projectTags)) {
// 如果是数组,转为逗号分隔的字符串
detailData.projectTags = detailData.projectTags.join(',');
}
this.detail = detailData;
this.detailVisible = true;
})
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm('是否确认删除该项目?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteProject(row.id).then(() => {
this.getList()
})
}).catch(() => {})
},
/** 表单提交 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
// 处理项目标签,将数组转为逗号分隔的字符串
const formData = { ...this.form };
if (Array.isArray(formData.projectTags)) {
formData.projectTags = formData.projectTags.join(',');
}
// 如果表单有ID则为编辑操作否则为新增操作
const isEdit = formData.id !== undefined;
const method = isEdit ? updateProject(formData.id, formData) : addProject(formData);
method.then(() => {
this.dialogVisible = false;
this.getList();
});
}
});
},
/** 图片上传成功处理 */
handleImageSuccess(res, file) {
// 假设后端返回了图片URL
this.form.projectImage = res.data
},
/** 图片上传前处理 */
beforeImageUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
const isLt2M = file.size / 1024 / 1024 < 2
if (!isJPG) {
this.$message.error('上传图片只能是 JPG/PNG 格式!')
}
if (!isLt2M) {
this.$message.error('上传图片大小不能超过 2MB!')
}
return isJPG && isLt2M
},
/** 分页大小改变 */
handleSizeChange(val) {
this.queryParams.pageSize = val
this.getList()
},
/** 分页页码改变 */
handleCurrentChange(val) {
this.queryParams.pageNum = val
this.getList()
},
/** 获取统计数据 */
async fetchStatistics() {
try {
const res = await getAllProjectStatistics()
this.statistics = {
managementArea: res.data.manageArea || '0',
availableArea: res.data.availableArea || '0',
availableRatio: res.data.availableArea && res.data.manageArea
? ((res.data.availableArea / res.data.manageArea) * 100).toFixed(2)
: '0',
totalRooms: res.data.totalRooms || '0',
availableRooms: res.data.availableRooms || '0'
}
} catch (error) {
console.error('获取统计数据失败:', error)
// 使用默认数据
this.statistics = {
managementArea: '37,234.52',
availableArea: '20,916.2',
availableRatio: '56.17',
totalRooms: '637',
availableRooms: '51'
}
}
},
/** 对话框打开时处理 */
onDialogOpen() {
// 只重置校验状态,不清空表单数据
this.$nextTick(() => {
this.$refs['form'] && this.$refs['form'].clearValidate()
})
},
/** 对话框关闭时处理 */
onDialogClose() {
// 重置表单和校验状态
this.form = {}
this.$refs['form'].clearValidate()
},
handleRegionChange(regionText) {
this.queryParams.region = regionText
}
}
}
</script>
<style lang="scss" scoped>
.statistics-row {
margin-bottom: 20px;
.stat-card {
background: #fff;
padding: 20px;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
text-align: center;
.stat-label {
color: #606266;
font-size: 14px;
margin-bottom: 10px;
}
.stat-value {
color: #303133;
font-size: 20px;
font-weight: bold;
}
}
}
/* 确保下拉框和输入框宽度一致 */
::v-deep .el-form-item {
.el-select {
width: 100%;
}
.el-input {
width: 100%;
}
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
.pagination {
margin-top: 15px;
text-align: right;
}
</style>