mirror of
https://gitee.com/shuto-github/intranet_app_manager.git
synced 2026-05-27 00:00:14 +08:00
Merge branch 'master' of github.com:yizhaorong/intranet_app_manager
This commit is contained in:
+2
-4
@@ -6,7 +6,7 @@ plugins {
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
group = 'org.yzr'
|
||||
version = '1.0.0'
|
||||
version = '1.0.1'
|
||||
sourceCompatibility = '1.8'
|
||||
|
||||
configurations {
|
||||
@@ -28,11 +28,9 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.16'
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
compile group: 'com.googlecode.plist', name: 'dd-plist', version: '1.21'
|
||||
compile group: 'net.dongliu', name: 'apk-parser', version: '2.6.9'
|
||||
compile group: 'net.glxn.qrgen', name: 'javase', version: '2.0'
|
||||
compile group: 'com.google.zxing', name: 'javase', version: '3.4.0'
|
||||
compile group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||
compile group: 'com.jcraft', name: 'jzlib', version: '1.1.3'
|
||||
compile group: 'org.freemarker', name: 'freemarker', version: '2.3.28'
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 39 KiB |
@@ -11,7 +11,6 @@ import org.yzr.vo.AppViewModel;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +44,20 @@ public class AppController {
|
||||
return "list";
|
||||
}
|
||||
|
||||
@RequestMapping("/packageList/{appID}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> getAppPackageList(@PathVariable("appID") String appID) {
|
||||
AppViewModel appViewModel = this.appService.getById(appID);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
try {
|
||||
map.put("packages", appViewModel.getPackageList());
|
||||
map.put("success", true);
|
||||
} catch (Exception e) {
|
||||
map.put("success", false);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@RequestMapping("/app/delete/{id}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> deleteById(@PathVariable("id") String id) {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package org.yzr.controller;
|
||||
|
||||
|
||||
import net.glxn.qrgen.javase.QRCode;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.yzr.model.App;
|
||||
@@ -12,6 +13,7 @@ import org.yzr.model.Package;
|
||||
import org.yzr.service.AppService;
|
||||
import org.yzr.service.PackageService;
|
||||
import org.yzr.utils.PathManager;
|
||||
import org.yzr.utils.QRCodeUtil;
|
||||
import org.yzr.utils.ipa.PlistGenerator;
|
||||
import org.yzr.utils.webhook.WebHookClient;
|
||||
import org.yzr.vo.AppViewModel;
|
||||
@@ -88,6 +90,18 @@ public class PackageController {
|
||||
try {
|
||||
String filePath = transfer(file);
|
||||
Package aPackage = this.packageService.buildPackage(filePath);
|
||||
Map<String , String> extra = new HashMap<>();
|
||||
String jobName = request.getParameter("jobName");
|
||||
String buildNumber = request.getParameter("buildNumber");
|
||||
if (StringUtils.hasLength(jobName)) {
|
||||
extra.put("jobName", jobName);
|
||||
}
|
||||
if (StringUtils.hasLength(buildNumber)) {
|
||||
extra.put("buildNumber", buildNumber);
|
||||
}
|
||||
if (!extra.isEmpty()) {
|
||||
aPackage.setExtra(JSON.toJSONString(extra));
|
||||
}
|
||||
App app = this.appService.getByPackage(aPackage);
|
||||
app.getPackageList().add(aPackage);
|
||||
app.setCurrentPackage(aPackage);
|
||||
@@ -151,7 +165,7 @@ public class PackageController {
|
||||
public void getManifest(@PathVariable("id") String id, HttpServletResponse response) {
|
||||
try {
|
||||
PackageViewModel viewModel = this.packageService.findById(id);
|
||||
if (viewModel != null && viewModel.isIOS()) {
|
||||
if (viewModel != null && viewModel.isiOS()) {
|
||||
response.setContentType("application/force-download");
|
||||
response.setHeader("Content-Disposition", "attachment;fileName=manifest.plist");
|
||||
Writer writer = new OutputStreamWriter(response.getOutputStream());
|
||||
@@ -173,7 +187,7 @@ public class PackageController {
|
||||
PackageViewModel viewModel = this.packageService.findById(id);
|
||||
if (viewModel != null) {
|
||||
response.setContentType("image/png");
|
||||
QRCode.from(viewModel.getPreviewURL()).withSize(250, 250).writeTo(response.getOutputStream());
|
||||
QRCodeUtil.encode(viewModel.getPreviewURL()).withSize(250, 250).writeTo(response.getOutputStream());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.yzr.model;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
@@ -10,8 +8,6 @@ import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "tb_app", uniqueConstraints = {@UniqueConstraint(columnNames={"platform", "bundleID"})})
|
||||
@Setter
|
||||
@Getter
|
||||
public class App {
|
||||
// 主键
|
||||
@Id
|
||||
@@ -43,4 +39,83 @@ public class App {
|
||||
@JoinColumn(name = "currentID",referencedColumnName = "id")
|
||||
private Package currentPackage;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getBundleID() {
|
||||
return bundleID;
|
||||
}
|
||||
|
||||
public void setBundleID(String bundleID) {
|
||||
this.bundleID = bundleID;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getShortCode() {
|
||||
return shortCode;
|
||||
}
|
||||
|
||||
public void setShortCode(String shortCode) {
|
||||
this.shortCode = shortCode;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public List<Package> getPackageList() {
|
||||
return packageList;
|
||||
}
|
||||
|
||||
public void setPackageList(List<Package> packageList) {
|
||||
this.packageList = packageList;
|
||||
}
|
||||
|
||||
public List<WebHook> getWebHookList() {
|
||||
return webHookList;
|
||||
}
|
||||
|
||||
public void setWebHookList(List<WebHook> webHookList) {
|
||||
this.webHookList = webHookList;
|
||||
}
|
||||
|
||||
public Package getCurrentPackage() {
|
||||
return currentPackage;
|
||||
}
|
||||
|
||||
public void setCurrentPackage(Package currentPackage) {
|
||||
this.currentPackage = currentPackage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package org.yzr.model;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name="tb_package")
|
||||
@Setter
|
||||
@Getter
|
||||
public class Package {
|
||||
// 主键
|
||||
@Id
|
||||
@@ -34,6 +30,8 @@ public class Package {
|
||||
private String minVersion;
|
||||
// 平台(Android 或 iOS)
|
||||
private String platform;
|
||||
// 扩展消息 (json格式)
|
||||
private String extra;
|
||||
// 文件名
|
||||
private String fileName;
|
||||
@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
@@ -44,4 +42,107 @@ public class Package {
|
||||
@JoinColumn(name = "provisionId",referencedColumnName = "id")
|
||||
private Provision provision;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getBundleID() {
|
||||
return bundleID;
|
||||
}
|
||||
|
||||
public void setBundleID(String bundleID) {
|
||||
this.bundleID = bundleID;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getBuildVersion() {
|
||||
return buildVersion;
|
||||
}
|
||||
|
||||
public void setBuildVersion(String buildVersion) {
|
||||
this.buildVersion = buildVersion;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public String getMinVersion() {
|
||||
return minVersion;
|
||||
}
|
||||
|
||||
public void setMinVersion(String minVersion) {
|
||||
this.minVersion = minVersion;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public App getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(App app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Provision getProvision() {
|
||||
return provision;
|
||||
}
|
||||
|
||||
public void setProvision(Provision provision) {
|
||||
this.provision = provision;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.yzr.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
@@ -10,8 +8,6 @@ import java.util.Date;
|
||||
|
||||
@Entity
|
||||
@Table(name="tb_provision")
|
||||
@Setter
|
||||
@Getter
|
||||
public class Provision {
|
||||
// 主键
|
||||
@Id
|
||||
@@ -29,4 +25,84 @@ public class Provision {
|
||||
private int deviceCount;
|
||||
private String type;
|
||||
private boolean isEnterprise;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTeamName() {
|
||||
return teamName;
|
||||
}
|
||||
|
||||
public void setTeamName(String teamName) {
|
||||
this.teamName = teamName;
|
||||
}
|
||||
|
||||
public String getTeamID() {
|
||||
return teamID;
|
||||
}
|
||||
|
||||
public void setTeamID(String teamID) {
|
||||
this.teamID = teamID;
|
||||
}
|
||||
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
public Date getExpirationDate() {
|
||||
return expirationDate;
|
||||
}
|
||||
|
||||
public void setExpirationDate(Date expirationDate) {
|
||||
this.expirationDate = expirationDate;
|
||||
}
|
||||
|
||||
public String getUUID() {
|
||||
return UUID;
|
||||
}
|
||||
|
||||
public void setUUID(String UUID) {
|
||||
this.UUID = UUID;
|
||||
}
|
||||
|
||||
public String[] getDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
public void setDevices(String[] devices) {
|
||||
this.devices = devices;
|
||||
}
|
||||
|
||||
public int getDeviceCount() {
|
||||
return deviceCount;
|
||||
}
|
||||
|
||||
public void setDeviceCount(int deviceCount) {
|
||||
this.deviceCount = deviceCount;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isEnterprise() {
|
||||
return isEnterprise;
|
||||
}
|
||||
|
||||
public void setEnterprise(boolean enterprise) {
|
||||
isEnterprise = enterprise;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package org.yzr.model;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "tb_web_hook")
|
||||
@Setter
|
||||
@Getter
|
||||
public class WebHook {
|
||||
// 钉钉
|
||||
public static final String WEB_HOOK_TYPE_DING_DING="DingDing";
|
||||
@@ -31,4 +27,44 @@ public class WebHook {
|
||||
@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name="appId")
|
||||
private App app;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public App getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(App app) {
|
||||
this.app = app;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
package org.yzr.service;
|
||||
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.yzr.dao.AppDao;
|
||||
import org.yzr.dao.PackageDao;
|
||||
import org.yzr.model.App;
|
||||
import org.yzr.model.Package;
|
||||
import org.yzr.utils.ImageUtils;
|
||||
import org.yzr.utils.PathManager;
|
||||
import org.yzr.utils.ipa.PlistGenerator;
|
||||
import org.yzr.utils.parser.ParserClient;
|
||||
import org.yzr.vo.PackageViewModel;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.transaction.Transactional;
|
||||
import java.io.File;
|
||||
|
||||
@@ -39,12 +34,9 @@ public class PackageService {
|
||||
String tempIconPath = PathManager.getTempIconPath(aPackage);
|
||||
String iconPath = packagePath + File.separator + "icon.png";
|
||||
String sourcePath = packagePath + File.separator + fileName;
|
||||
String jpgIconPath = packagePath + File.separator + "icon.jpg";
|
||||
|
||||
// 拷贝图标
|
||||
ImageUtils.resize(tempIconPath, iconPath, 192, 192);
|
||||
// 生成钉钉发送所需要图片
|
||||
ImageUtils.convertPNGToJPG(iconPath, jpgIconPath, 64, 64);
|
||||
// 源文件
|
||||
FileUtils.copyFile(new File(filePath), new File(sourcePath));
|
||||
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
package org.yzr.utils;
|
||||
|
||||
import com.google.zxing.*;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.client.j2se.MatrixToImageConfig;
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QRCodeUtil {
|
||||
|
||||
private String text;
|
||||
|
||||
private Integer width = 200;
|
||||
|
||||
private Integer height = 200;
|
||||
|
||||
private static final float PERCENT = 0.2F;
|
||||
|
||||
private static final int CORNER_RADIUS = 5;
|
||||
|
||||
private File icon;
|
||||
|
||||
private String format = "png";
|
||||
|
||||
public static QRCodeUtil encode(String text) {
|
||||
QRCodeUtil util = new QRCodeUtil();
|
||||
util.text = text;
|
||||
return util;
|
||||
}
|
||||
|
||||
public QRCodeUtil withSize(Integer width, Integer height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QRCodeUtil withIcon(File icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean writeTo(OutputStream outputStream) {
|
||||
try {
|
||||
BitMatrix bitMatrix = getBitMatrix();
|
||||
if (this.icon != null) {
|
||||
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
|
||||
BufferedImage bufferedImage = drawIconInMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), this.icon);
|
||||
ImageIO.write(bufferedImage, format, outputStream);
|
||||
} else {
|
||||
MatrixToImageWriter.writeToStream(bitMatrix, format, outputStream);
|
||||
}
|
||||
return true;
|
||||
} catch (WriterException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean writeTo(File file) {
|
||||
try {
|
||||
BitMatrix bitMatrix = getBitMatrix();
|
||||
if (this.icon != null) {
|
||||
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
|
||||
BufferedImage bufferedImage = drawIconInMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), this.icon);
|
||||
ImageIO.write(bufferedImage, format, file);
|
||||
} else {
|
||||
MatrixToImageWriter.writeToPath(bitMatrix, format, file.toPath());
|
||||
}
|
||||
return true;
|
||||
} catch (WriterException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private BitMatrix getBitMatrix() throws WriterException {
|
||||
Map<EncodeHintType, Object> hints = new HashMap<>();
|
||||
//内容编码格式
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
||||
// 指定纠错等级
|
||||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
|
||||
//设置二维码边的空度,非负数
|
||||
hints.put(EncodeHintType.MARGIN, 1);
|
||||
return new MultiFormatWriter().encode(this.text, BarcodeFormat.QR_CODE, width, height, hints);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 识别指定文件的二维码
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public static String parseCode(File file) {
|
||||
BufferedImage bufferedImage = null;
|
||||
try {
|
||||
bufferedImage = ImageIO.read(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return parseCode(bufferedImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别指定图片的二维码
|
||||
* @param bufferedImage
|
||||
* @return
|
||||
*/
|
||||
public static String parseCode(BufferedImage bufferedImage) {
|
||||
String content = null;
|
||||
try {
|
||||
//读取指定的二维码文件
|
||||
MultiFormatReader formatReader = new MultiFormatReader();
|
||||
BinaryBitmap binaryBitmap= new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));
|
||||
//定义二维码参数
|
||||
Map hints= new HashMap<>();
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
|
||||
Result result = formatReader.decode(binaryBitmap, hints);
|
||||
//输出相关的二维码信息
|
||||
System.out.println("解析结果:"+result.toString());
|
||||
System.out.println("二维码格式类型:"+result.getBarcodeFormat());
|
||||
System.out.println("二维码文本内容:"+result.getText());
|
||||
content = result.getText();
|
||||
if (bufferedImage != null) {
|
||||
bufferedImage.flush();
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别输入流的二维码
|
||||
* @param inputStream
|
||||
* @return
|
||||
*/
|
||||
public static String parseCode(InputStream inputStream) {
|
||||
BufferedImage bufferedImage = null;
|
||||
try {
|
||||
bufferedImage = ImageIO.read(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return parseCode(bufferedImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 二维码添加logo
|
||||
* @param matrixImage 源二维码图片
|
||||
* @param logoFile logo图片
|
||||
* @return 返回带有logo的二维码图片
|
||||
*/
|
||||
private BufferedImage drawIconInMatrix(BufferedImage matrixImage, File logoFile) throws IOException{
|
||||
/**
|
||||
* 读取二维码图片,并构建绘图对象
|
||||
*/
|
||||
Graphics2D g2 = matrixImage.createGraphics();
|
||||
int matrixWidth = matrixImage.getWidth();
|
||||
int matrixHeight = matrixImage.getHeight();
|
||||
|
||||
/**
|
||||
* 读取Logo图片
|
||||
*/
|
||||
BufferedImage logo = ImageIO.read(logoFile);
|
||||
|
||||
//开始绘制图片
|
||||
g2.drawImage(logo,(int)(matrixWidth * PERCENT*2),(int)(matrixHeight * PERCENT*2), (int)(matrixWidth * PERCENT), (int)(matrixHeight * PERCENT), null);//绘制
|
||||
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
|
||||
g2.setStroke(stroke);// 设置笔画对象
|
||||
//指定弧度的圆角矩形
|
||||
RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth * PERCENT*2, matrixHeight * PERCENT*2, matrixWidth * PERCENT, matrixHeight * PERCENT,CORNER_RADIUS,CORNER_RADIUS);
|
||||
g2.setColor(Color.white);
|
||||
g2.draw(round);// 绘制圆弧矩形
|
||||
|
||||
//设置logo 有一道灰色边框
|
||||
BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
|
||||
g2.setStroke(stroke2);// 设置笔画对象
|
||||
RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth * PERCENT*2+2, matrixHeight * PERCENT*2+2, matrixWidth * PERCENT-4, matrixHeight * PERCENT-4,CORNER_RADIUS,CORNER_RADIUS);
|
||||
g2.setColor(new Color(128,128,128));
|
||||
g2.draw(round2);// 绘制圆弧矩形
|
||||
|
||||
g2.dispose();
|
||||
matrixImage.flush() ;
|
||||
return matrixImage ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package org.yzr.utils.webhook;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import okhttp3.*;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.yzr.model.App;
|
||||
import org.yzr.model.Package;
|
||||
import org.yzr.model.WebHook;
|
||||
import org.yzr.utils.ImageUtils;
|
||||
import org.yzr.utils.PathManager;
|
||||
import org.yzr.utils.QRCodeUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -46,19 +51,30 @@ public class DingDingWebHook implements IWebHook {
|
||||
}
|
||||
Map<String, Object> markdown = new HashMap<>();
|
||||
markdown.put("title", app.getName());
|
||||
String url = pathManager.getBaseURL(false) + "s/" + app.getShortCode();
|
||||
String url = pathManager.getBaseURL(false) + "s/" + app.getShortCode() + "?id=" + app.getCurrentPackage().getId();
|
||||
String platform = "iOS";
|
||||
if (app.getPlatform().equalsIgnoreCase("android")) {
|
||||
platform = "Android";
|
||||
}
|
||||
|
||||
String appInfo = String.format("[%s(%s)更新](%s)", app.getName(), platform, url);
|
||||
|
||||
String iconPath = PathManager.getFullPath(app.getCurrentPackage()) + "icon.png";
|
||||
// 将图片转为 base64, 内网 ip 钉钉无法访问,直接给图片数据
|
||||
String iconPath = PathManager.getFullPath(app.getCurrentPackage()) + "icon.jpg";
|
||||
String icon = "data:image/jpg;base64," + ImageUtils.convertImageToBase64(iconPath);
|
||||
String codePath = PathManager.getFullPath(app.getCurrentPackage()) + "code.jpg";
|
||||
File codeFile = new File(codePath);
|
||||
// 图片不存在,生成图片
|
||||
if (!codeFile.exists()) {
|
||||
QRCodeUtil.encode(url).withSize(150, 150).withIcon(new File(iconPath)).writeTo(new File(codePath));
|
||||
}
|
||||
String icon = "data:image/jpg;base64," + ImageUtils.convertImageToBase64(codePath);
|
||||
String pathInfo = String.format("", app.getName(), icon);
|
||||
String otherInfo = String.format("链接:[%s](%s) \n\n 版本:%s (Build: %s)", url, url, app.getCurrentPackage().getVersion(), app.getCurrentPackage().getBuildVersion());
|
||||
String message = this.getPackageMessage(app.getCurrentPackage());
|
||||
String text = appInfo + " \n\n " + pathInfo + " \n\n " + otherInfo;
|
||||
if (message.length() > 0) {
|
||||
text += "\n\n" + message;
|
||||
}
|
||||
markdown.put("text", text);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("msgtype", "markdown");
|
||||
@@ -69,4 +85,23 @@ public class DingDingWebHook implements IWebHook {
|
||||
sendToDingding(json, webHook.getUrl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展消息
|
||||
* @return
|
||||
*/
|
||||
private String getPackageMessage(Package aPackage) {
|
||||
String message = "";
|
||||
if (StringUtils.hasLength(aPackage.getExtra())) {
|
||||
Map<String, String> extra = (Map<String, String>) JSON.parse(aPackage.getExtra());
|
||||
if (extra.containsKey("jobName")) {
|
||||
message += "任务名:" + extra.get("jobName");
|
||||
}
|
||||
|
||||
if (extra.containsKey("buildNumber")) {
|
||||
message += " 编号:#" + extra.get("buildNumber");
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
package org.yzr.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.yzr.model.App;
|
||||
import org.yzr.model.Package;
|
||||
import org.yzr.utils.PathManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Getter
|
||||
public class AppViewModel {
|
||||
|
||||
private String id;
|
||||
@@ -106,4 +101,52 @@ public class AppViewModel {
|
||||
});
|
||||
return packageViewModels;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public String getBundleID() {
|
||||
return bundleID;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getBuildVersion() {
|
||||
return buildVersion;
|
||||
}
|
||||
|
||||
public String getMinVersion() {
|
||||
return minVersion;
|
||||
}
|
||||
|
||||
public String getShortCode() {
|
||||
return shortCode;
|
||||
}
|
||||
|
||||
public String getInstallPath() {
|
||||
return installPath;
|
||||
}
|
||||
|
||||
public List<PackageViewModel> getPackageList() {
|
||||
return packageList;
|
||||
}
|
||||
|
||||
public PackageViewModel getCurrentPackage() {
|
||||
return currentPackage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package org.yzr.vo;
|
||||
|
||||
import lombok.Getter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.yzr.model.Package;
|
||||
import org.yzr.utils.PathManager;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Getter
|
||||
public class PackageViewModel {
|
||||
private String downloadURL;
|
||||
private String safeDownloadURL;
|
||||
@@ -31,6 +31,7 @@ public class PackageViewModel {
|
||||
private String type;
|
||||
private List<String> devices;
|
||||
private int deviceCount;
|
||||
private String message;
|
||||
|
||||
public PackageViewModel(Package aPackage, PathManager pathManager) {
|
||||
this.downloadURL = pathManager.getBaseURL(false) + "p/" + aPackage.getId();
|
||||
@@ -57,7 +58,7 @@ public class PackageViewModel {
|
||||
this.installURL = pathManager.getPackageResourceURL(aPackage, false) + aPackage.getFileName();
|
||||
}
|
||||
this.previewURL = pathManager.getBaseURL(false) + "s/" + aPackage.getApp().getShortCode() + "?id=" + aPackage.getId();
|
||||
if (this.isIOS()) {
|
||||
if (this.isiOS()) {
|
||||
if (aPackage.getProvision() == null) {
|
||||
this.type = "内测版";
|
||||
} else {
|
||||
@@ -78,6 +79,89 @@ public class PackageViewModel {
|
||||
} else {
|
||||
this.type = "内测版";
|
||||
}
|
||||
String message = "";
|
||||
if (StringUtils.hasLength(aPackage.getExtra())) {
|
||||
Map<String, String> extra = (Map<String, String>) JSON.parse(aPackage.getExtra());
|
||||
if (extra.containsKey("jobName")) {
|
||||
message += " 任务名:" + extra.get("jobName");
|
||||
}
|
||||
|
||||
if (extra.containsKey("buildNumber")) {
|
||||
message += " 编号:#" + extra.get("buildNumber");
|
||||
}
|
||||
}
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getDownloadURL() {
|
||||
return downloadURL;
|
||||
}
|
||||
|
||||
public String getSafeDownloadURL() {
|
||||
return safeDownloadURL;
|
||||
}
|
||||
|
||||
public String getIconURL() {
|
||||
return iconURL;
|
||||
}
|
||||
|
||||
public String getInstallURL() {
|
||||
return installURL;
|
||||
}
|
||||
|
||||
public String getPreviewURL() {
|
||||
return previewURL;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getBundleID() {
|
||||
return bundleID;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public String getBuildVersion() {
|
||||
return buildVersion;
|
||||
}
|
||||
|
||||
public String getDisplaySize() {
|
||||
return displaySize;
|
||||
}
|
||||
|
||||
public String getDisplayTime() {
|
||||
return displayTime;
|
||||
}
|
||||
|
||||
public boolean isiOS() {
|
||||
return iOS;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public List<String> getDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
public int getDeviceCount() {
|
||||
return deviceCount;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package org.yzr.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WebHookViewModel {
|
||||
private String id;
|
||||
|
||||
@@ -14,4 +11,44 @@ public class WebHookViewModel {
|
||||
|
||||
private String type;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
* 获取 webHook 列表
|
||||
*/
|
||||
function getWebHooks() {
|
||||
var appId =$("#appId").val();
|
||||
var appId = $("#appId").val();
|
||||
var url = "/webHook/find/" + appId;
|
||||
$.post(url, function(result){
|
||||
$.post(url, function (result) {
|
||||
$(".configrations").children(".config-name").remove();
|
||||
var content="";
|
||||
var content = "";
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
content += '<a onclick="editWebHook(this)" class="config-name ng-binding ng-scope"';
|
||||
content += 'data="'+ result[i].id +'" data-url="' + result[i].url + '" ';
|
||||
content += 'data-name="'+ result[i].name;
|
||||
content += '">#'+ result[i].name +'</a>';
|
||||
content += 'data="' + result[i].id + '" data-url="' + result[i].url + '" ';
|
||||
content += 'data-name="' + result[i].name;
|
||||
content += '">#' + result[i].name + '</a>';
|
||||
}
|
||||
$(".configrations").append(content);
|
||||
});
|
||||
@@ -44,6 +44,84 @@ function editWebHook(e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包列表
|
||||
*/
|
||||
function getPackageList() {
|
||||
var appId = $("#appId").val();
|
||||
var url = "/packageList/" + appId;
|
||||
$.post(url, function (result) {
|
||||
if (result.success) {
|
||||
var packages = result.packages;
|
||||
var packageList = '';
|
||||
packageList += '<li>';
|
||||
packageList += '<span class="dot"></span>';
|
||||
packageList += '<span class="filter ng-binding">版本更新</span>';
|
||||
packageList += '<span class="filter version-rollback ng-scope"></span>';
|
||||
packageList += '</li>';
|
||||
packageList += '<li>';
|
||||
packageList += '<div class="market-app-info">';
|
||||
packageList += '</div>';
|
||||
packageList += '</li>';
|
||||
for (var i = 0; i < packages.length; i++) {
|
||||
var package = packages[i];
|
||||
var version = package.version;
|
||||
var buildVersion = package.buildVersion;
|
||||
var displayTime = package.displayTime;
|
||||
var type = package.type;
|
||||
var downloadURL = package.downloadURL;
|
||||
var displaySize = package.displaySize;
|
||||
var previewURL = package.previewURL;
|
||||
var id = package.id;
|
||||
var message = package.message;
|
||||
packageList += '<li class="package_index_' + id + '">';
|
||||
packageList += '<div>';
|
||||
packageList += '<div class="directive-view-release">';
|
||||
packageList += '<i class="icon-upload-cloud2"></i>';
|
||||
packageList += '<b class="ng-binding">' + version + ' (Build ' + buildVersion + ')' + message + '</b > ';
|
||||
packageList += '<div class="release-metainfo ng-hide">';
|
||||
packageList += '<small><i class="icon-calendar"></i>';
|
||||
packageList += '<span class="ng-binding">' + displayTime + '</span>';
|
||||
packageList += '</small>';
|
||||
packageList += '</div>';
|
||||
packageList += '<div class="release-metainfo">';
|
||||
packageList += '<small><i class="icon-calendar"></i>';
|
||||
packageList += '<span class="ng-binding">' + displayTime + '</span></small> · ';
|
||||
packageList += '<small class="ng-scope">' + type + '</small>';
|
||||
packageList += '<i class="ng-hide"> · </i>';
|
||||
packageList += '<small class="ng-binding ng-hide"></small>';
|
||||
packageList += '</div>';
|
||||
packageList += '<div class="release-actions">';
|
||||
packageList += '<button class="tooltip-top download-action" tooltip="下载原文件" value="' + downloadURL + '">';
|
||||
packageList += '<i class="icon-cloud-download"></i>';
|
||||
packageList += '<span class="ng-binding"> ' + displaySize + '</span>';
|
||||
packageList += '</button>';
|
||||
packageList += '<button class="preview" value="' + previewURL + '">';
|
||||
packageList += '<i class="icon-eye"></i>';
|
||||
packageList += '<span class="ng-binding"> 预览</span>';
|
||||
packageList += '</button>';
|
||||
if (i > 0) {
|
||||
packageList += '<button class="ng-scope app-delete" data="' + id + '">';
|
||||
packageList += '<i class="icon-trash"></i>';
|
||||
packageList += '<span class="ng-binding"> 删除</span>';
|
||||
packageList += '</button>';
|
||||
}
|
||||
packageList += '</div>';
|
||||
packageList += '</div >';
|
||||
packageList += '</div >';
|
||||
packageList += '</li >';
|
||||
}
|
||||
packageList += '<li class="more ng-hide" ng-show="currentApp.releases.current_page < currentApp.releases.total_pages">';
|
||||
packageList += '<button ng-click="moreRelease()" class="ng-binding">显示更多版本</button></li>';
|
||||
$("#app-activity-panel").empty();
|
||||
$("#app-activity-panel").append(packageList);
|
||||
|
||||
bindActions();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造数据
|
||||
* @returns {{appId: (*|jQuery|string|undefined), name: (*|jQuery|string|undefined), id: (*|jQuery|string|undefined), url: (*|jQuery|string|undefined)}}
|
||||
@@ -53,11 +131,11 @@ function buildData() {
|
||||
var url = $("#ding-ding-web-hook-url").val();
|
||||
var appId = $("#appId").val();
|
||||
var id = $("#webHookId").val();
|
||||
var data ={
|
||||
name:name,
|
||||
url:url,
|
||||
appId:appId,
|
||||
id:id
|
||||
var data = {
|
||||
name: name,
|
||||
url: url,
|
||||
appId: appId,
|
||||
id: id
|
||||
};
|
||||
return data;
|
||||
}
|
||||
@@ -110,7 +188,7 @@ function remove() {
|
||||
function postWithURL(url) {
|
||||
var data = buildData();
|
||||
resetForm();
|
||||
$.post(url, data, function(result){
|
||||
$.post(url, data, function (result) {
|
||||
getWebHooks();
|
||||
});
|
||||
}
|
||||
@@ -130,9 +208,10 @@ function removeAllPanelClass() {
|
||||
$("#app-integration-panel").removeClass("ng-hide");
|
||||
}
|
||||
|
||||
$(function () {
|
||||
getWebHooks();
|
||||
|
||||
/**
|
||||
* 绑定事件
|
||||
*/
|
||||
function bindActions() {
|
||||
$(".download-action").click(function () {
|
||||
window.open($(this).val())
|
||||
});
|
||||
@@ -142,12 +221,23 @@ $(function () {
|
||||
});
|
||||
|
||||
$(".app-delete").click(function () {
|
||||
var url = "/p/delete/" + $(this).attr("data");
|
||||
$.post(url, function(result){
|
||||
window.location.href = window.location.href
|
||||
window.location.reload
|
||||
var id = $(this).attr("data");
|
||||
var url = "/p/delete/" + id;
|
||||
var li = "package_index_" + id;
|
||||
console.log(li);
|
||||
var self = $("." + li);
|
||||
$.post(url, function (result) {
|
||||
if (result.success) {
|
||||
self.remove();
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
getPackageList();
|
||||
getWebHooks();
|
||||
|
||||
$("#js-app-short-copy-trigger").click(function () {
|
||||
new ClipboardJS('#js-app-short-copy-trigger', {
|
||||
text: function (trigger) {
|
||||
@@ -180,12 +270,12 @@ $(function () {
|
||||
|
||||
$("#delete-app").click(function () {
|
||||
var url = "/app/delete/" + $(this).attr("data");
|
||||
$.post(url, function(result){
|
||||
$.post(url, function (result) {
|
||||
window.location.href = "/apps"
|
||||
});
|
||||
});
|
||||
|
||||
$("#ding-ding-web-hook-name, #ding-ding-web-hook-url").bind("input propertychange",function(event){
|
||||
$("#ding-ding-web-hook-name, #ding-ding-web-hook-url").bind("input propertychange", function (event) {
|
||||
var name = $("#ding-ding-web-hook-name").val();
|
||||
var url = $("#ding-ding-web-hook-url").val();
|
||||
if (name.length > 0 && url.length > 0) {
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
<span itemprop="softwareVersion">[[${app.version}]] (Build [[${app.buildVersion}]]) -
|
||||
[[${app.currentPackage.displaySize}]]</span></p>
|
||||
<p>更新于: <span itemprop="datePublished">[[${app.currentPackage.displayTime}]]</span></p>
|
||||
<p>[[${app.currentPackage.message}]]</p>
|
||||
</div>
|
||||
<div class="action-animate">
|
||||
<input id="installURL" th:value="${app.currentPackage.installURL}" style="display: none" />
|
||||
|
||||
@@ -1,62 +1,67 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Stict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge">
|
||||
<meta name="renderer" content="webkit">
|
||||
<title class="ng-binding">[[${package.name}]] - 应用动态</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}" />
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/index.css}">
|
||||
<script type="text/javascript" th:src="@{/js/jquery-1.11.0.min.js}"></script>
|
||||
<script type="text/javascript" th:src="@{/js/clipboard.min.js}"></script>
|
||||
</head>
|
||||
|
||||
<body class="ng-scope">
|
||||
<nav class="navbar navbar-transparent fade-out navbar-black">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="/apps"><i class="icon-logo"></i></a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-ex1-collapse ng-scope">
|
||||
<div class="dropdown">
|
||||
<div>
|
||||
</div>
|
||||
<nav class="navbar navbar-transparent fade-out navbar-black">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="/apps"><i class="icon-logo"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="menu-toggle fade-out">
|
||||
<i class="icon-menu"></i>
|
||||
</div>
|
||||
<div class="navbar-wrapper ng-scope">
|
||||
<div ng-controller="NavbarController" class="ng-scope">
|
||||
<div class="navbar-header-wrap">
|
||||
<div class="middle-wrapper">
|
||||
<nav>
|
||||
<h1 class="navbar-title logo">
|
||||
<i class="icon-logo"></i>
|
||||
</h1>
|
||||
<i class="icon-angle-right"></i>
|
||||
<div class="navbar-title primary-title">
|
||||
<a class="ng-binding" href="/apps">我的应用</a>
|
||||
</div>
|
||||
<i class="icon-angle-right"></i>
|
||||
<div class="navbar-title secondary-title ng-binding" style="">
|
||||
[[${package.name}]]
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ngInclude: '/templates_manage/upload_modal.html' --><section data-ui-view="" class="ng-scope" style="">
|
||||
<div id="info-container" class="page-app app-activities">
|
||||
<div class="banner has-devices">
|
||||
<div class="middle-wrapper clearfix">
|
||||
<div id="app-activity-icon" class="pull-left icon-container appicon">
|
||||
<img th:src="'/' + ${package.icon}" width="100" height="100" class="change_icon ng-isolate-scope"/>
|
||||
<div class="collapse navbar-collapse navbar-ex1-collapse ng-scope">
|
||||
<div class="dropdown">
|
||||
<div>
|
||||
</div>
|
||||
<div class="badges">
|
||||
<span tooltip-top="" tooltip="复制到剪贴板" id="js-app-short-copy-trigger" class="short tooltip-top ng-binding ng-isolate-scope" th:value="${package.installPath}" copy-trigger="">[[${package.installPath}]]</span>
|
||||
<span class="apptype ng-binding" th:if="${#strings.containsIgnoreCase(package.platform,'ios')}">iOS</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="menu-toggle fade-out">
|
||||
<i class="icon-menu"></i>
|
||||
</div>
|
||||
<div class="navbar-wrapper ng-scope">
|
||||
<div ng-controller="NavbarController" class="ng-scope">
|
||||
<div class="navbar-header-wrap">
|
||||
<div class="middle-wrapper">
|
||||
<nav>
|
||||
<h1 class="navbar-title logo">
|
||||
<i class="icon-logo"></i>
|
||||
</h1>
|
||||
<i class="icon-angle-right"></i>
|
||||
<div class="navbar-title primary-title">
|
||||
<a class="ng-binding" href="/apps">我的应用</a>
|
||||
</div>
|
||||
<i class="icon-angle-right"></i>
|
||||
<div class="navbar-title secondary-title ng-binding" style="">
|
||||
[[${package.name}]]
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ngInclude: '/templates_manage/upload_modal.html' -->
|
||||
<section data-ui-view="" class="ng-scope" style="">
|
||||
<div id="info-container" class="page-app app-activities">
|
||||
<div class="banner has-devices">
|
||||
<div class="middle-wrapper clearfix">
|
||||
<div id="app-activity-icon" class="pull-left icon-container appicon">
|
||||
<img th:src="'/' + ${package.icon}" width="100" height="100" class="change_icon ng-isolate-scope" />
|
||||
</div>
|
||||
<div class="badges">
|
||||
<span tooltip-top="" tooltip="复制到剪贴板" id="js-app-short-copy-trigger"
|
||||
class="short tooltip-top ng-binding ng-isolate-scope" th:value="${package.installPath}"
|
||||
copy-trigger="">[[${package.installPath}]]</span>
|
||||
<span class="apptype ng-binding" th:if="${#strings.containsIgnoreCase(package.platform,'ios')}">iOS</span>
|
||||
<span class="apptype ng-binding" th:if="${#strings.containsIgnoreCase(package.platform,'android')}">Android</span>
|
||||
<span class="bundleid ng-binding">BundleID<b class="ng-binding"> [[${package.bundleID}]]</b></span>
|
||||
<span class="version ng-scope" th:if="${#strings.containsIgnoreCase(package.platform,'ios')}">iOS [[${package.minVersion}]] 或者高版本</span>
|
||||
@@ -83,53 +88,6 @@
|
||||
<div class="middle-wrapper" ng-show="activitiesReady">
|
||||
<!-- 更新面板-->
|
||||
<ul id="app-activity-panel" class="list-unstyled time-line">
|
||||
<li>
|
||||
<span class="dot"></span>
|
||||
<span class="filter ng-binding">版本更新</span>
|
||||
<span class="filter version-rollback ng-scope"></span>
|
||||
</li>
|
||||
<li>
|
||||
<div class="market-app-info">
|
||||
</div>
|
||||
</li>
|
||||
<li th:each="app,appStat : ${apps}">
|
||||
<div>
|
||||
<div class="directive-view-release">
|
||||
<i class="icon-upload-cloud2"></i>
|
||||
<b class="ng-binding">[[${app.version}]] (Build [[${app.buildVersion}]])</b>
|
||||
<div class="release-metainfo ng-hide">
|
||||
<small>
|
||||
<i class="icon-calendar"></i>
|
||||
<span class="ng-binding">[[${app.displayTime}]]</span>
|
||||
</small>
|
||||
</div>
|
||||
<div class="release-metainfo">
|
||||
<small>
|
||||
<i class="icon-calendar"></i>
|
||||
<span class="ng-binding">[[${app.displayTime}]]</span></small> ·
|
||||
<small class="ng-scope">[[${app.type}]]</small>
|
||||
<i class="ng-hide"> · </i>
|
||||
<small class="ng-binding ng-hide"></small>
|
||||
</div>
|
||||
<div class="release-actions">
|
||||
<button class="tooltip-top download-action" tooltip="下载原文件" th:value="${app.downloadURL}">
|
||||
<i class="icon-cloud-download"></i>
|
||||
<span class="ng-binding">[[${app.displaySize}]]</span>
|
||||
</button>
|
||||
<button class="preview" th:value="${app.previewURL}">
|
||||
<i class="icon-eye"></i>
|
||||
<span class="ng-binding">预览</span>
|
||||
</button>
|
||||
<button class="ng-scope app-delete" th:data="${app.id}" th:if="${appStat.index> 0}">
|
||||
<i class="icon-trash"></i>
|
||||
<span class="ng-binding">删除</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="more ng-hide" ng-show="currentApp.releases.current_page < currentApp.releases.total_pages">
|
||||
<button ng-click="moreRelease()" class="ng-binding">显示更多版本</button></li>
|
||||
</ul>
|
||||
<!--信息面板-->
|
||||
<div id="app-info-panel" class="app-info-form ng-pristine ng-valid ng-valid-required ng-valid-pattern ng-hide">
|
||||
|
||||
Reference in New Issue
Block a user