Forráskód Böngészése

wip: b2 小组件

wjc 2 hete
szülő
commit
8fd595322d

+ 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.9.0",
+    "sass": "^1.94.0",
     "sass-loader": "^7.1.0",
     "vue-template-compiler": "^2.6.10"
   }

+ 3 - 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,7 @@
     <router-view/>
   </div>
 </template>
-<style lang="scss" scoped>
+<style lang="scss">
 @import '../src/assets/css/theme.scss';
 #app{
   background: $big-bg;

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

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

+ 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-17 16:30:37
  * @Description: 白名单菜单
  */
 import _import from './_import'
@@ -39,6 +39,15 @@ export default [
       icon: ''
     }
   },
+  {
+    path: '/hui-jia',
+    component: () => import('@/views/hui-jia/index.vue'),
+    meta: {
+      title: '绘家科技',
+      hideInMenu: false,
+      icon: ''
+    }
+  },
   {
     path: '/login',
     component: _import('login'),

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

@@ -0,0 +1,362 @@
+<template>
+  <div class="implementing-container">
+    <div class="implementing-title">
+      <i class="iconfont icon-task"></i>
+      进行中的实施服务
+    </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">
+      <i class="iconfont icon-bar-chart"></i>
+      实施服务(今年数据)
+    </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>

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

@@ -0,0 +1,221 @@
+<template>
+  <div class="total-container">
+    <div class="total-title">实施服务(汇总数据)</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 {
+    font-size: 18px;
+    font-weight: 500;
+    color: var(--title-primary);
+    margin-bottom: 20px;
+    text-align: center;
+  }
+  
+  .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>

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

@@ -0,0 +1,356 @@
+<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, 0, 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" },
+                ]),
+              },
+              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" },
+                ]),
+              },
+              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: 8px;
+    border: 1px solid rgba(64, 158, 255, 0.2);
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .market-title {
+    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;
+  }
+
+  // 响应式设计
+  @media (max-width: 1200px) {
+    .market-container {
+      padding: 16px;
+    }
+
+    .market-title {
+      font-size: 16px;
+      margin-bottom: 16px;
+    }
+
+    .chart {
+      min-height: 350px;
+    }
+  }
+
+  @media (max-width: 768px) {
+    .market-container {
+      padding: 12px;
+    }
+
+    .market-title {
+      font-size: 14px;
+    }
+
+    .chart {
+      min-height: 300px;
+    }
+  }
+</style>

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

@@ -0,0 +1,35 @@
+<!--
+ * @Author: wjc
+ * @Date: 2025-11-17 16:26:35
+ * @LastEditors: wjc
+ * @LastEditTime: 2025-11-18 10:10:35
+ * @Description:
+-->
+<template>
+  <div>
+    <implementationTotal />
+    <implementationIng />
+    <implementationNowYear />
+    <Market />
+  </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 {
+  components: {
+    implementationTotal,
+    implementationIng,
+    implementationNowYear,
+    Market
+  }
+}
+</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: {

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 185 - 366
yarn.lock


Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott