Files
fad-dashboard/frontend/packages/BasicComponents/InfoCardCollection/index.vue
砂糖 b5c3c34b81 fix(BasicComponents): 修复资金格式化函数处理字符串输入的问题
将formatFundsRmb函数修改为接受字符串输入并转换为数值,确保金额计算正确
2025-11-12 16:09:32 +08:00

327 lines
9.0 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="width: 100%; height: 100%"
class="bs-design-wrap"
>
<!-- 滚动容器 -->
<div class="scroll-container">
<!-- 内容容器使用CSS动画实现滚动 -->
<div class="content-wrapper" :class="{ 'scroll-animation': shouldScroll }">
<!-- 第一组卡片 -->
<div class="card-grid">
<div
v-for="(item, index) in config.option.tableData"
:key="item.projectId"
class="info-card"
:class="`card-theme-${getCardTheme(index)}`"
>
<h3 class="card-title">{{ item.projectName }}</h3>
<dl class="card-info-list">
<dt>项目编号{{ item.projectNum }}</dt>
<dt>负责人{{ item.functionary }}</dt>
<dt>金额区间{{ formatFundsRmb(item.fundsRmb) }}</dt>
<dt>贸易类型{{ formatTradeType(item.tradeType) }}</dt>
</dl>
</div>
</div>
<!-- 第二组卡片完全相同的副本 -->
<div class="card-grid copy-grid">
<div
v-for="(item, index) in config.option.tableData"
:key="item.projectId + '-copy'"
class="info-card"
:class="`card-theme-${getCardTheme(index)}`"
>
<h3 class="card-title">{{ item.projectName }}</h3>
<dl class="card-info-list">
<dt>项目编号{{ item.projectNum }}</dt>
<dt>负责人{{ item.functionary }}</dt>
<dt>金额区间{{ formatFundsRmb(item.fundsRmb) }}</dt>
<dt>贸易类型{{ formatTradeType(item.tradeType) }}</dt>
</dl>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import commonMixins from 'data-room-ui/js/mixins/commonMixins'
import paramsMixins from 'data-room-ui/js/mixins/paramsMixins'
import linkageMixins from 'data-room-ui/js/mixins/linkageMixins'
import cloneDeep from 'lodash/cloneDeep'
import { settingToTheme } from 'data-room-ui/js/utils/themeFormatting'
export default {
name: 'tables',
mixins: [paramsMixins, commonMixins, linkageMixins],
props: {
id: {
type: String,
default: ''
},
config: {
type: Object,
default: () => ({})
}
},
data () {
return {
updateKey: 0,
headerCellStyleObj: {
backgroundColor: 'transparent'
},
cellStyleObj: {
backgroundColor: 'transparent'
},
columnData: {},
isInit: true,
cardThemes: [] // 存储每个卡片的主题,确保副本颜色一致
}
},
computed: {
headerCellStyle () {
const headerBackgroundColor = {
light: '#ffffff',
dark: 'transparent'
}
if (document.getElementById(this.config.code)?.querySelector('tr')) {
document
.getElementById(this.config.code)
.querySelector('tr').style.backgroundColor =
this.customTheme !== 'custom'
? this.config.customize.headerBackgroundColor ||
headerBackgroundColor[this.customTheme]
: this.headerCellStyleObj.backgroundColor
}
const style = {
height: '48px',
borderBottom: 'solid 2px #007aff',
backgroundColor:
this.customTheme !== 'custom'
? this.config.customize.headerBackgroundColor ||
headerBackgroundColor[this.customTheme]
: this.headerCellStyleObj.backgroundColor,
color:
this.customTheme === 'light'
? '#000000'
: this.config.customize.headerFontColor || '#000000',
fontSize: this.config.customize.headerFontSize + 'px' || '14px'
}
return style
},
shouldShowCopy() {
return this.config.option.tableData && this.config.option.tableData.length > 0
},
shouldScroll() {
return this.config.option.tableData && this.config.option.tableData.length > 0
}
},
watch: {
activeItemConfig (val) {
console.dir(val)
},
// 监听数据变化,重新生成主题
'config.option.tableData': {
handler(newData) {
if (newData && newData.length > 0) {
this.generateCardThemes(newData.length)
}
},
immediate: true,
deep: true
}
},
mounted () {
this.chartInit()
console.log(this.config.option, '信息卡片初始化')
},
methods: {
// 生成卡片主题,确保颜色一致性
generateCardThemes(count) {
this.cardThemes = []
for (let i = 0; i < count; i++) {
// 使用固定的算法生成主题,确保相同位置的卡片颜色一致
this.cardThemes.push((i % 3) + 1)
}
},
// 获取卡片主题
getCardTheme(index) {
if (this.cardThemes.length > index) {
return this.cardThemes[index]
}
return (index % 3) + 1
},
formatFundsRmb (str) {
const amount = Number(str) / 10000;
if (amount === undefined || amount === null) return '未知'
if (amount < 10) return '0w-10w'
else if (amount < 20) return '10w-20w'
else if (amount < 50) return '20w-50w'
else if (amount < 100) return '50w-100w'
else if (amount < 200) return '100w-200w'
else return '200w以上'
},
formatTradeType (type) {
return type === 0 ? '内贸' : '外贸'
},
changeStyle (config) {
config = { ...this.config, ...config }
config.theme = settingToTheme(cloneDeep(config), this.customTheme)
this.changeChartConfig(config)
if (config.code === this.activeCode) {
this.changeActiveItemConfig(config)
}
return config
},
dataFormatting (config, data) {
config.option.tableData =
data?.data && data.data.length > 0 ? data.data : []
const filteredData = {}
const columnData = data?.columnData || {}
const dimensionFieldList = config.dataSource.dimensionFieldList || []
if (
config.dataSource.dimensionFieldList &&
config.dataSource.dimensionFieldList.length > 0
) {
const sortedColumnData = {}
dimensionFieldList.forEach((item, index) => {
sortedColumnData[item] = columnData[item]
})
Object?.keys(sortedColumnData).forEach((key) => {
if (
config.dataSource.dimensionFieldList.includes(
sortedColumnData[key]?.alias
)
) {
filteredData[key] = sortedColumnData[key]
}
})
config.option.columnData = filteredData
} else {
config.option.columnData = columnData
}
this.columnData = cloneDeep(config.option.columnData)
this.updateKey = new Date().getTime()
// 数据更新时重新生成主题
if (config.option.tableData && config.option.tableData.length > 0) {
this.generateCardThemes(config.option.tableData.length)
}
return config
}
}
}
</script>
<style lang="scss" scoped>
.bs-design-wrap {
position: relative;
width: 100%;
height: 100%;
background-color: transparent;
border-radius: 4px;
box-sizing: border-box;
overflow: hidden;
}
// 滚动容器
.scroll-container {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
// 内容容器
.content-wrapper {
width: 100%;
// 滚动动画 - 使用更精确的动画
&.scroll-animation {
animation: seamlessScroll 100s linear infinite;
// 悬停时暂停
&:hover {
animation-play-state: paused;
}
}
}
// 无缝滚动动画 - 精确控制动画距离
@keyframes seamlessScroll {
0% {
transform: translate3d(0, 0, 0);
}
100% {
// 滚动一个完整内容区域的高度
transform: translate3d(0, -50%, 0);
}
}
// 瀑布流布局
.card-grid {
column-count: 6;
column-gap: 20px;
padding: 10px;
// 确保副本与原始内容完全一致
&.copy-grid {
// 不再使用绝对定位,而是正常文档流
}
}
// 单个信息卡片
.info-card {
break-inside: avoid;
margin-bottom: 20px;
border-radius: 8px;
padding: 15px;
color: #fff;
backdrop-filter: blur(10px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
&:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
}
// 科技感主题色
.card-theme-1 {
background: linear-gradient(135deg, rgba(0, 128, 255, 0.3), rgba(0, 128, 255, 0.1));
border: 1px solid rgba(0, 128, 255, 0.5);
}
.card-theme-2 {
background: linear-gradient(135deg, rgba(0, 255, 128, 0.3), rgba(0, 255, 128, 0.1));
border: 1px solid rgba(0, 255, 128, 0.5);
}
.card-theme-3 {
background: linear-gradient(135deg, rgba(128, 0, 255, 0.3), rgba(128, 0, 255, 0.1));
border: 1px solid rgba(128, 0, 255, 0.5);
}
// 卡片标题
.card-title {
margin-top: 0;
margin-bottom: 10px;
font-size: 18px;
border-bottom: 1px solid rgba(255, 255, 255, 0.5);
padding-bottom: 8px;
font-weight: bold;
}
// 卡片信息列表
.card-info-list {
margin: 0;
dt {
font-weight: normal;
margin-top: 8px;
font-size: 14px;
line-height: 1.4;
}
}
</style>