瀏覽代碼

数据看板修改

duy 7 月之前
父節點
當前提交
56ef5b2999

+ 1 - 1
electron.vite.config.mjs

@@ -36,7 +36,7 @@ export default defineConfig({
                     changeOrigin: true,
                     //target: 'http://127.0.0.1:8014',
                     target: 'http://192.168.0.109:8014',
-                    // target: 'http://39.108.216.210:8014',
+                    // target: 'http://219.151.181.73:8014',
                         //    target: 'http://192.168.0.21:8014',
                     rewrite: (path) => path.replace(new RegExp('^/api'), '/'),
                 },

+ 19 - 1
src/main/index.js

@@ -67,6 +67,8 @@ function createWindow() {
             sandbox: false,
             webviewTag: true,
             nodeIntegration: true,
+            contextIsolation: true,
+            webSecurity: true,
         },
     })
 
@@ -91,6 +93,22 @@ function createWindow() {
             mainWindow.webContents.send('clear-token-cache')
         }
     })
+    // 添加 CSP 配置
+    mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
+        callback({
+            responseHeaders: {
+                ...details.responseHeaders,
+                'Content-Security-Policy': [
+                    'default-src \'self\' \'unsafe-inline\' \'unsafe-eval\' data: blob:; '
+                    + 'script-src \'self\' \'unsafe-inline\' \'unsafe-eval\'; '
+                    + 'style-src \'self\' \'unsafe-inline\'; '
+                    + 'img-src \'self\' data: blob: https:; '
+                    + 'connect-src \'self\' https: ws: wss:; '
+                    + 'font-src \'self\' data:;',
+                ],
+            },
+        })
+    })
 }
 
 function setupWebRequestFilter() {
@@ -99,7 +117,7 @@ function setupWebRequestFilter() {
     }
     //const url = 'http://127.0.0.1:8014'
         const url = 'http://192.168.0.109:8014'
-    // const url = 'http://39.108.216.210:8014'
+    // const url = 'http://219.151.181.73:8014'
             // const url = 'http://192.168.0.21:8014'
     session.defaultSession.webRequest.onBeforeRequest(
         filter,

二進制
src/renderer/src/assets/view/beijing.png


二進制
src/renderer/src/assets/view/top.png


+ 4 - 0
src/renderer/src/layout/index2.vue

@@ -62,6 +62,10 @@ const menuBarData = ref([
                 code: 'system-user',
                 name: '用户管理',
             },
+            {
+                code: 'system-menu',
+                name: '菜单管理',
+            },
             {
                 code: 'system-role',
                 name: '角色管理',

+ 6 - 0
src/renderer/src/router/modules/base.js

@@ -136,6 +136,12 @@ export default [
                 meta: { title: '角色管理' },
                 component: () => import('~src/views/system/role.vue'),
             },
+            {
+                path: '/system/menu',
+                name: 'system-menu',
+                meta: { title: '菜单管理' },
+                component: () => import('~src/views/system/menu.vue'),
+            },
         ],
     },
     {

+ 254 - 2
src/renderer/src/views/home2/datav.vue

@@ -1,3 +1,255 @@
 <template>
-    <div>数据看板</div>
-</template>
+    <div class="hc-datav-main hc-full">
+        <img class="hc-datav-bg" :src="bgPng" alt="bg">
+        <div id="hc-datav-header-body" class="relative">
+            <div class="hc-datav-header">
+                <img id="datav-header-bg" :src="png2" alt="头部图">
+                <div class="header-title hc-flex-center w-full">
+                    <div ref="nameRef" class="name hc-flex" @click="toHomePage">
+                        <i class="i-solar-graph-outline" />
+                        高速公路投资效益分析看板
+                    </div>
+                </div>
+            </div>
+            <div class="hc-datav-total relative p-[14px]">
+                <el-row :gutter="24">
+                    <el-col :span="12">
+                        <HcDatavCard title="项目数" :num="0" unit="" color="#D5DEFF" />
+                    </el-col>
+                    <el-col :span="12">
+                        <HcDatavCard title="运营单位" :num="0" unit="" color="#EEB500" />
+                    </el-col>
+                </el-row>
+            </div>
+            <div class="hc-datav-statics-1 relative p-[14px]">
+                <el-row :gutter="24">
+                    <el-col :span="8">
+                        <div class="bg-box-card">
+                            <div class="bg-box-card-title">
+                                <i class="ri-share-line" /> <span>项目统计</span>
+                            </div>
+                            <div class="hc-full relative">
+                                <ArrRoundChart
+                                    ref="fixedChartRef" 
+                                    :datas="{ 
+                                        type1: 33, 
+                                        type2: 120, 
+                                        type3: 200, 
+                                    }"
+                                    :config="{
+                                        color: ['#4B91FF', '#36CBCB', '#32C67C'],
+                                        name: ['四环线', '二十环线', '六十环线'],
+                                        key: ['type1', 'type2', 'type3'],
+                                        label: '项目统计',
+                                    }"
+                                    @chart-click="handleChartClick"
+                                />
+                            </div>
+                        </div>
+                    </el-col>
+                    <el-col :span="8">
+                        <div class="bg-box-card">
+                            <div class="bg-box-card-title">
+                                <i class="ri-numbers-line" style="color:rgb(62, 177, 165)" /> <span>运营统计</span>
+                            </div>
+                            <div class="hc-full relative">
+                                <HcDatavBarChart
+                                    :datas="[
+                                        { name: '渝东公司', value: 100 },
+                                        { name: '南方公司', value: 150 },
+                                        { name: '北方公司', value: 200 },
+                                        { name: '中交一公司', value: 250 },
+                                        { name: '渝东公司', value: 100 },
+                                        { name: '南方公司', value: 150 },
+                                        { name: '北方公司', value: 200 },
+                                        { name: '中交一公司', value: 250 },
+                                    ]"
+                                />
+                            </div>
+                        </div>
+                    </el-col>
+                    <el-col :span="8">
+                        <div class="bg-box-card">
+                            <div class="bg-box-card-title flex justify-between">
+                                <div> <i class="ri-line-chart-line" style="color:#18DD32" /> <span>收益统计</span></div>
+                                <div ref="searchRef">
+                                    <HcDatavSelect v-model="searchForm.year" :datas="yearArr" :clearable="false" @change="searchChange" />
+                                    <HcDatavSelect v-model="searchForm.projectType" :datas="typeArr" placeholder="项目类型" @change="searchChange" />
+                                    <HcDatavSelect v-model="searchForm.projectType" :datas="typeArr2" placeholder="前五名" @change="searchChange" />
+                                </div>
+                            </div>
+                            <div class="hc-full relative">
+                                <HcDatavVerticalBarChart
+                                    :datas="[
+                                        { name: '1号高速公路', value: 100 },
+                                        { name: '2号高速公路', value: 50 },
+                                        { name: '3号高速公路', value: 200 },
+                                        { name: '4号高速公路', value: 120 },
+                                        { name: '5号高速公路', value: 150 },
+                                    ]"
+                                />
+                            </div>
+                        </div>
+                    </el-col>
+                </el-row>
+            </div>
+            <div class="hc-datav-statics-2 relative p-[14px]">
+                <el-row :gutter="24">
+                    <el-col :span="24">
+                        <div class="bg-box-card-1">
+                            <div class="bg-box-card-title flex justify-between">
+                                <div> <i class="ri-taxi-wifi-line" style="color:#B3206F" /> <span>车流量统计</span></div>
+                                <div ref="searchRef">
+                                    <HcDatavSelect v-model="searchForm.year" :datas="yearArr" :clearable="false" @change="searchChange" />
+                                    <HcDatavSelect v-model="searchForm.projectType" :datas="typeArr" placeholder="项目类型" @change="searchChange" />
+                                    <HcDatavSelect v-model="searchForm.projectType" :datas="typeArr2" placeholder="前五名" @change="searchChange" />
+                                </div>
+                            </div>
+                            <div class="hc-full relative">
+                                <HcDatavLineChart
+                                    :datas="[
+                                        { name: '1月', value: 100 },
+                                        { name: '2月', value: 150 },
+                                        { name: '3月', value: 220 },
+                                        { name: '4月', value: 100 },
+                                        { name: '5月', value: 140 },
+                                        { name: '6月', value: 180 },
+                                        { name: '7月', value: 160 },
+                                        { name: '8月', value: 100 },
+                                        { name: '9月', value: 200 },
+                                        { name: '10月', value: 220 },
+                                        { name: '11月', value: 180 },
+                                        { name: '12月', value: 140 },
+                                    ]"
+                                />
+                            </div>
+                        </div>
+                    </el-col>
+                </el-row>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted, ref } from 'vue'
+import { useRouter } from 'vue-router'
+import { useAppStore } from '~src/store'
+import { getStore, setStore } from 'hc-vue3-ui'
+import bgPng from '~src/assets/view/beijing.png'
+import png2 from '~src/assets/view/top.png'
+import HcDatavSelect from './modules/select.vue'
+import HcDatavCard from './modules/card.vue'
+import HcDatavBarChart from './modules/echarts/HcDatavBarChart.vue'
+import HcDatavVerticalBarChart from './modules/echarts/HcDatavVerticalBarChart.vue'
+import HcDatavLineChart from './modules/echarts/HcDatavLineChart.vue'
+import ArrRoundChart from './modules/echarts/HcDatavRoundChart.vue'
+import { getArrValue, getObjValue, isNullES } from 'js-fast-way'
+import { getDictionaryData } from '~src/utils/tools'
+import projectApi from '~api/datav/projectdata'
+import dayjs from 'dayjs'
+
+const router = useRouter()
+const store = useAppStore()
+
+//引导
+const nameRef = ref(null)
+
+
+onMounted(() => {
+
+
+})
+const yearArr = ref( [{ id: '2024年', name: '2024年' }, { id: '2025年', name: '2025年' }, { id: '2026年', name: '2026年' }])
+const typeArr = ref([])
+const typeArr2 = ref( [{ id: '前五名', name: '前五名' }, { id: '前十名', name: '前十名' }, { id: '前十名', name: '前十名' }])
+const fixedChartRef = ref(null)
+
+//搜索表单
+const pageType = ref('1')
+const searchRef = ref(null)
+const searchForm = ref({
+    year: new dayjs().year(), month: null, projectScheduleGrade: '-1', projectStage: null, projectType: null, projectScheduleType: null,
+    quarter: '1',
+})
+const searchChange = () => {
+  console.log(111111111)
+  
+}
+
+
+
+
+
+
+
+
+
+
+
+
+//跳转到首页
+const toHomePage = () => {
+    console.log(store.page)
+    router.push( { name: 'project-data' })
+}
+
+//监听浏览器窗口变化
+const windowResize = () => {
+    window.addEventListener('resize', resizeEvent)
+}
+const resizeEvent = () => {
+    window.requestAnimationFrame(() => {
+        onWindowResize()
+    })
+}
+
+//设置尺寸
+const onWindowResize = () => {
+    const height = document.getElementById('hc-datav-header-body').offsetHeight
+    document.getElementById('hc-datav-row-total-body').style.height = `calc(100% - ${height + 10}px)`
+}
+
+//被卸载
+onUnmounted(() => {
+    window.removeEventListener('resize', resizeEvent)
+})
+// 在 script setup 中添加处理函数
+const handleChartClick = (data) => {
+    console.log('点击了扇形:', data)
+    router.push( { name: 'project-data' })
+    // 这里可以添加您的业务逻辑
+}
+</script>
+
+<style lang="scss">
+@import '~src/styles/view/datav';
+.bg-box-card{
+    background-color: rgba(0, 43, 84, 0.8);
+    border: 1px solid rgba(15, 84, 155, 0.8);
+    border-radius: 4px;
+    height: calc(34vh);  // 修改固定高度为动态高度
+    padding: 14px;
+}
+
+.bg-box-card-1{
+    background-color: rgba(0, 43, 84, 0.8);
+    border: 1px solid rgba(15, 84, 155, 0.8);
+    border-radius: 4px;
+    height: calc(33vh - 17px);  // 修改固定高度为动态高度
+    padding: 14px;
+}
+.bg-box-card-title{
+    height: 25px;
+    color:#5087EC;
+    font-size: 18px;
+    font-weight: 700;
+    z-index: 999;
+    margin-bottom: 15px;
+ 
+}
+.hc-full {
+    height: calc(100% - 40px);  // 减去标题和padding的高度
+    overflow: hidden;
+}
+</style>

+ 0 - 0
src/renderer/src/views/home2/modules/bg-card.vue


+ 92 - 0
src/renderer/src/views/home2/modules/card.vue

@@ -0,0 +1,92 @@
+<template>
+    <div class="hc-datav-total-card relative h-[120px] p-[14px]">
+        <div class="card-angle absolute inset-0">
+            <div class="angle a1 absolute left-0 top-0 h-[21px] w-[34px]" />
+            <div class="angle a2 absolute right-0 top-0 h-[21px] w-[34px]" />
+            <div class="angle a3 absolute bottom-0 left-0 h-[21px] w-[34px]" />
+            <div class="angle a4 absolute bottom-0 right-0 h-[21px] w-[34px]" />
+        </div>
+        <div class="card-content relative h-full">
+            <template v-if="isSlotDefault">
+                <slot />
+            </template>
+            <template v-else>
+                <div v-if="isSlotTitle" class="title text-[28px] font-bold">
+                    <slot name="title" />
+                </div>
+                <div v-else class="title text-ti-color text-[24px] font-bold">{{ title }}</div>
+                <div class="quantity absolute bottom-[-8px] font-bold">
+                    <span class="num vertical-sub text-[60px]">{{ num }}</span>
+                    <span v-if="unit" class="unit ml-[5px] text-[28px]">({{ unit }})</span>
+                </div>
+            </template>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, useSlots } from 'vue'
+defineProps({
+    title: {
+        type: String,
+        default: '',
+    },
+    num: {
+        type: [String, Number],
+        default: '0',
+    },
+    unit: {
+        type: String,
+        default: '亿',
+    },
+    color: {
+        type: String,
+        default: '',
+    },
+})
+
+//判断<slot>是否有传值
+const slots = useSlots()
+const isSlotDefault = ref(!!slots.default)
+const isSlotTitle = ref(!!slots.title)
+</script>
+
+<style scoped lang="scss">
+.text-ti-color{
+    color:rgba(165, 244, 245, 1);
+}
+.hc-datav-total-card {
+    .card-angle {
+        background-color: rgb(0 43 84 / 80%);
+        border: 1px solid rgb(15 84 155 / 80%);
+        border-radius: 4px;
+        z-index: 0;
+        .angle {
+            // border: 5px solid #66FFFF;
+            &.a1 {
+                border-right: 0;
+                border-bottom: 0;
+                border-radius: 4px 0 0 0;
+            }
+            &.a2 {
+                border-left: 0;
+                border-bottom: 0;
+                border-radius: 0 4px 0 0;
+            }
+            &.a3 {
+                border-top: 0;
+                border-right: 0;
+                border-radius: 0 0 0 4px;
+            }
+            &.a4 {
+                border-top: 0;
+                border-left: 0;
+                border-radius: 0 0 4px 0;
+            }
+        }
+    }
+    .card-content {
+        z-index: 1;
+    }
+}
+</style>

+ 144 - 0
src/renderer/src/views/home2/modules/echarts/HcDatavBarChart.vue

@@ -0,0 +1,144 @@
+<template>
+    <div class="hc-bar-chart-box">
+        <div ref="echart" class="hc-bar-chart-echarts" />
+    </div>
+</template>
+
+<script setup>
+import * as echarts from 'echarts'
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
+
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => [],
+    },
+})
+
+let chart = null
+const echart = ref(null)
+
+// 监听数据变化
+watch(() => props.datas, (newVal) => {
+    if (newVal) {
+        setOptions(newVal)
+    }
+}, { deep: true })
+
+// 初始化图表
+const initChart = () => {
+    chart = echarts.init(echart.value)
+    setOptions(props.datas)
+}
+
+// 设置图表配置
+const setOptions = (chartData) => {
+    const names = chartData.map(item => item.name)
+    const values = chartData.map(item => item.value)
+    
+    chart.setOption({
+        grid: {
+            left: '3%',
+            right: '4%',
+            bottom: '3%',
+            top: '3%',
+            containLabel: true,
+        },
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'shadow',
+            },
+            formatter: (params) => {
+                return `${params[0].name}: ${params[0].value}`
+            },
+            backgroundColor: '#fff',
+            borderColor: '#E8E8E8',
+            textStyle: {
+                color: '#333',
+            },
+        },
+        xAxis: {
+            type: 'value',
+            splitLine: {
+                show: true,
+                lineStyle: {
+                    color: 'rgba(255, 255, 255, 0.1)',
+                    type: 'dashed',
+                },
+            },
+            axisLine: {
+                show: false,
+            },
+            axisTick: {
+                show: false,
+            },
+            axisLabel: {
+                color: '#fff',
+            },
+        },
+        yAxis: {
+            type: 'category',
+            data: names,
+            axisLine: {
+                show: false,
+            },
+            axisTick: {
+                show: false,
+            },
+            axisLabel: {
+                color: '#fff',
+            },
+        },
+        series: [{
+            type: 'bar',
+            data: values,
+            barWidth: '40%',
+            itemStyle: {
+                color: '#3F95C2',
+                borderRadius: [0, 4, 4, 0],
+            },
+        }],
+    })
+}
+
+// 监听窗口大小变化
+const handleResize = () => {
+    chart && chart.resize()
+}
+
+// 组件挂载
+onMounted(() => {
+    nextTick(() => {
+        initChart()
+        window.addEventListener('resize', handleResize)
+    })
+})
+
+// 组件卸载
+onUnmounted(() => {
+    window.removeEventListener('resize', handleResize)
+    if (chart) {
+        chart.dispose()
+        chart = null
+    }
+})
+
+// 暴露方法
+defineExpose({
+    resize: handleResize,
+})
+</script>
+
+<style lang="scss" scoped>
+.hc-bar-chart-box {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    
+    .hc-bar-chart-echarts {
+        width: 100%;
+        height: 100%;
+    }
+}
+</style>

+ 165 - 0
src/renderer/src/views/home2/modules/echarts/HcDatavLineChart.vue

@@ -0,0 +1,165 @@
+<template>
+    <div class="hc-line-chart-box">
+        <div ref="echart" class="hc-line-chart-echarts" />
+    </div>
+</template>
+
+<script setup>
+import * as echarts from 'echarts'
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
+
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => [],
+    },
+})
+
+let chart = null
+const echart = ref(null)
+
+// 监听数据变化
+watch(() => props.datas, (newVal) => {
+    if (newVal) {
+        setOptions(newVal)
+    }
+}, { deep: true })
+
+// 初始化图表
+const initChart = () => {
+    chart = echarts.init(echart.value)
+    setOptions(props.datas)
+}
+
+// 设置图表配置
+const setOptions = (chartData) => {
+    const names = chartData.map(item => item.name)
+    const values = chartData.map(item => item.value)
+    
+    chart.setOption({
+        grid: {
+            top: '5%',
+            left: '3%',
+            right: '4%',
+            bottom: '3%',
+            containLabel: true,
+        },
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'line',
+                lineStyle: {
+                    color: '#fff',
+                    type: 'solid',
+                },
+            },
+            backgroundColor: '#5087EC',
+            borderColor: 'rgba(255,255,255,0.3)',
+            textStyle: {
+                color: '#fff',
+            },
+        },
+        xAxis: {
+            type: 'category',
+            boundaryGap: false,
+            data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+            axisLine: {
+                lineStyle: {
+                    color: 'rgba(255,255,255,0.1)',
+                },
+            },
+            axisTick: {
+                show: false,
+            },
+            axisLabel: {
+                color: '#fff',
+            },
+            splitLine: {
+                show: true,
+                lineStyle: {
+                    color: 'rgba(255,255,255,0.1)',
+                    type: 'dashed',
+                },
+            },
+        },
+        yAxis: {
+            type: 'value',
+            splitLine: {
+                show: true,
+                lineStyle: {
+                    color: 'rgba(255,255,255,0.1)',
+                    type: 'dashed',
+                },
+            },
+            axisLine: {
+                show: false,
+            },
+            axisTick: {
+                show: false,
+            },
+            axisLabel: {
+                color: '#fff',
+            },
+        },
+        series: [{
+            type: 'line',
+            data: values,
+            symbol: 'circle',
+            symbolSize: 8,
+            itemStyle: {
+                color: '#fff',
+            },
+            lineStyle: {
+                color: '#4B91FF',
+                width: 2,
+            },
+            areaStyle: {
+                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: 'rgba(75,145,255,0.3)' },
+                    { offset: 1, color: 'rgba(75,145,255,0)' },
+                ]),
+            },
+        }],
+    })
+}
+
+// 监听窗口大小变化
+const handleResize = () => {
+    chart && chart.resize()
+}
+
+// 组件挂载
+onMounted(() => {
+    nextTick(() => {
+        initChart()
+        window.addEventListener('resize', handleResize)
+    })
+})
+
+// 组件卸载
+onUnmounted(() => {
+    window.removeEventListener('resize', handleResize)
+    if (chart) {
+        chart.dispose()
+        chart = null
+    }
+})
+
+// 暴露方法
+defineExpose({
+    resize: handleResize,
+})
+</script>
+
+<style lang="scss" scoped>
+.hc-line-chart-box {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    
+    .hc-line-chart-echarts {
+        width: 100%;
+        height: 100%;
+    }
+}
+</style>

+ 170 - 0
src/renderer/src/views/home2/modules/echarts/HcDatavRoundChart.vue

@@ -0,0 +1,170 @@
+<template>
+    <div class="hc-round-chart-box">
+        <div ref="echart" class="hc-round-chart-echarts" />
+    </div>
+</template>
+
+<script setup>
+import * as echarts from 'echarts'
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
+
+const props = defineProps({
+    datas: {
+        type: Object,
+        default: () => ({}),
+    },
+    config: {
+        type: Object,
+        default: () => ({
+            color: ['#5087EC', '#58A55C', '#58A55C'],
+            name: ['四环线', '二十环线', '六十环线'],
+            key: ['type1', 'type2', 'type3'],
+            label: '项目统计',
+        }),
+    },
+})
+
+// 定义事件
+const emit = defineEmits(['chartClick'])
+let chart = null
+const echart = ref(null)
+
+// 监听数据变化
+watch(() => props.datas, (newVal) => {
+    if (newVal) {
+        setDatas(newVal)
+    }
+}, { deep: true })
+
+// 初始化图表
+const initChart = () => {
+    chart = echarts.init(echart.value)
+    setDatas(props.datas)
+}
+
+// 设置数据
+const setDatas = (data) => {
+    const chartData = []
+    const { name, key } = props.config
+    
+    for (let i = 0; i < name.length; i++) {
+        chartData.push({
+            name: name[i],
+            value: data[key[i]] || 0,
+        })
+    }
+    
+    setOptions(chartData)
+}
+
+// 设置图表配置
+const setOptions = (chartData) => {
+    const { color, label } = props.config
+    chart.setOption({
+        
+        legend: {
+            top: '6',
+            data: ['四环线', '二十环线', '六十环线'],
+            textStyle: {
+                color: '#fff',
+            },
+        },
+        color: color,
+        tooltip: {
+            trigger: 'item',
+            position: 'right',
+            formatter: (params) => {
+                return `<div style="padding: 8px;">
+ <div style="margin-bottom: 4px;">运营期:<span style="font-weight: bold; font-size: 16px;">${params.value}</span></div>
+                    <div style="margin-bottom: 4px;">运营期:<span style="font-weight: bold; font-size: 16px;">${params.value}</span></div>
+                    <div>建设期:<span style="font-weight: bold; font-size: 16px;">${params.value}</span></div>
+                </div>`
+            },
+            backgroundColor: '#fff',
+            borderColor: '#E8E8E8',
+            borderWidth: 1,
+            textStyle: {
+                color: '#333',
+                fontSize: 14,
+            },
+            padding: 0,
+            borderRadius: 4,
+            extraCssText: 'box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);',
+        },
+        series: [{
+            name: label,
+            type: 'pie',
+            radius: ['40%', '70%'],
+            center: ['50%', '50%'],
+            avoidLabelOverlap: true,
+            itemStyle: {
+                borderRadius: 10,
+                borderWidth: 2,
+            },
+            labelLine: {
+                show: false,
+            },
+            label: {
+                show: false,
+            },
+            emphasis: {
+                label: {
+                    show: false,
+                    fontSize: 20,
+                    fontWeight: 'bold',
+                },
+            },
+            data: chartData,
+        }],
+    })
+
+    // 添加点击事件监听
+    chart.on('click', (params) => {
+        emit('chartClick', {
+            name: params.name,
+            value: params.value,
+            dataIndex: params.dataIndex,
+        })
+    })
+}
+
+// 监听窗口大小变化
+const handleResize = () => {
+    chart && chart.resize()
+}
+
+// 组件挂载
+onMounted(() => {
+    nextTick(() => {
+        initChart()
+        window.addEventListener('resize', handleResize)
+    })
+})
+
+// 组件卸载
+onUnmounted(() => {
+    window.removeEventListener('resize', handleResize)
+    if (chart) {
+        chart.dispose()
+        chart = null
+    }
+})
+
+// 暴露方法
+defineExpose({
+    resize: handleResize,
+})
+</script>
+
+<style lang="scss" scoped>
+.hc-round-chart-box {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    
+    .hc-round-chart-echarts {
+        width: 100%;
+        height: 100%;
+    }
+}
+</style>

+ 149 - 0
src/renderer/src/views/home2/modules/echarts/HcDatavVerticalBarChart.vue

@@ -0,0 +1,149 @@
+<template>
+    <div class="hc-bar-chart-box">
+        <div ref="echart" class="hc-bar-chart-echarts" />
+    </div>
+</template>
+
+<script setup>
+import * as echarts from 'echarts'
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
+
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => [],
+    },
+})
+
+let chart = null
+const echart = ref(null)
+
+// 监听数据变化
+watch(() => props.datas, (newVal) => {
+    if (newVal) {
+        setOptions(newVal)
+    }
+}, { deep: true })
+
+// 初始化图表
+const initChart = () => {
+    chart = echarts.init(echart.value)
+    setOptions(props.datas)
+}
+
+// 设置图表配置
+const setOptions = (chartData) => {
+    const names = chartData.map(item => item.name)
+    const values = chartData.map(item => item.value)
+    
+    chart.setOption({
+        grid: {
+            left: '3%',
+            right: '4%',
+            bottom: '3%',
+            top: '3%',
+            containLabel: true,
+        },
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'line',
+                lineStyle: {
+                    color: '#fff',
+                    type: 'solid',
+                },
+            },
+            backgroundColor: '#5087EC',
+            borderColor: 'rgba(255,255,255,0.3)',
+            textStyle: {
+                color: '#fff',
+            },
+            formatter: (params) => {
+                return `${params[0].name}<br/>数据:${params[0].value}`
+            },
+        },
+        xAxis: {
+            type: 'category',
+            data: names,
+            axisLine: {
+                show: false,
+            },
+            axisTick: {
+                show: false,
+            },
+            axisLabel: {
+                color: '#fff',
+                interval: 0,
+            },
+        },
+        yAxis: {
+            type: 'value',
+            splitLine: {
+                show: true,
+                lineStyle: {
+                    color: 'rgba(255, 255, 255, 0.1)',
+                    type: 'dashed',
+                },
+            },
+            axisLine: {
+                show: false,
+            },
+            axisTick: {
+                show: false,
+            },
+            axisLabel: {
+                color: '#fff',
+            },
+        },
+        series: [{
+            type: 'bar',
+            data: values,
+            barWidth: '30%',
+            itemStyle: {
+                color: '#5087EC',
+                borderRadius: [4, 4, 0, 0],
+            },
+        }],
+    })
+}
+
+// 监听窗口大小变化
+const handleResize = () => {
+    chart && chart.resize()
+}
+
+// 组件挂载
+onMounted(() => {
+    nextTick(() => {
+        initChart()
+        window.addEventListener('resize', handleResize)
+    })
+})
+
+// 组件卸载
+onUnmounted(() => {
+    window.removeEventListener('resize', handleResize)
+    if (chart) {
+        chart.dispose()
+        chart = null
+    }
+})
+
+// 暴露方法
+defineExpose({
+    resize: handleResize,
+})
+</script>
+
+<style lang="scss" scoped>
+.hc-bar-chart-box {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    
+    .hc-bar-chart-echarts {
+        width: 100%;
+        height: 100%;
+    }
+}
+</style>

+ 132 - 0
src/renderer/src/views/home2/modules/select.vue

@@ -0,0 +1,132 @@
+<template>
+    <div class="hc-datav-select-main">
+        <div class="hc-datav-select-name">{{ name || placeholder }}</div>
+        <el-select
+            v-model="selectKey" popper-class="hc-datav-select-popper"
+            :placeholder="placeholder" size="small" :clearable="clearable" :disabled="disabled"
+            placement="bottom-end"
+            @change="selectChange"
+        >
+            <el-option v-for="item in data" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from 'vue'
+import { isNullES } from 'js-fast-way'
+
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => [],
+    },
+    disabled: {
+        type: Boolean,
+        default: false,
+    },
+    clearable: {
+        type: Boolean,
+        default: true,
+    },
+    placeholder: {
+        type: String,
+        default: '请选择',
+    },
+})
+
+//事件
+const emit = defineEmits(['change'])
+
+//双向绑定
+const selectKey = defineModel('modelValue', {
+    default: '',
+})
+
+onMounted(() => {
+    name.value = getDataNmae(selectKey.value)
+})
+
+//监听数据变化
+const data = ref(props.datas)
+watch(() => props.datas, (val) => {
+    data.value = val
+})
+
+//监听值变化
+const name = ref('')
+watch(() => selectKey, (val) => {
+    name.value = getDataNmae(val.value)
+})
+
+//获取数据名称
+const getDataNmae = (id) => {
+    if (isNullES(id)) return props.placeholder
+    const item = data.value.find((item) => item.id === id)
+    return item ? item.name : props.placeholder
+}
+
+//下来框被改变
+const selectChange = (id) => {
+    name.value = getDataNmae(id)
+    emit('change', id)
+}
+</script>
+
+<style lang="scss">
+.hc-datav-select-main {
+    position: relative;
+    display: inline-block;
+    .hc-datav-select-name {
+        position: relative;
+        padding-left: 16px;
+        z-index: -10;
+    }
+    .el-select {
+        position: absolute;
+        top: 0;
+        width: 100%;
+        height: 100%;
+        .el-select__wrapper {
+            font-size: 14px;
+            gap: unset;
+            line-height: unset;
+            min-height: unset;
+            padding: 0;
+            height: 100%;
+            background: unset;
+            box-shadow: unset;
+            border-radius: 0;
+        }
+        .el-select__placeholder {
+            color: white;
+        }
+        .el-select__placeholder.is-transparent {
+            color: #d6d6d6;
+        }
+        .el-select__caret {
+            color: #ffffff;
+        }
+    }
+}
+.el-popper.hc-datav-select-popper {
+    background: #565656;
+    border: 1px solid #000000;
+    .el-popper__arrow:before {
+        background: #565656;
+        border-color: #000000;
+    }
+    .el-select-dropdown__item {
+        height: 28px;
+        line-height: 28px;
+        color: #34e3ff;
+        padding: 0 28px 0 14px;
+    }
+    .el-select-dropdown__item.is-hovering {
+        background-color: #395cc6;
+    }
+}
+.hc-datav-select-main + .hc-datav-select-main {
+    margin-left: 40px;
+}
+</style>

+ 167 - 0
src/renderer/src/views/project/data/addAndEdit.vue

@@ -205,6 +205,164 @@
                     </div>
                 </hc-card-item>
             </div>
+            <div class="mt-4">
+                <hc-card-item class="hac-card-item">
+                    <template #header>
+                        <div class="hac-card-title g">
+                            <div class="w-[150px]">
+                                <el-select v-model="baseForm.stage" filterable clearable block placeholder="建设期" @change="stageClick">
+                                    <el-option v-for="item in stageOptions" :key="item.value" :label="item.label" :value="item.value" />
+                                </el-select>
+                            </div>
+                            <span class="ml-2">车流量信息</span>
+                        </div>
+                    </template>
+                    <div class="cash-in-list mt-2 flex justify-between">
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>1月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key1" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>2月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key2" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="cash-in-list mt-2 flex justify-between">
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>3月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key1" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>4月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key2" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="cash-in-list mt-2 flex justify-between">
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>5月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key1" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>6月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key2" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="cash-in-list mt-2 flex justify-between">
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>7月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key1" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>8月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key2" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="cash-in-list mt-2 flex justify-between">
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>9月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key1" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>10月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key2" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="cash-in-list mt-2 flex justify-between">
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>11月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key1" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="cash-in-list-item text-sm">
+                            <div class="flex font-bold">
+                                <div>12月</div>
+                            </div>
+                            <div class="jitems-center mt-1 w-full flex justify-between">
+                                <span class="text-gray">车流量</span>
+                                <div class="ml-3 w-64 flex items-center">
+                                    <el-input v-model="stage.key2" clearable placeholder="请输入" /><span class="ml-1 font-900">辆</span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </hc-card-item>
+            </div>
         </div>
         <div class="mt-4 text-center">
             <el-button type="info" style="background-color: white; color: black; border-color: white" @click="dialogSubmit">退出</el-button>
@@ -334,6 +492,15 @@ const dialogClose = () => {
      
    }
 }
+.cash-in-list2{
+    width: 48%;
+    .cash-in-list-item{
+        padding: 10px;
+        width: 32%;
+        border: 1px solid #E6E6E6;
+     
+   }
+}
 .icon-avatar{
     width: 14px;
     height: 14px;