Merge branch 'master' of gitee.com:yizhaorong/intranet_app_manager
@@ -0,0 +1,4 @@
|
||||
*.js linguist-language=java
|
||||
*.css linguist-language=java
|
||||
*.html linguist-language=java
|
||||
*.java linguist-language=java
|
||||
@@ -13,6 +13,12 @@
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
##### 证书信任设置
|
||||
|
||||

|
||||
|
||||
#### 安装教程
|
||||
|
||||
项目使用 JAVA 开发,需要 JDK 1.8 运行环境,数据库使用的是 Mysql,需要安装 Mysql。JDK 安装直接找网上教程。
|
||||
@@ -33,7 +39,7 @@ mysql -u root -p
|
||||
|
||||
```shell
|
||||
# 创建库
|
||||
create database app_manager;
|
||||
create database app_manager DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
|
||||
```
|
||||
|
||||
##### HTTPS 证书
|
||||
@@ -56,7 +62,7 @@ create database app_manager;
|
||||
|
||||
#### 部署
|
||||
|
||||
本项目使用的是 80 和 443 端口,确保端口未被占用。
|
||||
本项目使用的是 80 和 443 端口,确保端口未被占用。可以配置文件中更改为别的端口。
|
||||
|
||||
> 启动服务
|
||||
|
||||
@@ -68,7 +74,11 @@ java -jar intranet_app_manager-1.0.0.jar
|
||||
|
||||
> 上传与安装
|
||||
|
||||
可以将 ipa 或 apk 拖入上传块中进行上传,上传完成后会在列表中展示。iOS 安装需要使用 https 协议,由于内网部署是用的自建证书,需要将 ca 添加到设备的信用列表中才可正常进行安装。
|
||||
可以将 ipa 或 apk 拖入上传块中进行上传,上传完成后会在列表中展示。
|
||||
|
||||
**注意**
|
||||
|
||||
本项目默认采用 http 方式访问,这样可以避免没必要的证书信任。iOS 安装需要使用 https 协议,由于内网部署是用的自建证书,需要将 ca 添加到设备的信用列表中才可正常进行安装。**设置抓包代理会影响自建证书**,导致无法下载。
|
||||
|
||||
#### Jenkins 集成
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ localityName_default=HangZhou
|
||||
organizationalUnitName=Organizational Unit Name (eg, section)
|
||||
organizationalUnitName_default=Domain Control Validated
|
||||
commonName=Internet Widgits Ltd
|
||||
commonName_default=192.168.0.*
|
||||
commonName_default=DigiCert APP Manager Root CA
|
||||
commonName_max=64
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 842 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 32 KiB |
@@ -45,9 +45,35 @@ public class PackageController {
|
||||
AppViewModel viewModel = this.appService.findByCode(code, id);
|
||||
request.setAttribute("app", viewModel);
|
||||
request.setAttribute("ca_path", this.pathManager.getCAPath());
|
||||
request.setAttribute("basePath", this.pathManager.getBaseURL(false));
|
||||
return "install";
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备列表
|
||||
* @param id
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/devices/{id}")
|
||||
public String devices(@PathVariable("id") String id, HttpServletRequest request) {
|
||||
PackageViewModel viewModel= this.packageService.findById(id);
|
||||
request.setAttribute("app", viewModel);
|
||||
return "devices";
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装教程
|
||||
* @param platform
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/guide/{platform}")
|
||||
public String guide(@PathVariable("platform") String platform, HttpServletRequest request) {
|
||||
request.setAttribute("platform", platform);
|
||||
return "guide";
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传包
|
||||
* @param file
|
||||
@@ -182,7 +208,7 @@ public class PackageController {
|
||||
// 生成文件名
|
||||
String newFileName = UUID.randomUUID().toString() + "." + ext;
|
||||
// 转存到 tmp
|
||||
String destPath = FileUtils.getTempDirectory() + newFileName;
|
||||
String destPath = FileUtils.getTempDirectoryPath() + File.separator + newFileName;
|
||||
srcFile.transferTo(new File(destPath));
|
||||
return destPath;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -39,5 +39,9 @@ public class Package {
|
||||
@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name="appId")
|
||||
private App app;
|
||||
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
// Provision 文件
|
||||
@JoinColumn(name = "provisionId",referencedColumnName = "id")
|
||||
private Provision provision;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.yzr.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name="tb_provision")
|
||||
@Setter
|
||||
@Getter
|
||||
public class Provision {
|
||||
// 主键
|
||||
@Id
|
||||
@GeneratedValue(generator = "system-uuid")
|
||||
@GenericGenerator(name = "system-uuid", strategy = "uuid")
|
||||
@Column(length = 32)
|
||||
private String id;
|
||||
private String teamName;
|
||||
private String teamID;
|
||||
private Date createDate;
|
||||
private Date expirationDate;
|
||||
private String UUID;
|
||||
@Column(length = 80000)
|
||||
private String[] devices;
|
||||
private int deviceCount;
|
||||
private String type;
|
||||
private boolean isEnterprise;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class PathManager {
|
||||
}
|
||||
int httpPort = Integer.parseInt(environment.getProperty("server.http.port"));
|
||||
int httpsPort = Integer.parseInt(environment.getProperty("server.port"));
|
||||
int port = isHttps ? httpPort : httpsPort;
|
||||
int port = isHttps ? httpsPort : httpPort;
|
||||
String protocol = isHttps ? "https" : "http";
|
||||
String portString = ":" + port;
|
||||
if (port == 80 || port == 443) {
|
||||
@@ -54,6 +54,14 @@ public class PathManager {
|
||||
}
|
||||
|
||||
String baseURL = protocol + "://" + domain + portString + "/";
|
||||
|
||||
//解决重复读配置文件
|
||||
if (isHttps) {
|
||||
httpsBaseURL = baseURL;
|
||||
} else {
|
||||
httpBaseURL = baseURL;
|
||||
}
|
||||
|
||||
return baseURL;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -88,7 +96,7 @@ public class PathManager {
|
||||
public static String getTempIconPath(Package aPackage) {
|
||||
if (aPackage == null) return null;
|
||||
StringBuilder path = new StringBuilder();
|
||||
path.append(FileUtils.getTempDirectoryPath()).append(aPackage.getPlatform());
|
||||
path.append(FileUtils.getTempDirectoryPath()).append(File.separator).append(aPackage.getPlatform());
|
||||
path.append(File.separator).append(aPackage.getBundleID());
|
||||
// 如果目录不存在,创建目录
|
||||
File dir = new File(path.toString());
|
||||
|
||||
@@ -14,7 +14,7 @@ public class ZipUtils {
|
||||
public static String unzip(String path) {
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
String destDirPath = System.getProperty("java.io.tmpdir") + start;
|
||||
String destDirPath = FileUtils.getTempDirectoryPath() + File.separator + start;
|
||||
ZipFile zipFile = new ZipFile(path);
|
||||
Enumeration<?> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package org.yzr.utils.ipa;
|
||||
|
||||
import com.dd.plist.NSArray;
|
||||
import com.dd.plist.NSDictionary;
|
||||
import com.dd.plist.NSObject;
|
||||
import com.dd.plist.PropertyListParser;
|
||||
import com.dd.plist.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -81,18 +78,26 @@ public class Plist {
|
||||
}
|
||||
|
||||
public List<String> arrayValueForPath(String path) {
|
||||
List<String> devices = new ArrayList<>();
|
||||
Object object = valueForKeyPath(path);
|
||||
if (object != null) {
|
||||
NSArray deviceArray = (NSArray)object;
|
||||
List<String> devices = new ArrayList<>();
|
||||
if (deviceArray != null && deviceArray.count() > 0) {
|
||||
for (int i = 0; i < deviceArray.count(); i++) {
|
||||
devices.add(deviceArray.objectAtIndex(i).toString());
|
||||
}
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
return null;
|
||||
return devices;
|
||||
}
|
||||
|
||||
public boolean boolValueForPath(String keyPath) {
|
||||
Object object = valueForKeyPath(keyPath);
|
||||
if (object instanceof NSNumber) {
|
||||
NSNumber number = (NSNumber)object;
|
||||
return number.boolValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package org.yzr.utils.ipa;
|
||||
|
||||
import com.dd.plist.NSDate;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class Provision {
|
||||
private String teamName;
|
||||
private String teamID;
|
||||
private Date createDate;
|
||||
private Date expirationDate;
|
||||
private String UUID;
|
||||
private List<String> devices;
|
||||
private int deviceCount;
|
||||
private String type;
|
||||
|
||||
public Provision(String appPath) {
|
||||
String profile = appPath + File.separator + "embedded.mobileprovision";
|
||||
try {
|
||||
boolean started = false;
|
||||
boolean ended = false;
|
||||
BufferedReader reader = new BufferedReader(new FileReader(profile));
|
||||
StringBuffer plist = new StringBuffer();
|
||||
String str = null;
|
||||
while ((str = reader.readLine()) != null) {
|
||||
if (str.contains("</plist>")) {
|
||||
ended = true;
|
||||
plist.append("</plist>").append("\n");
|
||||
} else if (started && !ended) {
|
||||
plist.append(str).append("\n");
|
||||
} else if (str.contains("<?xml")) {
|
||||
started = true;
|
||||
plist.append(str.substring(str.indexOf("<?xml"))).append("\n");
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
Plist provisionFile = Plist.parseWithString(plist.toString());
|
||||
this.devices = provisionFile.arrayValueForPath("ProvisionedDevices");
|
||||
this.deviceCount = this.devices.size();
|
||||
this.teamName = provisionFile.stringValueForPath("TeamName");
|
||||
this.teamID = provisionFile.arrayValueForPath("TeamIdentifier").get(0);
|
||||
this.createDate = ((NSDate)provisionFile.valueForKeyPath("CreationDate")).getDate();
|
||||
this.expirationDate = ((NSDate)provisionFile.valueForKeyPath("ExpirationDate")).getDate();
|
||||
this.UUID = provisionFile.stringValueForPath("UUID");
|
||||
this.type = this.deviceCount > 0 ? "Ad-hoc" : "Release";
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
package org.yzr.utils.parser;
|
||||
|
||||
import com.dd.plist.NSDate;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.yzr.model.Package;
|
||||
import org.yzr.utils.PNGConverter;
|
||||
import org.yzr.utils.PathManager;
|
||||
import org.yzr.utils.ZipUtils;
|
||||
import org.yzr.utils.ipa.Plist;
|
||||
import org.yzr.utils.ipa.Provision;
|
||||
import org.yzr.model.Provision;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class IPAParser implements PackageParser {
|
||||
@@ -49,7 +51,7 @@ public class IPAParser implements PackageParser {
|
||||
PNGConverter.convert(iconPath, iconTempPath);
|
||||
|
||||
// 解析 Provision
|
||||
Provision provision = new Provision(appPath);
|
||||
aPackage.setProvision(getProvision(appPath));
|
||||
|
||||
// 清除目录
|
||||
FileUtils.deleteDirectory(new File(targetPath));
|
||||
@@ -100,4 +102,44 @@ public class IPAParser implements PackageParser {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Provision getProvision(String appPath) {
|
||||
Provision provision = new Provision();
|
||||
String profile = appPath + File.separator + "embedded.mobileprovision";
|
||||
try {
|
||||
boolean started = false;
|
||||
boolean ended = false;
|
||||
BufferedReader reader = new BufferedReader(new FileReader(profile));
|
||||
StringBuffer plist = new StringBuffer();
|
||||
String str = null;
|
||||
while ((str = reader.readLine()) != null) {
|
||||
if (str.contains("</plist>")) {
|
||||
ended = true;
|
||||
plist.append("</plist>").append("\n");
|
||||
} else if (started && !ended) {
|
||||
plist.append(str).append("\n");
|
||||
} else if (str.contains("<?xml")) {
|
||||
started = true;
|
||||
plist.append(str.substring(str.indexOf("<?xml"))).append("\n");
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
Plist provisionFile = Plist.parseWithString(plist.toString());
|
||||
provision.setEnterprise(provisionFile.boolValueForPath("ProvisionsAllDevices"));
|
||||
List<String> provisionedDevices = provisionFile.arrayValueForPath("ProvisionedDevices");
|
||||
String[] devices = new String[provisionedDevices.size()];
|
||||
devices = provisionedDevices.toArray(devices);
|
||||
provision.setDevices(devices);
|
||||
provision.setDeviceCount(devices.length);
|
||||
provision.setTeamName(provisionFile.stringValueForPath("TeamName"));
|
||||
provision.setTeamID(provisionFile.arrayValueForPath("TeamIdentifier").get(0));
|
||||
provision.setCreateDate(((NSDate)provisionFile.valueForKeyPath("CreationDate")).getDate());
|
||||
provision.setExpirationDate(((NSDate)provisionFile.valueForKeyPath("ExpirationDate")).getDate());
|
||||
provision.setUUID(provisionFile.stringValueForPath("UUID"));
|
||||
provision.setType(provision.getDeviceCount() > 0 ? "AdHoc" : "Release");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return provision;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ 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;
|
||||
|
||||
|
||||
@Getter
|
||||
@@ -25,6 +28,9 @@ public class PackageViewModel {
|
||||
private String displaySize;
|
||||
private String displayTime;
|
||||
private boolean iOS;
|
||||
private String type;
|
||||
private List<String> devices;
|
||||
private int deviceCount;
|
||||
|
||||
public PackageViewModel(Package aPackage, PathManager pathManager) {
|
||||
this.downloadURL = pathManager.getBaseURL(false) + "p/" + aPackage.getId();
|
||||
@@ -51,6 +57,27 @@ 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 (aPackage.getProvision() == null) {
|
||||
this.type = "内测版";
|
||||
} else {
|
||||
if (aPackage.getProvision().isEnterprise()) {
|
||||
this.type = "企业版";
|
||||
} else {
|
||||
if ("AdHoc".equalsIgnoreCase(aPackage.getProvision().getType())) {
|
||||
this.type = "内测版";
|
||||
} else {
|
||||
this.type = "商店版";
|
||||
}
|
||||
this.deviceCount = aPackage.getProvision().getDeviceCount();
|
||||
if (aPackage.getProvision().getDeviceCount() > 0) {
|
||||
this.devices = Arrays.asList(aPackage.getProvision().getDevices());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.type = "内测版";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
########################################################
|
||||
### Mysql
|
||||
########################################################
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/app_manager
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/app_manager?useUnicode=true&characterEncoding=utf-8
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
@@ -41,4 +41,4 @@ server.ssl.key-alias=1
|
||||
server.port=443
|
||||
server.http.port=80
|
||||
config.debug=debug
|
||||
server.domain=192.168.0.108
|
||||
server.domain=127.0.0.1
|
||||
@@ -1,459 +0,0 @@
|
||||
@font-face {
|
||||
font-family: partner;
|
||||
src: url(./fonts/ipartner.eot?rkodm6);
|
||||
src: url(./fonts/ipartner.eot?rkodm6#iefix) format("embedded-opentype"), url(./fonts/ipartner.ttf?rkodm6) format("truetype"), url(./fonts/ipartner.woff?rkodm6) format("woff"), url(./fonts/ipartner.svg?rkodm6#ipartner) format("svg");
|
||||
font-weight: 400;
|
||||
font-style: normal
|
||||
}
|
||||
|
||||
[class*=" ipartner-"], [class^=ipartner-] {
|
||||
font-family: partner!important;
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
}
|
||||
|
||||
.ipartner-swift:before {
|
||||
content: "\e900"
|
||||
}
|
||||
|
||||
.ipartner-qingcloud:before {
|
||||
content: "\e902"
|
||||
}
|
||||
|
||||
.ipartner-devlink:before {
|
||||
content: "\e920"
|
||||
}
|
||||
|
||||
.ipartner-logo-pingxx:before {
|
||||
content: "\e921"
|
||||
}
|
||||
|
||||
.ipartner-logo-qiniu:before {
|
||||
content: "\e922"
|
||||
}
|
||||
|
||||
.ipartner-logo-leancloud:before {
|
||||
content: "\e923"
|
||||
}
|
||||
|
||||
.ipartner-logo-flowci:before {
|
||||
content: "\e924"
|
||||
}
|
||||
|
||||
.ipartner-deveco:before {
|
||||
content: "\e925"
|
||||
}
|
||||
|
||||
.ipartner-wilddog:before {
|
||||
content: "\e926"
|
||||
}
|
||||
|
||||
.ipartner-xitu:before {
|
||||
content: "\e927"
|
||||
}
|
||||
|
||||
.ipartner-36kr:before {
|
||||
content: "\e928"
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: icomoon;
|
||||
src: url(./fonts/icomoon.eot?wcusdg);
|
||||
src: url(./fonts/icomoon.eot?wcusdg#iefix) format("embedded-opentype"), url(./fonts/icomoon.ttf?wcusdg) format("truetype"), url(./fonts/icomoon.woff?wcusdg) format("woff"), url(./fonts/icomoon.svg?wcusdg#icomoon) format("svg");
|
||||
font-weight: 400;
|
||||
font-style: normal
|
||||
}
|
||||
|
||||
[class*=" icon-"], [class^=icon-] {
|
||||
font-family: icomoon!important;
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
}
|
||||
|
||||
.icon-cake:before {
|
||||
content: "\e900"
|
||||
}
|
||||
|
||||
.icon-weibo:before {
|
||||
content: "\e600"
|
||||
}
|
||||
|
||||
.icon-wechat:before {
|
||||
content: "\e601"
|
||||
}
|
||||
|
||||
.icon-firim:before {
|
||||
content: "\e602"
|
||||
}
|
||||
|
||||
.icon-bug:before {
|
||||
content: "\e603"
|
||||
}
|
||||
|
||||
.icon-ion:before {
|
||||
content: "\e604"
|
||||
}
|
||||
|
||||
.icon-angle-right:before {
|
||||
content: "\e606"
|
||||
}
|
||||
|
||||
.icon-cloud-download:before {
|
||||
content: "\e607"
|
||||
}
|
||||
|
||||
.icon-question:before {
|
||||
content: "\e608"
|
||||
}
|
||||
|
||||
.icon-optimize-upload:before {
|
||||
content: "\e609"
|
||||
}
|
||||
|
||||
.icon-console:before {
|
||||
content: "\e60a"
|
||||
}
|
||||
|
||||
.icon-microscope:before {
|
||||
content: "\e60b"
|
||||
}
|
||||
|
||||
.icon-user-access:before {
|
||||
content: "\e60c"
|
||||
}
|
||||
|
||||
.icon-logo-jiecao:before {
|
||||
content: "\e60d"
|
||||
}
|
||||
|
||||
.icon-m:before {
|
||||
content: "\e60e"
|
||||
}
|
||||
|
||||
.icon-f:before {
|
||||
content: "\e60f"
|
||||
}
|
||||
|
||||
.icon-plugin:before {
|
||||
content: "\e610"
|
||||
}
|
||||
|
||||
.icon-launch:before {
|
||||
content: "\e611"
|
||||
}
|
||||
|
||||
.icon-brace-left:before {
|
||||
content: "\e613"
|
||||
}
|
||||
|
||||
.icon-logo:before {
|
||||
content: "\e620"
|
||||
}
|
||||
|
||||
.icon-thumbsup:before {
|
||||
content: "\e615"
|
||||
}
|
||||
|
||||
.icon-webhooks:before {
|
||||
content: "\e616"
|
||||
}
|
||||
|
||||
.icon-brace-right:before {
|
||||
content: "\e617"
|
||||
}
|
||||
|
||||
.icon-comma-eye:before {
|
||||
content: "\e618"
|
||||
}
|
||||
|
||||
.icon-mouth:before {
|
||||
content: "\e619"
|
||||
}
|
||||
|
||||
.icon-brace-hor:before {
|
||||
content: "\e61a"
|
||||
}
|
||||
|
||||
.icon-brace-right-b:before {
|
||||
content: "\e61b"
|
||||
}
|
||||
|
||||
.icon-brace-left-b:before {
|
||||
content: "\e61c"
|
||||
}
|
||||
|
||||
.icon-brace-box:before {
|
||||
content: "\e61d"
|
||||
}
|
||||
|
||||
.icon-menu:before {
|
||||
content: "\e61e"
|
||||
}
|
||||
|
||||
.icon-app:before {
|
||||
content: "\e61f"
|
||||
}
|
||||
|
||||
.icon-box:before {
|
||||
content: "\e620"
|
||||
}
|
||||
|
||||
.icon-combo:before {
|
||||
content: "\e621"
|
||||
}
|
||||
|
||||
.icon-device:before {
|
||||
content: "\e622"
|
||||
}
|
||||
|
||||
.icon-face:before {
|
||||
content: "\e623"
|
||||
}
|
||||
|
||||
.icon-file:before {
|
||||
content: "\e624"
|
||||
}
|
||||
|
||||
.icon-msg:before {
|
||||
content: "\e625"
|
||||
}
|
||||
|
||||
.icon-pen:before {
|
||||
content: "\e626"
|
||||
}
|
||||
|
||||
.icon-ipa:before {
|
||||
content: "\e627"
|
||||
}
|
||||
|
||||
.icon-lock2:before {
|
||||
content: "\e628"
|
||||
}
|
||||
|
||||
.icon-qrcode:before {
|
||||
content: "\e629"
|
||||
}
|
||||
|
||||
.icon-rollback:before {
|
||||
content: "\e62a"
|
||||
}
|
||||
|
||||
.icon-eye:before {
|
||||
content: "\e62b"
|
||||
}
|
||||
|
||||
.icon-plus:before {
|
||||
content: "\e62c"
|
||||
}
|
||||
|
||||
.icon-chart:before {
|
||||
content: "\e62d"
|
||||
}
|
||||
|
||||
.icon-idea:before {
|
||||
content: "\e62e"
|
||||
}
|
||||
|
||||
.icon-owner:before {
|
||||
content: "\e62f"
|
||||
}
|
||||
|
||||
.icon-search:before {
|
||||
content: "\e630"
|
||||
}
|
||||
|
||||
.icon-studio:before {
|
||||
content: "\e631"
|
||||
}
|
||||
|
||||
.icon-upload-cloud2:before {
|
||||
content: "\e632"
|
||||
}
|
||||
|
||||
.icon-android:before {
|
||||
content: "\e633"
|
||||
}
|
||||
|
||||
.icon-trash:before {
|
||||
content: "\e634"
|
||||
}
|
||||
|
||||
.icon-attachment:before {
|
||||
content: "\e635"
|
||||
}
|
||||
|
||||
.icon-apple:before {
|
||||
content: "\e636"
|
||||
}
|
||||
|
||||
.icon-calendar:before {
|
||||
content: "\e637"
|
||||
}
|
||||
|
||||
.icon-calendar2:before {
|
||||
content: "\e638"
|
||||
}
|
||||
|
||||
.icon-eye-close:before {
|
||||
content: "\e639"
|
||||
}
|
||||
|
||||
.icon-reply:before {
|
||||
content: "\e63a"
|
||||
}
|
||||
|
||||
.icon-email:before {
|
||||
content: "\e63b"
|
||||
}
|
||||
|
||||
.icon-error2:before {
|
||||
content: "\e63c"
|
||||
}
|
||||
|
||||
.icon-cross:before {
|
||||
content: "\e63d"
|
||||
}
|
||||
|
||||
.icon-user-plus:before {
|
||||
content: "\e63e"
|
||||
}
|
||||
|
||||
.icon-ios:before {
|
||||
content: "\e63f"
|
||||
}
|
||||
|
||||
.icon-filter:before {
|
||||
content: "\e640"
|
||||
}
|
||||
|
||||
.icon-test-speed:before {
|
||||
content: "\e641"
|
||||
}
|
||||
|
||||
.icon-udid:before {
|
||||
content: "\e642"
|
||||
}
|
||||
|
||||
.icon-update:before {
|
||||
content: "\e643"
|
||||
}
|
||||
|
||||
.icon-comma:before {
|
||||
content: "\e644"
|
||||
}
|
||||
|
||||
.icon-i:before {
|
||||
content: "\e645"
|
||||
}
|
||||
|
||||
.icon-r:before {
|
||||
content: "\e646"
|
||||
}
|
||||
|
||||
.icon-f-dot:before {
|
||||
content: "\e647"
|
||||
}
|
||||
|
||||
.icon-layers:before {
|
||||
content: "\e648"
|
||||
}
|
||||
|
||||
.icon-news:before {
|
||||
content: "\e649"
|
||||
}
|
||||
|
||||
.icon-percent:before {
|
||||
content: "\e64a"
|
||||
}
|
||||
|
||||
.icon-bughd:before {
|
||||
content: "\e64b"
|
||||
}
|
||||
|
||||
.icon-incode:before {
|
||||
content: "\e64c"
|
||||
}
|
||||
|
||||
.icon-message:before {
|
||||
content: "\e64d"
|
||||
}
|
||||
|
||||
.icon-eclipse:before {
|
||||
content: "\e64e"
|
||||
}
|
||||
|
||||
.icon-turkey:before {
|
||||
content: "\e901"
|
||||
}
|
||||
|
||||
.icon-jenkins:before {
|
||||
content: "\e902"
|
||||
}
|
||||
|
||||
.icon-gradle:before {
|
||||
content: "\e903"
|
||||
}
|
||||
|
||||
.icon-statistics:before {
|
||||
content: "\e904"
|
||||
}
|
||||
|
||||
.icon-done:before {
|
||||
content: "\e905"
|
||||
}
|
||||
|
||||
.icon-qiniu:before {
|
||||
content: "\e906"
|
||||
}
|
||||
|
||||
.icon-logo-leancloud:before {
|
||||
content: "\e907"
|
||||
}
|
||||
|
||||
.icon-logo-jd:before {
|
||||
content: "\e908"
|
||||
}
|
||||
|
||||
.icon-logo-xiachufang:before {
|
||||
content: "\e909"
|
||||
}
|
||||
|
||||
.icon-logo-ebaoyang:before {
|
||||
content: "\e90a"
|
||||
}
|
||||
|
||||
.icon-logo-jumei:before {
|
||||
content: "\e90b"
|
||||
}
|
||||
|
||||
.icon-cart:before {
|
||||
content: "\e90c"
|
||||
}
|
||||
|
||||
.icon-users:before {
|
||||
content: "\e90d"
|
||||
}
|
||||
|
||||
.icon-spinner3:before {
|
||||
content: "\e97c"
|
||||
}
|
||||
|
||||
.icon-infinite:before {
|
||||
content: "\ea2f"
|
||||
}
|
||||
|
||||
.icon-spinner:before {
|
||||
content: "\f110"
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.6 MiB |
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<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">
|
||||
<meta name="viewport"
|
||||
content="minimal-ui,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
|
||||
|
||||
<title>[[${app.name}]]-设备列表</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}" />
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="card container">
|
||||
<div class="list-group text-center">
|
||||
<a href="#" class="list-group-item active">
|
||||
<h4 class="list-group-item-heading">
|
||||
设备ID
|
||||
</h4>
|
||||
</a>
|
||||
<a class="list-group-item" href="#" th:each="device,appStat : ${app.devices}">
|
||||
[[${device}]]
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!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">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
|
||||
<title class="ng-binding">[[${platform}]] - 安装教程</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}" />
|
||||
<link rel="stylesheet" th:href="@{/css/icons.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/manage.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/index.css}">
|
||||
<script type="text/javascript" th:src="@{/js/jquery-1.11.0.min.js}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="guide">
|
||||
<img th:src="@{/images/install_crt.gif}"/>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -8,9 +8,7 @@
|
||||
|
||||
<title>应用列表</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}" />
|
||||
<link rel="stylesheet" th:href="@{/css/icons.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/manage.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/index.css}">
|
||||
|
||||
<script type="text/javascript" th:src="@{/js/jquery-1.11.0.min.js}"></script>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p class="release-type wrapper">内测版</p>
|
||||
<p class="release-type wrapper">[[${app.currentPackage.type}]]</p>
|
||||
|
||||
<h1 class="name wrapper">
|
||||
<span class="icon-warp">
|
||||
@@ -54,7 +54,7 @@
|
||||
<p class="scan-tips">扫描二维码下载<br>或用手机浏览器输入这个网址: <span
|
||||
class="text-black">[[${app.installPath}]]</span></p>
|
||||
<div class="release-info">
|
||||
<p>内测版 -
|
||||
<p>[[${app.currentPackage.type}]] -
|
||||
<span itemprop="softwareVersion">[[${app.version}]] (Build [[${app.buildVersion}]]) -
|
||||
[[${app.currentPackage.displaySize}]]</span></p>
|
||||
<p>更新于: <span itemprop="datePublished">[[${app.currentPackage.displayTime}]]</span></p>
|
||||
@@ -64,11 +64,21 @@
|
||||
<div class="action-animate-text" id="install">下载安装</div>
|
||||
<div class="action-animate-active"></div>
|
||||
</div>
|
||||
<div class="action-animate">
|
||||
<div class="action-animate" th:if="${#strings.containsIgnoreCase(app.platform,'ios')}">
|
||||
<input id="crtURL" th:value="${ca_path}" style="display: none"/>
|
||||
<div class="action-animate-text" id="installCRT">安装证书</div>
|
||||
<div class="action-animate-active"></div>
|
||||
</div>
|
||||
<div class="action-animate" th:if="${app.currentPackage.deviceCount > 0}">
|
||||
<input id="devices" th:value="${basePath} + 'devices/' + ${app.currentPackage.id}" style="display: none"/>
|
||||
<div class="action-animate-text" id="showDevices">查看设备列表</div>
|
||||
<div class="action-animate-active"></div>
|
||||
</div>
|
||||
<div class="action-animate" th:if="${#strings.containsIgnoreCase(app.platform,'ios')}">
|
||||
<input id="trust_crt" th:value="${basePath} + 'guide/ios'" style="display: none"/>
|
||||
<div class="action-animate-text" id="trustCTR">证书信任教程</div>
|
||||
<div class="action-animate-active"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -86,6 +96,14 @@
|
||||
window.open($("#crtURL").val())
|
||||
})
|
||||
|
||||
$("#showDevices").click(function () {
|
||||
window.open($("#devices").val())
|
||||
})
|
||||
|
||||
$("#trustCTR").click(function () {
|
||||
window.open($("#trust_crt").val())
|
||||
})
|
||||
|
||||
var codeData = $("#qrcode").attr("data");
|
||||
new QRCode("qrcode", {
|
||||
text: codeData,
|
||||
|
||||
@@ -8,11 +8,10 @@
|
||||
|
||||
<title class="ng-binding">[[${package.name}]] - 应用动态</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}" />
|
||||
<link rel="stylesheet" th:href="@{/css/icons.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/manage.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">
|
||||
@@ -108,7 +107,7 @@
|
||||
<small>
|
||||
<i class="icon-calendar"></i>
|
||||
<span class="ng-binding">[[${app.displayTime}]]</span></small> ·
|
||||
<small class="ng-scope">内测版</small>
|
||||
<small class="ng-scope">[[${app.type}]]</small>
|
||||
<i class="ng-hide"> · </i>
|
||||
<small class="ng-binding ng-hide"></small>
|
||||
</div>
|
||||
@@ -155,6 +154,14 @@
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
$("#js-app-short-copy-trigger").click(function(){
|
||||
new ClipboardJS('#js-app-short-copy-trigger', {
|
||||
text: function(trigger) {
|
||||
return trigger.getAttribute('value');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||