This commit is contained in:
‘937886381’
2025-12-30 19:36:05 +08:00
parent 7b3873f9ea
commit 20ef2b9763
158 changed files with 3059 additions and 462 deletions

View File

@@ -99,7 +99,6 @@ export default {
return {
name: config.name,
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: config.lineColor },

View 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→0110→10
const monthNum = (index + 1).toString().padStart(2, '0');
// 拼接成calendarList中的键格式如2025-01
const yearMonthKey = `2025-${monthNum}`; // 若年份不固定可改为props传递年份
// 判断calendarObj中该键对应的值1→true0→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>

View 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>仅允许导入xlsxlsx格式文件</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>

View 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;
// 时间维度对应mode2=月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>

View File

@@ -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;

View File

@@ -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 },

View File

@@ -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',

View File

@@ -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 // 本月值
};

View File

@@ -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)' },

View 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→0110→10
const monthNum = (index + 1).toString().padStart(2, '0');
// 拼接成calendarList中的键格式如2025-01
const yearMonthKey = `2025-${monthNum}`; // 若年份不固定可改为props传递年份
// 判断calendarObj中该键对应的值1→true0→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>

View 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>

View 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>

View File

@@ -83,11 +83,11 @@ export default {
return html;
}
},
grid: {
grid: {
top: 30,
bottom: 30,
right: 70,
left: 40,
right: 20,
left: 60,
},
xAxis: [
{

View File

@@ -83,11 +83,11 @@ export default {
// return html;
// }
},
grid: {
grid: {
top: 30,
bottom: 30,
right: 70,
left: 40,
right: 20,
left: 60,
},
xAxis: [
{

View File

@@ -81,11 +81,11 @@ export default {
// return html;
// }
},
grid: {
grid: {
top: 30,
bottom: 30,
right: 70,
left: 40,
right: 20,
left: 60,
},
xAxis: [
{

View File

@@ -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)',

View File

@@ -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 = [
'成本',
'制造成本',
'原片成本',
'加工成本',
'原片成品率',

View File

@@ -118,11 +118,11 @@ export default {
return html;
}
},
grid: {
grid: {
top: 30,
bottom: 30,
right: 70,
left: 40,
right: 20,
left: 60,
},
xAxis: [
{

View File

@@ -93,11 +93,11 @@ export default {
return html;
}
},
grid: {
grid: {
top: 30,
bottom: 30,
right: 70,
left: 40,
right: 20,
left: 60,
},
xAxis: [
{

View File

@@ -71,8 +71,8 @@ export default {
// 定义一个映射关系,将后端字段名与前端显示信息关联起来
const dataMap = [
{
key: 'totalCost',
unit: '成本·元/㎡',
key: 'processCost',
unit: '制造成本·元/㎡',
route: '/productionCostAnalysis/productionCostAnalysis'
},
{