diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java index 3d36e563c..a9db9cf93 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java @@ -10,18 +10,16 @@ import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLReadable; import com.fr.stable.xml.XMLable; import com.fr.stable.xml.XMLableReader; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Set; -import java.util.Stack; import org.jetbrains.annotations.NotNull; -import javax.swing.*; +import javax.swing.KeyStroke; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; +import java.util.Stack; /** * AlphaFine配置类 @@ -54,13 +52,17 @@ public class AlphaFineConfigManager implements XMLable { */ private boolean containRecommend = true; /** - * 设置 + * 功能 */ private boolean containAction = true; /** * 帮助文档 */ private boolean containDocument = true; + /** + * 我的模板 + * */ + private boolean containMyTemplate = true; /** * 模板 */ @@ -70,7 +72,7 @@ public class AlphaFineConfigManager implements XMLable { */ private boolean containFileContent; /** - * 应用中心 + * 插件中心 */ private boolean containPlugin = true; /** @@ -95,6 +97,11 @@ public class AlphaFineConfigManager implements XMLable { */ private boolean productDynamics = true; + /** + * 模板商城是否展示 + * */ + private boolean showTemplateShop = true; + private Map actionSearchTextCache = new HashMap<>(8); private String cacheBuildNO; @@ -326,6 +333,14 @@ public class AlphaFineConfigManager implements XMLable { this.containDocument = containDocument; } + public void setContainMyTemplate(boolean containMyTemplate) { + this.containMyTemplate = containMyTemplate; + } + + public boolean isContainMyTemplate() { + return containMyTemplate; + } + public boolean isContainTemplate() { return containTemplate; } @@ -446,6 +461,17 @@ public class AlphaFineConfigManager implements XMLable { return productDynamics && FRContext.isChineseEnv(); } + /** + * 有无模板商城 + * */ + public boolean hasTemplateShop() { + return showTemplateShop && FRContext.isChineseEnv(); + } + + public void setShowTemplateShop(boolean showTemplateShop) { + this.showTemplateShop = showTemplateShop; + } + public void setProductDynamics(boolean productDynamics) { this.productDynamics = productDynamics; } diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java index 55d467e88..90d39b11e 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java @@ -1,17 +1,29 @@ package com.fr.design.actions.help.alphafine; import com.fr.base.FRContext; +import com.fr.base.svg.IconUtils; import com.fr.design.DesignerEnvManager; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.utils.gui.GUICoreUtils; import com.fr.log.FineLoggerFactory; -import javax.swing.*; -import java.awt.*; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; @@ -25,14 +37,22 @@ import java.awt.event.MouseEvent; public class AlphaFineConfigPane extends BasicPane { private static final String TYPE = "pressed"; private static final String DISPLAY_TYPE = "+"; + private static final Color LABEL_TEXT = new Color(0x919193); - - private static final double COLUMN_GAP = 180; - private static final double ROW_GAP = 25; + private static final double COLUMN_WIDTH = 150; + private static final double ROW_HEIGHT = 25; private KeyStroke shortCutKeyStore = null; - private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox, needIntelligentCustomerService, productDynamicsCheckbox, containActionCheckbox, containDocumentCheckbox, containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox; + private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox; + private UICheckBox productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox, + containPluginCheckbox, containActionCheckbox, containMyTemplateCheckbox; private UITextField shortcutsField; + // 搜索范围-我的模板,相关组件 + private JPanel containMyTemplatePane; + private JButton myTemplateSearchConfigButton; + private UIPopupMenu myTemplateSearchMenu; + private UICheckBox containTemplateNameSearchCheckbox, containFileContentSearchCheckbox; + public AlphaFineConfigPane() { this.initComponents(); } @@ -45,15 +65,6 @@ public class AlphaFineConfigPane extends BasicPane { createSearchConfigPane(contentPane); this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.add(contentPane, BorderLayout.NORTH); - - } - - private Component[][] initSearchRangeComponents() { - Component[][] components = new Component[][]{ - new Component[]{productDynamicsCheckbox, containActionCheckbox, containDocumentCheckbox}, - new Component[]{containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox}, - }; - return components; } private Component[][] initOnlineComponents() { @@ -63,24 +74,103 @@ public class AlphaFineConfigPane extends BasicPane { return components; } + /** + * 搜索范围 + * */ private void createSearchConfigPane(JPanel contentPane) { - double[] rowSize = {ROW_GAP, ROW_GAP, ROW_GAP}; - - double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP}; + double[] rowSize = {ROW_HEIGHT, ROW_HEIGHT, ROW_HEIGHT}; + double[] columnSize = {COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH}; JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Search_Range")); - productDynamicsCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_Dynamics")); - containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set")); + productDynamicsCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_News")); + containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Function")); containPluginCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Plugin_Addon")); containDocumentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Community_Help")); - containTemplateCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Templates")); - containFileContentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Templates_Content")); - needIntelligentCustomerService = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Intelligent_Customer_Service")); + containMyTemplateCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_My_Templates")); + containFileContentSearchCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Templates_Content")); + containTemplateShopCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Shop")); + containMyTemplateCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_My_Templates")); JPanel searchConfigPane = TableLayoutHelper.createTableLayoutPane(initSearchRangeComponents(), rowSize, columnSize); northPane.add(searchConfigPane); contentPane.add(northPane); } + private Component[][] initSearchRangeComponents() { + // 我的模板checkbox设置,点击后 + initMyTemplateSearchPane(); + + Component[][] components = new Component[][]{ + new Component[]{productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox}, + new Component[]{containPluginCheckbox, containActionCheckbox, containMyTemplatePane}, + }; + + for (int i = 0; i < components.length; i++) { + for (int j = 0; j < components[i].length; j++) { + if (components[i][j] instanceof UICheckBox) { + UICheckBox box = (UICheckBox) components[i][j]; + } + } + } + return components; + } + + /** + * 【搜索范围】中的复选框有无选中的 + * */ + private boolean hasSelectedSearchRangeCheckBox() { + return productDynamicsCheckbox.isSelected() || containTemplateShopCheckbox.isSelected() || containDocumentCheckbox.isSelected() + || containPluginCheckbox.isSelected() || containActionCheckbox.isSelected() || containMyTemplateCheckbox.isSelected(); + } + + /** + * 搜索范围-我的模板 + */ + private void initMyTemplateSearchPane() { + containMyTemplatePane = new JPanel(new FlowLayout(FlowLayout.LEFT,4,5)); + containMyTemplateCheckbox.setBorder(BorderFactory.createEmptyBorder()); + containMyTemplateCheckbox.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (containMyTemplateCheckbox.isSelected()) { + myTemplateSearchConfigButton.setVisible(true); + } else { + myTemplateSearchConfigButton.setVisible(false); + } + } + } + ); + myTemplateSearchConfigButton = new JButton(); + myTemplateSearchConfigButton.setBorder(BorderFactory.createEmptyBorder()); + myTemplateSearchConfigButton.setMargin(new Insets(0,0,0,0)); + myTemplateSearchConfigButton.setIcon(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/config.svg")); + myTemplateSearchMenu = new UIPopupMenu(); + containTemplateNameSearchCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_AlphaFine_Config_Name_Search")); + containFileContentSearchCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_AlphaFine_Config_Content_Search")); + containTemplateNameSearchCheckbox.setSelected(true); + containTemplateNameSearchCheckbox.setEnabled(false); + containTemplateNameSearchCheckbox.setBackground(null); + containFileContentSearchCheckbox.setBackground(null); + myTemplateSearchMenu.add(containTemplateNameSearchCheckbox); + myTemplateSearchMenu.add(containFileContentSearchCheckbox); + myTemplateSearchConfigButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + GUICoreUtils.showPopupMenu(myTemplateSearchMenu, containMyTemplatePane, containMyTemplateCheckbox.getWidth(), containMyTemplatePane.getY()); + } + + @Override + public void mouseMoved(MouseEvent e) { + super.mouseMoved(e); + myTemplateSearchMenu.setVisible(false); + } + }); + containMyTemplatePane.add("containMyTemplateCheckbox", containMyTemplateCheckbox); + containMyTemplatePane.add("myTemplateSearchConfigButton", myTemplateSearchConfigButton); + } + + private void createShortcutsPane(JPanel contentPane) { JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Shortcut_Config")); shortcutsField = new UITextField(); @@ -91,7 +181,7 @@ public class AlphaFineConfigPane extends BasicPane { northPane.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open") + ":")); northPane.add(shortcutsField); UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_SetShortcuts")); - label.setForeground(Color.RED); + label.setForeground(LABEL_TEXT); northPane.add(label); contentPane.add(northPane); } @@ -130,21 +220,21 @@ public class AlphaFineConfigPane extends BasicPane { productDynamicsCheckbox.setEnabled(false); containPluginCheckbox.setEnabled(false); containDocumentCheckbox.setEnabled(false); - needIntelligentCustomerService.setEnabled(false); + containTemplateShopCheckbox.setEnabled(false); productDynamicsCheckbox.setSelected(false); containPluginCheckbox.setSelected(false); containDocumentCheckbox.setSelected(false); - needIntelligentCustomerService.setSelected(false); + containTemplateShopCheckbox.setSelected(false); } else { productDynamicsCheckbox.setEnabled(true); containPluginCheckbox.setEnabled(true); containDocumentCheckbox.setEnabled(true); - needIntelligentCustomerService.setEnabled(true); + containTemplateShopCheckbox.setEnabled(true); } } }); - double[] rowSize = {ROW_GAP}; - double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP}; + double[] rowSize = {ROW_HEIGHT}; + double[] columnSize = {COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH}; JPanel onlinePane = TableLayoutHelper.createTableLayoutPane(initOnlineComponents(), rowSize, columnSize); northPane.add(onlinePane); contentPane.add(northPane); @@ -172,8 +262,10 @@ public class AlphaFineConfigPane extends BasicPane { this.searchOnlineCheckbox.setSelected(enabled4Locale); this.containActionCheckbox.setSelected(alphaFineConfigManager.isContainAction()); - this.containTemplateCheckbox.setSelected(alphaFineConfigManager.isContainTemplate()); - this.containFileContentCheckbox.setSelected(alphaFineConfigManager.isContainFileContent()); + + this.containMyTemplateCheckbox.setSelected(alphaFineConfigManager.isContainMyTemplate()); + this.myTemplateSearchConfigButton.setVisible(alphaFineConfigManager.isContainMyTemplate()); + this.containFileContentSearchCheckbox.setSelected(alphaFineConfigManager.isContainFileContent()); this.containDocumentCheckbox.setSelected(alphaFineConfigManager.isContainDocument() && enabled4Locale); this.containDocumentCheckbox.setEnabled(enabled4Locale); @@ -184,13 +276,13 @@ public class AlphaFineConfigPane extends BasicPane { this.productDynamicsCheckbox.setSelected(alphaFineConfigManager.isProductDynamics() && enabled4Locale); this.productDynamicsCheckbox.setEnabled(enabled4Locale); + this.containTemplateShopCheckbox.setSelected(alphaFineConfigManager.hasTemplateShop() && enabled4Locale); + this.containTemplateShopCheckbox.setEnabled(enabled4Locale); + this.shortcutsField.setText(AlphaFineShortCutUtil.getDisplayShortCut(alphaFineConfigManager.getShortcuts())); this.needSegmentationCheckbox.setSelected(alphaFineConfigManager.isNeedSegmentationCheckbox()); - this.needIntelligentCustomerService.setSelected(alphaFineConfigManager.isNeedIntelligentCustomerService() && enabled4Locale); - this.needIntelligentCustomerService.setEnabled(enabled4Locale); - shortCutKeyStore = convert2KeyStroke(alphaFineConfigManager.getShortcuts()); } @@ -201,12 +293,12 @@ public class AlphaFineConfigPane extends BasicPane { alphaFineConfigManager.setContainAction(this.containActionCheckbox.isSelected()); alphaFineConfigManager.setContainDocument(this.containDocumentCheckbox.isSelected()); alphaFineConfigManager.setProductDynamics(this.productDynamicsCheckbox.isSelected()); + alphaFineConfigManager.setShowTemplateShop(this.containTemplateShopCheckbox.isSelected()); alphaFineConfigManager.setEnabled(this.enabledCheckbox.isSelected()); alphaFineConfigManager.setSearchOnLine(this.searchOnlineCheckbox.isSelected()); - alphaFineConfigManager.setContainTemplate(this.containTemplateCheckbox.isSelected()); - alphaFineConfigManager.setContainFileContent(this.containFileContentCheckbox.isSelected()); + alphaFineConfigManager.setContainMyTemplate(this.containMyTemplateCheckbox.isSelected()); + alphaFineConfigManager.setContainFileContent(this.containFileContentSearchCheckbox.isSelected()); alphaFineConfigManager.setNeedSegmentationCheckbox(this.needSegmentationCheckbox.isSelected()); - alphaFineConfigManager.setNeedIntelligentCustomerService(this.needIntelligentCustomerService.isSelected()); alphaFineConfigManager.setShortcuts(shortCutKeyStore != null ? shortCutKeyStore.toString().replace(TYPE, DISPLAY_TYPE) : this.shortcutsField.getText()); designerEnvManager.setAlphaFineConfigManager(alphaFineConfigManager); try { @@ -233,10 +325,10 @@ public class AlphaFineConfigPane extends BasicPane { } public UICheckBox getIsContainFileContentCheckbox() { - return containFileContentCheckbox; + return containFileContentSearchCheckbox; } public void setIsContainFileContentCheckbox(UICheckBox isContainFileContentCheckbox) { - this.containFileContentCheckbox = isContainFileContentCheckbox; + this.containFileContentSearchCheckbox = isContainFileContentCheckbox; } } diff --git a/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java b/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java index dd3ddab3b..fe6614c0a 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java +++ b/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java @@ -18,6 +18,7 @@ import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.FlowLayout; import java.awt.Frame; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -43,6 +44,10 @@ public abstract class UIDialog extends JDialog { super(parent); } + public UIDialog(Window parent) { + super(parent); + } + public UIDialog(Frame parent, BasicPane pane) { this(parent, pane, true); diff --git a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java index 2e839d27c..b4229a2fa 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java +++ b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java @@ -1,16 +1,18 @@ package com.fr.design.dialog.link; -import com.fr.design.gui.ilable.UILabel; +import com.fr.design.utils.LinkStrUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import javax.swing.JEditorPane; import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; import java.awt.Color; import java.awt.Desktop; import java.awt.Font; import java.net.URI; +import java.net.URL; + +import static com.fr.design.utils.LinkStrUtils.LABEL; /** * 用来构建JOptionPane带超链的消息提示 @@ -21,8 +23,32 @@ import java.net.URI; */ public class MessageWithLink extends JEditorPane { - private static final UILabel LABEL = new UILabel(); + private static final String HTML_BODY = " 的话,将会自动点击匹配 url + * + * @param htmlText html内容 + */ + public MessageWithLink(String htmlText) { + + super("text/html", htmlText); + initListener(); + setEditable(false); + setBorder(null); + } + + public MessageWithLink(String htmlText, Runnable action) { + super("text/html", htmlText); + initListener(action); + setEditable(false); + setBorder(null); + } public MessageWithLink(String message, String linkName, String link) { this(message, linkName, link, LABEL.getBackground(), LABEL.getFont()); @@ -48,37 +74,74 @@ public class MessageWithLink extends JEditorPane { this(frontMessage, linkName, link, backMessage, color, font, LABEL.getForeground()); } + public MessageWithLink(String htmlText, Font font) { + this(setHtmlFont(htmlText, font)); + } + + + + /** + * 将指定的字体赋给html文本 + * 任何失败,返回原html文本 + * */ + private static String setHtmlFont(String htmlText, Font font) { + + try { + int bodyIndex = htmlText.indexOf(HTML_BODY); + StringBuilder sb = new StringBuilder(); + String left = htmlText.substring(0, bodyIndex + HTML_BODY.length()); + String right = htmlText.substring(bodyIndex + HTML_BODY.length()); + sb.append(left); + sb.append(String.format(HTML_STYLE_FORMAT, LinkStrUtils.generateStyle(Color.WHITE, font, Color.BLACK))); + sb.append(right); + return sb.toString(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + + return htmlText; + } + public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) { - super("text/html", "" + frontMessage + "" + linkName + "" + backMessage + ""); + + super("text/html", "" + frontMessage + "" + linkName + "" + backMessage + ""); initListener(link); setEditable(false); setBorder(null); } - protected void initListener(String link) { - addHyperlinkListener(new HyperlinkListener() { - @Override - public void hyperlinkUpdate(HyperlinkEvent e) { - if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { - try { - Desktop.getDesktop().browse(URI.create(link)); - } catch (Exception exception) { - FineLoggerFactory.getLogger().error(exception.getMessage(), exception); - } + protected void initListener() { + + addHyperlinkListener(hyperlinkEvent -> { + try { + if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { + URL url = hyperlinkEvent.getURL(); + Desktop.getDesktop().browse(url.toURI()); } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); } }); } - private static StringBuilder generateStyle(Color backgroundColor, Font font, Color fontColor) { - // 构建相同风格样式 - StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); - style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); - style.append("font-size:").append(font.getSize()).append("pt;"); - style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");"); - style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");"); + protected void initListener(Runnable runnable) { - return style; + addHyperlinkListener(e -> { + if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { + runnable.run(); + } + }); + } + + protected void initListener(String link) { + + initListener(() -> { + try { + Desktop.getDesktop().browse(URI.create(link)); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + }); } } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/ImgChooseWrapper.java b/designer-base/src/main/java/com/fr/design/gui/frpane/ImgChooseWrapper.java index 19823d8b4..1f8475869 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/ImgChooseWrapper.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/ImgChooseWrapper.java @@ -105,7 +105,7 @@ public class ImgChooseWrapper { } else { BufferedImage image = BaseUtils.readImage(selectedFile.getPath()); String type = ImageUtils.getImageType(selectedFile); - imageWithSuffix = new ImageWithSuffix(image, type); + imageWithSuffix = new ImageWithSuffix(image, type, selectedFile.getPath()); } CoreGraphHelper.waitForImage(imageWithSuffix); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java b/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java new file mode 100644 index 000000000..c0ea5be20 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java @@ -0,0 +1,202 @@ +package com.fr.design.mainframe.toast; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.dialog.UIDialog; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.module.ModuleContext; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Window; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * + * alphafine - 下载模板时的toast弹窗 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class SimpleToast extends UIDialog { + private static final int MIN_HEIGHT = 36; + private static final String TOAST_MSG_TIMER = "TOAST_MSG_TIMER"; + private static final long DEFAULT_DISAPPEAR_DELAY = 5000; + private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS; + + + private ScheduledExecutorService timer; + private int hideHeight = 0; + private JPanel contentPane; + private boolean show = false; + private Window parent; + private boolean autoDisappear; + + public SimpleToast(Window parent, Icon icon, String text, boolean autoDisappear) { + super(parent); + this.parent = parent; + this.autoDisappear = autoDisappear; + JPanel panel = createContentPane(icon, text); + init(panel); + } + + private JPanel createContentPane(Icon icon, String text) { + JPanel pane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + UILabel iconLabel = new UILabel(icon); + iconLabel.setVerticalAlignment(SwingConstants.TOP); + iconLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0)); + + + UILabel textLabel = new UILabel(text); + pane.add(iconLabel, BorderLayout.WEST); + pane.add(textLabel, BorderLayout.CENTER); + pane.setBorder(BorderFactory.createEmptyBorder(8, 15, 8, 15)); + + return pane; + } + + + private void init(JPanel panel) { + setFocusable(false); + setAutoRequestFocus(false); + setUndecorated(true); + contentPane = panel; + initComponent(); + } + + private void initComponent() { + this.getContentPane().setLayout(null); + this.getContentPane().add(contentPane); + Dimension dimension = calculatePreferSize(); + hideHeight = dimension.height; + setSize(new Dimension(dimension.width, 0)); + contentPane.setSize(dimension); + setRelativeLocation(dimension); + if (autoDisappear) { + disappear(contentPane); + } + } + + private void setRelativeLocation(Dimension dimension) { + int positionX = parent.getLocationOnScreen().x + (parent.getWidth() - dimension.width) / 2; + int positionY = parent.getLocationOnScreen().y + 10; + this.setLocation(positionX, positionY); + } + + private Dimension calculatePreferSize() { + Dimension contentDimension = contentPane.getPreferredSize(); + int height = Math.max(MIN_HEIGHT, contentDimension.height); + return new Dimension(contentDimension.width, height); + } + + + /** + * 显示toast + * */ + public void display(JPanel outerPanel) { + show = true; + outerPanel.setLocation(0, -hideHeight); + ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService(); + tipToolTimer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(()->{ + displayStep(outerPanel, tipToolTimer); + }); + } + }, 0, 50, TimeUnit.MILLISECONDS); + + } + + void displayStep(JPanel outerPanel, ScheduledExecutorService timer) { + Point point = outerPanel.getLocation(); + if (point.y >= 0 && !timer.isShutdown()) { + timer.shutdown(); + } + int showDistance = 5 + point.y < 0 ? 5 : -point.y; + outerPanel.setLocation(point.x, point.y + showDistance); + Dimension dimension = SimpleToast.this.getSize(); + SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height + showDistance)); + } + + + + + + + private void disappear(JPanel outerPanel, long delay, TimeUnit timeUnit) { + timer = createToastScheduleExecutorService(); + timer.schedule(new DisappearMotion(outerPanel), delay, timeUnit); + } + + /** + * toast消失的动画效果 + * */ + class DisappearMotion implements Runnable { + JPanel panel; + + DisappearMotion(JPanel panel) { + this.panel = panel; + } + + @Override + public void run() { + ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService(); + tipToolTimer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(()->{ + disappearStep(tipToolTimer); + }); + } + }, 0, 50, TimeUnit.MILLISECONDS); + } + + void disappearStep(ScheduledExecutorService timer) { + Point point = panel.getLocation(); + if (point.y <= -hideHeight && !timer.isShutdown()) { + timer.shutdown(); + SimpleToast.this.setVisible(false); + SimpleToast.this.dispose(); + SimpleToast.this.show = false; + } + panel.setLocation(point.x, point.y - 5); + Dimension dimension = SimpleToast.this.getSize(); + SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height - 5)); + } + } + + private void disappear(JPanel outerPanel) { + disappear(outerPanel, DEFAULT_DISAPPEAR_DELAY, DEFAULT_TIME_UNIT); + } + + private ScheduledExecutorService createToastScheduleExecutorService() { + return ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory(TOAST_MSG_TIMER)); + } + + @Override + public void checkValid() throws Exception { + } + + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + display(contentPane); + } + } + + @Override + public void dispose() { + super.dispose(); + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java b/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java new file mode 100644 index 000000000..e394bbbac --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java @@ -0,0 +1,108 @@ +package com.fr.design.utils; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.stable.StringUtils; + +import javax.swing.JComponent; +import java.awt.Color; +import java.awt.Font; + +/** + * + * 链接字符串工具类 + * + * @author Harrison + * @version 10.0 + * created by Harrison on 2022/05/24 + **/ +public class LinkStrUtils { + + public static final UILabel LABEL = new UILabel(); + + /** + * 创建链接label + * */ + public static UILabel generateLabel(String html, JComponent templateLabel) { + + String style = generateStyle(templateLabel.getBackground(), templateLabel.getFont(), templateLabel.getForeground()); + String fullHtml = generateHtmlTag(style, html); + return new UILabel(fullHtml); + } + + /** + * 创建链接字符串,html格式 + * */ + public static String generateHtmlTag(String html) { + + String defaultStyle = generateDefaultStyle(); + return generateHtmlTag(defaultStyle, html); + } + + /** + * 创建链接字符串,html格式 + * */ + public static String generateHtmlTag(String style, String html) { + + if (StringUtils.isEmpty(style)) { + throw new NullPointerException("style"); + } + if (StringUtils.isEmpty(html)) { + throw new NullPointerException("html"); + } + return "" + html + ""; + } + + /** + * 创建链接字符串,html格式 + * */ + public static String generateLinkTag(String link, String text) { + + return "" + text + ""; + } + + /** + * 创建链接字符串,无下划线,html格式 + * */ + public static String generateLinkTagWithoutUnderLine(String link, String text) { + return "" + text + ""; + } + + /** + * 创建链接字符串的html style + * */ + public static String generateStyle(Color backgroundColor, Font font, Color fontColor) { + + // 构建相同风格样式 + StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); + + style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); + style.append("font-size:").append(font.getSize()).append("pt;"); + style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");"); + style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");"); + + return style.toString(); + } + + /** + * 创建链接字符串的html style + * */ + public static String generateStyle(Font font, Color fontColor) { + + // 构建相同风格样式 + StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); + + style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); + style.append("font-size:").append(font.getSize()).append("pt;"); + style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");"); + return style.toString(); + } + + + /** + * 创建默认style + * */ + public static String generateDefaultStyle() { + + return generateStyle(LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground()); + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java index 8de2a0d63..935d2d0e3 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java @@ -5,8 +5,9 @@ import com.fr.base.svg.IconUtils; import com.fr.design.i18n.Toolkit; import com.fr.design.utils.DesignUtils; import com.fr.general.CloudCenter; - import com.fr.general.IOUtils; + +import javax.swing.Icon; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; @@ -14,7 +15,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; -import javax.swing.Icon; /** @@ -81,6 +81,8 @@ public class AlphaFineConstants { public static final Color WHITE = new Color(0xf9f9f9); + public static final Color LABEL_SELECTED = new Color(0x419bf9); + public static final Color GRAY = new Color(0xd2d2d2); public static final Color LIGHT_GRAY = new Color(0xcccccc); @@ -154,9 +156,21 @@ public class AlphaFineConstants { public static final String ALPHA_PREVIEW = CloudCenter.getInstance().acquireUrlByKind("af.preview"); - public static final String ALPHA_CID = CloudCenter.getInstance().acquireUrlByKind("af.cid", "https://cid.fanruan.com/api/nav/alphafine"); + public static final String ALPHA_CID = CloudCenter.getInstance().acquireUrlByKind("af.cid.new"); + + public static final String ALPHA_CID_USER_GROUP_INFO = CloudCenter.getInstance().acquireUrlByKind("af.cid.user.group.info"); + + public static final String SEARCH_BY_ID = "?id="; + + private static final String QUICK_START_URL = CloudCenter.getInstance().acquireUrlByKind("af.help.quick.start"); + private static final String REPORT_LEARNING_PATH = CloudCenter.getInstance().acquireUrlByKind("af.help.report.learning.path"); + private static final String PARAMETER_LEARNING_PATH = CloudCenter.getInstance().acquireUrlByKind("af.help.param.learning.path"); + private static final String FILL_LEARNING_PATH = CloudCenter.getInstance().acquireUrlByKind("af.help.fill.learning.path"); + private static final String API_SUMMARY = CloudCenter.getInstance().acquireUrlByKind("af.help.api.summary"); + private static final String MONTHLY_DOCUMENT = CloudCenter.getInstance().acquireUrlByKind("af.help.monthly.document"); + - private static final String DEFAULT_RECOMMEND = "[ { \"name\":\"快速入门指南\", \"link\":\"https://help.fanruan.com/finereport/doc-view-1335.html?source=3\" }, { \"name\":\"报表应用学习路径\", \"link\":\"https://help.fanruan.com/finereport/doc-view-1336.html?source=3\" }, { \"name\":\"参数应用学习路径\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4219.html?source=3\" }, { \"name\":\"填报学习路径\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4103.html?source=3\" }, { \"name\":\"API接口汇总\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4327.html?source=3\" }, { \"name\":\"文档月刊\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4613.html?source=3\" } ]"; + private static final String DEFAULT_RECOMMEND = "[ { \"name\":\"快速入门指南\", \"link\":\"" + QUICK_START_URL + "\" }, { \"name\":\"报表应用学习路径\", \"link\":\"" + REPORT_LEARNING_PATH + "\" }, { \"name\":\"参数应用学习路径\", \"link\":\"" + PARAMETER_LEARNING_PATH + "\" }, { \"name\":\"填报学习路径\", \"link\":\"" + FILL_LEARNING_PATH + "\" }, { \"name\":\"API接口汇总\", \"link\":\"" + API_SUMMARY + "\" }, { \"name\":\"文档月刊\", \"link\":\"" + MONTHLY_DOCUMENT + "\" } ]"; public static final String ALPHA_HELP_RECOMMEND = CloudCenter.getInstance().acquireUrlByKind("af.recommend", DEFAULT_RECOMMEND); diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/CellType.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/CellType.java index c558ee584..fc01f668d 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/CellType.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/CellType.java @@ -17,7 +17,8 @@ public enum CellType { RECOMMEND_ROBOT(8), BOTTOM(9), ROBOT(10), - PRODUCT_NEWS(11, "productNews", "productNewsResult", true); + PRODUCT_NEWS(11, "productNews", "productNewsResult", true, false), + TEMPLATE_SHOP(12, "templateShop", "templateShop", false, true); private int typeValue; @@ -35,11 +36,19 @@ public enum CellType { private boolean needNetWork = true; - CellType(int type, String flagStr4None, String flagStr4Result, boolean needNetWork) { + private boolean canLocalSearch = false; + + + CellType(int type, String flagStr4None, String flagStr4Result, boolean needNetWork, boolean canLocalSearch) { this.typeValue = type; this.flagStr4None = flagStr4None; this.flagStr4Result = flagStr4Result; this.needNetWork = needNetWork; + this.canLocalSearch = canLocalSearch; + } + + CellType(int type, String flagStr4None, String flagStr4Result, boolean needNetWork) { + this(type, flagStr4None, flagStr4Result, needNetWork, false); } CellType(int type) { @@ -75,5 +84,8 @@ public enum CellType { public boolean isNeedNetWork() { return needNetWork; } -} + public boolean isCanLocalSearch() { + return canLocalSearch; + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java new file mode 100644 index 000000000..042262609 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java @@ -0,0 +1,102 @@ +package com.fr.design.mainframe.alphafine.action; + +import com.fr.common.util.Strings; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.download.FineMarketConstants; +import com.fr.design.mainframe.alphafine.download.FineMarketDownloadManager; +import com.fr.design.mainframe.alphafine.model.TemplateResourceDetail; +import com.fr.file.FileFILE; +import com.fr.log.FineLoggerFactory; + +import javax.swing.SwingWorker; +import java.awt.Desktop; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; + + +/** + * + * 点击后跳转至帆软市场下载对应模板资源 + * + * @author Link + * @version 11.0 + * Created by Link on 2022/9/22 + * + * TODO:可以参考mini组件商城的下载@ComponentsPackageInstallation#install + * */ +public class StartUseAction implements ActionListener { + + TemplateResourceDetail resourceDetail; + + public StartUseAction(TemplateResourceDetail detail) { + this.resourceDetail = detail; + } + + @Override + public void actionPerformed(ActionEvent e) { + new SwingWorker() { + + @Override + protected String doInBackground() throws Exception { + return FineMarketDownloadManager.getInstance().installResource(resourceDetail.getRoot(), AlphaFineHelper.getAlphaFineDialog()); + } + + @Override + protected void done() { + try { + open(get()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + super.done(); + } + }.execute(); + } + + /** + * 打开模板并打开文件目录 + * */ + void open(String fileName) throws IOException { + if (Strings.isEmpty(fileName)) { + return; + } + // 打开模板 + openInDesigner(fileName); + + // 打开系统文件夹 + File parentDir = new File(fileName).getParentFile(); + Desktop.getDesktop().open(parentDir); + } + + void openInDesigner(String fileName) { + File fileNeedOpen = new File(fileName); + if (fileName.endsWith(FineMarketConstants.ZIP)) { + File[] files = fileNeedOpen.getParentFile().listFiles(); + fileNeedOpen = getFirstCptOrFrm(files); + } else if (fileName.endsWith(FineMarketConstants.RAR)) { + // rar资源没有解压,所以不用打开模板 + return; + } + + // 打开模板 + if (fileNeedOpen == null) { + //有可能压缩包解压出来还是压缩包 + FineLoggerFactory.getLogger().error("AlphaFine open resource error: " + fileName); + } else { + DesignerContext.getDesignerFrame().openTemplate(new FileFILE(fileNeedOpen)); + } + } + + + private File getFirstCptOrFrm(File[] files) { + for (File f : files) { + if (f.getName().endsWith(FineMarketConstants.CPT) || f.getName().endsWith(FineMarketConstants.FRM)) { + return f; + } + } + return null; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/cell/model/DocumentModel.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/cell/model/DocumentModel.java index e83b4be76..7456daffc 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/cell/model/DocumentModel.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/cell/model/DocumentModel.java @@ -2,11 +2,10 @@ package com.fr.design.mainframe.alphafine.cell.model; import com.fr.design.mainframe.alphafine.AlphaFineConstants; import com.fr.design.mainframe.alphafine.CellType; -import com.fr.log.FineLoggerFactory; -import com.fr.json.JSONException; import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; -import java.awt.*; +import java.awt.Desktop; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -60,8 +59,15 @@ public class DocumentModel extends AlphaCellModel { @Override public void doAction() { + openInBrowser(getDocumentUrl()); + } + + /** + * 方便埋点 + * */ + void openInBrowser(String url) { try { - Desktop.getDesktop().browse(new URI(getDocumentUrl())); + Desktop.getDesktop().browse(new URI(url)); } catch (IOException e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } catch (URISyntaxException e) { diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineFrame.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineFrame.java index b6819f56c..66a300280 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineFrame.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineFrame.java @@ -22,20 +22,34 @@ import com.fr.design.mainframe.alphafine.preview.NoResultPane; import com.fr.design.mainframe.alphafine.preview.NoResultWithLinkPane; import com.fr.design.mainframe.alphafine.preview.SearchLoadingPane; import com.fr.design.mainframe.alphafine.preview.SimpleRightSearchResultPane; +import com.fr.design.mainframe.alphafine.preview.TemplateShopPane; import com.fr.design.mainframe.alphafine.question.QuestionWindow; import com.fr.design.mainframe.alphafine.search.ProductNewsSearchWorkerManager; import com.fr.design.mainframe.alphafine.search.SearchTextBean; import com.fr.design.mainframe.alphafine.search.SearchWorkerManager; +import com.fr.design.mainframe.alphafine.search.TemplateResourceSearchWorkerManager; import com.fr.design.mainframe.alphafine.search.manager.impl.ActionSearchManager; import com.fr.design.mainframe.alphafine.search.manager.impl.DocumentSearchManager; import com.fr.design.mainframe.alphafine.search.manager.impl.FileSearchManager; import com.fr.design.mainframe.alphafine.search.manager.impl.PluginSearchManager; import com.fr.design.mainframe.alphafine.search.manager.impl.ProductNewsSearchManager; import com.fr.design.mainframe.alphafine.search.manager.impl.SegmentationManager; +import com.fr.design.mainframe.alphafine.search.manager.impl.TemplateResourceSearchManager; import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.SwingConstants; +import javax.swing.Timer; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; @@ -62,16 +76,6 @@ import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.BorderFactory; -import javax.swing.Icon; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.SwingConstants; -import javax.swing.Timer; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; /** * @author hades @@ -98,7 +102,7 @@ public class AlphaFineFrame extends JFrame { private static final String PLACE_HOLDER = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine"); - private static final String SETTING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set"); + private static final String FUNCTION = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Function"); private static final String NO_RESULT = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_No_Result"); @@ -110,7 +114,7 @@ public class AlphaFineFrame extends JFrame { private static final String GO_FORUM = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Go_Forum"); - private static final String TEMPLATES = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Templates"); + private static final String MY_TEMPLATES = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_My_Templates"); public static final String PRODUCT_NEWS = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_News"); @@ -122,7 +126,7 @@ public class AlphaFineFrame extends JFrame { private static final String NO_SEARCH_RESULT = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_NO_Result"); - private static final String PRODUCT_DYNAMICS = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_Dynamics"); + private static final String TEMPLATE_SHOP = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Shop"); private static final Image SEARCH_IMAGE = SVGLoader.load("/com/fr/design/mainframe/alphafine/images/search.svg"); @@ -152,7 +156,19 @@ public class AlphaFineFrame extends JFrame { private JPanel tabPane; - private CellType selectedType; + private JPanel labelPane; + + private JPanel labelContentPane; + + private JPanel labelEastPane; + + private JPanel labelWestPane; + + private UILabel tabLabel; + + private UILabel readLabel; + + private SelectedLabel selectedTab; private String beforeSearchStr = StringUtils.EMPTY; @@ -168,15 +184,47 @@ public class AlphaFineFrame extends JFrame { private ProductNewsSearchWorkerManager productNewsSearchWorkerManager; + private TemplateResourceSearchWorkerManager templateResourceSearchWorkerManager; + public AlphaFineFrame() { this.setTitle(AlphaFineConstants.TITLE); + //去掉边框 setUndecorated(true); - setSize(AlphaFineConstants.FIELD_SIZE); + setSize(AlphaFineConstants.FULL_SIZE); initComponents(); centerWindow(this); initSearchManager(); } + /** + * 显示指定结果面板 + * */ + public void showResult(String flag) { + cardLayout.show(resultPane, flag); + } + + /** + * add结果面板 + * */ + public void addResult(JPanel panel, String flag) { + resultPane.add(panel, flag); + } + + /** + * 移除指定结果面板 + * */ + public void removeSearchResultPane(JPanel panel) { + resultPane.remove(panel); + } + + public String getSearchText() { + return searchTextField.getText(); + } + + public CellType getSelectedType() { + return selectedTab.getCellType(); + } + private void initSearchManager() { this.productNewsSearchWorkerManager = new ProductNewsSearchWorkerManager( @@ -213,20 +261,26 @@ public class AlphaFineFrame extends JFrame { new LoadingRightSearchResultPane() ); + templateResourceSearchWorkerManager = new TemplateResourceSearchWorkerManager( + CellType.TEMPLATE_SHOP, + searchTextBean -> { + return TemplateResourceSearchManager.getInstance().getSearchResult(searchTextBean.getSearchText()); + }, + this + ); + } /** * 初始化全部组件 */ private void initComponents() { - add(createTopPane(), BorderLayout.NORTH); initSearchTextField(); add(createSearchPane(), BorderLayout.CENTER); add(createShowPane(), BorderLayout.SOUTH); this.getContentPane().setBackground(Color.WHITE); - this.setIconImage(SEARCH_IMAGE); - this.setSize(AlphaFineConstants.FULL_SIZE); + this.setIconImage(SEARCH_IMAGE); // 应用图标 } private JPanel createTopPane() { @@ -289,7 +343,6 @@ public class AlphaFineFrame extends JFrame { } }; - private JPopupMenu createTipPop() { JPanel panel = new JPanel(new BorderLayout()); String toolTip = AlphaFineShortCutUtil.getDisplayShortCut(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Short_Cut", DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getShortcuts())); @@ -305,7 +358,7 @@ public class AlphaFineFrame extends JFrame { popupMenu.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { - // do nothing + // do nothing } @Override @@ -372,29 +425,35 @@ public class AlphaFineFrame extends JFrame { return searchPane; } + /** + * showPane,内容展示区,分为三个小区,tab区,label区,内容区 + * */ private JPanel createShowPane() { JPanel showPane = new JPanel(new BorderLayout()); + + // 内容区,card layout resultPane.add(new DefaultProductNewsPane(), CellType.PRODUCT_NEWS.getFlagStr4None()); resultPane.add(new NoResultWithLinkPane(GO_FORUM, AlphaFineConstants.NO_RESULT_ICON), CellType.NO_RESULT.getFlagStr4None()); resultPane.add(new NoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.ACTION.getFlagStr4None()); resultPane.add(new NoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.FILE.getFlagStr4None()); resultPane.add(new NoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.PLUGIN.getFlagStr4None()); resultPane.add(new HelpDocumentNoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.DOCUMENT.getFlagStr4None()); + resultPane.add(TemplateShopPane.getInstance(), CellType.TEMPLATE_SHOP.getFlagStr4None()); resultPane.add(new NetWorkFailedPane(this::reSearch), AlphaFineConstants.NETWORK_ERROR); - JPanel labelPane = new JPanel(new BorderLayout()); + + // label区,border layout + labelPane = new JPanel(new BorderLayout()); labelPane.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20)); labelPane.setBackground(Color.WHITE); - JPanel labelContentPane = new JPanel(new BorderLayout()); - UILabel tabLabel = new UILabel(PRODUCT_DYNAMICS); - tabLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6); - tabLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); - tabLabel.setPreferredSize(new Dimension(100, 30)); - JPanel westPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); - westPane.add(tabLabel); - labelContentPane.add(westPane, BorderLayout.WEST); - JPanel eastPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0)); - UILabel readLabel = new UILabel(ONE_CLICK_READ); + labelContentPane = new JPanel(new BorderLayout()); + tabLabel = createTabLabel(PRODUCT_NEWS); + labelWestPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); + labelWestPane.add(tabLabel); + labelContentPane.add(labelWestPane, BorderLayout.WEST); + labelEastPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0)); + // 一键已读 + readLabel = new UILabel(ONE_CLICK_READ); readLabel.setHorizontalAlignment(SwingConstants.RIGHT); readLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));; readLabel.setPreferredSize(new Dimension(100, 30)); @@ -406,24 +465,30 @@ public class AlphaFineFrame extends JFrame { showPane.repaint(); } }); - eastPane.add(readLabel); - labelContentPane.add(eastPane, BorderLayout.EAST); + labelEastPane.add(readLabel); + labelContentPane.add(labelEastPane, BorderLayout.EAST); labelContentPane.setBackground(new Color(245, 245, 247)); labelPane.add(labelContentPane); labelPane.setPreferredSize(new Dimension(AlphaFineConstants.FULL_SIZE.width, 30)); + // tab区 flow layout tabPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 10)); tabPane.setBackground(Color.WHITE); List selectedLabelList = createSelectedLabelList(); - selectedType = selectedLabelList.get(0).getCellType(); - // 第一个tab 非产品动态 - if (selectedType != CellType.PRODUCT_NEWS) { - tabLabel.setText(selectedLabelList.get(0).getText()); + selectedTab = null; + for (SelectedLabel label : selectedLabelList) { + if (label.isSelected()) { + selectedTab = label; + break; + } + } + if (this.selectedTab.getCellType() != CellType.PRODUCT_NEWS) { + tabLabel.setText(this.selectedTab.getText()); readLabel.setVisible(false); } - for (SelectedLabel selectedLabel : selectedLabelList) { - selectedLabel.addMouseListener(createMouseListener(selectedLabelList, selectedLabel, tabPane, tabLabel, readLabel)); - tabPane.add(selectedLabel); + for (SelectedLabel label : selectedLabelList) { + label.addMouseListener(createMouseListener(selectedLabelList, label, tabPane, tabLabel, readLabel)); + tabPane.add(label); } showPane.add(tabPane, BorderLayout.NORTH); showPane.add(labelPane, BorderLayout.CENTER); @@ -431,46 +496,55 @@ public class AlphaFineFrame extends JFrame { return showPane; } + private UILabel createTabLabel(String labelName) { + UILabel label = new UILabel(labelName); + label.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + label.setPreferredSize(new Dimension(60, 30)); + label.setForeground(AlphaFineConstants.LABEL_SELECTED); + return label; + } + + public JPanel getLabelWestPane() { + return labelWestPane; + } + + public UILabel getTabLabel() { + return tabLabel; + } + private MouseAdapter createMouseListener(List selectedLabelList, SelectedLabel selectedLabel, JPanel tabPane, UILabel tabLabel, UILabel readLabel) { return new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { + // tab栏里的label全设置为没选中,并设置颜色为灰色 for (SelectedLabel label : selectedLabelList) { label.setSelected(false); label.setForeground(AlphaFineConstants.FOREGROUND_COLOR_8); } + // 选中 selectedLabel.setSelected(true); + AlphaFineFrame.this.selectedTab = selectedLabel; + // 处理产品动态 tab与下方文字展示不一致 if (ComparatorUtils.equals(selectedLabel.getText().trim(), PRODUCT_NEWS)) { - tabLabel.setText(PRODUCT_DYNAMICS); + tabLabel.setText(PRODUCT_NEWS); } else { tabLabel.setText(selectedLabel.getText()); } + + // 刷新westlabelpane + refreshLabelPane(); + + // 将已读设置不可见 readLabel.setVisible(false); + + // tab栏重新绘制 tabPane.repaint(); - switch (selectedLabel.getCellType()) { - case PRODUCT_NEWS: - readLabel.setVisible(true); - switchType(CellType.PRODUCT_NEWS); - break; - case ACTION: - currentSearchWorkerManager = settingSearchWorkerManager; - switchType(CellType.ACTION); - break; - case FILE: - currentSearchWorkerManager = fileSearchWorkerManager; - switchType(CellType.FILE); - break; - case DOCUMENT: - currentSearchWorkerManager = documentWorkerManager; - switchType(CellType.DOCUMENT); - break; - case PLUGIN: - currentSearchWorkerManager = pluginSearchWorkerManager; - switchType(CellType.PLUGIN); - break; - } + + // 选中事件 + switchTab(selectedLabel.getCellType(), readLabel); + if (currentSearchWorkerManager != null) { AlphaFineList alphaFineList = currentSearchWorkerManager.getSearchResultList(); if (alphaFineList != null) { @@ -494,17 +568,55 @@ public class AlphaFineFrame extends JFrame { }; } + + /** + * 方便记埋点 + * */ + private void switchTab(CellType cellType, UILabel readLabel) { + switch (cellType) { + case PRODUCT_NEWS: + readLabel.setVisible(true); + switchType(CellType.PRODUCT_NEWS); + break; + case ACTION: + currentSearchWorkerManager = settingSearchWorkerManager; + switchType(CellType.ACTION); + break; + case FILE: + currentSearchWorkerManager = fileSearchWorkerManager; + switchType(CellType.FILE); + break; + case DOCUMENT: + currentSearchWorkerManager = documentWorkerManager; + switchType(CellType.DOCUMENT); + break; + case PLUGIN: + currentSearchWorkerManager = pluginSearchWorkerManager; + switchType(CellType.PLUGIN); + break; + case TEMPLATE_SHOP: + TemplateShopPane.getInstance().showResult(); + switchType(CellType.TEMPLATE_SHOP); + break; + default: + break; + } + } + + private void refreshLabelPane() { + labelWestPane.removeAll(); + tabLabel.setForeground(AlphaFineConstants.LABEL_SELECTED); + labelWestPane.add(tabLabel); + } + private List createSelectedLabelList() { List selectedLabelList = new ArrayList<>(); AlphaFineConfigManager alphaFineConfigManager = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager(); if (alphaFineConfigManager.isProductDynamics()) { - selectedLabelList.add(new SelectedLabel(PRODUCT_NEWS, CellType.PRODUCT_NEWS, true)); + selectedLabelList.add(new SelectedLabel(PRODUCT_NEWS, CellType.PRODUCT_NEWS)); } - if (alphaFineConfigManager.isContainAction()) { - selectedLabelList.add(new SelectedLabel(SETTING, CellType.ACTION)); - } - if (alphaFineConfigManager.isContainFileContent() || alphaFineConfigManager.isContainTemplate()) { - selectedLabelList.add(new SelectedLabel(TEMPLATES, CellType.FILE)); + if (alphaFineConfigManager.hasTemplateShop()) { + selectedLabelList.add(new SelectedLabel(TEMPLATE_SHOP, CellType.TEMPLATE_SHOP)); } if (alphaFineConfigManager.isContainDocument()) { selectedLabelList.add(new SelectedLabel(HELP, CellType.DOCUMENT)); @@ -512,6 +624,19 @@ public class AlphaFineFrame extends JFrame { if (alphaFineConfigManager.isContainPlugin()) { selectedLabelList.add(new SelectedLabel(PLUGIN, CellType.PLUGIN)); } + if (alphaFineConfigManager.isContainAction()) { + selectedLabelList.add(new SelectedLabel(FUNCTION, CellType.ACTION)); + } + if (alphaFineConfigManager.isContainMyTemplate()) { + selectedLabelList.add(new SelectedLabel(MY_TEMPLATES, CellType.FILE)); + } + + + // 默认选中第一个tab + if (!selectedLabelList.isEmpty()) { + selectedLabelList.get(0).setSelected(true); + } + return selectedLabelList; } @@ -524,7 +649,6 @@ public class AlphaFineFrame extends JFrame { } private void switchType(CellType cellType) { - this.selectedType = cellType; if (StringUtils.isEmpty(searchTextField.getText())) { cardLayout.show(resultPane, cellType.getFlagStr4None()); } else { @@ -541,8 +665,7 @@ public class AlphaFineFrame extends JFrame { if (checkNetworkError()) { return; } - - cardLayout.show(resultPane, cellType.getFlagStr4Result()); + showResult(cellType.getFlagStr4Result()); checkSearchResult(); } @@ -550,23 +673,27 @@ public class AlphaFineFrame extends JFrame { private boolean checkNetworkError() { boolean networkError; - if (selectedType == CellType.PRODUCT_NEWS) { + if (selectedTab.getCellType() == CellType.PRODUCT_NEWS) { networkError = productNewsSearchWorkerManager.isNetWorkError(); + } else if (selectedTab.getCellType() == CellType.TEMPLATE_SHOP) { + networkError = templateResourceSearchWorkerManager.isNetWorkError(); } else { networkError = currentSearchWorkerManager.isNetWorkError(); } - cardLayout.show(resultPane, AlphaFineConstants.NETWORK_ERROR); + showResult(AlphaFineConstants.NETWORK_ERROR); return networkError; } private boolean checkSearchLoading() { boolean searchOver; - if (selectedType == CellType.PRODUCT_NEWS) { + if (selectedTab.getCellType() == CellType.PRODUCT_NEWS) { searchOver = productNewsSearchWorkerManager.isSearchOver(); + } else if (selectedTab.getCellType() == CellType.TEMPLATE_SHOP) { + searchOver = templateResourceSearchWorkerManager.isSearchOver(); } else { searchOver = currentSearchWorkerManager.isSearchOver(); } - cardLayout.show(resultPane, AlphaFineConstants.LOADING); + showResult(AlphaFineConstants.LOADING); return searchOver; } @@ -586,17 +713,20 @@ public class AlphaFineFrame extends JFrame { if (searchResultList != null) { searchResultList.requestFocus(); } - boolean hasSearchResult = true; - if (selectedType == CellType.PRODUCT_NEWS) { - hasSearchResult = productNewsSearchWorkerManager.hasSearchResult(); - } else { - hasSearchResult = currentSearchWorkerManager.hasSearchResult(); - } - if (!hasSearchResult) { - cardLayout.show(resultPane, CellType.NO_RESULT.getFlagStr4None()); + if (!hasSearchResult()) { + showResult(CellType.NO_RESULT.getFlagStr4None()); } + } + private boolean hasSearchResult() { + if (selectedTab.getCellType() == CellType.PRODUCT_NEWS) { + return productNewsSearchWorkerManager.hasSearchResult(); + } else if (selectedTab.getCellType() == CellType.TEMPLATE_SHOP) { + return templateResourceSearchWorkerManager.hasSearchResult(); + } else { + return currentSearchWorkerManager.hasSearchResult(); + } } private void initSearchTextField() { @@ -608,7 +738,6 @@ public class AlphaFineFrame extends JFrame { searchTextField.setBorder(null); } - private void initTextFieldListener() { searchTextField.addKeyListener(new KeyAdapter() { @Override @@ -659,20 +788,24 @@ public class AlphaFineFrame extends JFrame { } + /** + * 控制搜索tip框弹出收起 + * 不断地刷新tab页,并防止tab页显示错误 + * */ private void startSearchTextFieldTimer() { Timer timer = new Timer(TIMER_DELAY, e -> { // 坑 isShowing返回false 即使textField有内容 getText返回的也是空 if (searchTextField.isShowing() && StringUtils.isEmpty(searchTextField.getText())) { SearchTooltipPopup.getInstance().hide(); clearLabel.setVisible(false); - switchType(selectedType); + switchType(selectedTab.getCellType()); + TemplateShopPane.getInstance().quitSearchResultPane(); beforeSearchStr = StringUtils.EMPTY; } else if (searchTextField.hasFocus()) { clearLabel.setVisible(true); SearchTooltipPopup.getInstance().show(searchTextFieldWrapperPane); } tabPane.repaint(); - }); timer.start(); } @@ -751,21 +884,8 @@ public class AlphaFineFrame extends JFrame { } } - public void showResult(String flag) { - cardLayout.show(resultPane, flag); - } - - public void addResult(JPanel panel, String flag) { - resultPane.add(panel, flag); - } - - public void removeSearchResultPane(JPanel panel) { - resultPane.remove(panel); - } - - - private void doSearch(String text) { + refreshLabelPane(); initSearchLoadingPane(); SearchTextBean searchTextBean = generateSearchTextBean(text); this.productNewsSearchWorkerManager.doSearch(searchTextBean); @@ -773,6 +893,7 @@ public class AlphaFineFrame extends JFrame { this.fileSearchWorkerManager.doSearch(searchTextBean); this.documentWorkerManager.doSearch(searchTextBean); this.pluginSearchWorkerManager.doSearch(searchTextBean); + this.templateResourceSearchWorkerManager.doSearch(searchTextBean); } private SearchTextBean generateSearchTextBean(String searchText) { @@ -806,25 +927,15 @@ public class AlphaFineFrame extends JFrame { this.pluginSearchWorkerManager.doSearch(searchTextBean); } + /** + * 所有tab页搜索通用的加载panel + * */ private void initSearchLoadingPane() { if (searchLoadingPane == null) { searchLoadingPane = new SearchLoadingPane(); } resultPane.add(searchLoadingPane, AlphaFineConstants.LOADING); - cardLayout.show(resultPane, AlphaFineConstants.LOADING); - } - - public String getSearchText() { - return searchTextField.getText(); - } - - - public CellType getSelectedType() { - return selectedType; - } - - public void setStoreText(String storeText) { - this.storeText = storeText; + showResult(AlphaFineConstants.LOADING); } /** @@ -839,6 +950,9 @@ public class AlphaFineFrame extends JFrame { return storeText; } + public void setStoreText(String storeText) { + this.storeText = storeText; + } /** * 去除特殊字符,空格等 @@ -894,6 +1008,7 @@ public class AlphaFineFrame extends JFrame { @Override public void setVisible(boolean b) { super.setVisible(b); + switchTab(selectedTab.getCellType(), readLabel); QuestionWindow.getInstance().setVisible(!b); if (!b) { AlphaFineHelper.resetAlphaFineDialog(); @@ -907,4 +1022,4 @@ public class AlphaFineFrame extends JFrame { QuestionWindow.getInstance().setVisible(true); } -} +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsList.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsList.java index 9e4d1c402..91c482579 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsList.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsList.java @@ -4,18 +4,16 @@ import com.fr.design.DesignerEnvManager; import com.fr.design.mainframe.alphafine.AlphaFineConstants; import com.fr.design.mainframe.alphafine.AlphaFineHelper; import com.fr.design.mainframe.alphafine.model.ProductNews; -import com.fr.log.FineLoggerFactory; +import com.fr.design.utils.BrowseUtils; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.ListModel; import java.awt.Cursor; -import java.awt.Desktop; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; -import java.net.URI; -import javax.swing.DefaultListModel; -import javax.swing.JList; -import javax.swing.ListModel; /** * @author hades @@ -63,15 +61,18 @@ public class ProductNewsList extends JList { private void dealWithClick() { ProductNews productNews = getSelectedValue(); - try { - Desktop.getDesktop().browse(new URI(productNews.getUrl())); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } + openNewsInBrowser(productNews.getUrl()); DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getReadSet().add(productNews.getId()); AlphaFineHelper.getAlphaFineDialog().repaint(); } + /** + * 方便埋点 + * */ + private void openNewsInBrowser(String url) { + BrowseUtils.browser(url); + } + public int getHoverIndex() { return hoverIndex; } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/RecommendSearchPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/RecommendSearchPane.java new file mode 100644 index 000000000..bd1abe510 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/RecommendSearchPane.java @@ -0,0 +1,82 @@ +package com.fr.design.mainframe.alphafine.component; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.model.TemplateResource; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +/** + * + * alphafine - 推荐搜索面板 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class RecommendSearchPane extends TemplateResourcePanel { + + private static final Color BORDER_WHITE = new Color(0xe8e8e9); + private static final Color RECOMMEND_SEARCH_KEY_BLUE = new Color(0x419bf9); + + public RecommendSearchPane(TemplateResource templateResource) { + super(); + setTemplateResource(templateResource); + initComponent(); + this.setLayout(new BorderLayout()); + + this.setBorder(BorderFactory.createLineBorder(BORDER_WHITE, 1)); + this.add(getNorthPane(), BorderLayout.NORTH); + this.add(getCenterPane(), BorderLayout.CENTER); + } + + private void initComponent() { + createNorthPane(); + createCenterPane(); + } + + + private void createCenterPane() { + setCenterPane(new JPanel(new FlowLayout(FlowLayout.LEFT))); + JPanel centerPane = getCenterPane(); + centerPane.setBackground(Color.WHITE); + JLabel recommend = new JLabel(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Recommend_For_You")); + centerPane.add(recommend); + + List searchKeys = getTemplateResource().getRecommendSearchKey(); + + for (String key : searchKeys) { + JLabel keyLabel = new SearchKeyLabel(key); + centerPane.add(keyLabel); + } + } + + + class SearchKeyLabel extends JLabel { + String searchKey; + + SearchKeyLabel(String searchKey) { + this.searchKey = searchKey; + setText(searchKey); + setBackground(Color.WHITE); + setForeground(RECOMMEND_SEARCH_KEY_BLUE); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + AlphaFineHelper.getAlphaFineDialog().fireSearch(searchKey); + } + }); + } + + + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourceImagePanel.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourceImagePanel.java new file mode 100644 index 000000000..c8b589e17 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourceImagePanel.java @@ -0,0 +1,90 @@ +package com.fr.design.mainframe.alphafine.component; + +import com.fr.base.GraphHelper; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.utils.DesignUtils; +import com.fr.general.FRFont; +import com.fr.third.jodd.util.StringUtil; + +import javax.swing.JPanel; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; + + +/** + * + * alphafine - 模板资源图片面板 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourceImagePanel extends JPanel { + + private static final int BACKGROUND_HEIGHT = 20; + + private static final Color BACKGROUND_COLOR = new Color(0x419BF9); + + private static final Font TAG_FONT = DesignUtils.getDefaultGUIFont().applySize(12); + + private static final Color COVER_COLOR = new Color(116, 181, 249, 26); + + private TemplateResource templateResource; + + private int width = 200; + private int height = 100; + + public TemplateResourceImagePanel(TemplateResource templateResource) { + this.templateResource = templateResource; + } + + public TemplateResourceImagePanel(TemplateResource templateResource, int width, int height) { + this(templateResource); + this.width = width; + this.height = height; + } + + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + Color defaultColor = g2.getColor(); + + Image image = templateResource.getImage(); + if (image != null) { + g2.drawImage(templateResource.getImage(), 0, 0, getWidth(), getHeight(), this); + } else { + g2.setColor(COVER_COLOR); + g2.fillRect(0, 0, getWidth(), getHeight()); + } + + String tagName = templateResource.getType().getName(); + + if (!StringUtil.isEmpty(tagName)) { + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, .8f)); + g2.setColor(BACKGROUND_COLOR); + g2.fillRect(0, getHeight() - BACKGROUND_HEIGHT, getWidth(), BACKGROUND_HEIGHT); + g2.setColor(Color.WHITE); + int x = (getWidth() - GraphHelper.getWidth(tagName, g2.getFont())) / 2; + g2.setFont(TAG_FONT); + g2.drawString(tagName, x, getHeight() - 5); + } + g2.setColor(defaultColor); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourcePageGridPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourcePageGridPane.java new file mode 100644 index 000000000..7d73bb239 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourcePageGridPane.java @@ -0,0 +1,231 @@ +package com.fr.design.mainframe.alphafine.component; + +import com.fr.base.svg.IconUtils; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.alphafine.model.TemplateResource; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Label; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + * alphafine - 模板资源最外层面板, 卡片布局,每个卡片里塞了scrollpanel + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourcePageGridPane extends JPanel { + + private List data; + private CardLayout cardLayout; + private List pages; + private int totalPage; + + List scrollPanes = new ArrayList<>(); + + private static final int PAGE_MAX_SIZE = 12; + private static final int TABLE_MAX_ROW_COUNT = 4; + private static final int TABLE_COL_COUNT = 3; + private static final int TABLE_VGAP = 15; + private static final int TABLE_HGAP = 15; + private static final int RESOURCE_WIDTH = 197; + private static final int RESOURCE_HEIGHT = 128; + + public TemplateResourcePageGridPane(List templateResourceList) { + this.data = templateResourceList; + totalPage = (int) Math.ceil((double)data.size() / PAGE_MAX_SIZE); + createPages(); + initComponents(); + this.setBackground(Color.WHITE); + this.setBorder(BorderFactory.createEmptyBorder(10, 20, 0, 20)); + switchPage(1); + } + + private void initComponents() { + cardLayout = new CardLayout(); + this.setLayout(cardLayout); + this.setBackground(Color.WHITE); + for (int i = 0; i < pages.size(); i++) { + UIScrollPane scrollPane = new UIScrollPane(pages.get(i)); + scrollPanes.add(scrollPane); + this.add(scrollPane, String.valueOf(i + 1)); + } + } + + + /** + * 构建分页,将资源切分到每一页,并在每一页尾部添加分页按钮 + * */ + private void createPages() { + int dataCnt = data.size(); + List[] slice = new ArrayList[totalPage]; + for (int i = 0; i < dataCnt; i++) { + int index = i / PAGE_MAX_SIZE; + if (slice[index] == null) { + slice[index] = new ArrayList<>(); + } + slice[index].add(data.get(i)); + } + pages = new ArrayList<>(); + for (int i = 0; i < totalPage; i++) { + pages.add(new Page(slice[i], i + 1)); + } + } + + + private void switchPage(int pageNumber) { + if (pageNumber < 1 || pageNumber > this.totalPage) { + return; + } + cardLayout.show(TemplateResourcePageGridPane.this, String.valueOf(pageNumber)); + scrollPanes.get(pageNumber - 1).getVerticalScrollBar().setValue(0); + // 坑,切换页面会刷新失败,需要手动滚动一下才能刷新 + scrollPanes.get(pageNumber - 1).getVerticalScrollBar().setValue(1); + scrollPanes.get(pageNumber - 1).getVerticalScrollBar().setValue(0); + } + + + /** + * 分页panel,borderlayout布局,north为信息页,south为分页按钮区 + * */ + private class Page extends JPanel { + List pageData; + Component[][] comps; + + JPanel contentPane; + + JPanel pageButtonPane; + JButton prev, next; + JTextField pageNumberField; + JLabel pageCnt; + + int pageNumber; + + Page(List pageData, int pageNumber) { + super(); + this.pageData = pageData; + this.pageNumber = pageNumber; + initComponents(); + this.setLayout(new BorderLayout()); + this.add(contentPane, BorderLayout.NORTH); + if (totalPage > 1) { + this.add(pageButtonPane, BorderLayout.SOUTH); + } + this.setBackground(Color.WHITE); + this.setBorder(BorderFactory.createEmptyBorder()); + } + + private void initComponents() { + createContentPane(); + createPageButtonPane(); + } + + void createContentPane() { + int dataCnt = pageData.size(); + int rowCnt = (int) Math.ceil((double)dataCnt / 3); + double[] rowHeight = new double[rowCnt]; + double[] colWidth = new double[TABLE_COL_COUNT]; + Arrays.fill(rowHeight, RESOURCE_HEIGHT); + Arrays.fill(colWidth, RESOURCE_WIDTH); + comps = new Component[rowCnt][TABLE_COL_COUNT]; + + for (int i = 0; i < rowCnt; i++) { + for (int j = 0; j < TABLE_COL_COUNT; j++) { + int which = i * 3 + j; + if (which >= dataCnt) { + Label empty = new Label(); + empty.setPreferredSize(new Dimension(RESOURCE_WIDTH, RESOURCE_HEIGHT)); + empty.setVisible(false); + comps[i][j] = empty; + } else { + TemplateResourcePanel resource = TemplateResourcePanel.create(pageData.get(which)); + resource.setPreferredSize(new Dimension(RESOURCE_WIDTH, RESOURCE_HEIGHT)); + comps[i][j] = resource; + } + } + } + contentPane = TableLayoutHelper.createGapTableLayoutPane(comps, rowHeight, colWidth, TABLE_HGAP, TABLE_VGAP); + contentPane.setBackground(Color.WHITE); + } + + void createPageButtonPane() { + prev = new JButton(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/prev.svg")); + next = new JButton(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/next.svg")); + pageNumberField = new JTextField((int) Math.log10(totalPage) + 1); + pageNumberField.setText(String.valueOf(this.pageNumber)); + pageCnt = new JLabel("/ " + totalPage); + + pageButtonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + pageButtonPane.add(prev); + pageButtonPane.add(pageNumberField); + pageButtonPane.add(pageCnt); + pageButtonPane.add(next); + + addPageAction(); + } + + // 添加翻页按钮事件 + void addPageAction() { + addPrevPageAction(); + addNextPageAction(); + addGotoPageAction(); + } + + void addPrevPageAction() { + prev.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (pageNumber > 1) { + switchPage(pageNumber - 1); + } + } + }); + }; + void addNextPageAction() { + next.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (pageNumber < totalPage) { + switchPage(pageNumber + 1); + } + } + }); + + } + void addGotoPageAction() { + pageNumberField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + super.keyPressed(e); + String numb = pageNumberField.getText(); + if (numb != null && !numb.equals(pageNumber)) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + switchPage(Integer.parseInt(numb)); + } + } + } + }); + } + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourcePanel.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourcePanel.java new file mode 100644 index 000000000..4985f9c11 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/TemplateResourcePanel.java @@ -0,0 +1,138 @@ +package com.fr.design.mainframe.alphafine.component; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.mainframe.alphafine.preview.TemplateShopPane; +import com.fr.design.utils.BrowseUtils; +import com.fr.design.utils.DesignUtils; +import com.fr.log.FineLoggerFactory; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * + * alphafine - 模板资源面板 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourcePanel extends JPanel { + + private JPanel northPane; + private JPanel centerPane; + private TemplateResource templateResource; + + private static final Color PANEL_BORDER_COLOR = new Color(0xe8e8e9); + private static final Color DEMO_LABEL_FOREGROUND = new Color(0x419bf9); + private static final Font RESOURCE_NAME_FONT = DesignUtils.getDefaultGUIFont().applySize(12); + private static final Color RESOURCE_NAME_COLOR = new Color(0x5c5c5d); + + protected TemplateResourcePanel() { + + } + + protected TemplateResourcePanel(TemplateResource templateResource) { + this.templateResource = templateResource; + initComponent(); + this.setLayout(new BorderLayout()); + this.setBorder(BorderFactory.createLineBorder(PANEL_BORDER_COLOR, 1)); + this.add(northPane, BorderLayout.NORTH); + this.add(centerPane, BorderLayout.CENTER); + addAction(); + } + + private void addAction() { + this.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + TemplateShopPane.getInstance().searchAndShowDetailPane(templateResource); + } + }); + } + + /** + * 通过数据构造面板 + * */ + public static TemplateResourcePanel create(TemplateResource templateResource) { + if (TemplateResource.Type.RECOMMEND_SEARCH.equals(templateResource.getType())) { + return new RecommendSearchPane(templateResource); + } else { + return new TemplateResourcePanel(templateResource); + } + } + + public JPanel getNorthPane() { + return northPane; + } + public JPanel getCenterPane() { + return centerPane; + } + public TemplateResource getTemplateResource() { + return templateResource; + } + + public void setNorthPane(JPanel northPane) { + this.northPane = northPane; + } + + public void setCenterPane(JPanel centerPane) { + this.centerPane = centerPane; + } + + public void setTemplateResource(TemplateResource templateResource) { + this.templateResource = templateResource; + } + + private void initComponent() { + createNorthPane(); + createCenterPane(); + } + + protected void createNorthPane() { + northPane = new TemplateResourceImagePanel(templateResource); + } + + private void createCenterPane() { + JLabel nameLabel = new JLabel(templateResource.getName()); + nameLabel.setFont(RESOURCE_NAME_FONT); + nameLabel.setForeground(RESOURCE_NAME_COLOR); + nameLabel.setBackground(Color.WHITE); + nameLabel.setBorder(BorderFactory.createEmptyBorder()); + + JLabel demoLabel = new JLabel(); + if (templateResource.hasDemoUrl()) { + demoLabel.setText(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Demo")); + demoLabel.setForeground(DEMO_LABEL_FOREGROUND); + demoLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + try { + BrowseUtils.browser(templateResource.getDemoUrl()); + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex, ex.getMessage()); + } + } + }); + } + + centerPane = new JPanel(new BorderLayout()); + centerPane.setBackground(Color.WHITE); + centerPane.add(nameLabel, BorderLayout.WEST); + centerPane.add(demoLabel, BorderLayout.EAST); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(180, 90); + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketConstants.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketConstants.java new file mode 100644 index 000000000..d5a45ad63 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketConstants.java @@ -0,0 +1,19 @@ +package com.fr.design.mainframe.alphafine.download; + + +/** + * + * alphafine - 帆软市场常量 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class FineMarketConstants { + + public static final String REPORTLETS = "/reportlets"; + public static final String ZIP = ".zip"; + public static final String RAR = ".rar"; + public static final String CPT = ".cpt"; + public static final String FRM = ".frm"; +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketDownloadManager.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketDownloadManager.java new file mode 100644 index 000000000..6ec224d0e --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketDownloadManager.java @@ -0,0 +1,159 @@ +package com.fr.design.mainframe.alphafine.download; + +import com.fr.base.svg.IconUtils; +import com.fr.common.util.Strings; +import com.fr.design.DesignerEnvManager; +import com.fr.design.extra.Process; +import com.fr.design.i18n.Toolkit; +import com.fr.design.login.DesignerLoginHelper; +import com.fr.design.login.DesignerLoginSource; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.mainframe.alphafine.search.helper.FineMarketClientHelper; +import com.fr.design.mainframe.toast.SimpleToast; +import com.fr.log.FineLoggerFactory; +import com.fr.third.jodd.io.ZipUtil; + +import javax.swing.SwingUtilities; +import javax.swing.filechooser.FileSystemView; +import java.awt.Window; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + + +/** + * 在这里统一管理帆软市场的下载 + * 下载的流程控制尽量都在这个类内部完成 + * 通过Process类来实现下载流程控制 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class FineMarketDownloadManager { + + private static final FineMarketDownloadManager INSTANCE = new FineMarketDownloadManager(); + public static final FineMarketDownloadManager getInstance() { + return INSTANCE; + } + + + public static final double PROCESS_SUCCESS = 1d; + public static final double PROCESS_FAILED = -1d; + public static final double OPENING_FILE = 2d; + + private static final String OPENING_PLEASE_WAIT = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Opening"); + private static final String DOWNLOAD_FAILED = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Download_Failed_Check_Network"); + + + /** + * 下载资源并解压 + * */ + public String installResource(TemplateResource resource, Window parentWindow){ + // 验证登录 + String token = DesignerEnvManager.getEnvManager().getDesignerLoginRefreshToken(); + if (Strings.isEmpty(token)) { + DesignerLoginHelper.showLoginDialog(DesignerLoginSource.NORMAL, new HashMap<>(), AlphaFineHelper.getAlphaFineDialog()); + return null; + } + return install(resource, parentWindow); + } + + private String install(TemplateResource resource, Window parentWindow) { + // 默认下载到桌面 + String workDir = FileSystemView.getFileSystemView().getHomeDirectory().getPath(); + File destDir = new File(workDir); + + DownloadProcess downloadProcess = new DownloadProcess(parentWindow); + String fileName = null; + try { + fileName = FineMarketClientHelper.getInstance().download(resource, destDir, downloadProcess); + unzip(fileName, downloadProcess); + return fileName; + } catch (Exception e) { + downloadProcess.process(FineMarketDownloadManager.PROCESS_FAILED); + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return null; + } + + void unzip(String fileName, DownloadProcess process) throws IOException { + process.process(OPENING_FILE); + + if (fileName.endsWith(FineMarketConstants.ZIP)) { + File file = new File(fileName); + File parentDir = file.getParentFile(); + ZipUtil.unzip(file, parentDir); + } + } + + + + + /** + * 下载流程控制,主要控制ui的显示 + * */ + class DownloadProcess implements Process { + + SimpleToast downloadingToast; + SimpleToast openingToast; + SimpleToast failedToast; + Window parent; + + public DownloadProcess(Window parentWindow) { + this.parent = parentWindow; + init(); + } + + void init() { + showLoadingToast(); + } + + @Override + public void process(Double aDouble) { + SwingUtilities.invokeLater(()->{ + if (aDouble == PROCESS_FAILED) { + downloadFailed(); + } else if (aDouble == PROCESS_SUCCESS) { + downloadSuccess(); + } else if (aDouble == OPENING_FILE) { + openingFile(); + } + }); + } + + /** + * 下载失败 + */ + public void downloadFailed() { + downloadingToast.setVisible(false); + showFailedToast(); + } + + /** + * 下载成功 + */ + public void downloadSuccess() { + downloadingToast.setVisible(false); + } + + + private void openingFile() { + downloadingToast.setVisible(false); + openingToast = new SimpleToast(AlphaFineHelper.getAlphaFineDialog(), IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/loading.svg"), OPENING_PLEASE_WAIT, true); + openingToast.setVisible(true); + } + + private void showLoadingToast() { + downloadingToast = new SimpleToast(AlphaFineHelper.getAlphaFineDialog(), IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/loading.svg"), OPENING_PLEASE_WAIT, false); + downloadingToast.setVisible(true); + } + + private void showFailedToast() { + failedToast = new SimpleToast(AlphaFineHelper.getAlphaFineDialog(), IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/caution.svg"), DOWNLOAD_FAILED, true); + failedToast.setVisible(true); + } + + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/ProductNews.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/ProductNews.java index aea152da2..1673f3bb8 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/ProductNews.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/ProductNews.java @@ -1,8 +1,12 @@ package com.fr.design.mainframe.alphafine.model; import com.fr.design.i18n.Toolkit; + import java.awt.Image; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; +import java.util.List; /** * 产品动态 @@ -17,7 +21,9 @@ public class ProductNews { private String title; private Tag tag; - private Target target; + + // 推送对象,对象为 list<用户组id> + private List target; private Status status; private String url; @@ -26,6 +32,8 @@ public class ProductNews { private Date pushDate; + public static final String ALL_USER_TARGET = "0"; + /** * 创建cid的用户 */ @@ -58,11 +66,11 @@ public class ProductNews { return this; } - public Target getTarget() { + public List getTarget() { return target; } - public ProductNews setTarget(Target target) { + public ProductNews setTarget(List target) { this.target = target; return this; } @@ -172,29 +180,18 @@ public class ProductNews { } } - public enum Target { - ALL_USER(0); - - private final int code; - - Target(int code) { - this.code = code; - } - - public int getCode() { - return code; - } - - public static Target parseCode(int code) { - for (Target target : values()) { - if (target.code == code) { - return target; - } - } - throw new IllegalArgumentException(); + /** + * 将接口中的target字段转换一下 + * 原始数据是字符串,例如:"1,2,3,4" + * 转换为 List{1,2,3,4} + * */ + public static List ParseTarget(String s) { + List list = new ArrayList<>(); + if (s != null) { + String[] targets = s.split(","); + list.addAll(Arrays.asList(targets)); } - + return list; } - } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java new file mode 100644 index 000000000..d81d7b280 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java @@ -0,0 +1,238 @@ +package com.fr.design.mainframe.alphafine.model; + +import com.fr.common.util.Strings; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.alphafine.download.FineMarketConstants; +import com.fr.design.mainframe.alphafine.search.manager.impl.TemplateResourceSearchManager; +import com.fr.general.IOUtils; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.third.jodd.util.StringUtil; + +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; + + +/** + * + * alphafine - 模板资源数据 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResource { + + /*** + * 模板资源类型:模板,解决方案,推荐搜索 + */ + public enum Type { + // 单个模板 + SINGLE_TEMPLATE(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Single_Template")), + // 场景解决方案 + SCENARIO_SOLUTION(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Scenario_Solution")), + // 推荐搜索 + RECOMMEND_SEARCH; + + private String name; + + Type() { + } + + Type(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + // 模板资源搜索接口返回值字段名 + public static final String ID = "id"; + public static final String UUID = "uuid"; + public static final String NAME = "name"; + public static final String IMAGE_URL = "pic"; + public static final String DEMO_URL = "demoUrl"; + public static final String PKG_SIZE = "pkgsize"; + public static final String FILE_NAME = "fileLoca"; + private static final String RECOMMEND_SEARCH_IMG_URL = "com/fr/design/mainframe/alphafine/images/more.png"; + + + // 模板资源属性 + private String id; + private String uuid; + private Type type; + private String imageUrl; + private Image image; + private String name; + private String demoUrl; + private String fileName; + private int pkgSize; + private List recommendSearchKey; + private boolean embed; + + /** + * json转obj + * */ + public static List createByJson(JSONArray jsonArray) { + List list = new ArrayList<>(); + if (jsonArray != null) { + for (int i = jsonArray.length() - 1; i >= 0; i--) { + list.add(createByJson(jsonArray.getJSONObject(i))); + } + } + return list; + } + + /** + * json转obj + * */ + public static TemplateResource createByJson(JSONObject jsonObject) { + + TemplateResource templateResource = new TemplateResource().setId(jsonObject.getString(ID)).setUuid(jsonObject.getString(UUID)).setName(jsonObject.getString(NAME)) + .setDemoUrl(jsonObject.getString(DEMO_URL)).setPkgSize(jsonObject.getInt(PKG_SIZE)).setFileName(jsonObject.getString(FILE_NAME)); + int pkgSize = templateResource.getPkgSize(); + if (pkgSize == 0) { + templateResource.type = Type.SINGLE_TEMPLATE; + } else { + templateResource.type = Type.SCENARIO_SOLUTION; + } + + templateResource.setImageUrl(parseUrl(jsonObject)); + + templateResource.setImage(IOUtils.readImage(templateResource.imageUrl)); + return templateResource; + } + + /** + * 商城接口传过来的图片url是特殊格式,需要特殊处理下 + * */ + static String parseUrl(JSONObject jsonObject) { + String imgUrl = jsonObject.getString(IMAGE_URL); + int index = imgUrl.indexOf(","); + if (index != -1) { + imgUrl = imgUrl.substring(0, imgUrl.indexOf(",")); + } + return imgUrl; + } + + public static TemplateResource getRecommendSearch() { + TemplateResource recommend = new TemplateResource(); + recommend.setType(Type.RECOMMEND_SEARCH); + recommend.setImageUrl(RECOMMEND_SEARCH_IMG_URL); + recommend.setImage(IOUtils.readImage(RECOMMEND_SEARCH_IMG_URL)); + recommend.setRecommendSearchKey(TemplateResourceSearchManager.getInstance().getRecommendSearchKeys()); + return recommend; + } + + + + public String getFileName() { + return fileName; + } + + public TemplateResource setFileName(String fileName) { + if (Strings.isEmpty(fileName)) { + this.fileName = getName() + FineMarketConstants.ZIP; + } else { + this.fileName = fileName; + } + return this; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getRecommendSearchKey() { + return recommendSearchKey; + } + + public void setRecommendSearchKey(List recommendSearchKey) { + this.recommendSearchKey = recommendSearchKey; + } + + public TemplateResource setImage(Image image) { + this.image = image; + return this; + } + + public Image getImage() { + return image; + } + + public TemplateResource setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + return this; + } + + + /** + * 判断是否为内置模板资源 + * */ + public boolean isEmbed() { + return embed; + } + + public void setEmbed(boolean embed) { + this.embed = embed; + } + + public String getName() { + return name; + } + + public TemplateResource setName(String name) { + this.name = name; + return this; + } + + public String getDemoUrl() { + return demoUrl; + } + + /** + * 有无在线演示 + * */ + public boolean hasDemoUrl() { + return !StringUtil.isEmpty(demoUrl); + } + + public TemplateResource setDemoUrl(String demoUrl) { + this.demoUrl = demoUrl; + return this; + } + + public int getPkgSize() { + return pkgSize; + } + + public TemplateResource setPkgSize(int pkgSize) { + this.pkgSize = pkgSize; + return this; + } + + public String getId() { + return id; + } + + public TemplateResource setId(String id) { + this.id = id; + return this; + } + + public String getUuid() { + return uuid; + } + + public TemplateResource setUuid(String uuid) { + this.uuid = uuid; + return this; + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResourceDetail.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResourceDetail.java new file mode 100644 index 000000000..5ef5f8c83 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResourceDetail.java @@ -0,0 +1,251 @@ +package com.fr.design.mainframe.alphafine.model; + + +import com.fr.design.mainframe.alphafine.search.helper.FineMarketClientHelper; +import com.fr.design.mainframe.alphafine.search.manager.impl.TemplateResourceSearchManager; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * + * alphafine - 模板资源详细数据 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourceDetail { + + // 与对应的模板资源关联 + private final TemplateResource root; + private String info; + private String vendor; + private String htmlText; + private List detailInfo; + private String[] tagsId; + private List tagsName; + private double price; + private String parentPkgName = ""; + private String parentPkgUrl; + private String resourceUrl; + + public static final String ID = "id"; + public static final String INFO = "description"; + public static final String VENDOR = "vendor"; + public static final String DETAIL_INFO = "text"; + public static final String TAGS_ID = "cid"; + public static final String PRICE = "price"; + public static final String NAME = "name"; + public static final String PARENT_NAME = "parentName"; + public static final String PARENT_URL = "parentUrl"; + public static final String TAGS_NAME = "tagsName"; + public static final String URL = "url"; + + + + public TemplateResourceDetail(TemplateResource resource) { + this.root = resource; + } + + + public String getVendor() { + return vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public TemplateResource getRoot() { + return root; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } + + public List getDetailInfo() { + return detailInfo; + } + + public void setDetailInfo(List detailInfo) { + this.detailInfo = detailInfo; + } + + public String[] getTagsId() { + return tagsId; + } + + public void setTagsId(String[] tagsId) { + this.tagsId = tagsId; + } + + public List getTagsName() { + return tagsName; + } + + public String getTagsString() { + StringBuilder sb = new StringBuilder(); + if (tagsName != null) { + for (String tag : tagsName) { + sb.append(tag + " "); + } + } + return sb.toString(); + } + + public void setTagsName(List tagsName) { + this.tagsName = tagsName; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public String getParentPkgName() { + return parentPkgName; + } + + public void setParentPkgName(String parentPkgName) { + if (StringUtils.isEmpty(parentPkgName)) { + this.parentPkgName = ""; + } else { + this.parentPkgName = parentPkgName; + } + } + + public String getResourceUrl() { + return resourceUrl; + } + + public void setResourceUrl(String resourceUrl) { + this.resourceUrl = resourceUrl; + } + + public String getHtmlText() { + return htmlText; + } + + public void setHtmlText(String htmlText) { + this.htmlText = htmlText; + } + + public String getParentPkgUrl() { + return parentPkgUrl; + } + + public void setParentPkgUrl(String parentPkgUrl) { + this.parentPkgUrl = parentPkgUrl; + } + + /** + * 通过模板资源数据构建详细数据 + * */ + public static TemplateResourceDetail createByTemplateResource(TemplateResource root) { + return Builder.buildByResource(root); + } + + /** + * 通过内置模板资源数据构建详细数据 + * */ + public static TemplateResourceDetail createFromEmbedResource(TemplateResource root) { + return Builder.buildFromEmbedResource(root); + } + + static class Builder { + + static FineMarketClientHelper helper = FineMarketClientHelper.getInstance(); + + static TemplateResourceDetail buildFromEmbedResource(TemplateResource templateResource) { + TemplateResourceDetail detail = new TemplateResourceDetail(templateResource); + String resourceId = templateResource.getId(); + JSONArray embedResources = TemplateResourceSearchManager.getInstance().getEmbedResourceJSONArray(); + for (int i = 0; i < embedResources.length(); i++) { + JSONObject resource = embedResources.getJSONObject(i); + if (resourceId.equals(resource.getString(ID))) { + detail.setInfo(resource.getString(INFO)); + detail.setHtmlText(resource.getString(DETAIL_INFO)); + detail.setVendor(resource.getString(VENDOR)); + detail.setPrice(resource.getDouble(PRICE)); + detail.setResourceUrl(resource.getString(URL)); + detail.setParentPkgName(resource.getString(PARENT_NAME)); + detail.setParentPkgUrl(resource.getString(PARENT_URL)); + detail.setTagsName(Arrays.asList(resource.getString(TAGS_NAME).split(","))); + break; + } + } + return detail; + } + + static TemplateResourceDetail buildByResource(TemplateResource templateResource) { + TemplateResourceDetail detail = new TemplateResourceDetail(templateResource); + String resourceId = templateResource.getId(); + + // 获取模板详情页的信息一共需要三次请求 + try { + // 1请求详细信息 + JSONObject info = helper.getTemplateInfoById(resourceId); + detail.setInfo(info.getString(INFO)); + detail.setHtmlText(info.getString(DETAIL_INFO)); + detail.setVendor(info.getString(VENDOR)); + detail.setTagsId(info.getString(TAGS_ID).split(",")); + detail.setPrice(info.getDouble(PRICE)); + detail.setResourceUrl(helper.getTemplateUrlById(templateResource.getId())); + + // 2请求所属模板包信息 + JSONObject parentPkginfo = helper.getTemplateParentPackageByTemplateId(resourceId); + if (parentPkginfo != null) { + detail.setParentPkgName(parentPkginfo.getString(NAME)); + detail.setParentPkgUrl(FineMarketClientHelper.getInstance().getTemplateUrlById(parentPkginfo.getString(ID))); + } + + // 3请求标签信息 + detail.setTagsName(helper.getTemplateTagsByTemplateTagIds(detail.getTagsId())); + return detail; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + + return null; + } + + /** + * 这里做下数据转换 + * 原始数据是html标签写的,如下 + * "
  1. 该模板需用10.0及以上版本设计器预览

  2. 该模板为库存场景解决方案的部分内容,全部内容可下载库存场景解决方案查看

  3. 为保障模板预览效果,建议安装新自适应插件(FR11.0版本插件已内置,无需手动安装),有使用需求或疑问,请联系帆软技术支持咨询

", + * + * 转换的后的数据 是原始数据中所有

标签内的(包括标签)的字符串(List),如上字符串会转为如下 + * List [

该模板需用10.0及以上版本设计器预览

, + *

该模板为库存场景解决方案的部分内容,全部内容可下载库存场景解决方案查看

, + *

为保障模板预览效果,建议安装新自适应插件(FR11.0版本插件已内置,无需手动安装),有使用需求或疑问,请联系帆软技术支持咨询

+ * ] + * */ + static final Pattern HTML_PATTERN = Pattern.compile("

(.+?)

"); + static List parseDetailInfo(String htmlDetailInfo) { + List infos = new ArrayList<>(); + Matcher matcher = HTML_PATTERN.matcher(htmlDetailInfo); + while (matcher.find()) { + infos.add(matcher.group()); + } + return infos; + } + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/TemplateResourceDetailPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/TemplateResourceDetailPane.java new file mode 100644 index 000000000..48b684cf8 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/TemplateResourceDetailPane.java @@ -0,0 +1,241 @@ +package com.fr.design.mainframe.alphafine.preview; + +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.alphafine.AlphaFineConstants; +import com.fr.design.mainframe.alphafine.action.StartUseAction; +import com.fr.design.mainframe.alphafine.component.TemplateResourceImagePanel; +import com.fr.design.mainframe.alphafine.model.TemplateResourceDetail; +import com.fr.design.utils.BrowseUtils; +import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.LinkStrUtils; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * + * alphafine - 模板资源详情页 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourceDetailPane extends JPanel { + + + private TemplateResourceDetail data; + + private TemplateResourceImagePanel imagePane; + private JPanel contentPane; + private UIScrollPane infoScrollPane; + private JPanel operatePane; + private UIScrollPane detailInfoPane; + + + private static final int IMAGE_HEIGHT = 170; + private static final int IMAGE_WIDTH = 310; + private static final int SCROLL_PANE_WIDTH = 315; + private static final int SCROLL_PANE_HEIGHT = 135; + private static final int CONTENT_PANE_WIDTH = 320; + private static final int CONTENT_PANE_HEIGHT = 180; + private static final int DETAIL_PANE_HEIGHT = 95; + private static final int TEXT_SCROLL_PANE_HEIGHT = 500; + private static final int PANE_WIDTH = 635; + private static final int BUTTON_WIDTH = 68; + private static final int BUTTON_HEIGHT = 20; + + private static final String GOTO_DETAIL = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_GOTO_DETAIL"); + private static final String START_USE = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_START_USE"); + private static final String VENDOR = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_Vendor"); + private static final String TAGS = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_Tags"); + private static final String PARENT_PACKAGE = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_Parent_Package"); + private static final String DETAIL_INFO = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_Info"); + private static final String FREE = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Detail_Price_Free"); + private static final String SPACE = " "; + private static final String LF = "
"; + private static final String RMB = "¥"; + + + private static final Color INFO_PANE_BACKGROUND = new Color(0xf9f9f9); + private static final Color INFO_PANE_FOREGROUND = new Color(0x5b5b5c); + private static final Color MORE_INFO_LINK = new Color(0x419bf9); + + private static final Font HTML_FONT = DesignUtils.getDefaultGUIFont().applySize(12); + private static final Color HTML_COLOR = new Color(0x5c5c5d); + private static final String HTML_FORMAT = "%s"; + private static final String DETAIL_INFO_HTML_FORMAT = "

" + DETAIL_INFO + "

%s"; + private static final String HTML_P_TAG_FORMAT = "

%s

"; + + + + public TemplateResourceDetailPane(TemplateResourceDetail detail) { + this.data = detail; + initComponent(); + this.setLayout(new FlowLayout(FlowLayout.LEFT)); + this.setBorder(BorderFactory.createEmptyBorder(10, 20, 0, 20)); + this.add(imagePane); + this.add(contentPane); + this.add(detailInfoPane); + this.setBackground(Color.WHITE); + SwingUtilities.invokeLater(()->{scrollToTop();}); + } + + /** + * scrollPane创建后会拉到最底下,初始化的时候手动拉到顶 + */ + public void scrollToTop() { + infoScrollPane.getVerticalScrollBar().setValue(0); + detailInfoPane.getVerticalScrollBar().setValue(0); + } + + private void initComponent() { + createImagePane(); + createContentPane(); + createDetailInfoScrollPane(); + } + + private void createContentPane() { + createInfoScrollPane(); + createOperatePane(); + contentPane = new JPanel(); + contentPane.setLayout(new FlowLayout(FlowLayout.LEFT)); + contentPane.setPreferredSize(new Dimension(CONTENT_PANE_WIDTH, CONTENT_PANE_HEIGHT)); + contentPane.add(infoScrollPane); + contentPane.add(operatePane); + contentPane.setBackground(Color.WHITE); + } + + /** + * 操作区:查看详情,立即使用 + */ + private void createOperatePane() { + operatePane = new JPanel(new FlowLayout(FlowLayout.LEFT)); + + JLabel emptyLabel = new JLabel(); + emptyLabel.setPreferredSize(new Dimension(145, 25)); + JLabel priceLabel = new JLabel(); + priceLabel.setForeground(Color.RED); + if (data.getPrice() == 0) { + priceLabel.setText(FREE); + } else { + priceLabel.setText(RMB + SPACE + data.getPrice()); + } + + operatePane.add(createLinkLabel()); + operatePane.add(emptyLabel); + operatePane.add(priceLabel); + operatePane.add(createStartUseButton()); + operatePane.setBackground(Color.WHITE); + + } + + /** + * 查看详情 + */ + JLabel createLinkLabel() { + JLabel linkLabel = new JLabel(GOTO_DETAIL); + linkLabel.setBackground(Color.WHITE); + linkLabel.setForeground(MORE_INFO_LINK); + linkLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + openResourceUrl(data.getResourceUrl()); + } + }); + return linkLabel; + } + + /** + * 方便埋点 + */ + void openResourceUrl(String url) { + BrowseUtils.browser(url); + } + + + /** + * “立即使用” 按钮 + */ + JButton createStartUseButton() { + JButton starUseButton = new JButton(START_USE) { + @Override + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setColor(UIConstants.FLESH_BLUE); + g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 4, 4); + super.paintComponent(g2d); + } + }; + starUseButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + starUseButton.setForeground(Color.WHITE); + starUseButton.setFont(AlphaFineConstants.MEDIUM_FONT); + starUseButton.addActionListener(new StartUseAction(data)); + starUseButton.setPreferredSize(new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT)); + starUseButton.setContentAreaFilled(false); + return starUseButton; + } + + private void createImagePane() { + imagePane = new TemplateResourceImagePanel(data.getRoot(), IMAGE_WIDTH, IMAGE_HEIGHT); + } + + /** + * 基本信息页 + */ + private void createInfoScrollPane() { + + StringBuilder sb = new StringBuilder(); + + // 开发者 + sb.append(String.format(HTML_P_TAG_FORMAT, VENDOR + data.getVendor())); + // 标签 + sb.append(String.format(HTML_P_TAG_FORMAT, TAGS + data.getTagsString())); + // 所属模板包 + if (!StringUtils.isEmpty(data.getParentPkgName())) { + sb.append(String.format(HTML_P_TAG_FORMAT, PARENT_PACKAGE + LinkStrUtils.generateLinkTagWithoutUnderLine(data.getParentPkgUrl(), data.getParentPkgName()))); + } + // 信息 + sb.append(String.format(HTML_P_TAG_FORMAT, data.getInfo())); + + + MessageWithLink content = new MessageWithLink(String.format(HTML_FORMAT, sb)); + content.setBackground(INFO_PANE_BACKGROUND); + content.setForeground(INFO_PANE_FOREGROUND); + infoScrollPane = new UIScrollPane(content); + infoScrollPane.setForeground(INFO_PANE_FOREGROUND); + infoScrollPane.setPreferredSize(new Dimension(SCROLL_PANE_WIDTH, SCROLL_PANE_HEIGHT)); + infoScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + } + + /** + * 详细信息页 + */ + private void createDetailInfoScrollPane() { + MessageWithLink content = new MessageWithLink(String.format(DETAIL_INFO_HTML_FORMAT, data.getHtmlText())); + detailInfoPane = new UIScrollPane(content); + detailInfoPane.setPreferredSize(new Dimension(PANE_WIDTH, DETAIL_PANE_HEIGHT)); + detailInfoPane.setBackground(Color.WHITE); + detailInfoPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + } + + + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/TemplateShopPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/TemplateShopPane.java new file mode 100644 index 000000000..a1dbebd96 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/TemplateShopPane.java @@ -0,0 +1,212 @@ +package com.fr.design.mainframe.alphafine.preview; + +import com.fr.common.util.Strings; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.mainframe.alphafine.AlphaFineConstants; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.component.TemplateResourcePageGridPane; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.mainframe.alphafine.model.TemplateResourceDetail; +import com.fr.design.mainframe.alphafine.search.manager.impl.TemplateResourceSearchManager; +import com.fr.log.FineLoggerFactory; +import org.jooq.tools.StringUtils; + + +import javax.swing.JPanel; +import javax.swing.SwingWorker; +import java.awt.CardLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + + +/** + * + * alphafine - 模板商城面板 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateShopPane extends JPanel { + + private static final TemplateShopPane INSTANCE = new TemplateShopPane(); + public static TemplateShopPane getInstance() { + return INSTANCE; + } + + // public 方便埋点 + public static final String DEFAULT_PAGE_PANEL = "defaultPagePane"; + public static final String PAGE_PANEL = "pagePane"; + public static final String DETAIL_PANEL = "detailPane"; + public static final String LOADING_PANEL = "loadingPane"; + public static final String FAILED_PANEL = "failedPane"; + private String currentCard = StringUtils.EMPTY; + private static final String SLASH = "/"; + + private CardLayout cardLayout = new CardLayout(); + private JPanel defaultPagePane; + private JPanel pagePane; + private JPanel detailPane; + private JPanel loadingPane; + private JPanel failedPane; + + private TemplateShopPane() { + setLayout(cardLayout); + initComponents(); + this.add(defaultPagePane, DEFAULT_PAGE_PANEL); + this.add(loadingPane, LOADING_PANEL); + this.setPreferredSize(AlphaFineConstants.PREVIEW_SIZE); + switchCard(DEFAULT_PAGE_PANEL); + } + + private void switchCard(String flag) { + cardLayout.show(this, flag); + currentCard = flag; + } + + private void initComponents() { + defaultPagePane = createDefaultResourcePane(); + loadingPane = createLoadingPane(); + } + + /** + * 刷新 + * */ + public void refreshPagePane(List resourceList) { + pagePane = createContentPane(resourceList); + this.add(pagePane, PAGE_PANEL); + switchCard(PAGE_PANEL); + } + + /** + * 退出搜索结果面板 + * */ + public void quitSearchResultPane() { + if (StringUtils.equals(currentCard,PAGE_PANEL)) { + switchCard(DEFAULT_PAGE_PANEL); + } + } + + /** + * 显示结果 + * */ + public void showResult() { + if (Strings.isEmpty(AlphaFineHelper.getAlphaFineDialog().getSearchText())) { + switchCard(DEFAULT_PAGE_PANEL); + } else { + switchCard(PAGE_PANEL); + } + } + + + /** + * 打开二级页面,显示详细信息 + * */ + public void searchAndShowDetailPane(TemplateResource resource) { + + changeLabel(resource.getName()); + + switchCard(LOADING_PANEL); + + new SwingWorker() { + @Override + protected TemplateResourceDetail doInBackground(){ + // 搜搜 + TemplateResourceDetail detail = TemplateResourceSearchManager.getInstance().getDetailSearchResult(resource); + return detail; + } + + @Override + protected void done() { + TemplateResourceDetail detail = null; + try { + detail = get(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + + if (detail == null) { + setRetryAction(resource); + switchCard(FAILED_PANEL); + } else { + // detailpane初始化 + detailPane = new TemplateResourceDetailPane(detail); + // 切换 + INSTANCE.add(detailPane, DETAIL_PANEL); + switchCard(DETAIL_PANEL); + } + } + + + }.execute(); + + } + + + + private void changeLabel(String resourceName) { + JPanel labelNamePane = AlphaFineHelper.getAlphaFineDialog().getLabelWestPane(); + UILabel tabLabel = AlphaFineHelper.getAlphaFineDialog().getTabLabel(); + tabLabel.setForeground(AlphaFineConstants.DARK_GRAY); + + UILabel slash = new UILabel(SLASH); + slash.setForeground(AlphaFineConstants.DARK_GRAY); + + UILabel resourceLabel = new UILabel(resourceName); + resourceLabel.setForeground(AlphaFineConstants.LABEL_SELECTED); + + + labelNamePane.removeAll(); + labelNamePane.add(tabLabel); + labelNamePane.add(slash); + labelNamePane.add(resourceLabel); + + + tabLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + switchCard(PAGE_PANEL); + tabLabel.setForeground(AlphaFineConstants.LABEL_SELECTED); + labelNamePane.remove(slash); + labelNamePane.remove(resourceLabel); + } + }); + } + + /** + * 方便埋点,勿删 + * */ + public String getCurrentCard() { + return currentCard; + } + + private JPanel createContentPane(List templateResources) { + return new TemplateResourcePageGridPane(templateResources); + } + + private JPanel createDefaultResourcePane() { + return createContentPane(TemplateResourceSearchManager.getInstance().getDefaultResourceList()); + } + + + private JPanel createLoadingPane() { + return new SearchLoadingPane(); + } + + private void setRetryAction(TemplateResource resource) { + if (failedPane != null) { + INSTANCE.remove(failedPane); + } + failedPane = createFailedPane(resource); + INSTANCE.add(failedPane, FAILED_PANEL); + } + + private JPanel createFailedPane(TemplateResource resource) { + return new NetWorkFailedPane(()->{this.searchAndShowDetailPane(resource);}); + } + + + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/TemplateResourceSearchWorkerManager.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/TemplateResourceSearchWorkerManager.java new file mode 100644 index 000000000..f99d22a5f --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/TemplateResourceSearchWorkerManager.java @@ -0,0 +1,116 @@ +package com.fr.design.mainframe.alphafine.search; + +import com.fr.design.mainframe.alphafine.AlphaFineConstants; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.CellType; +import com.fr.design.mainframe.alphafine.component.AlphaFineFrame; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.mainframe.alphafine.preview.TemplateShopPane; +import com.fr.log.FineLoggerFactory; + +import javax.swing.SwingWorker; +import java.util.List; +import java.util.function.Function; + +/** + * + * alphafine - 模板资源搜索管理 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourceSearchWorkerManager implements SearchManager { + + private final CellType cellType; + + private SwingWorker, Void> searchWorker; + + private Function> searchFunction; + + private AlphaFineFrame alphaFineFrame; + + private volatile boolean searchResult = true; + + private volatile boolean searchOver = false; + + private volatile boolean networkError = false; + + public TemplateResourceSearchWorkerManager(CellType cellType, Function> searchFunction, AlphaFineFrame alphaFineFrame) { + this.cellType = cellType; + this.searchFunction = searchFunction; + this.alphaFineFrame = alphaFineFrame; + } + + @Override + public void doSearch(SearchTextBean searchTextBean) { + checkSearchWork(); + searchOver = false; + + this.searchWorker = new SwingWorker, Void>() { + @Override + protected List doInBackground() { + List list; + if (!AlphaFineHelper.isNetworkOk()) { + networkError = true; + FineLoggerFactory.getLogger().warn("alphaFine network error"); + } + list = searchFunction.apply(searchTextBean); + return list; + } + + @Override + protected void done() { + searchOver = true; + if (!isCancelled()) { + try { + List list = get(); + searchResult = !list.isEmpty(); + showResult(list); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + }; + this.searchWorker.execute(); + } + + void showResult(List list) { + if (networkError && !searchResult) { + alphaFineFrame.showResult(AlphaFineConstants.NETWORK_ERROR); + return; + } + + if (alphaFineFrame.getSelectedType() == cellType) { + if (!searchResult) { + alphaFineFrame.showResult(CellType.NO_RESULT.getFlagStr4None()); + } else { + TemplateShopPane.getInstance().refreshPagePane(list); + AlphaFineHelper.getAlphaFineDialog().showResult(cellType.getFlagStr4None()); + } + } + } + + @Override + public boolean hasSearchResult() { + return searchResult; + } + + @Override + public boolean isSearchOver() { + return searchOver; + } + + private void checkSearchWork() { + if (this.searchWorker != null && !this.searchWorker.isDone()) { + this.searchWorker.cancel(true); + this.searchWorker = null; + } + } + + @Override + public boolean isNetWorkError() { + return networkError; + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java new file mode 100644 index 000000000..9aff9f92b --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java @@ -0,0 +1,358 @@ +package com.fr.design.mainframe.alphafine.search.helper; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.extra.PluginConstants; +import com.fr.design.mainframe.alphafine.download.FineMarketDownloadManager; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.file.FileCommonUtils; +import com.fr.general.CloudCenter; +import com.fr.general.http.HttpToolbox; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.market.key.FineMarketPublicKeyHolder; +import com.fr.security.SecurityToolbox; +import com.fr.stable.StableUtils; +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.HttpException; +import com.fr.third.org.apache.http.HttpStatus; +import com.fr.third.org.apache.http.client.config.CookieSpecs; +import com.fr.third.org.apache.http.client.config.RequestConfig; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; +import com.fr.third.org.apache.http.client.methods.HttpUriRequest; +import com.fr.third.org.apache.http.client.methods.RequestBuilder; +import com.fr.third.org.apache.http.impl.client.BasicCookieStore; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.third.org.apache.http.impl.client.HttpClients; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * alphafine - 帆软市场助手 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class FineMarketClientHelper { + private static final FineMarketClientHelper INSTANCE = new FineMarketClientHelper(); + public static FineMarketClientHelper getInstance() { + return INSTANCE; + } + + private static final String CERTIFICATE_PUBLIC_KEY = FineMarketPublicKeyHolder.getInstance().getDefaultKey(); + public static final String FINE_MARKET_TEMPLATE_INFO = CloudCenter.getInstance().acquireUrlByKind("market.template.info"); + public static final String FINE_MARKET_TEMPLATE_URL = CloudCenter.getInstance().acquireUrlByKind("market.template.url"); + public static final String FILE_DOWNLOAD = "file/download/"; + public static final String PACKAGE_DOWNLOAD = "package/download/"; + public static final String TEMPLATES_PARENT_PACKAGE = "parent/"; + public static final String TEMPLATES_TAGS = "filter"; + public static final String NAME_SEARCH = "?searchKeyword="; + + public static final String RESPONSE_STATE = "state"; + public static final String RESPONSE_SUCCESS = "ok"; + public static final String RESPONSE_RESULT = "result"; + public static final String TAGS_KEY = "key"; + public static final String TAGS_ITEMS = "items"; + public static final String TAG_NAME = "name"; + public static final String TAG_ID = "id"; + private static final String FILENAME_FORMAT = ".+?(.zip|.rar|.cpt|.frm)"; + private static final Pattern FILENAME_PATTERN = Pattern.compile(FILENAME_FORMAT); + + // 缓存下所有tag标签 + private Map tags; + + + /** + * 获取模板资源的下载链接 + * */ + public String getResourceDownloadUrl(TemplateResource templateResource) { + if (TemplateResource.Type.SCENARIO_SOLUTION.equals(templateResource.getType())) { + return getPackageDownloadUrl(); + } else { + return getFileDownLoadUrl(); + } + + } + + private String getPackageDownloadUrl() { + return FINE_MARKET_TEMPLATE_INFO + PACKAGE_DOWNLOAD; + } + + private String getFileDownLoadUrl() { + return FINE_MARKET_TEMPLATE_INFO + FILE_DOWNLOAD; + } + + + /** + * 下载 + * */ + public String download(TemplateResource resource, File destDir, com.fr.design.extra.Process process) throws Exception { + String resourceId = resource.getId(); + + CloseableHttpResponse fileRes = getFileResponse(resource, resourceId); + + if (fileRes.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + + File destFile = createDestFile(destDir, resource); + + StableUtils.makesureFileExist(destFile); + + InputStream content = null; + FileOutputStream writer = null; + try { + writer = new FileOutputStream(FileCommonUtils.getAbsolutePath(destFile)); + + HttpEntity entity = fileRes.getEntity(); + long totalSize = entity.getContentLength(); + content = entity.getContent(); + + + byte[] data = new byte[PluginConstants.BYTES_NUM]; + int bytesRead; + int totalBytesRead = 0; + + while ((bytesRead = content.read(data)) > 0) { + writer.write(data, 0, bytesRead); + data = new byte[PluginConstants.BYTES_NUM]; + totalBytesRead += bytesRead; + process.process(totalBytesRead / (double) totalSize); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } finally { + content.close(); + writer.flush(); + writer.close(); + } + + + FineLoggerFactory.getLogger().info("download resource{} success", resourceId); + process.process(FineMarketDownloadManager.PROCESS_SUCCESS); + + return FileCommonUtils.getAbsolutePath(destFile); + } else { + FineLoggerFactory.getLogger().info("download resource{} failed", resourceId); + process.process(FineMarketDownloadManager.PROCESS_FAILED); + throw new HttpException(); + } + + } + + + private CloseableHttpResponse getFileResponse(TemplateResource resource, String resourceId) throws Exception { + CloseableHttpResponse fileRes = postDownloadHttpResponse(getResourceDownloadUrl(resource), resourceId); + if (fileRes.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) { + fileRes = getDownloadHttpResponse(fileRes.getHeaders("Location")[0].getValue()); + } + return fileRes; + } + + /** + * 在目标路径下(destDir)创建与资源名称相同的文件夹 (finalDir) + * 将资源下载到 destDir/finalDir + * 如果文件重复,则在文件名前加自增id + * */ + private File createDestFile(File destDir, TemplateResource resource) { + String fileName = resource.getName(); + File finalDir = new File(StableUtils.pathJoin(FileCommonUtils.getAbsolutePath(destDir), fileName)); + try { + if (!finalDir.exists()) { + finalDir.mkdir(); + } + + fileName = resource.getFileName(); + fileName = rename(fileName, finalDir); + + File destFile = new File(StableUtils.pathJoin(FileCommonUtils.getAbsolutePath(finalDir), fileName)); + return destFile; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + fileName = UUID.randomUUID() + fileName; + File dest = new File(StableUtils.pathJoin(FileCommonUtils.getAbsolutePath(finalDir), fileName)); + return dest; + } + + /** + * 处理下文件名,比如重复下载需要处理重名的情况 + * */ + String rename(String fileName, File parentDir) throws Exception { + + if (!FILENAME_PATTERN.matcher(fileName).matches()) { + throw new Exception("fileName format error: " + fileName); + } + + // 获取文件名(含后缀) + String prefix = fileName.substring(0, fileName.length() - 4); + String suffix = fileName.substring(fileName.length() - 4); + + + File file = new File(StableUtils.pathJoin(FileCommonUtils.getAbsolutePath(parentDir), fileName)); + // 处理重复文件名 + if (file.exists()) { + String fileNameFormat = prefix + "(%d)" + suffix; + Pattern pattern = Pattern.compile(prefix + "\\((\\d)\\)" + suffix); + int cnt = 0; + + File[] files = parentDir.listFiles(); + for (File f : files) { + Matcher matcher = pattern.matcher(f.getName()); + if (matcher.find()) { + cnt = Math.max(cnt, Integer.parseInt(matcher.group(1))); + } + } + cnt++; + fileName = String.format(fileNameFormat, cnt); + } + return fileName; + + } + + private static CloseableHttpResponse getDownloadHttpResponse(String url) throws Exception { + //先登录一下。不然可能失败 + CloseableHttpClient client = createClient(); + HttpUriRequest file = RequestBuilder.get() + .setUri(url) + .build(); + return client.execute(file); + } + + private static CloseableHttpResponse postDownloadHttpResponse(String url, String id) throws Exception { + return postDownloadHttpResponse(url, id, new HashMap<>()); + } + + private static CloseableHttpResponse postDownloadHttpResponse(String url, String id, Map params) throws Exception { + //先登录一下。不然可能失败 + CloseableHttpClient client = createClient(); + FineLoggerFactory.getLogger().info("login fr-market"); + FineLoggerFactory.getLogger().info("start download resource {}", id); + RequestBuilder builder = RequestBuilder.post() + .setHeader("User-Agent", "Mozilla/5.0") + .setUri(url) + .addParameter("id", SecurityToolbox.encrypt(id, CERTIFICATE_PUBLIC_KEY)) + .addParameter("userId", String.valueOf(DesignerEnvManager.getEnvManager().getDesignerLoginUid())); + + if (params != null) { + Set keys = params.keySet(); + for (String key: keys) { + builder.addParameter(key, params.get(key)); + } + } + return client.execute(builder.build()); + } + + + private static CloseableHttpClient createClient() { + + BasicCookieStore cookieStore = new BasicCookieStore(); + return HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom() + .setCookieSpec(CookieSpecs.STANDARD).build()) + .setDefaultCookieStore(cookieStore) + .build(); + } + + public @Nullable JSONObject getTemplateInfoById(String id) throws IOException { + String url = FINE_MARKET_TEMPLATE_INFO + id; + String jsonString = HttpToolbox.get(url); + JSONObject jsonObject = new JSONObject(jsonString); + String responseState = (String) jsonObject.get(RESPONSE_STATE); + if (RESPONSE_SUCCESS.equals(responseState)) { + return jsonObject.getJSONObject(RESPONSE_RESULT); + } else { + return null; + } + } + + public @Nullable JSONArray getTemplateInfoByName(String name) throws IOException { + String url = FINE_MARKET_TEMPLATE_INFO + NAME_SEARCH + name; + String jsonString = HttpToolbox.get(url); + JSONObject jsonObject = new JSONObject(jsonString); + String responseState = (String) jsonObject.get(RESPONSE_STATE); + if (RESPONSE_SUCCESS.equals(responseState)) { + return jsonObject.getJSONArray(RESPONSE_RESULT); + } + return null; + } + + public String getTemplateUrlById(String id) { + return FINE_MARKET_TEMPLATE_URL + id; + } + + public @Nullable JSONObject getTemplateParentPackageByTemplateId(String id) throws IOException { + String url = FINE_MARKET_TEMPLATE_INFO + TEMPLATES_PARENT_PACKAGE + id; + String jsonString = HttpToolbox.get(url); + JSONObject jsonObject = new JSONObject(jsonString); + String responseState = (String) jsonObject.get(RESPONSE_STATE); + if (RESPONSE_SUCCESS.equals(responseState)) { + JSONArray jsonArray = jsonObject.getJSONArray(RESPONSE_RESULT); + if (!jsonArray.isEmpty()) { + return jsonObject.getJSONArray(RESPONSE_RESULT).getJSONObject(0); + } + } + return null; + + } + + + /** + * 根据模板资源的tagid,获取tagName + * */ + public List getTemplateTagsByTemplateTagIds(String[] tagIds) throws IOException { + List list = new ArrayList<>(); + + initTags(); + + if (tagIds != null) { + for (String tagId : tagIds) { + String tagName = tags.get(tagId); + if (tagName != null) { + list.add(tagName); + } + } + } + + return list; + } + + /** + * 请求帆软市场,获取所有tag信息,并构建tagid - tagname的map + * */ + private void initTags() throws IOException { + tags = new HashMap<>(); + String url = FINE_MARKET_TEMPLATE_INFO + TEMPLATES_TAGS; + String jsonString = HttpToolbox.get(url); + JSONObject jsonObject = new JSONObject(jsonString); + String responseState = (String) jsonObject.get(RESPONSE_STATE); + if (RESPONSE_SUCCESS.equals(responseState)) { + JSONArray resultArray = jsonObject.getJSONArray(RESPONSE_RESULT); + for (int i = 1; i < resultArray.size(); i++) { + JSONObject result = resultArray.getJSONObject(i); + String key = result.getString(TAGS_KEY); + key = key.substring(key.indexOf('@') + 1); + JSONArray items = result.getJSONArray(TAGS_ITEMS); + for (int j = 0; j < items.length(); j++) { + JSONObject item = items.getJSONObject(j); + String id = item.getString(TAG_ID); + String name = item.getString(TAG_NAME); + tags.put(key + '-' + id, name); + } + } + } + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/ProductNewsSearchManager.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/ProductNewsSearchManager.java index 463eeb4ae..97b705fc1 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/ProductNewsSearchManager.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/ProductNewsSearchManager.java @@ -1,6 +1,7 @@ package com.fr.design.mainframe.alphafine.search.manager.impl; import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.DesignerEnvManager; import com.fr.design.mainframe.alphafine.AlphaFineConstants; import com.fr.design.mainframe.alphafine.AlphaFineHelper; import com.fr.design.mainframe.alphafine.model.ProductNews; @@ -14,6 +15,7 @@ import java.awt.Image; import java.net.URL; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -90,7 +92,7 @@ public class ProductNewsSearchManager { setImage(getCoverImage(obj.getString("pic"))). setUrl(obj.getString("url")).setTag(ProductNews.Tag.parseCode(obj.getInt("tag"))). setStatus(ProductNews.Status.parseCode(obj.getInt("status"))).setTarget( - ProductNews.Target.parseCode(obj.getInt("target"))). + ProductNews.ParseTarget(obj.getString("target"))). setCreator(obj.getInt("creator")).setPushDate(new Date(obj.getLong("push_time"))); Date currentDate = new Date(System.currentTimeMillis()); // 推送时间check @@ -99,9 +101,69 @@ public class ProductNewsSearchManager { idSet.add(productNews.getId()); } } + + productNewsList = filterByDesignerId(productNewsList); + return productNewsList; } + + /** + * 将productNews根据设计器id进行过滤 + * productNews有个target字段,代表推送对象用户组,检查设计器id是否在用户组中来进行过滤 + * */ + private List filterByDesignerId(List list) { + //设计器id + String designId = DesignerEnvManager.getEnvManager().getUUID(); + + HashMap> userGroupInfoCache = new HashMap<>(); + //遍历资源,获取target下的所有用户组信息,检查是否包含设计器id + List newsList = new ArrayList<>(); + for (ProductNews productNews : list) { + List targets = productNews.getTarget(); + + boolean targetsContainDesignerId = false; + + // 每条推送可能推送至多个用户组,需要逐一判断 + for (String userGroupId : targets) { + // 没有记录的用户组信息需要请求一下 + if (!userGroupInfoCache.containsKey(userGroupId)) { + userGroupInfoCache.put(userGroupId, searchUserGroupInfo(userGroupId)); + } + + // 判断设计器id是否在这个用户组中,在则退出判断,不在则继续 + if (userGroupInfoCache.get(userGroupId).contains(designId) || userGroupId.equals(ProductNews.ALL_USER_TARGET)) { + targetsContainDesignerId = true; + break; + } + } + + if (targetsContainDesignerId) { + newsList.add(productNews); + } + } + return newsList; + } + + /** + * 根据用户组id,查询用户组信息(改用户组中的所有设计器id) + * */ + private Set searchUserGroupInfo(String userGroupId) { + String url = AlphaFineConstants.ALPHA_CID_USER_GROUP_INFO + AlphaFineConstants.SEARCH_BY_ID + userGroupId; + Set idSet = new HashSet<>(); + try { + String jsonStr = HttpToolbox.get(url); + JSONObject jsonObject = new JSONObject(jsonStr); + JSONArray idArray = jsonObject.getJSONArray("data"); + for (int i = 0; i < idArray.length(); i++) { + idSet.add(idArray.getJSONObject(i).getString("userid")); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return idSet; + } + public List getCachedProductNewsList() { return productNewsList; } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/TemplateResourceSearchManager.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/TemplateResourceSearchManager.java new file mode 100644 index 000000000..60f846759 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/TemplateResourceSearchManager.java @@ -0,0 +1,111 @@ +package com.fr.design.mainframe.alphafine.search.manager.impl; + + +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.mainframe.alphafine.model.TemplateResourceDetail; +import com.fr.design.mainframe.alphafine.search.helper.FineMarketClientHelper; +import com.fr.general.CloudCenter; +import com.fr.general.IOUtils; +import com.fr.json.JSONArray; + +import java.util.ArrayList; +import java.util.List; + + +/** + * + * alphafine - 模板资源搜索助手 + * + * @author Link + * @version 10.0 + * Created by Link on 2022/9/22 + * */ +public class TemplateResourceSearchManager { + + private static final TemplateResourceSearchManager INSTANCE = new TemplateResourceSearchManager(); + public static TemplateResourceSearchManager getInstance() { + return INSTANCE; + } + + public static final String LOCAL_RESOURCE_URL = "/com/fr/design/mainframe/alphafine/template_resource/local_templates.json"; + private static final FineMarketClientHelper HELPER = FineMarketClientHelper.getInstance(); + + + /** + * 帆软市场暂时没有分页搜索接口,先全量搜,分页展示 + * */ + public List getSearchResult(String searchText) { + List resourceList = new ArrayList<>(); + + // 联网搜索 + try { + JSONArray jsonArray = HELPER.getTemplateInfoByName(searchText); + if (jsonArray != null && !jsonArray.isEmpty()) { + resourceList.addAll(TemplateResource.createByJson(jsonArray)); + } + } catch (Exception e) { + + } + + // 本地搜索 + if (resourceList.isEmpty()) { + List localResource = getEmbedResourceList(); + localResource.stream().forEach(resource->{ + if (resource.getName().toLowerCase().contains(searchText)) { + resourceList.add(resource); + } + }); + } + return resourceList; + } + + + /** + * 返回默认资源 + * */ + public List getDefaultResourceList() { + List resourceList = getEmbedResourceList(); + // 添加推荐搜索卡片 + resourceList.add(TemplateResource.getRecommendSearch()); + return resourceList; + } + + /** + * 返回内置资源 + * */ + public List getEmbedResourceList() { + List resourceList = new ArrayList<>(); + JSONArray jsonArray = getEmbedResourceJSONArray(); + for (int i = 0; i < jsonArray.size(); i++) { + TemplateResource resource = TemplateResource.createByJson(jsonArray.getJSONObject(i)); + resource.setEmbed(true); + resourceList.add(resource); + } + return resourceList; + } + + public JSONArray getEmbedResourceJSONArray() { + String jsonString = IOUtils.readResourceAsString(LOCAL_RESOURCE_URL); + return new JSONArray(jsonString); + } + + public List getRecommendSearchKeys() { + List searchKey = new ArrayList<>(); + String[] keys = CloudCenter.getInstance().acquireConf("alphafine.tempalte.recommend", "跑马灯,填报,地图").split(","); + for (String k : keys) { + searchKey.add(k); + } + return searchKey; + } + + + public TemplateResourceDetail getDetailSearchResult(TemplateResource resource) { + if (AlphaFineHelper.isNetworkOk()) { + return TemplateResourceDetail.createByTemplateResource(resource); + } else { + return TemplateResourceDetail.createFromEmbedResource(resource); + } + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/market/key/FineMarketDefaultKeyProperties.java b/designer-realize/src/main/java/com/fr/market/key/FineMarketDefaultKeyProperties.java new file mode 100644 index 000000000..6365b14c7 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/market/key/FineMarketDefaultKeyProperties.java @@ -0,0 +1,73 @@ +package com.fr.market.key; + +import com.fr.general.IOUtils; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.log.FineLoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * + * 帆软市场公钥Properties + * + * @author Link + * @version 11.0 + * Created by Yvan on 2022/8/25 + */ +public class FineMarketDefaultKeyProperties { + + private Properties properties = new Properties(); + + private Map publicKeyMap = new HashMap<>(); + + private String propertyPath; + + private FineMarketDefaultKeyProperties(String propertyPath) { + this.propertyPath = propertyPath; + load(); + } + + /** + * 构造方法 + */ + public static FineMarketDefaultKeyProperties create(String propertyPath) { + return new FineMarketDefaultKeyProperties(propertyPath); + } + + private void load() { + try (InputStream inputStream = IOUtils.readResource(getPropertyPath())) { + byte[] data = ResourceIOUtils.inputStream2Bytes(inputStream); + properties.load(new ByteArrayInputStream(data)); + trims(properties); + publicKeyMap.put(FineMarketPublicKeyConstants.DEFAULT_KEY_KEY, properties.getProperty(FineMarketPublicKeyConstants.DEFAULT_KEY_KEY)); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + private String getPropertyPath() { + return this.propertyPath; + } + + public String getPublicKey() { + return publicKeyMap.get(FineMarketPublicKeyConstants.DEFAULT_KEY_KEY); + } + + /** + * 去除properties中value末尾的空格 + * @param properties + */ + public static void trims(Properties properties) { + for (String key : properties.stringPropertyNames()) { + String value = properties.getProperty(key); + if (value != null) { + properties.put(key, value.trim()); + } + } + } +} diff --git a/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyConstants.java b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyConstants.java new file mode 100644 index 000000000..9c8c122f8 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyConstants.java @@ -0,0 +1,32 @@ +package com.fr.market.key; + + +/** + * + * 帆软市场公钥常量 + * + * @author Link + * @version 11.0 + * Created by Link on 2022/8/25 + */ +public class FineMarketPublicKeyConstants { + + public static final String DEFAULT_KEY_KEY = "defaultKey"; + + public static final String DEFAULT_KEY_DIRECTORY = "/com/fr/market/key"; + + /** + * 公钥第一段 + */ + public static final String FIRST_PROPERTY = "76c1/default"; + + /** + * 公钥第二段 + */ + public static final String SECOND_PROPERTY = "943f/default"; + + /** + * 公钥第三段 + */ + public static final String THIRD_PROPERTY = "d8a3/default"; +} diff --git a/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyHolder.java b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyHolder.java new file mode 100644 index 000000000..b37493559 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyHolder.java @@ -0,0 +1,48 @@ +package com.fr.market.key; + +import com.fr.stable.StableUtils; + +/** + * 帆软市场公钥Holder + * @author Link + * @version 10.0 + * Created by Link on 2022/8/25 + */ +public class FineMarketPublicKeyHolder { + + private static FineMarketPublicKeyHolder instance = null; + + private String defaultKey; + + public static FineMarketPublicKeyHolder getInstance() { + + if (instance == null) { + synchronized (FineMarketPublicKeyHolder.class) { + if (instance == null) { + instance = new FineMarketPublicKeyHolder(); + } + } + } + return instance; + } + + private FineMarketPublicKeyHolder() { + init(); + } + + private void init() { + // 读取三个default.properties文件,组成公钥 + String firstPart = FineMarketDefaultKeyProperties.create(StableUtils.pathJoin(FineMarketPublicKeyConstants.DEFAULT_KEY_DIRECTORY, FineMarketPublicKeyConstants.FIRST_PROPERTY)).getPublicKey(); + String secondPart = FineMarketDefaultKeyProperties.create(StableUtils.pathJoin(FineMarketPublicKeyConstants.DEFAULT_KEY_DIRECTORY, FineMarketPublicKeyConstants.SECOND_PROPERTY)).getPublicKey(); + String thirdPart = FineMarketDefaultKeyProperties.create(StableUtils.pathJoin(FineMarketPublicKeyConstants.DEFAULT_KEY_DIRECTORY, FineMarketPublicKeyConstants.THIRD_PROPERTY)).getPublicKey(); + this.defaultKey = firstPart + secondPart + thirdPart; + } + + /** + * 获取默认公钥 + * @return 公钥 + */ + public String getDefaultKey() { + return this.defaultKey; + } +} diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/bottom.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/bottom.svg new file mode 100644 index 000000000..ef489cdce --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/bottom.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/bottom_disable.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/bottom_disable.svg new file mode 100644 index 000000000..e924fcb81 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/bottom_disable.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/caution.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/caution.svg new file mode 100644 index 000000000..731e79d0d --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/caution.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/config.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/config.svg new file mode 100644 index 000000000..f322cde88 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/config.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/down.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/down.svg new file mode 100644 index 000000000..9bc79b1c0 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/down.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/down_disable.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/down_disable.svg new file mode 100644 index 000000000..ec61156a0 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/down_disable.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/loading.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/loading.svg new file mode 100644 index 000000000..1df6ef5f2 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/loading.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template1.png b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template1.png new file mode 100644 index 000000000..203701cba Binary files /dev/null and b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template1.png differ diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template2.png b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template2.png new file mode 100644 index 000000000..a16f0dc40 Binary files /dev/null and b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template2.png differ diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template3.png b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template3.png new file mode 100644 index 000000000..89fd1386d Binary files /dev/null and b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template3.png differ diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template4.png b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template4.png new file mode 100644 index 000000000..fd30a4b7b Binary files /dev/null and b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_template4.png differ diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/more.png b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/more.png new file mode 100644 index 000000000..e49b1c96f Binary files /dev/null and b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/more.png differ diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/next.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/next.svg new file mode 100644 index 000000000..ba63a3d99 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/next.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/prev.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/prev.svg new file mode 100644 index 000000000..b70a6199a --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/prev.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/top.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/top.svg new file mode 100644 index 000000000..b82ae8475 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/top.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/top_disable.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/top_disable.svg new file mode 100644 index 000000000..b507888ef --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/top_disable.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/up.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/up.svg new file mode 100644 index 000000000..625153a57 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/up.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/up_disable.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/up_disable.svg new file mode 100644 index 000000000..d84b3b3c5 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/up_disable.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/template_resource/local_templates.json b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/template_resource/local_templates.json new file mode 100644 index 000000000..4e9265b14 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/template_resource/local_templates.json @@ -0,0 +1,110 @@ +[ + { + "id": 20000770, + "name": "PDCA销售运营闭环管理方案", + "uuid": "7975ad73-9aea-4634-96f1-d33ec1b4283c", + "vendor": "Victoria.", + "sellerId": 202, + "cid": "industry-3,purpose-2,purpose-16,purpose-15", + "tag": null, + "pic": "com/fr/design/mainframe/alphafine/images/local_template1.png", + "price": 0, + "fileLoca": null, + "text": "
  1. 此方案共包括14张模板,其中12张可视化分析看板、1张分析报表以及1张填报表,需在10.0及以上版本设计器中预览;

  2. 了解方案详情,可移步-数据分析与可视化指南

  3. 如果您希望在线体验当前方案,可移步-官方DEMO系统:业务场景应用->营销管理

  4. 如果您对此方案感兴趣,希望更加深入了解,可以填写此表单:方案需求录入;后续会有帆软行业顾问将与您联系。

", + "description": "将PDCA循环嵌入销售运营管理的全流程中,从决策层、管理层与执行层三个层级,对目标制定、执行过程、复盘分析、问题跟踪进行全方位精细化管理。", + "updateTime": "2022-06-15T06:36:39.000Z", + "downloadTimes": 1152, + "state": 1, + "designVersion": "10.0", + "involvePlugins": null, + "uploadTime": "2022-06-15T06:36:39.000Z", + "style": null, + "link": "template", + "sellerName": "Victoria.", + "pluginName": [], + "pkgsize": 14, + "material": "方案附件.rar", + "tagsName": "制造加工,营销,组织,管理,经营汇报" + }, + { + "id": 20000733, + "name": "库存场景解决方案", + "uuid": "43d1c14b-1a73-41e6-adcc-aaf2872bc8d4", + "vendor": "Victoria.", + "sellerId": 202, + "cid": "industry-3,purpose-5", + "tag": null, + "pic": "com/fr/design/mainframe/alphafine/images/local_template2.png", + "price": 0, + "fileLoca": null, + "text": "

当前库存管理面临的现状:库存成本劣势明显、库存周转差距较大。如果对此没有合理有效的解决方案,往往会导致企业库存越来越混乱,经营、资金、成本等问题丛生。

库存管理解决方案从:“盘”、“析”、“管”三个方向开展,彻底解决库存量大、结构复杂、管理混乱等常见问题

", + "description": "库存管理解决方案即从:“盘”、“析”、“管”三个方向开展,对导致库存管理问题的原因逐一击破。", + "updateTime": "2022-05-05T03:53:55.000Z", + "downloadTimes": 816, + "state": 1, + "designVersion": "10.0", + "involvePlugins": null, + "uploadTime": "2022-05-05T03:53:55.000Z", + "style": null, + "link": "template", + "sellerName": "Victoria.", + "pluginName": [], + "pkgsize": 11, + "material": "", + "tagsName":"制造加工,库存" + }, + { + "id": 20000581, + "name": "采购场景解决方案", + "uuid": "7994b01f-5069-4554-83cf-9d3506e30767", + "vendor": "Victoria.", + "sellerId": 202, + "cid": "industry-3,purpose-3", + "tag": null, + "pic": "com/fr/design/mainframe/alphafine/images/local_template3.png", + "price": 0, + "fileLoca": null, + "text": "

采购场景方案具体细节可参考:可视化指南-采购场景应用

", + "description": "采购解决方案采用:“自上而下”的分析思路,针对采购相关的不同角色层级及其不同角度发数据分析需求,产出不同的内容", + "updateTime": "2022-03-10T03:50:17.000Z", + "downloadTimes": 2353, + "state": 1, + "designVersion": "10.0", + "involvePlugins": null, + "uploadTime": "2022-03-10T03:50:18.000Z", + "style": null, + "link": "template", + "sellerName": "Victoria.", + "pluginName": [], + "pkgsize": 6, + "material": "", + "tagsName": "制造加工,采购" + }, + { + "id": 20000747, + "name": "费用预算系统解决方案", + "uuid": "0776533469c3401a8da78706856b6b02", + "vendor": "finereport", + "sellerId": 1, + "cid": "template_type-1,terminal-1,industry-13,purpose-1", + "tag": null, + "pic": "com/fr/design/mainframe/alphafine/images/local_template4.png", + "price": 0, + "fileLoca": "费用预算系统解决方案.zip", + "text": "

模板中使用了数据查询数据集,如果要在本地打开,需要在自己的数据库中建表,并修改数据连接。

1)建表语句见附件文件夹:SQL语句与表。


2)数据连接默认为 FRDemo,如果用户表所在的数据库连接不是 FRDemo,将模板中数据连接修改为用户默认的数据连接。


3)模板中 SQL 语句为 MYSQL 数据库,若用户使用中数据库语句不匹配,可对应修改为匹配的语句。


4)模板中有大量的超链接,用户存在本地后,预览时注意修改超链接。


5)费用预算系统的平台沿用人事管理系统的平台配置,如果要在本地体验效果,可先下载人事管理系统部署:人事管理系统

模板中图标等背景样式见背景附件。 如果数据替换麻烦,可直接使用内置数据集模板,但内置模板只提供了样式,控件、数据等不能联动。如何制作,可查看帮助文档:费用预算系统

", + "description": "费用预算系统是通过 FineReport 填报功能和平台功能结合实现的审批流程系统。能够在线采集数据,提供标准数据模板,解决不同部门、子公司之间数据不统一的问题,\n实现记录预算审批与更改的操作,审批与更改记录留痕等。\n详细内容可查看帮助文档:费用预算系统", + "updateTime": "2022-05-15T05:34:45.000Z", + "downloadTimes": 141, + "state": 1, + "designVersion": "10.0", + "involvePlugins": null, + "uploadTime": "2022-05-15T05:34:45.000Z", + "style": "简约清新", + "link": "template", + "sellerName": "finereport", + "pluginName": [], + "pkgsize": 1, + "material": null, + "tagsName": "IT互联网,财务" + } +] \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/market/key/76c1/default b/designer-realize/src/main/resources/com/fr/market/key/76c1/default new file mode 100644 index 000000000..58044d9c0 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/market/key/76c1/default @@ -0,0 +1 @@ +defaultKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtsz62CPSWXZE/IYZRiAuTSZkw \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/market/key/943f/default b/designer-realize/src/main/resources/com/fr/market/key/943f/default new file mode 100644 index 000000000..80946f51c --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/market/key/943f/default @@ -0,0 +1 @@ +defaultKey=1WOwer8+JFktK0uKLAUuQoBr+UjAMFtRA8W7JgKMDwZy/2liEAiXEOSPU/hrdV8D \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/market/key/d8a3/default b/designer-realize/src/main/resources/com/fr/market/key/d8a3/default new file mode 100644 index 000000000..af41473f3 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/market/key/d8a3/default @@ -0,0 +1 @@ +defaultKey=tT541LnGi1X/hXiRwuttPWYN3L2GYm/d5blU+FBNwghBIrdAxXTzYBc6P4KL/oYXnMdTIrkz8tYkG3QoFQIDAQAB \ No newline at end of file