Files
yudao-dev/src/views/home/components/budgetDetails.vue
‘937886381’ 20ef2b9763 修改
2025-12-30 19:36:05 +08:00

441 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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