From 8b6f23bcac412fbd0ffb79ef51b3068650544518 Mon Sep 17 00:00:00 2001
From: purple <purple_lihe@163.com>
Date: Tue, 11 Aug 2020 16:12:11 +0800
Subject: [PATCH] =?UTF-8?q?feature(=E4=BC=98=E5=8C=96=E4=BD=9C=E4=BB=B7?=
 =?UTF-8?q?=E5=B9=B3=E5=8F=B0)=EF=BC=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

1. 接入es提升查询效率
2. 配置一套module,查询买卖成交案例
3. 配置住宅租赁汇总案例module
3. 新增菜单icon
---
 .../api/data/aggregateResidenceRentCase.js    |  26 +
 ruoyi-ui/src/assets/icons/svg/adjust.svg      |   1 +
 ruoyi-ui/src/assets/icons/svg/basicPrice.svg  |   1 +
 ruoyi-ui/src/assets/icons/svg/business.svg    |   1 +
 ruoyi-ui/src/assets/icons/svg/compute.svg     |   1 +
 ruoyi-ui/src/assets/icons/svg/lianjia.svg     |   1 +
 ruoyi-ui/src/assets/icons/svg/office.svg      |   1 +
 ruoyi-ui/src/assets/icons/svg/price.svg       |   1 +
 ruoyi-ui/src/assets/icons/svg/rent.svg        |   1 +
 ruoyi-ui/src/assets/icons/svg/residence.svg   |   1 +
 ruoyi-ui/src/assets/icons/svg/sale.svg        |   1 +
 ruoyi-ui/src/assets/icons/svg/ultimate.svg    |   1 +
 ruoyi-ui/src/main.js                          | 143 ++--
 ruoyi-ui/src/utils/index.js                   | 757 +++++++++---------
 ruoyi-ui/src/utils/ruoyi.js                   | 289 +++----
 .../data/cases/AggregateResidenceRentCase.vue | 298 +++++++
 16 files changed, 933 insertions(+), 591 deletions(-)
 create mode 100644 ruoyi-ui/src/api/data/aggregateResidenceRentCase.js
 create mode 100644 ruoyi-ui/src/assets/icons/svg/adjust.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/basicPrice.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/business.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/compute.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/lianjia.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/office.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/price.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/rent.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/residence.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/sale.svg
 create mode 100644 ruoyi-ui/src/assets/icons/svg/ultimate.svg
 create mode 100644 ruoyi-ui/src/views/data/cases/AggregateResidenceRentCase.vue

diff --git a/ruoyi-ui/src/api/data/aggregateResidenceRentCase.js b/ruoyi-ui/src/api/data/aggregateResidenceRentCase.js
new file mode 100644
index 000000000..347e8b535
--- /dev/null
+++ b/ruoyi-ui/src/api/data/aggregateResidenceRentCase.js
@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+// 查询住宅销售基价修正列表
+export function list(query) {
+  return request({
+    url: '/data/cases/residence/aggregate-rent-case/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出住宅销售基价修正
+export function export2File(query) {
+  return request({
+    url: '/data/cases/residence/aggregate-rent-case/export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getYearMonthList() {
+  return request({
+    url: '/data/cases/residence/aggregate-rent-case/yearmonth',
+    method: 'get'
+  })
+}
diff --git a/ruoyi-ui/src/assets/icons/svg/adjust.svg b/ruoyi-ui/src/assets/icons/svg/adjust.svg
new file mode 100644
index 000000000..df2f1c4bf
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/adjust.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597113718881" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4634" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M178.7 312.2c11 0 19.9-8.9 19.9-20.8 0-49.2 40.1-89.2 89.3-89.2 16.1 0 31.4 4.8 45 10.7 1.5 0.9 3.2 1.4 4.7 2.4l-15 17.5c-2.6 3.1-3.4 7.2-2.1 10.8 1.3 3.3 4.1 5.6 7.6 6.1l76.3 11.4c3.4 0 6.7-1.7 8.8-4.6 2.1-2.9 2.7-6.3 1.7-9.6l-22.3-72.2c-1.3-4.1-4.9-6.8-9.3-6.8-3.1 0-6.1 1.4-8.3 3.9l-11 16.5c-22.6-16.8-48.9-25.7-76.1-25.7-71.1 0-129 57.9-129 129.8 0 10.9 8.9 19.8 19.8 19.8zM396.8 270.1c-10.9 0-19.8 8.9-19.7 21.4 0 49.2-40.1 89.3-89.3 89.3-15.1 0-29.8-4.4-43.2-9.8-1.7-0.9-3.6-1.5-5.2-2.6l15.1-16.7c2.7-3 3.6-7.1 2.4-10.7-1.2-3.3-4-5.7-7.4-6.3l-76.3-13.2c-3.4 0-6.6 1.7-8.7 4.5-2.1 2.8-2.8 6.2-1.9 9.4l20.6 72.8c1.2 4.2 4.9 7 9.3 7 3.1 0 6-1.4 8.1-3.7l11.4-16.1c22.2 16.4 48.4 25.1 75.8 25.1 71.1 0 129-57.9 128.6-131.5-0.4-10.6-9.1-18.9-19.6-18.9zM481 481.7H207.9c-17.9 0-32.5 14.6-32.5 32.5s14.6 32.5 32.5 32.5H481c17.9 0 32.5-14.6 32.5-32.5 0-17.8-14.6-32.5-32.5-32.5z" p-id="4635" fill="#BFBFBF"></path><path d="M161.7 837.5c-26.1 0-47.3-21.2-47.3-47.3V106c0-26.1 21.2-47.3 47.3-47.3h320.7v88.6c0 46.8 38.1 84.9 84.9 84.9h95.1l5.3 4.5 0.5 4.6v322.1H727V241.2l-0.5-5.7c-1.3-23-10.3-44.7-25.3-61.3L572.6 32.7C553.7 11.9 526.8 0 498.8 0H161.7c-58.5 0-106 47.5-106 106v684.3c0 58.4 47.6 106 106 106h347.2v-58.7H161.7z" p-id="4636" fill="#BFBFBF"></path><path d="M511.5 640.6c2.9-15.9 10.5-30.2 21.1-42.4H207.9c-17.9 0-32.5 14.6-32.5 32.5s14.6 32.5 32.5 32.5h301v-14.8l2.6-7.8zM175.3 747.1c0 17.9 14.6 32.5 32.5 32.5h301v-65.1h-301c-17.8 0.1-32.5 14.7-32.5 32.6zM926.1 1022.8H602.3c-0.7-0.3-1.5-0.6-2.2-0.8-18.7-3.4-31.2-14.1-37.6-32-1.1-3.1-1.7-6.4-2.5-9.5V656.8c0.3-0.7 0.6-1.5 0.8-2.2 3.8-20.6 16.1-33.3 36.2-38.7 1.8-0.5 3.6-0.9 5.3-1.3h278.3c11.6 2.6 20.7 9.5 28.9 17.4 13.7 13.1 27.2 26.6 40.3 40.2 8.3 8.6 15.7 18 18.4 30.1v278.3c-0.3 0.7-0.6 1.5-0.8 2.2-3.8 20.6-16.1 33.3-36.2 38.7-1.6 0.5-3.4 0.9-5.1 1.3m-161.9-15.6h139.1c11.8 0 18-6.2 18-17.9V836.6c0-11.7-6.3-18-17.9-18H624.8c-11.4 0-17.8 6.3-17.8 17.7v153.1c0 1.8 0 3.7 0.5 5.5 1.9 8.1 8 12.3 17.6 12.3h139.1m-8-235.5h99.2c12.7 0 18.8-6.1 18.8-18.8v-104c0-12.8-6-18.8-18.8-18.8H656.9c-12.5 0-18.7 6.1-18.7 18.5V753c0 12.4 6.2 18.6 18.6 18.6 33.3 0.1 66.3 0.1 99.4 0.1M796 646.2h46.1v109.2H796V646.2" p-id="4637" fill="#BFBFBF"></path></svg>
diff --git a/ruoyi-ui/src/assets/icons/svg/basicPrice.svg b/ruoyi-ui/src/assets/icons/svg/basicPrice.svg
new file mode 100644
index 000000000..4dea02cfb
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/basicPrice.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597125639935" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13471" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M192 672c19.2 0 32 12.8 32 32v128c0 19.2-12.8 32-32 32s-32-12.8-32-32v-128c0-19.2 12.8-32 32-32zM416 480c19.2 0 32 12.8 32 32v320c0 19.2-12.8 32-32 32s-32-12.8-32-32V512c0-19.2 12.8-32 32-32zM608 608c19.2 0 32 12.8 32 32v192c0 19.2-12.8 32-32 32s-32-12.8-32-32v-192c0-19.2 12.8-32 32-32zM832 448c19.2 0 32 12.8 32 32v352c0 19.2-12.8 32-32 32s-32-12.8-32-32V480c0-19.2 12.8-32 32-32z" fill="#BFBFBF" p-id="13472"></path><path d="M419.2 323.2l-246.4 246.4c-12.8 12.8-32 12.8-44.8 0-12.8-12.8-12.8-32 0-44.8l291.2-291.2 192 192 217.6-217.6c12.8-12.8 32-12.8 44.8 0 12.8 12.8 12.8 32 0 44.8l-262.4 262.4-192-192z" fill="#BFBFBF" p-id="13473"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/business.svg b/ruoyi-ui/src/assets/icons/svg/business.svg
new file mode 100644
index 000000000..9c5886f44
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/business.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597113833754" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6873" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M510.9 565.9L374.7 429.7c-5.4-5.4-5.4-14.1 0-19.4s14.1-5.4 19.4 0L510.9 527l115.7-115.7c5.4-5.4 14.1-5.4 19.4 0 5.4 5.4 5.4 14.1 0 19.4L510.9 565.9z" fill="#BFBFBF" p-id="6874"></path><path d="M636.4 560.2h-252c-7.6 0-13.7-6.1-13.7-13.7s6.1-13.7 13.7-13.7h251.9c7.6 0 13.7 6.1 13.7 13.7 0.1 7.5-6.1 13.7-13.6 13.7zM636.4 656.1h-252c-7.6 0-13.7-6.1-13.7-13.7s6.1-13.7 13.7-13.7h251.9c7.6 0 13.7 6.1 13.7 13.7 0.1 7.5-6.1 13.7-13.6 13.7z" fill="#BFBFBF" p-id="6875"></path><path d="M510.9 784.6c-7.6 0-13.7-6.1-13.7-13.7V546.5c0-7.6 6.1-13.7 13.7-13.7s13.7 6.1 13.7 13.7v224.4c0 7.5-6.1 13.7-13.7 13.7z" fill="#BFBFBF" p-id="6876"></path><path d="M946 513.4c-3.1 0-6.1-1-8.7-3.1L521.4 169.2c-6.2-5.1-15.1-5.1-21.3 0L86.7 507.9c-5.9 4.8-14.5 3.9-19.3-1.9-4.8-5.9-3.9-14.5 1.9-19.3L482.7 148c16.3-13.3 39.8-13.3 56.1 0l415.9 341.1c5.9 4.8 6.7 13.5 1.9 19.3-2.7 3.3-6.6 5-10.6 5z" fill="#BFBFBF" p-id="6877"></path><path d="M752.8 886.1H268c-41.3 0-74.9-33.6-74.9-74.9V391.7c0-7.6 6.1-13.7 13.7-13.7s13.7 6.1 13.7 13.7v419.4c0 26.2 21.3 47.5 47.5 47.5h484.8c26.2 0 47.5-21.3 47.5-47.5V391.7c0-7.6 6.1-13.7 13.7-13.7s13.7 6.1 13.7 13.7v419.4c0 41.3-33.6 75-74.9 75z" fill="#BFBFBF" p-id="6878"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/compute.svg b/ruoyi-ui/src/assets/icons/svg/compute.svg
new file mode 100644
index 000000000..4684782a0
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/compute.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597125321332" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10786" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M869.262222 116.053333H571.164444c-20.48 0-36.408889 15.928889-36.408888 36.408889v300.373334c0 20.48 15.928889 36.408889 36.408888 36.408888h298.097778c20.48 0 36.408889-15.928889 36.408889-36.408888V152.462222c0-20.48-15.928889-36.408889-36.408889-36.408889z m-75.093333 211.626667h-150.186667c-15.928889 0-29.582222-11.377778-29.582222-25.031111 0-13.653333 13.653333-25.031111 29.582222-25.031111h150.186667c15.928889 0 29.582222 11.377778 29.582222 25.031111 0 13.653333-13.653333 25.031111-29.582222 25.031111z m0 0M436.906667 116.053333H138.808889c-20.48 0-36.408889 15.928889-36.408889 36.408889v300.373334c0 20.48 15.928889 36.408889 36.408889 36.408888h298.097778c20.48 0 36.408889-15.928889 36.408889-36.408888V152.462222c0-20.48-15.928889-36.408889-36.408889-36.408889z m-75.093334 211.626667h-50.062222v50.062222c0 15.928889-11.377778 29.582222-25.031111 29.582222-13.653333 0-25.031111-13.653333-25.031111-29.582222v-50.062222H211.626667c-15.928889 0-29.582222-11.377778-29.582223-25.031111 0-13.653333 13.653333-25.031111 29.582223-25.031111h50.062222V227.555556c0-15.928889 11.377778-29.582222 25.031111-29.582223 13.653333 0 25.031111 13.653333 25.031111 29.582223v50.062222h50.062222c15.928889 0 29.582222 11.377778 29.582223 25.031111 0 13.653333-13.653333 25.031111-29.582223 25.031111z m0 0M436.906667 546.133333H138.808889c-20.48 0-36.408889 15.928889-36.408889 36.408889v300.373334c0 20.48 15.928889 36.408889 36.408889 36.408888h298.097778c20.48 0 36.408889-15.928889 36.408889-36.408888V582.542222c0-20.48-15.928889-36.408889-36.408889-36.408889z m-150.186667 81.92c15.928889 0 29.582222 13.653333 29.582222 29.582223 0 15.928889-13.653333 29.582222-29.582222 29.582222-15.928889 0-29.582222-13.653333-29.582222-29.582222 2.275556-15.928889 13.653333-29.582222 29.582222-29.582223z m0 209.351111c-15.928889 0-29.582222-13.653333-29.582222-29.582222 0-15.928889 13.653333-29.582222 29.582222-29.582222 15.928889 0 29.582222 13.653333 29.582222 29.582222 0 18.204444-13.653333 29.582222-29.582222 29.582222z m75.093333-79.644444H211.626667c-15.928889 0-29.582222-11.377778-29.582223-25.031111 0-13.653333 13.653333-25.031111 29.582223-25.031111h150.186666c15.928889 0 29.582222 11.377778 29.582223 25.031111 0 13.653333-13.653333 25.031111-29.582223 25.031111z m0 0M869.262222 546.133333H571.164444c-20.48 0-36.408889 15.928889-36.408888 36.408889v300.373334c0 20.48 15.928889 36.408889 36.408888 36.408888h298.097778c20.48 0 36.408889-15.928889 36.408889-36.408888V582.542222c0-20.48-15.928889-36.408889-36.408889-36.408889z m-75.093333 259.413334h-150.186667c-15.928889 0-29.582222-11.377778-29.582222-25.031111 0-13.653333 13.653333-25.031111 29.582222-25.031112h150.186667c15.928889 0 29.582222 11.377778 29.582222 25.031112 0 13.653333-13.653333 25.031111-29.582222 25.031111z m0-95.573334h-150.186667c-15.928889 0-29.582222-11.377778-29.582222-25.031111 0-13.653333 13.653333-25.031111 29.582222-25.031111h150.186667c15.928889 0 29.582222 11.377778 29.582222 25.031111 0 13.653333-13.653333 25.031111-29.582222 25.031111z m0 0" fill="#BFBFBF" p-id="10787"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/lianjia.svg b/ruoyi-ui/src/assets/icons/svg/lianjia.svg
new file mode 100644
index 000000000..7012ef15d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/lianjia.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597125922762" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15530" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M552.362667 101.034667l406.954666 373.034666a34.133333 34.133333 0 0 1-23.04 59.306667L896 533.333333v298.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-298.666667h-40.234667a34.133333 34.133333 0 0 1-23.04-59.264l406.912-373.034666a59.733333 59.733333 0 0 1 80.725334 0zM400.896 614.826667a34.901333 34.901333 0 0 0-49.237333 3.541333l-6.357334 7.978667a129.834667 129.834667 0 0 0-25.301333 77.056v46.677333c0 26.453333 21.504 48 48 48h288c26.496 0 48-21.504 48-48v-46.677333c0-30.549333-10.666667-59.349333-29.184-82.005334l-1.92-2.176-2.048-2.048a38.442667 38.442667 0 0 0-54.357333 2.688l-2.389334 2.602667a80.085333 80.085333 0 0 1-5.504 5.674667 152.96 152.96 0 0 1-96.597333 34.176 152.874667 152.874667 0 0 1-111.104-47.488zM512 353.194667a115.2 115.2 0 0 0-115.2 115.2v40.32a115.2 115.2 0 0 0 230.4 0v-40.32a115.2 115.2 0 0 0-115.2-115.2z" fill="#39A461" p-id="15531"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/office.svg b/ruoyi-ui/src/assets/icons/svg/office.svg
new file mode 100644
index 000000000..1fbb18515
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/office.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597125223401" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6730" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M852.986802 59.256853v906.525888H169.973604V59.256853h683.013198M912.243655 0H111.756345v1024h800.48731V0z" p-id="6731" fill="#BFBFBF"></path><path d="M247.943147 132.028426h81.088325v81.088325h-81.088325zM397.64467 132.028426h81.088325v81.088325h-81.088325zM547.346193 132.028426h81.088325v81.088325h-81.088325zM697.047716 132.028426h81.088325v81.088325h-81.088325zM247.943147 280.690355h81.088325v81.088325h-81.088325zM397.64467 280.690355h81.088325v81.088325h-81.088325zM547.346193 280.690355h81.088325v81.088325h-81.088325zM697.047716 280.690355h81.088325v81.088325h-81.088325zM697.047716 726.676142h81.088325v81.088325h-81.088325zM247.943147 726.676142h81.088325v81.088325h-81.088325z" p-id="6732" fill="#BFBFBF"></path><path d="M395.565482 835.833503h231.829442v115.394923H395.565482z" fill="#BFBFBF" p-id="6733"></path><path d="M395.565482 806.724873h231.829442v164.255838H395.565482zM247.943147 429.352284h81.088325v81.088325h-81.088325zM397.64467 429.352284h81.088325v81.088325h-81.088325zM547.346193 429.352284h81.088325v81.088325h-81.088325zM697.047716 429.352284h81.088325v81.088325h-81.088325z" p-id="6734" fill="#BFBFBF"></path><path d="M247.943147 578.014213h81.088325v81.088325h-81.088325zM397.64467 578.014213h81.088325v81.088325h-81.088325zM547.346193 578.014213h81.088325v81.088325h-81.088325zM697.047716 578.014213h81.088325v81.088325h-81.088325z" p-id="6735" fill="#BFBFBF"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/price.svg b/ruoyi-ui/src/assets/icons/svg/price.svg
new file mode 100644
index 000000000..1a853d892
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/price.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597122406396" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4087" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M512 64C264.576 64 64 264.576 64 512c0 247.36 200.576 448 448 448 247.424 0 448-200.64 448-448C960 264.576 759.424 64 512 64zM689.728 478.464l0 94.656L564.48 573.12l0 32.832 125.248 0 0 94.784L564.48 700.736l0 91.008L471.168 791.744l0-91.008L349.44 700.736 349.44 605.952l121.728 0L471.168 573.12 349.44 573.12 349.44 478.464l71.104 0L301.312 258.688l107.712 0L512 448.256l102.912-189.568 107.776 0L603.456 478.464 689.728 478.464z" p-id="4088" fill="#BFBFBF"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/rent.svg b/ruoyi-ui/src/assets/icons/svg/rent.svg
new file mode 100644
index 000000000..2c5202779
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/rent.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597113553063" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2134" width="211.71875" height="200" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M510.192941 1004.242824C238.411294 1003.941647 18.221176 783.721412 17.889882 512 18.221176 240.278588 238.441412 20.058353 510.192941 19.757176 781.884235 20.058353 1002.104471 240.278588 1002.405647 512c-0.301176 271.721412-220.521412 491.941647-492.242823 492.242824z m0-921.268706C273.257412 83.184941 81.317647 275.124706 81.046588 512c0.240941 236.845176 192.150588 428.815059 429.025883 429.086118 236.875294-0.271059 428.815059-192.210824 429.086117-429.086118-0.240941-236.845176-192.150588-428.784941-429.025882-429.025882z" fill="#BFBFBF" p-id="2135"></path><path d="M248.922353 602.112c32.858353-46.110118 60.114824-104.749176 81.859765-175.706353H251.512471V389.12h85.534117V306.296471c-22.016 1.746824-46.170353 3.523765-72.372706 5.210353a391.649882 391.649882 0 0 0-7.860706-38.309648c73.065412-4.216471 135.860706-9.999059 188.29553-17.317647l9.456941 39.845647c-20.992 2.108235-47.254588 4.577882-78.727529 7.318589v86.046117h82.944v37.225412h-82.944v70.896941l23.100235-20.419764a1181.515294 1181.515294 0 0 1 67.162353 71.318588l-29.906824 25.690353a877.206588 877.206588 0 0 0-60.355764-70.324706v241.904941h-38.79153v-234.496a570.036706 570.036706 0 0 1-69.812706 136.432941 1108.871529 1108.871529 0 0 0-18.311529-45.206588z m173.116235 83.998118h63.006118V262.234353h240.278588V686.08h45.116235v37.225412H422.038588v-37.225412zM525.854118 299.369412v103.905882h158.448941V299.369412h-158.448941z m0 244.495059h158.448941V440.018824h-158.448941v103.845647z m0 142.215529h158.448941v-105.472h-158.448941v105.472z" fill="#BFBFBF" p-id="2136"></path></svg>
diff --git a/ruoyi-ui/src/assets/icons/svg/residence.svg b/ruoyi-ui/src/assets/icons/svg/residence.svg
new file mode 100644
index 000000000..e93a151f3
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/residence.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597113735162" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4884" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M981.737401 435.219371L558.429727 18.925867a66.55781 66.55781 0 0 0-92.976141 0L407.2923 76.114385a38.091547 38.091547 0 0 0-14.489123-2.867105H186.01318A85.501187 85.501187 0 0 0 100.61439 158.748467v195.270375a38.142745 38.142745 0 0 0 5.119831 18.738584L42.145913 435.219371A65.021861 65.021861 0 0 0 27.400798 506.38503a65.789836 65.789836 0 0 0 61.437979 40.958652h20.991309v376.717206A100.041509 100.041509 0 0 0 209.564405 1024h604.754504a100.041509 100.041509 0 0 0 99.939112-99.939112V547.343682h20.991309a65.789836 65.789836 0 0 0 61.437979-40.958652 65.021861 65.021861 0 0 0-14.949908-71.165659zM511.941657 81.029424l396.172566 389.414388H115.769091zM177.51426 158.748467a8.601317 8.601317 0 0 1 8.49892-8.498921h145.966398L177.51426 302.10375z m358.797795 784.716583v-218.104825a1.279958 1.279958 0 0 1 1.126363-1.177561h84.784411a1.331156 1.331156 0 0 1 1.177561 1.177561v218.002428a1.331156 1.331156 0 0 1-1.177561 1.177561H537.540815a1.279958 1.279958 0 0 1-1.22876-1.177561z m301.097294-19.301765a23.346432 23.346432 0 0 1-23.09044 23.039242h-114.223442v-221.842302a78.179828 78.179828 0 0 0-78.077432-78.077431h-84.47722a78.12863 78.12863 0 0 0-78.026233 78.077431V947.10013H209.564405a23.346432 23.346432 0 0 1-23.09044-23.039242V547.343682h650.935384z" p-id="4885" fill="#BFBFBF"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/sale.svg b/ruoyi-ui/src/assets/icons/svg/sale.svg
new file mode 100644
index 000000000..b8f4759fd
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/sale.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597113679046" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4408" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M994.802 251.097v567.292c0 48.281-42.244 90.527-90.523 90.527H493.896c-18.105 0-30.175-12.07-30.175-30.178 0-36.209-30.176-66.383-66.385-66.383-36.211 0-72.422 30.174-72.422 66.383 0 18.107-12.069 30.178-30.174 30.178H119.725c-48.28 0-90.526-42.246-90.526-90.527V251.097c0-48.28 42.247-90.524 90.526-90.524h175.016c18.104 0 30.174 12.07 30.174 30.175 0 36.209 30.177 66.385 66.386 66.385 36.211 0 66.387-30.176 66.387-66.385 0-18.105 12.069-30.175 30.173-30.175h410.381c54.316 0 96.56 42.244 96.56 90.524zM524.07 848.564h380.208c18.105 0 30.174-12.068 30.174-30.176V251.097c0-18.105-12.068-30.175-30.174-30.175H524.07c-12.068 54.315-66.383 96.56-126.734 96.56-60.353 0-114.665-42.244-126.737-96.56H119.725c-18.105 0-30.176 12.07-30.176 30.175v567.292c0 18.107 12.071 30.176 30.176 30.176h150.874c12.072-54.314 66.385-96.561 126.737-96.561 60.351 0 108.629 42.246 126.734 96.56z" p-id="4409" fill="#BFBFBF"></path><path d="M158.602 617.545l25.5-30.601c15.9 14.7 36.9 24.601 56.4 24.601 23.1 0 35.4-9.9 35.4-25.5 0-16.501-13.5-21.601-33.3-30.001l-29.7-12.6c-22.5-9.301-45-27.301-45-59.701 0-36.3 31.8-64.2 76.801-64.2 25.8 0 51.601 10.2 69.601 28.5l-22.5 27.9c-14.1-11.7-28.8-18.3-47.1-18.3-19.5 0-32.101 8.7-32.101 23.399 0 15.9 15.9 21.601 34.8 29.101l29.101 12.301c27 11.1 44.7 28.2 44.7 60.3 0 36.301-30.3 67.201-81.601 67.201-29.7 0-59.401-11.7-81.001-32.4zM464.601 588.744H392.6L377 645.745h-45l71.101-222.002h52.2l71.4 222.002h-46.5l-15.6-57.001z m-9.6-34.5l-6.6-24.3c-6.9-23.101-12.9-48.601-19.5-72.602h-1.2c-5.7 24.301-12.3 49.501-18.9 72.602l-6.6 24.3h52.8zM552.797 423.743h44.4v184.802h90.002v37.2H552.797V423.743zM725.896 423.743h136.201v36.9h-91.801v51.3h78v37.201h-78v59.4h95.102v37.2H725.896V423.743z" p-id="4410" fill="#BFBFBF"></path></svg>
diff --git a/ruoyi-ui/src/assets/icons/svg/ultimate.svg b/ruoyi-ui/src/assets/icons/svg/ultimate.svg
new file mode 100644
index 000000000..a9d1ac140
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/ultimate.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1597125499816" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12329" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M97.878 483.853c0-117.062-0.108-160.999-0.108-278.062 0-101.472 56.328-108.082 110.483-108.082h441.933c85.128 0 111.453 28.968 111.453 110.481v55.241c0 43.562-55.419 38.57-55.419 0V208.19c0-40.918-13.309-55.24-56.035-55.24H208.252c-45.746 0-55.241 6.203-55.241 55.24v552.407c0 30.278 16.572 55.241 55.241 55.241 67.004 0 43.482 0.026 110.484 0 33.77 0 36.252 55.241 0 55.241s-63.711 0.44-131.306 0.17c-39.867-0.163-72.883-23.774-84.643-60.322-3.292-10.223-4.694-21.525-4.694-32.34-0.323-116.658-0.215-178.076-0.215-294.734" fill="#BFBFBF" p-id="12330"></path><path d="M649.644 926.291c-152.344-0.027-275.666-123.537-275.666-276.122 0-152.586 123.915-276.259 276.529-276.042 152.616 0.215 275.884 124.022 275.722 276.878-0.16 152.236-123.807 275.314-276.585 275.286m0.756-496.868c-121.109-0.271-220.641 98.828-220.91 220.045-0.27 121.541 98.345 220.934 219.561 221.287 121.704 0.324 221.505-98.208 221.775-219.047 0.324-122.594-98.236-221.99-220.426-222.285M594.945 263.061c44.02 0.027 37.978 55.979 0 55.979h-331.45c-41.431 0-39.704-55.979 0-55.979 108.756-0.027 289.155-0.027 331.45 0zM318.736 428.782c44.021 0.028 37.979 55.98 0 55.98h-55.242c-41.431 0-39.704-55.98 0-55.98 108.757-0.027 12.948-0.027 55.242 0z" fill="#BFBFBF" p-id="12331"></path><path d="M785.502 547.22c-12.496-12.498-32.758-12.498-45.254 0L602.151 685.316l-42.191-42.191c-12.498-12.496-32.758-12.496-45.256 0-12.496 12.497-12.496 32.759 0 45.256l64.818 64.818c6.249 6.248 14.438 9.372 22.628 9.372s16.379-3.124 22.628-9.372a32.424 32.424 0 0 0 2.402-2.695 32.304 32.304 0 0 0 2.689-2.397l155.633-155.633c12.497-12.496 12.497-32.758 0-45.254z" fill="#BFBFBF" p-id="12332"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index c2834bf76..ffae62dba 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -1,71 +1,72 @@
-import Vue from 'vue'
-
-import Cookies from 'js-cookie'
-
-import 'normalize.css/normalize.css' // a modern alternative to CSS resets
-
-import Element from 'element-ui'
-import './assets/styles/element-variables.scss'
-
-import '@/assets/styles/index.scss' // global css
-import '@/assets/styles/ruoyi.scss' // ruoyi css
-import App from './App'
-import store from './store'
-import router from './router'
-import permission from './directive/permission'
-
-import './assets/icons' // icon
-import './permission' // permission control
-import { getDicts } from "@/api/system/dict/data";
-import { getConfigKey } from "@/api/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, download, handleTree } from "@/utils/ruoyi";
-import Pagination from "@/components/Pagination";
-
-// 全局方法挂载
-Vue.prototype.getDicts = getDicts
-Vue.prototype.getConfigKey = getConfigKey
-Vue.prototype.parseTime = parseTime
-Vue.prototype.resetForm = resetForm
-Vue.prototype.addDateRange = addDateRange
-Vue.prototype.selectDictLabel = selectDictLabel
-Vue.prototype.download = download
-Vue.prototype.handleTree = handleTree
-
-Vue.prototype.msgSuccess = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "success" });
-}
-
-Vue.prototype.msgError = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "error" });
-}
-
-Vue.prototype.msgInfo = function (msg) {
-  this.$message.info(msg);
-}
-
-// 全局组件挂载
-Vue.component('Pagination', Pagination)
-
-Vue.use(permission)
-
-/**
- * If you don't want to use mock-server
- * you want to use MockJs for mock api
- * you can execute: mockXHR()
- *
- * Currently MockJs will be used in the production environment,
- * please remove it before going online! ! !
- */
-
-Vue.use(Element, {
-  size: Cookies.get('size') || 'medium' // set element-ui default size
-})
-
-Vue.config.productionTip = false
-
-new Vue({
-  el: '#app',
-  router,
-  store,
-  render: h => h(App)
-})
+import Vue from 'vue'
+
+import Cookies from 'js-cookie'
+
+import 'normalize.css/normalize.css' // a modern alternative to CSS resets
+
+import Element from 'element-ui'
+import './assets/styles/element-variables.scss'
+
+import '@/assets/styles/index.scss' // global css
+import '@/assets/styles/ruoyi.scss' // ruoyi css
+import App from './App'
+import store from './store'
+import router from './router'
+import permission from './directive/permission'
+
+import './assets/icons' // icon
+import './permission' // permission control
+import { getDicts } from "@/api/system/dict/data";
+import { getConfigKey } from "@/api/system/config";
+import { parseTime, resetForm, addDateRange, selectDictLabel, download, handleTree,formatDate } from "@/utils/ruoyi";
+import Pagination from "@/components/Pagination";
+
+// 全局方法挂载
+Vue.prototype.getDicts = getDicts
+Vue.prototype.getConfigKey = getConfigKey
+Vue.prototype.parseTime = parseTime
+Vue.prototype.formatDate = formatDate
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.download = download
+Vue.prototype.handleTree = handleTree
+
+Vue.prototype.msgSuccess = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "success" });
+}
+
+Vue.prototype.msgError = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "error" });
+}
+
+Vue.prototype.msgInfo = function (msg) {
+  this.$message.info(msg);
+}
+
+// 全局组件挂载
+Vue.component('Pagination', Pagination)
+
+Vue.use(permission)
+
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online! ! !
+ */
+
+Vue.use(Element, {
+  size: Cookies.get('size') || 'medium' // set element-ui default size
+})
+
+Vue.config.productionTip = false
+
+new Vue({
+  el: '#app',
+  router,
+  store,
+  render: h => h(App)
+})
diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
index 6c3017c76..360ed5f42 100644
--- a/ruoyi-ui/src/utils/index.js
+++ b/ruoyi-ui/src/utils/index.js
@@ -1,386 +1,371 @@
-/**
- * 表格时间格式化
- */
-export function formatDate(cellValue) {
-  if (cellValue == null || cellValue == "") return "";
-  var date = new Date(cellValue) 
-  var year = date.getFullYear()
-  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
-  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() 
-  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() 
-  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() 
-  var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
-  return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
-}
-
-/**
- * @param {number} time
- * @param {string} option
- * @returns {string}
- */
-export function formatTime(time, option) {
-  if (('' + time).length === 10) {
-    time = parseInt(time) * 1000
-  } else {
-    time = +time
-  }
-  const d = new Date(time)
-  const now = Date.now()
-
-  const diff = (now - d) / 1000
-
-  if (diff < 30) {
-    return '刚刚'
-  } else if (diff < 3600) {
-    // less 1 hour
-    return Math.ceil(diff / 60) + '分钟前'
-  } else if (diff < 3600 * 24) {
-    return Math.ceil(diff / 3600) + '小时前'
-  } else if (diff < 3600 * 24 * 2) {
-    return '1天前'
-  }
-  if (option) {
-    return parseTime(time, option)
-  } else {
-    return (
-      d.getMonth() +
-      1 +
-      '月' +
-      d.getDate() +
-      '日' +
-      d.getHours() +
-      '时' +
-      d.getMinutes() +
-      '分'
-    )
-  }
-}
-
-/**
- * @param {string} url
- * @returns {Object}
- */
-export function getQueryObject(url) {
-  url = url == null ? window.location.href : url
-  const search = url.substring(url.lastIndexOf('?') + 1)
-  const obj = {}
-  const reg = /([^?&=]+)=([^?&=]*)/g
-  search.replace(reg, (rs, $1, $2) => {
-    const name = decodeURIComponent($1)
-    let val = decodeURIComponent($2)
-    val = String(val)
-    obj[name] = val
-    return rs
-  })
-  return obj
-}
-
-/**
- * @param {string} input value
- * @returns {number} output value
- */
-export function byteLength(str) {
-  // returns the byte length of an utf8 string
-  let s = str.length
-  for (var i = str.length - 1; i >= 0; i--) {
-    const code = str.charCodeAt(i)
-    if (code > 0x7f && code <= 0x7ff) s++
-    else if (code > 0x7ff && code <= 0xffff) s += 2
-    if (code >= 0xDC00 && code <= 0xDFFF) i--
-  }
-  return s
-}
-
-/**
- * @param {Array} actual
- * @returns {Array}
- */
-export function cleanArray(actual) {
-  const newArray = []
-  for (let i = 0; i < actual.length; i++) {
-    if (actual[i]) {
-      newArray.push(actual[i])
-    }
-  }
-  return newArray
-}
-
-/**
- * @param {Object} json
- * @returns {Array}
- */
-export function param(json) {
-  if (!json) return ''
-  return cleanArray(
-    Object.keys(json).map(key => {
-      if (json[key] === undefined) return ''
-      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
-    })
-  ).join('&')
-}
-
-/**
- * @param {string} url
- * @returns {Object}
- */
-export function param2Obj(url) {
-  const search = url.split('?')[1]
-  if (!search) {
-    return {}
-  }
-  return JSON.parse(
-    '{"' +
-      decodeURIComponent(search)
-        .replace(/"/g, '\\"')
-        .replace(/&/g, '","')
-        .replace(/=/g, '":"')
-        .replace(/\+/g, ' ') +
-      '"}'
-  )
-}
-
-/**
- * @param {string} val
- * @returns {string}
- */
-export function html2Text(val) {
-  const div = document.createElement('div')
-  div.innerHTML = val
-  return div.textContent || div.innerText
-}
-
-/**
- * Merges two objects, giving the last one precedence
- * @param {Object} target
- * @param {(Object|Array)} source
- * @returns {Object}
- */
-export function objectMerge(target, source) {
-  if (typeof target !== 'object') {
-    target = {}
-  }
-  if (Array.isArray(source)) {
-    return source.slice()
-  }
-  Object.keys(source).forEach(property => {
-    const sourceProperty = source[property]
-    if (typeof sourceProperty === 'object') {
-      target[property] = objectMerge(target[property], sourceProperty)
-    } else {
-      target[property] = sourceProperty
-    }
-  })
-  return target
-}
-
-/**
- * @param {HTMLElement} element
- * @param {string} className
- */
-export function toggleClass(element, className) {
-  if (!element || !className) {
-    return
-  }
-  let classString = element.className
-  const nameIndex = classString.indexOf(className)
-  if (nameIndex === -1) {
-    classString += '' + className
-  } else {
-    classString =
-      classString.substr(0, nameIndex) +
-      classString.substr(nameIndex + className.length)
-  }
-  element.className = classString
-}
-
-/**
- * @param {string} type
- * @returns {Date}
- */
-export function getTime(type) {
-  if (type === 'start') {
-    return new Date().getTime() - 3600 * 1000 * 24 * 90
-  } else {
-    return new Date(new Date().toDateString())
-  }
-}
-
-/**
- * @param {Function} func
- * @param {number} wait
- * @param {boolean} immediate
- * @return {*}
- */
-export function debounce(func, wait, immediate) {
-  let timeout, args, context, timestamp, result
-
-  const later = function() {
-    // 据上一次触发时间间隔
-    const last = +new Date() - timestamp
-
-    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
-    if (last < wait && last > 0) {
-      timeout = setTimeout(later, wait - last)
-    } else {
-      timeout = null
-      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
-      if (!immediate) {
-        result = func.apply(context, args)
-        if (!timeout) context = args = null
-      }
-    }
-  }
-
-  return function(...args) {
-    context = this
-    timestamp = +new Date()
-    const callNow = immediate && !timeout
-    // 如果延时不存在,重新设定延时
-    if (!timeout) timeout = setTimeout(later, wait)
-    if (callNow) {
-      result = func.apply(context, args)
-      context = args = null
-    }
-
-    return result
-  }
-}
-
-/**
- * This is just a simple version of deep copy
- * Has a lot of edge cases bug
- * If you want to use a perfect deep copy, use lodash's _.cloneDeep
- * @param {Object} source
- * @returns {Object}
- */
-export function deepClone(source) {
-  if (!source && typeof source !== 'object') {
-    throw new Error('error arguments', 'deepClone')
-  }
-  const targetObj = source.constructor === Array ? [] : {}
-  Object.keys(source).forEach(keys => {
-    if (source[keys] && typeof source[keys] === 'object') {
-      targetObj[keys] = deepClone(source[keys])
-    } else {
-      targetObj[keys] = source[keys]
-    }
-  })
-  return targetObj
-}
-
-/**
- * @param {Array} arr
- * @returns {Array}
- */
-export function uniqueArr(arr) {
-  return Array.from(new Set(arr))
-}
-
-/**
- * @returns {string}
- */
-export function createUniqueString() {
-  const timestamp = +new Date() + ''
-  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
-  return (+(randomNum + timestamp)).toString(32)
-}
-
-/**
- * Check if an element has a class
- * @param {HTMLElement} elm
- * @param {string} cls
- * @returns {boolean}
- */
-export function hasClass(ele, cls) {
-  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
-}
-
-/**
- * Add class to element
- * @param {HTMLElement} elm
- * @param {string} cls
- */
-export function addClass(ele, cls) {
-  if (!hasClass(ele, cls)) ele.className += ' ' + cls
-}
-
-/**
- * Remove class from element
- * @param {HTMLElement} elm
- * @param {string} cls
- */
-export function removeClass(ele, cls) {
-  if (hasClass(ele, cls)) {
-    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
-    ele.className = ele.className.replace(reg, ' ')
-  }
-}
-
-export function makeMap(str, expectsLowerCase) {
-  const map = Object.create(null)
-  const list = str.split(',')
-  for (let i = 0; i < list.length; i++) {
-    map[list[i]] = true
-  }
-  return expectsLowerCase
-    ? val => map[val.toLowerCase()]
-    : val => map[val]
-}
- 
-export const exportDefault = 'export default '
-
-export const beautifierConf = {
-  html: {
-    indent_size: '2',
-    indent_char: ' ',
-    max_preserve_newlines: '-1',
-    preserve_newlines: false,
-    keep_array_indentation: false,
-    break_chained_methods: false,
-    indent_scripts: 'separate',
-    brace_style: 'end-expand',
-    space_before_conditional: true,
-    unescape_strings: false,
-    jslint_happy: false,
-    end_with_newline: true,
-    wrap_line_length: '110',
-    indent_inner_html: true,
-    comma_first: false,
-    e4x: true,
-    indent_empty_lines: true
-  },
-  js: {
-    indent_size: '2',
-    indent_char: ' ',
-    max_preserve_newlines: '-1',
-    preserve_newlines: false,
-    keep_array_indentation: false,
-    break_chained_methods: false,
-    indent_scripts: 'normal',
-    brace_style: 'end-expand',
-    space_before_conditional: true,
-    unescape_strings: false,
-    jslint_happy: true,
-    end_with_newline: true,
-    wrap_line_length: '110',
-    indent_inner_html: true,
-    comma_first: false,
-    e4x: true,
-    indent_empty_lines: true
-  }
-}
-
-// 首字母大小
-export function titleCase(str) {
-  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
-}
-
-// 下划转驼峰
-export function camelCase(str) {
-  return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
-}
-
-export function isNumberStr(str) {
-  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
-}
- 
\ No newline at end of file
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+  if (('' + time).length === 10) {
+    time = parseInt(time) * 1000
+  } else {
+    time = +time
+  }
+  const d = new Date(time)
+  const now = Date.now()
+
+  const diff = (now - d) / 1000
+
+  if (diff < 30) {
+    return '刚刚'
+  } else if (diff < 3600) {
+    // less 1 hour
+    return Math.ceil(diff / 60) + '分钟前'
+  } else if (diff < 3600 * 24) {
+    return Math.ceil(diff / 3600) + '小时前'
+  } else if (diff < 3600 * 24 * 2) {
+    return '1天前'
+  }
+  if (option) {
+    return parseTime(time, option)
+  } else {
+    return (
+      d.getMonth() +
+      1 +
+      '月' +
+      d.getDate() +
+      '日' +
+      d.getHours() +
+      '时' +
+      d.getMinutes() +
+      '分'
+    )
+  }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function getQueryObject(url) {
+  url = url == null ? window.location.href : url
+  const search = url.substring(url.lastIndexOf('?') + 1)
+  const obj = {}
+  const reg = /([^?&=]+)=([^?&=]*)/g
+  search.replace(reg, (rs, $1, $2) => {
+    const name = decodeURIComponent($1)
+    let val = decodeURIComponent($2)
+    val = String(val)
+    obj[name] = val
+    return rs
+  })
+  return obj
+}
+
+/**
+ * @param {string} input value
+ * @returns {number} output value
+ */
+export function byteLength(str) {
+  // returns the byte length of an utf8 string
+  let s = str.length
+  for (var i = str.length - 1; i >= 0; i--) {
+    const code = str.charCodeAt(i)
+    if (code > 0x7f && code <= 0x7ff) s++
+    else if (code > 0x7ff && code <= 0xffff) s += 2
+    if (code >= 0xDC00 && code <= 0xDFFF) i--
+  }
+  return s
+}
+
+/**
+ * @param {Array} actual
+ * @returns {Array}
+ */
+export function cleanArray(actual) {
+  const newArray = []
+  for (let i = 0; i < actual.length; i++) {
+    if (actual[i]) {
+      newArray.push(actual[i])
+    }
+  }
+  return newArray
+}
+
+/**
+ * @param {Object} json
+ * @returns {Array}
+ */
+export function param(json) {
+  if (!json) return ''
+  return cleanArray(
+    Object.keys(json).map(key => {
+      if (json[key] === undefined) return ''
+      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
+    })
+  ).join('&')
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+  const search = url.split('?')[1]
+  if (!search) {
+    return {}
+  }
+  return JSON.parse(
+    '{"' +
+    decodeURIComponent(search)
+      .replace(/"/g, '\\"')
+      .replace(/&/g, '","')
+      .replace(/=/g, '":"')
+      .replace(/\+/g, ' ') +
+    '"}'
+  )
+}
+
+/**
+ * @param {string} val
+ * @returns {string}
+ */
+export function html2Text(val) {
+  const div = document.createElement('div')
+  div.innerHTML = val
+  return div.textContent || div.innerText
+}
+
+/**
+ * Merges two objects, giving the last one precedence
+ * @param {Object} target
+ * @param {(Object|Array)} source
+ * @returns {Object}
+ */
+export function objectMerge(target, source) {
+  if (typeof target !== 'object') {
+    target = {}
+  }
+  if (Array.isArray(source)) {
+    return source.slice()
+  }
+  Object.keys(source).forEach(property => {
+    const sourceProperty = source[property]
+    if (typeof sourceProperty === 'object') {
+      target[property] = objectMerge(target[property], sourceProperty)
+    } else {
+      target[property] = sourceProperty
+    }
+  })
+  return target
+}
+
+/**
+ * @param {HTMLElement} element
+ * @param {string} className
+ */
+export function toggleClass(element, className) {
+  if (!element || !className) {
+    return
+  }
+  let classString = element.className
+  const nameIndex = classString.indexOf(className)
+  if (nameIndex === -1) {
+    classString += '' + className
+  } else {
+    classString =
+      classString.substr(0, nameIndex) +
+      classString.substr(nameIndex + className.length)
+  }
+  element.className = classString
+}
+
+/**
+ * @param {string} type
+ * @returns {Date}
+ */
+export function getTime(type) {
+  if (type === 'start') {
+    return new Date().getTime() - 3600 * 1000 * 24 * 90
+  } else {
+    return new Date(new Date().toDateString())
+  }
+}
+
+/**
+ * @param {Function} func
+ * @param {number} wait
+ * @param {boolean} immediate
+ * @return {*}
+ */
+export function debounce(func, wait, immediate) {
+  let timeout, args, context, timestamp, result
+
+  const later = function () {
+    // 据上一次触发时间间隔
+    const last = +new Date() - timestamp
+
+    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
+    if (last < wait && last > 0) {
+      timeout = setTimeout(later, wait - last)
+    } else {
+      timeout = null
+      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+      if (!immediate) {
+        result = func.apply(context, args)
+        if (!timeout) context = args = null
+      }
+    }
+  }
+
+  return function (...args) {
+    context = this
+    timestamp = +new Date()
+    const callNow = immediate && !timeout
+    // 如果延时不存在,重新设定延时
+    if (!timeout) timeout = setTimeout(later, wait)
+    if (callNow) {
+      result = func.apply(context, args)
+      context = args = null
+    }
+
+    return result
+  }
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+export function deepClone(source) {
+  if (!source && typeof source !== 'object') {
+    throw new Error('error arguments', 'deepClone')
+  }
+  const targetObj = source.constructor === Array ? [] : {}
+  Object.keys(source).forEach(keys => {
+    if (source[keys] && typeof source[keys] === 'object') {
+      targetObj[keys] = deepClone(source[keys])
+    } else {
+      targetObj[keys] = source[keys]
+    }
+  })
+  return targetObj
+}
+
+/**
+ * @param {Array} arr
+ * @returns {Array}
+ */
+export function uniqueArr(arr) {
+  return Array.from(new Set(arr))
+}
+
+/**
+ * @returns {string}
+ */
+export function createUniqueString() {
+  const timestamp = +new Date() + ''
+  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
+  return (+(randomNum + timestamp)).toString(32)
+}
+
+/**
+ * Check if an element has a class
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ * @returns {boolean}
+ */
+export function hasClass(ele, cls) {
+  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
+}
+
+/**
+ * Add class to element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function addClass(ele, cls) {
+  if (!hasClass(ele, cls)) ele.className += ' ' + cls
+}
+
+/**
+ * Remove class from element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function removeClass(ele, cls) {
+  if (hasClass(ele, cls)) {
+    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
+    ele.className = ele.className.replace(reg, ' ')
+  }
+}
+
+export function makeMap(str, expectsLowerCase) {
+  const map = Object.create(null)
+  const list = str.split(',')
+  for (let i = 0; i < list.length; i++) {
+    map[list[i]] = true
+  }
+  return expectsLowerCase
+    ? val => map[val.toLowerCase()]
+    : val => map[val]
+}
+
+export const exportDefault = 'export default '
+
+export const beautifierConf = {
+  html: {
+    indent_size: '2',
+    indent_char: ' ',
+    max_preserve_newlines: '-1',
+    preserve_newlines: false,
+    keep_array_indentation: false,
+    break_chained_methods: false,
+    indent_scripts: 'separate',
+    brace_style: 'end-expand',
+    space_before_conditional: true,
+    unescape_strings: false,
+    jslint_happy: false,
+    end_with_newline: true,
+    wrap_line_length: '110',
+    indent_inner_html: true,
+    comma_first: false,
+    e4x: true,
+    indent_empty_lines: true
+  },
+  js: {
+    indent_size: '2',
+    indent_char: ' ',
+    max_preserve_newlines: '-1',
+    preserve_newlines: false,
+    keep_array_indentation: false,
+    break_chained_methods: false,
+    indent_scripts: 'normal',
+    brace_style: 'end-expand',
+    space_before_conditional: true,
+    unescape_strings: false,
+    jslint_happy: true,
+    end_with_newline: true,
+    wrap_line_length: '110',
+    indent_inner_html: true,
+    comma_first: false,
+    e4x: true,
+    indent_empty_lines: true
+  }
+}
+
+// 首字母大小
+export function titleCase(str) {
+  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
+}
+
+// 下划转驼峰
+export function camelCase(str) {
+  return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
+}
+
+export function isNumberStr(str) {
+  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
+}
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
index dc18b9122..6fc4e5167 100644
--- a/ruoyi-ui/src/utils/ruoyi.js
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -1,134 +1,155 @@
-/**
- * 通用js方法封装处理
- * Copyright (c) 2019 ruoyi
- */
-
-const baseURL = process.env.VUE_APP_BASE_API
-
-// 日期格式化
-export function parseTime(time, pattern) {
-	if (arguments.length === 0 || !time) {
-		return null
-	}
-	const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
-	let date
-	if (typeof time === 'object') {
-		date = time
-	} else {
-		if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
-			time = parseInt(time)
-		} else if (typeof time === 'string') {
-			time = time.replace(new RegExp(/-/gm), '/');
-		}
-		if ((typeof time === 'number') && (time.toString().length === 10)) {
-			time = time * 1000
-		}
-		date = new Date(time)
-	}
-	const formatObj = {
-		y: date.getFullYear(),
-		m: date.getMonth() + 1,
-		d: date.getDate(),
-		h: date.getHours(),
-		i: date.getMinutes(),
-		s: date.getSeconds(),
-		a: date.getDay()
-	}
-	const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
-		let value = formatObj[key]
-		// Note: getDay() returns 0 on Sunday
-		if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
-		if (result.length > 0 && value < 10) {
-			value = '0' + value
-		}
-		return value || 0
-	})
-	return time_str
-}
-
-// 表单重置
-export function resetForm(refName) {
-	if (this.$refs[refName]) {
-		this.$refs[refName].resetFields();
-	}
-}
-
-// 添加日期范围
-export function addDateRange(params, dateRange) {
-	var search = params;
-	search.beginTime = "";
-	search.endTime = "";
-	if (null != dateRange && '' != dateRange) {
-		search.beginTime = this.dateRange[0];
-		search.endTime = this.dateRange[1];
-	}
-	return search;
-}
-
-// 回显数据字典
-export function selectDictLabel(datas, value) {
-	var actions = [];
-	Object.keys(datas).map((key) => {
-		if (datas[key].dictValue == ('' + value)) {
-			actions.push(datas[key].dictLabel);
-			return false;
-		}
-	})
-	return actions.join('');
-}
-
-// 通用下载方法
-export function download(fileName) {
-	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
-}
-
-// 字符串格式化(%s )
-export function sprintf(str) {
-	var args = arguments, flag = true, i = 1;
-	str = str.replace(/%s/g, function () {
-		var arg = args[i++];
-		if (typeof arg === 'undefined') {
-			flag = false;
-			return '';
-		}
-		return arg;
-	});
-	return flag ? str : '';
-}
-
-// 转换字符串,undefined,null等转化为""
-export function praseStrEmpty(str) {
-    if (!str || str == "undefined" || str == "null") {
-        return "";
-    }
-    return str;
-}
-
-/**
- * 构造树型结构数据
- * @param {*} data 数据源
- * @param {*} id id字段 默认 'id'
- * @param {*} parentId 父节点字段 默认 'parentId'
- * @param {*} children 孩子节点字段 默认 'children'
- * @param {*} rootId 根Id 默认 0
- */
-export function handleTree(data, id, parentId, children, rootId) {
-	id = id || 'id'
-	parentId = parentId || 'parentId'
-	children = children || 'children'
-	rootId = rootId || 0
-	//对源数据深度克隆
-	const cloneData = JSON.parse(JSON.stringify(data))
-	//循环所有项
-	const treeData =  cloneData.filter(father => {
-	  let branchArr = cloneData.filter(child => {
-		//返回每一项的子级数组
-		return father[id] === child[parentId]
-	  });
-	  branchArr.length > 0 ? father.children = branchArr : '';
-	  //返回第一层
-	  return father[parentId] === rootId;
-	});
-	return treeData != '' ? treeData : data;
-  }
-  
\ No newline at end of file
+/**
+ * 通用js方法封装处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+const baseURL = process.env.VUE_APP_BASE_API
+
+/**
+ * 表格时间格式化
+ */
+export function formatDate(cellValue) {
+  if (cellValue == null || cellValue == "") return "";
+  if (typeof cellValue === 'string') {
+    if (cellValue) {
+      return cellValue.substring(0, 10);
+    }
+    return;
+  }
+  var date = new Date(cellValue)
+  var year = date.getFullYear()
+  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
+  var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
+  return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
+}
+
+
+// 日期格式化
+export function parseTime(time, pattern) {
+	if (arguments.length === 0 || !time) {
+		return null
+	}
+	const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+	let date
+	if (typeof time === 'object') {
+		date = time
+	} else {
+		if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+			time = parseInt(time)
+		} else if (typeof time === 'string') {
+			time = time.replace(new RegExp(/-/gm), '/');
+		}
+		if ((typeof time === 'number') && (time.toString().length === 10)) {
+			time = time * 1000
+		}
+		date = new Date(time)
+	}
+	const formatObj = {
+		y: date.getFullYear(),
+		m: date.getMonth() + 1,
+		d: date.getDate(),
+		h: date.getHours(),
+		i: date.getMinutes(),
+		s: date.getSeconds(),
+		a: date.getDay()
+	}
+	const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+		let value = formatObj[key]
+		// Note: getDay() returns 0 on Sunday
+		if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+		if (result.length > 0 && value < 10) {
+			value = '0' + value
+		}
+		return value || 0
+	})
+	return time_str
+}
+
+// 表单重置
+export function resetForm(refName) {
+	if (this.$refs[refName]) {
+		this.$refs[refName].resetFields();
+	}
+}
+
+// 添加日期范围
+export function addDateRange(params, dateRange) {
+	var search = params;
+	search.beginTime = "";
+	search.endTime = "";
+	if (null != dateRange && '' != dateRange) {
+		search.beginTime = this.dateRange[0];
+		search.endTime = this.dateRange[1];
+	}
+	return search;
+}
+
+// 回显数据字典
+export function selectDictLabel(datas, value) {
+	var actions = [];
+	Object.keys(datas).map((key) => {
+		if (datas[key].dictValue == ('' + value)) {
+			actions.push(datas[key].dictLabel);
+			return false;
+		}
+	})
+	return actions.join('');
+}
+
+// 通用下载方法
+export function download(fileName) {
+	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
+}
+
+// 字符串格式化(%s )
+export function sprintf(str) {
+	var args = arguments, flag = true, i = 1;
+	str = str.replace(/%s/g, function () {
+		var arg = args[i++];
+		if (typeof arg === 'undefined') {
+			flag = false;
+			return '';
+		}
+		return arg;
+	});
+	return flag ? str : '';
+}
+
+// 转换字符串,undefined,null等转化为""
+export function praseStrEmpty(str) {
+    if (!str || str == "undefined" || str == "null") {
+        return "";
+    }
+    return str;
+}
+
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ * @param {*} rootId 根Id 默认 0
+ */
+export function handleTree(data, id, parentId, children, rootId) {
+	id = id || 'id'
+	parentId = parentId || 'parentId'
+	children = children || 'children'
+	rootId = rootId || 0
+	//对源数据深度克隆
+	const cloneData = JSON.parse(JSON.stringify(data))
+	//循环所有项
+	const treeData =  cloneData.filter(father => {
+	  let branchArr = cloneData.filter(child => {
+		//返回每一项的子级数组
+		return father[id] === child[parentId]
+	  });
+	  branchArr.length > 0 ? father.children = branchArr : '';
+	  //返回第一层
+	  return father[parentId] === rootId;
+	});
+	return treeData != '' ? treeData : data;
+  }
diff --git a/ruoyi-ui/src/views/data/cases/AggregateResidenceRentCase.vue b/ruoyi-ui/src/views/data/cases/AggregateResidenceRentCase.vue
new file mode 100644
index 000000000..0b96db51e
--- /dev/null
+++ b/ruoyi-ui/src/views/data/cases/AggregateResidenceRentCase.vue
@@ -0,0 +1,298 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" :rules="rules" ref="queryForm" :inline="true" label-width="100px">
+      <el-form-item label="年月" prop="yearMonth">
+        <el-select v-model="queryParams.yearMonth" placeholder="请选择年月">
+          <el-option
+            v-for="item in yearMonthList"
+            :value="item.value"
+            :label="item.label"
+            :key="item.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="案例名称" prop="caseName" clearable>
+        <el-input
+          v-model="queryParams.caseName"
+          placeholder="请输入案例名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </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-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:user:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="dataList">
+      <!-- <el-table-column label="年月" align="center" prop="yearMonth" /> -->
+      <el-table-column label="案例URL" align="center" prop="urlHouseholds" width="300">
+        <template slot-scope="scope">
+          <a
+            :href="scope.row.urlHouseholds"
+            target="_blank"
+            v-bind:style="'color: blue;'"
+          >{{scope.row.urlHouseholds}}</a>
+        </template>
+      </el-table-column>
+      <el-table-column label="案例名称" align="center" prop="caseName" width="240" />
+      <el-table-column label="案例来源" align="center" prop="origin" />
+      <el-table-column label="挂牌/成交" align="center" prop="caseType" :formatter="caseTypeFormatter" />
+      <el-table-column label="案例单套ID" align="center" prop="householdsIdSRC" width="120" />
+      <el-table-column label="案例小区ID" align="center" prop="projectIdSRC" />
+      <el-table-column label="小区ID" align="center" prop="communityId" />
+      <el-table-column label="楼栋ID" align="center" prop="buildingId" />
+      <el-table-column label="租赁类型" align="center" :formatter="rentTypeFormatter" />
+      <el-table-column label="室-厅-卫">
+        <template slot-scope="scope">
+          <span>{{ scope.row.roomNum+'-'+scope.row.hallNum+'-'+(scope.row.bashRoomNum?scope.row.bashRoomNum:0) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="面积" align="center" prop="area" />
+      <el-table-column label="朝向" align="center" prop="toward" />
+      <el-table-column label="所在层/总楼层" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.currentFloor+'/'+scope.row.totalFloor }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="有无电梯" align="center" prop="elevator" :formatter="youOrWuFormatter" />
+      <el-table-column label="装修类型" align="center" prop="decoration" />
+      <el-table-column label="建成年代" align="center" prop="year" />
+      <el-table-column label="房屋面积系数" align="center" prop="areaCoefficient" />
+      <el-table-column label="朝向系数" align="center" prop="towardCoefficient" />
+      <el-table-column label="楼层系数" align="center" prop="floorCoefficient" />
+      <el-table-column label="装修系数" align="center" prop="decorationCoefficient" />
+      <el-table-column label="建成年代系数" align="center" prop="yearCoefficient" />
+      <el-table-column label="楼栋系数" align="center" prop="buildingCoefficient" />
+      <el-table-column label="室厅修正系数" align="center" prop="roomTypeCoefficient" />
+      <el-table-column label="总价(元)" align="center" prop="totalPrice" />
+      <el-table-column label="单价" align="center" prop="unitPrice" />
+      <el-table-column label="散租单价" align="center" prop="priceScatterRent" />
+      <el-table-column label="整租单价" align="center" prop="priceEntireRent" />
+      <el-table-column label="合租折算价" align="center" prop="priceShareRent" />
+      <el-table-column label="带看总次数" align="center" prop="visitedNum" />
+      <el-table-column label="首次带看时间" align="center" prop="firstVisitedDate" />
+      <el-table-column label="15天内带看总次数" align="center" prop="visitedNum15" />
+      <el-table-column label="30天内带看总次数" align="center" prop="visitedNum30" />
+      <el-table-column label="案例状态" align="center" prop="status" :formatter="statusFormatter" />
+      <el-table-column label="最近一次挂牌总价调整幅度" align="center" prop="adjustedValue" />
+      <el-table-column label="最近一次挂牌总价调整比例" align="center" prop="adjustedPst" />
+      <el-table-column label="累计挂牌总价调整幅度" align="center" prop="adjustedCumValue" />
+      <el-table-column label="累计挂牌总价调整比例" align="center" prop="adjustedCumPst" />
+      <el-table-column label="累计挂牌总价绝对调整幅度" align="center" prop="adjustedCumValueAbs" />
+      <el-table-column label="累计挂牌总价绝对调整比例" align="center" prop="adjustedCumPstAbs" />
+      <el-table-column label="累计挂牌总价调价次数" align="center" prop="adjustedCumNum" />
+      <el-table-column label="首次挂牌总价" align="center" prop="priceTotalIn" />
+      <el-table-column label="下架时挂牌总价" align="center" prop="priceTotalOut" />
+      <el-table-column label="首次挂牌日期" align="center" width="120">
+        <template slot-scope="scope">
+          <span>{{ formatDate(scope.row.priceDateIn) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="下架日期" align="center" width="120">
+        <template slot-scope="scope">
+          <span>{{ formatDate(scope.row.priceDateOut) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="案例小区URL" align="center" width="400">
+        <template slot-scope="scope">
+          <a :href="scope.row.urlProjects" target="_blank">{{scope.row.urlProjects}}</a>
+        </template>
+      </el-table-column>
+      <el-table-column label="平均租金(上周期)" align="center" prop="rentPrice_1" />
+      <el-table-column label="案例涨跌幅" align="center" prop="range" />
+      <el-table-column label="涨跌类型" align="center" prop="rangeFlag" />
+      <el-table-column label="平均租金" align="center" prop="rentPrice" />
+      <el-table-column label="整租比" align="center" prop="entireRentRatio" />
+      <el-table-column label="分租比" align="center" prop="shareRentRatio" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageIndex"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import {
+  list,
+  export2File,
+  getYearMonthList
+} from "@/api/data/aggregateResidenceRentCase";
+
+export default {
+  name: "aggregateResidenceRentCase",
+  data() {
+    // 年月
+    var checkYearMonth = (rule, value, callback) => {
+      if (!value) {
+        callback(new Error("请输入年月"));
+      } else if (value === "" || isNaN(parseInt(value))) {
+        callback(new Error("请输入年月"));
+      } else {
+        callback();
+      }
+    };
+
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 总条数
+      total: 0,
+      // 办公基价表格数据
+      dataList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        yearMonth: undefined,
+        caseName: undefined,
+        pageIndex: 1,
+        pageSize: 10
+      },
+      yearMonthList: [],
+      statusOptions: [
+        { value: 1, text: "正常" },
+        { value: 1, text: "失效" }
+      ],
+      upload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url:
+          process.env.VUE_APP_BASE_API +
+          "/data/compute/rentprice/residence/importData"
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        yearMonth: [
+          { validator: checkYearMonth, trigger: "blur" },
+          { validator: checkYearMonth, trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.loading = false;
+    getYearMonthList().then(response => {
+      this.yearMonthList = response.data;
+    });
+  },
+  methods: {
+    rentTypeFormatter: function(row, column, cellValue, index) {
+      if (cellValue === 1) return "整租";
+      if (cellValue === 2) return "散租";
+      if (cellValue === 3) return "分租";
+      return "无";
+    },
+    caseTypeFormatter: function(row, column, cellValue, index) {
+      if (cellValue == "0") return "成交案例";
+      return "挂牌案例";
+    },
+    youOrWuFormatter: function(row, column, cellValue, index) {
+      if (cellValue) return "有";
+      return "无";
+    },
+    yesOrNotFormatter: function(row, column, cellValue, index) {
+      if (cellValue) return "是";
+      return "否";
+    },
+    statusFormatter: function(row, column, cellValue, index) {
+      if (cellValue === 3) return "当期活跃";
+      if (cellValue === 4) return "当期下架";
+      if (cellValue === 5) return "历史下架";
+      return "否";
+    },
+    /** 查询办公基价列表 */
+    getList() {
+      this.$refs["queryForm"].validate(valid => {
+        if (valid) {
+          this.loading = true;
+          list(this.queryParams).then(response => {
+            this.dataList = response.rows;
+            this.total = response.total;
+            this.loading = false;
+          });
+        }
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageIndex = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$refs["queryForm"].validate(valid => {
+        if (valid) {
+          this.$confirm("是否确认导出所有住宅租赁基价数据项?", "警告", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          })
+            .then(function() {
+              return export2File(queryParams);
+            })
+            .then(response => {
+              this.download(response.msg);
+            })
+            .catch(function() {});
+        }
+      });
+    }
+  }
+};
+</script>