whistle.mock-plugins 1.2.2-beta.2 → 1.2.2-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION.md +16 -1
- package/app/public/js/index.js +1 -1
- package/package.json +1 -1
- package/ui/src/components/interface-management/DataManagementDrawer.js +115 -0
- package/ui/src/components/interface-management/index.js +1 -0
- package/ui/src/pages/InterfaceManagementV2.js +137 -19
- package/ui/src/pages/Settings.js +40 -6
- package/ui/src/styles/interface-management.css +3 -11
- package/ui/src/styles/settings.css +29 -0
package/package.json
CHANGED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Drawer, Form, Input, message, Button, Space } from 'antd';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { ResponseContentEditor, PreviewModal, formatResponseContent, refreshCacheAfterUpdate } from '.';
|
|
5
|
+
|
|
6
|
+
const DataManagementDrawer = ({ visible, onCancel, interfaceItem, onSaved }) => {
|
|
7
|
+
const [form] = Form.useForm();
|
|
8
|
+
const [previewVisible, setPreviewVisible] = useState(false);
|
|
9
|
+
const [previewContent, setPreviewContent] = useState(null);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (visible && interfaceItem) {
|
|
13
|
+
let responses = Array.isArray(interfaceItem.responses) ? interfaceItem.responses : [];
|
|
14
|
+
let activeResponseId = interfaceItem.activeResponseId || (responses[0] && responses[0].id) || '';
|
|
15
|
+
form.setFieldsValue({ responses, activeResponseId });
|
|
16
|
+
}
|
|
17
|
+
}, [visible, interfaceItem]);
|
|
18
|
+
|
|
19
|
+
const handlePreview = () => {
|
|
20
|
+
const values = form.getFieldsValue(true);
|
|
21
|
+
const responses = Array.isArray(values.responses) ? values.responses : [];
|
|
22
|
+
const activeResponse = responses.find(r => r.id === values.activeResponseId) || responses[0];
|
|
23
|
+
if (!activeResponse) {
|
|
24
|
+
message.error('未找到有效的响应内容');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const contentType = 'application/json; charset=utf-8';
|
|
28
|
+
const formatted = formatResponseContent(activeResponse.content || '', contentType);
|
|
29
|
+
setPreviewContent({ title: `预览: ${activeResponse.name || '未命名响应'}`, content: formatted, contentType, description: '' });
|
|
30
|
+
setPreviewVisible(true);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleOk = async () => {
|
|
34
|
+
try {
|
|
35
|
+
await form.validateFields();
|
|
36
|
+
const values = form.getFieldsValue(true);
|
|
37
|
+
const payload = {
|
|
38
|
+
responses: Array.isArray(values.responses) ? values.responses : [],
|
|
39
|
+
activeResponseId: values.activeResponseId || (values.responses && values.responses[0] && values.responses[0].id) || ''
|
|
40
|
+
};
|
|
41
|
+
if (!interfaceItem || !interfaceItem.id) {
|
|
42
|
+
message.error('缺少接口ID,无法保存');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const res = await axios.patch(`/cgi-bin/interfaces/${interfaceItem.id}`, payload);
|
|
46
|
+
if (res.data && res.data.code === 0) {
|
|
47
|
+
message.success('保存成功');
|
|
48
|
+
await refreshCacheAfterUpdate();
|
|
49
|
+
if (onSaved) onSaved();
|
|
50
|
+
if (onCancel) onCancel();
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error(res.data?.message || '保存失败');
|
|
53
|
+
}
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (err && err.errorFields) return; // 表单校验错误
|
|
56
|
+
console.error('保存失败', err);
|
|
57
|
+
message.error(err.response?.data?.message || err.message || '保存失败');
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<Drawer
|
|
64
|
+
title="数据管理"
|
|
65
|
+
placement="right"
|
|
66
|
+
width={1040}
|
|
67
|
+
open={visible}
|
|
68
|
+
onClose={onCancel}
|
|
69
|
+
destroyOnClose
|
|
70
|
+
bodyStyle={{ paddingBottom: 80 }}
|
|
71
|
+
footer={
|
|
72
|
+
<div style={{ textAlign: 'right' }}>
|
|
73
|
+
<Space>
|
|
74
|
+
<Button onClick={onCancel}>取消</Button>
|
|
75
|
+
<Button type="primary" onClick={handleOk}>保存</Button>
|
|
76
|
+
</Space>
|
|
77
|
+
</div>
|
|
78
|
+
}
|
|
79
|
+
>
|
|
80
|
+
<Form form={form} layout="vertical" initialValues={{ responses: [], activeResponseId: '' }}>
|
|
81
|
+
<Form.Item name="responses" hidden>
|
|
82
|
+
<Input />
|
|
83
|
+
</Form.Item>
|
|
84
|
+
<Form.Item name="activeResponseId" hidden>
|
|
85
|
+
<Input />
|
|
86
|
+
</Form.Item>
|
|
87
|
+
<Form.Item noStyle shouldUpdate>
|
|
88
|
+
{({ getFieldValue }) => {
|
|
89
|
+
const responses = getFieldValue('responses') || [];
|
|
90
|
+
const activeResponseId = getFieldValue('activeResponseId') || (responses[0] && responses[0].id) || '';
|
|
91
|
+
return (
|
|
92
|
+
<ResponseContentEditor
|
|
93
|
+
form={form}
|
|
94
|
+
responses={responses}
|
|
95
|
+
activeResponseId={activeResponseId}
|
|
96
|
+
onPreview={handlePreview}
|
|
97
|
+
enableSorting={true}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}}
|
|
101
|
+
</Form.Item>
|
|
102
|
+
</Form>
|
|
103
|
+
</Drawer>
|
|
104
|
+
|
|
105
|
+
<PreviewModal
|
|
106
|
+
visible={previewVisible}
|
|
107
|
+
onCancel={() => setPreviewVisible(false)}
|
|
108
|
+
previewContent={previewContent}
|
|
109
|
+
/>
|
|
110
|
+
</>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export default DataManagementDrawer;
|
|
115
|
+
|
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
export { default as ResponseContentEditor } from './ResponseContentEditor';
|
|
3
3
|
export { default as InterfaceTestModal } from './InterfaceTestModal';
|
|
4
4
|
export { default as PreviewModal } from './PreviewModal';
|
|
5
|
+
export { default as DataManagementDrawer } from './DataManagementDrawer';
|
|
5
6
|
export * from './constants';
|
|
6
7
|
export * from './utils';
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
generateResponseId
|
|
33
33
|
} from '../components/interface-management';
|
|
34
34
|
import DataManagementModal from '../components/interface-management/DataManagementModal';
|
|
35
|
+
import { DataManagementDrawer } from '../components/interface-management';
|
|
35
36
|
|
|
36
37
|
const { Option } = Select;
|
|
37
38
|
const { Search } = AntInput;
|
|
@@ -91,6 +92,9 @@ const InterfaceManagement = () => {
|
|
|
91
92
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
|
92
93
|
const [drawerVisible, setDrawerVisible] = useState(false);
|
|
93
94
|
|
|
95
|
+
// 数据管理显示模式
|
|
96
|
+
const [displayMode, setDisplayMode] = useState('modal');
|
|
97
|
+
|
|
94
98
|
// 表单实例
|
|
95
99
|
const [form] = Form.useForm();
|
|
96
100
|
|
|
@@ -138,6 +142,29 @@ const InterfaceManagement = () => {
|
|
|
138
142
|
}
|
|
139
143
|
}, [selectedFeatureId]);
|
|
140
144
|
|
|
145
|
+
// 监听数据管理显示模式变化
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
// 初始化时从 localStorage 读取配置
|
|
148
|
+
const savedMode = localStorage.getItem('dataManagementDisplayMode');
|
|
149
|
+
if (savedMode) {
|
|
150
|
+
setDisplayMode(savedMode);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 监听 storage 事件,实现设置立即生效
|
|
154
|
+
const handleStorageChange = () => {
|
|
155
|
+
const newMode = localStorage.getItem('dataManagementDisplayMode');
|
|
156
|
+
if (newMode) {
|
|
157
|
+
setDisplayMode(newMode);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
window.addEventListener('storage', handleStorageChange);
|
|
162
|
+
|
|
163
|
+
return () => {
|
|
164
|
+
window.removeEventListener('storage', handleStorageChange);
|
|
165
|
+
};
|
|
166
|
+
}, []);
|
|
167
|
+
|
|
141
168
|
// 获取当前选中的功能模块
|
|
142
169
|
const selectedFeature = features.find(f => f.id === selectedFeatureId);
|
|
143
170
|
|
|
@@ -693,7 +720,17 @@ const InterfaceManagement = () => {
|
|
|
693
720
|
saveTableConfig({
|
|
694
721
|
visibleColumns: defaultColumns,
|
|
695
722
|
columnWidths: {
|
|
696
|
-
|
|
723
|
+
active: 80,
|
|
724
|
+
name: 150,
|
|
725
|
+
group: 120,
|
|
726
|
+
urlPattern: 250,
|
|
727
|
+
proxyType: 120,
|
|
728
|
+
currentResponse: 180,
|
|
729
|
+
responseDelay: 100,
|
|
730
|
+
httpStatus: 100,
|
|
731
|
+
contentType: 120,
|
|
732
|
+
targetUrl: 200,
|
|
733
|
+
customHeaders: 100
|
|
697
734
|
}
|
|
698
735
|
});
|
|
699
736
|
};
|
|
@@ -740,11 +777,21 @@ const InterfaceManagement = () => {
|
|
|
740
777
|
|
|
741
778
|
const startX = e.clientX;
|
|
742
779
|
const startWidth = width;
|
|
780
|
+
let currentWidth = startWidth;
|
|
743
781
|
|
|
744
782
|
const handleMouseMove = (moveEvent) => {
|
|
745
783
|
const deltaX = moveEvent.clientX - startX;
|
|
746
|
-
|
|
747
|
-
|
|
784
|
+
currentWidth = Math.max(50, startWidth + deltaX); // 最小宽度 50px
|
|
785
|
+
|
|
786
|
+
// 实时更新列宽(不保存到 localStorage)
|
|
787
|
+
const newColumnWidths = {
|
|
788
|
+
...tableConfig.columnWidths,
|
|
789
|
+
[columnKey]: currentWidth
|
|
790
|
+
};
|
|
791
|
+
setTableConfig(prev => ({
|
|
792
|
+
...prev,
|
|
793
|
+
columnWidths: newColumnWidths
|
|
794
|
+
}));
|
|
748
795
|
};
|
|
749
796
|
|
|
750
797
|
const handleMouseUp = () => {
|
|
@@ -752,6 +799,9 @@ const InterfaceManagement = () => {
|
|
|
752
799
|
document.removeEventListener('mouseup', handleMouseUp);
|
|
753
800
|
document.body.style.cursor = '';
|
|
754
801
|
document.body.style.userSelect = '';
|
|
802
|
+
|
|
803
|
+
// 拖动结束后保存到 localStorage
|
|
804
|
+
onResize(columnKey, currentWidth);
|
|
755
805
|
};
|
|
756
806
|
|
|
757
807
|
document.addEventListener('mousemove', handleMouseMove);
|
|
@@ -815,7 +865,12 @@ const InterfaceManagement = () => {
|
|
|
815
865
|
title: '状态',
|
|
816
866
|
dataIndex: 'active',
|
|
817
867
|
key: 'active',
|
|
818
|
-
width: 80,
|
|
868
|
+
width: tableConfig.columnWidths?.active || 80,
|
|
869
|
+
onHeaderCell: (column) => ({
|
|
870
|
+
width: column.width,
|
|
871
|
+
columnKey: 'active',
|
|
872
|
+
onResize: handleResize,
|
|
873
|
+
}),
|
|
819
874
|
render: (active, record) => (
|
|
820
875
|
<Switch
|
|
821
876
|
checked={active !== false}
|
|
@@ -828,6 +883,12 @@ const InterfaceManagement = () => {
|
|
|
828
883
|
title: '名称',
|
|
829
884
|
dataIndex: 'name',
|
|
830
885
|
key: 'name',
|
|
886
|
+
width: tableConfig.columnWidths?.name || 150,
|
|
887
|
+
onHeaderCell: (column) => ({
|
|
888
|
+
width: column.width,
|
|
889
|
+
columnKey: 'name',
|
|
890
|
+
onResize: handleResize,
|
|
891
|
+
}),
|
|
831
892
|
sorter: (a, b) => a.name.localeCompare(b.name),
|
|
832
893
|
render: (text) => <span className="interface-name">{text}</span>,
|
|
833
894
|
},
|
|
@@ -835,7 +896,12 @@ const InterfaceManagement = () => {
|
|
|
835
896
|
title: '分组',
|
|
836
897
|
dataIndex: 'group',
|
|
837
898
|
key: 'group',
|
|
838
|
-
width: 120,
|
|
899
|
+
width: tableConfig.columnWidths?.group || 120,
|
|
900
|
+
onHeaderCell: (column) => ({
|
|
901
|
+
width: column.width,
|
|
902
|
+
columnKey: 'group',
|
|
903
|
+
onResize: handleResize,
|
|
904
|
+
}),
|
|
839
905
|
sorter: (a, b) => {
|
|
840
906
|
const groupA = a.group || '';
|
|
841
907
|
const groupB = b.group || '';
|
|
@@ -856,6 +922,12 @@ const InterfaceManagement = () => {
|
|
|
856
922
|
title: 'URL匹配规则',
|
|
857
923
|
dataIndex: 'urlPattern',
|
|
858
924
|
key: 'urlPattern',
|
|
925
|
+
width: tableConfig.columnWidths?.urlPattern || 250,
|
|
926
|
+
onHeaderCell: (column) => ({
|
|
927
|
+
width: column.width,
|
|
928
|
+
columnKey: 'urlPattern',
|
|
929
|
+
onResize: handleResize,
|
|
930
|
+
}),
|
|
859
931
|
ellipsis: true,
|
|
860
932
|
render: (text) => <span className="url-pattern">{text}</span>,
|
|
861
933
|
},
|
|
@@ -863,7 +935,12 @@ const InterfaceManagement = () => {
|
|
|
863
935
|
title: '处理方式',
|
|
864
936
|
dataIndex: 'proxyType',
|
|
865
937
|
key: 'proxyType',
|
|
866
|
-
width: 120,
|
|
938
|
+
width: tableConfig.columnWidths?.proxyType || 120,
|
|
939
|
+
onHeaderCell: (column) => ({
|
|
940
|
+
width: column.width,
|
|
941
|
+
columnKey: 'proxyType',
|
|
942
|
+
onResize: handleResize,
|
|
943
|
+
}),
|
|
867
944
|
render: (text) => {
|
|
868
945
|
const proxyType = proxyTypes.find(item => item.value === text);
|
|
869
946
|
return (
|
|
@@ -879,11 +956,15 @@ const InterfaceManagement = () => {
|
|
|
879
956
|
dataIndex: 'activeResponseId',
|
|
880
957
|
key: 'currentResponse',
|
|
881
958
|
width: tableConfig.columnWidths?.currentResponse || 180,
|
|
959
|
+
className: 'current-response-column',
|
|
882
960
|
onHeaderCell: (column) => ({
|
|
883
961
|
width: column.width,
|
|
884
962
|
columnKey: 'currentResponse',
|
|
885
963
|
onResize: handleResize,
|
|
886
964
|
}),
|
|
965
|
+
onCell: () => ({
|
|
966
|
+
className: 'current-response-cell',
|
|
967
|
+
}),
|
|
887
968
|
render: (activeResponseId, record) => {
|
|
888
969
|
// 如果没有响应数据,返回空
|
|
889
970
|
if (!record.responses || !Array.isArray(record.responses) || record.responses.length === 0) {
|
|
@@ -917,7 +998,12 @@ const InterfaceManagement = () => {
|
|
|
917
998
|
title: '延迟(毫秒)',
|
|
918
999
|
dataIndex: 'responseDelay',
|
|
919
1000
|
key: 'responseDelay',
|
|
920
|
-
width: 100,
|
|
1001
|
+
width: tableConfig.columnWidths?.responseDelay || 100,
|
|
1002
|
+
onHeaderCell: (column) => ({
|
|
1003
|
+
width: column.width,
|
|
1004
|
+
columnKey: 'responseDelay',
|
|
1005
|
+
onResize: handleResize,
|
|
1006
|
+
}),
|
|
921
1007
|
sorter: (a, b) => (a.responseDelay || 0) - (b.responseDelay || 0),
|
|
922
1008
|
render: (delay) => {
|
|
923
1009
|
const delayValue = parseInt(delay, 10) || 0;
|
|
@@ -932,7 +1018,12 @@ const InterfaceManagement = () => {
|
|
|
932
1018
|
title: '状态码',
|
|
933
1019
|
dataIndex: 'httpStatus',
|
|
934
1020
|
key: 'httpStatus',
|
|
935
|
-
width: 100,
|
|
1021
|
+
width: tableConfig.columnWidths?.httpStatus || 100,
|
|
1022
|
+
onHeaderCell: (column) => ({
|
|
1023
|
+
width: column.width,
|
|
1024
|
+
columnKey: 'httpStatus',
|
|
1025
|
+
onResize: handleResize,
|
|
1026
|
+
}),
|
|
936
1027
|
render: (status) => {
|
|
937
1028
|
const statusCode = status || 200;
|
|
938
1029
|
let statusClass = 'status-success';
|
|
@@ -948,7 +1039,12 @@ const InterfaceManagement = () => {
|
|
|
948
1039
|
title: '内容类型',
|
|
949
1040
|
dataIndex: 'contentType',
|
|
950
1041
|
key: 'contentType',
|
|
951
|
-
width: 120,
|
|
1042
|
+
width: tableConfig.columnWidths?.contentType || 120,
|
|
1043
|
+
onHeaderCell: (column) => ({
|
|
1044
|
+
width: column.width,
|
|
1045
|
+
columnKey: 'contentType',
|
|
1046
|
+
onResize: handleResize,
|
|
1047
|
+
}),
|
|
952
1048
|
sorter: (a, b) => {
|
|
953
1049
|
const aType = a.contentType || '';
|
|
954
1050
|
const bType = b.contentType || '';
|
|
@@ -967,6 +1063,12 @@ const InterfaceManagement = () => {
|
|
|
967
1063
|
title: '目标URL',
|
|
968
1064
|
dataIndex: 'targetUrl',
|
|
969
1065
|
key: 'targetUrl',
|
|
1066
|
+
width: tableConfig.columnWidths?.targetUrl || 200,
|
|
1067
|
+
onHeaderCell: (column) => ({
|
|
1068
|
+
width: column.width,
|
|
1069
|
+
columnKey: 'targetUrl',
|
|
1070
|
+
onResize: handleResize,
|
|
1071
|
+
}),
|
|
970
1072
|
ellipsis: true,
|
|
971
1073
|
sorter: (a, b) => {
|
|
972
1074
|
const aUrl = a.targetUrl || '';
|
|
@@ -982,7 +1084,12 @@ const InterfaceManagement = () => {
|
|
|
982
1084
|
title: '自定义头',
|
|
983
1085
|
dataIndex: 'customHeaders',
|
|
984
1086
|
key: 'customHeaders',
|
|
985
|
-
width: 100,
|
|
1087
|
+
width: tableConfig.columnWidths?.customHeaders || 100,
|
|
1088
|
+
onHeaderCell: (column) => ({
|
|
1089
|
+
width: column.width,
|
|
1090
|
+
columnKey: 'customHeaders',
|
|
1091
|
+
onResize: handleResize,
|
|
1092
|
+
}),
|
|
986
1093
|
sorter: (a, b) => {
|
|
987
1094
|
const aCount = Object.keys(a.customHeaders || {}).length;
|
|
988
1095
|
const bCount = Object.keys(b.customHeaders || {}).length;
|
|
@@ -2008,15 +2115,26 @@ const InterfaceManagement = () => {
|
|
|
2008
2115
|
previewContent={previewContent}
|
|
2009
2116
|
/>
|
|
2010
2117
|
|
|
2011
|
-
{/*
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2118
|
+
{/* 数据管理弹窗/抽屉 */}
|
|
2119
|
+
{displayMode === 'drawer' ? (
|
|
2120
|
+
<DataManagementDrawer
|
|
2121
|
+
visible={dataModalVisible}
|
|
2122
|
+
onCancel={() => { setDataModalVisible(false); setDataModalRecord(null); }}
|
|
2123
|
+
interfaceItem={dataModalRecord}
|
|
2124
|
+
onSaved={() => {
|
|
2125
|
+
fetchInterfaces();
|
|
2126
|
+
}}
|
|
2127
|
+
/>
|
|
2128
|
+
) : (
|
|
2129
|
+
<DataManagementModal
|
|
2130
|
+
visible={dataModalVisible}
|
|
2131
|
+
onCancel={() => { setDataModalVisible(false); setDataModalRecord(null); }}
|
|
2132
|
+
interfaceItem={dataModalRecord}
|
|
2133
|
+
onSaved={() => {
|
|
2134
|
+
fetchInterfaces();
|
|
2135
|
+
}}
|
|
2136
|
+
/>
|
|
2137
|
+
)}
|
|
2020
2138
|
</div>
|
|
2021
2139
|
</AppLayout>
|
|
2022
2140
|
);
|
package/ui/src/pages/Settings.js
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import AppLayout from '../components/AppLayout';
|
|
3
|
-
import { Card, Typography,
|
|
3
|
+
import { Card, Typography, Switch, Space, Divider } from 'antd';
|
|
4
4
|
import '../styles/settings.css';
|
|
5
5
|
|
|
6
6
|
const { Title, Text, Paragraph } = Typography;
|
|
7
7
|
|
|
8
8
|
const Settings = () => {
|
|
9
|
+
const [displayMode, setDisplayMode] = useState('modal');
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// 从 localStorage 读取配置
|
|
13
|
+
const savedMode = localStorage.getItem('dataManagementDisplayMode');
|
|
14
|
+
if (savedMode) {
|
|
15
|
+
setDisplayMode(savedMode);
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
|
|
19
|
+
const handleDisplayModeChange = (checked) => {
|
|
20
|
+
const newMode = checked ? 'drawer' : 'modal';
|
|
21
|
+
setDisplayMode(newMode);
|
|
22
|
+
localStorage.setItem('dataManagementDisplayMode', newMode);
|
|
23
|
+
|
|
24
|
+
// 触发 storage 事件,通知其他页面
|
|
25
|
+
window.dispatchEvent(new Event('storage'));
|
|
26
|
+
};
|
|
27
|
+
|
|
9
28
|
return (
|
|
10
29
|
<AppLayout>
|
|
11
30
|
<div className="page-container">
|
|
@@ -19,10 +38,25 @@ const Settings = () => {
|
|
|
19
38
|
</div>
|
|
20
39
|
|
|
21
40
|
<Card title="界面设置" className="settings-card">
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
41
|
+
<div className="settings-item">
|
|
42
|
+
<div className="settings-item-header">
|
|
43
|
+
<div>
|
|
44
|
+
<div className="settings-item-title">数据管理交互</div>
|
|
45
|
+
<div className="settings-item-description">
|
|
46
|
+
选择数据管理的显示方式
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<Space>
|
|
50
|
+
<Text type="secondary">
|
|
51
|
+
{displayMode === 'drawer' ? '抽屉模式' : '弹窗模式'}
|
|
52
|
+
</Text>
|
|
53
|
+
<Switch
|
|
54
|
+
checked={displayMode === 'drawer'}
|
|
55
|
+
onChange={handleDisplayModeChange}
|
|
56
|
+
/>
|
|
57
|
+
</Space>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
26
60
|
</Card>
|
|
27
61
|
</div>
|
|
28
62
|
</AppLayout>
|
|
@@ -294,20 +294,12 @@
|
|
|
294
294
|
.interface-table td {
|
|
295
295
|
padding: 12px 16px !important;
|
|
296
296
|
white-space: nowrap;
|
|
297
|
-
overflow:
|
|
297
|
+
overflow: hidden;
|
|
298
298
|
text-overflow: ellipsis;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
/*
|
|
302
|
-
.interface-
|
|
303
|
-
overflow: visible !important;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.interface-list-container .ant-table-container {
|
|
307
|
-
overflow: visible !important;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
.interface-list-container .ant-table-body {
|
|
301
|
+
/* 当前响应列需要 overflow: visible 以显示完整的下拉菜单 */
|
|
302
|
+
.interface-table td.current-response-cell {
|
|
311
303
|
overflow: visible !important;
|
|
312
304
|
}
|
|
313
305
|
|
|
@@ -33,6 +33,35 @@
|
|
|
33
33
|
font-weight: 500;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/* 设置项样式 */
|
|
37
|
+
.settings-item {
|
|
38
|
+
padding: 16px 0;
|
|
39
|
+
border-bottom: 1px solid #f0f0f0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.settings-item:last-child {
|
|
43
|
+
border-bottom: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.settings-item-header {
|
|
47
|
+
display: flex;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
align-items: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.settings-item-title {
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
color: #262626;
|
|
56
|
+
margin-bottom: 4px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.settings-item-description {
|
|
60
|
+
font-size: 12px;
|
|
61
|
+
color: #8c8c8c;
|
|
62
|
+
line-height: 1.5;
|
|
63
|
+
}
|
|
64
|
+
|
|
36
65
|
.settings-section {
|
|
37
66
|
margin-bottom: 32px;
|
|
38
67
|
}
|