Browse Source

REPORT-75091 - 数据脱敏(报表)

【问题原因】rt
【改动思路】详见开发文档:https://kms.fineres.com/pages/viewpage.action?pageId=504469104
【review建议】提交晚是因为虽然任务是一期,但是放到二期发布,需要在合并release/11.0后才提交feature
feature/x
Yvan-欧阳帆 2 years ago
parent
commit
b8c2d337a8
  1. 14
      designer-base/src/main/java/com/fr/design/actions/UpdateAction.java
  2. 1
      designer-base/src/main/java/com/fr/design/constants/UIConstants.java
  3. 2
      designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java
  4. 421
      designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
  5. 178
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/TableDataPreviewDesensitizeManager.java
  6. 113
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/model/DesensitizedPreviewTableModel.java
  7. 308
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java
  8. 127
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleDebugPane.java
  9. 296
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java
  10. 80
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRulePane.java
  11. 48
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleSourceChoosePane.java
  12. 110
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationSettingPane.java
  13. 459
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTableModel.java
  14. 64
      designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTablePane.java
  15. 7
      designer-base/src/main/resources/com/fr/design/images/control/refresh_normal.svg
  16. 3
      designer-base/src/main/resources/com/fr/design/standard/add/add_black_normal.svg
  17. 6
      designer-base/src/main/resources/com/fr/design/standard/debug/debug_disabled.svg
  18. 4
      designer-base/src/main/resources/com/fr/design/standard/debug/debug_normal.svg
  19. 5
      designer-base/src/main/resources/com/fr/design/standard/edit/edit_disabled.svg
  20. 3
      designer-base/src/main/resources/com/fr/design/standard/edit/edit_normal.svg
  21. 7
      designer-base/src/main/resources/com/fr/design/standard/remove/remove_red_normal.svg

14
designer-base/src/main/java/com/fr/design/actions/UpdateAction.java

@ -185,12 +185,24 @@ public abstract class UpdateAction extends ShortCut implements Action {
* @param resource 图标资源路径
*/
public void setSmallIcon(String resource) {
setSmallIcon(resource, true);
}
/**
* 使用传入资源url的方式设置Icon会自动设置_normal.svg然后通过needDisable参数判断是否需要自动设置_disable.svg
* 因为有些地方是不需要设置灰化图标的所以不存在灰化图标资源这边如果一并设置就会报错文件找不到
* @param resource
* @param needDisable
*/
public void setSmallIcon(String resource, boolean needDisable) {
if (StringUtils.equals(resource, StringUtils.EMPTY)) {
this.putValue(Action.SMALL_ICON, null);
return;
}
this.putValue(Action.SMALL_ICON, IconUtils.readIcon(resource));
this.putValue(UpdateAction.DISABLED_ICON, IconUtils.readSVGIcon(resource, IconUtils.ICON_TYPE_DISABLED));
if (needDisable) {
this.putValue(UpdateAction.DISABLED_ICON, IconUtils.readSVGIcon(resource, IconUtils.ICON_TYPE_DISABLED));
}
}
public void setSmallIcon(Icon[] smallIcon, boolean white) {

1
designer-base/src/main/java/com/fr/design/constants/UIConstants.java

@ -150,6 +150,7 @@ public interface UIConstants {
public static final Color LIST_ITEM_SPLIT_LINE = new Color(0xf0f0f3);
public static final Color DESIGNER_LOGIN_BACKGROUND = new Color(0xf1ad14);
public static final Color DESIGNER_LOGIN_BACKGROUND_ONCLICK = new Color(0xd89600);
public static final Color CHECK_BOX_TIP_FONT_COLOR = new Color(51, 51, 52, (int)Math.round(0.5 * 255));
public static final BufferedImage DRAG_BAR = IOUtils.readImage("com/fr/design/images/control/bar.png");
public static final BufferedImage DRAG_BAR_LIGHT = IOUtils.readImage("com/fr/design/images/control/bar-light.png");

2
designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java

@ -26,6 +26,8 @@ public class PreviewTableModel extends AbstractTableModel {
public IntList dateIndexs = new IntList(4);
public PreviewTableModel() {}
public PreviewTableModel(int maxRowCount) {
// peter:默认必须显示错误的数据源.
this(new ErrorResultSet(), maxRowCount);

421
designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java

@ -3,28 +3,39 @@
*/
package com.fr.design.data.datapane.preview;
import com.fr.base.BaseUtils;
import com.fr.base.TableData;
import com.fr.base.svg.IconUtils;
import com.fr.data.TableDataSource;
import com.fr.data.desensitize.base.AbstractDesensitizationTableData;
import com.fr.data.impl.DBTableData;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.data.impl.NameDataModel;
import com.fr.data.operator.DataOperator;
import com.fr.design.DesignerEnvManager;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.preview.desensitization.TableDataPreviewDesensitizeManager;
import com.fr.design.data.datapane.preview.desensitization.model.DesensitizedPreviewTableModel;
import com.fr.design.data.datapane.preview.desensitization.view.setting.TableDataDesensitizationSettingPane;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.gui.frpane.UITabbedPane;
import com.fr.design.gui.ibutton.UIToggleButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.iprogressbar.AutoProgressBar;
import com.fr.design.gui.itable.SortableJTable;
import com.fr.design.gui.itable.TableSorter;
import com.fr.design.gui.itextfield.UINumberField;
import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.SeparatorDef;
import com.fr.design.menu.ToolBarDef;
import com.fr.design.ui.util.UIUtil;
import com.fr.function.TIME;
import com.fr.general.FRFont;
@ -39,6 +50,7 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
@ -57,12 +69,19 @@ import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CancellationException;
/**
* august PreviewTablePane一共提供5个共有的静态方法用来预览
*/
public class PreviewTablePane extends BasicPane {
private static final String DATA_DESENSITIZATION_CONFIG = Toolkit.i18nText("Fine-Design_Report_Desensitization_Config");
private static final String LEFT_BRACKET = "(";
private static final String RIGHT_BRACKET = ")";
private static final String COUNT = Toolkit.i18nText("Fine-Design_Report_Desensitization_Count");
private TableData tableData;
private DataModel dataModel;
private UINumberField maxPreviewNumberField;
@ -78,6 +97,54 @@ public class PreviewTablePane extends BasicPane {
private static PreviewTablePane THIS;
private EmbeddedTableData previewTableData;
private UILabel desensitizationLabel;
/**
* 用于refreshLabel的鼠标监听
*/
private final MouseAdapter refreshLabelMouseAdapter = new MouseAdapter() {
boolean mouseEntered = false;
boolean buttonPressed = false;
@Override
public void mouseEntered(MouseEvent e) { // 当鼠标进入时候调用.
mouseEntered = true;
if (!buttonPressed) {
refreshLabel.setBackground(java.awt.Color.WHITE);
refreshLabel.setOpaque(true);
refreshLabel.setBorder(BorderFactory.createLineBorder(java.awt.Color.GRAY));
}
}
@Override
public void mouseExited(MouseEvent e) {
mouseEntered = false;
refreshLabel.setOpaque(false);
refreshLabel.setBorder(BorderFactory.createEmptyBorder());
}
@Override
public void mousePressed(MouseEvent e) {
buttonPressed = true;
refreshLabel.setBackground(java.awt.Color.lightGray);
}
@Override
public void mouseReleased(MouseEvent e) {
buttonPressed = false;
if (mouseEntered) {
refreshLabel.setBackground(java.awt.Color.WHITE);
try {
populate(tableData);
if (dataModel != null) {
setRowsLimitTableModel();
}
} catch (Exception ignore) {
}
}
}
};
public static final PreviewTablePane getInstance() {
if (THIS == null) {
THIS = new PreviewTablePane();
@ -87,91 +154,175 @@ public class PreviewTablePane extends BasicPane {
private PreviewTablePane() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
// northPane
this.add(initNorthPane(), BorderLayout.NORTH);
// centerPane
this.add(initCenterPane(), BorderLayout.CENTER);
// dialog
initDialog();
// progressBar
initProgressBar();
}
// elalke:预览行数
JPanel previewNumberPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
this.add(previewNumberPanel, BorderLayout.NORTH);
/**
* 初始化northPane
*
* @return
*/
private JComponent initNorthPane() {
JPanel northPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
// 预览行数面板
northPane.add(initPreviewNumberPane(), BorderLayout.CENTER);
// 脱敏预览设置面板
northPane.add(initDesensitizationPane(), BorderLayout.EAST);
return northPane;
}
/**
* 初始化预览行数面板
*
* @return
*/
private JComponent initPreviewNumberPane() {
JPanel previewNumberPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
// 当前行数
JPanel currentPreviewPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
previewNumberPanel.add(currentPreviewPanel);
currentPreviewPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Current_Preview_Rows") + ":"));
currentRowsField = new UINumberField();
currentPreviewPanel.add(currentRowsField);
currentRowsField.setEditable(false);
currentRowsField.setColumns(4);
currentRowsField.setInteger(true);
// 最大行数
JPanel maxPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
previewNumberPanel.add(maxPanel);
maxPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Datasource_Maximum_Number_of_Preview_Rows") + ":"));
maxPreviewNumberField = new UINumberField();
maxPanel.add(maxPreviewNumberField);
maxPreviewNumberField.setColumns(4);
maxPreviewNumberField.setInteger(true);
DesignerEnvManager designerEnvManager = DesignerEnvManager.getEnvManager();
maxPreviewNumberField.setValue(designerEnvManager.getMaxNumberOrPreviewRow());
maxPreviewNumberField.setValue(DesignerEnvManager.getEnvManager().getMaxNumberOrPreviewRow());
maxPreviewNumberField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
DesignerEnvManager designerEnvManager = DesignerEnvManager.getEnvManager();
designerEnvManager.setMaxNumberOrPreviewRow((int) ((UINumberField) evt.getSource()).getValue());
}
});
// 刷新按钮
initRefreshLabel();
Icon refreshImage = BaseUtils.readIcon("/com/fr/design/images/control/refresh.png");
refreshLabel = new UILabel(refreshImage);
previewNumberPanel.add(currentPreviewPanel);
previewNumberPanel.add(maxPanel);
previewNumberPanel.add(refreshLabel);
refreshLabel.addMouseListener(new MouseAdapter() {
boolean mouseEntered = false;
boolean buttonPressed = false;
public void mouseEntered(MouseEvent e) { // 当鼠标进入时候调用.
mouseEntered = true;
if (!buttonPressed) {
refreshLabel.setBackground(java.awt.Color.WHITE);
refreshLabel.setOpaque(true);
refreshLabel.setBorder(BorderFactory.createLineBorder(java.awt.Color.GRAY));
}
}
public void mouseExited(MouseEvent e) {
mouseEntered = false;
refreshLabel.setOpaque(false);
refreshLabel.setBorder(BorderFactory.createEmptyBorder());
}
return previewNumberPanel;
}
public void mousePressed(MouseEvent e) {
buttonPressed = true;
refreshLabel.setBackground(java.awt.Color.lightGray);
}
private void initRefreshLabel() {
Icon refreshImage = IconUtils.readIcon("/com/fr/design/images/control/refresh");
refreshLabel = new UILabel(refreshImage);
refreshLabel.addMouseListener(refreshLabelMouseAdapter);
}
public void mouseReleased(MouseEvent e) {
buttonPressed = false;
if (mouseEntered) {
refreshLabel.setBackground(java.awt.Color.WHITE);
try {
populate(tableData);
if (dataModel != null) {
setRowsLimitTableModel();
/**
* 初始化脱敏设置面板
*
* @return
*/
private JComponent initDesensitizationPane() {
JPanel desensitizationPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
// 初始化Label
desensitizationLabel = new UILabel(DATA_DESENSITIZATION_CONFIG);
desensitizationLabel.setForeground(UIConstants.NORMAL_BLUE);
desensitizationLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TableDataDesensitizationSettingPane settingPane = new TableDataDesensitizationSettingPane((AbstractDesensitizationTableData) tableData);
settingPane.populateBean((AbstractDesensitizationTableData) tableData);
BasicDialog dialog = settingPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(PreviewTablePane.this), new DialogActionAdapter() {
@Override
public void doOk() {
// 保存脱敏规则配置
settingPane.updateBean();
// 改变模板保存状态
JTemplate<?, ?> editingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (Objects.nonNull(editingTemplate)) {
editingTemplate.fireTargetModified(true);
}
} catch (Exception e1) {
// 刷新预览页面
refreshTable();
}
}
@Override
public void doCancel() {
}
}, BasicDialog.DEFAULT);
dialog.setVisible(true);
}
});
// 初始化分隔符
ToolBarDef toolbarDef = new ToolBarDef();
toolbarDef.addShortCut(SeparatorDef.DEFAULT);
UIToolbar toolBar = ToolBarDef.createJToolBar();
toolBar.setBorderPainted(false);
toolbarDef.updateToolBar(toolBar);
// 初始化预览按钮
UIToggleButton previewToggle = new UIToggleButton(new Icon[]{IconUtils.readIcon("/com/fr/design/images/m_file/preview"), IconUtils.readIcon("/com/fr/design/images/m_file/preview")}, true);
previewToggle.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Desensitization_Preview"));
previewToggle.setSelected(false);
previewToggle.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 切换TableModel的脱敏状态
togglePreviewTableModelDesensitizeStatus();
// 刷新页面,展示
refreshTable();
}
});
desensitizationPane.add(desensitizationLabel);
desensitizationPane.add(toolBar);
desensitizationPane.add(previewToggle);
return desensitizationPane;
}
/**
* 设置脱敏设置的个数
*
* @param model
*/
private void setDesensitizationCount(TableModel model) {
if (isDesensitizeOpened()) {
int count = model instanceof DesensitizedPreviewTableModel ? ((DesensitizedPreviewTableModel) model).getDesensitizeColumnsCount() : 0;
desensitizationLabel.setText(DATA_DESENSITIZATION_CONFIG + LEFT_BRACKET + count + RIGHT_BRACKET + COUNT);
} else {
desensitizationLabel.setText(DATA_DESENSITIZATION_CONFIG);
}
}
/**
* 初始化centerPane
*
* @return
*/
private JComponent initCenterPane() {
preveiwTable = new CopyableJTable(new TableSorter());
preveiwTable.setRowSelectionAllowed(false);
preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
return new JScrollPane(preveiwTable);
}
this.add(new JScrollPane(preveiwTable), BorderLayout.CENTER);
private void initDialog() {
if (this.dialog == null) {
this.dialog = this.showWindow(new JFrame());
}
}
private void initProgressBar() {
progressBar = new AutoProgressBar(this, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) {
@Override
public void doMonitorCanceled() {
if (getWorker() != null) {
getWorker().cancel(true);
@ -182,7 +333,7 @@ public class PreviewTablePane extends BasicPane {
}
public AutoProgressBar getProgressBar() {
return this.progressBar;
return PreviewTablePane.progressBar;
}
@Override
@ -222,13 +373,19 @@ public class PreviewTablePane extends BasicPane {
return this.worker;
}
// elake:为预览表的columnIndex列着c色.
/**
* 为预览表的columnIndex列着色.
*
* @param columnIndex 列索引值
* @param c 颜色
*/
private void setPreviewTableColumnColor(final int columnIndex, final Color c) {
addLoadedListener(new LoadedEventListener() {
@Override
public void fireLoaded() {
TableColumn column = preveiwTable.getColumnModel().getColumn(columnIndex);
DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
comp.setBackground(c);
@ -249,7 +406,7 @@ public class PreviewTablePane extends BasicPane {
getInstance().preveiwTable = new SortableJTable(new TableSorter());
getInstance().preveiwTable.setRowSelectionAllowed(false);
getInstance().preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
getInstance().progressBar.close();
PreviewTablePane.progressBar.close();
getInstance().repaint();
}
@ -331,6 +488,7 @@ public class PreviewTablePane extends BasicPane {
private void previewTableDataSQL() throws Exception {
connectionBar = new AutoProgressBar(this, Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) {
@Override
public void doMonitorCanceled() {
getWorker().cancel(true);
getDialog().setVisible(false);
@ -345,42 +503,49 @@ public class PreviewTablePane extends BasicPane {
private void setPreviewTableColumnValue(final Graphics g) {
for (int i = 0; i < preveiwTable.getColumnModel().getColumnCount(); i++) {
TableColumn column = preveiwTable.getColumnModel().getColumn(i);
DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Font f = table.getFont();
//默认在系统不支持 无法显示时 如自造的字 ,字体设置为空.
Font defaultShowFont = FRFont.getInstance("", f.getStyle(), f.getSize());
if (value instanceof String) {
String str = (String) value;
for (int j = 0; j < str.length(); j++) {
char c = str.charAt(j);
if (!f.canDisplay(c)) {
table.setFont(defaultShowFont);
}
DefaultTableCellRenderer cellRenderer = getDefaultTableCellRenderer();
column.setCellRenderer(cellRenderer);
}
}
/**
* 默认表格格子渲染器
*
* @return
*/
private DefaultTableCellRenderer getDefaultTableCellRenderer() {
return new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Font f = table.getFont();
//默认在系统不支持 无法显示时 如自造的字 ,字体设置为空.
Font defaultShowFont = FRFont.getInstance("", f.getStyle(), f.getSize());
if (value instanceof String) {
String str = (String) value;
for (int j = 0; j < str.length(); j++) {
char c = str.charAt(j);
if (!f.canDisplay(c)) {
table.setFont(defaultShowFont);
}
}
return comp;
}
};
column.setCellRenderer(cellRenderer);
}
return comp;
}
};
}
private void setWorker() {
worker = new SwingWorker<PreviewTableModel, Void>() {
protected PreviewTableModel doInBackground() throws Exception {
worker = new SwingWorker<TableModel, Void>() {
@Override
protected TableModel doInBackground() throws Exception {
connectionBar.start();
try {
if (tableData instanceof DBTableData) {
boolean status = DataOperator.getInstance().testConnection(((DBTableData) tableData).getDatabase());
if (!status) {
throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"));
}
}
testDBTableDataConnection(tableData);
} finally {
// 将close操作放到EDT线程中
UIUtil.invokeLaterIfNeeded(() -> connectionBar.close());
@ -390,22 +555,20 @@ public class PreviewTablePane extends BasicPane {
// parameterInputDialog
// update之后的parameters,转成一个parameterMap,用于预览TableData
PreviewTableModel previewModel = new PreviewTableModel(previewTableData.createDataModel(null), (int) maxPreviewNumberField.getValue());
for (int i = 0; i < previewTableData.getColumnCount(); i++) {
Class<?> cls = previewTableData.getColumnClass(i);
if (cls == Date.class || cls == TIME.class || cls == Timestamp.class) {
previewModel.dateIndexs.add(i);
}
if (TableDataPreviewDesensitizeManager.getInstance().needDesensitize(tableData)) {
// 数据集预览脱敏
previewModel = TableDataPreviewDesensitizeManager.getInstance().desensitizeTableModel(tableData, previewModel);
}
dealWithPreviewTableModelColumnClass(previewModel, previewTableData);
return previewModel;
}
@Override
public void done() {
try {
PreviewTableModel model = get();
setModel(model);
setCurrentRows(model.getRowCount());
TableModel model = get();
setPreviewTableModel(model);
setPreviewTableColumnValue(getParent().getGraphics());
fireLoadedListener();
} catch (Exception e) {
if (!(e instanceof CancellationException)) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
@ -420,6 +583,36 @@ public class PreviewTablePane extends BasicPane {
};
}
/**
* 检查DBTableData连接
*
* @param tableData
* @throws Exception
*/
private void testDBTableDataConnection(TableData tableData) throws Exception {
if (tableData instanceof DBTableData) {
boolean status = DataOperator.getInstance().testConnection(((DBTableData) tableData).getDatabase());
if (!status) {
throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"));
}
}
}
/**
* 处理预览Model的列类型
*
* @param previewModel
* @param previewTableData
*/
private void dealWithPreviewTableModelColumnClass(PreviewTableModel previewModel, EmbeddedTableData previewTableData) {
for (int i = 0; i < previewTableData.getColumnCount(); i++) {
Class<?> cls = previewTableData.getColumnClass(i);
if (cls == Date.class || cls == TIME.class || cls == Timestamp.class) {
previewModel.dateIndexs.add(i);
}
}
}
/**
* 直接预览存储过程的一个返回数据集没有实际值和显示值
*
@ -528,9 +721,61 @@ public class PreviewTablePane extends BasicPane {
} catch (Exception e) {
previewModel = new PreviewTableModel((int) maxPreviewNumberField.getValue());
}
setModel(previewModel);
setCurrentRows(previewModel.getRowCount());
setPreviewTableModel(previewModel);
}
/**
* 切换TableModel的展示状态
*/
private void togglePreviewTableModelDesensitizeStatus() {
if (!isDesensitizeOpened()) {
// 未启用数据脱敏时,不需要切换
return;
}
TableSorter tableSorter = (TableSorter) preveiwTable.getModel();
TableModel originTableModel = tableSorter.getTableModel();
if (originTableModel instanceof DesensitizedPreviewTableModel) {
((DesensitizedPreviewTableModel) originTableModel).toggleNeedDesensite();
}
}
/**
* 刷新一下预览页面用于切换脱敏和非脱敏时的显示
*/
private void refreshTable() {
TableModel originTableModel = getCurrentTableModel();
setPreviewTableModel(originTableModel);
}
/**
* 获取当前的TableModel已经除掉了TableSorter的包装
*
* @return
*/
private TableModel getCurrentTableModel() {
TableSorter tableSorter = (TableSorter) preveiwTable.getModel();
return tableSorter.getTableModel();
}
/**
* 设置预览TableModel
*
* @param previewTableModel
*/
private void setPreviewTableModel(TableModel previewTableModel) {
setDesensitizationCount(previewTableModel);
setModel(previewTableModel);
setCurrentRows(previewTableModel.getRowCount());
fireLoadedListener();
}
/**
* 数据脱敏是否启用
* @return
*/
private boolean isDesensitizeOpened() {
return tableData instanceof AbstractDesensitizationTableData &&
((AbstractDesensitizationTableData) tableData).getDesensitizeOpen();
}
}

178
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/TableDataPreviewDesensitizeManager.java

@ -0,0 +1,178 @@
package com.fr.design.data.datapane.preview.desensitization;
import com.fr.base.TableData;
import com.fr.data.desensitize.base.AbstractDesensitizationTableData;
import com.fr.data.desensitize.base.TableDataDesensitizationBean;
import com.fr.data.desensitize.manage.DesensitizationManager;
import com.fr.data.desensitize.util.DesentizationUtils;
import com.fr.decision.webservice.bean.user.DepartmentPostBean;
import com.fr.decision.webservice.bean.user.RoleBean;
import com.fr.decision.webservice.utils.DecisionServiceConstants;
import com.fr.decision.webservice.v10.user.CustomRoleService;
import com.fr.decision.webservice.v10.user.PositionService;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.preview.PreviewTableModel;
import com.fr.design.data.datapane.preview.desensitization.model.DesensitizedPreviewTableModel;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 管理所有数据集预览过程中的脱敏计算
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/14
*/
public class TableDataPreviewDesensitizeManager implements DesensitizationManager {
private static final String CONNECTOR = "_";
private TableDataPreviewDesensitizeManager() {
}
private static class Holder {
private static final TableDataPreviewDesensitizeManager INSTANCE = new TableDataPreviewDesensitizeManager();
}
public static TableDataPreviewDesensitizeManager getInstance() {
return TableDataPreviewDesensitizeManager.Holder.INSTANCE;
}
/**
* 判断数据集预览时是否需要脱敏这里不需要判断roleIds因为默认有权限编辑的人一定有权限看脱敏前后字段值
*
* @param tableData
* @return
*/
public boolean needDesensitize(TableData tableData) {
return tableData instanceof AbstractDesensitizationTableData &&
DesentizationUtils.isCollectionNotEmpty(((AbstractDesensitizationTableData) tableData).getDesensitizationBeans()) &&
((AbstractDesensitizationTableData) tableData).getDesensitizationBeans().stream().noneMatch(TableDataDesensitizationBean::invalid);
}
/**
* 数据集预览脱敏使用DesensitizedPreviewTableModel对当前的预览TableModel做包装
*
* @param model
* @return
*/
public PreviewTableModel desensitizeTableModel(TableData tableData, PreviewTableModel model) {
if (needDesensitize(tableData)) {
Map<Integer, TableDataDesensitizationBean> desensitizationBeanMap = new LinkedHashMap<>();
// 获取此数据集的所有脱敏信息
Collection<TableDataDesensitizationBean> desensitizationBeans = ((AbstractDesensitizationTableData) tableData).getDesensitizationBeans();
// 排个序
List<TableDataDesensitizationBean> sortedBeans = desensitizationBeans.stream().sorted(Comparator.comparingInt(TableDataDesensitizationBean::getColumnIndex)).collect(Collectors.toList());
int columnIndex = 0;
for (TableDataDesensitizationBean sortedBean : sortedBeans) {
// 当map中已包含列序号时,代表对这一列设置了不同的脱敏规则,将key + 1
if (desensitizationBeanMap.containsKey(columnIndex)) {
columnIndex++;
}
desensitizationBeanMap.put(columnIndex, sortedBean);
}
// 包装TableModel
return new DesensitizedPreviewTableModel(model, desensitizationBeanMap);
}
return model;
}
/**
* 通过TableData获取其列名
* 实现逻辑有点绕TableData本身并不能返回列名集合只能先去获取当前模板所有数据集然后匹配名称拿到TableDataWrapper再获取列名
* @param tableData
* @return
*/
public List<String> getColumnNamesByTableData(TableData tableData) {
List<Map<String, TableDataWrapper>> editingDataSet = DesignTableDataManager.getEditingDataSet(DesignTableDataManager.getEditingTableDataSource());
// 当前所有模板数据集Wrapper,不包括存储过程
Map<String, TableDataWrapper> templeteDataMap = editingDataSet.get(0);
// 当前所有模板数据集Wrapper,包括存储过程
Map<String, TableDataWrapper> dataWrapperMap = DesignTableDataManager.getAllDataSetIncludingProcedure(templeteDataMap);
// 找到匹配当前数据集名称的Wrapper
TableDataWrapper tableDataWrapper = dataWrapperMap.get(tableData.getName());
return tableDataWrapper == null ?
new ArrayList<>() :
tableDataWrapper.calculateColumnNameList();
}
/**
* 这个api会返回 部门职位 + 自定义角色 的Map
* 其中 key为 "pid" + "_" + "id"value为 "ptext" + "text"
* @return
*/
public Map<String, String> getAllRoles() {
Map<String, String> rolesMap = new LinkedHashMap<>();
// 处理部门职位相关的用户组
addDepartmentAndPositionRoles2Map(rolesMap);
// 处理自定义角色相关的用户组
addCustomRoles2Map(rolesMap);
return rolesMap;
}
/**
* 获取所有的部门职位按照 key为 "pid" + "_" + "id"value为 "ptext" + "text"的格式添加到参数Map中
* @param rolesMap
*/
private void addDepartmentAndPositionRoles2Map(Map<String, String> rolesMap) {
try {
List<DepartmentPostBean> postBeans = PositionService.getInstance().getDepartmentPostNameList();
for (DepartmentPostBean postBean : postBeans) {
String department = postBean.getpText();
String position = postBean.getText();
String departmentId = postBean.getpId();
String positionId = postBean.getId();
if (!ComparatorUtils.equals(DecisionServiceConstants.DECISION_DEP_ROOT, postBean.getId()) && StringUtils.isNotEmpty(position)) {
// 只添加部门和职位同时存在的
rolesMap.put(mergeRoleId(departmentId, positionId), mergeRoleText(department, position));
}
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, "[Desensitization] failed to add department and position roles to map for {}", e.getMessage());
}
}
/**
* 获取所有的自定义角色按照 id - name添加到参数map里
* @param rolesMap
*/
private void addCustomRoles2Map(Map<String, String> rolesMap) {
try {
List<RoleBean> allCustomRole = CustomRoleService.getInstance().getAllCustomRoleNameList(null);
allCustomRole.forEach(roleBean -> rolesMap.put(roleBean.getId(), roleBean.getText()));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, "[Desensitization] failed to add custom role to map for {}", e.getMessage());
}
}
/**
* 合并部门 + 职位的名称
* @param departmentName
* @param positionName
* @return
*/
public String mergeRoleText(String departmentName, String positionName) {
return departmentName + positionName;
}
/**
* 合并部门 + 职位的id
* @param departmentId
* @param positionId
* @return
*/
public String mergeRoleId(String departmentId, String positionId) {
return departmentId + CONNECTOR + positionId;
}
}

113
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/model/DesensitizedPreviewTableModel.java

@ -0,0 +1,113 @@
package com.fr.design.data.datapane.preview.desensitization.model;
import com.fr.data.desensitize.base.TableDataDesensitizationBean;
import com.fr.data.desensitize.calculate.DesensitizationCalculator;
import com.fr.data.desensitize.rule.base.DesensitizationRule;
import com.fr.design.data.datapane.preview.PreviewTableModel;
import java.util.Map;
import java.util.Objects;
/**
* 数据集预览TableModel的脱敏实现
*
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/14
*/
public class DesensitizedPreviewTableModel extends PreviewTableModel {
/**
* 原始数据Model
*/
private PreviewTableModel previewTableModel;
/**
* 脱敏后新组装的TableModel中列序号 - 脱敏信息 对应的Map
*/
private Map<Integer, TableDataDesensitizationBean> desensitizationBeanMap;
private boolean needDesensitize = false;
public DesensitizedPreviewTableModel(PreviewTableModel previewTableModel, Map<Integer, TableDataDesensitizationBean> desensitizationBeanMap) {
this.previewTableModel = previewTableModel;
this.desensitizationBeanMap = desensitizationBeanMap;
}
@Override
public String getColumnName(int column) {
int originIndex = needDesensitize && Objects.nonNull(desensitizationBeanMap.get(column)) ?
desensitizationBeanMap.get(column).getColumnIndex() : column;
return previewTableModel.getColumnName(originIndex);
}
@Override
public int getRowCount() {
return previewTableModel.getRowCount();
}
@Override
public int getColumnCount() {
return needDesensitize ?
getDesensitizeColumnsCount() :
previewTableModel.getColumnCount();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return needDesensitize && Objects.nonNull(desensitizationBeanMap.get(columnIndex)) ?
getDesensitizedValue(rowIndex, columnIndex) :
previewTableModel.getValueAt(rowIndex, columnIndex);
}
/**
* 返回脱敏后的数据值
*
* @param rowIndex
* @param columnIndex
* @return
*/
private Object getDesensitizedValue(int rowIndex, int columnIndex) {
// 先通过columnIndex找到对应原TableModel的列序号
int originColumnIndex = desensitizationBeanMap.get(columnIndex).getColumnIndex();
// 获取原值
Object value = previewTableModel.getValueAt(rowIndex, originColumnIndex);
// 判空
if (Objects.isNull(value)) {
return value;
}
// 脱敏
String strValue = String.valueOf(value);
value = desensitizeValue(strValue, columnIndex);
return value;
}
/**
* 计算脱敏后的value,此时columnIndex对应的脱敏信息一定不为空
*
* @param strValue
* @param columnIndex
* @return
*/
private String desensitizeValue(String strValue, int columnIndex) {
TableDataDesensitizationBean desensitizationBean = desensitizationBeanMap.get(columnIndex);
DesensitizationRule desensitizationRule = desensitizationBean.getDesensitizationRule();
return DesensitizationCalculator.getInstance().desensitize(strValue, desensitizationRule);
}
/**
* 获取当前有效的脱敏字段个数
* @return
*/
public int getDesensitizeColumnsCount() {
return desensitizationBeanMap.size();
}
/**
* 切换脱敏状态
*/
public void toggleNeedDesensite() {
this.needDesensitize = !needDesensitize;
}
}

308
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java

@ -0,0 +1,308 @@
package com.fr.design.data.datapane.preview.desensitization.view.rule;
import com.fr.base.svg.IconUtils;
import com.fr.data.desensitize.rule.DesensitizationRuleManager;
import com.fr.data.desensitize.rule.base.DesensitizationRule;
import com.fr.data.desensitize.rule.base.DesensitizationRuleSource;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.gui.ibutton.UIRadioButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itableeditorpane.UITableEditAction;
import com.fr.design.gui.itableeditorpane.UITableEditorPane;
import com.fr.design.gui.itableeditorpane.UITableModelAdapter;
import com.fr.design.i18n.Toolkit;
import com.fr.stable.StringUtils;
import com.fr.stable.collections.CollectionUtils;
import javax.swing.AbstractCellEditor;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 脱敏规则选择页面
*
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/26
*/
public class DesensitizationRuleChoosePane extends JPanel {
private CardLayout cardLayout;
private UITableEditorPane<DesensitizationRule> serverRuleEditPane;
private UITableEditorPane<DesensitizationRule> customRuleEditPane;
private DesensitizationRuleSource currentRuleSource;
public DesensitizationRuleChoosePane() {
this.cardLayout = new CardLayout();
this.setLayout(cardLayout);
serverRuleEditPane = new UITableEditorPane<>(new DesensitizationRuleChooseTableModel(this, true));
customRuleEditPane = new UITableEditorPane<>(new DesensitizationRuleChooseTableModel(this, false));
serverRuleEditPane.setHeaderResizing(false);
customRuleEditPane.setHeaderResizing(false);
populateDesensitizationRules();
this.add(serverRuleEditPane, DesensitizationRuleSource.SERVER.name());
this.add(customRuleEditPane, DesensitizationRuleSource.CUSTOM.name());
// 默认显示平台规则
switchPaneByRuleSource(DesensitizationRuleSource.SERVER);
}
public void switchPaneByRuleSource(DesensitizationRuleSource ruleSource) {
this.currentRuleSource = ruleSource;
this.cardLayout.show(this, ruleSource.name());
}
/**
* 展示当前规则
*/
private void populateDesensitizationRules() {
serverRuleEditPane.populate(DesensitizationRuleManager.getInstance().getRules(DesensitizationRuleSource.SERVER));
customRuleEditPane.populate(DesensitizationRuleManager.getInstance().getRules(DesensitizationRuleSource.CUSTOM));
}
/**
* 获取当前选中的规则
*
* @return
*/
public DesensitizationRule getSelectedDesensitizationRule() {
switch (currentRuleSource) {
case SERVER:
return serverRuleEditPane.getTableModel().getSelectedValue();
case CUSTOM:
return customRuleEditPane.getTableModel().getSelectedValue();
default:
return null;
}
}
/**
* 规则选择Table的TableModel
*/
private class DesensitizationRuleChooseTableModel extends UITableModelAdapter<DesensitizationRule> {
private Component parent;
private boolean debugActionOnly;
protected DesensitizationRuleChooseTableModel(Component parent, boolean debugActionOnly) {
super(new String[]{
StringUtils.EMPTY,
Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name"),
Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Description")
});
this.parent = parent;
this.debugActionOnly = debugActionOnly;
this.setColumnClass(new Class[]{
RuleChoosePane.class,
UILabel.class,
UILabel.class
});
this.setDefaultEditor(RuleChoosePane.class, new RuleChoosePane());
this.setDefaultRenderer(RuleChoosePane.class, new RuleChoosePane());
this.createTable().getColumnModel().getColumn(0).setMaxWidth(20);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
DesensitizationRule rule = getList().get(rowIndex);
switch (columnIndex) {
case 0:
return rule.equals(getSelectedValue());
case 1:
return rule.getRuleName();
case 2:
return DesensitizationRule.getDescription(rule);
default:
return StringUtils.EMPTY;
}
}
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
@Override
public UITableEditAction[] createAction() {
return debugActionOnly ?
new UITableEditAction[]{new DebugRuleAction(parent)} :
new UITableEditAction[]{new AddRuleAction(), new EditRuleAction(), new DeleteRuleAction(parent), new DebugRuleAction(parent)};
}
private Set<String> getCurrentExistRuleNames(String excludeName) {
List<DesensitizationRule> rules = getList();
return CollectionUtils.isEmpty(rules) ?
new LinkedHashSet<>() :
rules.stream()
.map(DesensitizationRule::getRuleName)
.filter(name -> !StringUtils.equals(name, excludeName))
.collect(Collectors.toSet());
}
private class RuleChoosePane extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private UIRadioButton selectedButton;
public RuleChoosePane() {
this.selectedButton = new UIRadioButton();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
selectedButton.setSelected(isSelected);
return selectedButton;
}
@Override
public Object getCellEditorValue() {
return selectedButton.isSelected();
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
selectedButton.setSelected(isSelected);
return selectedButton;
}
}
/**
* 添加规则
*/
private class AddRuleAction extends AddTableRowAction {
public AddRuleAction() {
this.setName(Toolkit.i18nText("Fine-Design_Report_Desensitization_Add"));
this.setSmallIcon("/com/fr/design/standard/add/add_black", false);
}
@Override
public void actionPerformed(ActionEvent e) {
// 新增一条规则
DesensitizationRuleEditPane editPane = new DesensitizationRuleEditPane(getCurrentExistRuleNames(StringUtils.EMPTY));
BasicDialog basicDialog = editPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), new DialogActionAdapter() {
@Override
public void doOk() {
DesensitizationRule rule = editPane.updateBean();
// 添加到Rule Manager中
if (DesensitizationRule.valid(rule)) {
DesensitizationRuleManager.getInstance().addRule(rule);
}
// 添加到Table中
addRow(rule);
fireTableDataChanged();
}
@Override
public void doCancel() {
super.doCancel();
}
}, BasicDialog.DEFAULT);
basicDialog.setVisible(true);
}
}
private class EditRuleAction extends UITableEditAction {
public EditRuleAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Edit"));
this.setSmallIcon(IconUtils.readIcon("/com/fr/design/standard/edit/edit"));
}
@Override
public void checkEnabled() {
setEnabled(table.getSelectedRow() != -1);
}
@Override
public void actionPerformed(ActionEvent e) {
// 获取当前选中规则
DesensitizationRule selectedValue = getSelectedValue();
DesensitizationRuleEditPane editPane = new DesensitizationRuleEditPane(getCurrentExistRuleNames(selectedValue.getRuleName()));
editPane.populateBean(selectedValue);
BasicDialog basicDialog = editPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), new DialogActionAdapter() {
@Override
public void doOk() {
DesensitizationRule rule = editPane.updateBean();
// 修改同步到RuleManager中
if (DesensitizationRule.valid(rule)) {
DesensitizationRuleManager.getInstance().updateRule(rule);
}
fireTableDataChanged();
}
@Override
public void doCancel() {
super.doCancel();
}
}, BasicDialog.DEFAULT);
basicDialog.setVisible(true);
}
}
private class DeleteRuleAction extends DeleteAction {
public DeleteRuleAction(Component parent) {
super(parent);
this.setName(Toolkit.i18nText("Fine-Design_Basic_Base_Remove"));
this.setSmallIcon("/com/fr/design/images/control/remove");
}
@Override
public void checkEnabled() {
setEnabled(table.getSelectedRow() != -1);
}
@Override
public void actionPerformed(ActionEvent e) {
// 获取当前选中规则
DesensitizationRule selectedRule = getSelectedValue();
// 删除同步到RuleManager中
if (DesensitizationRule.valid(selectedRule)) {
DesensitizationRuleManager.getInstance().removeRule(selectedRule);
}
super.actionPerformed(e);
}
}
private class DebugRuleAction extends UITableEditAction {
private Component parent;
public DebugRuleAction(Component parent) {
this.parent = parent;
this.setName(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Debug"));
this.setSmallIcon("/com/fr/design/standard/debug/debug");
}
@Override
public void checkEnabled() {
setEnabled(table.getSelectedRow() != -1);
}
@Override
public void actionPerformed(ActionEvent e) {
// 获取当前选中规则
DesensitizationRule selectedRule = getSelectedValue();
DesensitizationRuleDebugPane ruleDebugPane = new DesensitizationRuleDebugPane(selectedRule);
BasicDialog ruleDebugDialog = ruleDebugPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), null, BasicDialog.DEFAULT);
ruleDebugDialog.setVisible(true);
}
}
}
}

127
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleDebugPane.java

@ -0,0 +1,127 @@
package com.fr.design.data.datapane.preview.desensitization.view.rule;
import com.fr.data.desensitize.calculate.DesensitizationCalculator;
import com.fr.data.desensitize.rule.base.DesensitizationRule;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
/**
* 脱敏规则调试页
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/8
*/
public class DesensitizationRuleDebugPane extends BasicPane {
/**
* 脱敏规则
*/
private DesensitizationRule rule;
public DesensitizationRuleDebugPane(DesensitizationRule rule) {
this.rule = rule;
initComponent();
}
private void initComponent() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.add(initNorthPane(), BorderLayout.NORTH);
this.add(initCenterPane(), BorderLayout.CENTER);
}
private JPanel initNorthPane() {
JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Description"));
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 0));
UILabel desensitizationRule = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Algorithm"));
UILabel characterReplace = new UILabel(rule.getRuleType().getTypeName());
UILabel description = new UILabel(DesensitizationRule.getDescription(rule));
JComponent[][] components = new JComponent[][] {
{desensitizationRule, characterReplace},
{new UILabel(), description}
};
panel.add(
TableLayoutHelper.createCommonTableLayoutPane(
components,
new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED},
new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED},
20),
BorderLayout.CENTER);
northPane.add(panel);
return northPane;
}
private JPanel initCenterPane() {
JPanel centerPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Debug"));
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 0));
UILabel beforeDesensitize = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Before"));
UITextField beforeDesensitizeText = new UITextField(20);
beforeDesensitizeText.setPlaceholder(Toolkit.i18nText("Fine-Design_Report_Desensitization_Enter_Content"));
UILabel afterDesensitize = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_After"));
UITextField afterDesensitizeText = new UITextField(20);
afterDesensitizeText.setEditable(false);
UIButton desensitizeButton = new UIButton(Toolkit.i18nText("Fine-Design_Report_Desensitization_Debug"));
beforeDesensitizeText.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
afterDesensitizeText.setText(StringUtils.EMPTY);
}
@Override
public void focusLost(FocusEvent e) {
}
});
desensitizeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String text = beforeDesensitizeText.getText();
if (StringUtils.isEmpty(text)) {
FineJOptionPane.showMessageDialog(DesensitizationRuleDebugPane.this,
Toolkit.i18nText("Fine-Design_Report_Desensitization_Please_Enter_Valid_Content"));
}
String desensitizedText = DesensitizationCalculator.getInstance().desensitize(text, rule);
afterDesensitizeText.setText(desensitizedText);
}
});
JComponent[][] components = new JComponent[][] {
{beforeDesensitize, beforeDesensitizeText, desensitizeButton},
{afterDesensitize, afterDesensitizeText, new UILabel()}
};
panel.add(
TableLayoutHelper.createCommonTableLayoutPane(
components,
new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED},
new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED},
20),
BorderLayout.CENTER);
centerPane.add(panel);
return centerPane;
}
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Debug");
}
}

296
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java

@ -0,0 +1,296 @@
package com.fr.design.data.datapane.preview.desensitization.view.rule;
import com.fr.data.desensitize.rule.base.DesensitizationCondition;
import com.fr.data.desensitize.rule.base.DesensitizationRule;
import com.fr.data.desensitize.rule.base.DesensitizationRuleType;
import com.fr.design.beans.BasicBeanPane;
import com.fr.design.constants.UIConstants;
import com.fr.design.event.UIObserverListener;
import com.fr.design.gui.icombobox.UIComboBox;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UINumberField;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Insets;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Arrays;
import java.util.Set;
/**
* 脱敏规则编辑页
*
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/8
*/
public class DesensitizationRuleEditPane extends BasicBeanPane<DesensitizationRule> {
/**
* 已经存在的规则名称用于检测重名
*/
private Set<String> existRuleNames;
private UITextField ruleNameTextField;
private UIComboBox ruleTypeComboBox;
private UINumberField retainFrontTextField;
private UINumberField retainBackTextField;
private UITextField firstSymbolTextField;
private UITextField secondSymbolTextField;
private CardLayout cardLayout;
private JPanel ruleConditionPane;
private DesensitizationRule rule = DesensitizationRule.createDefaultEmptyRule();
private final FocusListener retainFrontListener = new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
}
@Override
public void focusLost(FocusEvent e) {
rule.getCondition().setRetainFront((int) retainFrontTextField.getValue());
}
};
private final FocusListener retainBackListener = new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
}
@Override
public void focusLost(FocusEvent e) {
rule.getCondition().setRetainBack((int) retainBackTextField.getValue());
}
};
private final FocusListener firstSymbolListener = new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
}
@Override
public void focusLost(FocusEvent e) {
rule.getCondition().setSymbol(firstSymbolTextField.getText());
}
};
private final FocusListener secondSymbolListener = new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
}
@Override
public void focusLost(FocusEvent e) {
rule.getCondition().setRetainFront(0);
rule.getCondition().setRetainBack(0);
rule.getCondition().setSymbol(secondSymbolTextField.getText());
}
};
public DesensitizationRuleEditPane(Set<String> existRuleNames) {
this.existRuleNames = existRuleNames;
initComponent();
}
/**
* 初始化面板
*/
private void initComponent() {
this.setLayout(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout());
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 0));
UILabel ruleNameLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name"));
// 规则名称输入框
initRuleNameTextField();
UILabel ruleTypeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Algorithm"));
// 脱敏算法Type设置
JPanel ruleTypePane = initRuleTypePane();
// 脱敏算法Condition设置
JPanel ruleConditionPane = initRuleConditionPane();
JComponent[][] components = {
{ruleNameLabel, ruleNameTextField},
{ruleTypeLabel, ruleTypePane},
{new UILabel(), ruleConditionPane}
};
panel.add(
TableLayoutHelper.createGapTableLayoutPane(
components,
new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.FILL},
new double[]{TableLayout.FILL, TableLayout.PREFERRED},
20,
20),
BorderLayout.CENTER);
this.add(panel);
}
/**
* 初始化规则类型面板
* @return
*/
private JPanel initRuleTypePane() {
JPanel ruleTypePane = FRGUIPaneFactory.createBorderLayout_S_Pane();
// 脱敏算法类型下拉框
initRuleTypeComboBox();
ruleTypePane.add(ruleTypeComboBox, BorderLayout.CENTER);
return ruleTypePane;
}
/**
* 初始化规则条件面板
* @return
*/
private JPanel initRuleConditionPane() {
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
cardLayout = new CardLayout();
ruleConditionPane = new JPanel(cardLayout);
// 字符替换
JPanel characterReplacePane = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane();
UILabel retainFrontLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Retain_Front") + StringUtils.BLANK);
retainFrontTextField = new UINumberField(5);
retainFrontTextField.addFocusListener(retainFrontListener);
UILabel retainBackLabel = new UILabel(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_Desensitization_Count_And_Back") + StringUtils.BLANK);
retainBackTextField = new UINumberField(5);
retainBackTextField.addFocusListener(retainBackListener);
UILabel replaceLabel = new UILabel(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_Desensitization_Count_And_Other_Character_Replace_By") + StringUtils.BLANK);
firstSymbolTextField = new UITextField(10);
firstSymbolTextField.addFocusListener(firstSymbolListener);
characterReplacePane.add(retainFrontLabel);
characterReplacePane.add(retainFrontTextField);
characterReplacePane.add(retainBackLabel);
characterReplacePane.add(retainBackTextField);
characterReplacePane.add(replaceLabel);
characterReplacePane.add(firstSymbolTextField);
// 整体替换
JPanel characterAllReplacePane = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane();
UILabel allReplaceLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_All_Character_Replace_By") + StringUtils.BLANK);
secondSymbolTextField = new UITextField(10);
secondSymbolTextField.addFocusListener(secondSymbolListener);
characterAllReplacePane.add(allReplaceLabel);
characterAllReplacePane.add(secondSymbolTextField);
ruleConditionPane.add(characterReplacePane, DesensitizationRuleType.CHARACTER_REPLACE.getTypeName());
ruleConditionPane.add(characterAllReplacePane, DesensitizationRuleType.ALL_CHARACTERS_REPLACE.getTypeName());
// 初始化状态为字符替换
switchRuleConditionPane(DesensitizationRuleType.CHARACTER_REPLACE);
panel.add(ruleConditionPane, BorderLayout.CENTER);
return panel;
}
/**
* 切换规则类型面板
* @param ruleType
*/
private void switchRuleConditionPane(DesensitizationRuleType ruleType) {
this.cardLayout.show(ruleConditionPane, ruleType.getTypeName());
}
/**
* 初始化规则类型下拉框
*/
private void initRuleTypeComboBox() {
ruleTypeComboBox = new UIComboBox(Arrays.stream(DesensitizationRuleType.values()).map(DesensitizationRuleType::getTypeName).toArray());
ruleTypeComboBox.setSelectedIndex(0);
ruleTypeComboBox.registerChangeListener(new UIObserverListener() {
@Override
public void doChange() {
DesensitizationRuleType ruleType = DesensitizationRuleType.matchByTypeName((String) ruleTypeComboBox.getSelectedItem());
rule.setRuleType(ruleType);
// 修改底下的conditionPane
switchRuleConditionPane(ruleType);
}
});
}
/**
* 初始化规则名称输入框
*/
private void initRuleNameTextField() {
ruleNameTextField = new UITextField(20) {
@Override
public Insets getInsets() {
return new Insets(2, 4, 0, 4);
}
};
ruleNameTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Report_Desensitization_Please_Enter_Rule_Name"));
ruleNameTextField.setBorderPainted(true);
ruleNameTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
ruleNameTextField.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE));
ruleNameTextField.repaint();
}
@Override
public void focusLost(FocusEvent e) {
ruleNameTextField.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
rule.setRuleName(ruleNameTextField.getText());
ruleNameTextField.repaint();
}
});
}
@Override
public void populateBean(DesensitizationRule ob) {
this.rule = ob;
this.ruleNameTextField.setText(rule.getRuleName());
String typeName = rule.getRuleType().getTypeName();
this.ruleTypeComboBox.setSelectedItem(typeName);
switch (DesensitizationRuleType.matchByTypeName(typeName)) {
case CHARACTER_REPLACE:
this.retainFrontTextField.setValue(rule.getCondition().getRetainFront());
this.retainBackTextField.setValue(rule.getCondition().getRetainBack());
this.firstSymbolTextField.setText(rule.getCondition().getSymbol());
break;
case ALL_CHARACTERS_REPLACE:
this.secondSymbolTextField.setText(rule.getCondition().getSymbol());
break;
default:
}
}
@Override
public DesensitizationRule updateBean() {
rule.setEnable(true);
return rule;
}
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Report_Desensitization_Custom_Config_Rules");
}
@Override
public void checkValid() throws Exception {
// 保存rule前检查下
String checkMessage = StringUtils.EMPTY;
if (StringUtils.isEmpty(rule.getRuleName())) {
checkMessage = Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name_Cannot_Be_Empty");
} else if (existRuleNames.contains(rule.getRuleName())) {
checkMessage = Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name_Cannot_Repeat");
} else if (DesensitizationCondition.invalid(rule.getCondition())) {
checkMessage = Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Wrong_Condition");
}
if (StringUtils.isNotEmpty(checkMessage)) {
throw new Exception(checkMessage);
}
}
}

80
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRulePane.java

@ -0,0 +1,80 @@
package com.fr.design.data.datapane.preview.desensitization.view.rule;
import com.fr.data.desensitize.rule.base.DesensitizationRule;
import com.fr.data.desensitize.rule.base.DesensitizationRuleSource;
import com.fr.design.beans.BasicBeanPane;
import com.fr.design.border.UITitledBorder;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
/**
* 脱敏规则展示页
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/8
*/
public class DesensitizationRulePane extends BasicBeanPane<DesensitizationRule> {
/**
* 规则来源选择面板
*/
private DesensitizationRuleSourceChoosePane ruleSourceChoosePane;
/**
* 规则选择面板
*/
private DesensitizationRuleChoosePane ruleChoosePane;
/**
* 内容面板
*/
private JPanel contentPane;
public DesensitizationRulePane() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
initPane();
}
private void initPane() {
// 内容面板
contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
contentPane.setBorder(UITitledBorder.createBorderWithTitle(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Choose")));
this.add(contentPane, BorderLayout.CENTER);
// 规则来源选择Pane
ruleSourceChoosePane = new DesensitizationRuleSourceChoosePane(this);
// 规则选择Pane
ruleChoosePane = new DesensitizationRuleChoosePane();
contentPane.add(ruleSourceChoosePane, BorderLayout.NORTH);
contentPane.add(ruleChoosePane, BorderLayout.CENTER);
}
/**
* 处理规则来源选择面板中改动来源的事件
* @param newRuleSource
*/
public void dealWithRuleSourceChanged(DesensitizationRuleSource newRuleSource) {
ruleChoosePane.switchPaneByRuleSource(newRuleSource);
}
@Override
public void populateBean(DesensitizationRule ob) {
// 这边展示当前所有规则时,不依靠外界传值,初始化的时候,从规则管理中心去获取
}
@Override
public DesensitizationRule updateBean() {
DesensitizationRule desensitizationRule = ruleChoosePane.getSelectedDesensitizationRule();
return DesensitizationRule.valid(desensitizationRule) ?
desensitizationRule :
DesensitizationRule.createDefaultEmptyRule();
}
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule");
}
}

48
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleSourceChoosePane.java

@ -0,0 +1,48 @@
package com.fr.design.data.datapane.preview.desensitization.view.rule;
import com.fr.data.desensitize.rule.base.DesensitizationRuleSource;
import com.fr.design.gui.ibutton.UIRadioButton;
import com.fr.design.i18n.Toolkit;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import java.awt.FlowLayout;
/**
* 脱敏规则来源选择页面
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/26
*/
public class DesensitizationRuleSourceChoosePane extends JPanel {
/**
* 来源平台的按钮
*/
private UIRadioButton serverSource;
/**
* 来源本地的按钮
*/
private UIRadioButton customSource;
public DesensitizationRuleSourceChoosePane(DesensitizationRulePane desensitizationRulePane) {
this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
serverSource = new UIRadioButton(Toolkit.i18nText("Fine-Design_Report_Desensitization_Server_Config_Rules"));
customSource = new UIRadioButton(Toolkit.i18nText("Fine-Design_Report_Desensitization_Custom_Config_Rules"));
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(serverSource);
buttonGroup.add(customSource);
serverSource.setSelected(true);
serverSource.registerChangeListener(() -> desensitizationRulePane.dealWithRuleSourceChanged(DesensitizationRuleSource.SERVER));
customSource.registerChangeListener(() -> desensitizationRulePane.dealWithRuleSourceChanged(DesensitizationRuleSource.CUSTOM));
this.add(serverSource);
this.add(customSource);
}
}

110
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationSettingPane.java

@ -0,0 +1,110 @@
package com.fr.design.data.datapane.preview.desensitization.view.setting;
import com.fr.data.desensitize.base.AbstractDesensitizationTableData;
import com.fr.data.desensitize.base.TableDataDesensitizationBean;
import com.fr.design.beans.BasicBeanPane;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.List;
/**
* 数据集脱敏字段设置页面
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/8
*/
public class TableDataDesensitizationSettingPane extends BasicBeanPane<AbstractDesensitizationTableData> {
/**
* 设置针对的数据集
*/
private AbstractDesensitizationTableData tableData;
private UICheckBox desensitizeOpen;
private TableDataDesensitizationTablePane tableDataDesensitizationTablePane;
public TableDataDesensitizationSettingPane(AbstractDesensitizationTableData tableData) {
this.tableData = tableData;
initComponents();
}
private void initComponents() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.add(initNorthPane(), BorderLayout.NORTH);
this.add(initCenterPane(), BorderLayout.CENTER);
}
/**
* 初始化启用数据脱敏面板
* @return
*/
private JComponent initNorthPane() {
JPanel northPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Desensitization_Config"));
this.desensitizeOpen = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_Desensitization_Opened"));
northPane.add(desensitizeOpen);
UILabel tipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Opened_Tooltips"));
tipLabel.setForeground(UIConstants.CHECK_BOX_TIP_FONT_COLOR);
northPane.add(tipLabel);
return northPane;
}
/**
* 初始化数据脱敏规则表面板
* @return
*/
private JComponent initCenterPane() {
this.tableDataDesensitizationTablePane = new TableDataDesensitizationTablePane(tableData, this);
return tableDataDesensitizationTablePane;
}
/**
* 是否启用脱敏
* @return
*/
public boolean isDesensitizeOpened() {
return desensitizeOpen.isSelected();
}
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Report_Desensitization_Config");
}
@Override
public void populateBean(AbstractDesensitizationTableData tableData) {
this.tableData = tableData;
this.desensitizeOpen.setSelected(tableData.getDesensitizeOpen());
tableDataDesensitizationTablePane.populateDesensitizationSetting(tableData);
}
@Override
public AbstractDesensitizationTableData updateBean() {
saveDesensitizeOpened();
saveDesensitizationBeans(tableDataDesensitizationTablePane.updateDesensitizationSetting());
return tableData;
}
/**
* 保存脱敏启用状态
*/
public void saveDesensitizeOpened() {
tableData.setDesensitizeOpen(desensitizeOpen.isSelected());
}
/**
* 保存脱敏规则配置信息
* @param tableDataDesensitizationBeans
*/
public void saveDesensitizationBeans(List<TableDataDesensitizationBean> tableDataDesensitizationBeans) {
tableData.setDesensitizationBeans(tableDataDesensitizationBeans);
}
}

459
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTableModel.java

@ -0,0 +1,459 @@
package com.fr.design.data.datapane.preview.desensitization.view.setting;
import com.fr.data.desensitize.base.AbstractDesensitizationTableData;
import com.fr.data.desensitize.base.TableDataDesensitizationBean;
import com.fr.data.desensitize.rule.base.DesensitizationRule;
import com.fr.design.data.datapane.preview.desensitization.TableDataPreviewDesensitizeManager;
import com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRulePane;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.icombobox.UIComboBox;
import com.fr.design.gui.icombocheckbox.UIComboCheckBox;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itableeditorpane.UITableEditAction;
import com.fr.design.gui.itableeditorpane.UITableModelAdapter;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.stable.StringUtils;
import com.fr.stable.collections.CollectionUtils;
import org.jetbrains.annotations.Nullable;
import javax.swing.AbstractCellEditor;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/**
* 处理TableDataDesensitizationTablePane中TableEditPane的Model
*
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/23
*/
public class TableDataDesensitizationTableModel extends UITableModelAdapter<TableDataDesensitizationBean> {
private static final String APOSTROPHE = "...";
private AbstractDesensitizationTableData tableData;
/**
* 当前数据集的所有列名
*/
private List<String> columnNames;
/**
* key为用户组唯一标识id拼接value为用户组名称
*/
private Map<String, String> roleMap;
private Component parent;
private DesensitizationRuleChooser ruleChooser;
private DesensitizationRuleDescriptionPane descriptionPane;
public TableDataDesensitizationTableModel(AbstractDesensitizationTableData tableData, Component parent) {
// table相关
super(new String[]{
Toolkit.i18nText("Fine-Design_Report_Desensitization_Column"),
Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule"),
StringUtils.EMPTY,
Toolkit.i18nText("Fine-Design_Report_Desensitization_Effected_Roles")
});
// 一些数据相关
this.tableData = tableData;
// 获取当前数据集的所有列名
this.columnNames = TableDataPreviewDesensitizeManager.getInstance().getColumnNamesByTableData(tableData);
// 获取当前所有用户组
this.roleMap = TableDataPreviewDesensitizeManager.getInstance().getAllRoles();
this.parent = parent;
this.setColumnClass(new Class[]{
// 列名选择
ColumnNamesComboBox.class,
// 规则选择
DesensitizationRuleChooser.class,
// 规则详情展示
DesensitizationRuleDescriptionPane.class,
// 生效用户组选择
EffectedRolesChooser.class
});
this.setDefaultEditor(ColumnNamesComboBox.class, new ColumnNamesComboBox());
this.ruleChooser = new DesensitizationRuleChooser();
this.setDefaultEditor(DesensitizationRuleChooser.class, ruleChooser);
this.setDefaultRenderer(DesensitizationRuleChooser.class, ruleChooser);
this.descriptionPane = new DesensitizationRuleDescriptionPane();
this.setDefaultEditor(DesensitizationRuleDescriptionPane.class, new DesensitizationRuleDescriptionPane());
this.setDefaultEditor(EffectedRolesChooser.class, new EffectedRolesChooser());
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
TableDataDesensitizationBean desensitizationBean = this.getList().get(rowIndex);
switch (columnIndex) {
case 0:
return getColumnNameValue(desensitizationBean);
case 1:
return desensitizationBean.getDesensitizationRule().getRuleName();
case 2:
return DesensitizationRule.getDescription(desensitizationBean.getDesensitizationRule());
case 3:
return matchRoleNamesByIds(desensitizationBean.getRoleIds());
default:
return StringUtils.EMPTY;
}
}
/**
* 根据当前选中的Bean获取其对应的列名字段
* @param desensitizationBean
* @return
*/
private Object getColumnNameValue(TableDataDesensitizationBean desensitizationBean) {
// 内部列名list为空时直接返回空字符串
if (CollectionUtils.isEmpty(columnNames)) {
return StringUtils.EMPTY;
}
// bean的列字段index不对劲时,返回空字符串
return validColumnIndex(desensitizationBean.getColumnIndex()) ?
columnNames.get(desensitizationBean.getColumnIndex()) :
StringUtils.EMPTY;
}
/**
* 判断字段索引是否越界
* @param columnIndex
* @return
*/
private boolean validColumnIndex(int columnIndex) {
return columnIndex >= 0 && columnIndex < columnNames.size();
}
/**
* 通过id匹配此用户组对应的部门职位名称或者说自定义角色名称
*
* @param roleIds
* @return
*/
private List<String> matchRoleNamesByIds(Set<String> roleIds) {
List<String> result = new ArrayList<>();
for (String roleId : roleIds) {
if (roleMap != null && roleMap.containsKey(roleId)) {
result.add(roleMap.get(roleId));
}
}
return result;
}
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
@Override
public UITableEditAction[] createAction() {
return new UITableEditAction[]{new AddDesensitizationAction(), new RemoveDesensitizationAction(parent)};
}
/**
* 获取当前选中的item可能为null
*
* @return
*/
@Nullable
private TableDataDesensitizationBean getCurrentSelectBean() {
return table.getSelectedRow() == -1 ?
null :
getList().get(table.getSelectedRow());
}
/**
* 列名选择下拉框
*/
private class ColumnNamesComboBox extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private UIComboBox columnNameComboBox;
ColumnNamesComboBox() {
columnNameComboBox = new UIComboBox(columnNames.toArray(new String[0]));
this.addCellEditorListener(new CellEditorListener() {
@Override
public void editingStopped(ChangeEvent e) {
TableDataDesensitizationBean desensitizationBean = getCurrentSelectBean();
if (Objects.nonNull(desensitizationBean)) {
desensitizationBean.setColumnIndex(columnNameComboBox.getSelectedIndex());
fireTableDataChanged();
}
}
@Override
public void editingCanceled(ChangeEvent e) {
}
});
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
columnNameComboBox.setSelectedIndex(getList().get(row).getColumnIndex());
return columnNameComboBox;
}
@Override
public Object getCellEditorValue() {
Object selectedItem = columnNameComboBox.getSelectedItem();
return Objects.isNull(selectedItem) ? StringUtils.EMPTY : selectedItem.toString();
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
columnNameComboBox.setSelectedIndex(getList().get(row).getColumnIndex());
return columnNameComboBox;
}
}
private class DesensitizationRuleChooser extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
/**
* 规则选择页面
*/
private JPanel choosePane;
/**
* 规则名称
*/
private UITextField ruleNameTextField;
/**
* 规则选择按钮
*/
private UIButton chooseButton;
/**
* 规则
*/
private DesensitizationRule rule;
private ActionListener chooseRuleListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DesensitizationRulePane rulePane = new DesensitizationRulePane();
BasicDialog ruleDialog = rulePane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), new DialogActionAdapter() {
@Override
public void doOk() {
rule = rulePane.updateBean();
TableDataDesensitizationBean desensitizationBean = getCurrentSelectBean();
if (Objects.nonNull(desensitizationBean) && Objects.nonNull(rule)) {
desensitizationBean.setDesensitizationRule(rule);
fireTableDataChanged();
}
rule = null;
}
}, BasicDialog.DEFAULT);
ruleDialog.setVisible(true);
}
};
DesensitizationRuleChooser() {
// 规则名称展示
ruleNameTextField = new UITextField();
ruleNameTextField.setEnabled(false);
// 规则选择按钮
chooseButton = new UIButton(APOSTROPHE);
chooseButton.addActionListener(chooseRuleListener);
// 规则选择页面
Component[][] templateChooserComponent = {{ruleNameTextField, chooseButton}};
double[] rowSize = {TableLayout.PREFERRED};
double[] columnSize = {TableLayout.FILL, 22};
choosePane = TableLayoutHelper.createCommonTableLayoutPane(templateChooserComponent, rowSize, columnSize, 0);
this.addCellEditorListener(new CellEditorListener() {
@Override
public void editingCanceled(ChangeEvent e) {
}
@Override
public void editingStopped(ChangeEvent e) {
TableDataDesensitizationBean desensitizationBean = getCurrentSelectBean();
if (Objects.nonNull(desensitizationBean) && Objects.nonNull(rule)) {
desensitizationBean.setDesensitizationRule(rule);
fireTableDataChanged();
}
}
});
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
ruleNameTextField.setText(getList().get(row).getDesensitizationRule().getRuleName());
return choosePane;
}
@Override
public Object getCellEditorValue() {
return ruleNameTextField.getText();
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
ruleNameTextField.setText((String) value);
return choosePane;
}
}
private class DesensitizationRuleDescriptionPane extends AbstractCellEditor implements TableCellEditor {
private UILabel descriptionLabel;
DesensitizationRuleDescriptionPane() {
// 规则描述
this.descriptionLabel = new UILabel();
}
/**
* 根据脱敏规则信息刷新下规则描述文字主要用于与规则选择器的联动
*
* @param desensitizationRule
*/
public void refreshDescription(DesensitizationRule desensitizationRule) {
this.descriptionLabel.setText(DesensitizationRule.getDescription(desensitizationRule));
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
refreshDescription(getList().get(row).getDesensitizationRule());
return descriptionLabel;
}
@Override
public Object getCellEditorValue() {
return this.descriptionLabel.getText();
}
}
private class EffectedRolesChooser extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private UIComboCheckBox rolesCheckBox;
EffectedRolesChooser() {
this.rolesCheckBox = new UIComboCheckBox(roleMap.values().toArray(), true);
this.addCellEditorListener(new CellEditorListener() {
@Override
public void editingStopped(ChangeEvent e) {
TableDataDesensitizationBean desensitizationBean = getCurrentSelectBean();
if (Objects.nonNull(desensitizationBean)) {
desensitizationBean.setRoleIds(generateRolesIdsBySelectedValues());
fireTableDataChanged();
}
}
@Override
public void editingCanceled(ChangeEvent e) {
}
});
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
rolesCheckBox.setSelectedValues(generateRolesCheckBoxSelectedValues(getList().get(row)));
return rolesCheckBox;
}
/**
* 根据当前的规则配置信息生成选中的rolesMap用来展示
* @param desensitizationBean
* @return
*/
private Map<Object, Boolean> generateRolesCheckBoxSelectedValues(TableDataDesensitizationBean desensitizationBean) {
Map<Object, Boolean> result = new HashMap<>(roleMap.size());
for (Map.Entry<String, String> roleEntry : roleMap.entrySet()) {
String roleId = roleEntry.getKey();
String roleName = roleEntry.getValue();
if (desensitizationBean.getRoleIds().contains(roleId)) {
result.put(roleName, true);
} else {
result.put(roleName, false);
}
}
return result;
}
/**
* 根据当前的RoleName选择项生成其对应的RoleId的set存入规则配置信息
* @return
*/
private Set<String> generateRolesIdsBySelectedValues() {
Set<String> result = new LinkedHashSet<>();
Object[] selectedValues = rolesCheckBox.getSelectedValues();
for (Object selectedValue : selectedValues) {
String selectedRoleName = (String) selectedValue;
if (roleMap.containsValue(selectedRoleName)) {
Optional<Map.Entry<String, String>> matchedEntry = roleMap.entrySet().stream().filter(entry -> StringUtils.equals(entry.getValue(), selectedRoleName)).findFirst();
matchedEntry.ifPresent(stringStringEntry -> result.add(stringStringEntry.getKey()));
}
}
return result;
}
@Override
public Object getCellEditorValue() {
return rolesCheckBox.getSelectedValues();
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
rolesCheckBox.setSelectedValues(generateRolesCheckBoxSelectedValues(getList().get(row)));
return rolesCheckBox;
}
}
private class AddDesensitizationAction extends AddTableRowAction {
public AddDesensitizationAction() {
this.setName(Toolkit.i18nText("Fine-Design_Report_Desensitization_Add"));
this.setSmallIcon("/com/fr/design/standard/add/add_black", false);
}
@Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
// 添加一条空白数据
addRow(TableDataDesensitizationBean.createEmyptBean());
fireTableDataChanged();
table.getSelectionModel().setSelectionInterval(table.getRowCount() - 1, table.getRowCount() - 1);
}
}
private class RemoveDesensitizationAction extends DeleteAction {
public RemoveDesensitizationAction(Component component) {
super(component);
this.setName(Toolkit.i18nText("Fine-Design_Basic_Base_Remove"));
this.setSmallIcon("/com/fr/design/standard/remove/remove_red", false);
}
@Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
}
}
}

64
designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTablePane.java

@ -0,0 +1,64 @@
package com.fr.design.data.datapane.preview.desensitization.view.setting;
import com.fr.data.desensitize.base.AbstractDesensitizationTableData;
import com.fr.data.desensitize.base.TableDataDesensitizationBean;
import com.fr.design.gui.itableeditorpane.UITableEditorPane;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.util.List;
/**
* 脱敏字段设置页面中的Table
* @author Yvan
* @version 11.0
* Created by Yvan on 2022/9/14
*/
public class TableDataDesensitizationTablePane extends JPanel {
/**
* 脱敏数据集
*/
private AbstractDesensitizationTableData tableData;
/**
* 父页面
*/
private Component parent;
/**
* 脱敏信息Table
*/
private UITableEditorPane<TableDataDesensitizationBean> editorPane;
public TableDataDesensitizationTablePane(AbstractDesensitizationTableData tableData, Component parent) {
this.tableData = tableData;
this.parent = parent;
initComponent();
}
private void initComponent() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.editorPane = new UITableEditorPane<>(new TableDataDesensitizationTableModel(tableData, parent));
this.editorPane.setHeaderResizing(false);
this.add(editorPane, BorderLayout.CENTER);
}
/**
* 展示此TableData中已配置的脱敏规则信息
* @param tableData
*/
public void populateDesensitizationSetting(AbstractDesensitizationTableData tableData) {
this.tableData = tableData;
editorPane.populate(tableData.getDesensitizationBeans().toArray(new TableDataDesensitizationBean[0]));
}
/**
* 获取当前对TableData的配置脱敏规则信息
*/
public List<TableDataDesensitizationBean> updateDesensitizationSetting() {
return editorPane.update();
}
}

7
designer-base/src/main/resources/com/fr/design/images/control/refresh_normal.svg

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>icon_刷新_normal</title>
<g id="icon_刷新_normal" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M13.0593807,1 C13.4802225,1 13.8213822,1.34115968 13.8213822,1.76200147 L13.8213822,1.76200147 L13.8213822,5.2534957 C13.8213822,5.67433749 13.4802225,6.01549717 13.0593807,6.01549717 L13.0593807,6.01549717 L9.56788646,6.01549717 C9.14704467,6.01549717 8.80588499,5.67433749 8.80588499,5.2534957 C8.80588499,4.83265391 9.14704467,4.49149423 9.56788646,4.49149423 L9.56788646,4.49149423 L11.169634,4.48959417 C10.8434607,4.27112237 10.4895308,4.09123525 10.1125367,3.95402064 C7.56533579,3.02691531 4.74885407,4.34026231 3.82174874,6.88746326 C2.89464341,9.43466421 4.20799041,12.2511459 6.75519136,13.1782513 C9.30239231,14.1053566 12.118874,12.7920096 13.0459794,10.2448086 C13.1899157,9.84934672 13.6271844,9.64544497 14.0226464,9.78938133 C14.4181083,9.9333177 14.62201,10.3705864 14.4780737,10.7660483 C13.2630956,14.1041731 9.57207646,15.8253236 6.23395166,14.6103456 C2.89582685,13.3953675 1.17467636,9.70434836 2.38965442,6.36622356 C3.60463249,3.02809876 7.29565164,1.30694826 10.6337764,2.52192632 C11.3047108,2.76612647 11.9217951,3.11486447 12.467588,3.55405023 L12.297,3.423 L12.2973792,1.76200147 C12.2973792,1.37622983 12.5840481,1.05741329 12.9559816,1.00695618 Z" id="Combined-Shape" fill="#333334" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

3
designer-base/src/main/resources/com/fr/design/standard/add/add_black_normal.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 2C7.6134 2 7.3 2.3134 7.3 2.7V7.3H2.7C2.3134 7.3 2 7.6134 2 8C2 8.3866 2.3134 8.7 2.7 8.7H7.3V13.3C7.3 13.6866 7.6134 14 8 14C8.3866 14 8.7 13.6866 8.7 13.3V8.7H13.3C13.6866 8.7 14 8.3866 14 8C14 7.6134 13.6866 7.3 13.3 7.3H8.7V2.7C8.7 2.3134 8.3866 2 8 2Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 430 B

6
designer-base/src/main/resources/com/fr/design/standard/debug/debug_disabled.svg

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.3">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 15V1H15V7.75777C14.6915 7.55127 14.356 7.3819 14 7.25606V2H2V14H8.75777C9.01056 14.3776 9.31899 14.7149 9.67133 15H1ZM8.5 9.4364C8.18047 10.0545 8 10.7562 8 11.5C8 11.8437 8.03853 12.1784 8.11151 12.5H7.5V8.8H7V8V7.8V7H7.5V3.5H8.5V7H9V7.8V8V8.67133C8.9658 8.7136 8.93235 8.75649 8.89967 8.8H8.5V9.4364ZM12 7.02746C11.6533 7.06579 11.3184 7.14352 11 7.25606V3.5H12V7.02746ZM5 3.5H4V5H3.5V5.8V6V6.8H4V12.5H5V6.8H5.5V6V5.8V5H5V3.5Z" fill="#333334"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5 8C12.0858 8 11.75 8.33579 11.75 8.75V9.11511C11.6089 9.15943 11.4731 9.21594 11.344 9.2834L11.0858 9.02516C10.7929 8.73227 10.318 8.73227 10.0251 9.02516C9.73222 9.31806 9.73222 9.79293 10.0251 10.0858L10.2832 10.3439C10.2156 10.473 10.159 10.6088 10.1147 10.75H9.75C9.33579 10.75 9 11.0858 9 11.5C9 11.9142 9.33579 12.25 9.75 12.25H10.1142C10.1588 12.3921 10.2158 12.5287 10.2838 12.6586L10.0266 12.916C9.73378 13.209 9.73378 13.684 10.0266 13.977C10.3194 14.27 10.7941 14.27 11.0869 13.977L11.3452 13.7185C11.4739 13.7857 11.6093 13.842 11.75 13.8862V14.25C11.75 14.6642 12.0858 15 12.5 15C12.9142 15 13.25 14.6642 13.25 14.25V13.8862C13.3914 13.8418 13.5274 13.7851 13.6568 13.7175L13.9142 13.9749C14.2071 14.2678 14.682 14.2678 14.9749 13.9749C15.2678 13.682 15.2678 13.2071 14.9749 12.9142L14.7173 12.6567C14.7848 12.5273 14.8414 12.3914 14.8858 12.25H15.25C15.6642 12.25 16 11.9142 16 11.5C16 11.0858 15.6642 10.75 15.25 10.75H14.8853C14.841 10.609 14.7845 10.4734 14.7171 10.3444L14.9747 10.0866C15.2675 9.79364 15.2675 9.31861 14.9747 9.02562C14.6819 8.73263 14.2072 8.73263 13.9144 9.02562L13.6565 9.28367C13.5272 9.21609 13.3913 9.15949 13.25 9.11511V8.75C13.25 8.33579 12.9142 8 12.5 8ZM12.5 12.5C13.0523 12.5 13.5 12.0523 13.5 11.5C13.5 10.9477 13.0523 10.5 12.5 10.5C11.9477 10.5 11.5 10.9477 11.5 11.5C11.5 12.0523 11.9477 12.5 12.5 12.5Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

4
designer-base/src/main/resources/com/fr/design/standard/debug/debug_normal.svg

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 15V1H15V7.75777C14.6915 7.55127 14.356 7.3819 14 7.25606V2H2V14H8.75777C9.01056 14.3776 9.31899 14.7149 9.67133 15H1ZM8.5 9.4364C8.18047 10.0545 8 10.7562 8 11.5C8 11.8437 8.03853 12.1784 8.11151 12.5H7.5V8.8H7V8V7.8V7H7.5V3.5H8.5V7H9V7.8V8V8.67133C8.9658 8.7136 8.93235 8.75649 8.89967 8.8H8.5V9.4364ZM12 7.02746C11.6533 7.06579 11.3184 7.14352 11 7.25606V3.5H12V7.02746ZM5 3.5H4V5H3.5V5.8V6V6.8H4V12.5H5V6.8H5.5V6V5.8V5H5V3.5Z" fill="#333334"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5 8C12.0858 8 11.75 8.33579 11.75 8.75V9.11511C11.6089 9.15943 11.4731 9.21594 11.344 9.2834L11.0858 9.02516C10.7929 8.73227 10.318 8.73227 10.0251 9.02516C9.73222 9.31806 9.73222 9.79293 10.0251 10.0858L10.2832 10.3439C10.2156 10.473 10.159 10.6088 10.1147 10.75H9.75C9.33579 10.75 9 11.0858 9 11.5C9 11.9142 9.33579 12.25 9.75 12.25H10.1142C10.1588 12.3921 10.2158 12.5287 10.2838 12.6586L10.0266 12.916C9.73378 13.209 9.73378 13.684 10.0266 13.977C10.3194 14.27 10.7941 14.27 11.0869 13.977L11.3452 13.7185C11.4739 13.7857 11.6093 13.842 11.75 13.8862V14.25C11.75 14.6642 12.0858 15 12.5 15C12.9142 15 13.25 14.6642 13.25 14.25V13.8862C13.3914 13.8418 13.5274 13.7851 13.6568 13.7175L13.9142 13.9749C14.2071 14.2678 14.682 14.2678 14.9749 13.9749C15.2678 13.682 15.2678 13.2071 14.9749 12.9142L14.7173 12.6567C14.7848 12.5273 14.8414 12.3914 14.8858 12.25H15.25C15.6642 12.25 16 11.9142 16 11.5C16 11.0858 15.6642 10.75 15.25 10.75H14.8853C14.841 10.609 14.7845 10.4734 14.7171 10.3444L14.9747 10.0866C15.2675 9.79364 15.2675 9.31861 14.9747 9.02562C14.6819 8.73263 14.2072 8.73263 13.9144 9.02562L13.6565 9.28367C13.5272 9.21609 13.3913 9.15949 13.25 9.11511V8.75C13.25 8.33579 12.9142 8 12.5 8ZM12.5 12.5C13.0523 12.5 13.5 12.0523 13.5 11.5C13.5 10.9477 13.0523 10.5 12.5 10.5C11.9477 10.5 11.5 10.9477 11.5 11.5C11.5 12.0523 11.9477 12.5 12.5 12.5Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

5
designer-base/src/main/resources/com/fr/design/standard/edit/edit_disabled.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.3">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V6H13V14H3V2H9V1H3ZM13.6741 3.2816L7.37761 11.3408L5.4982 12.1221L5.80159 10.1095L12.0981 2.05028C12.4381 1.61507 13.0666 1.53791 13.5018 1.87793C13.937 2.21795 14.0142 2.8464 13.6741 3.2816Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 473 B

3
designer-base/src/main/resources/com/fr/design/standard/edit/edit_normal.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V6H13V14H3V2H9V1H3ZM13.6741 3.2816L7.37761 11.3408L5.4982 12.1221L5.80159 10.1095L12.0981 2.05028C12.4381 1.61507 13.0666 1.53791 13.5018 1.87793C13.937 2.21795 14.0142 2.8464 13.6741 3.2816Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 450 B

7
designer-base/src/main/resources/com/fr/design/standard/remove/remove_red_normal.svg

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>icon_关闭_red</title>
<g id="icon_关闭_red" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M7.89949494,0.899494937 C8.28609426,0.899494937 8.59949494,1.21820884 8.59949494,1.59375711 L8.59849494,7.19949494 L14.2052328,7.19949494 C14.5567106,7.19949494 14.8471855,7.46057376 14.8931571,7.80394288 L14.8994949,7.89949494 C14.8994949,8.28609426 14.580781,8.59949494 14.2052328,8.59949494 L8.59849494,8.59849494 L8.59949494,14.2052328 C8.59949494,14.5567106 8.33841611,14.8471855 7.99504699,14.8931571 L7.89949494,14.8994949 C7.51289561,14.8994949 7.19949494,14.580781 7.19949494,14.2052328 L7.19949494,8.59849494 L1.59375711,8.59949494 C1.24227924,8.59949494 0.951804388,8.33841611 0.905832732,7.99504699 L0.899494937,7.89949494 C0.899494937,7.51289561 1.21820884,7.19949494 1.59375711,7.19949494 L7.19949494,7.19949494 L7.19949494,1.59375711 C7.19949494,1.24227924 7.46057376,0.951804388 7.80394288,0.905832732 L7.89949494,0.899494937 Z" id="Combined-Shape" fill="#EB1D1F" transform="translate(7.899495, 7.899495) rotate(45.000000) translate(-7.899495, -7.899495) "></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Loading…
Cancel
Save