后台管理系统-园区管理

功能演示和模版搭建

<template><div class="building-container"><!-- 搜索区域 --><div class="search-container"><div class="search-label">企业名称:</div><el-input clearable placeholder="请输入内容" class="search-main"/><el-button type="primary">查询</el-button></div><div class="create-container"><el-button type="primary" >添加企业</el-button></div><!-- 表格区域 --><div class="table"><el-table style="width: 100%" :data="[]"><el-table-column type="index" label="序号" /><el-table-column label="企业名称" width="320" prop="name" /><el-table-column label="联系人" prop="contact" /><el-table-columnlabel="联系电话"prop="contactNumber"/><el-table-column label="操作"><template #default="scope"><el-button size="mini" type="text">添加合同</el-button><el-button size="mini" type="text">查看</el-button><el-button size="mini" type="text">编辑</el-button><el-button size="mini" type="text">删除</el-button></template></el-table-column></el-table></div><div class="page-container"><el-paginationlayout="total, prev, pager, next"/></div></div></template><style lang="scss" scoped>
.department-container {padding: 10px;
}.search-container {display: flex;align-items: center;border-bottom: 1px solid rgb(237, 237, 237, .9);;padding-bottom: 20px;.search-label {width: 100px;}.search-main {width: 220px;margin-right: 10px;}
}
.create-container{margin: 10px 0px;
}
.page-container{padding:4px 0px;text-align: right;
}
.form-container{padding:0px 80px;
}
</style>

渲染基础Table列表

1. 封装获取企业列表接口

import request from '@/utils/request'/*** 获取企业列表* @param { page, pageSize} params* @returns*/
export function getEnterpriseListAPI(params) {return request({url: '/park/enterprise',params})
}

2. 组件中获取数据

<script>
import { getEnterpriseListAPI } from '@/apis/enterprise'
export default {name: 'Building',data() {return {exterpriseList: [],params: {page: 1,pageSize: 10}}},mounted() {this.getExterpriseList()},methods: {async getExterpriseList() {const res = await getEnterpriseListAPI(this.params)this.exterpriseList = res.data.rows}}
}
</script>

3. 绑定模版

核心思路:

  1. 通过data属性给el-table组件绑定数据列表
  1. 通过prop属性指定当前列要渲染的字段名称(参考接口文档)
<template><div class="building-container"><!-- 表格区域 --><div class="table"><el-table style="width: 100%" :data="exterpriseList"><el-table-column type="index" label="序号" /><el-table-column label="企业名称" width="320" prop="name" /><el-table-column label="联系人" prop="contact" /><el-table-columnlabel="联系电话"prop="contactNumber"/><el-table-column label="操作"><template #default="scope"><el-button size="mini" type="text">添加合同</el-button><el-button size="mini" type="text">查看</el-button><el-button size="mini" type="text">编辑</el-button><el-button size="mini" type="text">删除</el-button></template></el-table-column></el-table></div></div></template>

分页管理

1. 渲染分页

页数 = 总数 / 每页条数

data() {return {total: 0}
}async getExterpriseList() {const res = await getEnterpriseListAPI(this.params)this.exterpriseList = res.data.rowsthis.total = res.data.total
}<el-paginationlayout="total, prev, pager, next":total="total":page-size="params.pageSize"
/>

2. 点击实现分页切换

实现思路:

  1. 通过事件拿到当前页数
  1. 以当前页数作为参数发送数据请求获取当前页数据
  1. 重新把列表交给buildingList
<el-pagination@current-change="pageChange"
/>pageChange(page) {// 更改参数this.params.page = page// 重新获取数据渲染this.getExterpriseList()
}

查询搜索

业务背景:

  1. 用户输入查询内容之后点击查询按钮以当前输入关键词做为参数获取数据
  1. 点击清空按钮时复原初始数据

思路:作为查询的name其实也是一个接口参数,通过input双向绑定,然后通过它来获取数据重新渲染列表

// 增加新的name查询字段
data() {return {params: {page: 1,pageSize: 10,name: '' // 增加字段name}}
}// 绑定查询回调
<div class="search-container"><div class="search-label">企业名称:</div><el-input v-model="params.name" clearable placeholder="请输入内容" class="search-main" @clear="doSearch" /><el-button type="primary" @click="doSearch">查询</el-button></div>// 准备查询后调方法
doSearch() {this.params.page = 1this.getExterpriseList()
}

添加企业

1. 功能演示和绑定路由

准备组件

<template><div class="add-enterprise"><header class="add-header"><div class="left"><span class="arrow" @click="$router.back()"><i class="el-icon-arrow-left" />返回</span><span>|</span><span>添加企业</span></div><div class="right">黑马程序员</div></header><main class="add-main"><div class="form-container"><div class="title">企业信息</div><div class="form"><el-form ref="ruleForm" label-width="100px"><el-form-item label="企业名称" prop="name"><el-input v-model="addForm.name" /></el-form-item><el-form-item label="法人" prop="name"><el-input v-model="addForm.legalPerson" /></el-form-item><el-form-item label="注册地址" prop="name"><el-input v-model="addForm.registeredAddress" /></el-form-item><el-form-item label="所在行业" prop="name"><el-select v-model="addForm.industryCode" /></el-form-item><el-form-item label="企业联系人" prop="name"><el-input v-model="addForm.contact" /></el-form-item><el-form-item label="联系电话" prop="name"><el-input v-model="addForm.contactNumber" /></el-form-item><el-form-item label="营业执照" prop="name" /></el-form></div></div></main><footer class="add-footer"><div class="btn-container"><el-button>重置</el-button><el-button type="primary">确定</el-button></div></footer></div></template><script>
export default {data() {return {addForm: {name: '', // 企业名称legalPerson: '', // 法人registeredAddress: '', // 注册地址industryCode: '', // 所在行业contact: '', // 企业联系人contactNumber: '', // 联系人电话businessLicenseUrl: '', // 营业执照urlbusinessLicenseId: '' // 营业执照id}}}
}
</script><style scoped lang="scss">
.add-enterprise {background-color: #f4f6f8;height: 100vh;.add-header {display: flex;justify-content: space-between;padding: 0 20px;height: 64px;line-height: 64px;font-size: 16px;font-weight: bold;background-color: #fff;.left {span {margin-right: 4px;}.arrow{cursor: pointer;}}.right {text-align: right;}}.add-main {background: #f4f6f8;padding: 20px 130px;.form-container {background-color: #fff;.title {height: 60px;line-height: 60px;padding-left:20px;}.form {margin-bottom: 20px;padding: 20px 65px 24px;.el-form{display: flex;flex-wrap: wrap;.el-form-item{width: 50%;}}}}}.add-footer {position: fixed;bottom: 0;width: 100%;padding: 24px 50px;color: #000000d9;font-size: 14px;background: #fff;text-align: center;}
}
</style>

绑定路由

 {path: '/exterpriseAdd',component: () => import('@/views/park/enterprise/Add')
}

路由跳转

 <el-button type="primary" @click="$router.push('/exterpriseAdd')">添加企业</el-button>

2. 行业字段渲染


封装接口


/*** 获取行业列表* @returns*/
export function getIndustryListAPI() {return request({url: '/park/industry'})
}

获取数据

<script>
import { getIndustryListAPI } from '@/api/enterprise'
export default {data() {return {industryList: [] // 可选行业列表}},mounted() {this.getIndustryList()},methods: {async getIndustryList() {const res = await getIndustryListAPI()this.industryList = res.data}}
}
</script>

绑定下拉框

 <el-form-item label="所在行业" prop="name"><el-select v-model="addForm.industryCode"><el-optionv-for="item in industryList":key="item.industryCode":value="item.industryCode":label="item.industryName"/></el-select></el-form-item>

测试效果

3. 营业执照上传基础功能实现


 


封装上传接口

/*** 上传合同* @returns*/
export function uploadAPI(data) {return request({url: '/upload',method: 'POST',data})
}

准备自定义上传组件

<el-form-item label="营业执照"><el-uploadaction="#":http-request="uploadRequest"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div></el-upload></el-form-item>

调用接口完成上传

import { getIndustryListAPI, uploadAPI } from '@/apis/enterprise'async uploadRequest(data) {const file = data.file// 处理formData类型参数const formData = new FormData()formData.append('file', file)formData.append('type', 'businessLicense')const res = await uploadAPI(formData)// 赋值表单数据this.addForm.businessLicenseId = res.data.idthis.addForm.businessLicenseUrl = res.data.url
}

验证字段覆盖

4. 上传前验证文件

业务背景:通常上传的文件需要我们用程序做一些限制,防止用户选择并不符合要求的文件

// 绑定上传前回调
<el-uploadaction="#":http-request="uploadRequest":before-upload="beforeUpload"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">支持扩展名:.png .jpg .jpeg,文件大小不得超过5M</div></el-upload>// 编写校验逻辑
beforeUpload(file) {const allowImgType = ['image/jpeg', 'image/png', 'image/jpg'].includes(file.type)const isLt5M = file.size / 1024 / 1024 < 5if (!allowImgType) {this.$message.error('上传合同图片只能是 PNG/JPG/JPEG 格式!')}if (!isLt5M) {this.$message.error('上传合同图片大小不能超过 5MB!')}return allowImgType && isLt5M
}

5. 表单校验

业务背景:表单字段可以分为两类:1. 直接通过element默认配置即可解决 2. 需要单独校验的字段

1. 表单基础校验

// 1. 创建表单规则
data() {return {addRules: {name: [{ required: true, message: '企业名称为必填', trigger: 'blur' }],legalPerson: [{ required: true, message: '法人为必填', trigger: 'blur' }],registeredAddress: [{ required: true, message: '注册地址为必填', trigger: 'blur' }],industryCode: [{ required: true, message: '所在行业为必填', trigger: 'change' }],contact: [{ required: true, message: '企业联系人为必填', trigger: 'blur' }],contactNumber: [{ required: true, message: '企业联系人电话为必填', trigger: 'blur' }],businessLicenseId: [{ required: true, message: '请上传营业执照', trigger: 'blur' }]}}
}// 2. 绑定表单规则
<el-form :model="addForm" :rules="addRules" label-width="100px"><el-form-item label="企业名称" prop="name"><el-input v-model="addForm.name" /></el-form-item><el-form-item label="法人" prop="legalPerson"><el-input v-model="addForm.legalPerson" /></el-form-item><el-form-item label="注册地址" prop="registeredAddress"><el-input v-model="addForm.registeredAddress" /></el-form-item><el-form-item label="所在行业" prop="industryCode"><el-select v-model="addForm.industryCode"><el-optionv-for="item in industryList":key="item.industryCode":value="item.industryCode":label="item.industryName"/></el-select></el-form-item><el-form-item label="企业联系人" prop="contact"><el-input v-model="addForm.contact" /></el-form-item><el-form-item label="联系电话" prop="contactNumber"><el-input v-model="addForm.contactNumber" /></el-form-item><el-form-item label="营业执照" prop="businessLicenseId"><el-uploadaction="#":http-request="uploadRequest":before-upload="beforeUpload"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">支持扩展名:.png .jpg .jpeg,文件大小不得超过5M</div></el-upload></el-form-item></el-form>

2. 统一校验

点击确认按钮 统一校验所有项
核心:获取到表单组件实例对象 -> 调用实例方法(validate)

<el-form ref="ruleForm"></el-form><el-button type="primary" @click="confirmSubmit">确定</el-button>confirmSubmit() {this.$refs.ruleForm.validate(valid => {console.log(valid)})
}

3. 正则校验手机号

场景:复杂的校验场景,默认的那些规则不够用,组件提供了通过自定义校验函数方式

const validatePhone = (rule, value, callback) => {if (/^1[3-9]\d{9}$/.test(value)) {callback()} else {callback(new Error('请输入正常的手机号'))}
}contactNumber: [{ required: true, message: '企业联系人电话为必填', trigger: 'blur' },{ validator: validatePhone, trigger: 'blur' }
]

4. 上传完毕单独校验营业执照字段

业务背景: 上传营业执照完毕之后并不能让校验痕迹消失掉,愿意是因为el-form表单校验系统不能得到上传之后的通知
解决办法:在上传完毕之后手动校验营业执照字段

async uploadRequest(data) {// 上传逻辑...// 单独校验表单,清除错误信息this.$refs.ruleForm.validateField('businessLicenseId')
}

5. 提交表单

收集表单数据 - 调用接口 - 提示用户+返回列表页显示新项

1-封装新增接口

/*** 创建公司* @param {*} data* @returns*/
export function createExterpriseAPI(data) {return request({url: '/park/enterprise',method: 'POST',data})
}

2-点击提交

confirmSubmit() {this.$refs.ruleForm.validate(async valid => {if (!valid) return// 1. 调用接口await createExterpriseAPI(this.addForm)// 2. 返回列表页this.$router.back()})
}

编辑企业

提供用户二次修改的机会 把一些已经存在的数据进行更新操作
编辑和新增:

  1. 大部分的东西是可以复用的 表单的结构 表单校验逻辑 提交逻辑
  1. 编辑的时候需要做数据回填 用到当前要编辑谁 把它的id拿过来

携带参数跳转编辑页

<el-button size="mini" type="text" @click="editRent(scope.row.id)">编辑</el-button>editRent(id) {this.$router.push({path: '/exterpriseAdd',query: {id}})
}

根据id适配文案显示

如果参数有id代表当前是编辑状态,如果没有则是新增状态

<el-page-header :content="`${id?'编辑企业':'添加企业'}`" @back="$router.back()" />computed: {id() {return this.$route.query.id}
}

回填企业数据


1- 封装接口

/*** 获取合同详情* @param {*} id* @returns*/
export function getEnterpriseDetailAPI(id) {return request({url: `/park/enterprise/${id}`})
}

2- 调用接口回填数据

async getEnterpriseDetail() {const res = await getEnterpriseDetailAPI(this.rentId)const { businessLicenseId, businessLicenseUrl, contact, contactNumber, industryCode, legalPerson, name, registeredAddress } = res.datathis.addForm = { businessLicenseId, businessLicenseUrl, contact, contactNumber, industryCode, legalPerson, name, registeredAddress }
}mounted() {// 省略代码 有合同id 调用详情接口if (this.Id) {this.getEnterpriseDetail()}
}

编辑确认修改

根据编辑和新增状态,调用不同借口

1- 封装编辑更新接口

/*** 更新企业* @param {*} data* @returns*/
export function updateExterpriseAPI(data) {return request({url: '/park/enterprise',method: 'PUT',data})
}

2- 区分状态接口提交

confirmSubmit() {this.$refs.ruleForm.validate(async valid => {console.log(valid)if (this.id) {// 编辑await updateExterpriseAPI({...this.addForm,id: this.Id})} else {// 新增await createExterpriseAPI(this.addForm)}this.$router.back()})
}

删除功能实现


1- 封装接口函数

/*** 删除企业* @param {*} id* @returns*/
export function delExterpriseAPI(id) {return request({url: `/park/enterprise/${id}`,method: 'DELETE'})
}

2- 绑定事件执行删除

<el-table-column label="操作"><template #default="scope"><el-button size="mini" type="text">添加合同</el-button><el-button size="mini" type="text">查看</el-button><el-button size="mini" type="text">编辑</el-button><el-button size="mini" type="text" @click="delExterprise(scope.row.id)">删除</el-button></template></el-table-column>delExterprise(id) {this.$confirm('确认删除该企业吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async() => {await delExterpriseAPI(id)this.getExterpriseList()this.$message({type: 'success',message: '删除成功!'})})
}

创建合同

控制弹框打开关闭

通过 visible 属性的true和false切换打开关闭弹框

<el-button size="mini" type="text" @click="addRent()">添加合同</el-button><el-dialogtitle="添加合同":visible="rentDialogVisible"width="580px"@close="closeDialog"><!-- 表单区域 --><div class="form-container"></div><template #footer><el-button size="mini" @click="closeDialog">取 消</el-button><el-button size="mini" type="primary">确 定</el-button></template></el-dialog>data(){return {rentDialogVisible:false}
}methods:{// 打开addRent(){this.rentDialogVisible = true},// 关闭closeDialog(){this.rentDialogVisible = false}
}

准备表单

<!-- 表单模版 -->
<div class="form-container"><el-form ref="addForm" :model="rentForm" :rules="rentRules" label-position="top"><el-form-item label="租赁楼宇" prop="buildingId"><el-select v-model="rentForm.buildingId" placeholder="请选择"><el-optionv-for="item in []":key="item.id":label="item.name":value="item.id"/></el-select></el-form-item><el-form-item label="租赁起止日期" prop="rentTime"><el-date-pickerv-model="rentForm.rentTime"type="daterange"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"value-format="yyyy-MM-dd"/></el-form-item><el-form-item label="租赁合同" prop="contractId"><el-uploadaction="#"><el-button size="small" type="primary" plain>上传合同文件</el-button><div slot="tip" class="el-upload__tip">支持扩展名:.doc .docx .pdf, 文件大小不超过5M</div></el-upload></el-form-item></el-form></div>data(){return {rentForm: {buildingId: null, // 楼宇idcontractId: null, // 合同idcontractUrl: '', // 合同UrlenterpriseId: null, // 企业名称type: 0, // 合同类型rentTime: [] // 合同时间},rentRules: {buildingId: [{ required: true, message: '请选择楼宇', trigger: 'change' }],rentTime: [{ required: true, message: '请选择租赁日期', trigger: 'change' }],contractId: [{ required: true, message: '请上传合同文件' }]}}
}

获取楼宇下拉框数据


1- 封装获取楼宇列表接口

/*** 获取楼宇列表* @param {*} id* @returns*/
export function getRentBuildListAPI() {return request({url: '/park/rent/building'})
}

2- 打开弹框时调用接口

import { getRentBuildListAPI } from '@/apis/enterprise'// 打开弹框
async addRent(enterpriseId) {this.rentDialogVisible = true// 获取楼宇下拉列表const res = await getRentBuildListAPI()this.buildList = res.data
}

3- 渲染下拉列表视图模版

<el-form-item label="租赁楼宇" prop="buildingId"><el-select v-model="rentForm.buildingId" placeholder="请选择"><el-optionv-for="item in buildList":key="item.id":label="item.name":value="item.id"/></el-select></el-form-item>

上传合同文件

  1. 把文件处理为FormData类型
  1. 上传文件并保存返回的合同文件id和url地址
  1. 单独校验表单字段
<el-form-item label="租赁合同" prop="contractId"><el-uploadaction="#":http-request="uploadHandle"><el-button size="small" type="primary" plain>上传合同文件</el-button><div slot="tip" class="el-upload__tip">支持扩展名:.doc .docx .pdf, 文件大小不超过5M</div></el-upload></el-form-item// 上传合同
async uploadHandle(fileData) {// 1. 处理FormDataconst { file } = fileDataconst formData = new FormData()formData.append('file', file)formData.append('type', 'contract')// 2. 上传并赋值const res = await uploadAPI(formData)const { id, url } = res.datathis.rentForm.contractId = idthis.rentForm.contractUrl = url// 单独校验表单
this.$refs.addForm.validate('contractId')}

提交表单创建合同

重点:按照后端接口要求,处理数据再做提交

1- 封装接口

/*** 创建合同* @param {*}* @returns*/
export function createRentAPI(data) {return request({url: '/park/enterprise/rent',method: 'POST',data})
}

2- 补充企业id参数

<el-button size="mini" type="text" @click="addRent(row.id)">添加合同</el-button>// 添加合同
addRent(id) {this.dialogVisible = true// 把企业id存入表单对象this.rentForm.enterpriseId = id
}

3- 处理参数提交表单

 // 确认提交
confirmAdd() {this.$refs.addForm.validate(async valid => {if (valid) {const { buildingId, contractId, contractUrl, enterpriseId, type } = this.rentFormawait createRentAPI({buildingId, contractId, contractUrl, enterpriseId, type,startTime: this.rentForm.rentTime[0],endTime: this.rentForm.rentTime[1]})// 更新列表this.getExterpriseList()// 关闭弹框this.rentDialogVisible = false}})
}

显示合同列表

准备Table静态结构

el-table支持嵌套内容,只需要在el-table-column组件上添加type属性,指定值为 expand

<el-table-column type="expand"><template #default><el-table><el-table-column label="租赁楼宇" width="320" prop="buildingName" /><el-table-column label="租赁起始时间" prop="startTime" /><el-table-column label="合同状态" prop="status" /><el-table-column label="操作" width="180"><template #default="scope"><el-button size="mini" type="text">退租</el-button><el-button size="mini" type="text">删除</el-button></template></el-table-column></el-table></template></el-table-column>

获取当前合同列表

1- 封装接口函数

/*** 获取合同列表* @param {*} id* @returns*/
export function getRentListAPI(id) {return request({url: `/park/enterprise/rent/${id}`})
}

2- 展开时获取合同数据

// 1. 绑定事件 & 绑定数据
<el-table style="width: 100%" :data="exterpriseList" @expand-change="expandHandle"><el-table-column type="expand"><template #default="{row}"><el-table :data="row.rentList"><el-table-column label="租赁楼宇" width="320" prop="buildingName" /><el-table-column label="租赁起始时间" prop="startTime" /><el-table-column label="合同状态" prop="status" /><el-table-column label="操作" width="180"><template #default="scope"><el-button size="mini" type="text">续租</el-button><el-button size="mini" type="text">退租</el-button><el-button size="mini" type="text">删除</el-button></template></el-table-column></el-table></template></el-table-column>// 2. 初始化时增加合同数据默认列表   
async getExterpriseList() {const res = await getEnterpriseListAPI(this.params)this.exterpriseList = res.data.rows.map((item) => {return {...item,rentList: [] // 每一行补充存放合同的列表}})this.total = res.data.total
}// 3. 只有展开时获取数据并绑定
async expandHandle(row, rows) {console.log('展开或关闭', row, rows)const isExpend = rows.find(item => item.id === row.id)if (isExpend) {const res = await getRentListAPI(row.id)// eslint-disable-next-line require-atomic-updatesrow.rentList = res.data}
}

适配合同状态

// 格式化tag类型
formatInfoType(status) {const MAP = {0: 'warning',1: 'success',2: 'info',3: 'danger'}// return 格式化之后的中文显示return MAP[status]
}// 格式化status
formartStatus(type) {const TYPEMAP = {0: '待生效',1: '生效中',2: '已到期',3: '已退租'}return TYPEMAP[type]
}<el-table-column label="合同状态"><template #default="scope"><el-tag :type="formatInfoType(scope.row.status)"> {{ formatStatus(scope.row.status) }}</el-tag></template></el-table-column>

合同退租状态修改

封装接口

/*** 退租* @param {合同id} rentId* @returns*/export function outRentAPI(rentId) {return request({url: `/park/enterprise/rent/${rentId}`,method: 'PUT'})
}

修改状态

<el-table-column label="操作" width="180" fixed="right"><template #default="scope"><el-button size="mini" type="text" @click="outRent(scope.row.id)">退租</el-button><el-button size="mini" type="text" >删除</el-button></template></el-table-column>outRent(rentId) {this.$confirm('确认退租吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async() => {// 1. 调用接口await outRentAPI(rentId)// 2. 重新拉取列表this.getEnterpriseListAPI()this.$message({type: 'success',message: '退租成功!'})}).catch(() => {this.$message({type: 'info',message: '已取消删除'})})
}

适配视图状态

<el-table-column label="操作" width="180" fixed="right"><template #default="scope"><el-button size="mini" type="text" :disabled="scope.row.status === 3" @click="outRent(scope.row.id)">退租</el-button><el-button size="mini" type="text" :disabled="scope.row.status !== 3">删除</el-button></template></el-table-column>

查看企业

准备路由

<template><div class="detail-enterprise"><header class="add-header"><el-page-header content="查看企业" @back="$router.back()" /></header><main class="add-main"><div class="form-container"><div class="title">租赁记录</div><div class="table-container"><el-table:data="[]"style="width: 100%"border><el-table-columnprop="index"label="序号"width="50"/><el-table-columnprop="name"label="租赁楼宇"width="180"/><el-table-columnlabel="租赁起止时间"width="280"><template #default="{row}">{{ row.startTime }} - {{ row.endTime }}</template></el-table-column><el-table-columnlabel="租赁合同(点击预览)"><template #default="{row}"><el-button type="text">{{ row.contractName }}</el-button></template></el-table-column><el-table-columnprop="createTime"label="录入时间"/><el-table-columnprop="address"label="操作"><template #default="{row}"><el-button type="text">合同下载</el-button></template></el-table-column></el-table></div></div></main></div></template><script>
export default {data() {return {}}
}
</script><style scoped lang="scss">
.detail-enterprise {background-color: #f4f6f8;height: 100vh;.add-header {display: flex;align-items: center;padding: 0 20px;height: 64px;background-color: #fff;.left {span {margin-right: 4px;}.arrow{cursor: pointer;}}.right {text-align: right;}}.add-main {background: #f4f6f8;padding: 20px 130px;.form-container {background-color: #fff;margin-bottom: 20px;.title {height: 60px;line-height: 60px;padding-left: 20px;}}.table-container{padding:20px;}.preview{img{width: 100px;}}}
}
</style>
{path: '/exterpriseDetail',component: () => import('@/views/park/enterprise/Detail')
}

渲染列表

1- 封装接口

/*** 获取详情* @param {企业id} id* @returns*/export function getEnterpriseDetail(id) {return request({url: `/park/enterprise/${id}`,method: 'GET'})
}

2- 渲染数据

<template><div class="detail-enterprise"><header class="add-header"><el-page-header content="查看企业" @back="$router.back()" /></header><main class="add-main"><div class="form-container"><div class="title">租赁记录</div><div class="table-container"><el-table:data="form.rent"style="width: 100%"border><el-table-columnprop="index"label="序号"width="50"/><el-table-columnprop="name"label="租赁楼宇"width="180"/><el-table-columnlabel="租赁起止时间"width="280"><template #default="{row}">{{ row.startTime }} - {{ row.endTime }}</template></el-table-column><el-table-columnlabel="租赁合同(点击预览)"><template #default="{row}"><el-button type="text">{{ row.contractName }}</el-button></template></el-table-column><el-table-columnprop="createTime"label="录入时间"/><el-table-columnprop="address"label="操作"><template #default="{row}"><el-button type="text">合同下载</el-button></template></el-table-column></el-table></div></div></main></div></template><script>
import { getEnterpriseDetail } from '@/apis/enterprise'
export default {data() {return {form: {}}},mounted() {this.getDetail()},methods: {async getDetail() {const res = await getEnterpriseDetail(this.$route.query.id)this.form = res.data}}
}
</script>

预览功能实现

预览地址拼接上合同文件链接地址在新窗口打开

<el-button type="text"><a :href="`${previewURL}${row.contractUrl}`" target="_blank">{{ row.contractName }}</a></el-button>data() {return {previewURL: 'https://view.officeapps.live.com/op/view.aspx?src=' // 预览地址}
}

下载功能

<el-table-columnprop="address"label="操作"
><template #default="{row}"><el-button type="text"><a :href="row.contractUrl">合同下载</a></el-button></template></el-table-column>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/70672.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS中padding和margin属性的使用

在 HTML 中&#xff0c;padding 和 margin 是用于控制元素布局和间距的重要属性。 一、Padding&#xff08;内边距&#xff09; 定义&#xff1a;Padding 是指元素内容与元素边框之间的距离。它可以在元素内部创造出空白区域&#xff0c;使得内容不会紧贴着边框。 作用 增加元…

git中,如何查看具体单个文件的log

在 Git 中&#xff0c;可以使用多种方式查看单个文件的提交日志&#xff08;Log&#xff09;&#xff0c;以下详细介绍不同场景下的查看方法&#xff1a; 目录 一、基本命令查看文件的完整提交日志 二、查看文件提交日志并显示差异内容 三、限制显示的提交日志数量 四、按…

日常知识点之刷题一

1&#xff1a;流浪地球 0~n-1个发动机&#xff0c;计划启动m次&#xff0c;求最后启动的发动机的个数。 以及发动机的编号。&#xff08;模拟过程&#xff0c;每次手动启动的机器对应时间向两边扩散&#xff09; //输入每个启动的时间和编号 void test_liulang() {int n, m;ci…

C++面向对象编程技术研究

一、引言 面向对象编程&#xff08;OOP&#xff09;是一种程序设计方法&#xff0c;它将现实世界中的实体抽象为“对象”&#xff0c;并通过类和对象来实现程序的设计。OOP的核心思想包括封装、继承和多态&#xff0c;这些特性使得程序更加模块化、易于扩展和维护。C作为一种支…

Day54(补)【AI思考】-SOA,Web服务以及无状态分步解析与示例说明

文章目录 **SOA&#xff0c;Web服务以及无状态**分步解析与示例说明**分步解析与示例说明****1. 核心概念解析****2. 为什么说SOA与Web服务是“正交的”&#xff1f;****3. 架构风格 vs. 实现技术****4. 接口&#xff08;Interface&#xff09;的核心作用****5. Web服务的“被认…

【Deepseek高级使用教程】Deepseek-R1的5种高级进阶玩法,5分钟教会你Deepseek+行业的形式进行工作重构的保姆级教程

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 最近&#xff0c;有各行各业的小伙伴问我&#xff0c;到底应该怎么将deepseek融入进他们自身的工作流呢&#xff1f;其实这个问题很简单。我就以…

selenium爬取苏宁易购平台某产品的评论

目录 selenium的介绍 1、 selenium是什么&#xff1f; 2、selenium的工作原理 3、如何使用selenium&#xff1f; webdriver浏览器驱动设置 关键步骤 代码 运行结果 注意事项 selenium的介绍 1、 selenium是什么&#xff1f; 用于Web应用程序测试的工具。可以驱动浏览…

[实现Rpc] 客户端 | Requestor | RpcCaller的设计实现

目录 Requestor类的实现 框架 完善 onResponse处理回复 完整代码 RpcCaller类的实现 1. 同步调用 call 2. 异步调用 call 3. 回调调用 call Requestor类的实现 &#xff08;1&#xff09;主要功能&#xff1a; 客户端发送请求的功能&#xff0c;进行请求描述对服务器…

P2889 [USACO07NOV] Milking Time S

题目大意 有 N N N 个小时可以挤奶。其中有 m m m 个时间段可以给 Bessis 奶牛挤奶。第 i i i 个时间段为 s i s_i si​ ~ t i t_i ti​&#xff0c;可以获得 E f f i Eff_i Effi​ 滴奶。每次挤完奶后&#xff0c;人都要休息 R R R 小时。最后问&#xff0c;一共能挤出…

ONNX转RKNN的环境搭建和部署流程

将ONNX模型转换为RKNN模型的过程记录 工具准备 rknn-toolkit:https://github.com/rockchip-linux/rknn-toolkit rknn-toolkit2:https://github.com/airockchip/rknn-toolkit2 rknn_model_zoo:https://github.com/airockchip/rknn_model_zoo ultralytics_yolov8:https://github…

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量&#xff0c;提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗&#xff1f; 是的&#xff0c;文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…

C++基础知识学习记录—多态

1、函数覆盖 函数覆盖也被称为函数重写&#xff0c;类似于函数隐藏&#xff0c; 函数覆盖是多态的前提条件之一。 函数覆盖与函数隐藏的区别&#xff1a; ● 基类的被覆盖函数需要使用virtual关键字修饰&#xff0c;表示这个函数是一个虚函数 在Qt Creator中虚函数是斜体 虚…

GoFly框架中集成Bolt 和badfer两个Go语言嵌入式键值数据库

本插件集成了Bolt 和badfer两个纯Go实现的快速的嵌入式K/V数据库&#xff0c;方便开发时本地存储使用。插件集成Bolt 和badfer两个&#xff0c;如果确定使用其中一个&#xff0c;也可以把其中不用的一个删除&#xff0c;不删除也不会有任何影响。 插件使用说明 1.安装插件 到…

AWS - Redshift - 外部表读取 Parquet 文件中 timestamp 类型的数据

问题&#xff1a; 通过 Redshift Spectrum 功能可以读取 S3 中的文件&#xff0c;当读取 Parquet 文件时&#xff0c;如果列格式设置为 timestamp&#xff0c; 通过 psql 客户端读取会出现以下错误&#xff1a; testdb# select * from myspectrum_schema_0219.test_ns; ERROR…

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…

重新求职刷题DAY18

1.513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 输入: root [2,1,3] 输出: 1思路&#xff1a; 这…

B站pwn教程笔记-2

这次是栈溢出基础。 栈基础知识 栈帧结构概览 看上图的高地址和低地址。arguments是子函数的形参。蓝色的是上一个栈的ebp值&#xff0c;用于在子函数执行完毕之后&#xff0c;返回到正确的ebp. heap的占的内存大大的超过stack。 下面看看调用栈的详细过程。 一个函数都是以…

Qt中C++与QML交互从原理、方法与实践陷阱深度解析

在我们使用Qt开发中&#xff0c;现在以及普遍通过 C 与 QML 的交互&#xff0c;将 C 的强大功能与 QML 的界面设计优势相结合&#xff0c;既保证了应用程序的性能和稳定性&#xff0c;又能快速实现美观、易用的用户界面。接下来专门讲下C与QML交互原理、方法与实践中的一些陷阱…

JavaScript获取DOM元素语法总结(getElementsByName()、querySelector()、querySelectorAll())

文章目录 JavaScript DOM 元素获取语法总结关键点简介方法概述详细报告引言DOM 元素获取方法1. getElementById()&#xff08;弃用&#xff09;2. getElementsByClassName()&#xff08;弃用&#xff09;3. getElementsByTagName()&#xff08;弃用&#xff09;4. getElementsB…

tableau之人口金字塔、漏斗图、箱线图

一、人口金字塔 人口金字塔在本质上就是成对的条形图 人口金字塔是一种特殊的旋风图 1、数据处理 对异常数据进行处理 2、创建人口金字塔图 将年龄进行分桶 将男女人数数据隔离开 分别绘制两个条形图 双击男性条形图底部&#xff0c;将数据进行翻转&#xff08;倒序&a…