From d5e65bf5925c8cd1fe0f0bf0b8b857006d64ad94 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 30 一月 2026 15:26:34 +0800
Subject: [PATCH] 进销存升级 1.部分输入框(有效日期、检定周期)输入做下限制(大于0的整数数字)
---
src/views/financialManagement/accounting/index.vue | 900 +++++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 705 insertions(+), 195 deletions(-)
diff --git a/src/views/financialManagement/accounting/index.vue b/src/views/financialManagement/accounting/index.vue
index 06bf4cf..830fe1a 100644
--- a/src/views/financialManagement/accounting/index.vue
+++ b/src/views/financialManagement/accounting/index.vue
@@ -1,231 +1,741 @@
<template>
- <div class="app-container">
- <el-row :gutter="16" class="mb-16">
- <el-col :span="12">
- <el-card shadow="hover">
- <div class="section-title">缁熶竴浼氳绉戠洰浣撶郴</div>
- <el-tree
- :data="accountTree"
- node-key="code"
- :props="{ label: 'label', children: 'children' }"
- highlight-current
- default-expand-all
+ <div style="padding: 20px;">
+ <!-- 椤甸潰鏍囬鍜岀瓫閫夋潯浠� -->
+ <div class="w-full md:w-auto flex items-center gap-3">
+ <el-form :inline="true">
+ <el-form-item label="骞翠唤">
+ <el-date-picker
+ v-model="selectedYear"
+ type="year"
+ placeholder="璇烽�夋嫨骞翠唤"
+ format="YYYY"
+ value-format="YYYY"
+ clearable
+ @change="fetchData()"
+ style="width: 200px"
+ :disabled-date="(date) => date.getFullYear() > new Date().getFullYear()"
/>
- </el-card>
- </el-col>
- <el-col :span="12">
- <el-card shadow="hover">
- <div class="section-title">鍑瘉妯℃澘</div>
- <el-table :data="voucherTemplates" border size="small">
- <el-table-column prop="name" label="妯℃澘鍚嶇О" min-width="140" />
- <el-table-column prop="bizScene" label="涓氬姟鍦烘櫙" min-width="140" />
- <el-table-column prop="debit" label="鍊熸柟绉戠洰" min-width="160" />
- <el-table-column prop="credit" label="璐锋柟绉戠洰" min-width="160" />
- <el-table-column prop="auxDims" label="杈呭姪鏍哥畻缁村害" min-width="180">
- <template #default="scope">
- <el-space wrap>
- <el-tag v-for="dim in scope.row.auxDims" :key="dim" size="small" type="info">{{ dim }}</el-tag>
- </el-space>
- </template>
- </el-table-column>
- </el-table>
- </el-card>
- </el-col>
- </el-row>
+ </el-form-item>
+ <el-form-item>
+ <el-button
+ type="primary"
+ icon="Refresh"
+ @click="resetFilters"
+ size="default"
+ >
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
- <el-row :gutter="16" class="mb-16">
- <el-col :span="12">
- <el-card shadow="hover">
- <div class="section-title">涓氬姟娴佺▼ 鈫� 鍑瘉鑷姩鐢熸垚</div>
- <div class="toolbar">
- <el-text type="info">婕旂ず鏁版嵁浠呯敤浜庡睍绀虹粨鏋勪笌瀛楁</el-text>
+ <main class="container mx-auto px-4 pb-10">
+ <!-- 鍥哄畾璧勪骇鎸囨爣鍗$墖 -->
+ <div class="kpi-grid">
+ <!-- 璁惧鎬绘暟 -->
+ <div class="kpi-card">
+ <div class="kpi-left">
+ <span class="kpi-dot kpi-dot-blue"></span>
+ <span class="kpi-title">璁惧鎬绘暟</span>
+ <div class="kpi-value">{{ assetInfo.totalEquipment }}涓�</div>
</div>
- <el-table :data="generatedVouchers" border size="small">
- <el-table-column prop="date" label="鏃ユ湡" width="110" />
- <el-table-column prop="bizScene" label="涓氬姟鍦烘櫙" min-width="120" />
- <el-table-column prop="summary" label="鎽樿" min-width="160" />
- <el-table-column prop="amount" label="閲戦(楼)" width="110" />
- <el-table-column prop="status" label="鐘舵��" width="100">
- <template #default="scope">
- <el-tag :type="scope.row.status === '宸茬敓鎴�' ? 'success' : 'warning'">{{ scope.row.status }}</el-tag>
- </template>
- </el-table-column>
- </el-table>
- </el-card>
- </el-col>
- <el-col :span="12">
- <el-card shadow="hover">
- <div class="section-title">澶氱淮杈呭姪鏍哥畻</div>
- <div class="dims">
- <el-tag type="success">瀹㈡埛</el-tag>
- <el-tag type="warning">椤圭洰</el-tag>
- <el-tag type="info">閮ㄩ棬</el-tag>
- <el-tag type="primary">绠$悊鍛�</el-tag>
+ <div class="kpi-icon-wrap kpi-icon-blue">
+ <img :src="iconBlue" alt="" class="kpi-icon" />
</div>
- <el-table :data="auxSummary" size="small" border>
- <el-table-column prop="dimension" label="缁村害" width="100" />
- <el-table-column prop="category" label="绫诲埆" min-width="140" />
- <el-table-column prop="debit" label="鍊熸柟(鏈湡)" width="110" />
- <el-table-column prop="credit" label="璐锋柟(鏈湡)" width="110" />
- <el-table-column prop="balance" label="浣欓" width="100" />
- </el-table>
- </el-card>
- </el-col>
- </el-row>
+ </div>
- <el-row :gutter="16" class="mb-16">
- <el-col :span="12">
- <el-card shadow="hover">
- <div class="section-title">缁撹处浠诲姟锛堟湀/瀛�/骞达級</div>
- <div class="toolbar">
- <el-space>
- <el-button size="small" @click="runClose('鏈堢粨')">鎵ц鏈堢粨</el-button>
- <el-button size="small" @click="runClose('瀛f姤')">鎵ц瀛f姤</el-button>
- <el-button size="small" @click="runClose('骞村害缁撹处')">鎵ц骞村害缁撹处</el-button>
- </el-space>
+ <!-- 璧勪骇鍘熷�� -->
+ <div class="kpi-card">
+ <div class="kpi-left">
+ <span class="kpi-dot kpi-dot-orange"></span>
+ <span class="kpi-title">璧勪骇鍘熷��</span>
+ <div class="kpi-value">楼{{ formatCurrency(assetInfo.totalOriginalValue) }}</div>
</div>
- <el-timeline style="margin-top: 6px;">
- <el-timeline-item
- v-for="item in closingTasks"
- :key="item.id"
- :type="item.type"
- :timestamp="item.time"
- placement="top"
- >
- <div class="close-item">
- <div class="title">{{ item.name }}</div>
- <el-tag :type="item.status === '瀹屾垚' ? 'success' : 'info'" size="small">{{ item.status }}</el-tag>
+ <div class="kpi-icon-wrap kpi-icon-orange">
+ <img :src="iconWalletOrange" alt="" class="kpi-icon" />
+ </div>
+ </div>
+
+ <!-- 绱鎶樻棫 -->
+ <div class="kpi-card">
+ <div class="kpi-left">
+ <span class="kpi-dot kpi-dot-green"></span>
+ <span class="kpi-title">绱鎶樻棫</span>
+ <div class="kpi-value">楼{{ formatCurrency(assetInfo.totalDepreciation) }}</div>
+ </div>
+ <div class="kpi-icon-wrap kpi-icon-green">
+ <img :src="iconGreen" alt="" class="kpi-icon" />
+ </div>
+ </div>
+
+ <!-- 搴撳瓨璧勪骇 -->
+ <div class="kpi-card">
+ <div class="kpi-left">
+ <span class="kpi-dot kpi-dot-pink"></span>
+ <span class="kpi-title">搴撳瓨璧勪骇</span>
+ <div class="kpi-value">楼{{ formatCurrency(assetInfo.inventoryValue) }}</div>
+ </div>
+ <div class="kpi-icon-wrap kpi-icon-pink">
+ <img :src="iconPink" alt="" class="kpi-icon" />
+ </div>
+ </div>
+
+ <!-- 鍑�鍊� -->
+ <div class="kpi-card">
+ <div class="kpi-left">
+ <span class="kpi-dot kpi-dot-yellow"></span>
+ <span class="kpi-title">鍑�鍊�</span>
+ <div class="kpi-value">楼{{ formatCurrency(assetInfo.totalNetValue) }}</div>
+ </div>
+ <div class="kpi-icon-wrap kpi-icon-yellow">
+ <img :src="iconYellow" alt="" class="kpi-icon" />
+ </div>
+ </div>
+
+ <!-- 璐熷�� -->
+ <div class="kpi-card">
+ <div class="kpi-left">
+ <span class="kpi-dot kpi-dot-red"></span>
+ <span class="kpi-title">璐熷��</span>
+ <div class="kpi-value">楼{{ formatCurrency(assetInfo.debt) }}</div>
+ </div>
+ <div class="kpi-icon-wrap kpi-icon-red">
+ <img :src="iconWalletRed" alt="" class="kpi-icon" />
+ </div>
+ </div>
+ </div>
+
+ <!-- 鍥哄畾璧勪骇缁熻鍥捐〃 -->
+ <div class="chart-row">
+ <!-- 璁惧绫诲瀷鍒嗗竷 -->
+ <el-card class="chart-card">
+ <h2 class="section-title">璁惧绫诲瀷鍒嗗竷</h2>
+ <div class="chart-content">
+ <div class="pie-wrap">
+ <Echarts
+ :legend="typeDistributionLegend"
+ :chartStyle="chartStylePie"
+ :series="typeDistributionSeries"
+ :tooltip="pieTooltip"
+ style="height: 260px; width: 100%;"
+ />
+ </div>
+ <div class="type-cards">
+ <div class="type-card" v-for="(item, index) in typeDistributionData" :key="index">
+ <span class="type-name">{{ item.name }}</span>
+ <span class="type-count">{{ item.count }}</span>
</div>
- </el-timeline-item>
- </el-timeline>
+ </div>
+ </div>
</el-card>
- </el-col>
- <el-col :span="12">
- <el-card shadow="hover">
- <div class="section-title">瀹¤鐣欑棔涓庡鎵规潈闄�</div>
- <el-table :data="auditTrail" border size="small">
- <el-table-column prop="time" label="鏃堕棿" width="160" />
- <el-table-column prop="action" label="鍔ㄤ綔" min-width="160" />
- <el-table-column prop="bizScene" label="鍏宠仈涓氬姟" min-width="140" />
- <el-table-column prop="role" label="鎵ц瑙掕壊" width="120" />
- <el-table-column prop="result" label="缁撴灉" width="100">
- <template #default="scope">
- <el-tag :type="scope.row.result === '閫氳繃' ? 'success' : (scope.row.result === '椹冲洖' ? 'danger' : 'info')">
- {{ scope.row.result }}
- </el-tag>
- </template>
- </el-table-column>
- </el-table>
+ <!-- 璁惧閲戦鍒嗘瀽 -->
+ <el-card class="chart-card">
+ <h2 class="section-title">璁惧閲戦鍒嗘瀽</h2>
+ <div class="bar-chart-wrap">
+ <Echarts
+ ref="barChart"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="lineLegend"
+ :series="typeDistributionBarSeries"
+ :tooltip="tooltip"
+ :xAxis="xAxis"
+ :yAxis="yAxisBar"
+ style="height: 260px; width: 100%;"
+ />
+ </div>
</el-card>
- </el-col>
- </el-row>
+ </div>
+ <!-- 璁惧鏁版嵁琛� -->
+ <el-card class="table-card">
+ <h2 class="section-title">璁惧鏁版嵁琛�</h2>
+ <el-table
+ :data="equipmentList"
+ stripe
+ style="width: 100%"
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
+ >
+ <el-table-column type="index" label="搴忓彿" width="60" :index="(index) => (pagination.currentPage - 1) * pagination.pageSize + index + 1" />
+ <el-table-column prop="deviceName" label="璁惧鍚嶇О" width="250" />
+ <el-table-column prop="deviceModel" label="瑙勬牸鍨嬪彿" min-width="150" />
+ <el-table-column prop="supplierName" label="渚涘簲鍟�" min-width="120" />
+ <el-table-column prop="unit" label="鍗曚綅" width="120" />
+ <el-table-column prop="number" label="鏁伴噺" width="120" />
+ <el-table-column prop="originalValue" label="鍘熷��(鍏�)" width="120">
+ <template #default="{ row }">
+ {{ formatCurrency(row.taxIncludingPriceTotal) }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="depreciation" label="绱鎶樻棫(鍏�)" width="140">
+ <template #default="{ row }">
+ {{ formatCurrency(row.deprAmount) }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="netValue" label="鍑�鍊�(鍏�)" width="120">
+ <template #default="{ row }">
+ {{ formatCurrency(row.netValue) }}
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <div class="pagination-container">
+ <el-pagination
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ :current-page="pagination.currentPage"
+ :page-sizes="[10, 20, 50, 100]"
+ :page-size="pagination.pageSize"
+ layout="total, sizes, prev, pager, next, jumper"
+ :total="pagination.total"
+ />
+ </div>
+ </el-card>
+ </main>
+
</div>
-
</template>
<script setup>
-import { ref } from 'vue'
+import { ref, computed, onMounted, reactive } from 'vue';
+import 'element-plus/dist/index.css';
+import Echarts from "@/components/Echarts/echarts.vue";
+import { getAccountingTotal, getDeviceTypeDistribution, getCalculateDepreciation } from "@/api/financialManagement/accounting";
+import dayjs from "dayjs";
+import iconBlue from '@/assets/icons/png/blue@2x.png';
+import iconWalletOrange from '@/assets/icons/png/walletOrange@2x.png';
+import iconGreen from '@/assets/icons/png/green@2x.png';
+import iconPink from '@/assets/icons/png/pink@2x.png';
+import iconYellow from '@/assets/icons/png/yellow@2x.png';
+import iconWalletRed from '@/assets/icons/png/walletRed@2x.png';
-// 绉戠洰鏍戯紙绀轰緥锛�
-const accountTree = ref([
- { code: '1001', label: '璧勪骇', children: [
- { code: '100101', label: '搴撳瓨鐜伴噾' },
- { code: '100102', label: '閾惰瀛樻' },
- { code: '1122', label: '搴旀敹璐︽' },
- { code: '1601', label: '鍥哄畾璧勪骇' },
- ]},
- { code: '2001', label: '璐熷��', children: [
- { code: '2202', label: '搴斾粯璐︽' },
- { code: '2241', label: '鍏朵粬搴斾粯娆�' },
- ]},
- { code: '3001', label: '鎵�鏈夎�呮潈鐩�', children: [
- { code: '3103', label: '鏈勾鍒╂鼎' },
- ]},
- { code: '4001', label: '鎴愭湰璐圭敤', children: [
- { code: '5601', label: '鍒堕�犺垂鐢�' },
- { code: '6602', label: '绠$悊璐圭敤' },
- ]},
-])
+// 绛涢�夋潯浠�
+const dateRange = ref(null);
+const equipmentType = ref('');
+const selectedYear = ref(dayjs().format('YYYY')); // 榛樿褰撳墠骞翠唤
-// 鍑瘉妯℃澘锛堢ず渚嬶級
-const voucherTemplates = ref([
- { name: '閿�鍞敹鍏ョ‘璁�', bizScene: '閿�鍞嚭搴�', debit: '1122 搴旀敹璐︽', credit: '6001 涓昏惀涓氬姟鏀跺叆', auxDims: ['瀹㈡埛','椤圭洰'] },
- { name: '閲囪喘搴斾粯纭', bizScene: '閲囪喘鍏ュ簱', debit: '1403 鍦ㄩ�旂墿璧�', credit: '2202 搴斾粯璐︽', auxDims: ['椤圭洰','閮ㄩ棬'] },
- { name: '璐圭敤鎶ラ攢', bizScene: '璐圭敤鍗�', debit: '6602 绠$悊璐圭敤', credit: '1002 閾惰瀛樻', auxDims: ['閮ㄩ棬'] },
- { name: '鍥哄畾璧勪骇鎶樻棫', bizScene: '鏈堟湯鎶樻棫', debit: '6602 绠$悊璐圭敤', credit: '1602 绱鎶樻棫', auxDims: ['閮ㄩ棬'] },
-])
-// 鑷姩鐢熸垚鐨勫嚟璇侊紙绀轰緥锛�
-const generatedVouchers = ref([
- { date: '2025-10-01', bizScene: '閿�鍞嚭搴�', summary: '纭搴旀敹涓庢敹鍏�', amount: 128000, status: '宸茬敓鎴�' },
- { date: '2025-10-03', bizScene: '閲囪喘鍏ュ簱', summary: '纭鍒拌揣搴斾粯', amount: 56000, status: '宸茬敓鎴�' },
- { date: '2025-10-05', bizScene: '璐圭敤鍗�', summary: '鍔炲叕璐圭敤鎶ラ攢', amount: 3200, status: '宸茬敓鎴�' },
-])
+// 鍥哄畾璧勪骇淇℃伅
+const assetInfo = ref({
+ totalEquipment: 0, // deviceTotal
+ totalOriginalValue: 0, // deviceAmount
+ totalDepreciation: 0, // deprAmount
+ totalNetValue: 0, // netValue
+ debt: 0, // 璐熷��
+ inventoryValue: 0 // 搴撳瓨璧勪骇
+});
-// 鏃犳ā鎷熺敓鎴愭搷浣滐紝浠呭睍绀洪潤鎬佺ず渚嬫暟鎹�
+// 璁惧绫诲瀷鎬绘暟锛堢敤浜庡浘琛ㄦ樉绀猴級
+const deviceTypeTotalCount = ref(0);
-// 杈呭姪鏍哥畻绀轰緥姹囨�伙紙鏃犱釜浜哄鍚嶏紝浠呯淮搴︾被鍒級
-const auxSummary = ref([
- { dimension: '瀹㈡埛', category: '閲嶇偣瀹㈡埛闆嗗悎', debit: 320000, credit: 210000, balance: 110000 },
- { dimension: '椤圭洰', category: '椤圭洰A', debit: 150000, credit: 120000, balance: 30000 },
- { dimension: '閮ㄩ棬', category: '杩愯惀涓績', debit: 42000, credit: 18000, balance: 24000 },
- { dimension: '绠$悊鍛�', category: '绯荤粺瑙掕壊', debit: 0, credit: 0, balance: 0 },
-])
+// 璁惧鍒楄〃
+const equipmentList = ref([]);
+const pagination = ref({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0
+});
-// 缁撹处浠诲姟
-const closingTasks = ref([
- { id: 1, name: '2025骞�10鏈� 鏈堢粨', time: '2025-10-31 18:00', status: '瀹屾垚', type: 'success' },
- { id: 2, name: '2025骞碤4 瀛f姤', time: '2025-12-31 18:00', status: '璁″垝', type: 'info' },
- { id: 3, name: '2025骞村害 骞村害缁撹处', time: '2025-12-31 23:00', status: '璁″垝', type: 'info' },
-])
+// 鍥捐〃閰嶇疆
+const chartStyle = {
+ width: '100%',
+ height: '100%',
+ position: 'relative',
+};
-function runClose(kind) {
- closingTasks.value.unshift({
- id: Date.now(),
- name: `${new Date().getFullYear()}骞�${kind}`,
- time: new Date().toISOString().replace('T',' ').slice(0,16),
- status: '瀹屾垚',
- type: 'success',
- })
-}
+const grid = {
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ containLabel: true
+};
-// 瀹¤鐣欑棔锛堜笉鍚釜浜哄鍚嶏紝浠呰鑹�/鏈哄埗锛�
-const auditTrail = ref([
- { time: '2025-10-01 09:12', action: '閿�鍞嚭搴撹Е鍙戝嚟璇佺敓鎴�', bizScene: '閿�鍞嚭搴�', role: '绯荤粺鑷姩鍖�', result: '閫氳繃' },
- { time: '2025-10-03 14:20', action: '閲囪喘鍏ュ簱瑙﹀彂搴斾粯纭', bizScene: '閲囪喘鍏ュ簱', role: '绯荤粺鑷姩鍖�', result: '閫氳繃' },
- { time: '2025-10-05 10:03', action: '璐圭敤鍗曞鎵�', bizScene: '璐圭敤鍗�', role: '璐㈠姟瀹℃壒', result: '閫氳繃' },
- { time: '2025-10-08 16:45', action: '鍑瘉杩囪处', bizScene: '鎬昏处', role: '浼氳瀹℃牳', result: '閫氳繃' },
- { time: '2025-10-31 18:05', action: '鏈堢粨瀹屾垚骞堕攣璐�', bizScene: '鎬昏处', role: '绯荤粺鑷姩鍖�', result: '閫氳繃' },
-])
+const lineLegend = {
+ show: false,
+};
+
+// 鎶樼嚎鍥炬彁绀烘
+const tooltip = reactive({
+ trigger: 'axis',
+ axisPointer: {
+ type: 'line',
+ lineStyle: { color: '#aaa' }
+ },
+ // 鑷畾涔夊唴瀹�
+ formatter: function (params) {
+ if (!params || !params.length) return '';
+ const axisLabel = params[0].axisValueLabel || params[0].axisValue || '';
+ const rows = params
+ .map(p => {
+ const colorDot = `<span style="display:inline-block;margin-right:6px;width:8px;height:8px;border-radius:50%;background:${p.color}"></span>`;
+ return `${colorDot}${p.seriesName}: ${p.value}`;
+ })
+ .join('<br/>');
+ return `<div>${axisLabel}</div><div>${rows}</div>`;
+ }
+});
+
+const xAxis = ref([
+ {
+ type: 'category',
+ axisTick: { show: true, alignWithLabel: true },
+ data: [],
+ },
+]);
+
+const yAxis = [
+ {
+ type: 'value',
+ name: '鏁伴噺/閲戦', // 宸︿晶y杞�
+ position: 'left',
+ min: 0,
+ // 鍧愭爣杞村悕绉版牱寮�
+ nameTextStyle: {
+ color: '#000',
+ fontSize: 14,
+ },
+ }
+];
+
+const chartStylePie = {
+ width: '100%',
+ height: '100%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+};
+
+const pieColors = ['#165DFF', '#14C9C9', '#8543E0', '#1890FF', '#13C2C2', '#2FC25B']; // 鍙牴鎹疄闄呰皟鏁�
+
+// 楗煎浘鏁版嵁
+const typeDistributionData = ref([]);
+const departmentDistributionData = ref([]);
+
+// 楗煎浘鍥句緥锛堟偓鍋滄樉绀哄悕绉�+鍗犳瘮锛屽浘渚嬫斁涓嬫柟鍗$墖灞曠ず锛�
+const typeDistributionLegend = computed(() => ({
+ show: false,
+ data: typeDistributionData.value.map(item => item.name)
+}));
+
+
+// 楗煎浘绯诲垪
+const typeDistributionSeries = computed(() => [
+ {
+ type: 'pie',
+ radius: ['0%', '65%'],
+ center: ['50%', '45%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: { show: false },
+ data: typeDistributionData.value,
+ color: pieColors
+ }
+]);
+
+// 鎶樼嚎鍥炬暟鎹�
+const typeDistributionLineSeries = ref([]);
+// 鏌辩姸鍥炬暟鎹紙璁惧閲戦鍒嗘瀽锛�
+const typeDistributionBarSeries = computed(() => [
+ {
+ name: '閿�鍞',
+ type: 'bar',
+ data: typeDistributionData.value.map(item => (item.amountNum != null ? item.amountNum : 0)),
+ itemStyle: { color: '#13C2C2' }
+ }
+]);
+// 鏌辩姸鍥� Y 杞�
+const yAxisBar = [
+ {
+ type: 'value',
+ name: '閿�鍞(涓囧厓)',
+ position: 'left',
+ min: 0,
+ nameTextStyle: { color: '#000', fontSize: 14 },
+ splitLine: { lineStyle: { color: '#f0f0f0' } }
+ }
+];
+
+
+// 楗煎浘鎻愮ず妗嗭紙鍥惧唴鏍峰紡锛氬悕绉� + 鍗犳瘮锛�
+const pieTooltip = reactive({
+ trigger: 'item',
+ formatter: function(params) {
+ if (!params.data) return params.name;
+ const pct = params.percent != null ? params.percent.toFixed(0) : 0;
+ return `${params.name} ${pct}%`;
+ }
+});
+
+// 閫夐」鏁版嵁
+const equipmentTypeOptions = ref([]);
+
+// 鑾峰彇鏁版嵁
+const fetchData = async () => {
+ try {
+ // 鑾峰彇鍥哄畾璧勪骇姹囨�讳俊鎭�
+ const assetInfoRes = await getAccountingTotal({
+ startDate: dateRange.value ? dateRange.value[0] : null,
+ endDate: dateRange.value ? dateRange.value[1] : null,
+ equipmentType: equipmentType.value,
+ year: selectedYear.value
+ });
+
+ if (assetInfoRes.code === 200) {
+ // 鏄犲皠鍚庣瀛楁鍒板墠绔瓧娈�
+ const data = assetInfoRes.data;
+ assetInfo.value = {
+ totalEquipment: data.deviceTotal || 0, // 璁惧鎬绘暟
+ totalOriginalValue: data.deviceAmount || 0, // 璧勪骇鍘熷��
+ totalDepreciation: data.deprAmount || 0, // 绱鎶樻棫
+ totalNetValue: data.netValue || 0, // 鍑�鍊�
+ debt: data.debt || 0, // 璐熷��
+ inventoryValue: data.inventoryValue || 0 // 搴撳瓨璧勪骇
+ };
+ }
+
+ // 鑾峰彇璁惧绫诲瀷鍒嗗竷鏁版嵁锛堥ゼ鍥惧拰鎶樼嚎鍥撅級
+ const distributionRes = await getDeviceTypeDistribution({
+ startDate: dateRange.value ? dateRange.value[0] : null,
+ endDate: dateRange.value ? dateRange.value[1] : null,
+ equipmentType: equipmentType.value,
+ year: selectedYear.value
+ });
+
+ if (distributionRes.code === 200) {
+ const data = distributionRes.data;
+
+ // 鏇存柊璁惧绫诲瀷鎬绘暟
+ deviceTypeTotalCount.value = data.totalCount || 0;
+
+ // 杞崲楗煎浘鏁版嵁鏍煎紡
+ if (data.details && data.details.length > 0) {
+ typeDistributionData.value = data.details.map(item => ({
+ name: item.type || '',
+ value: Number(item.count || 0),
+ count: Number(item.count || 0),
+ amount: `楼${formatCurrency(item.amount || 0)}`,
+ amountNum: Number(item.amount || 0)
+ }));
+ } else if (data.categories && data.categories.length > 0) {
+ // 濡傛灉娌℃湁 details锛屼娇鐢� categories銆乧ountData 鍜� amountData 鏋勫缓
+ typeDistributionData.value = data.categories.map((category, index) => ({
+ name: category,
+ value: Number(data.countData[index] || 0),
+ count: Number(data.countData[index] || 0),
+ amount: `楼${formatCurrency(data.amountData[index] || 0)}`,
+ amountNum: Number(data.amountData[index] || 0)
+ }));
+ } else {
+ typeDistributionData.value = [];
+ }
+
+ // 鏇存柊x杞存暟鎹�
+ xAxis.value[0].data = data.categories || typeDistributionData.value.map(item => item.name);
+
+ // 鏋勫缓鎶樼嚎鍥炬暟鎹�
+ typeDistributionLineSeries.value = [
+ {
+ name: '璁惧鏁伴噺',
+ type: 'line',
+ data: data.countData || typeDistributionData.value.map(item => item.count)
+ }
+ ];
+ }
+
+ // 鑾峰彇璁惧鍒楄〃锛堟姌鏃ц绠楁暟鎹級
+ const equipmentListRes = await getCalculateDepreciation({
+ current: pagination.value.currentPage,
+ size: pagination.value.pageSize,
+ startDate: dateRange.value ? dateRange.value[0] : null,
+ endDate: dateRange.value ? dateRange.value[1] : null,
+ equipmentType: equipmentType.value,
+ year: selectedYear.value
+ });
+
+ if (equipmentListRes.code === 200) {
+ // 濡傛灉杩斿洖鐨勬槸鍒嗛〉鏁版嵁
+ if (equipmentListRes.data.records) {
+ equipmentList.value = equipmentListRes.data.records;
+ pagination.value.total = equipmentListRes.data.total;
+ } else if (Array.isArray(equipmentListRes.data)) {
+ // 濡傛灉杩斿洖鐨勬槸鏁扮粍
+ equipmentList.value = equipmentListRes.data;
+ pagination.value.total = equipmentListRes.data.length;
+ } else {
+ equipmentList.value = [];
+ pagination.value.total = 0;
+ }
+ }
+ } catch (error) {
+ console.error('鑾峰彇鍥哄畾璧勪骇鏁版嵁澶辫触锛�', error);
+ }
+};
+
+// 鍒濆鍖�
+onMounted(() => {
+ // 鑾峰彇鍒楄〃鏁版嵁
+ fetchData();
+});
+
+// 鏍煎紡鍖栬揣甯�
+const formatCurrency = (value) => {
+ if (!value) return '0.00';
+ return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+};
+
+// 鑾峰彇鐘舵�佹爣绛剧被鍨�
+const getStatusTagType = (status) => {
+ switch (status) {
+ case '鍦ㄧ敤':
+ return 'success';
+ case '闂茬疆':
+ return 'info';
+ case '缁翠慨涓�':
+ return 'warning';
+ case '鎶ュ簾':
+ return 'danger';
+ default:
+ return 'info';
+ }
+};
+
+// 閲嶇疆绛涢�夋潯浠�
+const resetFilters = () => {
+ dateRange.value = null;
+ equipmentType.value = '';
+ selectedYear.value = dayjs().format('YYYY'); // 閲嶇疆涓哄綋鍓嶅勾浠�
+ fetchData();
+};
+
+// 鍒嗛〉澶勭悊
+const handleSizeChange = (size) => {
+ pagination.value.pageSize = size;
+ fetchData();
+};
+
+const handleCurrentChange = (page) => {
+ pagination.value.currentPage = page;
+ fetchData();
+};
</script>
<style scoped lang="scss">
-.app-container {
- padding: 16px;
+:root {
+ --el-color-primary: #1890ff;
}
-.page-header {
- margin-bottom: 12px;
- h2 { margin: 0 0 6px 0; font-weight: 600; }
- p { margin: 0; color: #666; }
+
+/* 椤甸潰鑳屾櫙 */
+main {
+ background: #f5f5f5;
+ padding: 0;
+ margin: 0 -20px;
+ padding: 0 20px 20px;
}
+
+/* KPI 鍗$墖缃戞牸 */
+.kpi-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+ margin-bottom: 20px;
+}
+
+@media (max-width: 1024px) {
+ .kpi-grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+@media (max-width: 640px) {
+ .kpi-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* KPI 鍗$墖 - 鐧藉簳銆佸渾瑙掋�侀槾褰� */
+.kpi-card {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: #fff;
+ border-radius: 8px;
+ padding: 16px 20px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+ min-height: 100px;
+}
+
+.kpi-left {
+ flex: 1;
+ min-width: 0;
+}
+
+.kpi-dot {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ margin-right: 6px;
+ vertical-align: middle;
+}
+
+.kpi-dot-blue { background: #1890ff; }
+.kpi-dot-orange { background: #fa8c16; }
+.kpi-dot-green { background: #52c41a; }
+.kpi-dot-pink { background: #eb2f96; }
+.kpi-dot-yellow { background: #facc14; }
+.kpi-dot-red { background: #f5222d; }
+
+.kpi-title {
+ font-size: 14px;
+ color: #333;
+ vertical-align: middle;
+}
+
+.kpi-value {
+ font-size: 24px;
+ font-weight: 600;
+ color: #333;
+ margin-top: 8px;
+ line-height: 1.2;
+}
+
+/* 鍙充晶鍥炬爣鏂瑰潡 */
+.kpi-icon-wrap {
+ width: 48px;
+ height: 48px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+}
+
+.kpi-icon-blue { background: #e6f7ff; }
+.kpi-icon-orange { background: #fff7e6; }
+.kpi-icon-green { background: #f6ffed; }
+.kpi-icon-pink { background: #fff0f6; }
+.kpi-icon-yellow { background: #fffbe6; }
+.kpi-icon-red { background: #fff1f0; }
+
+.kpi-icon {
+ width: 28px;
+ height: 28px;
+ object-fit: contain;
+}
+
+/* 鍥捐〃鍖哄煙涓ゅ垪 */
+.chart-row {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+ margin-bottom: 20px;
+}
+
+@media (max-width: 1024px) {
+ .chart-row {
+ grid-template-columns: 1fr;
+ }
+}
+
+.chart-card {
+ border-radius: 8px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+
+ :deep(.el-card__body) {
+ padding: 16px 20px;
+ }
+}
+
+.chart-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.pie-wrap {
+ position: relative;
+ width: 100%;
+ height: 260px;
+}
+
+.type-cards {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ justify-content: center;
+ margin-top: 12px;
+}
+
+.type-card {
+ background: #fafafa;
+ border-radius: 6px;
+ padding: 8px 16px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-width: 80px;
+}
+
+.type-name {
+ font-size: 12px;
+ color: #666;
+}
+
+.type-count {
+ font-size: 16px;
+ font-weight: 600;
+ color: #333;
+ margin-top: 4px;
+}
+
+.bar-chart-wrap {
+ width: 100%;
+ height: 260px;
+}
+
+/* 鍖哄潡鏍囬 - 宸︿晶钃濊壊绔栫嚎 */
.section-title {
position: relative;
- padding-left: 10px;
- margin-bottom: 10px;
+ font-size: 18px;
+ color: #333;
+ padding-left: 12px;
+ margin-bottom: 16px;
font-weight: 700;
}
+
.section-title::before {
- content: '';
position: absolute;
- left: 0; top: 0.2em;
- width: 4px; height: 1.2em;
- background: #002FA7;
+ left: 0;
+ top: 2px;
+ content: '';
+ width: 4px;
+ height: 18px;
+ background: #1890ff;
border-radius: 2px;
}
-.mb-16 { margin-bottom: 16px; }
-.toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
-.dims { display: flex; gap: 8px; margin-bottom: 10px; }
-.close-item { display: flex; align-items: center; gap: 8px; }
+
+/* 琛ㄦ牸鍗$墖 */
+.table-card {
+ border-radius: 8px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+
+ :deep(.el-card__body) {
+ padding: 16px 20px;
+ }
+}
+
+.pagination-container {
+ margin-top: 20px;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+}
+
+:deep(.el-pagination) {
+ --el-pagination-button-bg-color: #fff;
+}
+
+:deep(.el-pager li.is-active) {
+ background: #1890ff;
+}
</style>
-
-
--
Gitblit v1.9.3