提交 9dd9c254 authored 作者: kxjia's avatar kxjia

指标名称

上级 dc235789
......@@ -8,7 +8,7 @@ VITE_GLOB_APP_TITLE = 科技风险管理平台
VITE_GLOB_APP_SHORT_NAME = 科技风险管理平台
# 单点登录服务端地址
VITE_GLOB_APP_CAS_BASE_URL=http://cas.test.com:8443/cas
# VITE_GLOB_APP_CAS_BASE_URL=http://cas.test.com:8443/cas
# 是否开启单点登录
......@@ -18,10 +18,10 @@ VITE_GLOB_APP_OPEN_SSO = false
VITE_GLOB_APP_OPEN_QIANKUN=true
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://47.98.203.68:8080/stm/
#VITE_GLOB_DOMAIN_URL=http://47.98.203.68:8080/stm/
# 文件预览地址
# VITE_GLOB_ONLINE_VIEW_URL=http://fileview.jeecg.com/onlinePreview
VITE_GLOB_ONLINE_VIEW_URL=http://47.98.203.68:8080/stm/sys/common/static/
# VITE_GLOB_ONLINE_VIEW_URL=http://47.98.203.68:8080/stm/sys/common/static/
......@@ -9,7 +9,7 @@ VITE_PUBLIC_PATH = /
VITE_PROXY = [["/stm","http://localhost:8080/stm"],["/upload","http://localhost:3300/upload"]]
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://localhost:8080/stm/
VITE_GLOB_DOMAIN_URL=http://localhost:8080/stm
#后台接口父地址(必填)
VITE_GLOB_API_URL=/stm
......@@ -33,5 +33,5 @@ VITE_APP_SUB_jeecg-app-1 = '//localhost:8092'
VITE_GLOB_ONLINE_DOCUMENT_VERSION=wps
# 文件预览地址
VITE_GLOB_ONLINE_VIEW_URL=http://localhost:8080/stm/sys/common/static/
VITE_GLOB_ONLINE_VIEW_URL=http://localhost:3100/stm/sys/common/static/
......@@ -16,13 +16,12 @@ VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
VITE_GLOB_API_URL=/stm
#后台接口全路径地址(必填)
# VITE_GLOB_DOMAIN_URL=https://itrm.westmining.com:8080/stm
# VITE_GLOB_ONLINE_VIEW_URL=https://itrm.westmining.com:8080/stm/sys/common/static/
VITE_GLOB_DOMAIN_URL=https://itrm.westmining.com/stm
VITE_GLOB_ONLINE_VIEW_URL=https://itrm.westmining.com/stm/sys/common/static/
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://47.98.203.68:8080/stm/
VITE_GLOB_ONLINE_VIEW_URL=http://47.98.203.68:8080/stm/sys/common/static/
# VITE_GLOB_DOMAIN_URL=http://47.98.203.68:8080/stm/
# VITE_GLOB_ONLINE_VIEW_URL=http://47.98.203.68:8080/stm/sys/common/static/
# 接口父路径前缀
VITE_GLOB_API_URL_PREFIX=
......
......@@ -157,7 +157,7 @@
</style>
<div class="app-loading">
<div class="app-loading-wrap">
<img src="<%= basePublicPath %>/resource/img/logo.png" class="app-loading-logo" alt="Logo" style="width: 80px;height:32px;" />
<img src="<%= basePublicPath %>/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
<div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
......
......@@ -22,8 +22,13 @@ enum Api {
queryDepartPostUserPageList = '/sys/user/queryDepartPostUserPageList',
//查询所选部门的所有父节点ID
queryAllParentId = '/sys/sysDepart/queryAllParentId',
getMetricList = '/metric/metricMonitorSet/list',
queryAllMetric = '/metric/metricMonitorSet/queryAllMetric',
rateRuleList = '/rate/rateRule/list',
}
/**
* 上传父路径
*/
......@@ -188,3 +193,16 @@ export const refreshDragCache = () => defHttp.get({ url: Api.refreshDragCache },
* @param params
*/
export const refreshHomeCache = () => defHttp.get({ url: Api.refreshDefaultIndexCache }, { isTransformResponse: false });
export const getMetricList = (params) => {
return defHttp.get({ url: Api.getMetricList, params })
};
export const queryAllMetric = (params) =>{
return defHttp.get({url: Api.queryAllMetric, params})
}
export const getRateRuleList = (params) => {
return defHttp.get({ url: Api.rateRuleList, params });
};
......@@ -76,7 +76,7 @@ import JCaSelect from './jeecg/components/JCaSelect.vue';
import StSelectLable from './jeecg/components/StSelectLable.vue';
import JSearchSelectDuty from './jeecg/components/JSearchSelectDuty.vue';
import JSelectMetric from './jeecg/components/JSelectMetric.vue';
const componentMap = new Map<ComponentType, Component>();
......@@ -182,6 +182,8 @@ componentMap.set('JCaSelect', JCaSelect);
componentMap.set('StSelectLable', StSelectLable);
componentMap.set('JSearchSelectDuty', JSearchSelectDuty);
componentMap.set('JSelectMetric', JSelectMetric);
export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, component);
}
......
......@@ -29,7 +29,7 @@
enum Api {
url = '/sys/dict/loadTreeData',
view = '/sys/dict/loadDictItem/',
view = '/base.domain/stDomain/queryByCode',
}
const props = defineProps({
......@@ -110,29 +110,30 @@
treeValue.value = props.multiple ? [] : null;
return;
}
const params = { key: props.value };
const result = await defHttp.get({ url: `${Api.view}${props.dict}`, params }, { isTransformResponse: false });
if (result.success && result.result?.length > 0) {
console.log(props.value, 'props.value');
const params = { code: props.value };
const result = await defHttp.get({ url: `${Api.view}`, params }, { isTransformResponse: false });
console.log(result, 'result');
console.log(result.result, 'result.result');
console.log(props, 'props');
const values = props.value;
console.log(values, 'values');
const length = values.length;
console.log(length, 'length');
if (length === 2) {
treeValue.value = [values];
console.log(treeValue.value, 'treeValue.value2');
} else if (length === 4) {
treeValue.value = [values.substring(0, 2), values];
console.log(treeValue.value, 'treeValue.value4');
} else if (length === 6) {
treeValue.value = [values.substring(0, 2), values.substring(0, 4), values];
console.log(treeValue.value, 'treeValue.value6');
}
if (result.success && result.result) {
// console.log(result.result, 'result.result');
// console.log(props, 'props');
// const values = props.value;
// console.log(values, 'values');
// const length = values.length;
// console.log(length, 'length');
// if (length === 2) {
// treeValue.value = [values];
// console.log(treeValue.value, 'treeValue.value2');
// } else if (length === 4) {
// treeValue.value = [values.substring(0, 2), values];
// console.log(treeValue.value, 'treeValue.value4');
// } else if (length === 6) {
// treeValue.value = [values.substring(0, 2), values.substring(0, 4), values];
// console.log(treeValue.value, 'treeValue.value6');
// }
treeValue.value = [result.result];
onLoadTriggleChange(result.result[0]);
}
}
......
<template>
<div>
<JMetricBiz @handleOpen="handleOpen" :loading="loadingEcho" v-bind="attrs"></JMetricBiz>
......
......@@ -168,4 +168,5 @@ export type ComponentType =
| 'StSelectLable'
| 'JTreeSelectDomain'
| 'JCaSelect'
| 'JInputSelect';
\ No newline at end of file
| 'JInputSelect'
| 'JSelectMetric';
\ No newline at end of file
......@@ -275,7 +275,7 @@
</vxe-column>
<!-- 备注列 -->
<vxe-column field="remarks" title="备注" width="200">
<vxe-column field="remarks" title="备注" width="100">
<template #default="{ row }">
<vxe-textarea
:rows="row.remarks.rows"
......
<template>
<a-modal
:visible="visible"
:title="title"
:width="'60%'"
:bodyStyle="{ height: '80vh', padding: '20px' }"
:footer="null"
@ok="handleOk"
@cancel="handleCancel"
@update:visible="(value) => emit('update:visible', value)"
:centered="true"
:destroyOnClose="true"
:maskClosable="false"
>
<div style="height: 100%; display: flex; flex-direction: column;">
<!-- 加载状态 -->
<div v-if="chartLoading" style="text-align: center; padding: 50px;">
<a-spin size="large" />
</div>
<template v-else>
<!-- 指标信息 -->
<div style="margin-bottom: 16px; padding: 12px; background: #f5f7fa; border-radius: 4px;">
<a-row :gutter="16">
<a-col :span="4"><strong>指标编码:</strong>{{ row?.mtrcNo }}</a-col>
<a-col :span="12" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"><strong>指标名称:</strong>{{ row?.mtrcName }}</a-col>
<a-col :span="4"><strong>采集频率:</strong>{{ getFreqText(row?.collFreq) }}</a-col>
<a-col :span="4"><strong>数据条数:</strong>{{ chartDataList.length }}</a-col>
</a-row>
</div>
<!-- 时间选择表单 -->
<div style="margin-bottom: 16px; padding: 12px; background: #f9f9f9; border-radius: 4px;">
<a-row :gutter="16">
<a-col :span="16">
<BasicForm @register="registerForm" />
</a-col>
<a-col :span="8">
<a-space :size="5" style="float: right;">
<a-button type="primary" @click="searchQuery">查询</a-button>
<a-button @click="searchReset">重置</a-button>
</a-space>
</a-col>
</a-row>
</div>
<a-tabs v-model:activeKey="activeTabKey" @change="handleTabChange" style="flex: 1; display: flex; flex-direction: column;">
<a-tab-pane key="list" tab="指标值" style="height: 100%;">
<a-table
:dataSource="chartDataList"
:columns="dataColumns"
:pagination="{ pageSize: 10 }"
size="small"
:scroll="{ y: 'calc(70vh - 200px)' }"
bordered
>
<template #bodyCell="{ column, text, record }">
<template v-if="column.key === 'riskLevel'">
<a-badge
:status="getRiskLevelStatus(record.riskLevel)"
:text="getRiskLevelText(record.riskLevel)"
/>
</template>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="line" tab="走势图" style="height: 100%;">
<div ref="lineChartRef" style="width: 100%; height: calc(70vh - 150px);"></div>
</a-tab-pane>
<a-tab-pane key="bar" tab="柱状图" style="height: 100%;">
<div ref="barChartRef" style="width: 100%; height: calc(70vh - 150px);"></div>
</a-tab-pane>
<a-tab-pane key="pie" tab="风险分布" style="height: 100%;">
<div ref="pieChartRef" style="width: 100%; height: calc(70vh - 150px);"></div>
</a-tab-pane>
</a-tabs>
</template>
</div>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick } from 'vue'
import * as echarts from 'echarts'
import { queryAllList,queryByMtrcNo } from '../../MetricReport.api'
import { BasicForm, useForm } from '/@/components/Form/index'
import { FormSchema } from '/@/components/Table'
interface Props {
visible: boolean
title: string
row?: any
}
const props = defineProps<Props>()
const emit = defineEmits(['update:visible', 'ok', 'cancel'])
// 响应式数据
const activeTabKey = ref('list')
const chartLoading = ref(false)
const chartDataList = ref<any[]>([])
const curMtrcSet = ref<any>({})
// 图表实例
const lineChartRef = ref<HTMLDivElement | null>(null)
const barChartRef = ref<HTMLDivElement | null>(null)
const pieChartRef = ref<HTMLDivElement | null>(null)
let lineChart: echarts.ECharts | null = null
let barChart: echarts.ECharts | null = null
let pieChart: echarts.ECharts | null = null
// 表单配置
const searchFormSchema: FormSchema[] = [
{
label: '开始日期',
field: 'stFillTime',
component: 'DatePicker',
colProps: { xs: 12, sm: 12, md: 12, lg: 8, xl: 8 },
defaultValue: (new Date().getFullYear() - 3) + "-" + (new Date().getMonth() + 1) + "-" + (new Date().getDate()),
},
{
label: '结束日期',
field: 'endFillTime',
defaultValue: new Date(),
component: 'DatePicker',
colProps: { xs: 12, sm: 12, md: 12, lg: 8, xl: 8 },
},
]
// 初始化表单
const [registerForm, { setFieldsValue, getFieldsValue }] = useForm({
labelWidth: 100,
schemas: searchFormSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 }
})
// 表格列定义
const dataColumns = [
{ title: '填报时间', dataIndex: 'fillTime', key: 'fillTime', width: 150, render: (text) => text || '无数据' },
{ title: '填报值', dataIndex: 'fillVals', key: 'fillVals', width: 100 },
{
title: '风险等级',
dataIndex: 'riskLevel',
key: 'riskLevel',
width: 100
},
]
// 处理确定
const handleOk = () => {
emit('ok')
emit('update:visible', false)
}
// 处理取消
const handleCancel = () => {
emit('cancel')
emit('update:visible', false)
// 销毁图表实例
cleanupCharts()
}
// 清理图表实例
const cleanupCharts = () => {
if (lineChart) {
lineChart.dispose()
lineChart = null
}
if (barChart) {
barChart.dispose()
barChart = null
}
if (pieChart) {
pieChart.dispose()
pieChart = null
}
}
// 获取采集频率文本
const getFreqText = (freq) => {
const map = {
1: '每日',
2: '每周',
3: '每月',
4: '每季度',
5: '每半年',
6: '每年'
}
return map[freq] || freq
}
// 获取风险等级状态
const getRiskLevelStatus = (level) => {
if (level === 1) return 'success'
if (level === 2) return 'processing'
if (level === 3) return 'error'
return 'default'
}
// 获取风险等级文本
const getRiskLevelText = (level) => {
if (level === 1) return '低风险'
if (level === 2) return '中风险'
if (level === 3) return '高风险'
return '其他'
}
// 格式化时间
const formatTime = (time, collFreq) => {
if (!time) return ''
// 确保 time 是字符串
const timeStr = String(time)
// 确保 collFreq 是数字
const freq = Number(collFreq) || 0
try {
if (freq == 1) {
return timeStr.length >= 10 ? timeStr.substr(5, 5) : timeStr // MM-DD
} else if (freq == 2) {
return timeStr.length >= 10 ? timeStr.substr(5, 5) : timeStr // MM-DD
} else if (freq == 3 || freq === 4 || freq === 5) {
return timeStr.length >= 7 ? timeStr.substr(0, 7) : timeStr // YYYY-MM
} else if (freq == 6) {
return timeStr.length >= 4 ? timeStr.substr(0, 4) : timeStr // YYYY
} else {
return timeStr.length >= 17 ? timeStr.substr(11, 16) : timeStr // HH:mm
}
} catch (error) {
return timeStr
}
}
// 加载数据
const loadData = async () => {
if (!props.row) return
chartLoading.value = true
try {
// 获取表单数据
const formData = getFieldsValue()
queryByMtrcNo({
mtrcNo: props.row.mtrcNo,
}).then(res => {
curMtrcSet.value = res || {}
})
// 从接口获取数据
const res = await queryAllList({
mtrcNos: props.row.mtrcNo,
stFillTime: formData.stFillTime,
endFillTime: formData.endFillTime
})
// 处理数据
if (res && res.dataList) {
chartDataList.value = res.dataList.map(item => {
const formattedTime = formatTime(item.fillTime, curMtrcSet.value.collFreq)
return {
...item,
fillTime: formattedTime
}
})
} else {
chartDataList.value = []
}
await nextTick()
// 根据当前激活的标签页初始化对应的图表
setTimeout(() => {
if (activeTabKey.value === 'line') {
initLineChart()
} else if (activeTabKey.value === 'bar') {
initBarChart()
} else if (activeTabKey.value === 'pie') {
initPieChart()
}
}, 200)
} catch (error) {
chartDataList.value = []
} finally {
chartLoading.value = false
}
}
// 查询
const searchQuery = () => {
loadData()
}
// 重置
const searchReset = () => {
setFieldsValue({
stFillTime: (new Date().getFullYear() - 3) + "-" + (new Date().getMonth() + 1) + "-" + (new Date().getDate()),
endFillTime: new Date()
})
loadData()
}
// 初始化所有图表
const initAllCharts = () => {
// 注意:由于标签页可能未激活,容器可能不存在,所以这里不直接初始化
// 图表会在标签切换时初始化
}
// 获取图表数据
const getChartData = () => {
const categories = chartDataList.value.map(item => item.fillTime)
const values = chartDataList.value.map(item => {
const val = parseFloat(item.fillVals) || 0
return val
})
// 按风险等级统计饼图数据
const riskCount = {
1: 0, // 低风险
2: 0, // 中风险
3: 0 // 高风险
}
chartDataList.value.forEach(item => {
if (item.riskLevel && riskCount[item.riskLevel] !== undefined) {
riskCount[item.riskLevel]++
}
})
const pieData = []
// 按固定顺序添加数据项,并指定颜色
if (riskCount[1] > 0) {
pieData.push({ value: riskCount[1], name: '低风险', itemStyle: { color: '#73D13D' } })
}
if (riskCount[2] > 0) {
pieData.push({ value: riskCount[2], name: '中风险', itemStyle: { color: '#FA8C16' } })
}
if (riskCount[3] > 0) {
pieData.push({ value: riskCount[3], name: '高风险', itemStyle: { color: '#CF1322' } })
}
return { categories, values, pieData }
}
// 初始化折线图
const initLineChart = () => {
if (!lineChartRef.value) {
return
}
if (lineChart) {
lineChart.dispose()
}
lineChart = echarts.init(lineChartRef.value)
const { categories, values } = getChartData()
const option = {
title: {
text: `${props.row?.mtrcName} - 趋势分析`,
left: 'center',
top: 10,
textStyle: {
fontSize: 16,
fontWeight: 'normal'
}
},
tooltip: {
trigger: 'axis',
formatter: function(params) {
return `${params[0].name}<br/>${params[0].marker}${params[0].seriesName}: ${params[0].value}`
}
},
grid: {
left: '8%',
right: '5%',
top: '15%',
bottom: '8%',
containLabel: true
},
xAxis: {
type: 'category',
data: categories.length > 0 ? categories : ['无数据'],
axisLabel: {
rotate: categories.length > 10 ? 30 : 0,
interval: categories.length > 20 ? 2 : 0
},
axisLine: {
lineStyle: { color: '#999' }
}
},
yAxis: {
type: 'value',
name: `单位[${props.row?.unit || ''}]`,
nameLocation: 'middle',
nameGap: 45,
splitLine: {
lineStyle: { type: 'dashed', color: '#eee' }
}
},
series: [{
name: props.row?.mtrcName || '指标数值',
data: values.length > 0 ? values : [0],
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 3,
color: '#409eff'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(64, 158, 255, 0.3)' },
{ offset: 1, color: 'rgba(64, 158, 255, 0.05)' }
])
},
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
]
},
markLine: {
data: [
{ type: 'average', name: '平均值' }
]
}
}]
}
lineChart.setOption(option)
lineChart.resize()
}
// 初始化柱状图
const initBarChart = () => {
if (!barChartRef.value) {
return
}
if (barChart) {
barChart.dispose()
}
barChart = echarts.init(barChartRef.value)
const { categories, values } = getChartData()
const option = {
title: {
text: `${props.row?.mtrcName} - 对比分析`,
left: 'center',
top: 10,
textStyle: {
fontSize: 16,
fontWeight: 'normal'
}
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: function(params) {
return `${params[0].name}<br/>${params[0].marker}${params[0].seriesName}: ${params[0].value}`
}
},
grid: {
left: '8%',
right: '5%',
top: '15%',
bottom: '8%',
containLabel: true
},
xAxis: {
type: 'category',
data: categories.length > 0 ? categories : ['无数据'],
axisLabel: {
rotate: categories.length > 10 ? 30 : 0,
interval: categories.length > 20 ? 2 : 0
},
axisLine: {
lineStyle: { color: '#999' }
}
},
yAxis: {
type: 'value',
name: `单位[${props.row?.unit || ''}]`,
nameLocation: 'middle',
nameGap: 45,
splitLine: {
lineStyle: { type: 'dashed', color: '#eee' }
}
},
series: [{
name: props.row?.mtrcName || '指标数值',
data: values.length > 0 ? values : [0],
type: 'bar',
barWidth: '50%',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
]),
borderRadius: [6, 6, 0, 0]
},
label: {
show: values.length <= 20,
position: 'top',
color: '#333',
fontSize: 11,
formatter: '{c}'
},
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
]
}
}]
}
barChart.setOption(option)
barChart.resize()
}
// 初始化饼图
const initPieChart = () => {
if (!pieChartRef.value) {
return
}
if (pieChart) {
pieChart.dispose()
}
pieChart = echarts.init(pieChartRef.value)
const { pieData } = getChartData()
if (pieData.length === 0) {
pieData.push({ value: 1, name: '暂无数据' })
}
const option = {
title: {
text: `${props.row?.mtrcName} - 风险分布`,
left: 'center',
top: 10,
textStyle: {
fontSize: 16,
fontWeight: 'normal'
}
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c} ({d}%)'
},
legend: {
orient: 'horizontal',
bottom: 20,
left: 'center',
itemWidth: 25,
itemHeight: 14
},
series: [{
name: '风险分布',
type: 'pie',
radius: ['45%', '70%'],
center: ['50%', '45%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 8,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside',
formatter: '{b}: {d}%',
fontSize: 11
},
emphasis: {
scale: true,
label: { show: true, fontWeight: 'bold' }
},
data: pieData
}]
}
pieChart.setOption(option)
pieChart.resize()
}
// 标签切换处理
const handleTabChange = (key) => {
setTimeout(() => {
if (key === 'line') {
initLineChart()
} else if (key === 'bar') {
initBarChart()
} else if (key === 'pie') {
initPieChart()
}
}, 100)
}
// 监听可见性变化
watch(() => props.visible, async (newVal) => {
if (newVal) {
activeTabKey.value = 'list' // 默认选中列表
await loadData()
} else {
cleanupCharts()
}
})
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div style="height: 100%;padding: 10px;">
<div style="padding: 10px;">
<a-row style="height: 100%;" :gutter="[8, 8]">
<a-col :span="5">
<a-card title="" :bordered="true" style="width:100%;height:100%;">
<Left @searchData="setDataList"></Left>
<a-card :bordered="true" style="width:100%;height:100%;">
<Left
@searchData="handleLeftSearch"
@resetData="handleLeftReset"
/>
</a-card>
</a-col>
<a-col :span="19">
<!-- 时间搜索表单 -->
<div style="margin-bottom: 16px; padding: 12px; background: #f9f9f9; border-radius: 4px;">
<a-row :gutter="16" align="middle">
<a-col :span="14">
<a-col :span="16">
<div style="display: flex; align-items: center; gap: 16px;">
<div style="display: flex; align-items: center;">
<span style="margin-right: 8px;">开始日期:</span>
<a-date-picker v-model:value="searchForm.stFillTime" style="width: 150px;" />
<a-date-picker v-model:value="searchForm.startTime" style="width: 150px;" />
</div>
<div style="display: flex; align-items: center;">
<span style="margin-right: 8px;">结束日期:</span>
<a-date-picker v-model:value="searchForm.endFillTime" style="width: 150px;" />
<a-date-picker v-model:value="searchForm.endTime" style="width: 150px;" />
</div>
<div style="display: flex; align-items: center;">
<span style="margin-right: 8px;">指标名称:</span>
<a-input v-model:value="searchForm.mtrcName" placeholder="请输入指标名称" style="width: 150px;" />
</div>
</div>
</a-col>
<a-col :span="10">
<a-col :span="8">
<a-space :size="5" style="margin-left:0px;">
<a-button type="primary" @click="handleSearch">查询</a-button>
<a-button type="primary" @click="handleSearch" :loading="gridOptions.loading">查询</a-button>
<a-button @click="resetSearch">重置</a-button>
</a-space>
</a-col>
</a-row>
</div>
<vxe-grid v-bind="gridOptions" ref="tableRef">
<vxe-grid
v-bind="gridOptions"
ref="tableRef"
@page-change="handlePageChange"
>
<template #toolbarButtons>
<div style="margin:2px 20px;size:15px">指标填报列表:</div>
<vxe-button size="small" @click="handleApproval(1)">审批通过</vxe-button>
<vxe-button size="small" @click="handleApproval(2)">审批未通过</vxe-button>
<vxe-button size="small" @click="handleApproval(1)" :loading="batchLoading">审批通过</vxe-button>
<vxe-button size="small" @click="handleApproval(2)" :loading="batchLoading">审批未通过</vxe-button>
<div style="margin:auto">
共搜索到 <span class="count-number">{{ totalRecords }}</span> 条记录
</div>
</template>
<template #active="{ row }">
<vxe-button mode="text" status="primary" @click="saveApproval(row.reportId,1)">通过</vxe-button>
<vxe-button mode="text" status="error" @click="saveApproval(row.reportId,2)">退回</vxe-button>
<vxe-button mode="text" status="primary" @click="saveApproval(row.reportId, 1)" :loading="row._loading">通过</vxe-button>
<vxe-button mode="text" status="error" @click="saveApproval(row.reportId, 2)" :loading="row._loading">退回</vxe-button>
</template>
<template #mtrcName="{ row }">
<a @click="showChartModal(row)" style="color: #409eff; cursor: pointer;">
......@@ -66,11 +76,13 @@
</template>
<script lang="ts" setup>
import { reactive, onMounted, ref } from 'vue'
import type { VxeGridProps } from 'vxe-table'
import { dataApprovalList,batchSaveApproval } from '../MetricReport.api';
import { reactive, onMounted, ref, computed } from 'vue'
import type { VxeGridProps, VxeGridInstance } from 'vxe-table'
import { debounce } from 'lodash-es'
import { dataApprovalList, batchSaveApproval } from '../MetricReport.api'
import Left from './left.vue'
import MetricChartModal from './components/MetricChartModal.vue'
import { VXETable } from 'vxe-table'
interface RowVO {
id: number
......@@ -81,8 +93,9 @@ interface RowVO {
address: string
}
const tableRef = ref()
const totalRecords = ref()
const tableRef = ref<VxeGridInstance>()
const totalRecords = ref(0)
const batchLoading = ref(false)
// 图表弹窗
const chartModalVisible = ref(false)
......@@ -91,203 +104,274 @@ const currentRow = ref<any>(null)
// 搜索表单
const searchForm = reactive({
stFillTime: null,
endFillTime: null
startTime: null,
endTime: null,
mtrcName: ''
})
// 左侧筛选条件
const formData = reactive({})
const leftFormData = ref({})
// 存储所有原始数据
const allData = ref<any[]>([])
// 防抖搜索函数
const debouncedSearch = debounce(() => {
handleSearch()
}, 500)
// 表格配置
const gridOptions = reactive<VxeGridProps<RowVO>>({
border: true,
showOverflow: true,
keepSource: true,
height: "auto",
maxHeight: "750px",
loading: false,
exportConfig: {},
columnConfig: {
resizable: true
},
editConfig: {
trigger: 'click',
mode: 'row',
showStatus: true
// 分页配置 - 前端分页模式
pagerConfig: {
enabled: true,
pageSize: 10,
currentPage: 1,
total: 0,
pageSizes: [10, 20, 50, 100],
layouts: ['PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'Sizes', 'Total'],
perfect: true
},
cellStyle ({ row, column }) {
if (column.field === 'appSta') {
if (row.appSta == '通过') {
return {
color: 'blue'
}
} else if (row.appSta == '未通过') {
return {
color: 'red'
}
} else if (row.appSta == '未审批') {
return {
backgroundColor: ''
}
}
} else if (column.field === 'riskLevel') {
if (row.riskLevel == '低风险') {
return {
color: '#73D13D'
}
} else if (row.riskLevel == '中风险') {
return {
color: '#FA8C16'
}
} else if (row.riskLevel == '高风险') {
return {
color: '#CF1322'
}
}
// 工具栏配置
toolbarConfig: {
refresh: true,
export: true,
zoom: true,
custom: true,
slots: {
buttons: 'toolbarButtons'
}
},
// 列配置
columns: [
{ type: 'seq', width: 50 },
{ type: 'checkbox', width: 50 },
{ field: 'reportId', title: 'id', visible:false },
{ field: 'reportId', title: 'id', visible: false },
{ field: 'mtrcNo', title: '指标编码', sortable: true },
{ field: 'mtrcName', title: '指标名称', showOverflow: true, slots: { default: 'mtrcName' } },
{ field: 'collFreq', title: '采集频率', },
{ field: 'collFreq', title: '采集频率' },
{ field: 'timeName', title: '填报时间' },
{ field: 'riskLevel', title: '风险等级' },
{ field: 'domainName', title: '所属领域', showOverflow: true },
{ field: 'mtrcCtp', title: '指标类型' },
{ field: 'fillVals', title: '填报值' },
{ field: 'appSta', title: '状态', },
{ field: 'appSta', title: '状态' },
{ field: 'active', title: '审批', width: 150, fixed: 'right', slots: { default: 'active' } }
],
toolbarConfig: {
refresh: true,
export: true,
zoom: true,
custom: true,
slots: {
buttons: 'toolbarButtons',
},
// 单元格样式
cellStyle({ row, column }) {
if (column.field === 'appSta') {
if (row.appSta == '通过') {
return { color: 'blue' }
} else if (row.appSta == '未通过') {
return { color: 'red' }
}
} else if (column.field === 'riskLevel') {
if (row.riskLevel == '低风险') {
return { color: '#73D13D' }
} else if (row.riskLevel == '中风险') {
return { color: '#FA8C16' }
} else if (row.riskLevel == '高风险') {
return { color: '#CF1322' }
}
}
},
data: []
})
async function setDataList(params = {}) {
// 存储左侧筛选条件
Object.assign(formData, params)
// 更新当前页数据
const updatePageData = () => {
const { currentPage, pageSize } = gridOptions.pagerConfig!
const start = (currentPage - 1) * pageSize
const end = start + pageSize
gridOptions.data = allData.value.slice(start, end)
// 更新分页总记录数
gridOptions.pagerConfig!.total = allData.value.length
totalRecords.value = allData.value.length
}
// 加载数据
async function loadData() {
if (gridOptions.loading) return
// 合并时间搜索条件
// 合并所有搜索条件
const searchParams = {
...params,
stFillTime: searchForm.stFillTime,
endFillTime: searchForm.endFillTime
...leftFormData.value,
startTime: searchForm.startTime,
endTime: searchForm.endTime,
mtrcName: searchForm.mtrcName
}
console.log('加载数据参数:', searchParams)
gridOptions.loading = true
try {
const res = await dataApprovalList(searchParams);
gridOptions.data = res || []
totalRecords.value = res.length
const res = await dataApprovalList(searchParams)
console.log('返回数据:', res)
// 处理返回数据
if (Array.isArray(res)) {
allData.value = res
} else if (res && res.records) {
allData.value = res.records
} else if (res && res.data) {
allData.value = res.data
} else {
allData.value = []
}
// 重置到第一页
gridOptions.pagerConfig!.currentPage = 1
// 更新表格数据
updatePageData()
} catch (error) {
console.error('加载数据失败:', error)
allData.value = []
gridOptions.data = []
totalRecords.value = 0
gridOptions.pagerConfig!.total = 0
} finally {
gridOptions.loading = false
}
}
const handleApproval = async (appSta)=> {
const ids = await getSelectIds();
if(ids.length == 0){
return;
}
batchSaveApproval({
ids:ids,
appSta:appSta
},setDataList)
}
// 处理分页变化
const handlePageChange = ({ currentPage, pageSize }: { currentPage: number, pageSize: number }) => {
console.log('分页变化:', currentPage, pageSize)
const saveApproval = async (id,sta)=> {
batchSaveApproval({
ids:[id],
appSta:sta
},function(){
// 更新分页配置
gridOptions.pagerConfig!.currentPage = currentPage
gridOptions.pagerConfig!.pageSize = pageSize
})
// 前端分页:直接从 allData 中切片
updatePageData()
}
// 处理左侧搜索
function handleLeftSearch(params) {
console.log('左侧搜索:', params)
leftFormData.value = { ...params }
loadData() // 重新从后端获取数据
}
async function getSelectIds() {
let ids = [];
const $table = tableRef.value;
if ($table) {
const selRecords = $table.getCheckboxRecords();
selRecords.forEach(function (ele) {
ids.push(ele.reportId);
});
}
return ids;
// 处理左侧重置
function handleLeftReset() {
console.log('左侧重置')
leftFormData.value = {}
searchForm.startTime = null
searchForm.endTime = null
loadData() // 重新从后端获取数据
}
// 处理搜索
const handleSearch = async () => {
await setDataList(formData)
async function handleSearch() {
console.log('执行搜索')
await loadData() // 重新从后端获取数据
}
// 重置搜索
const resetSearch = () => {
searchForm.stFillTime = null
searchForm.endFillTime = null
setDataList({})
function resetSearch() {
searchForm.startTime = null
searchForm.endTime = null
searchForm.mtrcName = ''
handleSearch()
}
onMounted(async () => {
await setDataList({});
})
// 批量审批
async function handleApproval(appSta: number) {
const $table = tableRef.value
if (!$table) return
const selectRecords = $table.getCheckboxRecords()
if (selectRecords.length === 0) {
VXETable.modal.message({ content: '请至少选择一条记录', status: 'warning' })
return
}
const ids = selectRecords.map(item => item.reportId)
batchLoading.value = true
try {
await batchSaveApproval({
ids: ids,
appSta: appSta
})
VXETable.modal.message({ content: '操作成功', status: 'success' })
// 重新加载数据
await loadData()
// 清空选中
$table.clearCheckboxRow()
} catch (error) {
console.error('批量审批失败:', error)
VXETable.modal.message({ content: '操作失败', status: 'error' })
} finally {
batchLoading.value = false
}
}
// 单个审批
async function saveApproval(id: number, sta: number) {
const row = gridOptions.data.find(item => item.reportId === id)
if (row) {
row._loading = true
}
try {
await batchSaveApproval({
ids: [id],
appSta: sta
})
VXETable.modal.message({ content: '操作成功', status: 'success' })
// 重新加载数据
await loadData()
} catch (error) {
console.error('审批失败:', error)
VXETable.modal.message({ content: '操作失败', status: 'error' })
} finally {
if (row) {
row._loading = false
}
}
}
// 显示图表弹窗
const showChartModal = (row) => {
function showChartModal(row: any) {
currentRow.value = row
chartModalTitle.value = `指标详情 - ${row.mtrcName}`
chartModalVisible.value = true
}
// 处理弹窗关闭
const handleModalClose = () => {
function handleModalClose() {
chartModalVisible.value = false
}
onMounted(async () => {
await loadData()
})
defineExpose({
setDataList,
loadData,
refreshData: loadData
})
</script>
<style scoped>
.custom-bottom {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-top: 1px solid #e1e4e8;
}
.record-count {
display: flex;
align-items: center;
padding: 8px 16px;
background: white;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
font-size: 14px;
color: #606266;
}
.record-count i {
margin-right: 8px;
color: #409eff;
}
.count-number {
font-weight: bold;
color: #409eff;
......
......@@ -5,15 +5,14 @@
ref="formRef"
:data="formData"
:loading="loading"
@submit="submitEvent"
@reset="resetEvent">
>
<vxe-form-item title="年份" field="qyear" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.qyear === undefined ? 'button' : 'text'"
:status="params.data.qyear === undefined ? 'primary' : ''"
@click="handleButtonClick('qyear', undefined, params)"
@click="handleButtonClick('qyear', undefined)"
>
全部
</vxe-button>
......@@ -22,20 +21,21 @@
:key="year"
:mode="params.data.qyear === year ? 'button' : 'text'"
:status="params.data.qyear === year ? 'primary' : ''"
@click="handleButtonClick('qyear', year, params)"
@click="handleButtonClick('qyear', year)"
>
{{ year }}
</vxe-button>
</div>
</template>
</vxe-form-item>
<vxe-form-item title="风险等级" field="riskLevel" span="24" :item-render="{}" title-overflow>
<vxe-form-item title="风险等级" field="riskLevel" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.riskLevel === undefined ? 'button' : 'text'"
:status="params.data.riskLevel === undefined ? 'primary' : ''"
@click="handleButtonClick('riskLevel', undefined, params)"
@click="handleButtonClick('riskLevel', undefined)"
>
全部
</vxe-button>
......@@ -44,20 +44,21 @@
:key="item.value"
:mode="params.data.riskLevel === item.value ? 'button' : 'text'"
:status="params.data.riskLevel === item.value ? 'primary' : ''"
@click="handleButtonClick('riskLevel', item.value, params)"
@click="handleButtonClick('riskLevel', item.value)"
>
{{ item.label }}
</vxe-button>
</div>
</template>
</vxe-form-item>
<vxe-form-item title="采集频率" field="collFreq" span="24" :item-render="{}" title-overflow>
<vxe-form-item title="采集频率" field="collFreq" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.collFreq === undefined ? 'button' : 'text'"
:status="params.data.collFreq === undefined ? 'primary' : ''"
@click="handleButtonClick('collFreq', undefined, params)"
@click="handleButtonClick('collFreq', undefined)"
>
全部
</vxe-button>
......@@ -66,20 +67,21 @@
:key="item.value"
:mode="params.data.collFreq === item.value ? 'button' : 'text'"
:status="params.data.collFreq === item.value ? 'primary' : ''"
@click="handleButtonClick('collFreq', item.value, params)"
@click="handleButtonClick('collFreq', item.value)"
>
{{ item.label }}
</vxe-button>
</div>
</template>
</vxe-form-item>
<vxe-form-item title="采集方法" field="collMethod" span="24" :item-render="{}" title-overflow>
<vxe-form-item title="采集方法" field="collMethod" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.collMethod === undefined ? 'button' : 'text'"
:status="params.data.collMethod === undefined ? 'primary' : ''"
@click="handleButtonClick('collMethod', undefined, params)"
@click="handleButtonClick('collMethod', undefined)"
>
全部
</vxe-button>
......@@ -88,34 +90,35 @@
:key="item.value"
:mode="params.data.collMethod === item.value ? 'button' : 'text'"
:status="params.data.collMethod === item.value ? 'primary' : ''"
@click="handleButtonClick('collMethod', item.value, params)"
@click="handleButtonClick('collMethod', item.value)"
>
{{ item.label }}
</vxe-button>
</div>
</template>
</vxe-form-item>
<vxe-form-item title="指标类型" field="mtrcCtp" span="24" :item-render="{}" title-overflow>
<vxe-form-item title="指标类型" field="mtrcCtp" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.mtrcCtp === undefined ? 'button' : 'text'"
:status="params.data.mtrcCtp === undefined ? 'primary' : ''"
@click="handleButtonClick('mtrcCtp', undefined, params)"
@click="handleButtonClick('mtrcCtp', undefined)"
>
全部
</vxe-button>
<vxe-button
:mode="params.data.mtrcCtp === '1' ? 'button' : 'text'"
:status="params.data.mtrcCtp === '1' ? 'primary' : ''"
@click="handleButtonClick('mtrcCtp', '1', params)"
@click="handleButtonClick('mtrcCtp', '1')"
>
基础指标
</vxe-button>
<vxe-button
:mode="params.data.mtrcCtp === '2' ? 'button' : 'text'"
:status="params.data.mtrcCtp === '2' ? 'primary' : ''"
@click="handleButtonClick('mtrcCtp', '2', params)"
@click="handleButtonClick('mtrcCtp', '2')"
>
计算指标
</vxe-button>
......@@ -123,210 +126,178 @@
</template>
</vxe-form-item>
<vxe-form-item title="是否统计" field="metrictype" span="24" :item-render="{}" title-overflow>
<vxe-form-item title="是否统计" field="mtrcTp" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.metrictype === undefined ? 'button' : 'text'"
:status="params.data.metrictype === undefined ? 'primary' : ''"
@click="handleButtonClick('mtrcTp', undefined, params)"
:mode="params.data.mtrcTp === undefined ? 'button' : 'text'"
:status="params.data.mtrcTp === undefined ? 'primary' : ''"
@click="handleButtonClick('mtrcTp', undefined)"
>
全部
</vxe-button>
<vxe-button
:mode="params.data.mtrcTp === '1' ? 'button' : 'text'"
:status="params.data.mtrcTp === '1' ? 'primary' : ''"
@click="handleButtonClick('mtrcTp', '1', params)"
@click="handleButtonClick('mtrcTp', '1')"
>
统计
</vxe-button>
<vxe-button
:mode="params.data.metrictype === '2' ? 'button' : 'text'"
:mode="params.data.mtrcTp === '2' ? 'button' : 'text'"
:status="params.data.mtrcTp === '2' ? 'primary' : ''"
@click="handleButtonClick('mtrcTp', '2', params)"
@click="handleButtonClick('mtrcTp', '2')"
>
不统计
</vxe-button>
</div>
</template>
</vxe-form-item>
<vxe-form-item title="审批状态" field="appSta" span="24" :item-render="{}" title-overflow>
<vxe-form-item title="审批状态" field="appSta" span="24">
<template #default="params">
<div class="button-group">
<vxe-button
:mode="params.data.appSta === undefined ? 'button' : 'text'"
:status="params.data.appSta === undefined ? 'primary' : ''"
@click="handleButtonClick('appSta', undefined, params)"
@click="handleButtonClick('appSta', undefined)"
>
全部
</vxe-button>
<vxe-button
:mode="params.data.appSta === '1' ? 'button' : 'text'"
:status="params.data.appSta === '1' ? 'primary' : ''"
@click="handleButtonClick('appSta', '1', params)"
@click="handleButtonClick('appSta', '1')"
>
通过
</vxe-button>
<vxe-button
:mode="params.data.appSta === '2' ? 'button' : 'text'"
:status="params.data.appSta === '2' ? 'primary' : ''"
@click="handleButtonClick('appSta', '2', params)"
@click="handleButtonClick('appSta', '2')"
>
未通过
</vxe-button>
</div>
</template>
</vxe-form-item>
<vxe-form-item title="指标名称" field="mtrcName" span="24" :item-render="{}" title-overflow>
<template #default="params">
<vxe-input v-model="params.data.mtrcName" placeholder="请输入名称" clearable @change="changeEvent"></vxe-input>
<!-- 添加搜索和重置按钮 -->
<!-- <vxe-form-item span="24">
<template #default>
<div style="display: flex; gap: 8px; justify-content: center;">
<vxe-button status="primary" @click="handleSubmit">查询</vxe-button>
<vxe-button @click="handleReset">重置</vxe-button>
</div>
</template>
</vxe-form-item>
</vxe-form-item> -->
</vxe-form>
</div>
</template>
<script lang="ts" setup>
import { ref,onMounted } from 'vue'
import { Dayjs } from 'dayjs';
import { VXETable, VxeFormInstance, VxeFormPropTypes, VxeFormEvents } from 'vxe-table'
import { labelCol } from '../../newlib/components/data/AuditCommon.data';
import { ref, onMounted } from 'vue'
interface FormDataVO {
qyear:number|undefined
qmonth: number|undefined
quarter: number|undefined
riskLevel:number|undefined
collMethod:number|undefined
collFreq:number|undefined
mtrcCtp:string|undefined
appSta:string|undefined,
mtrcTp:string|undefined,
qyear: number | undefined
qmonth: number | undefined
quarter: number | undefined
riskLevel: number | undefined
collMethod: number | undefined
collFreq: number | undefined
mtrcCtp: string | undefined
appSta: string | undefined
mtrcTp: string | undefined
}
const emit = defineEmits(['searchData']);
const formRef = ref<VxeFormInstance>()
const yearOptions = ref([]);
const emit = defineEmits(['searchData', 'resetData'])
const formRef = ref()
const yearOptions = ref<number[]>([])
const loading = ref(false)
const formData = ref<FormDataVO>({
qyear: 2025,
qmonth: undefined,
quarter: undefined,
riskLevel:undefined,
collMethod:undefined,
collFreq:undefined,
mtrcCtp:undefined,
appSta:undefined,
mtrcTp:undefined,
riskLevel: undefined,
collMethod: undefined,
collFreq: undefined,
mtrcCtp: undefined,
appSta: undefined,
mtrcTp: undefined
})
// 处理按钮点击事件
const handleButtonClick = (field: keyof FormDataVO, value: any, params: any) => {
// 选项数据
const riskLevelOptions = ref([
{ label: '低风险', value: 1 },
{ label: '中风险', value: 2 },
{ label: '高风险', value: 3 }
])
const collMethodOptions = ref([
{ label: '手动', value: 1 },
{ label: '自动', value: 2 },
{ label: '人工或自动', value: 3 }
])
// 如果点击已选中的按钮,则取消选择
if (formData.value[field] === value) {
formData.value[field] = undefined;
} else {
formData.value[field] = value;
}
const collFreqOptions = ref([
{ label: '月', value: 3 },
{ label: '季', value: 4 },
{ label: '半年', value: 5 },
{ label: '年', value: 6 }
])
const $form = formRef.value
if ($form) {
$form.updateStatus(params)
searchData()
// 初始化年份选项
const initYearOptions = () => {
const currentYear = new Date().getFullYear()
yearOptions.value = []
for (let i = currentYear - 3; i <= currentYear; i++) {
yearOptions.value.push(i)
}
}
const changeEvent = (params: any) => {
const $form = formRef.value
if ($form) {
$form.updateStatus(params)
searchData()
// 处理按钮点击
const handleButtonClick = (field: keyof FormDataVO, value: any) => {
if (formData.value[field] === value) {
formData.value[field] = undefined
} else {
formData.value[field] = value
}
}
const submitEvent: VxeFormEvents.Submit = () => {
loading.value = true
setTimeout(() => {
loading.value = false
VXETable.modal.message({ content: '保存成功', status: 'success' })
}, 1000)
handleSubmit();
}
const resetEvent: VxeFormEvents.Reset = () => {
VXETable.modal.message({ content: '重置事件', status: 'info' })
// 处理输入变化
const handleInputChange = () => {
// 不立即搜索,等待用户点击查询按钮
}
const getMonths = (value: Dayjs) => {
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
months.push(localeData.monthsShort(value.month(i)));
}
return months;
};
// 处理提交查询
const handleSubmit = () => {
emit('searchData', { ...formData.value })
}
const initYearOptions = () => {
yearOptions.value = [];
const currentYear = new Date().getFullYear();
for(let i = currentYear - 3; i <= currentYear; i++) {
yearOptions.value.push(i);
// 处理重置
const handleReset = () => {
formData.value = {
qyear: 2025,
qmonth: undefined,
quarter: undefined,
riskLevel: undefined,
collMethod: undefined,
collFreq: undefined,
mtrcCtp: undefined,
appSta: undefined,
mtrcTp: undefined
}
};
const monthOptions = ref([
{ label: '1月', value: 1 },
{ label: '2月', value: 2 },
{ label: '3月', value: 3 },
{ label: '4月', value: 4 },
{ label: '5月', value: 5 },
{ label: '6月', value: 6 },
{ label: '7月', value: 7 },
{ label: '8月', value: 8 },
{ label: '9月', value: 9 },
{ label: '10月', value: 10 },
{ label: '11月', value: 11 },
{ label: '12月', value: 12 }
]);
const quarterOptions = ref([
{ label: '第一季度', value: 1 },
{ label: '第二季度', value: 2 },
{ label: '第三季度', value: 3 },
{ label: '第四季度', value: 4 }
]);
const collMethodOptions = ref([
{ label: '手动', value: 1 },
{ label: '自动', value: 2},
{ label: '人工或自动', value: 3},
]);
const riskLevelOptions = ref([
{ label: '低风险', value: 1 },
{ label: '中风险', value: 2},
{ label: '高风险', value: 3},
]);
const collFreqOptions = ref([
{ label: '月', value: 3 },
{ label: '季', value: 4},
{ label: '半年', value: 5},
{ label: '年', value: 6},
]);
const searchData = ()=> {
emit('searchData',formData.value);
emit('resetData')
}
onMounted(async () => {
await initYearOptions();
onMounted(() => {
initYearOptions()
})
</script>
......
......@@ -23,6 +23,7 @@ export const columns: BasicColumn[] = [
ellipsis: true,
dataIndex: 'domainDesc',
width: 300,
ifShow: false,
},
{
title: '更新时间',
......
......@@ -7,6 +7,8 @@
<a-button type="primary" @click="handleCreate" preIcon="ant-design:plus-outlined">新建</a-button>
<a-button v-show="showBtn" type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button v-show="showBtn" type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-button type="primary" @click="handleExpandAll" preIcon="ant-design:down-outlined">展开所有</a-button>
<a-button type="primary" @click="handleCollapseAll" preIcon="ant-design:up-outlined">折叠所有</a-button>
<a-dropdown v-show="showBtn" v-if="selectedRowKeys.length > 0">
<template #overlay>
......@@ -217,7 +219,6 @@ import { downloadFile } from '/@/utils/common/renderUtils';
getDataByResult(result.items);
setTimeout(() => {
loadDataByExpandedRows()
nextTick(expandAll)
}, 800);
}
......@@ -281,10 +282,7 @@ import { downloadFile } from '/@/utils/common/renderUtils';
//判断是否标记了带有子节点
if(item["hasChild"]=='1'){
let loadChild = { id: item.id+'_loadChild', name: 'loading...', isLoading: true }
console.log(loadChild)
item.children = [loadChild]
// // 设置展开的key
handleExpand(true,item)
}
return item
})
......@@ -394,6 +392,51 @@ import { downloadFile } from '/@/utils/common/renderUtils';
]
}
/**
* 展开所有节点
*/
async function handleExpandAll() {
// 展开所有节点
expandAll();
// 加载所有子节点数据
const dataSource = getDataSource();
await loadAllChildren(dataSource);
}
/**
* 折叠所有节点
*/
function handleCollapseAll() {
// 清空展开的节点
expandedRowKeys.value = [];
// 重新加载表格数据,确保所有节点都折叠
reload();
}
/**
* 递归加载所有子节点数据
*/
async function loadAllChildren(nodes) {
if (!nodes || nodes.length === 0) return;
for (const node of nodes) {
if (node.children && node.children.length > 0 && node.children[0].isLoading) {
let data = getFormVlaue();
if (data.level !== "1") {
let result = await getChildList({upperDomainCode: node.domainCode, level: data.level, domainName: data.domainName});
result = result.records ? result.records : result;
if (result && result.length > 0) {
node.children = getDataByResult(result);
await loadAllChildren(node.children);
}
}
} else if (node.children && node.children.length > 0) {
await loadAllChildren(node.children);
}
}
}
</script>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论