@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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><body style=\"" + style + "\">" + html + "</body></html>"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 创建链接字符串,html格式 |
||||||
|
* */ |
||||||
|
public static String generateLinkTag(String link, String text) { |
||||||
|
|
||||||
|
return "<a href=\"" + link + "\">" + text + "</a>"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 创建链接字符串,无下划线,html格式 |
||||||
|
* */ |
||||||
|
public static String generateLinkTagWithoutUnderLine(String link, String text) { |
||||||
|
return "<a style=\"text-decoration:none;\" href=\"" + link + "\">" + text + "</a>"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 创建链接字符串的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()); |
||||||
|
} |
||||||
|
} |
@ -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<String, Void>() { |
||||||
|
|
||||||
|
@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; |
||||||
|
} |
||||||
|
} |
@ -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<String> 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); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -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<TemplateResource> data; |
||||||
|
private CardLayout cardLayout; |
||||||
|
private List<Page> pages; |
||||||
|
private int totalPage; |
||||||
|
|
||||||
|
List<UIScrollPane> 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<TemplateResource> 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<TemplateResource>[] 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<TemplateResource> pageData; |
||||||
|
Component[][] comps; |
||||||
|
|
||||||
|
JPanel contentPane; |
||||||
|
|
||||||
|
JPanel pageButtonPane; |
||||||
|
JButton prev, next; |
||||||
|
JTextField pageNumberField; |
||||||
|
JLabel pageCnt; |
||||||
|
|
||||||
|
int pageNumber; |
||||||
|
|
||||||
|
Page(List<TemplateResource> 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)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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"; |
||||||
|
} |
@ -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<Double> { |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -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<String> recommendSearchKey; |
||||||
|
private boolean embed; |
||||||
|
|
||||||
|
/** |
||||||
|
* json转obj |
||||||
|
* */ |
||||||
|
public static List<TemplateResource> createByJson(JSONArray jsonArray) { |
||||||
|
List<TemplateResource> 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<String> getRecommendSearchKey() { |
||||||
|
return recommendSearchKey; |
||||||
|
} |
||||||
|
|
||||||
|
public void setRecommendSearchKey(List<String> 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; |
||||||
|
} |
||||||
|
} |
@ -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<String> detailInfo; |
||||||
|
private String[] tagsId; |
||||||
|
private List<String> 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<String> getDetailInfo() { |
||||||
|
return detailInfo; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDetailInfo(List<String> detailInfo) { |
||||||
|
this.detailInfo = detailInfo; |
||||||
|
} |
||||||
|
|
||||||
|
public String[] getTagsId() { |
||||||
|
return tagsId; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTagsId(String[] tagsId) { |
||||||
|
this.tagsId = tagsId; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> 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<String> 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标签写的,如下 |
||||||
|
* "<ol style="list-style-type: decimal;" class=" list-paddingleft-2"><li><p>该模板需用10.0及以上版本设计器预览<br/></p></li><li><p>该模板为库存场景解决方案的部分内容,全部内容可下载<a href="https://market.fanruan.com/template/20000733" target="_self">库存场景解决方案</a>查看</p></li><li><p>为保障模板预览效果,建议安装<a href="https://help.fanruan.com/finereport10.0/doc-view-3665.html" target="_self">新自适应插件</a>(FR11.0版本插件已内置,无需手动安装),有使用需求或疑问,请联系帆软技术支持咨询<br/></p></li></ol>",
|
||||||
|
* |
||||||
|
* 转换的后的数据 是原始数据中所有<p></p>标签内的(包括标签)的字符串(List<String>),如上字符串会转为如下 |
||||||
|
* List [<p>该模板需用10.0及以上版本设计器预览<br/></p>, |
||||||
|
* <p>该模板为库存场景解决方案的部分内容,全部内容可下载<a href="https://market.fanruan.com/template/20000733" target="_self">库存场景解决方案</a>查看</p>, |
||||||
|
* <p>为保障模板预览效果,建议安装<a href="https://help.fanruan.com/finereport10.0/doc-view-3665.html" target="_self">新自适应插件</a>(FR11.0版本插件已内置,无需手动安装),有使用需求或疑问,请联系帆软技术支持咨询<br/></p> |
||||||
|
* ] |
||||||
|
* */ |
||||||
|
static final Pattern HTML_PATTERN = Pattern.compile("<p>(.+?)</p>"); |
||||||
|
static List<String> parseDetailInfo(String htmlDetailInfo) { |
||||||
|
List<String> infos = new ArrayList<>(); |
||||||
|
Matcher matcher = HTML_PATTERN.matcher(htmlDetailInfo); |
||||||
|
while (matcher.find()) { |
||||||
|
infos.add(matcher.group()); |
||||||
|
} |
||||||
|
return infos; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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 = "<br>"; |
||||||
|
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 = "<html><style>a {color: #419BF9;text-decoration:none;}</style><body style=\"line-height: 20px;"+ LinkStrUtils.generateStyle(HTML_FONT, HTML_COLOR) +"\">%s</body></html>"; |
||||||
|
private static final String DETAIL_INFO_HTML_FORMAT = "<html><style>a {color: #419BF9;text-decoration:none;}</style><body style=\"line-height: 20px;" + LinkStrUtils.generateStyle(HTML_FONT, HTML_COLOR) + "\"><p>" + DETAIL_INFO + "</p>%s</body></html>"; |
||||||
|
private static final String HTML_P_TAG_FORMAT = "<p style=\"margin-top:5pt;\">%s</p>"; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -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<TemplateResource> 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<TemplateResourceDetail, Void>() { |
||||||
|
@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<TemplateResource> 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);}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -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<List<TemplateResource>, Void> searchWorker; |
||||||
|
|
||||||
|
private Function<SearchTextBean, List<TemplateResource>> searchFunction; |
||||||
|
|
||||||
|
private AlphaFineFrame alphaFineFrame; |
||||||
|
|
||||||
|
private volatile boolean searchResult = true; |
||||||
|
|
||||||
|
private volatile boolean searchOver = false; |
||||||
|
|
||||||
|
private volatile boolean networkError = false; |
||||||
|
|
||||||
|
public TemplateResourceSearchWorkerManager(CellType cellType, Function<SearchTextBean, List<TemplateResource>> 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<List<TemplateResource>, Void>() { |
||||||
|
@Override |
||||||
|
protected List<TemplateResource> doInBackground() { |
||||||
|
List<TemplateResource> 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<TemplateResource> list = get(); |
||||||
|
searchResult = !list.isEmpty(); |
||||||
|
showResult(list); |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
this.searchWorker.execute(); |
||||||
|
} |
||||||
|
|
||||||
|
void showResult(List<TemplateResource> 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; |
||||||
|
} |
||||||
|
} |
@ -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<String, String> 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<Double> 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<String, String> 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<String> 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<String> getTemplateTagsByTemplateTagIds(String[] tagIds) throws IOException { |
||||||
|
List<String> 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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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<TemplateResource> getSearchResult(String searchText) { |
||||||
|
List<TemplateResource> 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<TemplateResource> localResource = getEmbedResourceList(); |
||||||
|
localResource.stream().forEach(resource->{ |
||||||
|
if (resource.getName().toLowerCase().contains(searchText)) { |
||||||
|
resourceList.add(resource); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
return resourceList; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 返回默认资源 |
||||||
|
* */ |
||||||
|
public List<TemplateResource> getDefaultResourceList() { |
||||||
|
List<TemplateResource> resourceList = getEmbedResourceList(); |
||||||
|
// 添加推荐搜索卡片
|
||||||
|
resourceList.add(TemplateResource.getRecommendSearch()); |
||||||
|
return resourceList; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 返回内置资源 |
||||||
|
* */ |
||||||
|
public List<TemplateResource> getEmbedResourceList() { |
||||||
|
List<TemplateResource> 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<String> getRecommendSearchKeys() { |
||||||
|
List<String> 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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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<String, String> 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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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"; |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 672 B |
After Width: | Height: | Size: 685 B |
After Width: | Height: | Size: 820 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 620 B |
After Width: | Height: | Size: 637 B |
After Width: | Height: | Size: 936 B |
After Width: | Height: | Size: 424 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 206 KiB |
After Width: | Height: | Size: 591 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 453 B |
After Width: | Height: | Size: 447 B |
After Width: | Height: | Size: 668 B |
After Width: | Height: | Size: 684 B |
After Width: | Height: | Size: 573 B |
After Width: | Height: | Size: 589 B |
@ -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": "<ol style=\"list-style-type: decimal;\" class=\" list-paddingleft-2\"><li><p>此方案共包括14张模板,其中12张可视化分析看板、1张分析报表以及1张填报表,需在10.0及以上版本设计器中预览;</p></li><li><p>了解方案详情,可移步-数据分析与可视化指南</p></li><li><p>如果您希望在线体验当前方案,可移步-<a href=\"https://demo.finereport.com/\" target=\"_self\">官方DEMO系统</a>:业务场景应用->营销管理<br/></p></li><li><p>如果您对此方案感兴趣,希望更加深入了解,可以填写此表单:<a href=\"https://t6ixa9nyl6.jiandaoyun.com/f/60dac9bd282e8e000796eac3\" target=\"_self\">方案需求录入</a>;后续会有帆软行业顾问将与您联系。<br/></p></li></ol>", |
||||||
|
"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": "<p>当前库存管理面临的现状:库存成本劣势明显、库存周转差距较大。如果对此没有合理有效的解决方案,往往会导致企业库存越来越混乱,经营、资金、成本等问题丛生。</p><p>库存管理解决方案从:“盘”、“析”、“管”三个方向开展,彻底解决库存量大、结构复杂、管理混乱等常见问题</p>", |
||||||
|
"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": "<p>采购场景方案具体细节可参考:<a href=\"https://help.fanruan.com/dvg/doc-view-151.html\" target=\"_self\">可视化指南-采购场景应用</a><br/></p>", |
||||||
|
"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": "<p>模板中使用了数据查询数据集,如果要在本地打开,需要在自己的数据库中建表,并修改数据连接。</p><p>1)建表语句见附件文件夹:SQL语句与表。</p><p><br>2)数据连接默认为 FRDemo,如果用户表所在的数据库连接不是 FRDemo,将模板中数据连接修改为用户默认的数据连接。</p><p><br>3)模板中 SQL 语句为 MYSQL 数据库,若用户使用中数据库语句不匹配,可对应修改为匹配的语句。</p><p><br>4)模板中有大量的超链接,用户存在本地后,预览时注意修改超链接。</p><p><br>5)费用预算系统的平台沿用人事管理系统的平台配置,如果要在本地体验效果,可先下载人事管理系统部署:</span><a href=\"https://help.fanruan.com/dvg/doc-view-6.html?source=0&from=demoshop\" target=\"_blank\" style=\"text-decoration: underline; color: rgb(28, 133, 231); font-family: arial, helvetica, sans-serif;\"><span style=\"font-family: arial, helvetica, sans-serif;\">人事管理系统</span></a><span style=\"font-family: arial, helvetica, sans-serif;\"><br></p><p>模板中图标等背景样式见背景附件。 如果数据替换麻烦,可直接使用内置数据集模板,但内置模板只提供了样式,控件、数据等不能联动。如何制作,可查看帮助文档:</span><a href=\"https://help.fanruan.com/dvg/doc-view-124.html?source=0&from=demoshop\" target=\"_blank\" style=\"text-decoration: underline; color: rgb(28, 133, 231); font-family: arial, helvetica, sans-serif;\"><span style=\"font-family: arial, helvetica, sans-serif;\">费用预算系统</span></a><span style=\"font-family: arial, helvetica, sans-serif;\"></p>", |
||||||
|
"description": "费用预算系统是通过 FineReport 填报功能和平台功能结合实现的审批流程系统。能够在线采集数据,提供标准数据模板,解决不同部门、子公司之间数据不统一的问题,\n实现记录预算审批与更改的操作,审批与更改记录留痕等。\n详细内容可查看帮助文档:</span><a href=\"https://help.fanruan.com/dvg/doc-view-124.html?source=0&from=demoshop\" target=\"_blank\" style=\"text-decoration: underline; color: rgb(28, 133, 231); font-family: arial, helvetica, sans-serif;\"><span style=\"font-family: arial, helvetica, sans-serif;\">费用预算系统</span></a><span style=\"font-family: arial, helvetica, sans-serif;\">", |
||||||
|
"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互联网,财务" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1 @@ |
|||||||
|
defaultKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtsz62CPSWXZE/IYZRiAuTSZkw |
@ -0,0 +1 @@ |
|||||||
|
defaultKey=1WOwer8+JFktK0uKLAUuQoBr+UjAMFtRA8W7JgKMDwZy/2liEAiXEOSPU/hrdV8D |