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.

1479 lines
56 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) &&
!isDateField(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' &&
isDateField(select.filter[0].key)
"
>
<el-date-picker
v-model="select.filter[0].value"
:type="getDatePickerType(select.filter[0].key)"
:value-format="getDatePickerFormat(select.filter[0].key)"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
placeholder="请选择日期"
></el-date-picker>
</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-if="
select.filter[0].op === 'range' &&
isDateField(select.filter[0].key) &&
select.filter[0].key !== 'qiandingnianyue'
"
>
<el-date-picker
v-model="dateRangeStart0"
:type="getDatePickerType(select.filter[0].key)"
placeholder="开始时间"
:value-format="getDatePickerFormat(select.filter[0].key)"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
@change="(val) => handleDateStartChange(val, select.filter[0])"
></el-date-picker>
<span
style="
margin-left: 10px;
display: flex;
align-items: center;
"
>至</span
>
<el-date-picker
v-model="dateRangeEnd0"
:type="getDatePickerType(select.filter[0].key)"
placeholder="结束时间"
:value-format="getDatePickerFormat(select.filter[0].key)"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
@change="(val) => handleDateEndChange(val, select.filter[0])"
></el-date-picker>
</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>
<el-date-picker
v-model="qiandingnianyueStart"
type="month"
placeholder="签订开始年月"
value-format="yyyy-MM"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
></el-date-picker>
<span
style="
margin-left: 10px;
display: flex;
align-items: center;
"
>至</span
>
<el-date-picker
v-model="qiandingnianyueEnd"
type="month"
placeholder="签订结束年月"
value-format="yyyy-MM"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
></el-date-picker>
<Select
v-model="leaseStatusFilter"
style="width: 120px; margin-left: 10px"
placeholder="过期筛选"
clearable
>
<Option value="">全部</Option>
<Option value="临期">临期</Option>
<Option value="已过期">已过期</Option>
</Select>
<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) && !isDateField(item.key)
"
>
<Input
v-model="item.value"
style="width: 150px; margin-left: 10px"
placeholder="请填写关键词"
/>
</template>
<template
v-else-if="
item.op !== 'range' && isDateField(item.key)
"
>
<el-date-picker
v-model="item.value"
:type="getDatePickerType(item.key)"
:value-format="getDatePickerFormat(item.key)"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
placeholder="请选择日期"
></el-date-picker>
</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-if="isDateField(item.key)"
>
<el-date-picker
:value="getDateRangeStart(item)"
:type="getDatePickerType(item.key)"
placeholder="开始时间"
:value-format="getDatePickerFormat(item.key)"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
@change="(val) => handleDateStartChange(val, item)"
></el-date-picker>
<span style="margin-left: 10px">至</span>
<el-date-picker
:value="getDateRangeEnd(item)"
:type="getDatePickerType(item.key)"
placeholder="结束时间"
:value-format="getDatePickerFormat(item.key)"
style="width: 150px; margin-left: 10px; height: 32px"
size="small"
@change="(val) => handleDateEndChange(val, item)"
></el-date-picker>
</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"
:destroy-action="destroy"
ref="xyTable"
:border="true"
:action="index"
:req-opt="formatSelect"
: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 { deepCopy } from '@/utils'
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,
dateRangeStart0: null, // 第一个筛选条件的开始时间
dateRangeEnd0: null, // 第一个筛选条件的结束时间
qiandingnianyueStart: null, // 签订开始年月
qiandingnianyueEnd: null, // 签订结束年月
leaseStatusFilter: '', // 租赁状态筛选:临期、已过期
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: "",
};
// 重置日期范围
this.dateRangeStart0 = null;
this.dateRangeEnd0 = null;
// 重置签订年月筛选
this.qiandingnianyueStart = null;
this.qiandingnianyueEnd = null;
// 重置状态筛选
this.leaseStatusFilter = '';
},
async exportExcel(sheetName) {
try {
// 获取列表显示的列配置tableFormat 是用户实际看到的列)
let filterTableColumns = this.$refs['xyTable']?.tableFormat || this.table || []
// 构建 export_fields 参数,按照列表顺序
const exportFields = {}
const assetField = {} // 单独保存资产字段
// 遍历列表显示的列,按照列表顺序构建 export_fields
filterTableColumns
.filter(i => {
// 只排除序号列prop为空和操作列没有prop或prop为特殊值
return i.prop !== '' && i.prop !== undefined && i.prop !== null
})
.forEach((col) => {
// 如果列是 assets单独保存稍后添加到末尾
if (col.prop === 'assets') {
assetField['asset_name'] = col.label || col.name || '资产'
} else if (col.prop === 'admin_id') {
// admin_id 列应该映射为 admin.name 来获取名称而不是 ID
exportFields['admin.name'] = col.label || '提交人'
} else {
// 使用列表中的 label 作为导出字段的标题
exportFields[col.prop] = col.label || col.name || col.prop
}
})
// 将资产字段添加到末尾
if (Object.keys(assetField).length > 0) {
Object.assign(exportFields, assetField)
}
// 检查列表列中是否已有提交人、提交单位和创建时间,如果没有才添加
const hasAdminName = filterTableColumns.some(col => col.prop === 'admin_id' || col.prop === 'admin.name')
const hasDepartmentName = filterTableColumns.some(col => col.prop === 'department.name')
const hasCreatedAt = filterTableColumns.some(col => col.prop === 'created_at')
if (!hasAdminName) {
exportFields['admin.name'] = '提交人'
}
if (!hasDepartmentName) {
exportFields['department.name'] = '提交单位'
}
if (!hasCreatedAt) {
exportFields['created_at'] = '创建时间'
}
// 构建请求参数,保持 filter 和 show_relation 与列表一致
const params = {
table_name: this.select.table_name,
is_export2: 1,
page: 1,
page_size: 99999,
is_auth: 1
}
// 复制 filter 参数(包括 formatSelect 中的筛选条件)
const currentSelect = this.formatSelect || this.select
if (currentSelect.filter && Array.isArray(currentSelect.filter)) {
currentSelect.filter.forEach((filter, index) => {
if (filter.key) {
params[`filter[${index}][key]`] = filter.key
params[`filter[${index}][op]`] = filter.op
params[`filter[${index}][value]`] = filter.value
}
})
}
// 添加 show_relation 参数(如果有)
if (currentSelect.show_relation) {
if (Array.isArray(currentSelect.show_relation)) {
currentSelect.show_relation.forEach((rel, index) => {
params[`show_relation[${index}]`] = rel
})
} else {
params['show_relation[0]'] = currentSelect.show_relation
}
}
// 添加 export_fields 参数,按照列表顺序
Object.keys(exportFields).forEach((field) => {
params[`export_fields[${field}]`] = exportFields[field]
})
// 调用下载接口
await download(
'/api/admin/base-form/index',
'get',
params,
`租赁台账_${new Date().getTime()}.xlsx`
)
} catch (error) {
console.error('导出失败:', error)
this.$message.error('导出失败,请稍后重试')
}
},
//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}`;
},
handleDateStartChange(val, target) {
// 开始时间变化时,更新筛选条件的值
if (!val) {
// 如果清空开始时间,只保留结束时间
const endValue = target.value && target.value.includes(',') ? target.value.split(',')[1] : '';
target.value = endValue ? `,${endValue}` : '';
if (target === this.select.filter[0]) {
this.dateRangeStart0 = null;
}
return;
}
// 获取结束时间
const endValue = target.value && target.value.includes(',') ? target.value.split(',')[1] : '';
// 如果是月份类型,需要转换为日期范围
if (this.isMonthField(target.key)) {
// val 应该是 YYYY-MM 格式,转换为该月第一天
const startDate = val + '-01';
let endDate = '';
if (endValue) {
// endValue 可能是日期格式YYYY-MM-DD或月份格式YYYY-MM
if (endValue.length === 10 && this.$moment(endValue).isValid()) {
// 已经是日期格式
endDate = endValue;
} else if (endValue.length === 7) {
// 月份格式,转换为该月最后一天
const monthMoment = this.$moment(endValue + '-01');
if (monthMoment.isValid()) {
endDate = monthMoment.endOf('month').format('YYYY-MM-DD');
}
}
}
target.value = endDate ? `${startDate},${endDate}` : `${startDate},`;
} else {
// 普通日期字段val 应该已经是 YYYY-MM-DD 格式(由 value-format 处理)
// 直接拼接,清理无效的结束值
let validEndValue = '';
if (endValue && endValue.length === 10 && this.$moment(endValue).isValid()) {
validEndValue = endValue;
} else if (endValue && !endValue.includes('Invalid date') && !endValue.includes('--')) {
// 如果不是明显的错误格式,尝试验证
const endMoment = this.$moment(endValue);
if (endMoment.isValid()) {
validEndValue = endMoment.format('YYYY-MM-DD');
}
}
target.value = validEndValue ? `${val},${validEndValue}` : `${val},`;
}
// 如果是第一个筛选条件,同步更新 dateRangeStart0
if (target === this.select.filter[0]) {
this.dateRangeStart0 = val;
}
},
handleDateEndChange(val, target) {
// 结束时间变化时,更新筛选条件的值
if (!val) {
// 如果清空结束时间,只保留开始时间
const startValue = target.value && target.value.includes(',') ? target.value.split(',')[0] : '';
target.value = startValue ? `${startValue},` : '';
if (target === this.select.filter[0]) {
this.dateRangeEnd0 = null;
}
return;
}
// 获取开始时间
const startValue = target.value && target.value.includes(',') ? target.value.split(',')[0] : '';
// 如果是月份类型,需要转换为日期范围
if (this.isMonthField(target.key)) {
// val 应该是 YYYY-MM 格式,转换为该月最后一天
const monthMoment = this.$moment(val + '-01');
if (!monthMoment.isValid()) {
return;
}
const endDate = monthMoment.endOf('month').format('YYYY-MM-DD');
let startDate = '';
if (startValue) {
// startValue 可能是日期格式YYYY-MM-DD或月份格式YYYY-MM
if (startValue.length === 10 && this.$moment(startValue).isValid()) {
// 已经是日期格式
startDate = startValue;
} else if (startValue.length === 7) {
// 月份格式,转换为该月第一天
const startMonthMoment = this.$moment(startValue + '-01');
if (startMonthMoment.isValid()) {
startDate = startValue + '-01';
}
}
}
target.value = startDate ? `${startDate},${endDate}` : `,${endDate}`;
} else {
// 普通日期字段val 应该已经是 YYYY-MM-DD 格式(由 value-format 处理)
// 直接拼接,清理无效的开始值
let validStartValue = '';
if (startValue && startValue.length === 10 && this.$moment(startValue).isValid()) {
validStartValue = startValue;
} else if (startValue && !startValue.includes('Invalid date') && !startValue.includes('--')) {
// 如果不是明显的错误格式,尝试验证
const startMoment = this.$moment(startValue);
if (startMoment.isValid()) {
validStartValue = startMoment.format('YYYY-MM-DD');
}
}
target.value = validStartValue ? `${validStartValue},${val}` : `,${val}`;
}
// 如果是第一个筛选条件,同步更新 dateRangeEnd0
if (target === this.select.filter[0]) {
this.dateRangeEnd0 = val;
}
},
getDateRangeStart(item) {
// 获取开始时间值
if (item.value && item.value.includes(',')) {
const startValue = item.value.split(',')[0];
// 如果是日期格式YYYY-MM-DD提取年月部分用于月份选择器
if (this.isMonthField(item.key) && startValue.includes('-')) {
return startValue.substring(0, 7); // 返回 YYYY-MM
}
return startValue;
}
return null;
},
getDateRangeEnd(item) {
// 获取结束时间值
if (item.value && item.value.includes(',')) {
const endValue = item.value.split(',')[1];
// 如果是日期格式YYYY-MM-DD提取年月部分用于月份选择器
if (this.isMonthField(item.key) && endValue.includes('-')) {
return endValue.substring(0, 7); // 返回 YYYY-MM
}
return endValue;
}
return null;
},
isMonthField(field) {
if (!field) return false;
// 检查是否是月份字段
const monthFields = ['qiandingnianyue']; // 签订年月
if (monthFields.includes(field)) {
return true;
}
// 通过检查字段名name中是否包含"年月"来判断
const fieldConfig = this.form.find((i) => i.field === field);
if (fieldConfig && fieldConfig.name) {
return fieldConfig.name.includes('年月');
}
return false;
},
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
)
);
});
if (this.table.find(row => row.prop === 'chuzufang')) {
this.table.find(row => row.prop === 'chuzufang').formatter = (row, column, cellValue, index) => row['chuzufang'] ? row['chuzufang'] : row['department']?.name
}
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={1000}>
<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: 'type',
width: 100,
render: (h, { row: myRow }) => {
let type = '资产'
if (myRow.house_id) {
type = '房产'
} else if (myRow.land_id) {
type = '土地'
} else if (myRow.biaodileixing) {
type = myRow.biaodileixing
}
return h('span', type)
}
},
{
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,
render: (h, { row: myRow }) => {
return h('span', myRow.xiangxiweizhi || " ")
}
},
{
title: '实际面积',
key: 'shijimianji',
width: 140,
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?.shijimianji || myRow.shijimianji || "0"))
}
},
{
title: '出租面积',
key: 'chuzumianji',
width: 140,
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 || "0"))
}
},
]}>
</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.name',
width: 120,
label: '提交单位'
})
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: {
formatSelect() {
let copySelect = deepCopy(this.select)
copySelect.filter = copySelect.filter.filter(i => i.key)
// 添加签订年月筛选条件
if (this.qiandingnianyueStart || this.qiandingnianyueEnd) {
let startMonth = this.qiandingnianyueStart || '';
// 如果没选结束年月,默认到当前年月
let endMonth = this.qiandingnianyueEnd || this.$moment().format('YYYY-MM');
if (startMonth) {
// 计算开始月份的第一天和结束月份的最后一天
let startDate = startMonth + '-01';
let endDate = this.$moment(endMonth + '-01').endOf('month').format('YYYY-MM-DD');
copySelect.filter.push({
key: 'qiandingnianyue',
op: 'range',
value: `${startDate},${endDate}`
});
}
}
// 添加租赁状态筛选条件(临期、已过期)
if (this.leaseStatusFilter) {
const now = this.$moment();
if (this.leaseStatusFilter === '临期') {
// 临期:结束期限在当前时间到 (当前时间 + config.time) 之间
// 因为临期的判断是:当前时间在 (结束期限 - config.time) 到 结束期限 之间
// 所以筛选条件是:结束期限在当前时间到 (当前时间 + config.time) 之间
const startDate = now.format('YYYY-MM-DD');
const endDate = this.$moment().add(this.config.time, this.config.unit).format('YYYY-MM-DD');
copySelect.filter.push({
key: 'zulinjieshuqixian',
op: 'range',
value: `${startDate},${endDate}`
});
} else if (this.leaseStatusFilter === '已过期') {
// 已过期:与 dashboard 保持一致
// 1. 结束期限在 1970-01-01 到 当前日期 之间
const startDate = this.$moment(0).format('YYYY-MM-DD');
const endDate = now.format('YYYY-MM-DD');
copySelect.filter.push({
key: 'zulinjieshuqixian',
op: 'range',
value: `${startDate},${endDate}`
});
// 2. zhuangtai 为 null
copySelect.filter.push({
key: 'zhuangtai',
op: 'is_null',
value: '1'
});
}
}
// 处理日期范围筛选:如果结束日期为空,默认使用当前日期
copySelect.filter = copySelect.filter.map(filter => {
// 排除签订年月字段,因为它有独立的筛选器
if (filter.key === 'qiandingnianyue') {
return filter;
}
// 处理普通日期字段的范围筛选
if (filter.key && filter.op === 'range' && this.isDateField(filter.key) && !this.isMonthField(filter.key) && filter.value) {
const parts = filter.value.split(',');
if (parts.length >= 1 && parts[0]) {
const startDate = parts[0];
const endDate = parts[1] || this.$moment().format('YYYY-MM-DD');
return {
...filter,
value: `${startDate},${endDate}`
};
}
}
return filter;
});
// 处理月份字段的范围筛选,将月份转换为日期范围
// 注意:签订年月字段应该使用独立的筛选器,这里只处理其他月份字段
copySelect.filter = copySelect.filter.map(filter => {
// 排除签订年月字段,因为它有独立的筛选器
if (filter.key === 'qiandingnianyue') {
return filter;
}
if (filter.key && filter.op === 'range' && this.isMonthField(filter.key) && filter.value) {
const parts = filter.value.split(',');
if (parts.length === 2) {
const startMonth = parts[0];
const endMonth = parts[1];
if (startMonth && endMonth) {
// 检查值是否已经是日期格式YYYY-MM-DD10个字符
let startDate = '';
if (startMonth.length === 10 && startMonth.includes('-')) {
// 已经是日期格式,直接使用
const startMoment = this.$moment(startMonth);
if (startMoment.isValid()) {
startDate = startMonth;
} else {
// 无效日期,尝试作为月份处理
startDate = startMonth.substring(0, 7) + '-01';
}
} else if (startMonth.length === 7 && startMonth.includes('-')) {
// 月份格式 YYYY-MM转换为该月第一天
startDate = startMonth + '-01';
} else {
// 其他格式尝试提取前7个字符作为月份
startDate = startMonth.substring(0, 7) + '-01';
}
let endDate = '';
if (endMonth.length === 10 && endMonth.includes('-')) {
// 已经是日期格式,转换为该月最后一天
const endMoment = this.$moment(endMonth);
if (endMoment.isValid()) {
endDate = endMoment.endOf('month').format('YYYY-MM-DD');
} else {
// 无效日期,尝试作为月份处理
const monthMoment = this.$moment(endMonth.substring(0, 7) + '-01');
if (monthMoment.isValid()) {
endDate = monthMoment.endOf('month').format('YYYY-MM-DD');
}
}
} else if (endMonth.length === 7 && endMonth.includes('-')) {
// 月份格式 YYYY-MM转换为该月最后一天
const monthMoment = this.$moment(endMonth + '-01');
if (monthMoment.isValid()) {
endDate = monthMoment.endOf('month').format('YYYY-MM-DD');
}
} else {
// 其他格式尝试提取前7个字符作为月份
const monthMoment = this.$moment(endMonth.substring(0, 7) + '-01');
if (monthMoment.isValid()) {
endDate = monthMoment.endOf('month').format('YYYY-MM-DD');
}
}
if (startDate && endDate) {
return {
...filter,
value: `${startDate},${endDate}`
};
}
}
}
}
return filter;
});
return copySelect
},
isDateField() {
return function (field) {
if (!field) return false;
// 排除签订年月,因为它有独立的筛选器
if (field === 'qiandingnianyue') {
return false;
}
// 检查特定字段或字段名中包含"日期"、"时间"、"期限"、"年月"的字段
const specificFields = [
'zulinkaishiqixian', // 租赁开始期限
'zulinjieshuqixian', // 租赁结束期限
];
if (specificFields.includes(field)) {
return true;
}
// 通过检查字段名name中是否包含"日期"、"时间"、"期限"、"年月"来判断
const fieldConfig = this.form.find((i) => i.field === field);
if (fieldConfig && fieldConfig.name) {
return fieldConfig.name.includes('日期') ||
fieldConfig.name.includes('时间') ||
fieldConfig.name.includes('期限') ||
(fieldConfig.name.includes('年月') && field !== 'qiandingnianyue');
}
return false;
};
},
getDatePickerType() {
return function (field) {
// 如果是月份字段,返回 month否则返回 date
return this.isMonthField(field) ? 'month' : 'date';
};
},
getDatePickerFormat() {
return function (field) {
// 如果是月份字段,返回 yyyy-MM否则返回 yyyy-MM-dd
return this.isMonthField(field) ? 'yyyy-MM' : 'yyyy-MM-dd';
};
},
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
: [];
};
}
},
watch: {
'select.filter[0].key'(newVal) {
// 当字段变化时,如果是日期字段且操作符是 range初始化日期范围值
if (this.isDateField(newVal) && this.select.filter[0].op === 'range') {
this.dateRangeStart0 = null;
this.dateRangeEnd0 = null;
if (this.select.filter[0].value) {
// 如果已有值,尝试解析
const parts = this.select.filter[0].value.split(',');
if (parts.length >= 1 && parts[0]) {
let startValue = parts[0];
// 如果是日期格式,提取年月部分用于月份选择器
if (this.isMonthField(newVal) && startValue.includes('-')) {
this.dateRangeStart0 = startValue.substring(0, 7);
} else {
this.dateRangeStart0 = startValue;
}
}
if (parts.length >= 2 && parts[1]) {
let endValue = parts[1];
// 如果是日期格式,提取年月部分用于月份选择器
if (this.isMonthField(newVal) && endValue.includes('-')) {
this.dateRangeEnd0 = endValue.substring(0, 7);
} else {
this.dateRangeEnd0 = endValue;
}
}
}
}
},
'select.filter[0].op'(newVal) {
// 当操作符变化时,如果是日期字段且操作符是 range初始化日期范围值
if (this.isDateField(this.select.filter[0].key) && newVal === 'range') {
this.dateRangeStart0 = null;
this.dateRangeEnd0 = null;
if (this.select.filter[0].value) {
// 如果是 range 且有值,尝试解析
const parts = this.select.filter[0].value.split(',');
if (parts.length >= 1 && parts[0]) {
let startValue = parts[0];
// 如果是日期格式,提取年月部分用于月份选择器
if (this.isMonthField(this.select.filter[0].key) && startValue.includes('-')) {
this.dateRangeStart0 = startValue.substring(0, 7);
} else {
this.dateRangeStart0 = startValue;
}
}
if (parts.length >= 2 && parts[1]) {
let endValue = parts[1];
// 如果是日期格式,提取年月部分用于月份选择器
if (this.isMonthField(this.select.filter[0].key) && endValue.includes('-')) {
this.dateRangeEnd0 = endValue.substring(0, 7);
} else {
this.dateRangeEnd0 = endValue;
}
}
}
}
}
},
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>