| | |
| | | <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 |
| | | /> |
| | | </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> |
| | | <div style="padding: 20px;"> |
| | | <!-- 页颿 é¢åç鿡件 --> |
| | | <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;"> |
| | | <el-button |
| | | type="primary" |
| | | icon="Refresh" |
| | | @click="resetFilters" |
| | | size="default" |
| | | > |
| | | æ¥è¯¢ |
| | | </el-button> |
| | | </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> |
| | | </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> |
| | | <main class="container mx-auto px-4 pb-10"> |
| | | <!-- åºå®èµäº§ææ å¡ç --> |
| | | <div class="grid-container"> |
| | | <!-- è®¾å¤æ»æ° --> |
| | | <el-card class="bg2"> |
| | | <p>è®¾å¤æ»æ°</p> |
| | | <h3> |
| | | {{ assetInfo.totalEquipment }} |
| | | </h3> |
| | | </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> |
| | | <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> |
| | | |
| | | <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('壿¥')">æ§è¡å£æ¥</el-button> |
| | | <el-button size="small" @click="runClose('年度ç»è´¦')">æ§è¡å¹´åº¦ç»è´¦</el-button> |
| | | </el-space> |
| | | </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> |
| | | <!-- èµäº§åå¼ --> |
| | | <el-card class="bg3"> |
| | | <p>èµäº§åå¼</p> |
| | | <h3> |
| | | ¥{{ assetInfo.totalOriginalValue }} |
| | | </h3> |
| | | </el-card> |
| | | |
| | | <!-- ç´¯è®¡ææ§ --> |
| | | <el-card class="bg4"> |
| | | <p>ç´¯è®¡ææ§</p> |
| | | <h3> |
| | | ¥{{ assetInfo.totalDepreciation }} |
| | | </h3> |
| | | </el-card> |
| | | |
| | | <!-- åå¼ --> |
| | | <el-card class="bg5"> |
| | | <p>åå¼</p> |
| | | <h3> |
| | | ¥{{ assetInfo.totalNetValue }} |
| | | </h3> |
| | | </el-card> |
| | | </div> |
| | | |
| | | <!-- åºå®èµäº§ç»è®¡å¾è¡¨ --> |
| | | <div class="grid-layout"> |
| | | <!-- æè®¾å¤ç±»åç»è®¡ --> |
| | | <el-card style="margin-bottom: 20px;"> |
| | | <h2 class="section-title">设å¤ç±»ååå¸</h2> |
| | | <div class="echarts"> |
| | | <Echarts |
| | | :legend="typeDistributionLegend" |
| | | :chartStyle="chartStylePie" |
| | | :series="typeDistributionSeries" |
| | | :tooltip="pieTooltip" |
| | | style="height: 260px; width: 35%;"> |
| | | <div class="chart-num"> |
| | | <span style="font-size: 22px;">设å¤ç±»å</span> |
| | | <span style="font-size: 36px; font-weight: 500; font-family: 'MyCustomFont', sans-serif;">{{ assetInfo.totalEquipment }}</span> |
| | | </div> |
| | | </el-timeline-item> |
| | | </el-timeline> |
| | | </Echarts> |
| | | <Echarts |
| | | ref="chart" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="lineLegend" |
| | | :series="typeDistributionLineSeries" |
| | | :tooltip="tooltip" |
| | | :xAxis="xAxis" |
| | | :yAxis="yAxis" |
| | | style="height: 260px; width: 64%;"></Echarts> |
| | | </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> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <!-- 设å¤å°è´¦è¡¨æ ¼ --> |
| | | <el-card style="margin-bottom: 20px;"> |
| | | <el-table |
| | | :data="equipmentList" |
| | | stripe |
| | | style="width: 100%" |
| | | :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" |
| | | > |
| | | <el-table-column prop="id" label="èµäº§ç¼å·" width="120" /> |
| | | <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.taxIncludingPriceTotal-row.unTaxIncludingPriceTotal) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="netValue" label="åå¼(å
)" width="120"> |
| | | <template #default="{ row }"> |
| | | ¥{{ formatCurrency(row.unTaxIncludingPriceTotal) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="ç¶æ" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag |
| | | :type="getStatusTagType(row.status)" |
| | | size="small" |
| | | > |
| | | {{ row.status }} |
| | | </el-tag> |
| | | </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 { getLedgerPage, getAssetInfo } from "@/api/equipmentManagement/ledger"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | // ç§ç®æ ï¼ç¤ºä¾ï¼ |
| | | 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 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, |
| | | totalOriginalValue: 0, |
| | | totalDepreciation: 0, |
| | | totalNetValue: 0 |
| | | }); |
| | | |
| | | // æ æ¨¡æçææä½ï¼ä»
å±ç¤ºéæç¤ºä¾æ°æ® |
| | | // 设å¤å表 |
| | | const equipmentList = ref([]); |
| | | const pagination = ref({ |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 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 chartStyle = { |
| | | width: '100%', |
| | | height: '100%', |
| | | position: 'relative', |
| | | }; |
| | | |
| | | // ç»è´¦ä»»å¡ |
| | | const closingTasks = ref([ |
| | | { id: 1, name: '2025å¹´10æ æç»', time: '2025-10-31 18:00', status: '宿', type: 'success' }, |
| | | { id: 2, name: '2025å¹´Q4 壿¥', time: '2025-12-31 18:00', status: '计å', type: 'info' }, |
| | | { id: 3, name: '2025年度 年度ç»è´¦', time: '2025-12-31 23:00', status: '计å', type: 'info' }, |
| | | ]) |
| | | const grid = { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }; |
| | | |
| | | 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 lineLegend = { |
| | | show: false, |
| | | }; |
| | | |
| | | // 审计ççï¼ä¸å«ä¸ªäººå§åï¼ä»
è§è²/æºå¶ï¼ |
| | | 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 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 = ['#F04864', '#FACC14', '#8543E0', '#1890FF', '#13C2C2', '#2FC25B']; // 坿 ¹æ®å®é
è°æ´ |
| | | |
| | | // 饼徿°æ® |
| | | const typeDistributionData = ref([]); |
| | | const departmentDistributionData = ref([]); |
| | | |
| | | // 饼å¾å¾ä¾ |
| | | const typeDistributionLegend = computed(() => ({ |
| | | show: true, |
| | | top: 'center', |
| | | left: '60%', |
| | | orient: 'vertical', |
| | | icon: 'circle', |
| | | data: typeDistributionData.value.map(item => item.name), |
| | | formatter: function(name) { |
| | | const item = typeDistributionData.value.find(i => i.name === name); |
| | | if (!item) return name; |
| | | return `${name} | ${item.count} å° | ${item.amount}`; |
| | | }, |
| | | textStyle: { |
| | | color: '#333', |
| | | fontSize: 14, |
| | | lineHeight: 26, |
| | | } |
| | | })); |
| | | |
| | | |
| | | // 饼å¾ç³»å |
| | | const typeDistributionSeries = computed(() => [ |
| | | { |
| | | type: 'pie', |
| | | radius: ['50%', '65%'], |
| | | center: ['25%', '50%'], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderColor: '#fff', |
| | | borderWidth: 2 |
| | | }, |
| | | label: { |
| | | show: false |
| | | }, |
| | | data: typeDistributionData.value, |
| | | color: pieColors |
| | | } |
| | | ]); |
| | | |
| | | // æçº¿å¾æ°æ® |
| | | const typeDistributionLineSeries = ref([]); |
| | | |
| | | |
| | | // é¥¼å¾æç¤ºæ¡ |
| | | const pieTooltip = reactive({ |
| | | trigger: 'item', |
| | | formatter: function(params) { |
| | | // æ£æ¥æ°æ®æ¯å¦åå¨ |
| | | if (!params.data) return params.name; |
| | | // æ¼æ¥å®æ´å
容 |
| | | return ` |
| | | <div> |
| | | <div style="color:${params.color};font-size:16px;">â</div> |
| | | <div>${params.name}</div> |
| | | <div>æ°éï¼${params.data.count} å°</div> |
| | | <div>éé¢ï¼${params.data.amount}</div> |
| | | </div> |
| | | `; |
| | | } |
| | | }); |
| | | |
| | | // éé¡¹æ°æ® |
| | | const equipmentTypeOptions = ref([]); |
| | | |
| | | // è·åæ°æ® |
| | | const fetchData = async () => { |
| | | try { |
| | | // è·ååºå®èµäº§æ±æ»ä¿¡æ¯ |
| | | const assetInfoRes = await getAssetInfo({ |
| | | startDate: dateRange.value ? dateRange.value[0] : null, |
| | | endDate: dateRange.value ? dateRange.value[1] : null, |
| | | equipmentType: equipmentType.value |
| | | }); |
| | | |
| | | if (assetInfoRes.code === 200) { |
| | | assetInfo.value = assetInfoRes.data; |
| | | } |
| | | |
| | | // è·å设å¤å表 |
| | | const equipmentListRes = await getLedgerPage({ |
| | | 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 |
| | | }); |
| | | |
| | | if (equipmentListRes.code === 200) { |
| | | equipmentList.value = equipmentListRes.data.records; |
| | | pagination.value.total = equipmentListRes.data.total; |
| | | |
| | | // æ ¹æ® equipmentList æ deviceName è¿è¡åç±»ç»è®¡ |
| | | const deviceNameMap = {}; |
| | | equipmentList.value.forEach(item => { |
| | | const deviceName = item.deviceName; |
| | | if (!deviceNameMap[deviceName]) { |
| | | deviceNameMap[deviceName] = { |
| | | name: deviceName, |
| | | count: 0, |
| | | totalValue: 0 |
| | | }; |
| | | } |
| | | deviceNameMap[deviceName].count += item.number || 1; // å设 number ä¸ºè®¾å¤æ°é |
| | | deviceNameMap[deviceName].totalValue += item.taxIncludingPriceTotal || 0; // ç´¯å å«ç¨æ»ä»· |
| | | }); |
| | | |
| | | // 转æ¢ä¸º typeDistributionData æ ¼å¼ |
| | | typeDistributionData.value = Object.values(deviceNameMap).map(item => ({ |
| | | name: item.name, |
| | | value: item.count, |
| | | count: item.count, |
| | | amount: `Â¥${formatCurrency(item.totalValue)}` |
| | | })); |
| | | |
| | | // æ´æ°xè½´æ°æ® |
| | | xAxis.value[0].data = typeDistributionData.value.map(item => item.name); |
| | | |
| | | // æå»ºæçº¿å¾æ°æ® |
| | | typeDistributionLineSeries.value = [ |
| | | { |
| | | name: 'è®¾å¤æ°é', |
| | | type: 'line', |
| | | data: typeDistributionData.value.map(item => item.count) |
| | | } |
| | | ]; |
| | | } |
| | | } 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 = ''; |
| | | 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: #4f46e5; |
| | | } |
| | | .page-header { |
| | | margin-bottom: 12px; |
| | | h2 { margin: 0 0 6px 0; font-weight: 600; } |
| | | p { margin: 0; color: #666; } |
| | | |
| | | .el-card { |
| | | position: relative; |
| | | border-radius: 12px; |
| | | padding: 14px 10px 10px 10px; |
| | | box-shadow: 0 2px 8px #eee; |
| | | |
| | | :deep(.el-card__body) { |
| | | padding: 10px 20px !important; |
| | | } |
| | | |
| | | &.bg1 { |
| | | background: url(@/assets/icons/png/1.png) no-repeat 100% 100% !important; |
| | | } |
| | | |
| | | &.bg2 { |
| | | background: url(@/assets/icons/png/2.png) no-repeat 100% 100% !important; |
| | | } |
| | | |
| | | &.bg3 { |
| | | background: url(@/assets/icons/png/3.png) no-repeat 100% 100% !important; |
| | | } |
| | | |
| | | &.bg4 { |
| | | background: url(@/assets/icons/png/4.png) no-repeat 100% 100% !important; |
| | | } |
| | | |
| | | &.bg5 { |
| | | background: url(@/assets/icons/png/5.png) no-repeat 100% 100% !important; |
| | | } |
| | | } |
| | | |
| | | .grid-container { |
| | | /* grid 容å¨åºç¡æ ·å¼ */ |
| | | display: grid; |
| | | gap: 1rem; /* gap-4 å¯¹åº 1rem (16px) */ |
| | | margin-bottom: 2rem; /* mb-8 å¯¹åº 2rem (32px) */ |
| | | |
| | | p { |
| | | font-size: 22px; |
| | | margin-top: 0px; |
| | | color: #fff; |
| | | } |
| | | |
| | | h3 { |
| | | font-size: 36px; |
| | | font-weight: 500; |
| | | font-family: 'MyCustomFont', sans-serif; |
| | | margin: 10px 0; |
| | | color: #fff; |
| | | } |
| | | } |
| | | |
| | | /* ç§»å¨ç«¯é»è®¤æ ·å¼ (grid-cols-1) */ |
| | | .grid-container { |
| | | grid-template-columns: repeat(1, minmax(0, 1fr)); |
| | | } |
| | | |
| | | /* å°å±å¹åä»¥ä¸ (sm:grid-cols-2) */ |
| | | @media (min-width: 640px) { |
| | | .grid-container { |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | } |
| | | } |
| | | |
| | | /* 大å±å¹åä»¥ä¸ (lg:grid-cols-5) */ |
| | | @media (min-width: 1024px) { |
| | | .grid-container { |
| | | grid-template-columns: repeat(5, minmax(0, 1fr)); |
| | | } |
| | | } |
| | | |
| | | /* å¡çæ¬åææå¢å¼º */ |
| | | .el-card:hover { |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .echarts { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | /* å¾è¡¨å®¹å¨æ ·å¼ */ |
| | | .el-chart { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .section-title { |
| | | position: relative; |
| | | font-size: 18px; |
| | | color: #333; |
| | | padding-left: 10px; |
| | | margin-bottom: 10px; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .section-title::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; top: 0.2em; |
| | | width: 4px; height: 1.2em; |
| | | background: #002FA7; |
| | | left: 0; |
| | | top: 0px; |
| | | content: ''; |
| | | width: 4px; |
| | | height: 18px; |
| | | background-color: #002FA7; |
| | | 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; } |
| | | |
| | | .chart-num { |
| | | position: absolute; |
| | | z-index: 3; |
| | | top: 92px; |
| | | left: 92px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .pagination-container { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | </style> |
| | | |
| | | |