You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

913 lines
31 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div>
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader
:icon="$route.meta.icon"
:text="$route.meta.title"
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
>
<div slot="header-right">
<div class="lease-legend">
<div>临期</div>
<div>到期</div>
</div>
</div>
<div slot="content"></div>
<slot>
<header-content :auths="auths_auth_mixin">
<template #search>
<div style="display: flex">
<Select
v-model="select.filter[0].key"
style="width: 100px"
placeholder="搜索条目"
>
<Option
v-for="item in form"
:key="item.id"
:value="item.field"
>{{ item.name }}</Option
>
</Select>
<Select
v-model="select.filter[0].op"
style="width: 100px; margin-left: 10px"
placeholder="搜索条件"
>
<Option
v-for="item in op"
:key="item.value"
:value="item.value"
>{{ item.label }}</Option
>
</Select>
<template
v-if="
select.filter[0].op !== 'range' &&
!columnArrTest(select.filter[0].key)
"
>
<Input
v-model="select.filter[0].value"
style="width: 150px; margin-left: 10px"
placeholder="请填写关键词"
/>
</template>
<template
v-else-if="
select.filter[0].op !== 'range' &&
columnArrTest(select.filter[0].key)
"
>
<Select
v-model="select.filter[0].value"
style="width: 150px; margin-left: 10px"
placeholder="请选择关键词"
>
<Option
v-for="item in getColumnParams(select.filter[0].key)"
:key="item.id"
:value="getColumnField(select.filter[0].key)._relations ? item[getColumnField(select.filter[0].key)._relations.foreign_key] : item.value"
>{{
item.key || item.value || item.name || item.no || item.mingcheng || item.id
}}</Option
>
</Select>
</template>
<template v-else>
<Input
:value="select.filter[0].value.split(',')[0]"
style="width: 150px; margin-left: 10px"
placeholder="范围开始关键词"
@input="(e) => inputStartHandler(e, select.filter[0])"
/>
<span
style="
margin-left: 10px;
display: flex;
align-items: center;
"
>至</span
>
<Input
:value="select.filter[0].value.split(',')[1]"
style="width: 150px; margin-left: 10px"
placeholder="范围结束关键词"
@input="(e) => inputEndHandler(e, select.filter[0])"
/>
</template>
<Button
style="margin-left: 10px"
type="primary"
@click="$refs['xyTable'].getTableData(true)"
>查询</Button
>
<xy-selectors
style="margin-left: 10px"
@reset="reset"
@search="$refs['xyTable'].getTableData(true)"
>
<template>
<div class="select">
<div
class="select__item"
v-for="(item, index) in select.filter"
:key="`${item.value}-${index}`"
>
<p>条件{{ index + 1 }}</p>
<Select
v-model="item.key"
style="width: 100px"
placeholder="搜索条目"
>
<Option
v-for="item in form"
:key="item.id"
:value="item.field"
>{{ item.name }}</Option
>
</Select>
<Select
v-model="item.op"
style="width: 100px; margin-left: 10px"
placeholder="搜索条件"
>
<Option
v-for="item in op"
:key="item.value"
:value="item.value"
>{{ item.label }}</Option
>
</Select>
<template
v-if="
item.op !== 'range' && !columnArrTest(item.key)
"
>
<Input
v-model="item.value"
style="width: 150px; margin-left: 10px"
placeholder="请填写关键词"
/>
</template>
<template
v-else-if="
item.op !== 'range' && columnArrTest(item.key)
"
>
<Select
v-model="item.value"
style="width: 150px; margin-left: 10px"
placeholder="请选择关键词"
>
<Option
v-for="item in getColumnParams(item.key)"
:key="item.id"
:value="getColumnField(item.key)._relations ? item[getColumnField(item.key)._relations.foreign_key] : item.value"
>{{
item.key || item.value || item.name || item.no || item.mingcheng || item.id
}}</Option
>
</Select>
</template>
<template v-else>
<Input
:value="item.value.split(',')[0]"
style="width: 150px; margin-left: 10px"
placeholder="范围开始关键词"
@input="(e) => inputStartHandler(e, item)"
/>
<span style="margin-left: 10px">至</span>
<Input
:value="item.value.split(',')[1]"
style="width: 150px; margin-left: 10px"
placeholder="范围结束关键词"
@input="(e) => inputEndHandler(e, item)"
/>
</template>
<el-button
v-if="index !== 0"
size="small"
type="danger"
icon="el-icon-delete"
circle
style="margin-left: 10px"
@click="select.filter.splice(index, 1)"
></el-button>
</div>
</div>
<div class="add-btn">
<el-button
size="small"
type="primary"
icon="el-icon-plus"
circle
@click="
select.filter.push({ key: '', op: '', value: '' })
"
></el-button>
<span>新增一条</span>
</div>
</template>
</xy-selectors>
</div>
</template>
<template #create>
<Button
type="primary"
@click="
$refs['dialog'].setType('add'), $refs['dialog'].show()
"
>新增</Button
>
</template>
<template #import>
<Button type="primary" @click="$refs['imports'].show()"
>导入</Button
>
</template>
<template #export>
<Button
type="primary"
@click="exportExcel(new Date().getTime().toString())"
>导出</Button
>
</template>
</header-content>
</slot>
</LxHeader>
</div>
</div>
<xy-table
:btn-width="300"
:row-style="rowStyle"
:auths="auths_auth_mixin"
:delay-req="true"
:destroy-action="destroy"
ref="xyTable"
:border="true"
:action="index"
:req-opt="select"
:destroy-req-opt="select"
:table-item="table"
:btn-to-more="true"
:more-auths="['contractChange','edit','delete']"
@detail="
(row) => {
$router.push({
path: $route.path + '/detail/' + row.id
})
}
"
@editor="
(row) => {
$router.push('/sign/'+row.let_id+'?type=editor&leaseId='+row.id)
}
"
@loaded="adjustAlignment"
>
<template #sign="{ row }">
<Button type="primary" size="small" @click="$router.push('/addlet'+'?leaseId='+row.id+(row.let_id ? ('&type=editor&letId=' + row.let_id) : '&type=add'))">招租管理</Button>
</template>
<template #rentCollection="{ row }">
<template>
<Button size="small" type="warning" @click="$refs['payList'].setLeaseId(row.id),$refs['payList'].show()">租金收取</Button>
</template>
</template>
<template #expiredLet="{ row }">
<template v-if="$moment().valueOf() > $moment(row.zulinjieshuqixian).valueOf()">
<Button size="small" type="error" @click="$router.push('/let'+'?renewId='+row.let_id)">到期招租</Button>
</template>
</template>
<template #contractChange="{ row }">
<a size="small" type="primary" @click="$router.push('/sign/'+row.let_id+'?type=change&leaseId='+row.id)">合同变更</a>
</template>
</xy-table>
<add
:table-name="customForm.tableName"
ref="dialog"
@refresh="$refs['xyTable'].getTableData()"
>
</add>
<addPay ref="addPay"></addPay>
<payList ref="payList"></payList>
<imports
:table-name="customForm.tableName"
:form-info="form"
ref="imports"
@refresh="$refs['xyTable'].getTableData()"></imports>
</div>
</template>
<script>
import { index as fieldIndex } from "@/api/system/customFormField";
import { authMixin } from "@/mixin/authMixin";
import { index, destroy } from "@/api/system/baseForm";
import { op } from "@/const/op";
import { download } from "@/utils/downloadRequest";
import { getparameter } from "@/api/system/dictionary";
import { show } from "@/api/system/customForm";
import * as XLSX from "xlsx";
import { saveAs } from "file-saver";
import { listdept } from "@/api/system/department"
import add from "./component/addLease.vue";
import imports from "./component/imports.vue"
import LxHeader from "@/components/LxHeader/index.vue";
import headerContent from "@/components/LxHeader/XyContent.vue";
import addPay from "@/views/lease/component/addPay.vue";
import payList from "@/views/lease/component/payList.vue"
export default {
name: 'leaseIndex',
components: {
imports,
LxHeader,
add,
headerContent,
addPay,
payList
},
mixins: [authMixin],
provide: {
formStore: () => this.form,
},
data() {
return {
config: {
time: 3,
unit: "months"
},
firstAdjustTable: true,
op,
select: {
is_auth: 1,
table_name: "",
filter: [
{
key: "",
op: "",
value: "",
},
],
},
form: [],
table: [],
customForm: {
customFormId: "",
tableName: "",
},
};
},
methods: {
index,
destroy,
download,
reset() {
this.select.filter.splice(1);
this.select.filter[0] = {
key: "",
op: "",
value: "",
};
},
async exportExcel(sheetName) {
let filterTableColumns = this.$refs['xyTable']?.tableFormat || []
const res = await index(
Object.assign(this.select, { page: 1, page_size: 9999 })
);
if (res.data) {
let headers = filterTableColumns.filter(i => !!i.prop).map((i) => {
return {
key: i.prop,
title: i.label,
};
});
let data = []
let merges = []
let rowIndex = 0
res.data.forEach((row, rindex) => {
let myRow = headers.map((header) => {
const i = this.form.find(i => i.field === header.key)
if (i && i._relations) {
let { link_relation, foreign_key, link_with_name } = i._relations;
if (link_relation === "newHasOne" || link_relation === "hasOne") {
return row[link_with_name]?.original_name || row[link_with_name]?.name ||
row[link_with_name]?.no ||
row[link_with_name]?.value
}
if (link_relation === "hasMany" || link_relation === "newHasMany") {
return row[link_with_name]?.map((o) => (
o?.name ||
o?.no ||
o?.value ||
o?.biaoti ||
o?.mingcheng
)).toString()
}
}
if (this.table.find(i => i.prop === header.key)?.formatter) {
return this.table.find(i => i.prop === header.key).formatter(row, {}, row[header.key], rindex)
}
return row[header.key]
})
if (row['id_leases_to_assets_lease_id_relation'].length > 0) {
for (let j = 0;j<row['id_leases_to_assets_lease_id_relation'].length;j++) {
let myAssetLink = row['id_leases_to_assets_lease_id_relation'][j]
let myAsset = {}
if (myAssetLink.land_id) {
myAsset = row['land'].find(k => k.id === myAssetLink.land_id)
} else if (myAssetLink.house_id) {
myAsset = row['houses'].find(k => k.id === myAssetLink.house_id)
}
data.push([...myRow,myAsset.name,myAssetLink.chuzumianji])
}
if (headers.length > 0) {
for (let q = 0;q < headers.length;q ++) {
merges.push({
s: {
r: rowIndex + 1,
c: q
},
e: {
r: rowIndex + 1 + row['id_leases_to_assets_lease_id_relation'].length - 1,
c: q
}
})
}
}
rowIndex += row['id_leases_to_assets_lease_id_relation'].length
} else {
rowIndex++
data.push(myRow)
}
});
headers.push({
title: '资产名称'
})
headers.push({
title: '出租面积'
})
data.unshift(headers.map((header) => header.title));
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(data);
ws['!merges'] = merges
XLSX.utils.book_append_sheet(wb, ws, sheetName);
const wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array",
});
saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
`${sheetName}.xlsx`
);
}
},
//target要为内存地址引用类型
inputStartHandler(e, target) {
let temp = target?.value.split(",")[1];
target.value = `${e},${temp ? temp : ""}`;
},
inputEndHandler(e, target) {
let temp = target?.value.split(",")[0];
target.value = `${temp ? temp : ""},${e}`;
},
async getFormDetail() {
if (this.$route.meta.params?.custom_form) {
let decode = decodeURIComponent(this.$route.meta.params?.custom_form);
try {
let custom_form = JSON.parse(decode);
this.customForm.customFormId = custom_form.custom_form_id;
this.customForm.tableName = custom_form.table_name;
this.select.table_name = custom_form.table_name;
} catch (err) {
console.warn(err);
}
}
const res = await show({ id: this.customForm.customFormId }, false);
//字段处理
//初始表白名单
let baseTable = new Map([
['departments', async () => {
const res = await listdept()
return res
}],
['admins',[]]
])
let { fields, relation } = res;
let fieldRes = fields.sort((a,b) => a.sort - b.sort)
if (
!fields ||
!relation ||
!fields instanceof Array ||
!relation instanceof Array
) {
throw new Error("fields或relation格式错误");
}
console.log(fieldRes)
fieldRes?.forEach((i, index) => {
i._relations = relation.find(
(j) => j.link_table_name.split("_")[1] === i.field
) || relation.find(
(j) => j.local_key === i.field
);
if (i.select_item && typeof i.select_item === "object") {
let keys = Object.keys(i.select_item);
if (keys.length > 0) {
i._params = keys.map((key) => {
return {
key,
value: /^\d*$/.test(i.select_item[key])
? Number(i.select_item[key])
: i.select_item[key],
};
});
}
}
if (i.edit_input === 'file' || i.edit_input === 'files') {
return
}
if (i._relations) {
if (baseTable.get(i._relations.link_table_name)) {
baseTable
.get(i._relations.link_table_name)()
.then((res) => {
i._params = res.data;
});
} else {
i._params = i._relations.parameter_id
? getparameter({ id: i._relations.parameter_id }, false).then(
(res) => {
i._params = res.detail;
}
)
: this.index({
table_name: i._relations.link_table_name,
page: 1,
page_size: 9999,
}).then((res) => {
i._params = res.data;
});
}
}
});
this.form = fieldRes || [];
this.form
?.filter((i) => i.list_show)
.forEach((i) => {
let linkOb = {};
if (i.edit_input === "richtext") {
linkOb.customFn = (row) => {
return (
<div
style={{ "max-height": "55px","overflow": "scroll" }}
domPropsInnerHTML={row[i.field]}
></div>
);
};
}
if (
i.select_item &&
typeof i.select_item === "object" &&
!(i.select_item instanceof Array)
) {
let keys = Object.keys(i.select_item);
linkOb.customFn = (row) => {
let paramMap = new Map();
keys.forEach((key) => {
paramMap.set(/^\d*$/.test(i.select_item[key]) ? Number(i.select_item[key]) : i.select_item[key], key);
});
return <span>{ paramMap.get(row[i.field]) ? paramMap.get(row[i.field]) : row[i.field] }</span>;
};
}
if (i._relations) {
let { link_relation, foreign_key, link_with_name } = i._relations;
if (link_relation === "newHasOne" || link_relation === "hasOne") {
linkOb.customFn = (row) => {
if (i.edit_input === "file") {
return (
<a
download={row[link_with_name]?.original_name}
href={row[link_with_name]?.url}
>
{row[link_with_name]?.original_name}
</a>
);
} else {
return (
<span>
{row[link_with_name]?.name ||
row[link_with_name]?.no ||
row[link_with_name]?.value}
</span>
);
}
};
}
if (link_relation === "hasMany" || link_relation === "newHasMany") {
linkOb.customFn = (row) => {
if (i.edit_input === "files") {
return (
<div style="display: flex;flex-direction: column;">
{row[link_with_name]?.map((o) => (
<a>
{ o?.original_name || o?.name }
</a>
))}
</div>
)
} else {
return (
<div>
{row[link_with_name]?.map((o) => (
<p>
{o?.name ||
o?.no ||
o?.value ||
o?.biaoti ||
o?.mingcheng}
</p>
))}
</div>
);
}
};
}
}
this.table.push(
Object.assign(
{
prop: i.field,
label: i.name,
width: i.width,
align: 'center',
fixed: i.is_fixed,
},
linkOb
)
);
});
this.table.unshift( {
label: "资产",
prop: 'assets',
width: 320,
align: 'left',
customFn: row => {
let tags = row.id_leases_to_assets_lease_id_relation?.slice(0,1)?.map(i => {
let asset = i.house_id ? row.houses.find(j => j.id === i.house_id) : row.land.find(j => j.id === i.land_id)
return (<Tag color="success" style="background: rgb(65, 100, 227) !important;">{(i.land_id ? '【土地】' : '【房产】')+(asset?.name || i.name || " ")}-{ i.xiangxiweizhi }</Tag>)
})
return (
<div>
{
tags.slice(0, 1)
}
<br></br>
<el-popover title="资产" width={600}>
<el-link slot="reference"
type="primary"
style={{
"font-size": "13px",
"word-break": "keep-all",
display: tags.length > 0 ? "inline" : "none",
}}>更多</el-link>
<div slot="default">
<Table size="small"
data={row.id_leases_to_assets_lease_id_relation}
columns={[
{
title: '资产名称',
key: 'name',
width: 180,
render: (h, { row: myRow }) => {
let asset = myRow.house_id ? row.houses.find(j => j.id === myRow.house_id) : row.land.find(j => j.id === myRow.land_id)
return h('span', (asset?.name || myRow.name || " "))
}
},
{
title: '坐落',
key: 'zuoluo',
minWidth: 200,
render: (h, { row: myRow }) => {
let asset = myRow.house_id ? row.houses.find(j => j.id === myRow.house_id) : row.land.find(j => j.id === myRow.land_id)
return h('span', (asset?.zuoluo || myRow.zuoluo || " "))
}
},
{
title: '详细位置',
key: 'xiangxiweizhi',
minWidth: 200
},
{
title: '出租面积',
key: 'chuzumianji',
width: 180,
render: (h, { row: myRow }) => {
let asset = myRow.house_id ? row.houses.find(j => j.id === myRow.house_id) : row.land.find(j => j.id === myRow.land_id)
return h('span', (asset?.chuzumianji || myRow.chuzumianji || " "))
}
},
]}>
</Table>
</div>
</el-popover>
</div>
)
}
})
this.table.unshift({
prop: "",
width: 60,
label: "序号",
formatter: (row, column, cellValue, index) => (this.$refs['xyTable'].selectOpt.page - 1) * this.$refs['xyTable'].selectOpt.page_size + index + 1
})
this.table.push({
prop: 'admin_id',
width: 120,
label: '提交人',
formatter: (row, column, cellValue, index) => row['admin']?.name
})
this.table.push({
prop: 'department_id',
width: 120,
label: '提交部门',
formatter: (row, column, cellValue, index) => row['department']?.name
})
this.table.push({
prop: 'created_at',
width: 160,
label: '提交日期',
formatter: (row, column, cellValue, index) => this.$moment(cellValue).format('YYYY-MM-DD')
})
},
adjustAlignment () {
if (this.firstAdjustTable) {
const data = this.$refs['xyTable'].getListData();
if (data.length < 2) return;
try {
this.form.filter(i => i.list_show).forEach((i) => {
let maxLength = -Infinity;
let minLength = Infinity;
let numberLength = 0;
let temp = 0;
while (temp < data.length) {
maxLength = Math.max(maxLength, data[temp][i.field]?.length??0);
minLength = Math.min(minLength, data[temp][i.field]?.length??0);
numberLength += /^-?[0-9]+(\.[0-9]+)?$/.test(data[temp][i.field]) ? 1 : 0;
temp++;
}
if (numberLength === temp && numberLength !== 0 && i.edit_input !== 'radio') {
this.table.find(a => a.prop === i.field).align = 'right';
}
else if (Math.abs(maxLength - minLength) > 4) {
this.table.find(a => a.prop === i.field).align = 'left';
}
})
} catch (e) {
console.error(e)
}
this.$nextTick(() => {
this.$refs['xyTable'].doLayout();
this.firstAdjustTable = false;
})
}
},
async getConfig () {
const res = await index({
table_name: "warnings",
filter: [
{
key: "flag",
op: "eq",
value: "contract"
}
]
});
this.config.time = Number(res.data[0]?.time);
this.config.unit = res.data[0]?.unit;
},
rowStyle ({ row }) {
if (row.zulinjieshuqixian && this.$moment().isBetween(this.$moment(row.zulinjieshuqixian).subtract(this.config.time,this.config.unit),this.$moment(row.zulinjieshuqixian))) {
return {
background: "rgb(255,251,230)"
}
}
else if (row.zulinjieshuqixian && this.$moment().isAfter(this.$moment(row.zulinjieshuqixian))) {
return {
background: "#e5e5e5"
}
} else {
return {
background: "#fff"
}
}
}
},
computed: {
columnArrTest() {
return function (field) {
return this.form.find((i) => i.field === field)
? this.form.find((i) => i.field === field).search_input === "checkbox" || this.form.find((i) => i.field === field).search_input === "radio"
: false;
};
},
getColumnField() {
return function (field) {
return this.form.find((i) => i.field === field)
? this.form.find((i) => i.field === field)
: {};
};
},
getColumnParams() {
return function (field) {
return this.form.find((i) => i.field === field)
? this.form.find((i) => i.field === field)._params
: [];
};
}
},
created() {
this.getConfig();
this.getFormDetail();
},
};
</script>
<style scoped lang="scss">
.lease-legend {
display: flex;
align-items: center;
margin-left: auto;
& > div {
font-size: 15px;
color: #595959;
position: relative;
&::before {
content: "";
width: 8px;
height: 8px;
border-radius: 100%;
position: absolute;
left: -14px;
top: calc(50% - 4px);
}
& + div {
margin-left: 35px;
}
}
& > div:nth-child(1)::before {
background: #fefbe8;
border: 1px solid #efde75;
}
& > div:nth-child(2)::before {
background: #e5e5e5;
}
}
.select {
&__item {
& > p {
display: inline-block;
width: 80px;
text-align: center;
}
& + div {
margin-top: 6px;
}
}
}
.add-btn {
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
& > span {
padding: 0 10px;
}
}
</style>