Browse Source

fix: sass依赖安装及eslint效验

mzr 2 weeks ago
parent
commit
84d2222542

+ 1 - 2
.npmrc

@@ -1,2 +1 @@
-# registry = http://nexus.wisdomcity.com.cn/repository/wisdomcity-npm-group/
-# _auth = YWRtaW46V2lzZG9tY2l0eUBAMjAyMg==
+registry = "https://registry.npmmirror.com"

+ 3 - 2
package.json

@@ -15,7 +15,7 @@
     "babel-polyfill": "^6.26.0",
     "core-js": "^2.6.5",
     "dayjs": "^1.11.11",
-    "echarts": "^4.3.0",
+    "echarts": "^6.0.0",
     "element-ui": "^2.12.0",
     "reset.css": "^2.0.2",
     "vue": "^2.6.10",
@@ -32,10 +32,11 @@
     "@vue/test-utils": "^1.0.0-beta.20",
     "babel-eslint": "^10.0.1",
     "eslint": "^5.16.0",
+    "eslint-loader": "^4.0.2",
     "eslint-plugin-cypress": "^2.6.1",
     "eslint-plugin-html": "^6.0.0",
     "eslint-plugin-vue": "^5.2.3",
-    "node-sass": "^4.13.1",
+    "sass": "^1.94.0",
     "sass-loader": "^7.1.0",
     "vue-template-compiler": "^2.6.10"
   }

+ 4 - 3
src/App.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: WangQiBiao
  * @Date: 2019-09-24 17:50:53
- * @LastEditors: MoZhuangRu
- * @LastEditTime: 2019-12-31 11:26:49
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-17 16:41:21
  * @Description:
  -->
 <template>
@@ -10,7 +10,8 @@
     <router-view/>
   </div>
 </template>
-<style lang="scss" scoped>
+<style lang="scss">
+@import '../src/assets/css/theme.scss';
 #app{
   width: 100vw;
   height: 100vh;

+ 13 - 0
src/assets/css/theme.scss

@@ -12,3 +12,16 @@ $bg-color: #f8f8f8;
 $divider-color: #f1f1f1;
 // 菜单宽度
 $left-width: 220px;
+
+:root {
+  --title-bg: #111c31;
+  --title-primary: #b9e3f4;
+  --title-secondary: #a1a1a1;
+  --content-bg: #0C1425;
+  --primary: #007bd3;
+}
+.title-icon {
+  width: 28px;
+  height: 28px;
+  margin-right: 8px;
+}

BIN
src/assets/images/fwzj.png


BIN
src/assets/images/nz.png


BIN
src/assets/images/qfefb.png


BIN
src/assets/images/rhys.png


BIN
src/assets/images/shb.png


BIN
src/assets/images/sswz.png


BIN
src/assets/images/tj.png


BIN
src/assets/images/xlzb.png


+ 11 - 2
src/route/white-list.js

@@ -1,8 +1,8 @@
 /*
  * @Author: WangQiBiao
  * @Date: 2019-09-18 09:40:26
- * @LastEditors: wangjiacheng
- * @LastEditTime: 2021-10-14 12:00:08
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 17:37:59
  * @Description: 白名单菜单
  */
 import _import from './_import'
@@ -39,6 +39,15 @@ export default [
       icon: ''
     }
   },
+  {
+    path: '/hui-jia',
+    component: () => import('@/views/hui-jia/b1-screen/index.vue'),
+    meta: {
+      title: '绘家科技',
+      hideInMenu: false,
+      icon: ''
+    }
+  },
   {
     path: '/login',
     component: _import('login'),

+ 1 - 1
src/views/components/community-type/components/three-pie.vue

@@ -10,7 +10,7 @@
 </template>
 
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 // import tdTheme from '_c/charts/theme.json'
 // import mixin from '_c/charts/mixin.js'
 // echarts.registerTheme('tdTheme', tdTheme)

+ 1 - 1
src/views/components/online-pay-day/index.vue

@@ -25,7 +25,7 @@
     </Card>
   </template>
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 // import { getBigNumberWithUint } from '@/libs/tools.js'
 import Card from '@/views/components/card'
 import icon from './images/icon-title.png'

+ 1 - 1
src/views/components/online-pay-week/index.vue

@@ -25,7 +25,7 @@
     </Card>
   </template>
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 // import { getBigNumberWithUint } from '@/libs/tools.js'
 import Card from '@/views/components/card'
 import icon from './images/icon-title.png'

+ 1 - 1
src/views/components/online-pay/index.vue

@@ -12,7 +12,7 @@
     </Card>
   </template>
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 // import { getBigNumberWithUint } from '@/libs/tools.js'
 import Card from '@/views/components/card'
 import icon from './images/icon-title.png'

+ 1 - 1
src/views/components/resident/index.vue

@@ -27,7 +27,7 @@
     </Card>
   </template>
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import Card from '@/views/components/card'
 import icon from './images/icon-title.png'
 import iconReport from './images/icon-report.png'

+ 42 - 0
src/views/hui-jia/b1-screen/index.vue

@@ -0,0 +1,42 @@
+<template>
+  <div class="b1-screen">
+    <div>1</div>
+    <div>2</div>
+    <implementationTotal />
+    <Market />
+    <implementationIng />
+    <implementationNowYear />
+  </div>
+</template>
+
+<script>
+import implementationTotal from '../components/implementary/total.vue'
+import implementationIng from '../components/implementary/ing.vue'
+import implementationNowYear from '../components/implementary/now-year.vue'
+import Market from '../components/market.vue'
+
+export default {
+  name: 'B1Screen',
+  components: {
+    implementationTotal,
+    implementationIng,
+    implementationNowYear,
+    Market
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .b1-screen {
+    height: 100vh;
+    width: 100vw;
+    display: grid;
+    grid-template-columns: repeat(4, 1fr);
+    grid-template-rows: repeat(3, 1fr);
+    gap: 20px;
+    .now-year-container {
+      grid-column: 1 / span 2;
+      grid-row: 1 / span 2;
+    }
+  }
+</style>

+ 504 - 0
src/views/hui-jia/components/hardware.vue

@@ -0,0 +1,504 @@
+<template>
+  <div class="hardware-data">
+    <!-- 标题 -->
+    <div class="module-title">硬件数据</div>
+
+    <!-- 智能电表部分 -->
+    <div class="data-section">
+      <div class="device-info">
+        <div class="device-icon electric"></div>
+        <div>
+          <div class="device-count">8921</div>
+          <div class="device-name">智能电表</div>
+        </div>
+      </div>
+      <div class="data-cards">
+        <div class="data-card">
+          <div class="data-label">年度用电</div>
+          <div>
+            <div class="data-value">428921</div>
+            <div class="data-unit">kW·h</div>
+          </div>
+        </div>
+        <div class="data-card">
+          <div class="data-label">月均用电</div>
+          <div>
+            <div class="data-value">18921</div>
+            <div class="data-unit">kW·h</div>
+          </div>
+        </div>
+        <div class="data-card">
+          <div class="data-label">日均用电</div>
+          <div>
+            <div class="data-value">8921</div>
+            <div class="data-unit">kW·h</div>
+          </div>
+        </div>
+        <div class="data-card">
+          <div class="data-label">开关次数</div>
+          <div>
+            <div class="data-value">887</div>
+            <div class="data-unit">近12个月</div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="charts-container">
+      <div ref="powerChart" class="chart-item"></div>
+      <div ref="waterChart" class="chart-item"></div>
+    </div>
+
+    <!-- 智能水表部分 -->
+    <div class="data-section">
+      <div class="device-info">
+        <div class="device-icon water"></div>
+        <div class="device-name">智能水表</div>
+        <div class="device-count">8921</div>
+      </div>
+      <div class="data-cards">
+        <div class="data-card">
+          <div class="data-label">年度用水</div>
+          <div>
+            <div class="data-value">89321</div>
+            <div class="data-unit">m³</div>
+          </div>
+        </div>
+        <div class="data-card">
+          <div class="data-label">月均用水</div>
+          <div>
+            <div class="data-value">9212</div>
+            <div class="data-unit">m³</div>
+          </div>
+        </div>
+        <div class="data-card">
+          <div class="data-label">日均用水</div>
+          <div>
+            <div class="data-value">921</div>
+            <div class="data-unit">m³</div>
+          </div>
+        </div>
+        <div class="data-card">
+          <div class="data-label">开关次数</div>
+          <div>
+            <div class="data-value">887</div>
+            <div class="data-unit">近12个月</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+export default {
+  name: 'HardwareData',
+  data () {
+    return {
+      powerChartInstance: null,
+      waterChartInstance: null,
+      // 模拟月度数据
+      monthlyData: [
+        { month: '十二月', power: 220000, water: 180000 },
+        { month: '一月', power: 210000, water: 170000 },
+        { month: '二月', power: 230000, water: 190000 },
+        { month: '三月', power: 225000, water: 185000 },
+        { month: '四月', power: 215000, water: 175000 },
+        { month: '五月', power: 200000, water: 160000 },
+        { month: '六月', power: 205000, water: 165000 },
+        { month: '七月', power: 210000, water: 170000 },
+        { month: '八月', power: 215000, water: 175000 },
+        { month: '九月', power: 220000, water: 180000 },
+        { month: '十月', power: 225000, water: 185000 },
+        { month: '十一月', power: 230000, water: 190000 }
+      ]
+    }
+  },
+  mounted () {
+    this.initPowerChart()
+    this.initWaterChart()
+    window.addEventListener('resize', this.handleResize)
+  },
+  beforeDestroy () {
+    window.removeEventListener('resize', this.handleResize)
+    if (this.powerChartInstance) {
+      this.powerChartInstance.dispose()
+    }
+    if (this.waterChartInstance) {
+      this.waterChartInstance.dispose()
+    }
+  },
+  methods: {
+    // 初始化用电量柱状图
+    initPowerChart () {
+      this.powerChartInstance = echarts.init(this.$refs.powerChart)
+
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          backgroundColor: 'rgba(0, 0, 0, 0.8)',
+          borderColor: 'rgba(64, 158, 255, 0.3)',
+          textStyle: {
+            color: '#fff'
+          },
+          formatter: (params) => {
+            let result = ``
+            params.forEach((param) => {
+              result += `${param.name}<br/>${
+                param.seriesName
+              }: ${param.value.toLocaleString()}<br/>`
+            })
+            return result
+          }
+        },
+        grid: {
+          left: '1%',
+          right: '1%',
+          top: '5%',
+          bottom: '2%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: this.monthlyData.map((item) => item.month),
+          axisLine: {
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.3)',
+              type: 'dashed'
+            }
+          },
+          axisLabel: {
+            color: 'rgba(160, 179, 214, 0.7)',
+            fontSize: 11,
+            interval: 0
+          },
+          axisTick: {
+            show: false
+          },
+          splitLine: {
+            show: true,
+            // 将坐标轴内的线设置为虚线
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.3)',
+              type: 'dashed'
+            }
+          }
+        },
+        yAxis: {
+          type: 'value',
+          axisLine: {
+            show: false
+          },
+          axisLabel: {
+            color: 'rgba(160, 179, 214, 0.7)',
+            fontSize: 11
+          },
+          axisTick: {
+            show: false
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.1)',
+              type: 'dashed',
+              width: 1
+            }
+          }
+        },
+        series: [
+          {
+            name: '用电量',
+            type: 'bar',
+            data: this.monthlyData.map((item) => item.power),
+            barWidth: '30%',
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
+                { offset: 0, color: '#FCE2B4' },
+                { offset: 1, color: '#F66757' }
+              ]),
+              borderRadius: [20, 20, 0, 0]
+            },
+            label: {
+              show: true,
+              position: 'top',
+              color: '#fff',
+              fontSize: 10,
+              formatter: (params) =>
+                params.value >= 10000
+                  ? (params.value / 10000).toFixed(1) + '万'
+                  : params.value
+            }
+          }
+        ]
+      }
+
+      this.powerChartInstance.setOption(option)
+    },
+
+    // 初始化用水量柱状图
+    initWaterChart () {
+      this.waterChartInstance = echarts.init(this.$refs.waterChart)
+
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          backgroundColor: 'rgba(0, 0, 0, 0.8)',
+          borderColor: 'rgba(64, 158, 255, 0.3)',
+          textStyle: {
+            color: '#fff'
+          },
+          formatter: (params) => {
+            let result = ``
+            params.forEach((param) => {
+              result += `${param.name}<br/>${
+                param.seriesName
+              }: ${param.value.toLocaleString()}<br/>`
+            })
+            return result
+          }
+        },
+        grid: {
+          left: '1%',
+          right: '1%',
+          top: '2%',
+          bottom: '5%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: this.monthlyData.map((item) => item.month),
+          axisLine: {
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.3)',
+              type: 'dashed'
+            }
+          },
+          axisLabel: {
+            color: 'rgba(160, 179, 214, 0.7)',
+            fontSize: 11,
+            interval: 0,
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          splitLine: {
+            show: true,
+            // 将坐标轴内的线设置为虚线
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.3)',
+              type: 'dashed'
+            }
+          }
+        },
+        yAxis: {
+          type: 'value',
+          // 反转 y 轴的 min 和 max,实现“倒立”
+          min: 400000,
+          max: 0,
+          axisLine: {
+            show: false
+          },
+          axisLabel: {
+            color: 'rgba(160, 179, 214, 0.7)',
+            fontSize: 11
+          },
+          axisTick: {
+            show: false
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.1)',
+              type: 'dashed',
+              width: 1
+            }
+          }
+        },
+        series: [
+          {
+            name: '用水量',
+            type: 'bar',
+            data: this.monthlyData.map((item) => item.water),
+            barWidth: '30%',
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#3AB3E3' },
+                { offset: 1, color: '#1620D4' }
+              ]),
+              borderRadius: [0, 0, 20, 20]
+            },
+            label: {
+              show: true,
+              position: 'bottom',
+              color: '#fff',
+              fontSize: 10,
+              formatter: (params) =>
+                params.value >= 10000
+                  ? (params.value / 10000).toFixed(1) + '万'
+                  : params.value
+            }
+          }
+        ]
+      }
+
+      this.waterChartInstance.setOption(option)
+    },
+
+    handleResize () {
+      if (this.powerChartInstance) {
+        this.powerChartInstance.resize()
+      }
+      if (this.waterChartInstance) {
+        this.waterChartInstance.resize()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .hardware-data {
+    background: var(--content-bg);
+    border-radius: 4px;
+    padding: 20px;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+  }
+
+  .module-title {
+    color: var(--title-primary);
+    font-size: 18px;
+    font-weight: 500;
+    margin-bottom: 10px;
+  }
+
+  .data-section {
+    display: flex;
+    justify-content: space-between;
+    gap: 20px;
+  }
+
+  .device-info {
+    text-align: right;
+    background: var(--title-bg);
+    display: flex;
+    align-items: center;
+    gap: 20px;
+    justify-content: space-between;
+    border: 1px solid rgba(64, 158, 255, 0.1);
+    border-radius: 6px;
+    padding: 16px;
+  }
+
+  .device-icon {
+    width: 48px;
+    height: 48px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: relative;
+  }
+
+  .device-icon.electric {
+    background: linear-gradient(135deg, #ff8c00 0%, #ffd700 100%);
+  }
+
+  .device-icon.water {
+    background: linear-gradient(135deg, #00bfff 0%, #87ceeb 100%);
+  }
+
+  .device-icon::after {
+    content: "";
+    position: absolute;
+    width: 24px;
+    height: 24px;
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center;
+  }
+
+  .device-icon.electric::after {
+    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M12 2C13.1 2 14 .9 14 0H10C10 .9 10.9 2 12 2M15.78 9H14.22L14 12H10L9.78 9H8.22L7.79 14H9.2L9.5 17H14.5L14.8 14H16.21L15.78 9M12 4C10.9 4 10 4.9 10 6S10.9 8 12 8 14 7.1 14 6 13.1 4 12 4Z"/></svg>');
+  }
+
+  .device-icon.water::after {
+    background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M12 2C13.1 2 14 .9 14 0H10C10 .9 10.9 2 12 2M12 18.5C11.45 18.5 11 18.05 11 17.5C11 16.95 11.45 16.5 12 16.5C12.55 16.5 13 16.95 13 17.5C13 18.05 12.55 18.5 12 18.5M12 12C9.79 12 8 13.79 8 16H16C16 13.79 14.21 12 12 12M12 4C9.79 4 8 5.79 8 8H16C16 5.79 14.21 4 12 4M3 20V22H13V20H3M16.5 18.21L17.79 16.93L19.5 18.65L23.07 15.07L24.5 16.45L19.5 21.45L16.5 18.21Z"/></svg>');
+  }
+
+  .device-name {
+    color: #fea373;
+    font-size: 16px;
+    font-weight: 500;
+  }
+
+  .device-count {
+    color: #fff;
+    font-size: 18px;
+    font-weight: 500;
+    margin-bottom: 10px;
+  }
+
+  .data-cards {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    // gap: 20px;
+    flex-wrap: wrap;
+    background: var(--title-bg);
+    border: 1px solid rgba(64, 158, 255, 0.1);
+    border-radius: 6px;
+  }
+
+  .data-card {
+    flex: 1;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    border-right: 1px solid rgba(64, 158, 255, 0.3);
+    text-align: right;
+    padding: 10px 20px;
+    &:last-child {
+      border-right: none;
+    }
+  }
+
+  .data-label {
+    color: var(--primary);
+    font-size: 18px;
+    font-weight: 500;
+  }
+
+  .data-value {
+    color: #fff;
+    font-size: 18px;
+    font-weight: 600;
+    margin-bottom: 2px;
+  }
+
+  .data-unit {
+    color: #fea373;
+    font-size: 16px;
+  }
+
+  /* 修改为两个图表容器 */
+  .charts-container {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    // min-height: 600px;
+  }
+
+  .chart-item {
+    flex: 1;
+    width: 100%;
+    height: 100%;
+    min-height: 300px;
+  }
+</style>

+ 362 - 0
src/views/hui-jia/components/implementary/ing.vue

@@ -0,0 +1,362 @@
+<template>
+  <div class="implementing-container">
+    <div class="implementing-title">
+      <img src="@/assets/images/nz.png" class="title-icon" />
+      进行中的实施服务
+    </div>
+    <div class="implementing-list">
+      <div
+        v-for="(item, index) in implementingList"
+        :key="index"
+        class="implementing-item"
+        :class="{ 'even-item': index % 2 === 1 }"
+      >
+        <div class="item-content">
+          <div class="item-date">{{ item.date }}</div>
+          <div class="item-city">{{ item.city }}</div>
+          <div class="project-info">
+            <div class="project-name">{{ item.projectName }}</div>
+            <div class="company-name">{{ item.companyName }}</div>
+          </div>
+          <div class="project-stats">
+            <div class="stat-item">
+              <span class="stat-value">{{ item.householdCount }}</span>
+              <span class="stat-label">户</span>
+            </div>
+            <div class="stat-item">
+              <span class="stat-value">{{ item.area }}</span>
+            </div>
+            <div class="stat-item">
+              <div class="progress-wrapper">
+                <span class="progress-text">{{ item.progress }}%</span>
+              </div>
+            </div>
+            <div class="stat-item service-item">
+              <span class="service-content">{{ item.serviceContent }}</span>
+            </div>
+            <div class="stat-item">
+              <span class="period">{{ item.period }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+// import { api } from '@/api'
+
+export default {
+  name: 'ImplementingServices',
+  data () {
+    return {
+      implementingList: [],
+      timer: null
+    }
+  },
+  computed: {
+    ...mapState(['entCode', 'communityId'])
+  },
+  mounted () {
+    this.init()
+    // 设置定时刷新
+    this.timer = setInterval(() => {
+      this.init()
+    }, 30000) // 每30秒刷新一次
+  },
+  beforeDestroy () {
+    if (this.timer) {
+      clearInterval(this.timer)
+    }
+  },
+  methods: {
+    // 初始化数据
+    async init () {
+      try {
+        // const params = {
+        //   entCode: this.entCode,
+        //   communityId: this.communityId
+        // }
+        // 这里应该调用实际的API获取数据
+        // const res = await api.getImplementingServices(params)
+        // this.implementingList = res.data || []
+
+        // 暂时使用模拟数据
+        this.loadMockData()
+      } catch (error) {
+        console.error('获取进行中实施服务数据失败:', error)
+      }
+    },
+    // 加载模拟数据
+    loadMockData () {
+      this.implementingList = [
+        {
+          date: '2025-11-19',
+          city: '五指山市',
+          projectName: '项目名称',
+          companyName: '物业公司名称',
+          householdCount: '999',
+          area: '北滨端',
+          progress: 90,
+          serviceContent: '数据清单模板填写培训',
+          period: '3周前'
+        },
+        {
+          date: '2025-11-19',
+          city: '五指山市',
+          projectName: '项目名称',
+          companyName: '物业公司名称',
+          householdCount: '999',
+          area: '北滨端',
+          progress: 90,
+          serviceContent: '数据清单模板填写培训',
+          period: '3周前'
+        },
+        {
+          date: '2025-11-19',
+          city: '五指山市',
+          projectName: '项目名称',
+          companyName: '物业公司名称',
+          householdCount: '999',
+          area: '北滨端',
+          progress: 90,
+          serviceContent: '数据清单模板填写培训',
+          period: '3周前'
+        },
+        {
+          date: '2025-11-19',
+          city: '五指山市',
+          projectName: '项目名称',
+          companyName: '物业公司名称',
+          householdCount: '999',
+          area: '北滨端',
+          progress: 90,
+          serviceContent: '数据清单模板填写培训',
+          period: '3周前'
+        },
+        {
+          date: '2025-11-19',
+          city: '五指山市',
+          projectName: '项目名称',
+          companyName: '物业公司名称',
+          householdCount: '999',
+          area: '北滨端',
+          progress: 90,
+          serviceContent: '数据清单模板填写培训',
+          period: '3周前'
+        },
+        {
+          date: '2025-11-19',
+          city: '五指山市',
+          projectName: '项目名称',
+          companyName: '物业公司名称',
+          householdCount: '999',
+          area: '北滨端',
+          progress: 90,
+          serviceContent: '数据清单模板填写培训',
+          period: '3周前'
+        }
+      ]
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .implementing-container {
+    background: var(--title-bg);
+    border-radius: 4px;
+    padding: 20px;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .implementing-title {
+    font-size: 18px;
+    font-weight: 500;
+    color: var(--title-primary);
+    margin-bottom: 20px;
+    display: flex;
+    align-items: center;
+
+    .iconfont {
+      margin-right: 8px;
+      font-size: 20px;
+    }
+  }
+
+  .implementing-list {
+    flex: 1;
+    overflow-y: auto;
+
+    // 自定义滚动条样式
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-track {
+      background: rgba(64, 158, 255, 0.1);
+      border-radius: 3px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background: rgba(64, 158, 255, 0.3);
+      border-radius: 3px;
+    }
+
+    &::-webkit-scrollbar-thumb:hover {
+      background: rgba(64, 158, 255, 0.5);
+    }
+  }
+
+  .implementing-item {
+    background: var(--content-bg); // 第一个项目使用--content-bg
+    padding: 16px;
+    margin-bottom: 12px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  // 偶数项使用--title-bg作为背景色
+  .implementing-item.even-item {
+    background: var(--title-bg);
+  }
+  .item-content {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap: 20px;
+    .item-date {
+      color: var(--title-secondary);
+      font-size: 14px;
+      margin-right: 16px;
+    }
+
+    .item-city {
+      color: var(--title-primary);
+      font-size: 14px;
+      font-weight: 500;
+      padding: 2px 8px;
+      border-radius: 4px;
+    }
+
+    .project-info {
+      flex: 1;
+      min-width: 200px;
+      margin-right: 20px;
+
+      .project-name {
+        flex: 0 0 1;
+        color: var(--title-primary);
+        font-size: 14px;
+        margin-bottom: 4px;
+        font-weight: 400;
+      }
+
+      .company-name {
+        color: var(--title-secondary);
+        font-size: 14px;
+      }
+    }
+
+    .project-stats {
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+      gap: 20px;
+    }
+
+    .stat-item {
+      display: flex;
+      align-items: center;
+      &:first-child {
+        .stat-value {
+          color: var(--primary);
+        }
+      }
+      .stat-value {
+        color: #fff;
+        font-size: 16px;
+        font-weight: 500;
+        margin-right: 4px;
+      }
+
+      .stat-label {
+        color: #fff;
+        font-size: 14px;
+      }
+
+      .progress-wrapper {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        .progress-text {
+          color: #40d9ac;
+          font-size: 14px;
+          font-weight: 500;
+          min-width: 35px;
+        }
+      }
+
+      .service-content {
+        color: #ffffff;
+        font-size: 14px;
+      }
+
+      .period {
+        color: #a0b3d6;
+        font-size: 14px;
+      }
+    }
+    .service-item {
+      flex: 1;
+    }
+  }
+
+  // 响应式设计
+  @media (max-width: 1200px) {
+    .item-content {
+      .content-main {
+        flex-direction: column;
+        gap: 12px;
+      }
+
+      .project-info {
+        margin-right: 0;
+        margin-bottom: 8px;
+      }
+
+      .project-stats {
+        width: 100%;
+        justify-content: space-between;
+      }
+    }
+  }
+
+  @media (max-width: 768px) {
+    .implementing-container {
+      padding: 16px;
+    }
+
+    .implementing-title {
+      font-size: 16px;
+    }
+
+    .item-content {
+      .project-stats {
+        gap: 12px;
+      }
+
+      .stat-item {
+        font-size: 12px;
+      }
+    }
+  }
+</style>

+ 342 - 0
src/views/hui-jia/components/implementary/now-year.vue

@@ -0,0 +1,342 @@
+<template>
+  <div class="now-year-container">
+    <div class="now-year-title">
+      <img src="@/assets/images/shb.png" class="title-icon" />
+      实施服务(今年数据)
+    </div>
+    <div class="chart-container">
+      <div id="nowYearChart" class="chart"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+// import { api } from '@/api'
+import * as echarts from 'echarts'
+
+export default {
+  name: 'NowYearServices',
+  data () {
+    return {
+      chartInstance: null,
+      chartData: {
+        categories: [
+          '履约城市',
+          '服务企业',
+          '服务项目',
+          '合同数',
+          '签约户数'
+        ],
+        ongoing: [88888, 88888, 88888, 88888, 88888], // 进行中
+        lastMonthCompleted: [88888, 88888, 88888, 88888, 88888], // 上月完成
+        yearTotal: [88888, 88888, 888888, 88888, 88888], // 今年累计
+        totalNumbers: [8888, 8888, 8888, 8888, 8888] // 左侧显示的总数
+      },
+      timer: null
+    }
+  },
+  computed: {
+    ...mapState(['entCode', 'communityId'])
+  },
+  mounted () {
+    this.init()
+    window.addEventListener('resize', this.handleResize)
+
+    // 设置定时刷新
+    this.timer = setInterval(() => {
+      this.loadData()
+    }, 30000) // 每30秒刷新一次
+  },
+  beforeDestroy () {
+    if (this.chartInstance) {
+      this.chartInstance.dispose()
+    }
+    window.removeEventListener('resize', this.handleResize)
+    if (this.timer) {
+      clearInterval(this.timer)
+    }
+  },
+  methods: {
+    // 初始化组件
+    init () {
+      this.initChart()
+      this.loadData()
+    },
+
+    // 初始化图表
+    initChart () {
+      this.chartInstance = echarts.init(
+        document.getElementById('nowYearChart')
+      )
+
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          },
+          backgroundColor: 'rgba(17, 28, 49, 0.9)',
+          borderColor: 'rgba(64, 158, 255, 0.2)',
+          textStyle: {
+            color: '#ffffff'
+          }
+        },
+        legend: {
+          data: ['进行中', '上月完成', '今年累计'],
+          textStyle: {
+            color: '#a0b3d6'
+          },
+          itemWidth: 16,
+          itemHeight: 8,
+          top: 10
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          top: 50,
+          containLabel: true
+        },
+        xAxis: {
+          type: 'value',
+          show: false, // 隐藏x轴
+          axisLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          axisLabel: {
+            show: false
+          },
+          splitLine: {
+            show: false
+          }
+        },
+        yAxis: {
+          type: 'category',
+          data: this.chartData.categories,
+          show: true, // 隐藏y轴
+          axisLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          axisLabel: {
+            show: true,
+            color: '#a1a1a1',
+            fontSize: 14
+          }
+        },
+        series: [
+          {
+            name: '进行中',
+            type: 'bar',
+            stack: 'total',
+            emphasis: {
+              focus: 'series'
+            },
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                { offset: 0, color: '#1620D4' },
+                { offset: 0.8, color: '#3AB3E3' }
+              ]),
+              borderRadius: [20, 0, 0, 20]
+            },
+            label: {
+              show: true,
+              color: '#fff'
+            },
+            barWidth: 30,
+            barGap: '0%',
+            barCategoryGap: '20%',
+            data: this.chartData.ongoing
+          },
+          {
+            name: '上月完成',
+            type: 'bar',
+            stack: 'total',
+            emphasis: {
+              focus: 'series'
+            },
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                { offset: 0, color: '#192FC9' },
+                { offset: 0.8, color: '#6D44BC' }
+              ]),
+              borderRadius: [0, 0, 0, 0]
+            },
+            label: {
+              show: true,
+              color: '#fff'
+            },
+            barWidth: 30,
+            barGap: '0%',
+            data: this.chartData.lastMonthCompleted
+          },
+          {
+            name: '今年累计',
+            type: 'bar',
+            stack: 'total',
+            emphasis: {
+              focus: 'series'
+            },
+            label: {
+              show: true,
+              color: '#fff'
+            },
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                { offset: 0, color: '#F7897D' },
+                { offset: 0.8, color: '#F66C89' }
+              ]),
+              borderRadius: [0, 20, 20, 0]
+            },
+            barWidth: 30,
+            barGap: '0%',
+            data: this.chartData.yearTotal
+          }
+        ]
+      }
+
+      this.chartInstance.setOption(option)
+    },
+
+    // 加载数据
+    async loadData () {
+      try {
+        // const params = {
+        //   entCode: this.entCode,
+        //   communityId: this.communityId
+        // }
+        // 这里应该调用实际的API获取数据
+        // const res = await api.getNowYearServices(params)
+        // this.chartData = res.data || this.chartData
+
+        // 暂时使用模拟数据
+        this.updateChart()
+      } catch (error) {
+        console.error('获取今年实施服务数据失败:', error)
+      }
+    },
+
+    // 更新图表
+    updateChart () {
+      if (this.chartInstance) {
+        this.chartInstance.setOption({
+          yAxis: {
+            data: this.chartData.categories
+          },
+          series: [
+            {
+              data: this.chartData.ongoing
+            },
+            {
+              data: this.chartData.lastMonthCompleted
+            },
+            {
+              data: this.chartData.yearTotal
+            }
+          ]
+        })
+      }
+    },
+
+    // 处理窗口大小变化
+    handleResize () {
+      if (this.chartInstance) {
+        this.chartInstance.resize()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .now-year-container {
+    background: var(--title-bg);
+    border-radius: 4px;
+    padding: 20px;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .now-year-title {
+    font-size: 18px;
+    font-weight: 500;
+    color: var(--title-primary);
+    margin-bottom: 20px;
+    display: flex;
+    align-items: center;
+
+    .iconfont {
+      margin-right: 8px;
+      font-size: 20px;
+    }
+  }
+
+  .chart-container {
+    flex: 1;
+    min-height: 0;
+    position: relative;
+    // 添加自定义内容显示
+    &::before {
+      content: "";
+      display: flex;
+      flex-direction: column;
+      justify-content: space-around;
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      bottom: 20px;
+      width: 120px;
+      z-index: 1;
+    }
+  }
+
+  .chart {
+    width: 100%;
+    height: 100%;
+    min-height: 400px;
+  }
+
+  // 添加自定义标签显示
+  .chart-container::before {
+    content: "";
+  }
+
+  // 响应式设计
+  @media (max-width: 1200px) {
+    .now-year-container {
+      padding: 16px;
+    }
+
+    .now-year-title {
+      font-size: 16px;
+      margin-bottom: 16px;
+    }
+
+    .chart {
+      min-height: 350px;
+    }
+  }
+
+  @media (max-width: 768px) {
+    .now-year-container {
+      padding: 12px;
+    }
+
+    .now-year-title {
+      font-size: 14px;
+    }
+
+    .chart {
+      min-height: 300px;
+    }
+  }
+</style>

+ 222 - 0
src/views/hui-jia/components/implementary/total.vue

@@ -0,0 +1,222 @@
+<template>
+  <div class="total-container">
+    <div class="total-title">
+      <img src="@/assets/images/tj.png" class="title-icon" />
+      实施服务(汇总数据
+    </div>
+    <div class="total-grid">
+      <div class="total-item">
+        <div class="total-label">城市总数</div>
+        <div class="total-value">{{ cityCount }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">企业总数</div>
+        <div class="total-value">{{ enterpriseCount }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">合同总数</div>
+        <div class="total-value">{{ contractCount }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">履约次数</div>
+        <div class="total-value">{{ performanceCount }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">服务时长</div>
+        <div class="total-value">{{ serviceHours }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">项目总数</div>
+        <div class="total-value">{{ projectCount }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">签约户数</div>
+        <div class="total-value">{{ signedUserCount }}</div>
+      </div>
+      <div class="total-item">
+        <div class="total-label">实施户数</div>
+        <div class="total-value">{{ implementationUserCount }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+// import { api } from '@/api'
+
+export default {
+  name: 'ImplementationTotal',
+  data () {
+    return {
+      cityCount: 99,
+      enterpriseCount: 99,
+      contractCount: 99,
+      performanceCount: 99,
+      serviceHours: 99,
+      projectCount: 99,
+      signedUserCount: 99,
+      implementationUserCount: 99,
+      timer: null
+    }
+  },
+  computed: {
+    ...mapState(['entCode', 'communityId'])
+  },
+  mounted () {
+    this.init()
+    // 设置定时刷新
+    this.timer = setInterval(() => {
+      this.init()
+    }, 60000) // 每分钟刷新一次
+  },
+  beforeDestroy () {
+    if (this.timer) {
+      clearInterval(this.timer)
+    }
+  },
+  methods: {
+    // 初始化数据
+    async init () {
+      try {
+        // const params = {
+        //   entCode: this.entCode,
+        //   communityId: this.communityId
+        // }
+        // 这里应该调用实际的API获取数据
+        // const res = await api.getImplementationTotal(params)
+        // 暂时使用模拟数据
+        this.updateData()
+      } catch (error) {
+        console.error('获取实施服务汇总数据失败:', error)
+      }
+    },
+    // 更新数据
+    updateData () {
+      // 这里可以根据实际API返回的数据进行更新
+      // 目前使用固定值展示
+      this.cityCount = 99
+      this.enterpriseCount = 99
+      this.contractCount = 99
+      this.performanceCount = 99
+      this.serviceHours = 99
+      this.projectCount = 99
+      this.signedUserCount = 99
+      this.implementationUserCount = 99
+    },
+    // 格式化数字显示
+    formatNumber (num) {
+      if (num >= 10000) {
+        return (num / 10000).toFixed(1) + '万'
+      }
+      return num.toString()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .total-container {
+    background: var(--title-bg);
+    border-radius: 4px;
+    padding: 20px;
+    position: relative;
+    overflow: hidden;
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      height: 2px;
+      background: linear-gradient(90deg, transparent, #409eff, transparent);
+    }
+
+    .total-title {
+      display: flex;
+      align-items: center;
+      font-size: 18px;
+      font-weight: 500;
+      color: var(--title-primary);
+      margin-bottom: 20px;
+    }
+
+    .total-grid {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      grid-template-rows: repeat(4, 1fr);
+      gap: 16px;
+    }
+
+    .total-item {
+      background: var(--content-bg);
+      border-radius: 6px;
+      padding: 16px;
+      text-align: center;
+      transition: all 0.3s ease;
+      border: 1px solid rgba(64, 158, 255, 0.1);
+
+      &:hover {
+        transform: translateY(-2px);
+        box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
+        border-color: rgba(64, 158, 255, 0.3);
+      }
+
+      .total-label {
+        font-size: 14px;
+        color: #a0b3d6;
+        margin-bottom: 8px;
+      }
+
+      .total-value {
+        font-size: 28px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 1.2;
+        // 添加数字闪烁动画
+        animation: pulse 2s infinite;
+      }
+    }
+  }
+
+  @keyframes pulse {
+    0% {
+      opacity: 1;
+      transform: scale(1);
+    }
+    50% {
+      opacity: 0.9;
+      transform: scale(1.02);
+    }
+    100% {
+      opacity: 1;
+      transform: scale(1);
+    }
+  }
+
+  // 响应式设计
+  @media (max-width: 1200px) {
+    .total-grid {
+      grid-template-columns: repeat(3, 1fr);
+      grid-template-rows: repeat(3, 1fr);
+    }
+
+    .total-value {
+      font-size: 24px !important;
+    }
+  }
+
+  @media (max-width: 768px) {
+    .total-grid {
+      grid-template-columns: repeat(2, 1fr);
+      grid-template-rows: repeat(4, 1fr);
+    }
+
+    .total-value {
+      font-size: 20px !important;
+    }
+  }
+</style>

+ 329 - 0
src/views/hui-jia/components/market.vue

@@ -0,0 +1,329 @@
+<template>
+  <div class="market-container">
+    <div class="market-title">
+      <i class="iconfont icon-enterprise"></i>
+      市场拓展
+    </div>
+    <div class="chart-content">
+      <div class="legend">
+        <div class="legend-item">上月</div>
+        <div class="legend-item">本月</div>
+      </div>
+      <div class="chart-container">
+        <div id="marketChart" class="chart"></div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+// import { api } from '@/api'
+import * as echarts from 'echarts'
+
+export default {
+  name: 'MarketExpansion',
+  data () {
+    return {
+      chartInstance: null,
+      chartData: {
+        categories: [
+          '新增企业',
+          '跟进项目',
+          '新增联系人',
+          '新增合同',
+          '新增项目',
+          '新增户数'
+        ],
+        lastMonthData: [-9, -9, -9, -9, -3, -12], // 上月数据
+        thisMonthData: [9, 9, 1, 1, 9, 10] // 本月数据
+      },
+      timer: null
+    }
+  },
+  computed: {
+    ...mapState(['entCode', 'communityId'])
+  },
+  mounted () {
+    this.init()
+    window.addEventListener('resize', this.handleResize)
+
+    // 设置定时刷新
+    this.timer = setInterval(() => {
+      this.loadData()
+    }, 30000) // 每30秒刷新一次
+  },
+  beforeDestroy () {
+    if (this.chartInstance) {
+      this.chartInstance.dispose()
+    }
+    window.removeEventListener('resize', this.handleResize)
+    if (this.timer) {
+      clearInterval(this.timer)
+    }
+  },
+  methods: {
+    // 初始化组件
+    init () {
+      this.initChart()
+      this.loadData()
+    },
+
+    // 初始化图表
+    initChart () {
+      this.chartInstance = echarts.init(
+        document.getElementById('marketChart')
+      )
+
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          },
+          backgroundColor: 'rgba(17, 28, 49, 0.9)',
+          borderColor: 'rgba(64, 158, 255, 0.2)',
+          textStyle: {
+            color: '#ffffff'
+          },
+          formatter: (params) => {
+            // 自定义tooltip格式
+            let result = params[0].name + '<br/>'
+            params.forEach((item) => {
+              result +=
+                  item.marker + item.seriesName + ': ' + item.value + '<br/>'
+            })
+            return result
+          }
+        },
+        grid: {
+          left: '25%',
+          right: '25%',
+          bottom: '3%',
+          top: 50,
+          containLabel: true
+        },
+        xAxis: {
+          type: 'value',
+          axisLabel: {
+            formatter: (value) => {
+              if (value < 0) return -value // 这里是针对取负值
+              else return value
+            }
+          },
+          show: false // 隐藏x轴
+          // axisLine: {
+          //   show: false,
+          // },
+          // axisTick: {
+          //   show: false,
+          // },
+          // axisLabel: {
+          //   show: false,
+          // },
+          // splitLine: {
+          //   show: false,
+          // },
+        },
+        yAxis: [
+          {
+            type: 'category',
+            data: this.chartData.categories,
+            axisLine: {
+              show: false
+            },
+            axisTick: {
+              show: false
+            },
+            axisLabel: {
+              show: false
+            }
+          },
+          {
+            type: 'category',
+            data: this.chartData.categories,
+            axisLine: {
+              show: false
+            },
+            axisTick: {
+              show: false
+            },
+            axisLabel: {
+              show: false,
+              color: '#a0b3d6',
+              fontSize: 14
+            }
+          }
+        ],
+        series: [
+          {
+            name: '上月',
+            type: 'bar',
+            //   stack: "sameStack",
+            stack: 'Total',
+            emphasis: {
+              focus: 'series'
+            },
+            barMinHeight: 4,
+            data: this.chartData.lastMonthData,
+            barWidth: 25,
+            itemStyle: {
+              // 左侧渐变色:从#F66757到#FCE2B4
+              color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
+                { offset: 0, color: '#FCE2B4' },
+                { offset: 1, color: '#F66757' }
+              ]),
+              borderRadius: [20, 0, 0, 20]
+            },
+            label: {
+              show: true,
+              position: 'left',
+              // formatter: '{c}',
+              color: '#ffffff',
+              fontSize: 12,
+              formatter: (value) => {
+                return -value.data
+              }
+            }
+          },
+          {
+            name: '本月',
+            type: 'bar',
+            //   stack: "sameStack",
+            stack: 'Total',
+            emphasis: {
+              focus: 'series'
+            },
+            barMinHeight: 4,
+            data: this.chartData.thisMonthData,
+            barWidth: 25,
+            itemStyle: {
+              // 右侧渐变色:从#1620D4到#3AB3E3
+              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                { offset: 0, color: '#3AB3E3' },
+                { offset: 1, color: '#1620D4' }
+              ]),
+              borderRadius: [0, 20, 20, 0]
+            },
+            label: {
+              show: true,
+              position: 'right',
+              formatter: '{c}',
+              color: '#ffffff',
+              fontSize: 12
+            }
+          }
+        ]
+      }
+
+      this.chartInstance.setOption(option)
+    },
+
+    // 加载数据
+    async loadData () {
+      try {
+        // const params = {
+        //   entCode: this.entCode,
+        //   communityId: this.communityId
+        // }
+        // 这里应该调用实际的API获取数据
+        // const res = await api.getMarketExpansionData(params)
+        // this.chartData = res.data || this.chartData
+
+        // 暂时使用模拟数据
+        this.updateChart()
+      } catch (error) {
+        console.error('获取市场拓展数据失败:', error)
+      }
+    },
+
+    // 更新图表
+    updateChart () {
+      if (this.chartInstance) {
+        this.chartInstance.setOption({
+          yAxis: [
+            {
+              data: this.chartData.categories
+            },
+            {
+              data: this.chartData.categories
+            }
+          ],
+          series: [
+            {
+              data: this.chartData.lastMonthData
+            },
+            {
+              data: this.chartData.thisMonthData
+            }
+          ]
+        })
+      }
+    },
+
+    // 处理窗口大小变化
+    handleResize () {
+      if (this.chartInstance) {
+        this.chartInstance.resize()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .market-container {
+    background: #0d1629;
+    border-radius: 4px;
+    border: 1px solid rgba(64, 158, 255, 0.2);
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .market-title {
+    border-radius: 4px;
+    background: var(--title-bg);
+    padding: 20px;
+    font-size: 18px;
+    font-weight: 500;
+    color: var(--title-primary);
+    display: flex;
+    align-items: center;
+
+    .iconfont {
+      margin-right: 8px;
+      font-size: 20px;
+    }
+  }
+
+  .chart-content {
+    margin: 20px;
+    background: var(--title-bg);
+    .legend {
+      display: flex;
+      justify-content: space-around;
+      align-items: center;
+      padding: 20px;
+      margin: 0px 10px;
+      font-size: 14px;
+      font-weight: 500;
+      color: #fff;
+      border-bottom: 1px solid rgba(64, 158, 255, 0.2);
+    }
+  }
+
+  .chart-container {
+    flex: 1;
+    min-height: 0;
+    position: relative;
+  }
+
+  .chart {
+    width: 100%;
+    height: 100%;
+    min-height: 400px;
+  }
+</style>

+ 277 - 0
src/views/hui-jia/components/smart.vue

@@ -0,0 +1,277 @@
+<template>
+  <div class="smart-door">
+    <!-- 标题 -->
+    <div class="module-title">智能门禁</div>
+
+    <!-- 数据卡片 -->
+    <div class="data-cards">
+      <div class="data-card">
+        <div class="data-info">
+          <i class="iconfont icon-door"></i>
+          <div class="data-label">门禁设备</div>
+        </div>
+        <div class="data-value">{{ doorDevices }}</div>
+      </div>
+
+      <div class="data-card">
+        <div class="data-info">
+          <i class="iconfont icon-project"></i>
+          <div class="data-label">开通项目</div>
+        </div>
+        <div class="data-value">{{ activeProjects }}</div>
+      </div>
+
+      <div class="data-card">
+        <div class="data-info">
+          <i class="iconfont icon-access"></i>
+          <div class="data-label">出入次数</div>
+        </div>
+        <div class="data-value">{{ accessTimes }}</div>
+      </div>
+    </div>
+
+    <!-- 通行流量趋势图 -->
+    <div class="chart-section">
+      <div class="chart-title">日通行流量趋势</div>
+      <div ref="trafficChart" class="traffic-chart"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'SmartDoor',
+  data () {
+    return {
+      doorDevices: '921',
+      activeProjects: '92',
+      accessTimes: '900000',
+      chartInstance: null,
+      // 模拟的通行流量数据
+      trafficData: [
+        { time: '01:00', count: 150 },
+        { time: '04:00', count: 250 },
+        { time: '07:00', count: 420 },
+        { time: '10:00', count: 380 },
+        { time: '13:00', count: 320 },
+        { time: '16:00', count: 230 },
+        { time: '19:00', count: 220 },
+        { time: '22:00', count: 300 }
+      ]
+    }
+  },
+  mounted () {
+    this.initChart()
+    window.addEventListener('resize', this.handleResize)
+  },
+  beforeDestroy () {
+    window.removeEventListener('resize', this.handleResize)
+    if (this.chartInstance) {
+      this.chartInstance.dispose()
+    }
+  },
+  methods: {
+    initChart () {
+      const echarts = require('echarts')
+      this.chartInstance = echarts.init(this.$refs.trafficChart)
+
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          backgroundColor: 'rgba(0, 0, 0, 0.8)',
+          borderColor: 'rgba(64, 158, 255, 0.3)',
+          textStyle: {
+            color: '#fff'
+          },
+          formatter: (params) => {
+            return `${params[0].name}<br/>${params[0].seriesName}: ${params[0].value}`
+          }
+        },
+        legend: {
+          data: ['开门次数'],
+          textStyle: {
+            color: '#fff'
+          },
+          top: '0%',
+          right: '0%'
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '10%',
+          top: '20%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: this.trafficData.map((item) => item.time),
+          axisLine: {
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.6)'
+            }
+          },
+          axisLabel: {
+            color: 'rgba(160, 179, 214, 0.7)',
+            fontSize: 14
+          },
+          axisTick: {
+            show: false
+          },
+          splitLine: {
+            show: true,
+            // 将坐标轴内的线设置为虚线
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.3)',
+              type: 'dashed'
+            }
+          }
+        },
+        yAxis: {
+          type: 'value',
+          axisLine: {
+            show: false
+          },
+          axisLabel: {
+            color: 'rgba(160, 179, 214, 0.7)',
+            fontSize: 12
+          },
+          axisTick: {
+            show: false
+          },
+          splitLine: {
+            // 将坐标轴内的线设置为虚线
+            lineStyle: {
+              color: 'rgba(160, 179, 214, 0.3)',
+              type: 'dashed'
+            }
+          }
+        },
+        series: [
+          {
+            name: '开门次数',
+            type: 'bar',
+            data: this.trafficData.map((item) => item.count),
+            barWidth: '30%',
+            // 添加标签配置,设置颜色为白色
+            label: {
+              show: true,
+              position: 'top',
+              color: '#fff',
+              fontSize: 14
+            },
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
+                { offset: 0, color: '#F6688B' },
+                { offset: 1, color: '#F89877' }
+              ])
+            }
+          }
+        ]
+      }
+
+      this.chartInstance.setOption(option)
+    },
+    handleResize () {
+      if (this.chartInstance) {
+        this.chartInstance.resize()
+      }
+    },
+    // 模拟数据更新方法
+    updateData () {
+      // 这里可以根据实际需求从API获取数据
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .smart-door {
+    background: var(--content-bg);
+    border-radius: 4px;
+    padding: 20px;
+    height: 100%;
+  }
+
+  .module-title {
+    color: var(--title-primary);
+    margin-bottom: 20px;
+  }
+
+  .data-cards {
+    display: flex;
+    gap: 16px;
+    margin-bottom: 24px;
+    flex-wrap: wrap;
+    padding: 10px 20px;
+    margin: 36px auto;
+    background: var(--title-bg);
+    border: 1px solid rgba(64, 158, 255, 0.1);
+    border-radius: 6px;
+  }
+
+  .data-card {
+    flex: 1;
+    min-width: 200px;
+    padding: 16px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    &:nth-child(1) {
+      border-right: 1px solid rgba(64, 158, 255, 0.1);
+    }
+    &:nth-child(2) {
+      border-right: 1px solid rgba(64, 158, 255, 0.1);
+    }
+
+    .iconfont {
+      width: 40px;
+      height: 40px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background: linear-gradient(135deg, #2196f3 0%, #64b5f6 100%);
+      border-radius: 6px;
+      font-size: 20px;
+      color: #ffffff;
+    }
+
+    .data-info {
+      display: flex;
+      gap: 12px;
+      align-items: center;
+    }
+
+    .data-label {
+      font-size: 14px;
+      color: var(--primary);
+      margin-bottom: 4px;
+    }
+
+    .data-value {
+      font-size: 24px;
+      font-weight: 600;
+      color: var(--title-primary, #ffffff);
+    }
+  }
+
+  .chart-section {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .chart-title {
+    font-size: 14px;
+    font-weight: 500;
+    color: #fff;
+    margin-bottom: 16px;
+  }
+
+  .traffic-chart {
+    flex: 1;
+    width: 100%;
+    min-height: 250px;
+  }
+</style>

+ 145 - 0
src/views/hui-jia/components/work-card.vue

@@ -0,0 +1,145 @@
+<template>
+  <div class="work-card">
+    <div class="work-card-item" v-for="item in dataList" :key="item.title">
+      <div class="card-header">
+        <!-- <i class="iconfont" :class="iconName"></i> -->
+        <span class="card-title">{{ item.title }}</span>
+      </div>
+      <div class="card-content">
+        <div class="card-subtitle">{{ item.subtitle }}</div>
+        <div class="card-value">{{ formatNumber(item.value) }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'WorkCard',
+  props: {
+    iconName: {
+      type: String,
+      required: true,
+      default: 'icon-enterprise'
+    },
+    title: {
+      type: String,
+      required: true
+    },
+    subtitle: {
+      type: String,
+      required: true
+    },
+    value: {
+      type: [Number, String],
+      required: true,
+      default: 0
+    }
+  },
+  data () {
+    return {
+      dataList: [
+        {
+          title: '数电票业务',
+          subtitle: '已开发票数',
+          value: 345345
+        },
+        {
+          title: '道闸系统',
+          subtitle: '设备数量',
+          value: 453
+        },
+        {
+          title: '智慧二维码',
+          subtitle: '配置数量',
+          value: 45
+        },
+        {
+          title: '短信业务',
+          subtitle: '销售数量',
+          value: 3456
+        },
+        {
+          title: '房屋租售',
+          subtitle: '发布资产数',
+          value: 887
+        },
+        {
+          title: '业委会',
+          subtitle: '开通数量',
+          value: 34
+        }
+      ]
+    }
+  },
+  methods: {
+    // 格式化数字显示
+    formatNumber (num) {
+      if (typeof num === 'string') {
+        return num
+      }
+      // 如果数字是整数,直接返回字符串形式
+      return num.toString()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "@/assets/css/theme.scss";
+
+  .work-card {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    grid-template-rows: repeat(2, 1fr);
+    gap: 10px;
+  }
+
+  .work-card-item {
+    background: var(--content-bg);
+    border-radius: 4px;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+  }
+
+  .card-header {
+    display: flex;
+    align-items: center;
+    margin-bottom: 16px;
+    padding: 20px;
+    background: var(--title-bg);
+
+    .iconfont {
+      font-size: 24px;
+      margin-right: 10px;
+      // 根据不同图标使用不同颜色
+      color: var(--primary-color, #409eff);
+    }
+
+    .card-title {
+      font-size: 16px;
+      font-weight: 500;
+      color: var(--title-primary);
+    }
+  }
+
+  .card-content {
+    display: flex;
+    align-items: flex-end;
+    padding: 20px;
+    .card-subtitle {
+      font-size: 14px;
+      color: #82d1f6;
+    }
+
+    .card-value {
+      margin-left: 12px;
+      font-size: 18px;
+      font-weight: 600;
+      color: #fff;
+      letter-spacing: 1px;
+    }
+  }
+</style>

+ 44 - 0
src/views/hui-jia/index.vue

@@ -0,0 +1,44 @@
+<!--
+ * @Author: wjc
+ * @Date: 2025-11-17 16:26:35
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 15:51:58
+ * @Description:
+-->
+<template>
+  <div>
+    <implementationTotal />
+    <implementationIng />
+    <implementationNowYear />
+    <Market />
+    <WorkCard />
+    <Smart />
+    <Hardware />
+  </div>
+</template>
+
+<script>
+
+import implementationTotal from './components/implementary/total.vue'
+import implementationIng from './components/implementary/ing.vue'
+import implementationNowYear from './components/implementary/now-year.vue'
+import Market from './components/market.vue'
+import WorkCard from './components/work-card.vue'
+import Smart from './components/smart.vue'
+import Hardware from './components/hardware.vue'
+
+export default {
+  components: {
+    implementationTotal,
+    implementationIng,
+    implementationNowYear,
+    Market,
+    WorkCard,
+    Smart,
+    Hardware
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 3 - 3
src/views/index/components/communication/index.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: WangQiBiao
  * @Date: 2019-09-25 14:10:08
- * @LastEditors: MoZhuangRu
- * @LastEditTime: 2020-03-18 15:40:00
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 09:50:12
  * @Description: 在线沟通
  -->
 <template>
@@ -35,7 +35,7 @@
 <script>
 import TitleCom from '@/components/title'
 import TagCom from '@/components/tag'
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import { api } from '@/api'
 import vueSeamless from 'vue-seamless-scroll'
 

+ 3 - 3
src/views/index/components/income/index.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: WangQiBiao
  * @Date: 2019-09-26 10:57:30
- * @LastEditors: MoZhuangRu
- * @LastEditTime: 2020-01-17 11:53:32
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 09:46:07
  * @Description: 收入统计
  -->
 <template>
@@ -38,7 +38,7 @@
   </div>
 </template>
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import { api } from '@/api'
 
 export default {

+ 3 - 3
src/views/index/components/paid-in/index.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: WangQiBiao
  * @Date: 2019-09-26 08:46:04
- * @LastEditors: MoZhuangRu
- * @LastEditTime: 2020-01-15 17:05:07
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 09:48:09
  * @Description: 近1年应实收统计
  -->
 <template>
@@ -19,7 +19,7 @@
 <script>
 import TitleCom from '@/components/title'
 import IncomeCom from './../income'
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import { api } from '@/api'
 
 export default {

+ 3 - 3
src/views/index/components/repair/index.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: WangQiBiao
  * @Date: 2019-09-25 17:54:01
- * @LastEditors: MoZhuangRu
- * @LastEditTime: 2020-07-22 11:07:39
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 09:50:34
  * @Description: 住户报修
  -->
 <template>
@@ -57,7 +57,7 @@
 </template>
 <script>
 import TitleCom from '@/components/title'
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import { api } from '@/api'
 export default {
   components: {

File diff suppressed because it is too large
+ 185 - 366
yarn.lock


Some files were not shown because too many files changed in this diff