修改
This commit is contained in:
4
.env.dev
4
.env.dev
@@ -5,11 +5,11 @@ ENV = 'development'
|
||||
VUE_APP_TITLE = 洛玻集团驾驶舱
|
||||
|
||||
# 芋道管理系统/开发环境
|
||||
VUE_APP_BASE_API = 'http://172.16.32.18:7070'
|
||||
# VUE_APP_BASE_API = 'http://172.16.32.18:7070'
|
||||
# VUE_APP_BASE_API = 'http://172.16.32.95:7070'
|
||||
# VUE_APP_BASE_API = 'http://172.16.33.83:7070'
|
||||
|
||||
# VUE_APP_BASE_API = 'http://192.168.0.35:7070'
|
||||
VUE_APP_BASE_API = 'http://192.168.0.35:7070'
|
||||
|
||||
|
||||
# 路由懒加载
|
||||
|
||||
@@ -246,3 +246,80 @@ export function getSingleMaterialCostAnalysis(data) {
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getCalendar(data) {
|
||||
return request({
|
||||
url: "lb/index-target-month/getCalendar",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function getLevelStruc(data) {
|
||||
return request({
|
||||
url: "/lb/index-target-month/getLevelStruc",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getTargetMonthPage(data) {
|
||||
return request({
|
||||
url: "/lb/index-target-month/list",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateTargetMonthData(data) {
|
||||
return request({
|
||||
url: "/lb/index-target-month/update",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getTargetYearPage(data) {
|
||||
return request({
|
||||
url: "/lb/index-target-year/list",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateTargetYearData(data) {
|
||||
return request({
|
||||
url: "/lb/index-target-year/update",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getRealMonthPage(data) {
|
||||
return request({
|
||||
url: "/lb/index-real-month/list",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getRealMonthCalendar(data) {
|
||||
return request({
|
||||
url: "/lb/index-real-month/getCalendar",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function updateRealMonthData(data) {
|
||||
return request({
|
||||
url: "/lb/index-real-month/update",
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function getDictListData(query) {
|
||||
return request({
|
||||
url: "/system/dict-data/page",
|
||||
method: "get",
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
BIN
src/assets/img/calendarBg.png
Normal file
BIN
src/assets/img/calendarBg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
BIN
src/assets/img/calendarTitleBg.png
Normal file
BIN
src/assets/img/calendarTitleBg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/img/indicatorDetailsBg.png
Normal file
BIN
src/assets/img/indicatorDetailsBg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 304 KiB |
BIN
src/assets/img/indicatorDetailsTitleBg.png
Normal file
BIN
src/assets/img/indicatorDetailsTitleBg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||
<template
|
||||
v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
|
||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
|
||||
<item :icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" :title="onlyOneChild.meta.title" />
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
@@ -12,14 +13,8 @@
|
||||
<template slot="title">
|
||||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
|
||||
</template>
|
||||
<sidebar-item
|
||||
v-for="(child, index) in item.children"
|
||||
:key="child.path + index"
|
||||
:is-nest="true"
|
||||
:item="child"
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu"
|
||||
/>
|
||||
<sidebar-item v-for="(child, index) in item.children" :key="child.path + index" :is-nest="true" :item="child"
|
||||
:base-path="resolvePath(child.path)" class="nest-menu" />
|
||||
</el-submenu>
|
||||
</div>
|
||||
</template>
|
||||
@@ -76,7 +71,7 @@ export default {
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
if (showingChildren.length === 0) {
|
||||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
|
||||
this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,38 @@
|
||||
<template>
|
||||
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
|
||||
<div :class="{ 'has-logo': showLogo }" :style="{
|
||||
backgroundColor:
|
||||
settings.sideTheme === 'theme-dark'
|
||||
? variables.menuBackground
|
||||
: variables.menuLightBackground,
|
||||
}">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
|
||||
:text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
|
||||
:unique-opened="true"
|
||||
:active-text-color="settings.theme"
|
||||
:collapse-transition="false"
|
||||
mode="vertical"
|
||||
>
|
||||
<el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="settings.sideTheme === 'theme-dark'
|
||||
? variables.menuBackground
|
||||
: variables.menuLightBackground
|
||||
" :text-color="settings.sideTheme === 'theme-dark'
|
||||
? variables.menuColor
|
||||
: variables.menuLightColor
|
||||
" :unique-opened="true" active-text-color="#fff" :collapse-transition="false" mode="vertical">
|
||||
<!-- 根据 sidebarRouters 路由,生成菜单 -->
|
||||
<sidebar-item
|
||||
v-for="(route, index) in sidebarRouters"
|
||||
:key="route.path + index"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
/>
|
||||
<sidebar-item v-for="(route, index) in sidebarRouters" :key="route.path + index" :item="route"
|
||||
:base-path="route.path" />
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
import Logo from "./Logo";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import variables from "@/assets/styles/variables.scss";
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import Logo from './Logo';
|
||||
import SidebarItem from './SidebarItem';
|
||||
import variables from '@/assets/styles/variables.scss';
|
||||
|
||||
export default {
|
||||
components: { SidebarItem, Logo },
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
...mapGetters(["sidebarRouters", "sidebar"]),
|
||||
...mapState(['settings']),
|
||||
...mapGetters(['sidebarRouters', 'sidebar']),
|
||||
activeMenu() {
|
||||
const route = this.$route;
|
||||
const { meta, path } = route;
|
||||
@@ -52,7 +50,7 @@ export default {
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
266
src/views/home/budgetSubmissionDetails.vue
Normal file
266
src/views/home/budgetSubmissionDetails.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<template>
|
||||
<div id="dayReport" class="dayReport" :style="styles">
|
||||
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
|
||||
<ReportHeader top-title="预算填报" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
|
||||
@getTimeType="handleTimeChange" :isBudget="true" />
|
||||
<div class="main-body" style="
|
||||
flex: 1;
|
||||
display: flex;
|
||||
padding: 0px 16px 0 272px;
|
||||
flex-direction: column;
|
||||
">
|
||||
<div class="top" style="margin-top: -20px; display: flex; gap: 16px">
|
||||
<div class="top-three" style="
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns:416px 1192px;
|
||||
">
|
||||
<indicatorCalendar :calendarList="calendarList" />
|
||||
<indicatorDetails :timeType="timeType" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="top" style="margin-top: -20px; display: flex; gap: 16px">
|
||||
<div class="top-three" style="
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns:416px 1192px;
|
||||
">
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="centerImg" style="
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1; /* 确保在 backp 之上、内容之下 */
|
||||
"></div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import ReportHeader from "./components/budgetHeader.vue";
|
||||
import { Sidebar } from "../../layout/components";
|
||||
import screenfull from "screenfull";
|
||||
import indicatorCalendar from "./components/budgetCalendar.vue";
|
||||
import indicatorDetails from "./components/budgetDetails.vue";
|
||||
|
||||
// import premProdStatus from "./components/premProdStatus.vue";
|
||||
import { mapState } from "vuex";
|
||||
// import operatingLineChart from "../operatingComponents/operatingLineChart";
|
||||
// import operatingLineChartCumulative from "../operatingComponents/operatingLineChartCumulative.vue";
|
||||
|
||||
import { getSalesRevenueGroupData, getCalendar } from '@/api/cockpit'
|
||||
import moment from "moment";
|
||||
export default {
|
||||
name: "DayReport",
|
||||
components: {
|
||||
ReportHeader,
|
||||
indicatorCalendar,
|
||||
indicatorDetails,
|
||||
// operatingLineChartCumulative,
|
||||
// operatingLineChart,
|
||||
// premProdStatus,
|
||||
Sidebar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
weekArr: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
isFullScreen: false,
|
||||
timer: null,
|
||||
beilv: 1,
|
||||
timeType:'month',
|
||||
value: 100,
|
||||
sort:1,
|
||||
selectDate:{},
|
||||
monthData: {},
|
||||
ytdData: {},
|
||||
calendarList:{},
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
this.windowWidth(document.documentElement.clientWidth);
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
theme: (state) => state.settings.theme,
|
||||
sideTheme: (state) => state.settings.sideTheme,
|
||||
sidebar: (state) => state.app.sidebar,
|
||||
device: (state) => state.app.device,
|
||||
needTagsView: (state) => state.settings.tagsView,
|
||||
fixedHeader: (state) => state.settings.fixedHeader,
|
||||
}),
|
||||
classObj() {
|
||||
return {
|
||||
hideSidebar: !this.sidebar.opened,
|
||||
openSidebar: this.sidebar.opened,
|
||||
withoutAnimation: this.sidebar.withoutAnimation,
|
||||
mobile: this.device === "mobile",
|
||||
};
|
||||
},
|
||||
variables() {
|
||||
return variables;
|
||||
},
|
||||
// ...mapGetters(['sidebar']),
|
||||
styles() {
|
||||
const v = Math.floor(this.value * this.beilv * 100) / 10000;
|
||||
return {
|
||||
transform: `scale(${v})`,
|
||||
transformOrigin: "left top",
|
||||
// overflow: hidden;
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
clientWidth(val) {
|
||||
if (!this.timer) {
|
||||
this.clientWidth = val;
|
||||
this.beilv2 = this.clientWidth / 1920;
|
||||
this.timer = true;
|
||||
let _this = this;
|
||||
setTimeout(function () {
|
||||
_this.timer = false;
|
||||
}, 500);
|
||||
}
|
||||
// 这里可以添加修改时的方法
|
||||
this.windowWidth(val);
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer);
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
const _this = this;
|
||||
_this.beilv = document.documentElement.clientWidth / 1920;
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
_this.clientWidth = `${document.documentElement.clientWidth}`;
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
// sortChange(value) {
|
||||
// this.sort = value
|
||||
// this.getData()
|
||||
// },
|
||||
getData() {
|
||||
getCalendar().then((res) => {
|
||||
console.log(res, 'res');
|
||||
this.calendarList = res.data
|
||||
// this.monthData = res.data.month
|
||||
// this.ytdData = res.data.ytd
|
||||
})
|
||||
// getSalesRevenueGroupData({
|
||||
// startTime: this.selectDate.startTime,
|
||||
// endTime: this.selectDate.endTime,
|
||||
// sort: this.sort,
|
||||
// index: undefined,
|
||||
// factory: undefined
|
||||
// // timeDim: obj.mode
|
||||
// }).then((res) => {
|
||||
// console.log(res);
|
||||
// this.monthData= res.data.month
|
||||
// this.ytdData = res.data.ytd
|
||||
// })
|
||||
},
|
||||
handleTimeChange(obj) {
|
||||
console.log(obj, 'obj');
|
||||
this.timeType = obj
|
||||
// this.getData()
|
||||
},
|
||||
handleClickOutside() {
|
||||
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
|
||||
},
|
||||
windowWidth(value) {
|
||||
this.clientWidth = value;
|
||||
this.beilv2 = this.clientWidth / 1920;
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen;
|
||||
},
|
||||
init() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: "you browser can not work",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.on("change", this.change);
|
||||
},
|
||||
destroy() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: "you browser can not work",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.off("change", this.change);
|
||||
},
|
||||
// 全屏
|
||||
screenfullChange() {
|
||||
console.log("screenfull.enabled", screenfull.isEnabled);
|
||||
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: "you browser can not work",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.toggle(this.$refs.dayReportB);
|
||||
},
|
||||
// 导出
|
||||
// exportPDF() {
|
||||
// this.$message.success('正在导出,请稍等!')
|
||||
// const element = document.getElementById('dayRepDom')
|
||||
// element.style.display = 'block'
|
||||
// const fileName = '株洲碲化镉生产日报' + moment().format('yyMMDD') + '.pdf'
|
||||
// html2canvas(element, {
|
||||
// dpi: 300, // Set to 300 DPI
|
||||
// scale: 3 // Adjusts your resolution
|
||||
// }).then(function(canvas) {
|
||||
// const imgWidth = 595.28
|
||||
// const imgHeight = 841.89
|
||||
// const pageData = canvas.toDataURL('image/jpeg', 1.0)
|
||||
// const PDF = new JsPDF('', 'pt', [imgWidth, imgHeight])
|
||||
// PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
|
||||
// setTimeout(() => {
|
||||
// PDF.save(fileName) // 导出文件名
|
||||
// }, 1000)
|
||||
// })
|
||||
// element.style.display = 'none'
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "~@/assets/styles/mixin.scss";
|
||||
@import "~@/assets/styles/variables.scss";
|
||||
.dayReport {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: url("../../assets/img/backp.png") no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
.hideSidebar .fixed-header {
|
||||
width: calc(100% - 54px);
|
||||
}
|
||||
|
||||
.sidebarHide .fixed-header {
|
||||
width: calc(100%);
|
||||
}
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -99,7 +99,6 @@ export default {
|
||||
return {
|
||||
name: config.name,
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: config.lineColor },
|
||||
|
||||
144
src/views/home/components/budgetCalendar.vue
Normal file
144
src/views/home/components/budgetCalendar.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="预算填报日历" icon="cockpitItemIcon" size="calendarBg" topSize="calendarTitleBg">
|
||||
<!-- 1. 移除 .kpi-content 的固定高度,改为自适应 -->
|
||||
<div class="kpi-content" style="padding: 14px 14px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 2. .top 保持 flex,无需固定高度,自动跟随子元素拉伸 -->
|
||||
<div class="bottom"
|
||||
style="display: flex; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);height: 844px;padding: 26px 16px;">
|
||||
<!-- 动态生成12个月的容器:优化flex布局,缩小行间距 -->
|
||||
<div class="month-list"
|
||||
style="display: flex; gap: 16px; flex-wrap: wrap; align-content: flex-start; row-gap: 8px;">
|
||||
<!-- 循环生成12个月:通过判断当前月份索引,添加current类 -->
|
||||
<div class="monthItem" :class="{
|
||||
'has-data': month.haveData,
|
||||
'current': index === currentMonthIndex // 本月匹配current样式
|
||||
}" v-for="(month, index) in monthList" :key="index">
|
||||
{{ month.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Container from './container.vue'
|
||||
// import * as echarts from 'echarts'
|
||||
// import topItem from './operating-item.vue'
|
||||
|
||||
export default {
|
||||
name: 'ProductionStatus',
|
||||
components: { Container },
|
||||
// mixins: [resize],
|
||||
props: {
|
||||
calendarList: { // 接收父组件传递的年月状态对象
|
||||
type: Object, // 注意:父组件传递的是对象,不是数组,修正props类型
|
||||
default: () => ({}) // 默认空对象,避免报错
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
// 初始化12个月的列表,可根据实际需求修改haveData默认值
|
||||
monthList: [
|
||||
{ name: '1月', haveData: false, isActive: false },
|
||||
{ name: '2月', haveData: false, isActive: false },
|
||||
{ name: '3月', haveData: false, isActive: false },
|
||||
{ name: '4月', haveData: false, isActive: false },
|
||||
{ name: '5月', haveData: false, isActive: false },
|
||||
{ name: '6月', haveData: false, isActive: false },
|
||||
{ name: '7月', haveData: false, isActive: false },
|
||||
{ name: '8月', haveData: false, isActive: false },
|
||||
{ name: '9月', haveData: false, isActive: false },
|
||||
{ name: '10月', haveData: false, isActive: false },
|
||||
{ name: '11月', haveData: false, isActive: false },
|
||||
{ name: '12月', haveData: false, isActive: false }
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 计算属性:获取当前月份对应的索引(0-11,对应1月-12月)
|
||||
currentMonthIndex() {
|
||||
// new Date().getMonth() 返回 0(1月) - 11(12月),正好匹配monthList索引
|
||||
return new Date().getMonth();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听calendarList变化,实时更新monthList的haveData状态
|
||||
calendarList: {
|
||||
immediate: true, // 组件挂载时立即执行一次
|
||||
deep: true, // 深度监听对象内部属性变化
|
||||
handler(newVal) {
|
||||
this.updateMonthHaveData(newVal);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 初始化图表(若需展示图表,需在模板中添加对应 DOM)
|
||||
// this.$nextTick(() => this.updateChart())
|
||||
},
|
||||
methods: {
|
||||
// 根据calendarList更新monthList的haveData状态
|
||||
updateMonthHaveData(calendarObj) {
|
||||
if (!calendarObj || typeof calendarObj !== 'object') return;
|
||||
|
||||
// 遍历12个月,匹配对应年月
|
||||
this.monthList.forEach((month, index) => {
|
||||
// 获取月份数字(索引+1,补两位,如1→01,10→10)
|
||||
const monthNum = (index + 1).toString().padStart(2, '0');
|
||||
// 拼接成calendarList中的键格式(如2025-01)
|
||||
const yearMonthKey = `2025-${monthNum}`; // 若年份不固定,可改为props传递年份
|
||||
|
||||
// 判断calendarObj中该键对应的值:1→true,0→false,无该键则保持默认false
|
||||
if (calendarObj.hasOwnProperty(yearMonthKey)) {
|
||||
month.haveData = calendarObj[yearMonthKey] === 1;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
// 月份列表容器(flex布局,自动换行)
|
||||
.month-list {
|
||||
// 内联样式已优化行间距,此处可留空或补充其他样式
|
||||
}
|
||||
|
||||
// 基础月份样式
|
||||
.monthItem {
|
||||
width: 164px;
|
||||
height: 42px;
|
||||
border-radius: 4px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
cursor: pointer; // 鼠标悬浮手型
|
||||
transition: all 0.2s ease; // 过渡效果,样式切换更平滑
|
||||
border: 2px solid transparent; // 透明边框,避免选中时布局偏移
|
||||
margin: 0; // 清除默认外边距,进一步缩小缝隙
|
||||
}
|
||||
|
||||
// 有数据的样式(背景色#D1E8FF)
|
||||
.monthItem.has-data {
|
||||
background-color: #D1E8FF;
|
||||
}
|
||||
|
||||
// 无数据的样式(背景色#EFF3F8,基础样式默认值)
|
||||
.monthItem:not(.has-data) {
|
||||
background-color: #EFF3F8;
|
||||
}
|
||||
|
||||
// 本月样式(current类,边框2px solid #0B58FF)
|
||||
.monthItem.current {
|
||||
border: 2px solid #0B58FF !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style></style>
|
||||
440
src/views/home/components/budgetDetails.vue
Normal file
440
src/views/home/components/budgetDetails.vue
Normal file
@@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="预算填报详情" icon="cockpitItemIcon" size="indicatorDetailsBg" topSize="indicatorDetailsTitleBg">
|
||||
<div class="kpi-content" style="padding: 14px 14px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 查询表单区域 -->
|
||||
<div class="bottom"
|
||||
style="display: flex;gap: 8px; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);height: 64px;padding: 16px 16px;">
|
||||
<div style="width: 4px;height: 16px;background: #0B58FF;border-radius: 1px;margin-top: 10px;"></div>
|
||||
<el-form :inline="true" :model="form" class="demo-form-inline">
|
||||
<el-form-item label="所属层级">
|
||||
<el-select v-model="form.levelId" placeholder="请选择">
|
||||
<el-option v-for="item in levelLList" :key="item.id" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="timeType === 'month' ? '填报月份' : '填报年份'">
|
||||
<!-- 根据timeType切换日期选择器类型:月/年 -->
|
||||
<el-date-picker v-model="form.date" :type="timeType" :placeholder="timeType === 'month' ? '选择月' : '选择年'"
|
||||
@change="handleDateChange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button style="background-color: #0B58FF;" type="primary" @click="onSubmit">查询</el-button>
|
||||
<!-- <el-button type="primary" plain size="medium">导入</el-button> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 表格操作区域 + 表格区域 -->
|
||||
<div class="bottom"
|
||||
style="display: flex; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);height: 772px;padding: 16px 16px;flex-direction: column; gap: 8px;">
|
||||
|
||||
<!-- 只读模式:显示编辑按钮 -->
|
||||
<div v-if="!isDetail" style="display: flex;gap: 8px;align-items: center;height: 32px;">
|
||||
<div style="width: 4px;height: 16px;background: #0B58FF;border-radius: 1px;"></div>
|
||||
<div style="width: 58px;
|
||||
height: 16px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: rgba(0,0,0,0.85);
|
||||
line-height: 16px;
|
||||
text-align: right;
|
||||
font-style: normal;">指标详情</div>
|
||||
<el-button style="background-color: #0B58FF;height: 32px;line-height: 10px;" type="primary"
|
||||
@click="handleEdit">编辑</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 编辑模式:显示快捷操作按钮 -->
|
||||
<div v-if="isDetail" style="display: flex;gap: 8px;align-items: center;height: 32px;">
|
||||
<div style="width: 4px;height: 16px;background: #0B58FF;border-radius: 1px;"></div>
|
||||
<div
|
||||
style="width: 58px;height: 16px;font-family: PingFangSC, PingFang SC;font-weight: 400;font-size: 14px;color: rgba(0,0,0,0.85);line-height: 16px;text-align: right;font-style: normal;">
|
||||
快捷操作</div>
|
||||
<!-- <el-button style="height: 32px;line-height: 10px;" type="primary" plain size="medium"
|
||||
@click="onSubmit">复制上月</el-button>
|
||||
<el-button style="height: 32px;line-height: 10px;" type="primary" plain size="medium"
|
||||
@click="onSubmit">全部上调5%</el-button>
|
||||
<el-button style="height: 32px;line-height: 10px;" type="primary" plain size="medium"
|
||||
@click="onSubmit">全部下调5%</el-button> -->
|
||||
<el-button style="height: 32px;line-height: 10px;" type="primary" plain size="medium"
|
||||
@click="handleClear">清空配置</el-button>
|
||||
<el-button style="background-color: #0B58FF;height: 32px;line-height: 10px;" type="primary"
|
||||
@click="handleSave">保存</el-button>
|
||||
<el-button text style="height: 32px;line-height: 10px;" plain size="medium"
|
||||
@click="handleCancel">取消</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 表格组件:添加key属性强制刷新,绑定所有必要属性 -->
|
||||
<base-table style="height: 700px;" :maxHeight=" '700' " @emitFun="inputChange" class="right-aside"
|
||||
:table-props="tableProps" :page="form.pageNo" :limit="form.pageSize" :table-data="tableData" ref="baseTable"
|
||||
:key="`base-table-${isDetail}-${timeType}`"></base-table>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
|
||||
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
|
||||
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
|
||||
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div class="el-upload__tip text-center" slot="tip">
|
||||
<div class="el-upload__tip" slot="tip">
|
||||
<el-checkbox v-model="upload.updateSupport" /> 是否更新已经存在的用户数据
|
||||
</div>
|
||||
<span>仅允许导入xls、xlsx格式文件。</span>
|
||||
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
|
||||
@click="importTemplate">下载模板</el-link>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
||||
<el-button @click="upload.open = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</Container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Container from './container.vue'
|
||||
import { getLevelStruc, getTargetMonthPage, updateTargetMonthData, getTargetYearPage, updateTargetYearData, getDictListData } from '@/api/cockpit'
|
||||
import inputArea from './inputArea.vue' // 导入输入组件
|
||||
import { getBaseHeader } from "@/utils/request";
|
||||
export default {
|
||||
name: 'ProductionStatus',
|
||||
components: {
|
||||
Container,
|
||||
inputArea // 注册输入组件
|
||||
},
|
||||
props: {
|
||||
timeType: {
|
||||
type: String,
|
||||
default: 'month', // 默认月份维度
|
||||
// validator: (val) => ['month', 'year'].includes(val) // 校验传入值只能是month/year
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
levelId: 1,
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
date: undefined, // 统一存储日期(月份/年份)
|
||||
startTime: undefined, // 起始时间戳
|
||||
endTime: undefined // 结束时间戳
|
||||
},
|
||||
dictData: [],
|
||||
upload: {
|
||||
// 是否显示弹出层(用户导入)
|
||||
open: false,
|
||||
// 弹出层标题(用户导入)
|
||||
title: "",
|
||||
// 是否禁用上传
|
||||
isUploading: false,
|
||||
// 是否更新已经存在的用户数据
|
||||
updateSupport: 0,
|
||||
// 设置上传的请求头部
|
||||
headers: getBaseHeader(),
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + '/admin-api/system/user/import'
|
||||
},
|
||||
getDataList: null, // 动态切换的查询接口
|
||||
updateData: null, // 动态切换的更新接口
|
||||
isDetail: false, // 编辑状态标识:false=只读,true=编辑
|
||||
tableData: [], // 表格数据
|
||||
levelLList: [], // 所属层级下拉数据
|
||||
tableProps: [] // 表格列配置
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听timeType变化,动态切换接口并重新初始化
|
||||
timeType: {
|
||||
immediate: true, // 首次加载立即执行
|
||||
handler(newVal) {
|
||||
// 根据timeType切换接口
|
||||
if (newVal === 'month') {
|
||||
this.getDataList = getTargetMonthPage;
|
||||
this.updateData = updateTargetMonthData;
|
||||
} else if (newVal === 'year') {
|
||||
this.getDataList = getTargetYearPage;
|
||||
this.updateData = updateTargetYearData;
|
||||
}
|
||||
// 重新初始化日期和时间戳
|
||||
this.initDefaultDate();
|
||||
this.calculateTimeStamp();
|
||||
// 重新初始化表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 重新请求数据
|
||||
this.$nextTick(() => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
},
|
||||
// 监听isDetail变化,确保配置同步(双重保障)
|
||||
isDetail(newVal) {
|
||||
this.initTableProps(newVal);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 1. 初始化默认日期
|
||||
this.initDefaultDate();
|
||||
// 2. 计算对应时间戳
|
||||
this.calculateTimeStamp();
|
||||
this.getDictData()
|
||||
// 3. 先初始化表格配置(优先于数据请求,避免表格空配置渲染)
|
||||
this.initTableProps(this.isDetail);
|
||||
// 4. 等待配置就绪后,再请求数据,避免异步冲突
|
||||
this.$nextTick(() => {
|
||||
this.getData();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getDictData() {
|
||||
getDictListData({ pageNo: 1, pageSize: 100, dictType: 'lb_dw' }).then((res) => {
|
||||
this.dictData = res.data.list
|
||||
})
|
||||
},
|
||||
// 表格单元格数据变更回调
|
||||
inputChange(val) {
|
||||
console.log('修改的数据:', val);
|
||||
// 安全修改:判断索引是否存在,避免数组越界
|
||||
if (this.tableData[val._pageIndex - 1]) {
|
||||
this.tableData[val._pageIndex - 1][val.prop] = val[val.prop];
|
||||
// 标记数据为已修改状态
|
||||
this.tableData[val._pageIndex - 1].status = 1;
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化表格列配置(核心:精准控制inputArea挂载)
|
||||
initTableProps(isEdit) {
|
||||
console.log('当前编辑状态:', isEdit, '当前时间维度:', this.timeType);
|
||||
|
||||
// 基础表格列配置(只读模式使用)
|
||||
const baseTableProps = [
|
||||
{ prop: 'type', label: '指标类型', align: 'center' },
|
||||
{ prop: 'name', label: '指标名称', align: 'center' },
|
||||
{ prop: 'unit', label: '单位', align: 'center' },
|
||||
{ prop: 'target', label: '预估值', align: 'center' },
|
||||
];
|
||||
|
||||
if (isEdit) {
|
||||
// 编辑模式:仅给「预估值」列添加inputArea(精准挂载,避免无效配置)
|
||||
this.tableProps = baseTableProps.map(item => {
|
||||
if (item.prop === 'target') { // 只给需要编辑的列添加子组件
|
||||
return {
|
||||
...item,
|
||||
subcomponent: inputArea // 挂载输入组件
|
||||
};
|
||||
}
|
||||
return item; // 其他列保持原有配置
|
||||
});
|
||||
} else {
|
||||
// 只读模式:深拷贝基础配置,避免引用污染
|
||||
this.tableProps = JSON.parse(JSON.stringify(baseTableProps));
|
||||
}
|
||||
console.log('表格配置:', this.tableProps);
|
||||
},
|
||||
|
||||
// 切换到编辑模式
|
||||
handleEdit() {
|
||||
this.isDetail = true;
|
||||
// 先更新表格配置,再强制表格刷新(双重保障)
|
||||
this.initTableProps(this.isDetail);
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.baseTable) {
|
||||
this.$refs.baseTable.$forceUpdate(); // 强制表格组件刷新
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 保存数据(使用动态切换的updateData接口)
|
||||
handleSave() {
|
||||
// if (!this.updateData) {
|
||||
// this.$modal.msgWarning('当前时间维度异常,无法保存');
|
||||
// return;
|
||||
// }
|
||||
this.$modal.confirm('是否确认保存数据?').then(() => {
|
||||
return this.updateData(this.tableData)
|
||||
}).then(() => {
|
||||
this.isDetail = false;
|
||||
// 重置表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 清空并重新请求数据,恢复原始状态
|
||||
this.$nextTick(() => {
|
||||
this.tableData = [];
|
||||
this.getData();
|
||||
});
|
||||
this.$modal.msgSuccess("保存成功");
|
||||
}).catch(() => { });
|
||||
},
|
||||
|
||||
// 取消编辑,恢复只读模式
|
||||
handleCancel() {
|
||||
this.isDetail = false;
|
||||
// 重置表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 清空并重新请求数据,恢复原始状态
|
||||
this.$nextTick(() => {
|
||||
this.tableData = [];
|
||||
this.getData();
|
||||
});
|
||||
console.log('已取消编辑,恢复原始数据');
|
||||
},
|
||||
|
||||
// 清空配置
|
||||
handleClear() {
|
||||
this.isDetail = false;
|
||||
// 重置表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 清空并重新请求数据,恢复原始状态
|
||||
this.$nextTick(() => {
|
||||
this.tableData = [];
|
||||
this.getData();
|
||||
});
|
||||
},
|
||||
|
||||
// 初始化默认日期(根据timeType)
|
||||
initDefaultDate() {
|
||||
const currentDate = new Date();
|
||||
this.form.date = currentDate;
|
||||
},
|
||||
|
||||
// 计算时间戳(根据timeType切换:月/年)
|
||||
calculateTimeStamp(selectDate) {
|
||||
let targetDate = selectDate || this.form.date;
|
||||
if (!targetDate) {
|
||||
targetDate = new Date();
|
||||
} else {
|
||||
targetDate = new Date(targetDate);
|
||||
}
|
||||
|
||||
const year = targetDate.getFullYear();
|
||||
let month = targetDate.getMonth(); // 月份0-11
|
||||
|
||||
if (this.timeType === 'month') {
|
||||
// 月维度:当月1号 00:00:00 → 当月最后一天 23:59:59
|
||||
const startDate = new Date(year, month, 1, 0, 0, 0);
|
||||
this.form.startTime = startDate.getTime();
|
||||
|
||||
const lastDay = new Date(year, month + 1, 0).getDate();
|
||||
const endDatePrecise = new Date(year, month, lastDay, 23, 59, 59);
|
||||
this.form.endTime = endDatePrecise.getTime();
|
||||
} else if (this.timeType === 'year') {
|
||||
// 年维度:当年1月1号 00:00:00 → 当年12月31号 23:59:59
|
||||
const startDate = new Date(year, 0, 1, 0, 0, 0);
|
||||
this.form.startTime = startDate.getTime();
|
||||
|
||||
const endDatePrecise = new Date(year, 11, 31, 23, 59, 59);
|
||||
this.form.endTime = endDatePrecise.getTime();
|
||||
}
|
||||
},
|
||||
|
||||
// 日期选择器变更事件(统一处理月/年变更)
|
||||
handleDateChange(val) {
|
||||
if (!val) {
|
||||
// 清空选择时,重置时间戳
|
||||
this.form.startTime = undefined;
|
||||
this.form.endTime = undefined;
|
||||
return;
|
||||
}
|
||||
// 计算选中日期对应的时间戳
|
||||
this.calculateTimeStamp(val);
|
||||
},
|
||||
getUnitLabel(unitCode) {
|
||||
// 若字典为空或无匹配编码,返回原编码或空字符串
|
||||
if (!this.dictData || this.dictData.length === 0) {
|
||||
return unitCode || '';
|
||||
}
|
||||
// 查找匹配的字典项
|
||||
const matchItem = this.dictData.find(item => item.value == unitCode);
|
||||
// 返回匹配的label,无匹配则返回原unit编码
|
||||
return matchItem ? matchItem.label : (unitCode || '');
|
||||
},
|
||||
// 请求下拉数据和表格数据(使用动态切换的getDataList接口)
|
||||
getData() {
|
||||
if (!this.getDataList) {
|
||||
console.warn('当前时间维度异常,无法获取数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 请求所属层级下拉数据
|
||||
getLevelStruc().then((res) => {
|
||||
console.log('所属层级数据:', res);
|
||||
this.levelLList = res.data || [];
|
||||
}).catch(err => {
|
||||
console.error('获取所属层级失败:', err);
|
||||
this.levelLList = [];
|
||||
});
|
||||
|
||||
// 2. 请求表格分页数据(使用动态接口)
|
||||
this.getDataList({
|
||||
levelId: this.form.levelId,
|
||||
startTime: this.form.startTime,
|
||||
endTime: this.form.endTime,
|
||||
pageSize: this.form.pageSize,
|
||||
pageNo: this.form.pageNo
|
||||
}).then((res) => {
|
||||
console.log('表格数据:', res);
|
||||
this.tableData = res.data.map(item => {
|
||||
// 新增unitLabel字段,存储匹配后的显示名称
|
||||
return {
|
||||
...item,
|
||||
unitLabel: this.getUnitLabel(item.unit)
|
||||
};
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error('获取表格数据失败:', err);
|
||||
this.tableData = [];
|
||||
});
|
||||
},
|
||||
|
||||
// 查询按钮点击事件(可根据需求扩展逻辑)
|
||||
onSubmit() {
|
||||
// 清空原有表格数据,重新请求
|
||||
this.tableData = [];
|
||||
this.$nextTick(() => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
// 月份列表容器样式(保留原有配置,若无使用可忽略)
|
||||
.month-list {
|
||||
// 内联样式已优化行间距,此处可留空或补充
|
||||
}
|
||||
|
||||
// 基础月份样式(保留原有配置,若无使用可忽略)
|
||||
.monthItem {
|
||||
width: 164px;
|
||||
height: 42px;
|
||||
border-radius: 4px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 2px solid transparent;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monthItem.has-data {
|
||||
background-color: #D1E8FF;
|
||||
}
|
||||
|
||||
.monthItem:not(.has-data) {
|
||||
background-color: #EFF3F8;
|
||||
}
|
||||
|
||||
.monthItem.active {
|
||||
border: 2px solid #0B58FF !important;
|
||||
}
|
||||
</style>
|
||||
379
src/views/home/components/budgetHeader.vue
Normal file
379
src/views/home/components/budgetHeader.vue
Normal file
@@ -0,0 +1,379 @@
|
||||
<template>
|
||||
<header class="report-header" :class="['report-header__' + size]">
|
||||
<!-- 左侧区域:标题 -->
|
||||
<div class="left-content" :style="{ marginLeft: leftMargin }">
|
||||
<div class="top-title">{{ topTitle }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧区域:全屏按钮 -->
|
||||
<div class="right-content">
|
||||
<el-button type="text" class="return-btn" :title="'返回'" @click="handleReturn">
|
||||
<svg-icon style="color: #0B58FF;" icon-class="returnIcon" />
|
||||
</el-button>
|
||||
<el-button type="text" class="screen-btn" :title="isFullScreen ? '退出全屏' : '全屏'" @click="changeFullScreen">
|
||||
<svg-icon style="color: #0B58FF;" v-if="isFullScreen" icon-class="unFullScreenView" />
|
||||
<svg-icon style="color: #0B58FF;" v-else icon-class="fullScreenView" />
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 时间选择区域:时间维度下拉框(月/年) + 日期选择下拉框 -->
|
||||
<div class="timeType" v-if="isBudget">
|
||||
<div class="dateP">
|
||||
<div class="label">
|
||||
<span class="label-text">时间范围</span>
|
||||
</div>
|
||||
<!-- 第一步:时间维度下拉框(月/年) -->
|
||||
<el-select v-model="timeDimension" class="time-dimension-select" @change="handleDimensionChange"
|
||||
style="width: 150px; height: 29px; margin-right: 8px;">
|
||||
<el-option label="月预算" value="month" />
|
||||
<el-option label="年预算" value="year" />
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'; // 引入moment
|
||||
|
||||
export default {
|
||||
name: 'Header',
|
||||
props: {
|
||||
isFullScreen: { type: Boolean, default: false },
|
||||
topTitle: { type: String, default: '' },
|
||||
size: { type: String, default: 'basic' },
|
||||
leftMargin: {
|
||||
type: [String, Number],
|
||||
default: '350px' // 默认值设为350px
|
||||
},
|
||||
isBudget: { type: Boolean, default: false },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentTime: '',
|
||||
timeTimer: null,
|
||||
timeDimension: 'month', // 默认时间维度:月(可选值:month/year)
|
||||
selectedDate: '', // 选中的日期(格式:YYYY-MM 或 YYYY)
|
||||
dateOptions: [] // 日期下拉框选项(动态生成)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 初始化默认时间维度和日期
|
||||
// this.initDateOptions();
|
||||
// 默认选中当前月/年
|
||||
// if (this.timeDimension === 'month') {
|
||||
// this.selectedDate = moment().format('YYYY-MM');
|
||||
// } else {
|
||||
// this.selectedDate = moment().format('YYYY');
|
||||
// }
|
||||
// this.$nextTick(() => this.emitTimeRange());
|
||||
},
|
||||
methods: {
|
||||
changeFullScreen() {
|
||||
this.$emit('screenfullChange');
|
||||
},
|
||||
handleReturn() {
|
||||
this.$router.go(-1);
|
||||
},
|
||||
exportPDF() {
|
||||
this.$emit('exportPDF');
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化日期下拉框选项(生成近10年的年份/月份选项,可自定义范围)
|
||||
*/
|
||||
initDateOptions() {
|
||||
this.dateOptions = [];
|
||||
const currentYear = moment().year();
|
||||
const range = 10; // 生成近10年的选项
|
||||
|
||||
if (this.timeDimension === 'month') {
|
||||
// 月维度:生成近10年的所有月份(格式:YYYY-MM)
|
||||
for (let y = currentYear; y >= currentYear - range; y--) {
|
||||
for (let m = 12; m >= 1; m--) {
|
||||
const monthStr = m < 10 ? `0${m}` : `${m}`;
|
||||
const value = `${y}-${monthStr}`;
|
||||
const label = `${y}年${monthStr}月`;
|
||||
this.dateOptions.push({ value, label });
|
||||
}
|
||||
}
|
||||
} else if (this.timeDimension === 'year') {
|
||||
// 年维度:生成近10年的年份(格式:YYYY)
|
||||
for (let y = currentYear; y >= currentYear - range; y--) {
|
||||
this.dateOptions.push({
|
||||
value: `${y}`,
|
||||
label: `${y}年`
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 时间维度切换回调(月→年 / 年→月)
|
||||
*/
|
||||
handleDimensionChange() {
|
||||
// 重新初始化日期选项
|
||||
this.$emit('getTimeType', this. timeDimension)
|
||||
},
|
||||
|
||||
/**
|
||||
* 核心方法:根据选中的维度和日期,计算时间范围(时间戳格式)
|
||||
*/
|
||||
calculateTimeRange() {
|
||||
// 初始化时间戳为0(兜底值)
|
||||
let startTime = 0;
|
||||
let endTime = 0;
|
||||
// 时间维度对应mode(2=月,3=年,保持和原有逻辑一致)
|
||||
const mode = this.timeDimension === 'month' ? 2 : 3;
|
||||
// 默认当前时间
|
||||
const defaultMoment = moment();
|
||||
|
||||
try {
|
||||
let targetMoment;
|
||||
// 根据维度解析选中的日期
|
||||
if (this.timeDimension === 'month') {
|
||||
targetMoment = this.selectedDate ? moment(this.selectedDate, 'YYYY-MM') : defaultMoment;
|
||||
} else {
|
||||
targetMoment = this.selectedDate ? moment(this.selectedDate, 'YYYY') : defaultMoment;
|
||||
}
|
||||
|
||||
// 验证日期是否有效,无效则使用当前时间兜底
|
||||
if (!targetMoment.isValid()) {
|
||||
console.warn('无效的日期格式,已使用当前时间:', this.selectedDate);
|
||||
targetMoment = defaultMoment;
|
||||
}
|
||||
|
||||
// 根据维度计算时间范围
|
||||
if (this.timeDimension === 'month') {
|
||||
// 月维度:当月第一天00:00:00 → 当月最后一天23:59:59
|
||||
startTime = targetMoment.startOf('month').millisecond(0).valueOf();
|
||||
endTime = targetMoment.endOf('month').millisecond(0).valueOf();
|
||||
} else if (this.timeDimension === 'year') {
|
||||
// 年维度:当年第一天00:00:00 → 当年最后一天23:59:59
|
||||
startTime = targetMoment.startOf('year').millisecond(0).valueOf();
|
||||
endTime = targetMoment.endOf('year').millisecond(0).valueOf();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('计算时间范围时出错:', error);
|
||||
}
|
||||
|
||||
// 返回时间范围信息
|
||||
return {
|
||||
startTime,
|
||||
endTime,
|
||||
mode
|
||||
};
|
||||
},
|
||||
|
||||
// 传递时间范围给父组件
|
||||
// emitTimeRange() {
|
||||
// const timeRange = this.calculateTimeRange();
|
||||
// this.$emit('timeRangeChange', timeRange);
|
||||
// }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 字体引入 */
|
||||
@font-face {
|
||||
font-family: "YouSheBiaoTiHei";
|
||||
src: url('../../../assets/fonts/YouSheBiaoTiHe.ttf') format('truetype');
|
||||
}
|
||||
|
||||
/* 头部容器基础样式 */
|
||||
.report-header {
|
||||
height: 117px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
&__basic {
|
||||
background: url(../../../assets/img/topBg.png) no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__psi {
|
||||
background: url(../../../assets/img/psiTopTitle.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
/* 左侧标题区域 */
|
||||
.left-content {
|
||||
margin-top: 11px;
|
||||
// margin-left: 350px;
|
||||
height: 55px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.top-title {
|
||||
height: 55px;
|
||||
font-family: "YouSheBiaoTiHei", sans-serif;
|
||||
font-size: 42px;
|
||||
color: #1E1651;
|
||||
line-height: 55px;
|
||||
letter-spacing: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 时间选择区域 */
|
||||
.timeType {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
top: 42px;
|
||||
right: 0px;
|
||||
margin-top: 18px;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.timeType .item {
|
||||
width: 50px;
|
||||
height: 28px;
|
||||
background: rgba(236, 244, 254, 1);
|
||||
transform: skew(-25deg);
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: rgba(11, 88, 255, 1);
|
||||
line-height: 28px;
|
||||
letter-spacing: 2px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeType .item .item-text {
|
||||
display: inline-block;
|
||||
transform: skew(25deg);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.timeType .item.no-skew {
|
||||
background: rgba(11, 88, 255, 1);
|
||||
color: rgba(249, 252, 255, 1);
|
||||
transform: skew(-25deg) !important;
|
||||
box-shadow: 0 2px 8px rgba(11, 88, 255, 0.3);
|
||||
}
|
||||
|
||||
.timeType .item.no-skew .item-text {
|
||||
transform: skew(25deg) !important;
|
||||
}
|
||||
|
||||
.dateP {
|
||||
position: relative;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.dateP .label {
|
||||
width: 165px;
|
||||
height: 28px;
|
||||
background: rgba(236, 244, 254, 1);
|
||||
transform: skew(-25deg);
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #0B58FF;
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dateP .label-text {
|
||||
display: inline-block;
|
||||
transform: skew(25deg);
|
||||
}
|
||||
|
||||
/* 右侧全屏按钮区域 */
|
||||
.right-content {
|
||||
display: flex;
|
||||
// flex-direction: column;
|
||||
margin-top: 12px;
|
||||
margin-right: 10px;
|
||||
gap: 21px;
|
||||
}
|
||||
|
||||
// .current-time {
|
||||
// color: #FFFFFF;
|
||||
// font-family: PingFangSC, PingFang SC;
|
||||
// font-weight: 500;
|
||||
// font-size: 22px;
|
||||
// line-height: 24px;
|
||||
// letter-spacing: 1px;
|
||||
// }
|
||||
|
||||
.screen-btn {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
color: #00fff0;
|
||||
font-size: 26px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.home-btn {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
// margin-left: 300px;
|
||||
color: #00fff0;
|
||||
font-size: 26px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.return-btn {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
// margin-left: 300px;
|
||||
color: #00fff0;
|
||||
font-size: 26px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 自定义下拉框样式(替换原有日期选择器样式) */
|
||||
::v-deep .time-dimension-select,
|
||||
::v-deep .custom-date-select {
|
||||
height: 28px !important;
|
||||
|
||||
.el-input__inner {
|
||||
height: 28px !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 28px !important;
|
||||
color: #fff !important;
|
||||
background-color: rgba(11, 88, 255, 1) !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-input__icon {
|
||||
color: #fff !important;
|
||||
font-size: 16px !important;
|
||||
line-height: 28px !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item {
|
||||
font-size: 14px !important;
|
||||
padding: 6px 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 时间维度下拉框额外样式 */
|
||||
::v-deep .time-dimension-select .el-input__inner {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.2) !important;
|
||||
border-radius: 4px 0 0 4px !important;
|
||||
}
|
||||
|
||||
/* 日期选择下拉框额外样式 */
|
||||
::v-deep .custom-date-select .el-input__inner {
|
||||
border-radius: 0 4px 4px 0 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
name: 'Container',
|
||||
components: {},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['name', 'size', 'icon', 'topSize','isShowTab'],
|
||||
props: ['name', 'size', 'icon', 'topSize', 'isShowTab'],
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'month' // 初始化激活的Tab(支持父组件传默认值)
|
||||
@@ -135,6 +135,17 @@ export default {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__calendarTitleBg {
|
||||
background: url(../../../assets/img/calendarTitleBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__indicatorDetailsTitleBg {
|
||||
background: url(../../../assets/img/indicatorDetailsTitleBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__topBasic {
|
||||
@@ -203,6 +214,18 @@ export default {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__calendarBg {
|
||||
background: url(../../../assets/img/calendarBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__indicatorDetailsBg {
|
||||
background: url(../../../assets/img/indicatorDetailsBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
// &__left {
|
||||
// background: url(../../../../../../../assets/img/left.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
@@ -293,6 +316,7 @@ export default {
|
||||
.container-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tab-group {
|
||||
display: inline-flex;
|
||||
position: absolute;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</div>
|
||||
<div class="button-line lineThree" v-if="activeButton !== 2 && activeButton !== 3"></div>
|
||||
<div class="item-button" :class="{ active: activeButton === 3 }" @click="activeButton = 3">
|
||||
双镀产品
|
||||
双镀销量
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,7 +60,7 @@ export default {
|
||||
'单价',
|
||||
'净价',
|
||||
'销量',
|
||||
'双镀面板' // 注意:数据中的 key 是“双镀面板”,按钮显示的是“双镀产品”
|
||||
'双镀销量' // 注意:数据中的 key 是“双镀面板”,按钮显示的是“双镀产品”
|
||||
]
|
||||
};
|
||||
},
|
||||
@@ -119,7 +119,6 @@ export default {
|
||||
{
|
||||
name: '实际',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
|
||||
|
||||
@@ -78,7 +78,7 @@ export default {
|
||||
label: { backgroundColor: '#6a7985' }
|
||||
}
|
||||
},
|
||||
grid: { top: 10, bottom: 20, right: 25, left: 50 },
|
||||
grid: { top: 10, bottom: 20, right: 25, left: 70 },
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="coreItem">
|
||||
<!-- 动态生成每个 item -->
|
||||
<div class="item" v-for="(item, index) in itemList" :key="index">
|
||||
<div @click="handleDashboardClick(item.path)" class="item" v-for="(item, index) in itemList" :key="index">
|
||||
<div class="unit">{{ item.name }}</div>
|
||||
<div class="item-content">
|
||||
<!-- 左右内容容器 -->
|
||||
@@ -61,6 +61,14 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : 5
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 核心转换函数:将 cost 对象转换为 itemList 数组
|
||||
* @param {Object} rawData - 原始的 cost 数据对象
|
||||
@@ -69,9 +77,16 @@ export default {
|
||||
transformData(rawData) {
|
||||
// 定义费用类型映射关系(键名、显示名称、单位)
|
||||
const costMapping = [
|
||||
{ key: 'manageCost', name: '管理费用·万元' },
|
||||
{ key: 'saleCost', name: '销售费用·万元' },
|
||||
{ key: 'financeCost', name: '财务费用·万元' }
|
||||
{
|
||||
key: 'totalCost', name: '总费用·万元',
|
||||
path:"/expenseAnalysis/expenseAnalysisBase"
|
||||
},
|
||||
{
|
||||
key: 'manageCost', name: '管理费用·万元',
|
||||
path: "/expenseAnalysis/expenseAnalysisBase"
|
||||
},
|
||||
{ key: 'saleCost', name: '销售费用·万元', path: "/expenseAnalysis/expenseAnalysisBase" },
|
||||
{ key: 'financeCost', name: '财务费用·万元', path: "/expenseAnalysis/expenseAnalysisBase" }
|
||||
];
|
||||
|
||||
// 遍历映射关系,转换数据
|
||||
@@ -81,6 +96,8 @@ export default {
|
||||
|
||||
return {
|
||||
name: mappingItem.name,
|
||||
path: mappingItem.path,
|
||||
hbe: costData.hbe,
|
||||
targetValue: costData.last, // 上月值
|
||||
currentValue: costData.this // 本月值
|
||||
};
|
||||
|
||||
@@ -87,7 +87,6 @@ export default {
|
||||
{
|
||||
name: '目标',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
|
||||
@@ -104,7 +103,6 @@ export default {
|
||||
{
|
||||
name: '实际',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
|
||||
|
||||
144
src/views/home/components/indicatorCalendar.vue
Normal file
144
src/views/home/components/indicatorCalendar.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="指标填报日历" icon="cockpitItemIcon" size="calendarBg" topSize="calendarTitleBg">
|
||||
<!-- 1. 移除 .kpi-content 的固定高度,改为自适应 -->
|
||||
<div class="kpi-content" style="padding: 14px 14px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 2. .top 保持 flex,无需固定高度,自动跟随子元素拉伸 -->
|
||||
<div class="bottom"
|
||||
style="display: flex; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);height: 844px;padding: 26px 16px;">
|
||||
<!-- 动态生成12个月的容器:优化flex布局,缩小行间距 -->
|
||||
<div class="month-list"
|
||||
style="display: flex; gap: 16px; flex-wrap: wrap; align-content: flex-start; row-gap: 8px;">
|
||||
<!-- 循环生成12个月:通过判断当前月份索引,添加current类 -->
|
||||
<div class="monthItem" :class="{
|
||||
'has-data': month.haveData,
|
||||
'current': index === currentMonthIndex // 本月匹配current样式
|
||||
}" v-for="(month, index) in monthList" :key="index">
|
||||
{{ month.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Container from './container.vue'
|
||||
// import * as echarts from 'echarts'
|
||||
// import topItem from './operating-item.vue'
|
||||
|
||||
export default {
|
||||
name: 'ProductionStatus',
|
||||
components: { Container },
|
||||
// mixins: [resize],
|
||||
props: {
|
||||
calendarList: { // 接收父组件传递的年月状态对象
|
||||
type: Object, // 注意:父组件传递的是对象,不是数组,修正props类型
|
||||
default: () => ({}) // 默认空对象,避免报错
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
// 初始化12个月的列表,可根据实际需求修改haveData默认值
|
||||
monthList: [
|
||||
{ name: '1月', haveData: false, isActive: false },
|
||||
{ name: '2月', haveData: false, isActive: false },
|
||||
{ name: '3月', haveData: false, isActive: false },
|
||||
{ name: '4月', haveData: false, isActive: false },
|
||||
{ name: '5月', haveData: false, isActive: false },
|
||||
{ name: '6月', haveData: false, isActive: false },
|
||||
{ name: '7月', haveData: false, isActive: false },
|
||||
{ name: '8月', haveData: false, isActive: false },
|
||||
{ name: '9月', haveData: false, isActive: false },
|
||||
{ name: '10月', haveData: false, isActive: false },
|
||||
{ name: '11月', haveData: false, isActive: false },
|
||||
{ name: '12月', haveData: false, isActive: false }
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 计算属性:获取当前月份对应的索引(0-11,对应1月-12月)
|
||||
currentMonthIndex() {
|
||||
// new Date().getMonth() 返回 0(1月) - 11(12月),正好匹配monthList索引
|
||||
return new Date().getMonth();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听calendarList变化,实时更新monthList的haveData状态
|
||||
calendarList: {
|
||||
immediate: true, // 组件挂载时立即执行一次
|
||||
deep: true, // 深度监听对象内部属性变化
|
||||
handler(newVal) {
|
||||
this.updateMonthHaveData(newVal);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 初始化图表(若需展示图表,需在模板中添加对应 DOM)
|
||||
// this.$nextTick(() => this.updateChart())
|
||||
},
|
||||
methods: {
|
||||
// 根据calendarList更新monthList的haveData状态
|
||||
updateMonthHaveData(calendarObj) {
|
||||
if (!calendarObj || typeof calendarObj !== 'object') return;
|
||||
|
||||
// 遍历12个月,匹配对应年月
|
||||
this.monthList.forEach((month, index) => {
|
||||
// 获取月份数字(索引+1,补两位,如1→01,10→10)
|
||||
const monthNum = (index + 1).toString().padStart(2, '0');
|
||||
// 拼接成calendarList中的键格式(如2025-01)
|
||||
const yearMonthKey = `2025-${monthNum}`; // 若年份不固定,可改为props传递年份
|
||||
|
||||
// 判断calendarObj中该键对应的值:1→true,0→false,无该键则保持默认false
|
||||
if (calendarObj.hasOwnProperty(yearMonthKey)) {
|
||||
month.haveData = calendarObj[yearMonthKey] === 1;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
// 月份列表容器(flex布局,自动换行)
|
||||
.month-list {
|
||||
// 内联样式已优化行间距,此处可留空或补充其他样式
|
||||
}
|
||||
|
||||
// 基础月份样式
|
||||
.monthItem {
|
||||
width: 164px;
|
||||
height: 42px;
|
||||
border-radius: 4px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
cursor: pointer; // 鼠标悬浮手型
|
||||
transition: all 0.2s ease; // 过渡效果,样式切换更平滑
|
||||
border: 2px solid transparent; // 透明边框,避免选中时布局偏移
|
||||
margin: 0; // 清除默认外边距,进一步缩小缝隙
|
||||
}
|
||||
|
||||
// 有数据的样式(背景色#D1E8FF)
|
||||
.monthItem.has-data {
|
||||
background-color: #D1E8FF;
|
||||
}
|
||||
|
||||
// 无数据的样式(背景色#EFF3F8,基础样式默认值)
|
||||
.monthItem:not(.has-data) {
|
||||
background-color: #EFF3F8;
|
||||
}
|
||||
|
||||
// 本月样式(current类,边框2px solid #0B58FF)
|
||||
.monthItem.current {
|
||||
border: 2px solid #0B58FF !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style></style>
|
||||
340
src/views/home/components/indicatorDetails.vue
Normal file
340
src/views/home/components/indicatorDetails.vue
Normal file
@@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="指标填报详情" icon="cockpitItemIcon" size="indicatorDetailsBg" topSize="indicatorDetailsTitleBg">
|
||||
<div class="kpi-content" style="padding: 14px 14px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 查询表单区域 -->
|
||||
<div class="bottom"
|
||||
style="display: flex;gap: 8px; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);height: 64px;padding: 16px 16px;">
|
||||
<div style="width: 4px;height: 16px;background: #0B58FF;border-radius: 1px;margin-top: 10px;"></div>
|
||||
<el-form :inline="true" :model="form" class="demo-form-inline">
|
||||
<el-form-item label="所属层级">
|
||||
<el-select v-model="form.levelId" placeholder="请选择">
|
||||
<el-option v-for="item in levelLList" :key="item.id" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="填报月份">
|
||||
<el-date-picker v-model="form.month" type="month" placeholder="选择月" @change="handleMonthChange">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button style="background-color: #0B58FF;" type="primary" @click="onSubmit">查询</el-button>
|
||||
<!-- <el-button type="primary" plain size="medium">导入</el-button> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 表格操作区域 + 表格区域 -->
|
||||
<div class="bottom"
|
||||
style="display: flex; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);height: 772px;padding: 16px 16px;flex-direction: column; gap: 8px;">
|
||||
|
||||
<!-- 只读模式:显示编辑按钮 -->
|
||||
<div v-if="!isDetail" style="display: flex;gap: 8px;align-items: center;height: 32px;">
|
||||
<div style="width: 4px;height: 16px;background: #0B58FF;border-radius: 1px;"></div>
|
||||
<div style="width: 58px;
|
||||
height: 16px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: rgba(0,0,0,0.85);
|
||||
line-height: 16px;
|
||||
text-align: right;
|
||||
font-style: normal;">指标详情</div>
|
||||
<el-button style="background-color: #0B58FF;height: 32px;line-height: 10px;" type="primary"
|
||||
@click="handleEdit">编辑</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 编辑模式:显示快捷操作按钮 -->
|
||||
<div v-if="isDetail" style="display: flex;gap: 8px;align-items: center;height: 32px;">
|
||||
<div style="width: 4px;height: 16px;background: #0B58FF;border-radius: 1px;"></div>
|
||||
<div
|
||||
style="width: 58px;height: 16px;font-family: PingFangSC, PingFang SC;font-weight: 400;font-size: 14px;color: rgba(0,0,0,0.85);line-height: 16px;text-align: right;font-style: normal;">
|
||||
指标详情</div>
|
||||
<el-button style="background-color: #0B58FF;height: 32px;line-height: 10px;" type="primary"
|
||||
@click="handleSave">保存</el-button>
|
||||
<el-button text style="height: 32px;line-height: 10px;" plain size="medium"
|
||||
@click="handleCancel">取消</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 表格组件:添加key属性强制刷新,绑定所有必要属性 -->
|
||||
<base-table style="height: 700px;" @emitFun="inputChange" class="right-aside" :table-props="tableProps"
|
||||
:page="form.pageNo" :limit="form.pageSize" :table-data="tableData" ref="baseTable"
|
||||
:key="`base-table-${isDetail}`" :maxHeight="700"
|
||||
></base-table>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Container from './container.vue'
|
||||
import { getLevelStruc, getRealMonthPage, updateRealMonthData, getDictListData, } from '@/api/cockpit'
|
||||
import inputArea from './inputArea.vue' // 导入输入组件
|
||||
|
||||
export default {
|
||||
name: 'ProductionStatus',
|
||||
components: {
|
||||
Container,
|
||||
inputArea // 注册输入组件
|
||||
},
|
||||
props: {
|
||||
// 可保留原有props配置,若无需求可忽略
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
levelId: 1,
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
month: undefined,
|
||||
startTime: undefined, // 当月起始时间戳(1号00:00:00)
|
||||
endTime: undefined // 当月结束时间戳(月末23:59:59)
|
||||
},
|
||||
dictData:[],
|
||||
isDetail: false, // 编辑状态标识:false=只读,true=编辑
|
||||
tableData: [], // 表格数据
|
||||
levelLList: [], // 所属层级下拉数据
|
||||
tableProps: [] // 表格列配置
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 可选:监听isDetail变化,确保配置同步(双重保障)
|
||||
isDetail(newVal) {
|
||||
this.initTableProps(newVal);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 1. 初始化当前月份到日期选择器
|
||||
const currentDate = new Date();
|
||||
this.form.month = currentDate;
|
||||
// 2. 计算当月起止时间戳
|
||||
this.setMonthTimeStamp();
|
||||
// 3. 先初始化表格配置(优先于数据请求,避免表格空配置渲染)
|
||||
this.initTableProps(this.isDetail);
|
||||
// 4. 等待配置就绪后,再请求数据,避免异步冲突
|
||||
this.getDictData()
|
||||
this.$nextTick(() => {
|
||||
this.getData();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getDictData() {
|
||||
getDictListData({ pageNo: 1, pageSize: 100, dictType: 'lb_dw' }).then((res) => {
|
||||
this.dictData = res.data.list
|
||||
})
|
||||
},
|
||||
// 表格单元格数据变更回调
|
||||
inputChange(val) {
|
||||
console.log('修改的数据:', val);
|
||||
// 安全修改:判断索引是否存在,避免数组越界
|
||||
if (this.tableData[val._pageIndex - 1]) {
|
||||
this.tableData[val._pageIndex - 1][val.prop] = val[val.prop];
|
||||
// 标记数据为已修改状态
|
||||
this.tableData[val._pageIndex - 1].status = 1;
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化表格列配置(核心:精准控制inputArea挂载)
|
||||
initTableProps(isEdit) {
|
||||
console.log('当前编辑状态:', isEdit);
|
||||
|
||||
// 基础表格列配置(只读模式使用)
|
||||
const baseTableProps = [
|
||||
{ prop: 'type', label: '指标类型', align: 'center' },
|
||||
{ prop: 'name', label: '指标名称', align: 'center' },
|
||||
{ prop: 'unitLabel', label: '单位', align: 'center' },
|
||||
{ prop: 'value', label: '实际值', align: 'center' },
|
||||
];
|
||||
|
||||
if (isEdit) {
|
||||
// 编辑模式:仅给「预估值」列添加inputArea(精准挂载,避免无效配置)
|
||||
this.tableProps = baseTableProps.map(item => {
|
||||
if (item.prop === 'value') { // 只给需要编辑的列添加子组件
|
||||
return {
|
||||
...item,
|
||||
subcomponent: inputArea // 挂载输入组件
|
||||
};
|
||||
}
|
||||
return item; // 其他列保持原有配置
|
||||
});
|
||||
} else {
|
||||
// 只读模式:深拷贝基础配置,避免引用污染
|
||||
this.tableProps = JSON.parse(JSON.stringify(baseTableProps));
|
||||
}
|
||||
console.log('表格配置:', this.tableProps);
|
||||
},
|
||||
|
||||
// 切换到编辑模式
|
||||
handleEdit() {
|
||||
this.isDetail = true;
|
||||
// 先更新表格配置,再强制表格刷新(双重保障)
|
||||
this.initTableProps(this.isDetail);
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.baseTable) {
|
||||
this.$refs.baseTable.$forceUpdate(); // 强制表格组件刷新
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSave() {
|
||||
this.$modal.confirm('是否确认保存数据?').then(() => {
|
||||
return updateRealMonthData(this.tableData)
|
||||
}).then(() => {
|
||||
this.isDetail = false;
|
||||
// 重置表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 清空并重新请求数据,恢复原始状态
|
||||
this.$nextTick(() => {
|
||||
this.tableData = [];
|
||||
this.getData();
|
||||
});
|
||||
this.$modal.msgSuccess("保存成功");
|
||||
}).catch(() => { });
|
||||
},
|
||||
// 取消编辑,恢复只读模式
|
||||
handleCancel() {
|
||||
this.isDetail = false;
|
||||
// 重置表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 清空并重新请求数据,恢复原始状态
|
||||
this.$nextTick(() => {
|
||||
this.tableData = [];
|
||||
this.getData();
|
||||
});
|
||||
console.log('已取消编辑,恢复原始数据');
|
||||
},
|
||||
handleClear() {
|
||||
this.isDetail = false;
|
||||
// 重置表格配置
|
||||
this.initTableProps(this.isDetail);
|
||||
// 清空并重新请求数据,恢复原始状态
|
||||
this.$nextTick(() => {
|
||||
this.tableData = [];
|
||||
this.getData();
|
||||
});
|
||||
},
|
||||
|
||||
// 通用方法:计算指定月份(默认当前月)的起止时间戳
|
||||
setMonthTimeStamp(selectDate) {
|
||||
let targetDate;
|
||||
if (selectDate) {
|
||||
targetDate = new Date(selectDate); // 传入选中日期,计算对应月份
|
||||
} else {
|
||||
targetDate = new Date(); // 未传入,使用当前系统日期
|
||||
}
|
||||
const year = targetDate.getFullYear();
|
||||
const month = targetDate.getMonth(); // 月份0-11
|
||||
|
||||
// 计算当月1号 00:00:00 时间戳
|
||||
const startDate = new Date(year, month, 1, 0, 0, 0);
|
||||
this.form.startTime = startDate.getTime();
|
||||
|
||||
// 计算当月最后一天 23:59:59 时间戳(精准版)
|
||||
const lastDay = new Date(year, month + 1, 0).getDate();
|
||||
const endDatePrecise = new Date(year, month, lastDay, 23, 59, 59);
|
||||
this.form.endTime = endDatePrecise.getTime();
|
||||
},
|
||||
|
||||
// 日期选择器变更事件:更新对应月份的起止时间戳
|
||||
handleMonthChange(val) {
|
||||
if (!val) {
|
||||
// 清空选择时,重置时间戳
|
||||
this.form.startTime = undefined;
|
||||
this.form.endTime = undefined;
|
||||
return;
|
||||
}
|
||||
// 计算选中月份的起止时间戳
|
||||
this.setMonthTimeStamp(val);
|
||||
},
|
||||
getUnitLabel(unitCode) {
|
||||
// 若字典为空或无匹配编码,返回原编码或空字符串
|
||||
if (!this.dictData || this.dictData.length === 0) {
|
||||
return unitCode || '';
|
||||
}
|
||||
// 查找匹配的字典项
|
||||
const matchItem = this.dictData.find(item => item.value == unitCode);
|
||||
// 返回匹配的label,无匹配则返回原unit编码
|
||||
return matchItem ? matchItem.label : (unitCode || '');
|
||||
},
|
||||
// 请求下拉数据和表格数据
|
||||
getData() {
|
||||
// 1. 请求所属层级下拉数据
|
||||
getLevelStruc().then((res) => {
|
||||
console.log('所属层级数据:', res);
|
||||
this.levelLList = res.data || [];
|
||||
}).catch(err => {
|
||||
console.error('获取所属层级失败:', err);
|
||||
this.levelLList = [];
|
||||
});
|
||||
|
||||
// 2. 请求表格分页数据
|
||||
getRealMonthPage({
|
||||
levelId: this.form.levelId,
|
||||
startTime: this.form.startTime,
|
||||
endTime: this.form.endTime,
|
||||
pageSize: this.form.pageSize,
|
||||
pageNo: this.form.pageNo
|
||||
}).then((res) => {
|
||||
console.log('表格数据:', res);
|
||||
this.tableData = res.data.map(item => {
|
||||
// 新增unitLabel字段,存储匹配后的显示名称
|
||||
return {
|
||||
...item,
|
||||
unitLabel: this.getUnitLabel(item.unit)
|
||||
};
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error('获取表格数据失败:', err);
|
||||
this.tableData = [];
|
||||
});
|
||||
},
|
||||
|
||||
// 查询按钮点击事件(可根据需求扩展逻辑)
|
||||
onSubmit() {
|
||||
// 清空原有表格数据,重新请求
|
||||
this.tableData = [];
|
||||
this.$nextTick(() => {
|
||||
this.getData();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
// 月份列表容器样式(保留原有配置,若无使用可忽略)
|
||||
.month-list {
|
||||
// 内联样式已优化行间距,此处可留空或补充
|
||||
}
|
||||
|
||||
// 基础月份样式(保留原有配置,若无使用可忽略)
|
||||
.monthItem {
|
||||
width: 164px;
|
||||
height: 42px;
|
||||
border-radius: 4px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 2px solid transparent;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monthItem.has-data {
|
||||
background-color: #D1E8FF;
|
||||
}
|
||||
|
||||
.monthItem:not(.has-data) {
|
||||
background-color: #EFF3F8;
|
||||
}
|
||||
|
||||
.monthItem.active {
|
||||
border: 2px solid #0B58FF !important;
|
||||
}
|
||||
</style>
|
||||
38
src/views/home/components/inputArea.vue
Normal file
38
src/views/home/components/inputArea.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
<template>
|
||||
<div class="tableInner">
|
||||
<el-input v-model="list[itemProp]" @blur="changeInput" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'InputArea',
|
||||
props: {
|
||||
injectData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
itemProp: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: this.injectData
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeInput() {
|
||||
console.log(this.list)
|
||||
this.$emit('emitData', this.list)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.tableInner .el-input__inner {
|
||||
border: none;
|
||||
padding: 0;
|
||||
height: 33px;
|
||||
}
|
||||
</style>
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -81,11 +81,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -197,7 +197,7 @@ export default {
|
||||
lineStyle: {
|
||||
color: 'rgba(98, 213, 180, 1)', // 加深颜色
|
||||
width: 2,
|
||||
type: 'dashed' // 目标线使用虚线
|
||||
// type: 'dashed' // 目标线使用虚线
|
||||
},
|
||||
itemStyle: {
|
||||
color: 'rgba(98, 213, 180, 1)',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="barTop">
|
||||
<div class="title">生产指标趋势</div>
|
||||
<div class="button-group">
|
||||
<div class="item-button" :class="{ active: activeButton === 0 }" @click="activeButton = 0">总成本</div>
|
||||
<div class="item-button" :class="{ active: activeButton === 0 }" @click="activeButton = 0">制造成本</div>
|
||||
<div class="button-line lineOne" v-if="activeButton !== 0 && activeButton !== 1"></div>
|
||||
<div class="item-button" :class="{ active: activeButton === 1 }" @click="activeButton = 1">原片成本</div>
|
||||
<div class="button-line lineTwo" v-if="activeButton !== 1 && activeButton !== 2"></div>
|
||||
@@ -44,7 +44,7 @@ export default {
|
||||
selectedChartData() {
|
||||
// 定义按钮索引与lineData中key的映射关系
|
||||
const dataKeyMap = [
|
||||
'总成本',
|
||||
'制造成本',
|
||||
'原片成本',
|
||||
'加工成本',
|
||||
'原片成品率',
|
||||
|
||||
@@ -118,11 +118,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -93,11 +93,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -71,8 +71,8 @@ export default {
|
||||
// 定义一个映射关系,将后端字段名与前端显示信息关联起来
|
||||
const dataMap = [
|
||||
{
|
||||
key: 'totalCost',
|
||||
unit: '总成本·元/㎡',
|
||||
key: 'processCost',
|
||||
unit: '制造成本·元/㎡',
|
||||
route: '/productionCostAnalysis/productionCostAnalysis'
|
||||
},
|
||||
{
|
||||
|
||||
@@ -90,11 +90,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :factory="factory" :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,7 +185,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: {show:true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
}
|
||||
|
||||
this.myChart = echarts.init(chartDom);
|
||||
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
console.log('chartData', this.chartData);
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: {show:true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -84,10 +84,10 @@ export default {
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
top: 40,
|
||||
bottom: 40,
|
||||
right: 70,
|
||||
left: 60,
|
||||
top: 30,
|
||||
bottom: 50,
|
||||
right: 20,
|
||||
left: 40,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<relatedIndicatorsAnalysis :relatedData="relatedData" :title="'相关指标分析·单位/万元'" />
|
||||
<relatedIndicatorsAnalysis :factory="factory" :relatedData="relatedData" :title="'相关指标分析·单位/万元'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -173,7 +173,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
@@ -188,7 +188,7 @@ export default {
|
||||
// sort: 1,
|
||||
paramName: '全成本',
|
||||
paramList: ['制造成本', '财务费用', '销售费用', '管理费用', '运费'],
|
||||
baseId: 2,
|
||||
baseId: this.factory,
|
||||
// baseId: Number(this.factory),
|
||||
};
|
||||
// 调用接口
|
||||
|
||||
@@ -125,7 +125,7 @@ export default {
|
||||
// 重构 chartD:替换硬编码数据为动态解析数据
|
||||
chartD() {
|
||||
// 获取动态解析的趋势数据
|
||||
const { months, rates, reals, targets, flags } = this.trendParsedData;
|
||||
const { months, rates, reals, targets, flags,diffs } = this.trendParsedData;
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
@@ -191,7 +191,7 @@ export default {
|
||||
height: 20,
|
||||
// 关键:去掉换行,让文字在一行显示,适配小尺寸
|
||||
formatter: function (params) {
|
||||
const diff = data.diffs || [];
|
||||
const diff = diffs || [];
|
||||
const currentDiff = diff[params.dataIndex] || 0;
|
||||
return `{rate|${currentDiff}}{text|差值}`;
|
||||
},
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<!-- 新增:topItem 专属包裹容器,统一控制样式和布局 -->
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left"
|
||||
@click="handleDashboardClick('/productionCostAnalysis/productionCostAnalysisBase')">
|
||||
<div class="title">
|
||||
制造成本·单位/万元
|
||||
</div>
|
||||
@@ -17,7 +18,7 @@
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/expenseAnalysis/expenseAnalysisBase')">
|
||||
<div class="title">
|
||||
财务费用·单位/万元
|
||||
</div>
|
||||
@@ -28,7 +29,7 @@
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/expenseAnalysis/expenseAnalysisBase')">
|
||||
<div class="title">
|
||||
销售费用·单位/万元
|
||||
</div>
|
||||
@@ -39,7 +40,7 @@
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/expenseAnalysis/expenseAnalysisBase')">
|
||||
<div class="title">
|
||||
管理费用·单位/万元
|
||||
</div>
|
||||
@@ -84,6 +85,10 @@ export default {
|
||||
relatedTotal: {} // 兜底累计数据
|
||||
})
|
||||
},
|
||||
factory: {
|
||||
type: [Number,String],
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -127,6 +132,14 @@ export default {
|
||||
// 无需额外操作,初始化数据已赋值
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory
|
||||
}
|
||||
})
|
||||
},
|
||||
handleRoute(path) {
|
||||
this.$router.push({
|
||||
path: path
|
||||
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
}
|
||||
|
||||
// 解构数据,避免重复取值
|
||||
const { diff, completeRate: rate, real, target, flag } = this.detailData;
|
||||
const { diff, completeRate, real, target, flag } = this.detailData;
|
||||
// 确保数值为数字类型
|
||||
const realValue = Number(real) || 0;
|
||||
const targetValue = Number(target) || 0;
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :factory="factory" :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -187,7 +187,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px; width: 100%;">
|
||||
<!-- 累计指标1 -->
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/operatingRevenue/operatingRevenueBase')">
|
||||
<div class="title">
|
||||
收入·单位/万元
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 累计指标2 -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/fullCostAnalysis/fullCostAnalysisBase')">
|
||||
<div class="title">
|
||||
全成本·单位/万元
|
||||
</div>
|
||||
@@ -39,10 +39,14 @@ export default {
|
||||
type: Array,
|
||||
// 正确写法:默认值通过 factory 函数返回(才能调用 default())
|
||||
default: () => [
|
||||
{ title: "累计收入", budget: 0, real: 0, rate: 0, diff: 0 },
|
||||
{ title: "收入", budget: 0, real: 0, rate: 0, diff: 0 },
|
||||
{ title: "累计全成本", budget: 0, real: 0, rate: 0, diff: 0 }
|
||||
]
|
||||
},
|
||||
factory: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -50,7 +54,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ytdIncomeData: { title: "累计收入", budget: 0, real: 0, rate: 0, diff: 0, flag: 0 },
|
||||
ytdIncomeData: { title: "收入", budget: 0, real: 0, rate: 0, diff: 0, flag: 0 },
|
||||
ytdCostData: { title: "累计全成本", budget: 0, real: 0, rate: 0, diff: 0, flag: 0 }
|
||||
}
|
||||
},
|
||||
@@ -67,6 +71,14 @@ export default {
|
||||
this.updateChart(this.monthAnalysis)
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory
|
||||
}
|
||||
})
|
||||
},
|
||||
getRateFlag(rate) {
|
||||
if (isNaN(rate) || rate === null || rate === undefined) return 0;
|
||||
return +(rate >= 100 || rate === 0); // + 号将布尔值转为数字(true→1,false→0)
|
||||
@@ -81,8 +93,8 @@ export default {
|
||||
: this.$props.monthAnalysis; // 直接取 props 默认值
|
||||
|
||||
// 提取累计收入(第0项)、累计全成本(第1项)数据
|
||||
const incomeItem = validData[0] || { title: "累计收入", budget: 0, real: 0, rate: 0, diff: 0 };
|
||||
const costItem = validData[1] || { title: "累计全成本", budget: 0, real: 0, rate: 0, diff: 0 };
|
||||
const incomeItem = validData[0] || { title: "收入", budget: 0, real: 0, rate: 0, diff: 0 };
|
||||
const costItem = validData[1] || { title: "全成本", budget: 0, real: 0, rate: 0, diff: 0 };
|
||||
|
||||
// 整合flag字段
|
||||
this.ytdIncomeData = {
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
|
||||
// 路由跳转时携带序号(或名称+序号)
|
||||
this.$router.push({
|
||||
path: 'operatingRevenueBase',
|
||||
path: 'grossMarginBase',
|
||||
query: { // 使用query传递参数(推荐),也可使用params
|
||||
// baseName: itemName,
|
||||
factory: baseIndex
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
}
|
||||
|
||||
this.myChart = echarts.init(chartDom);
|
||||
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
console.log('chartData', this.chartData);
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px; width: 100%;">
|
||||
<!-- 收入模块(传递整合了flag的incomeData) -->
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/operatingRevenue/operatingRevenueBase')">
|
||||
<div class="title">
|
||||
收入·单位/万元
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 全成本模块(传递整合了flag的totalCostData) -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/fullCostAnalysis/fullCostAnalysisBase')">
|
||||
<div class="title">
|
||||
全成本·单位/万元
|
||||
</div>
|
||||
@@ -76,6 +76,14 @@ export default {
|
||||
this.updateChart(this.ytdAnalysis)
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory
|
||||
}
|
||||
})
|
||||
},
|
||||
// 保留原flag判断逻辑(≥100返回1,<100返回0)
|
||||
getRateFlag(rate) {
|
||||
if (isNaN(rate) || rate === null || rate === undefined) return 0;
|
||||
|
||||
263
src/views/home/indicatorSubmissionDetails.vue
Normal file
263
src/views/home/indicatorSubmissionDetails.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div id="dayReport" class="dayReport" :style="styles">
|
||||
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
|
||||
<ReportHeader top-title="指标填报" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
|
||||
:isBudget="false" />
|
||||
<div class="main-body" style="
|
||||
flex: 1;
|
||||
display: flex;
|
||||
padding: 0px 16px 0 272px;
|
||||
flex-direction: column;
|
||||
">
|
||||
<div class="top" style="margin-top: -20px; display: flex; gap: 16px">
|
||||
<div class="top-three" style="
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns:416px 1192px;
|
||||
">
|
||||
<indicatorCalendar :calendarList="calendarList" />
|
||||
<indicatorDetails />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="top" style="margin-top: -20px; display: flex; gap: 16px">
|
||||
<div class="top-three" style="
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns:416px 1192px;
|
||||
">
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="centerImg" style="
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1; /* 确保在 backp 之上、内容之下 */
|
||||
"></div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import ReportHeader from "./components/budgetHeader.vue";
|
||||
import { Sidebar } from "../../layout/components";
|
||||
import screenfull from "screenfull";
|
||||
import indicatorCalendar from "./components/indicatorCalendar.vue";
|
||||
import indicatorDetails from "./components/indicatorDetails.vue";
|
||||
|
||||
// import premProdStatus from "./components/premProdStatus.vue";
|
||||
import { mapState } from "vuex";
|
||||
// import operatingLineChart from "../operatingComponents/operatingLineChart";
|
||||
// import operatingLineChartCumulative from "../operatingComponents/operatingLineChartCumulative.vue";
|
||||
|
||||
import { getRealMonthCalendar } from '@/api/cockpit'
|
||||
import moment from "moment";
|
||||
export default {
|
||||
name: "DayReport",
|
||||
components: {
|
||||
ReportHeader,
|
||||
indicatorCalendar,
|
||||
indicatorDetails,
|
||||
// operatingLineChartCumulative,
|
||||
// operatingLineChart,
|
||||
// premProdStatus,
|
||||
Sidebar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
weekArr: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
isFullScreen: false,
|
||||
timer: null,
|
||||
beilv: 1,
|
||||
value: 100,
|
||||
sort:1,
|
||||
selectDate:{},
|
||||
monthData: {},
|
||||
ytdData: {},
|
||||
calendarList:{},
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
this.windowWidth(document.documentElement.clientWidth);
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
theme: (state) => state.settings.theme,
|
||||
sideTheme: (state) => state.settings.sideTheme,
|
||||
sidebar: (state) => state.app.sidebar,
|
||||
device: (state) => state.app.device,
|
||||
needTagsView: (state) => state.settings.tagsView,
|
||||
fixedHeader: (state) => state.settings.fixedHeader,
|
||||
}),
|
||||
classObj() {
|
||||
return {
|
||||
hideSidebar: !this.sidebar.opened,
|
||||
openSidebar: this.sidebar.opened,
|
||||
withoutAnimation: this.sidebar.withoutAnimation,
|
||||
mobile: this.device === "mobile",
|
||||
};
|
||||
},
|
||||
variables() {
|
||||
return variables;
|
||||
},
|
||||
// ...mapGetters(['sidebar']),
|
||||
styles() {
|
||||
const v = Math.floor(this.value * this.beilv * 100) / 10000;
|
||||
return {
|
||||
transform: `scale(${v})`,
|
||||
transformOrigin: "left top",
|
||||
// overflow: hidden;
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
clientWidth(val) {
|
||||
if (!this.timer) {
|
||||
this.clientWidth = val;
|
||||
this.beilv2 = this.clientWidth / 1920;
|
||||
this.timer = true;
|
||||
let _this = this;
|
||||
setTimeout(function () {
|
||||
_this.timer = false;
|
||||
}, 500);
|
||||
}
|
||||
// 这里可以添加修改时的方法
|
||||
this.windowWidth(val);
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer);
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
const _this = this;
|
||||
_this.beilv = document.documentElement.clientWidth / 1920;
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
_this.clientWidth = `${document.documentElement.clientWidth}`;
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
// sortChange(value) {
|
||||
// this.sort = value
|
||||
// this.getData()
|
||||
// },
|
||||
getData() {
|
||||
getRealMonthCalendar().then((res) => {
|
||||
console.log(res, 'res');
|
||||
this.calendarList = res.data
|
||||
})
|
||||
// getSalesRevenueGroupData({
|
||||
// startTime: this.selectDate.startTime,
|
||||
// endTime: this.selectDate.endTime,
|
||||
// sort: this.sort,
|
||||
// index: undefined,
|
||||
// factory: undefined
|
||||
// // timeDim: obj.mode
|
||||
// }).then((res) => {
|
||||
// console.log(res);
|
||||
// this.monthData= res.data.month
|
||||
// this.ytdData = res.data.ytd
|
||||
// })
|
||||
},
|
||||
handleTimeChange(obj) {
|
||||
console.log(obj, 'obj');
|
||||
this.selectDate = obj
|
||||
this.getData()
|
||||
},
|
||||
handleClickOutside() {
|
||||
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
|
||||
},
|
||||
windowWidth(value) {
|
||||
this.clientWidth = value;
|
||||
this.beilv2 = this.clientWidth / 1920;
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen;
|
||||
},
|
||||
init() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: "you browser can not work",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.on("change", this.change);
|
||||
},
|
||||
destroy() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: "you browser can not work",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.off("change", this.change);
|
||||
},
|
||||
// 全屏
|
||||
screenfullChange() {
|
||||
console.log("screenfull.enabled", screenfull.isEnabled);
|
||||
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: "you browser can not work",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.toggle(this.$refs.dayReportB);
|
||||
},
|
||||
// 导出
|
||||
// exportPDF() {
|
||||
// this.$message.success('正在导出,请稍等!')
|
||||
// const element = document.getElementById('dayRepDom')
|
||||
// element.style.display = 'block'
|
||||
// const fileName = '株洲碲化镉生产日报' + moment().format('yyMMDD') + '.pdf'
|
||||
// html2canvas(element, {
|
||||
// dpi: 300, // Set to 300 DPI
|
||||
// scale: 3 // Adjusts your resolution
|
||||
// }).then(function(canvas) {
|
||||
// const imgWidth = 595.28
|
||||
// const imgHeight = 841.89
|
||||
// const pageData = canvas.toDataURL('image/jpeg', 1.0)
|
||||
// const PDF = new JsPDF('', 'pt', [imgWidth, imgHeight])
|
||||
// PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
|
||||
// setTimeout(() => {
|
||||
// PDF.save(fileName) // 导出文件名
|
||||
// }, 1000)
|
||||
// })
|
||||
// element.style.display = 'none'
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "~@/assets/styles/mixin.scss";
|
||||
@import "~@/assets/styles/variables.scss";
|
||||
.dayReport {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: url("../../assets/img/backp.png") no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
.hideSidebar .fixed-header {
|
||||
width: calc(100% - 54px);
|
||||
}
|
||||
|
||||
.sidebarHide .fixed-header {
|
||||
width: calc(100%);
|
||||
}
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -184,7 +184,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
}
|
||||
|
||||
this.myChart = echarts.init(chartDom);
|
||||
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
console.log('chartData', this.chartData);
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :relatedMon="relatedMon" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :relatedTotal="relatedTotal" :title="'累计·相关指标分析'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :relatedMon="relatedMon" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :factory="factory" :relatedTotal="relatedTotal" :title="'累计·相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,7 +178,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
@@ -193,7 +193,7 @@ export default {
|
||||
// sort: 1,
|
||||
paramName: '净价',
|
||||
paramList: this.paramList,
|
||||
baseId: 2,
|
||||
baseId: this.factory,
|
||||
// baseId: Number(this.factory),
|
||||
};
|
||||
// 调用接口
|
||||
|
||||
@@ -74,12 +74,13 @@ export default {
|
||||
// 1. 校验数据有效性
|
||||
if (!this.trendData || !this.selectedProfit) {
|
||||
return {
|
||||
diffs:[],
|
||||
|
||||
months: [], // 月份数组(x轴标签)
|
||||
rates: [], // 完成率(completeRate)
|
||||
reals: [], // 实际值(real)
|
||||
targets: [], // 目标值(target)
|
||||
flags: [] // 达标状态
|
||||
flags: [], // 达标状态
|
||||
diffs: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -121,7 +122,7 @@ export default {
|
||||
// 重构 chartD:替换硬编码数据为动态解析数据
|
||||
chartD() {
|
||||
// 获取动态解析的趋势数据
|
||||
const { months, rates, reals, targets, flags } = this.trendParsedData;
|
||||
const { months, rates, reals, targets, flags, diffs } = this.trendParsedData;
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
@@ -187,7 +188,7 @@ export default {
|
||||
height: 20,
|
||||
// 关键:去掉换行,让文字在一行显示,适配小尺寸
|
||||
formatter: function (params) {
|
||||
const diff = data.diffs || [];
|
||||
const diff = diffs || [];
|
||||
const currentDiff = diff[params.dataIndex] || 0;
|
||||
return `{rate|${currentDiff}}{text|差值}`;
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<!-- 新增:topItem 专属包裹容器,统一控制样式和布局 -->
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div class="title">
|
||||
单价·单位/万元
|
||||
</div>
|
||||
@@ -50,6 +50,10 @@ export default {
|
||||
运费: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
})
|
||||
},
|
||||
factory: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -82,6 +86,14 @@ export default {
|
||||
this.$nextTick(() => this.updateChart())
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 判断完成率对应的flag值(<100为0,≥100为1)
|
||||
* @param {number} rate 完成率(原始值,如89代表89%)
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
}
|
||||
|
||||
// 解构数据,避免重复取值
|
||||
const { diff, completeRate: rate, real, target, flag } = this.detailData;
|
||||
const { diff, completeRate, real, target, flag } = this.detailData;
|
||||
// 确保数值为数字类型
|
||||
const realValue = Number(real) || 0;
|
||||
const targetValue = Number(target) || 0;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<!-- 新增:topItem 专属包裹容器,统一控制样式和布局 -->
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div class="title">
|
||||
单价·单位/万元
|
||||
</div>
|
||||
@@ -50,6 +50,10 @@ export default {
|
||||
运费: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
})
|
||||
},
|
||||
factory: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -82,6 +86,14 @@ export default {
|
||||
this.$nextTick(() => this.updateChart())
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 判断完成率对应的flag值(<100为0,≥100为1)
|
||||
* @param {number} rate 完成率(原始值,如89代表89%)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px; width: 100%;">
|
||||
<!-- 销量模块(直接传递整合了flag的salesData) -->
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')">
|
||||
<div class="title">
|
||||
销量·单位/万元
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 单价模块(直接传递整合了flag的unitPriceData) -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div class="title">
|
||||
单价·单位/万元
|
||||
</div>
|
||||
@@ -46,6 +46,10 @@ export default {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
factory: {
|
||||
type: [String,Number],
|
||||
default: ''
|
||||
},
|
||||
month: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -72,6 +76,14 @@ export default {
|
||||
this.updateChart(this.monthAnalysis)
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory
|
||||
}
|
||||
})
|
||||
},
|
||||
// 判断flag的核心方法
|
||||
getRateFlag(rate) {
|
||||
if (isNaN(rate) || rate === null || rate === undefined) return 0;
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
}
|
||||
|
||||
this.myChart = echarts.init(chartDom);
|
||||
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
console.log('chartData', this.chartData);
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -92,10 +92,10 @@ export default {
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
top: 40,
|
||||
bottom: 40,
|
||||
right: 70,
|
||||
left: 60,
|
||||
top: 20,
|
||||
bottom: 60,
|
||||
right: 20,
|
||||
left: 40,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px; width: 100%;">
|
||||
<!-- 销量模块(直接传递整合了flag的salesData) -->
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')">
|
||||
<div class="title">
|
||||
销量·单位/万元
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 单价模块(直接传递整合了flag的unitPriceData) -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div class="title">
|
||||
单价·单位/万元
|
||||
</div>
|
||||
@@ -72,6 +72,14 @@ export default {
|
||||
this.updateChart(this.ytdAnalysis)
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : 5
|
||||
}
|
||||
})
|
||||
},
|
||||
// 判断flag的核心方法
|
||||
getRateFlag(rate) {
|
||||
if (isNaN(rate) || rate === null || rate === undefined) return 0;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<relatedIndicatorsAnalysis :relatedData="relatedData" :title="'相关指标分析·单位/万元'" />
|
||||
<relatedIndicatorsAnalysis :factory="factory" :relatedData="relatedData" :title="'相关指标分析·单位/万元'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,7 +174,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
@@ -193,7 +193,7 @@ export default {
|
||||
"经营性利润",
|
||||
],
|
||||
// paramList: ['制造成本', '财务费用', '销售费用', '管理费用', '运费'],
|
||||
levelId: this.levelId,
|
||||
levelId: this.factory,
|
||||
// baseId: Number(this.factory),
|
||||
};
|
||||
// 调用接口
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -156,14 +156,14 @@ export default {
|
||||
},
|
||||
scale: true,
|
||||
splitNumber: 4,
|
||||
axisTick: { show: false },
|
||||
axisTick: { show: true },
|
||||
axisLabel: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -172,14 +172,14 @@ export default {
|
||||
fontSize: 12,
|
||||
align: 'left'
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisTick: { show: true },
|
||||
axisLabel: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -87,7 +87,7 @@ export default {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
left: 30,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<!-- 横向滚动容器:适配多组件排列 -->
|
||||
<div class="topItem-container" style="display: flex; gap: 8px; ">
|
||||
<!-- 1. 销量组件:传递当前激活数据集中的销量数据 -->
|
||||
<div class="dashboard left">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')">
|
||||
<div class="title">
|
||||
销量·单位/万元
|
||||
</div>
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2. 单价组件:传递当前激活数据集中的单价数据 -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div class="title">
|
||||
单价·单位/万元
|
||||
</div>
|
||||
@@ -24,7 +24,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 3. 成本组件:传递当前激活数据集中的成本数据 -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right"
|
||||
@click="handleDashboardClick('/productionCostAnalysis/productionCostAnalysisBase')">
|
||||
<div class="title">
|
||||
成本·单位/万元
|
||||
</div>
|
||||
@@ -33,7 +34,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 4. 管理费用组件:传递当前激活数据集中的管理费用数据 -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/expenseAnalysis/expenseAnalysisBase')">
|
||||
<div class="title">
|
||||
管理费用·单位/万元
|
||||
</div>
|
||||
@@ -42,7 +43,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 5. 销售费用组件:传递当前激活数据集中的销售费用数据 -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/expenseAnalysis/expenseAnalysisBase')">
|
||||
<div class="title">
|
||||
销售费用·单位/万元
|
||||
</div>
|
||||
@@ -51,7 +52,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 6. 财务费用组件:传递当前激活数据集中的财务费用数据 -->
|
||||
<div class="dashboard right">
|
||||
<div class="dashboard right" @click="handleDashboardClick('/expenseAnalysis/expenseAnalysisBase')">
|
||||
<div class="title">
|
||||
财务费用·单位/万元
|
||||
</div>
|
||||
@@ -81,6 +82,10 @@ export default {
|
||||
relatedTotal: [] // 累计数据(数组格式,存储销量/单价等数据)
|
||||
})
|
||||
},
|
||||
factory: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 可选:动态标题
|
||||
title: {
|
||||
type: String,
|
||||
@@ -164,6 +169,14 @@ export default {
|
||||
console.log('组件挂载时的激活数据:', this.activeData);
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this,factory
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Tab 切换处理函数
|
||||
* @param {String} value 切换值('month' = 月度,'total' = 累计,可根据实际Tab值调整)
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :factory="factory" :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -187,7 +187,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -173,7 +173,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -76,12 +76,13 @@ export default {
|
||||
// 1. 校验数据有效性
|
||||
if (!this.trendData || !this.selectedProfit) {
|
||||
return {
|
||||
diffs: [],
|
||||
|
||||
months: [], // 月份数组(x轴标签)
|
||||
rates: [], // 完成率(completeRate)
|
||||
reals: [], // 实际值(real)
|
||||
targets: [], // 目标值(target)
|
||||
flags: [] // 达标状态
|
||||
flags: [], // 达标状态
|
||||
diffs: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ export default {
|
||||
// 重构 chartD:替换硬编码数据为动态解析数据
|
||||
chartD() {
|
||||
// 获取动态解析的趋势数据
|
||||
const { months, rates, reals, targets, flags } = this.trendParsedData;
|
||||
const { months, rates, reals, targets, flags, diffs } = this.trendParsedData;
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
@@ -190,7 +191,7 @@ export default {
|
||||
height: 20,
|
||||
// 关键:去掉换行,让文字在一行显示,适配小尺寸
|
||||
formatter: function (params) {
|
||||
const diff = data.diffs || [];
|
||||
const diff = diffs || [];
|
||||
const currentDiff = diff[params.dataIndex] || 0;
|
||||
return `{rate|${currentDiff}}{text|差值}`;
|
||||
},
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
formatter: '{value}%'
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
}
|
||||
],
|
||||
|
||||
@@ -83,11 +83,11 @@ export default {
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 30,
|
||||
right: 70,
|
||||
left: 40,
|
||||
right: 20,
|
||||
left: 60,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
},
|
||||
// 右侧Y轴:利润占比(百分比)
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
}
|
||||
|
||||
// 解构数据,避免重复取值
|
||||
const { diff, completeRate: rate, real, target, flag } = this.detailData;
|
||||
const { diff, completeRate, real, target, flag } = this.detailData;
|
||||
// 确保数值为数字类型
|
||||
const realValue = Number(real) || 0;
|
||||
const targetValue = Number(target) || 0;
|
||||
|
||||
@@ -183,6 +183,7 @@ export default {
|
||||
})();
|
||||
};
|
||||
console.log(this.$route.query.name, 'name');
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<!-- <monthlyRelatedMetrics :itemData="renderList" :title="'月度·相关指标分析'" /> -->
|
||||
<relatedIndicatorsAnalysis :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
<relatedIndicatorsAnalysis :factory="factory" :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -182,6 +182,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -182,6 +182,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<!-- <monthlyRelatedMetrics :itemData="renderList" :title="'月度·相关指标分析'" /> -->
|
||||
<relatedIndicatorsAnalysis :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
<relatedIndicatorsAnalysis :factory="factory" :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -182,6 +182,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -166,6 +166,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<!-- <monthlyRelatedMetrics :itemData="renderList" :title="'月度·相关指标分析'" /> -->
|
||||
<relatedIndicatorsAnalysis :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
<relatedIndicatorsAnalysis :factory="factory" :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -184,7 +184,7 @@ export default {
|
||||
};
|
||||
console.log('this.$route.query.factory', this.$route.query.factory);
|
||||
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :relatedData="monthRelatedData" :title="'月度概览'" />
|
||||
<yearRelatedMetrics :relatedData="totalRelatedData" :title="'累计概览'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :relatedData="monthRelatedData" :title="'月度概览'" />
|
||||
<yearRelatedMetrics :factory="factory" :relatedData="totalRelatedData" :title="'累计概览'" />
|
||||
|
||||
|
||||
</div>
|
||||
@@ -183,7 +183,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :relatedData="monthRelatedData" :title="'月度概览'" />
|
||||
<yearRelatedMetrics :relatedData="totalRelatedData" :title="'累计概览'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :relatedData="monthRelatedData" :title="'月度概览'" />
|
||||
<yearRelatedMetrics :factory="factory" :relatedData="totalRelatedData" :title="'累计概览'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom" style="display: flex; gap: 16px;margin-top: 6px;">
|
||||
|
||||
@@ -168,6 +168,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<!-- <monthlyRelatedMetrics :itemData="renderList" :title="'月度·相关指标分析'" /> -->
|
||||
<relatedIndicatorsAnalysis :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
<relatedIndicatorsAnalysis :factory="factory" :relatedData="relatedData" :title="'相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -184,7 +184,7 @@ export default {
|
||||
};
|
||||
console.log('this.$route.query.factory', this.$route.query.factory);
|
||||
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
">
|
||||
<monthlyRelatedMetrics :relatedData="monthRelatedData" :title="'月度概览'" />
|
||||
<yearRelatedMetrics :relatedData="totalRelatedData" :title="'累计概览'" />
|
||||
<monthlyRelatedMetrics :factory="factory" :relatedData="monthRelatedData" :title="'月度概览'" />
|
||||
<yearRelatedMetrics :factory="factory" :relatedData="totalRelatedData" :title="'累计概览'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom" style="display: flex; gap: 16px;margin-top: 6px;">
|
||||
@@ -69,7 +69,7 @@ import monthlyOverview from "../productionCostAnalysisComponents/monthlyOverview
|
||||
import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue";
|
||||
// import totalOverview from "../operatingComponents/totalOverview.vue";
|
||||
import monthlyRelatedMetrics from "../productionCostAnalysisComponents/monthlyRelatedMetricsProcessingFuel.vue";
|
||||
import yearRelatedMetrics from "../productionCostAnalysisComponents/yearRelatedMetrics.vue";
|
||||
import yearRelatedMetrics from "../productionCostAnalysisComponents/yearRelatedMetricsFuel.vue";
|
||||
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingFuel.vue";
|
||||
import { mapState } from "vuex";
|
||||
import { getCostAnalysisData } from '@/api/cockpit'
|
||||
@@ -175,7 +175,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : this.factory
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
|
||||
@@ -168,6 +168,7 @@ export default {
|
||||
this.beilv = _this.clientWidth / 1920;
|
||||
})();
|
||||
};
|
||||
this.factory = this.$route.query.factory ? Number(this.$route.query.factory) : 5
|
||||
},
|
||||
methods: {
|
||||
changeItem(item) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user