feat: 添加最小会议时长配置和优化设备列表样式

- 在 `AndroidMeetingController` 和 `AndroidMeetingConfigVo` 中添加最小会议时长配置
- 优化 `ListTable` 组件的滚动样式和逻辑
- 更新 `devices/index.less` 和 `devices/index.tsx`,改进设备列表单元格样式和内容展示
dev_na
chenhao 2026-06-16 16:35:17 +08:00
parent 443e067b30
commit 8d4a31e043
7 changed files with 71 additions and 5 deletions

View File

@ -22,6 +22,10 @@ public final class SysParamKeys {
public static final String MEETING_MAX_PAUSE_DURATION = "meeting.max_pause_duration"; public static final String MEETING_MAX_PAUSE_DURATION = "meeting.max_pause_duration";
/** 单场会议最大时长,单位分钟。 */ /** 单场会议最大时长,单位分钟。 */
public static final String MEETING_MAX_MEETING_DURATION = "meeting.max_meeting_duration"; public static final String MEETING_MAX_MEETING_DURATION = "meeting.max_meeting_duration";
/**
*
*/
public static final String MEETING_MIN_MEETING_DURATION = "meeting.min_meeting_duration";
/** 会议音频传输丢包率配置值。 */ /** 会议音频传输丢包率配置值。 */
public static final String MEETING_PACKET_LOSS_RATE = "meeting.packet_loss_rate"; public static final String MEETING_PACKET_LOSS_RATE = "meeting.packet_loss_rate";
/** 安卓端是否启用音频分片上传。 */ /** 安卓端是否启用音频分片上传。 */

View File

@ -453,6 +453,7 @@ public class AndroidMeetingController {
resultVo.setModelsList(enabledModels); resultVo.setModelsList(enabledModels);
resultVo.setSummaryDegreeOfDetail(dictItemService.getItemsByTypeCode("summary_degree_detail")); resultVo.setSummaryDegreeOfDetail(dictItemService.getItemsByTypeCode("summary_degree_detail"));
resultVo.setMaxMeetingDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MAX_MEETING_DURATION,"30"))); resultVo.setMaxMeetingDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MAX_MEETING_DURATION,"30")));
resultVo.setMinMeetingDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MIN_MEETING_DURATION, "10")));
resultVo.setMaxPauseDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MAX_PAUSE_DURATION,String.valueOf(60*4)))); resultVo.setMaxPauseDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MAX_PAUSE_DURATION,String.valueOf(60*4))));
BigDecimal bigDecimal = new BigDecimal(paramService.getParamValue(SysParamKeys.MEETING_MAX_PAUSE_DURATION, "99")); BigDecimal bigDecimal = new BigDecimal(paramService.getParamValue(SysParamKeys.MEETING_MAX_PAUSE_DURATION, "99"));
bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP); bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);

View File

@ -35,6 +35,8 @@ public class AndroidMeetingConfigVo {
private Integer maxPauseDuration; private Integer maxPauseDuration;
@io.swagger.v3.oas.annotations.media.Schema(description = "最大会议时长,单位分钟") @io.swagger.v3.oas.annotations.media.Schema(description = "最大会议时长,单位分钟")
private Integer maxMeetingDuration; private Integer maxMeetingDuration;
@io.swagger.v3.oas.annotations.media.Schema(description = "最小会议时长,单位秒")
private Integer minMeetingDuration;
@io.swagger.v3.oas.annotations.media.Schema(description = "允许的最大丢包率") @io.swagger.v3.oas.annotations.media.Schema(description = "允许的最大丢包率")
private BigDecimal packetLossRate; private BigDecimal packetLossRate;
@io.swagger.v3.oas.annotations.media.Schema(description = "是否启用音频分片上传") @io.swagger.v3.oas.annotations.media.Schema(description = "是否启用音频分片上传")

View File

@ -47,3 +47,31 @@
color: var(--link-color); color: var(--link-color);
opacity: 0.8; opacity: 0.8;
} }
.list-table-container .list-table-table--y-scroll.ant-table-wrapper,
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-spin-nested-loading,
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-spin-container,
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-table,
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-table-container {
height: 100%;
min-height: 0;
}
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-spin-container,
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-table,
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-table-container {
display: flex;
flex-direction: column;
}
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-table-content {
flex: none;
min-height: auto;
}
.list-table-container .list-table-table--y-scroll.ant-table-wrapper .ant-table-body {
flex: 1 1 auto;
min-height: 0;
max-height: var(--list-table-scroll-y) !important;
overflow-y: auto !important;
}

View File

@ -45,6 +45,7 @@ function ListTable<T extends Record<string, any>>({
className = "", className = "",
onChange, onChange,
}: ListTableProps<T>) { }: ListTableProps<T>) {
const hasVerticalScroll = scroll?.y !== undefined;
const rowSelection: TableProps<T>["rowSelection"] = onSelectionChange const rowSelection: TableProps<T>["rowSelection"] = onSelectionChange
? { ? {
selectedRowKeys, selectedRowKeys,
@ -101,9 +102,16 @@ function ListTable<T extends Record<string, any>>({
), ),
}; };
const wrapperStyle = hasVerticalScroll
? ({
["--list-table-scroll-y" as string]: typeof scroll.y === "number" ? `${scroll.y}px` : scroll.y,
} as React.CSSProperties)
: undefined;
return ( return (
<div className={`list-table-container ${className}`}> <div className={`list-table-container ${className}`} style={wrapperStyle}>
<Table <Table
className={hasVerticalScroll ? "list-table-table--y-scroll" : undefined}
size="middle" size="middle"
rowSelection={rowSelection} rowSelection={rowSelection}
columns={columns} columns={columns}

View File

@ -141,12 +141,25 @@
font-size: 20px; font-size: 20px;
} }
.device-cell {
width: 100%;
min-width: 0;
align-items: center;
}
.device-cell__content {
flex: 1;
min-width: 0;
}
.device-name { .device-name {
display: block;
font-weight: 600; font-weight: 600;
color: #262626; color: #262626;
} }
.device-code { .device-code {
display: block;
font-size: 12px; font-size: 12px;
color: #8c8c8c; color: #8c8c8c;
} }
@ -162,6 +175,11 @@
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.app-page__table-wrap .ant-table-wrapper .ant-table-cell-fix-right-first,
.app-page__table-wrap .ant-table-wrapper .ant-table-cell-fix-right-last {
right: 0 !important;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.devices-page { .devices-page {
padding: 16px; padding: 16px;

View File

@ -141,14 +141,19 @@ export default function Devices() {
title: t("devicesExt.device"), title: t("devicesExt.device"),
key: "device", key: "device",
width: 280, width: 280,
ellipsis: {showTitle: true},
render: (_value: unknown, record: DeviceInfo) => ( render: (_value: unknown, record: DeviceInfo) => (
<Space> <Space className="device-cell">
<div className="device-icon-placeholder"> <div className="device-icon-placeholder">
<DesktopOutlined aria-hidden="true" /> <DesktopOutlined aria-hidden="true" />
</div> </div>
<div> <div className="device-cell__content">
<div className="device-name font-medium">{record.deviceName || t("devicesExt.unnamedDevice")}</div> <Text className="device-name" ellipsis={{tooltip: record.deviceName || t("devicesExt.unnamedDevice")}}>
<div className="device-code text-xs text-gray-400 tabular-nums">{record.deviceCode}</div> {record.deviceName || t("devicesExt.unnamedDevice")}
</Text>
<Text className="device-code tabular-nums" ellipsis={{tooltip: record.deviceCode}}>
{record.deviceCode}
</Text>
</div> </div>
</Space> </Space>
) )