Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
水玉婷
ai-wechat
Commits
1a6bb856
Commit
1a6bb856
authored
Jan 28, 2026
by
水玉婷
Browse files
feat:表格添加排序分页功能及样式调整
parent
f377459f
Changes
7
Hide whitespace changes
Inline
Side-by-side
.env.dev
View file @
1a6bb856
# 开发环境配置
# 开发环境配置
VITE_API_BASE_URL=http://peddev.cmic.com.cn
VITE_API_BASE_URL=http://peddev.cmic.com.cn
# VITE_API_BASE_URL=http://10.17.86.60:8656
# VITE_API_BASE_URL=http://10.17.86.60:8656
# VITE_API_BASE_URL=http://10.17.86.171:8656
# 应用基础路径
# 应用基础路径
VITE_BASE_PATH=/ai/
VITE_BASE_PATH=/ai/
...
...
src/views/components/AiChat.vue
View file @
1a6bb856
...
@@ -65,6 +65,7 @@
...
@@ -65,6 +65,7 @@
<component
<component
:is=
"item.thinkBoxExpanded ? UpOutlined : DownOutlined"
:is=
"item.thinkBoxExpanded ? UpOutlined : DownOutlined"
class=
"toggle-icon"
class=
"toggle-icon"
v-if=
"item.thinkingTimeText !== '正在思考中'"
/>
/>
</div>
</div>
<div
:class=
"['think-box-content', item.thinkBoxExpanded ? 'expanded' : 'collapsed']"
<div
:class=
"['think-box-content', item.thinkBoxExpanded ? 'expanded' : 'collapsed']"
...
...
src/views/components/ChartComponent.vue
View file @
1a6bb856
<
template
>
<
template
>
<div
class=
"chart-container"
>
<div
class=
"chart-container"
>
<div
class=
"tips"
>
<div
class=
"tips"
v-if=
"chartData?.description"
>
{{
chartData
?.
description
}}
{{
chartData
?.
description
}}
</div>
</div>
<!-- 图表类型选择器 -->
<!-- 图表类型选择器 -->
...
@@ -341,6 +341,7 @@ onMounted(() => {
...
@@ -341,6 +341,7 @@ onMounted(() => {
overflow: hidden;
overflow: hidden;
width: 100% !important;
width: 100% !important;
max-width: 100% !important;
max-width: 100% !important;
border: 1px solid #EBEDF0;
.tips {
.tips {
margin-bottom: 8px;
margin-bottom: 8px;
font-weight: 500;
font-weight: 500;
...
...
src/views/components/ColumnChart.vue
View file @
1a6bb856
<
template
>
<
template
>
<div
class=
"message-chart"
>
<div
class=
"message-chart"
>
<div
class=
"chart-title"
>
{{
title
}}
</div>
<!--
<div
class=
"chart-title"
>
{{
title
}}
</div>
-->
<div
v-if=
"isEmpty"
class=
"chart-empty"
>
<div
v-if=
"isEmpty"
class=
"chart-empty"
>
<div
class=
"empty-icon"
>
📊
</div>
<div
class=
"empty-icon"
>
📊
</div>
<div
class=
"empty-text"
>
暂无数据
</div>
<div
class=
"empty-text"
>
暂无数据
</div>
...
@@ -243,7 +243,6 @@ const getXAxisConfig = (xAxisData: string[]) => {
...
@@ -243,7 +243,6 @@ const getXAxisConfig = (xAxisData: string[]) => {
interval
=
1
;
// 每2个显示一个标签
interval
=
1
;
// 每2个显示一个标签
}
else
if
(
dataLength
>
6
)
{
}
else
if
(
dataLength
>
6
)
{
// 数据项适中时,旋转15度
// 数据项适中时,旋转15度
rotate
=
15
;
margin
=
10
;
margin
=
10
;
interval
=
1
;
// 每2个显示一个标签
interval
=
1
;
// 每2个显示一个标签
}
else
{
}
else
{
...
@@ -688,7 +687,7 @@ onUnmounted(() => {
...
@@ -688,7 +687,7 @@ onUnmounted(() => {
<
style
scoped
>
<
style
scoped
>
.message-chart
{
.message-chart
{
margin
:
24
px
0
16px
;
margin
:
8
px
0
;
/* 完全自适应,不设置固定高度 */
/* 完全自适应,不设置固定高度 */
/* 确保宽度不超过父容器 */
/* 确保宽度不超过父容器 */
box-sizing
:
border-box
;
/* 包含边框和内边距在宽度计算中 */
box-sizing
:
border-box
;
/* 包含边框和内边距在宽度计算中 */
...
...
src/views/components/LineChart.vue
View file @
1a6bb856
<
template
>
<
template
>
<div
class=
"message-chart"
>
<div
class=
"message-chart"
>
<div
class=
"chart-title"
>
{{
title
}}
</div>
<!--
<div
class=
"chart-title"
>
{{
title
}}
</div>
-->
<div
v-if=
"isEmpty"
class=
"chart-empty"
>
<div
v-if=
"isEmpty"
class=
"chart-empty"
>
<div
class=
"empty-icon"
>
📊
</div>
<div
class=
"empty-icon"
>
📊
</div>
<div
class=
"empty-text"
>
暂无数据
</div>
<div
class=
"empty-text"
>
暂无数据
</div>
...
@@ -688,7 +688,7 @@ onUnmounted(() => {
...
@@ -688,7 +688,7 @@ onUnmounted(() => {
<
style
scoped
>
<
style
scoped
>
.message-chart
{
.message-chart
{
margin
:
24
px
0
16px
;
margin
:
8
px
0
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
}
}
...
...
src/views/components/PieChart.vue
View file @
1a6bb856
<
template
>
<
template
>
<div
class=
"pie-chart-container"
>
<div
class=
"pie-chart-container"
>
<div
class=
"chart-title"
>
{{
title
}}
</div>
<!--
<div
class=
"chart-title"
>
{{
title
}}
</div>
-->
<div
v-if=
"isEmpty"
class=
"chart-empty"
>
<div
v-if=
"isEmpty"
class=
"chart-empty"
>
<div
class=
"empty-icon"
>
📊
</div>
<div
class=
"empty-icon"
>
📊
</div>
<div
class=
"empty-text"
>
暂无数据
</div>
<div
class=
"empty-text"
>
暂无数据
</div>
...
@@ -153,22 +153,7 @@ const createPieOption = (chartConfig: any) => {
...
@@ -153,22 +153,7 @@ const createPieOption = (chartConfig: any) => {
// 按值从大到小排序,确保大块在前
// 按值从大到小排序,确保大块在前
pieData
.
sort
((
a
,
b
)
=>
b
.
value
-
a
.
value
);
pieData
.
sort
((
a
,
b
)
=>
b
.
value
-
a
.
value
);
// 如果数据项太多,只显示前10个,其他合并为"其他"
if
(
pieData
.
length
>
10
)
{
const
top10
=
pieData
.
slice
(
0
,
10
);
const
othersValue
=
pieData
.
slice
(
10
).
reduce
((
sum
,
item
)
=>
sum
+
item
.
value
,
0
);
if
(
othersValue
>
0
)
{
top10
.
push
({
name
:
'
其他
'
,
value
:
othersValue
});
}
return
createPieChartOption
(
top10
);
}
return
createPieChartOption
(
pieData
);
return
createPieChartOption
(
pieData
);
};
};
...
@@ -415,7 +400,7 @@ onUnmounted(() => {
...
@@ -415,7 +400,7 @@ onUnmounted(() => {
<
style
scoped
>
<
style
scoped
>
.pie-chart-container
{
.pie-chart-container
{
margin
:
16
px
0
;
margin
:
8
px
0
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
width
:
100%
!important
;
width
:
100%
!important
;
max-width
:
100%
!important
;
max-width
:
100%
!important
;
...
...
src/views/components/TableComponent.vue
View file @
1a6bb856
<
template
>
<
template
>
<div
class=
"message-chart"
>
<div
class=
"message-chart"
>
<!-- 表格标题 -->
<!-- 表格标题 -->
<div
class=
"table-title"
>
{{
tableTitle
}}
</div>
<!--
<div
class=
"table-title"
>
{{
tableTitle
}}
</div>
-->
<!-- Ant Design Table -->
<div
class=
"table-container"
>
<div
class=
"table-container"
>
<a-table
<a-table
:columns=
"tableColumns"
:columns=
"tableColumns"
...
@@ -11,16 +10,20 @@
...
@@ -11,16 +10,20 @@
size=
"middle"
size=
"middle"
:scroll=
"
{ x: 'max-content' }"
:scroll=
"
{ x: 'max-content' }"
:pagination="{
:pagination="{
pageSize: 15,
current: paginationState.current,
pageSize: paginationState.pageSize,
pageSizeOptions: ['15', '20', '30'],
total: processedTableData?.length || 0,
total: processedTableData?.length || 0,
showTotal: (total) => `共${total}条记录`,
showTotal: (total) => `共${total}条记录`,
showSizeChanger: true,
}"
}"
@change="handleTableChange"
class="data-table"
class="data-table"
>
>
<!-- 自定义单元格渲染 -->
<!-- 自定义单元格渲染 -->
<template
#bodyCell
="
{ column, text, record }">
<template
#bodyCell
="
{ column, text, record }">
<div
:class=
"getCellClass(column.dataIndex)"
>
<div
:class=
"getCellClass(column.dataIndex)"
>
{{
renderCellContent
(
column
.
dataIndex
,
text
)
||
'
-
'
}}
{{
renderCellContent
(
column
.
dataIndex
,
text
,
record
)
||
'
-
'
}}
</div>
</div>
</
template
>
</
template
>
</a-table>
</a-table>
...
@@ -31,10 +34,36 @@
...
@@ -31,10 +34,36 @@
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'
vue
'
;
import
{
computed
,
ref
}
from
'
vue
'
;
import
{
Table
as
ATable
}
from
'
ant-design-vue
'
;
import
{
Table
as
ATable
}
from
'
ant-design-vue
'
;
import
{
formatNumber
}
from
'
./utils/utils
'
;
import
{
formatNumber
}
from
'
./utils/utils
'
;
// 分页变化事件
const
emit
=
defineEmits
([
'
paginationChange
'
]);
// 分页状态
const
paginationState
=
ref
({
current
:
1
,
pageSize
:
15
});
// 处理表格变化事件(包括分页、排序等)
const
handleTableChange
=
(
pagination
:
any
,
filters
:
any
,
sorter
:
any
)
=>
{
// 处理分页变化
if
(
pagination
)
{
// 更新分页状态
paginationState
.
value
=
{
current
:
pagination
.
current
||
1
,
pageSize
:
pagination
.
pageSize
||
15
};
}
// 可以在这里添加排序变化的处理
if
(
sorter
)
{
// console.log('排序变化:', sorter);
}
};
// 类型定义
// 类型定义
interface
TableData
{
interface
TableData
{
[
key
:
string
]:
any
;
[
key
:
string
]:
any
;
...
@@ -65,25 +94,36 @@ const processedTableData = computed(() => {
...
@@ -65,25 +94,36 @@ const processedTableData = computed(() => {
// 处理传入完整数据结构的情况
// 处理传入完整数据结构的情况
if
(
Array
.
isArray
(
props
.
tableData
.
rows
))
{
if
(
Array
.
isArray
(
props
.
tableData
.
rows
))
{
//
过滤掉indexFields中的字段,只保留dimFields和indexFieldsFormat中的字段
//
获取字段配置
const
indexFields
=
props
.
tableData
?.
indexFields
||
[];
const
indexFields
=
props
.
tableData
?.
indexFields
||
[];
const
dimFields
=
props
.
tableData
?.
dimFields
||
[];
const
dimFields
=
props
.
tableData
?.
dimFields
||
[];
const
indexFieldsFormat
=
props
.
tableData
?.
indexFieldsFormat
||
[];
const
indexFieldsFormat
=
props
.
tableData
?.
indexFieldsFormat
||
[];
// 需要
保留
的字段:dimFields + indexFields
Format
// 需要
显示
的字段:dimFields + indexFields
const
fieldsTo
Keep
=
[...
dimFields
,
...
indexFields
Format
];
const
fieldsTo
Show
=
[...
dimFields
,
...
indexFields
];
return
props
.
tableData
.
rows
.
map
(
row
=>
{
return
props
.
tableData
.
rows
.
map
(
row
=>
{
const
filter
edRow
:
Record
<
string
,
any
>
=
{};
const
process
edRow
:
Record
<
string
,
any
>
=
{};
//
只保留需要的
字段
//
处理每个
字段
fieldsTo
Keep
.
forEach
(
field
=>
{
fieldsTo
Show
.
forEach
(
field
=>
{
if
(
row
.
hasOwnProperty
(
field
))
{
if
(
row
.
hasOwnProperty
(
field
))
{
filteredRow
[
field
]
=
row
[
field
];
// 如果是indexFields字段,检查是否有对应的indexFieldsFormat字段
const
fieldIndex
=
indexFields
.
indexOf
(
field
);
if
(
fieldIndex
!==
-
1
&&
indexFieldsFormat
[
fieldIndex
]
&&
row
.
hasOwnProperty
(
indexFieldsFormat
[
fieldIndex
]))
{
// 使用indexFieldsFormat的格式化值来显示,但保留原始值用于排序
processedRow
[
field
]
=
{
display
:
row
[
indexFieldsFormat
[
fieldIndex
]],
value
:
row
[
field
]
};
}
else
{
// 其他字段直接使用原始值
processedRow
[
field
]
=
row
[
field
];
}
}
}
});
});
return
filter
edRow
;
return
process
edRow
;
});
});
}
else
if
(
Array
.
isArray
(
props
.
tableData
))
{
}
else
if
(
Array
.
isArray
(
props
.
tableData
))
{
return
props
.
tableData
;
return
props
.
tableData
;
...
@@ -94,11 +134,11 @@ const processedTableData = computed(() => {
...
@@ -94,11 +134,11 @@ const processedTableData = computed(() => {
// 判断列是否为数字列
// 判断列是否为数字列
const
isNumericColumn
=
(
header
:
string
)
=>
{
const
isNumericColumn
=
(
header
:
string
)
=>
{
// 使用indexFields
Format来判断数字列,而不是indexFields
// 使用indexFields
来判断数字列
const
indexFields
Format
=
props
.
tableData
?.
indexFields
Format
||
[];
const
indexFields
=
props
.
tableData
?.
indexFields
||
[];
//
只
通过indexFields
Format
来判断数字列
// 通过indexFields来判断数字列
return
indexFields
Format
.
includes
(
header
);
return
indexFields
.
includes
(
header
);
};
};
// 表格标题
// 表格标题
...
@@ -114,13 +154,19 @@ const tableTitle = computed(() => {
...
@@ -114,13 +154,19 @@ const tableTitle = computed(() => {
const
tableColumns
=
computed
(()
=>
{
const
tableColumns
=
computed
(()
=>
{
if
(
processedTableData
.
value
.
length
===
0
)
return
[];
if
(
processedTableData
.
value
.
length
===
0
)
return
[];
// 使用过滤后的数据的字段作为表头
// 获取字段配置
const
indexFields
=
props
.
tableData
?.
indexFields
||
[];
// 使用处理后的数据的字段作为表头
const
headers
=
Object
.
keys
(
processedTableData
.
value
[
0
]);
const
headers
=
Object
.
keys
(
processedTableData
.
value
[
0
]);
return
headers
.
map
(
header
=>
{
return
headers
.
map
(
header
=>
{
// 将字段名中的FORMAT后缀去掉
// 将字段名中的FORMAT后缀去掉
const
displayHeader
=
header
.
replace
(
/FORMAT$/
,
''
);
const
displayHeader
=
header
.
replace
(
/FORMAT$/
,
''
);
// 判断当前字段是否为indexFields字段
const
isIndexField
=
indexFields
.
includes
(
header
);
return
{
return
{
title
:
displayHeader
,
title
:
displayHeader
,
dataIndex
:
header
,
dataIndex
:
header
,
...
@@ -129,9 +175,17 @@ const tableColumns = computed(() => {
...
@@ -129,9 +175,17 @@ const tableColumns = computed(() => {
width
:
getColumnWidth
(
header
),
width
:
getColumnWidth
(
header
),
ellipsis
:
true
,
ellipsis
:
true
,
sorter
:
isNumericColumn
(
header
)
?
(
a
,
b
)
=>
{
sorter
:
isNumericColumn
(
header
)
?
(
a
,
b
)
=>
{
const
aValue
=
parseFloat
(
a
[
header
]);
// 对于indexFields字段,使用存储的原始值进行排序
const
bValue
=
parseFloat
(
b
[
header
]);
if
(
isIndexField
&&
a
[
header
]
&&
a
[
header
].
value
!==
undefined
)
{
return
aValue
-
bValue
;
const
aValue
=
parseFloat
(
a
[
header
].
value
);
const
bValue
=
parseFloat
(
b
[
header
].
value
);
return
aValue
-
bValue
;
}
else
{
// 其他字段直接使用当前字段排序
const
aValue
=
parseFloat
(
a
[
header
]);
const
bValue
=
parseFloat
(
b
[
header
]);
return
aValue
-
bValue
;
}
}
:
undefined
}
:
undefined
};
};
});
});
...
@@ -187,7 +241,12 @@ const getCellClass = (header: string) => {
...
@@ -187,7 +241,12 @@ const getCellClass = (header: string) => {
};
};
// 渲染单元格内容
// 渲染单元格内容
const
renderCellContent
=
(
header
:
string
,
value
:
any
)
=>
{
const
renderCellContent
=
(
header
:
string
,
value
:
any
,
record
:
any
)
=>
{
// 处理indexFields字段的特殊数据结构
if
(
value
&&
typeof
value
===
'
object
'
&&
value
.
display
!==
undefined
)
{
value
=
value
.
display
;
}
// 如果是趋势列,根据up/down值显示箭头图标
// 如果是趋势列,根据up/down值显示箭头图标
if
(
isTrendColumn
(
header
))
{
if
(
isTrendColumn
(
header
))
{
const
trendValue
=
String
(
value
).
toLowerCase
().
trim
();
const
trendValue
=
String
(
value
).
toLowerCase
().
trim
();
...
@@ -205,7 +264,7 @@ const renderCellContent = (header: string, value: any) => {
...
@@ -205,7 +264,7 @@ const renderCellContent = (header: string, value: any) => {
.message-chart
{
.message-chart
{
width
:
100%
;
width
:
100%
;
max-width
:
100%
;
max-width
:
100%
;
margin
:
24px
0
16px
;
margin
:
0
0
16px
;
}
}
.table-title
{
.table-title
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment