From 18c90ce15d6836dd3dcf54ed01c34c32a592ee6c Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期一, 22 六月 2026 17:17:13 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro_河南鹤壁' into dev_pro_河南鹤壁_泽淇实业
---
src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue | 2
src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js | 15 +
src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue | 9
src/views/reportAnalysis/productionAnalysis/components/left-top.vue | 2
src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue | 9
src/views/reportAnalysis/PSIDataAnalysis/index.vue | 4
src/views/reportAnalysis/productionAnalysis/components/center-center.vue | 21 ++
src/views/reportAnalysis/productionAnalysis/components/right-top.vue | 2
src/views/equipmentManagement/upkeep/Form/detailDia.vue | 118 +++++++++++
src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue | 2
src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue | 30 ++
src/views/reportAnalysis/productionAnalysis/productionNavigation.js | 19 +
src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue | 30 ++
src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue | 2
src/views/equipmentManagement/upkeep/index.vue | 40 +++
src/views/reportAnalysis/productionAnalysis/components/center-top.vue | 22 ++
src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue | 2
src/views/productionManagement/productionReporting/index.vue | 16
src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue | 99 +++++++++
src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue | 2
src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue | 22 ++
src/views/salesManagement/indicatorStats/index.vue | 74 ++++++-
src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue | 30 ++
src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue | 2
src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue | 21 ++
25 files changed, 554 insertions(+), 41 deletions(-)
diff --git a/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
new file mode 100644
index 0000000..074628c
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
@@ -0,0 +1,99 @@
+<template>
+ <FormDialog
+ v-model="dialogVisitable"
+ title="淇濆吇璁板綍璇︽儏"
+ width="800px"
+ operation-type="detail"
+ @close="cancel"
+ >
+ <el-descriptions border :column="2">
+ <el-descriptions-item label="璁惧鍚嶇О">
+ {{ detailData.deviceName || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瑙勬牸鍨嬪彿">
+ {{ detailData.deviceModel || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="璁″垝淇濆吇鏃ユ湡">
+ {{ formatDate(detailData.maintenancePlanTime) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="褰曞叆浜�">
+ {{ detailData.createUserName || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="淇濆吇椤圭洰" :span="2">
+ {{ detailData.machineryCategory || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹為檯淇濆吇浜�">
+ {{ detailData.maintenanceActuallyName || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹為檯淇濆吇鏃ユ湡">
+ {{ formatDate(detailData.maintenanceActuallyTime) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="淇濆吇缁撴灉" :span="2">
+ {{ detailData.maintenanceResult || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐘舵��" :span="2">
+ <el-tag v-if="detailData.status === 2" type="danger">澶辫触</el-tag>
+ <el-tag v-else-if="detailData.status === 1" type="success">瀹岀粨</el-tag>
+ <el-tag v-else type="warning">寰呬繚鍏�</el-tag>
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <div v-if="fileList && fileList.length > 0" class="image-section">
+ <div class="image-title">淇濆吇闄勪欢(鍥剧墖)锛�</div>
+ <AttachmentUploadImage
+ v-model:fileList="fileList"
+ :disabled="true"
+ />
+ </div>
+ </FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+import dayjs from "dayjs";
+import { attachmentList } from "@/api/basicData/storageAttachment.js";
+import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+
+const dialogVisitable = ref(false);
+const detailData = ref({});
+const fileList = ref([]);
+
+const formatDate = (date) => {
+ return date ? dayjs(date).format("YYYY-MM-DD") : "--";
+};
+
+const openDialog = (row) => {
+ dialogVisitable.value = true;
+ detailData.value = { ...row };
+ fileList.value = [];
+
+ if (row.id) {
+ attachmentList({
+ recordType: 'device_maintenance',
+ recordId: row.id,
+ }).then(res => {
+ if (res && res.data) {
+ fileList.value = res.data || [];
+ }
+ });
+ }
+};
+
+const cancel = () => {
+ dialogVisitable.value = false;
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.image-section {
+ margin-top: 20px;
+}
+.image-title {
+ font-weight: bold;
+ margin-bottom: 10px;
+ color: #606266;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/detailDia.vue b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
new file mode 100644
index 0000000..c80691a
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
@@ -0,0 +1,118 @@
+<template>
+ <FormDialog
+ v-model="dialogVisitable"
+ title="淇濆吇浠诲姟璇︽儏"
+ width="800px"
+ operation-type="detail"
+ @close="cancel"
+ >
+ <el-descriptions border :column="2">
+ <el-descriptions-item label="璁惧鍚嶇О">
+ {{ detailData.taskName || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瑙勬牸鍨嬪彿">
+ {{ detailData.deviceModel || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="褰曞叆浜�">
+ {{ detailData.registrant || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐧昏鏃堕棿">
+ {{ detailData.registrationDate || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="淇濆吇椤圭洰" :span="2">
+ {{ detailData.machineryCategory || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="淇濆吇浜�">
+ {{ detailData.maintenancePerson || '--' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="浠诲姟棰戠巼">
+ {{ formatFrequencyType(detailData.frequencyType) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鎵ц鏃堕棿">
+ {{ formatFrequencyDetail(detailData.frequencyDetail) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹氭椂浠诲姟">
+ <el-tag :type="detailData.isActive === 1 ? 'success' : 'info'">
+ {{ detailData.isActive === 1 ? '寮�鍚�' : '鍏抽棴' }}
+ </el-tag>
+ </el-descriptions-item>
+ <el-descriptions-item label="澶囨敞" :span="2">
+ {{ detailData.remarks || '--' }}
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <div v-if="fileList && fileList.length > 0" class="image-section">
+ <div class="image-title">璁惧鍥剧墖锛�</div>
+ <AttachmentUploadImage
+ v-model:fileList="fileList"
+ :disabled="true"
+ />
+ </div>
+ </FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+import { getLedgerById } from "@/api/equipmentManagement/ledger";
+import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+
+const dialogVisitable = ref(false);
+const detailData = ref({});
+const fileList = ref([]);
+
+const formatFrequencyType = (type) => {
+ const map = {
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害",
+ };
+ return map[type] || "--";
+};
+
+const formatFrequencyDetail = (detail) => {
+ if (!detail) return "--";
+ const replacements = {
+ MON: "鍛ㄤ竴",
+ TUE: "鍛ㄤ簩",
+ WED: "鍛ㄤ笁",
+ THU: "鍛ㄥ洓",
+ FRI: "鍛ㄤ簲",
+ SAT: "鍛ㄥ叚",
+ SUN: "鍛ㄦ棩",
+ };
+ return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]);
+};
+
+const openDialog = (row) => {
+ dialogVisitable.value = true;
+ detailData.value = { ...row };
+ fileList.value = [];
+
+ if (row.taskId) {
+ getLedgerById(row.taskId).then(res => {
+ if (res.code === 200 && res.data) {
+ fileList.value = res.data.storageBlobVOs || [];
+ }
+ });
+ }
+};
+
+const cancel = () => {
+ dialogVisitable.value = false;
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.image-section {
+ margin-top: 20px;
+}
+.image-title {
+ font-weight: bold;
+ margin-bottom: 10px;
+ color: #606266;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index 52ad842..cd1adff 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -78,6 +78,11 @@
<template #operation="{ row }">
<el-button type="primary"
link
+ @click="handleDetail(row)">
+ 璇︽儏
+ </el-button>
+ <el-button type="primary"
+ link
@click="editScheduledTask(row)">
缂栬緫
</el-button>
@@ -177,6 +182,11 @@
type="warning">寰呬繚鍏�</el-tag>
</template>
<template #operation="{ row }">
+ <el-button type="primary"
+ link
+ @click="handleRecordDetail(row)">
+ 璇︽儏
+ </el-button>
<!-- 杩欎釜鍔熻兘璺熸柊澧炰繚鍏诲姛鑳戒竴妯′竴鏍凤紝鏈夊暐鎰忎箟锛� -->
<!-- <el-button
type="primary"
@@ -219,6 +229,8 @@
@ok="getTableData" />
<FormDia ref="formDiaRef"
@closeDia="getScheduledTableData" />
+ <DetailDia ref="detailDiaRef" />
+ <RecordDetailDia ref="recordDetailDiaRef" />
<FileList v-if="fileDialogVisible"
v-model:visible="fileDialogVisible"
:record-type="'device_maintenance'"
@@ -241,6 +253,8 @@
import PlanModal from "./Form/PlanModal.vue";
import MaintenanceModal from "./Form/MaintenanceModal.vue";
import FormDia from "./Form/formDia.vue";
+ import DetailDia from "./Form/detailDia.vue";
+ import RecordDetailDia from "./Form/RecordDetailDia.vue";
import {
getUpkeepPage,
delUpkeep,
@@ -263,6 +277,10 @@
const maintainModalRef = ref();
// 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
const formDiaRef = ref();
+ // 瀹氭椂浠诲姟璇︽儏寮圭獥鎺у埗鍣�
+ const detailDiaRef = ref();
+ // 淇濆吇璁板綍璇︽儏寮圭獥鎺у埗鍣�
+ const recordDetailDiaRef = ref();
// 闄勪欢寮圭獥
const fileListDialogRef = ref(null);
const fileDialogVisible = ref(false);
@@ -314,7 +332,7 @@
{
prop: "frequencyType",
label: "棰戞",
- minWidth: 50,
+ minWidth: 80,
// PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
formatData: cell =>
({
@@ -371,7 +389,7 @@
dataType: "slot",
slot: "operation",
align: "center",
- width: "150px",
+ width: "160px",
},
]);
@@ -445,7 +463,7 @@
dataType: "slot",
slot: "operation",
align: "center",
- width: "350px",
+ width: "250px",
},
]);
@@ -503,6 +521,14 @@
if (row) {
nextTick(() => {
formDiaRef.value?.openDialog("edit", row);
+ });
+ }
+ };
+
+ const handleDetail = row => {
+ if (row) {
+ nextTick(() => {
+ detailDiaRef.value?.openDialog(row);
});
}
};
@@ -578,6 +604,14 @@
maintainModalRef.value.open(row.id, row);
};
+ const handleRecordDetail = row => {
+ if (row) {
+ nextTick(() => {
+ recordDetailDiaRef.value?.openDialog(row);
+ });
+ }
+ };
+
const addPlan = () => {
planModalRef.value.openModal();
};
diff --git a/src/views/productionManagement/productionReporting/index.vue b/src/views/productionManagement/productionReporting/index.vue
index ee7b8ad..a24d691 100644
--- a/src/views/productionManagement/productionReporting/index.vue
+++ b/src/views/productionManagement/productionReporting/index.vue
@@ -180,27 +180,27 @@
{
label: "鎶ュ伐鍗曞彿",
prop: "productNo",
- width: 120,
+ width: 140,
},
{
label: "鎶ュ伐浜哄憳",
prop: "nickName",
width: 120,
},
- {
- label: "宸ユ椂锛坔锛�",
- width: 100,
- prop: "workHour",
- },
+ // {
+ // label: "宸ユ椂锛坔锛�",
+ // width: 100,
+ // prop: "workHour",
+ // },
{
label: "宸ュ簭",
prop: "process",
- width: 120,
+ width: 100,
},
{
label: "宸ュ崟缂栧彿",
prop: "workOrderNo",
- width: 120,
+ width: 140,
},
{
label: "閿�鍞悎鍚屽彿",
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
index 313f1df..fad818d 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
@@ -1,17 +1,35 @@
<template>
- <div class="panel-header">
+ <div
+ class="panel-header"
+ :class="{ clickable: !!to }"
+ @click="handleClick"
+ >
<span class="panel-title">{{ title }}</span>
</div>
</template>
<script setup>
-defineProps({
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
title: {
type: String,
required: true,
default: ''
+ },
+ to: {
+ type: String,
+ default: ''
}
})
+
+const router = useRouter()
+
+const handleClick = () => {
+ if (props.to) {
+ router.push(props.to)
+ }
+}
</script>
<style scoped>
@@ -30,4 +48,12 @@
padding-left: 46px;
line-height: 36px;
}
+
+.panel-header.clickable {
+ cursor: pointer;
+}
+
+.panel-header.clickable:hover .panel-title {
+ color: #43e8fc;
+}
</style>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
index e5a1781..b9b0d89 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="鍑哄叆搴撹秼鍔�" />
+ <PanelHeader title="鍑哄叆搴撹秼鍔�" to="/inventoryManagement/receiptManagement" />
<div class="main-panel panel-item-customers">
<div class="filters-row">
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
index 6e39eb1..068f05a 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
@@ -2,7 +2,7 @@
<div>
<!-- 璁惧缁熻 -->
<div class="equipment-stats">
- <div class="equipment-header">
+ <div class="equipment-header clickable" @click="handleNavigate">
<img
src="@/assets/BI/shujutongjiicon@2x.png"
alt="鍥炬爣"
@@ -28,8 +28,19 @@
<script setup>
import { ref, onMounted, inject, watch } from 'vue'
+import { useRouter } from 'vue-router'
import Echarts from '@/components/Echarts/echarts.vue'
import { productTurnoverDays } from '@/api/viewIndex.js'
+import { getPsiRoute } from '../psiNavigation.js'
+
+const router = useRouter()
+
+const handleNavigate = () => {
+ const path = getPsiRoute('浜у搧鍛ㄨ浆澶╂暟')
+ if (path) {
+ router.push(path)
+ }
+}
const chartStyle = { width: '100%', height: '100%' }
const grid = { left: '3%', right: '4%', bottom: '3%', top: '4%', containLabel: true }
@@ -119,6 +130,14 @@
padding-bottom: 2px;
}
+.equipment-header.clickable {
+ cursor: pointer;
+}
+
+.equipment-header.clickable:hover .equipment-title {
+ opacity: 0.85;
+}
+
.equipment-title {
font-weight: 500;
font-size: 18px;
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
index 055fb66..80657c4 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
@@ -6,6 +6,8 @@
v-for="item in statItems"
:key="item.name"
class="stat-card"
+ :class="{ clickable: !!getStatRoute(item.name) }"
+ @click="handleStatClick(item.name)"
>
<img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
<div class="card-content">
@@ -25,9 +27,21 @@
<script setup>
import { ref, onMounted, inject, watch } from 'vue'
+import { useRouter } from 'vue-router'
import { salesPurchaseStorageProductCount } from '@/api/viewIndex.js'
+import { getPsiRoute } from '../psiNavigation.js'
+const router = useRouter()
const statItems = ref([])
+
+const getStatRoute = (name) => getPsiRoute(name)
+
+const handleStatClick = (name) => {
+ const path = getStatRoute(name)
+ if (path) {
+ router.push(path)
+ }
+}
const formatPercent = (val) => {
const num = Number(val) || 0
@@ -81,6 +95,14 @@
height: 142px;
}
+.stat-card.clickable {
+ cursor: pointer;
+}
+
+.stat-card.clickable:hover .card-label {
+ color: #43e8fc;
+}
+
.card-icon {
width: 100px;
height: 100px;
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
index 65a72fe..aa27c0e 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="閲囪喘鍝佸垎甯�" />
+ <PanelHeader title="閲囪喘鍝佸垎甯�" to="/procurementManagement/procurementLedger" />
<div class="main-panel panel-item-customers">
<CarouselCards :items="cardItems" :visible-count="3" />
<div class="pie-chart-wrapper" ref="pieWrapperRef">
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
index f5dac31..cf2a234 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="閿�鍞搧鍒嗗竷" />
+ <PanelHeader title="閿�鍞搧鍒嗗竷" to="/salesManagement/salesLedger" />
<div class="main-panel panel-item-customers">
<CarouselCards :items="cardItems" :visible-count="3" />
<div class="pie-chart-wrapper" ref="pieWrapperRef">
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/index.vue b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
index f81e482..3f8d3df 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/index.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
@@ -34,8 +34,8 @@
<!-- 鍙充晶鍖哄煙 -->
<div class="right-panel">
- <RightBottom />
- <RightTop />
+ <RightBottom header-to="/salesManagement/receiptPaymentLedger" />
+ <RightTop header-to="/procurementManagement/paymentLedger" />
</div>
</div>
</div>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js b/src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js
new file mode 100644
index 0000000..425e666
--- /dev/null
+++ b/src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js
@@ -0,0 +1,15 @@
+export const PSI_ROUTE_MAP = {
+ 閿�鍞搧鍒嗗竷: '/salesManagement/salesLedger',
+ 閲囪喘鍝佸垎甯�: '/procurementManagement/procurementLedger',
+ 閿�鍞骇鍝佹暟: '/salesManagement/salesLedger',
+ 閲囪喘浜у搧鏁�: '/procurementManagement/procurementLedger',
+ 鍌ㄥ瓨浜у搧鏁�: '/inventoryManagement/stockManagement',
+ 瀹㈡埛璐$尞鎺掑悕: '/salesManagement/receiptPaymentLedger',
+ 渚涘簲鍟嗛噰璐帓鍚�: '/procurementManagement/paymentLedger',
+ 鍑哄叆搴撹秼鍔�: '/inventoryManagement/receiptManagement',
+ 浜у搧鍛ㄨ浆澶╂暟: '/inventoryManagement/stockManagement',
+}
+
+export function getPsiRoute(name) {
+ return PSI_ROUTE_MAP[name] || ''
+}
diff --git a/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue b/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
index 313f1df..fad818d 100644
--- a/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
@@ -1,17 +1,35 @@
<template>
- <div class="panel-header">
+ <div
+ class="panel-header"
+ :class="{ clickable: !!to }"
+ @click="handleClick"
+ >
<span class="panel-title">{{ title }}</span>
</div>
</template>
<script setup>
-defineProps({
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
title: {
type: String,
required: true,
default: ''
+ },
+ to: {
+ type: String,
+ default: ''
}
})
+
+const router = useRouter()
+
+const handleClick = () => {
+ if (props.to) {
+ router.push(props.to)
+ }
+}
</script>
<style scoped>
@@ -30,4 +48,12 @@
padding-left: 46px;
line-height: 36px;
}
+
+.panel-header.clickable {
+ cursor: pointer;
+}
+
+.panel-header.clickable:hover .panel-title {
+ color: #43e8fc;
+}
</style>
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
index bcdba84..9c0ce9a 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="瀹㈡埛璐$尞鎺掑悕" />
+ <PanelHeader title="瀹㈡埛璐$尞鎺掑悕" :to="headerTo" />
<div class="panel-item-customers">
<div class="switch-container">
<DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
@@ -28,6 +28,13 @@
import DateTypeSwitch from '../DateTypeSwitch.vue'
import { customerContributionRanking } from '@/api/viewIndex.js'
+defineProps({
+ headerTo: {
+ type: String,
+ default: ''
+ }
+})
+
const chartStyle = {
width: '100%',
height: '100%',
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
index 399354e..36741a9 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="渚涘簲鍟嗛噰璐帓鍚�" />
+ <PanelHeader title="渚涘簲鍟嗛噰璐帓鍚�" :to="headerTo" />
<div class="panel-item-customers">
<div class="switch-container">
<DateTypeSwitch v-model="radio1" @change="handleDateTypeChange" />
@@ -27,6 +27,13 @@
import DateTypeSwitch from '../DateTypeSwitch.vue'
import { supplierPurchaseRanking } from '@/api/viewIndex.js'
+defineProps({
+ headerTo: {
+ type: String,
+ default: ''
+ }
+})
+
const chartStyle = {
width: '100%',
height: '100%',
diff --git a/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue b/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue
index 313f1df..fad818d 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue
@@ -1,17 +1,35 @@
<template>
- <div class="panel-header">
+ <div
+ class="panel-header"
+ :class="{ clickable: !!to }"
+ @click="handleClick"
+ >
<span class="panel-title">{{ title }}</span>
</div>
</template>
<script setup>
-defineProps({
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
title: {
type: String,
required: true,
default: ''
+ },
+ to: {
+ type: String,
+ default: ''
}
})
+
+const router = useRouter()
+
+const handleClick = () => {
+ if (props.to) {
+ router.push(props.to)
+ }
+}
</script>
<style scoped>
@@ -30,4 +48,12 @@
padding-left: 46px;
line-height: 36px;
}
+
+.panel-header.clickable {
+ cursor: pointer;
+}
+
+.panel-header.clickable:hover .panel-title {
+ color: #43e8fc;
+}
</style>
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
index f4f4024..ce746c7 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="鐢熶骇璁㈠崟瀹屾垚杩涘害" />
+ <PanelHeader title="鐢熶骇璁㈠崟瀹屾垚杩涘害" to="/productionManagement/productionOrder" />
<div class="main-panel">
<div class="panel-item-customers">
<CarouselCards :items="cardItems" :visible-count="4" />
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
index 7221b47..c56a4f8 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
@@ -2,7 +2,7 @@
<div>
<!-- 璁惧缁熻 -->
<div class="equipment-stats">
- <div class="equipment-header">
+ <div class="equipment-header clickable" @click="handleNavigate">
<img
src="@/assets/BI/shujutongjiicon@2x.png"
alt="鍥炬爣"
@@ -32,10 +32,21 @@
<script setup>
import { ref, onMounted, inject, watch, nextTick } from 'vue'
+import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
import Echarts from '@/components/Echarts/echarts.vue'
import { inputOutputAnalysis } from '@/api/viewIndex.js'
import DateTypeSwitch from "@/views/reportAnalysis/productionAnalysis/components/DateTypeSwitch.vue";
+import { getProductionRoute } from '../productionNavigation.js'
+
+const router = useRouter()
+
+const handleNavigate = () => {
+ const path = getProductionRoute('鎶曞叆浜у嚭鍒嗘瀽')
+ if (path) {
+ router.push(path)
+ }
+}
const dateType = ref(3) // 1=鍛� 2=鏈� 3=瀛e害
const chartRef = ref(null)
@@ -204,6 +215,14 @@
padding-bottom: 2px;
}
+.equipment-header.clickable {
+ cursor: pointer;
+}
+
+.equipment-header.clickable:hover .equipment-title {
+ opacity: 0.85;
+}
+
.equipment-title {
font-weight: 500;
font-size: 18px;
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
index a806150..7a3deef 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
@@ -6,6 +6,8 @@
v-for="item in statItems"
:key="item.name"
class="stat-card"
+ :class="{ clickable: !!getStatRoute(item.name) }"
+ @click="handleStatClick(item.name)"
>
<img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
<div class="card-content">
@@ -25,9 +27,21 @@
<script setup>
import { ref, onMounted, inject, watch } from 'vue'
+import { useRouter } from 'vue-router'
import { orderCount } from '@/api/viewIndex.js'
+import { getProductionRoute } from '../productionNavigation.js'
+const router = useRouter()
const statItems = ref([])
+
+const getStatRoute = (name) => getProductionRoute(name)
+
+const handleStatClick = (name) => {
+ const path = getStatRoute(name)
+ if (path) {
+ router.push(path)
+ }
+}
const formatPercent = (val) => {
const num = Number(val) || 0
@@ -81,6 +95,14 @@
height: 142px;
}
+.stat-card.clickable {
+ cursor: pointer;
+}
+
+.stat-card.clickable:hover .card-label {
+ color: #43e8fc;
+}
+
.card-icon {
width: 100px;
height: 100px;
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
index b7c7358..e6e8189 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="鍦ㄥ埗鍝佺粺璁″垎鏋�" />
+ <PanelHeader title="鍦ㄥ埗鍝佺粺璁″垎鏋�" to="/productionManagement/productionOrder" />
<div class="main-panel panel-item-customers">
<CarouselCards :items="cardItems" :visible-count="3" />
<div class="chart-wrapper">
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
index 37c82f0..8b25973 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="宸ュ簭浜у嚭鍒嗘瀽" />
+ <PanelHeader title="宸ュ簭浜у嚭鍒嗘瀽" to="/productionManagement/processStatistics" />
<div class="main-panel panel-item-customers">
<div class="filters-row">
<DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
index c3d3db3..33c5c20 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="鐢熶骇鏍哥畻鍒嗘瀽" />
+ <PanelHeader title="鐢熶骇鏍哥畻鍒嗘瀽" to="/productionManagement/productionCosting" />
<div class="main-panel panel-item-customers">
<div class="filters-row">
<DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
index 5ac7035..8e6ffef 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
@@ -1,6 +1,6 @@
<template>
<div>
- <PanelHeader title="宸ュ崟鎵ц鏁堢巼鍒嗘瀽" />
+ <PanelHeader title="宸ュ崟鎵ц鏁堢巼鍒嗘瀽" to="/productionManagement/productionManagement/workOrderEdit/index" />
<div class="main-panel panel-item-customers">
<div class="filters-row">
<DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
diff --git a/src/views/reportAnalysis/productionAnalysis/productionNavigation.js b/src/views/reportAnalysis/productionAnalysis/productionNavigation.js
new file mode 100644
index 0000000..38b45e8
--- /dev/null
+++ b/src/views/reportAnalysis/productionAnalysis/productionNavigation.js
@@ -0,0 +1,19 @@
+const PRODUCTION_ORDER_ROUTE = '/productionManagement/productionOrder'
+
+export const PRODUCTION_ROUTE_MAP = {
+ 宸ュ簭浜у嚭鍒嗘瀽: '/productionManagement/processStatistics',
+ 鍦ㄥ埗鍝佺粺璁″垎鏋�: PRODUCTION_ORDER_ROUTE,
+ 鐢熶骇璁㈠崟鏁�: PRODUCTION_ORDER_ROUTE,
+ 宸插畬鎴愯鍗曟暟: PRODUCTION_ORDER_ROUTE,
+ 寰呯敓浜ц鍗�: PRODUCTION_ORDER_ROUTE,
+ 寰呯敓浜ц鍗曟暟: PRODUCTION_ORDER_ROUTE,
+ 鐢熶骇璁㈠崟瀹屾垚杩涘害: PRODUCTION_ORDER_ROUTE,
+ 鐢熶骇璁㈠崟瀹屾垚杩涘害鏁�: PRODUCTION_ORDER_ROUTE,
+ 鎶曞叆浜у嚭鍒嗘瀽: '/productionManagement/productionReporting',
+ 宸ュ崟鎵ц鏁堢巼鍒嗘瀽: '/productionManagement/productionManagement/workOrderEdit/index',
+ 鐢熶骇鏍哥畻鍒嗘瀽: '/productionManagement/productionCosting',
+}
+
+export function getProductionRoute(name) {
+ return PRODUCTION_ROUTE_MAP[name] || ''
+}
diff --git a/src/views/salesManagement/indicatorStats/index.vue b/src/views/salesManagement/indicatorStats/index.vue
index 8ae15ed..7e5e5ba 100644
--- a/src/views/salesManagement/indicatorStats/index.vue
+++ b/src/views/salesManagement/indicatorStats/index.vue
@@ -2,7 +2,7 @@
<div class="app-container indicator-stats">
<!-- KPI 姹囨�� -->
<el-row :gutter="20" class="stats-row">
- <el-col :xs="24" :sm="12" :md="8">
+ <el-col :xs="24" :sm="12" :md="6">
<div class="stat-card stat-card-blue">
<div class="stat-icon-wrapper">
<div class="stat-icon">
@@ -16,7 +16,7 @@
<div class="stat-bg-decoration"></div>
</div>
</el-col>
- <el-col :xs="24" :sm="12" :md="8">
+ <el-col :xs="24" :sm="12" :md="6">
<div class="stat-card stat-card-green">
<div class="stat-icon-wrapper">
<div class="stat-icon">
@@ -30,7 +30,21 @@
<div class="stat-bg-decoration"></div>
</div>
</el-col>
- <el-col :xs="24" :sm="12" :md="8">
+ <el-col :xs="24" :sm="12" :md="6">
+ <div class="stat-card stat-card-purple">
+ <div class="stat-icon-wrapper">
+ <div class="stat-icon">
+ <el-icon :size="32"><Goods /></el-icon>
+ </div>
+ </div>
+ <div class="stat-content">
+ <div class="stat-value">{{ formatQuantity(indicatorKpis.productSalesQuantity) }}</div>
+ <div class="stat-label">浜у搧閿�鍞暟閲�</div>
+ </div>
+ <div class="stat-bg-decoration"></div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="6">
<div class="stat-card stat-card-orange">
<div class="stat-icon-wrapper">
<div class="stat-icon">
@@ -132,7 +146,7 @@
<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
-import { Document, Van, Tickets, Search, Refresh } from '@element-plus/icons-vue'
+import { Document, Van, Tickets, Search, Refresh, Goods } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
import { getTotalStatistics, getStatisticsTable } from '@/api/salesManagement/indicatorStats'
import { productTreeList } from '@/api/basicData/product.js'
@@ -142,6 +156,7 @@
const indicatorKpis = reactive({
orderCount: 0,
salesAmount: 0,
+ productSalesQuantity: 0,
shipRate: 0
})
@@ -161,6 +176,11 @@
const productOptions = ref([])
const customerOption = ref([])
+const formatQuantity = (value) => {
+ const num = Number(value)
+ if (Number.isNaN(num)) return '0'
+ return num.toLocaleString(undefined, { maximumFractionDigits: 2 })
+}
// 杞崲浜у搧鏍戞暟鎹紝灏� id 鏀逛负 value
function convertIdToValue(data) {
return data.map((item) => {
@@ -234,7 +254,7 @@
if (res && res.data) {
indicatorKpis.orderCount = res.data.total || 0
indicatorKpis.salesAmount = res.data.contractAmountTotal || 0
- // 鍙戣揣鐜囧鏋滄帴鍙f病鏈夎繑鍥烇紝淇濇寔鍘熷�兼垨璁句负0
+ indicatorKpis.productSalesQuantity = res.data.productQuantityTotal || 0
indicatorKpis.shipRate = res.data.shipRate || 0
}
} catch (error) {
@@ -282,12 +302,19 @@
if (indicatorChart) indicatorChart.dispose()
indicatorChart = echarts.init(indicatorChartRef.value)
- // 鏍规嵁鎺ュ彛杩斿洖鐨勬暟鎹粨鏋勬洿鏂板浘琛�
- // 鎺ュ彛杩斿洖: dateList, orderCountList, salesAmountList
+ // 鎺ュ彛杩斿洖: dateList, orderCountList, salesAmountList, productQuantityList
const option = {
title: { text: '澶氱淮搴﹂攢鍞寚鏍囪秼鍔�', left: 'center' },
tooltip: { trigger: 'axis' },
- legend: { data: ['璁㈠崟鏁�', '閿�鍞'], top: 30 },
+ legend: {
+ data: ['璁㈠崟鏁�', '閿�鍞', '浜у搧閿�鍞暟閲�'],
+ top: 30,
+ selected: {
+ '璁㈠崟鏁�': false,
+ '閿�鍞': true,
+ '浜у搧閿�鍞暟閲�': true
+ }
+ },
grid: { left: '3%', right: '8%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
@@ -322,6 +349,13 @@
yAxisIndex: 0,
data: chartData.salesAmountList || [],
itemStyle: { color: '#67c23a' }
+ },
+ {
+ name: '浜у搧閿�鍞暟閲�',
+ type: 'line',
+ yAxisIndex: 1,
+ data: chartData.productQuantityList || [],
+ itemStyle: { color: '#f56c6c' }
}
]
}
@@ -335,7 +369,15 @@
const option = {
title: { text: '澶氱淮搴﹂攢鍞寚鏍囪秼鍔�', left: 'center' },
tooltip: { trigger: 'axis' },
- legend: { data: ['璁㈠崟鏁�', '閿�鍞'], top: 30 },
+ legend: {
+ data: ['璁㈠崟鏁�', '閿�鍞', '浜у搧閿�鍞暟閲�'],
+ top: 30,
+ selected: {
+ '璁㈠崟鏁�': false,
+ '閿�鍞': true,
+ '浜у搧閿�鍞暟閲�': true
+ }
+ },
grid: { left: '3%', right: '8%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: [] },
yAxis: [
@@ -355,7 +397,8 @@
],
series: [
{ name: '璁㈠崟鏁�', type: 'line', yAxisIndex: 1, data: [], itemStyle: { color: '#409eff' } },
- { name: '閿�鍞', type: 'bar', yAxisIndex: 0, data: [], itemStyle: { color: '#67c23a' } }
+ { name: '閿�鍞', type: 'bar', yAxisIndex: 0, data: [], itemStyle: { color: '#67c23a' } },
+ { name: '浜у搧閿�鍞暟閲�', type: 'line', yAxisIndex: 1, data: [], itemStyle: { color: '#f56c6c' } }
]
}
indicatorChart.setOption(option)
@@ -523,6 +566,17 @@
background: #e6a23c;
}
}
+
+ &.stat-card-purple {
+ .stat-icon {
+ background: linear-gradient(135deg, #9b59b6 0%, #b37fcc 100%);
+ color: #fff;
+ }
+
+ .stat-bg-decoration {
+ background: #9b59b6;
+ }
+ }
}
.chart-card,
--
Gitblit v1.9.3