新增钉钉机器人支持

This commit is contained in:
yizhaorong
2019-08-10 23:32:35 +08:00
parent e62c5fd782
commit f58e79634f
15 changed files with 2276 additions and 186 deletions
@@ -11,6 +11,7 @@ import org.yzr.model.App;
import org.yzr.model.Package; import org.yzr.model.Package;
import org.yzr.service.AppService; import org.yzr.service.AppService;
import org.yzr.service.PackageService; import org.yzr.service.PackageService;
import org.yzr.utils.DingdingUtils;
import org.yzr.utils.PathManager; import org.yzr.utils.PathManager;
import org.yzr.utils.ipa.PlistGenerator; import org.yzr.utils.ipa.PlistGenerator;
import org.yzr.vo.AppViewModel; import org.yzr.vo.AppViewModel;
@@ -94,6 +95,8 @@ public class PackageController {
app = this.appService.save(app); app = this.appService.save(app);
// URL // URL
String codeURL = this.pathManager.getBaseURL(false) + "p/code/" + app.getCurrentPackage().getId(); String codeURL = this.pathManager.getBaseURL(false) + "p/code/" + app.getCurrentPackage().getId();
// 发送钉钉消息
DingdingUtils.sendMarkdown(app, pathManager);
map.put("code", codeURL); map.put("code", codeURL);
map.put("success", true); map.put("success", true);
} catch (Exception e) { } catch (Exception e) {
@@ -1,38 +1,27 @@
package org.yzr.controller; package org.yzr.controller;
import net.glxn.qrgen.javase.QRCode; import org.springframework.beans.BeanUtils;
import org.apache.commons.io.FileUtils; import org.springframework.beans.BeansException;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.bind.annotation.PostMapping;
import org.yzr.model.App; import org.springframework.web.bind.annotation.ResponseBody;
import org.yzr.model.Package; import org.yzr.model.WebHook;
import org.yzr.service.AppService; import org.yzr.service.WebHookService;
import org.yzr.service.PackageService;
import org.yzr.utils.PathManager;
import org.yzr.utils.ipa.PlistGenerator;
import org.yzr.vo.AppViewModel;
import org.yzr.vo.PackageViewModel;
import org.yzr.vo.WebHookViewModel; import org.yzr.vo.WebHookViewModel;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import java.util.ArrayList;
import java.io.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
@Controller @Controller
public class WebHookController { public class WebHookController {
@Resource @Resource
private AppService appService; private WebHookService webHookService;
@Resource
private PackageService packageService;
@Resource
private PathManager pathManager;
/** /**
* 添加webHook * 添加webHook
@@ -44,6 +33,12 @@ public class WebHookController {
@ResponseBody @ResponseBody
public Map<String, Object> add(WebHookViewModel viewModel, HttpServletRequest request) { public Map<String, Object> add(WebHookViewModel viewModel, HttpServletRequest request) {
Map<String , Object> result = new HashMap<>(); Map<String , Object> result = new HashMap<>();
WebHook webHook = this.webHookService.save(viewModel);
if (webHook != null) {
result.put("success", true);
} else {
result.put("success", false);
}
return result; return result;
} }
@@ -57,6 +52,12 @@ public class WebHookController {
@ResponseBody @ResponseBody
public Map<String, Object> delete(WebHookViewModel viewModel, HttpServletRequest request) { public Map<String, Object> delete(WebHookViewModel viewModel, HttpServletRequest request) {
Map<String , Object> result = new HashMap<>(); Map<String , Object> result = new HashMap<>();
try {
this.webHookService.deleteById(viewModel.getId());
result.put("success", true);
} catch (Exception e) {
result.put("success", false);
}
return result; return result;
} }
@@ -70,7 +71,38 @@ public class WebHookController {
@ResponseBody @ResponseBody
public Map<String, Object> update(WebHookViewModel viewModel, HttpServletRequest request) { public Map<String, Object> update(WebHookViewModel viewModel, HttpServletRequest request) {
Map<String , Object> result = new HashMap<>(); Map<String , Object> result = new HashMap<>();
try {
this.webHookService.update(viewModel);
result.put("success", true);
} catch (Exception e) {
result.put("success", false);
}
return result; return result;
} }
/**
* 获取 webHook 列表
* @param id
* @param request
* @return
*/
@PostMapping("/webHook/find/{id}")
@ResponseBody
public List<WebHookViewModel> findById(@PathVariable("id") String id, HttpServletRequest request) {
List<WebHookViewModel> viewModels = new ArrayList<>();
try {
List<WebHook> webHookList = this.webHookService.findByAppId(id);
for (WebHook webHook :
webHookList) {
WebHookViewModel viewModel = new WebHookViewModel();
BeanUtils.copyProperties(webHook, viewModel);
viewModels.add(viewModel);
}
} catch (BeansException e) {
e.printStackTrace();
}
return viewModels;
}
} }
@@ -30,6 +30,12 @@ public class AppService {
public App save(App app) { public App save(App app) {
App app1 = this.appDao.save(app); App app1 = this.appDao.save(app);
app1.getCurrentPackage(); app1.getCurrentPackage();
try {
// 触发级联查询
app1.getWebHookList().forEach(webHook -> {});
} catch (Exception e) {
e.printStackTrace();
}
return app1; return app1;
} }
@@ -71,6 +77,7 @@ public class AppService {
app.setName(aPackage.getName()); app.setName(aPackage.getName());
// 触发级联查询 // 触发级联查询
app.getPackageList().forEach(p->{}); app.getPackageList().forEach(p->{});
app.getWebHookList().forEach(webHook -> {});
} }
if (app.getPackageList() == null) { if (app.getPackageList() == null) {
app.setPackageList(new ArrayList<>()); app.setPackageList(new ArrayList<>());
@@ -9,6 +9,7 @@ import org.yzr.dao.AppDao;
import org.yzr.dao.PackageDao; import org.yzr.dao.PackageDao;
import org.yzr.model.App; import org.yzr.model.App;
import org.yzr.model.Package; import org.yzr.model.Package;
import org.yzr.utils.ImageUtils;
import org.yzr.utils.PathManager; import org.yzr.utils.PathManager;
import org.yzr.utils.ipa.PlistGenerator; import org.yzr.utils.ipa.PlistGenerator;
import org.yzr.utils.parser.ParserClient; import org.yzr.utils.parser.ParserClient;
@@ -38,8 +39,9 @@ public class PackageService {
String tempIconPath = PathManager.getTempIconPath(aPackage); String tempIconPath = PathManager.getTempIconPath(aPackage);
String iconPath = packagePath + File.separator + "icon.png"; String iconPath = packagePath + File.separator + "icon.png";
String sourcePath = packagePath + File.separator + fileName; String sourcePath = packagePath + File.separator + fileName;
// 拷贝图标 // 拷贝图标
FileUtils.copyFile(new File(tempIconPath), new File(iconPath)); ImageUtils.resize(tempIconPath, iconPath, 192, 192);
// 源文件 // 源文件
FileUtils.copyFile(new File(filePath), new File(sourcePath)); FileUtils.copyFile(new File(filePath), new File(sourcePath));
@@ -1,22 +1,38 @@
package org.yzr.service; package org.yzr.service;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.yzr.dao.AppDao;
import org.yzr.dao.WebHookDao; import org.yzr.dao.WebHookDao;
import org.yzr.model.App;
import org.yzr.model.WebHook; import org.yzr.model.WebHook;
import org.yzr.vo.WebHookViewModel;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service @Service
public class WebHookService { public class WebHookService {
@Resource @Resource
private WebHookDao webHookDao; private WebHookDao webHookDao;
@Resource
private AppDao appDao;
@Transactional @Transactional
public WebHook save(WebHook webHook) { public WebHook save(WebHookViewModel viewModel) {
return this.webHookDao.save(webHook); App app = appDao.findById(viewModel.getAppId()).get();
if (app != null) {
WebHook webHook = new WebHook();
BeanUtils.copyProperties(viewModel, webHook);
webHook.setApp(app);
webHook.setType(WebHook.WEB_HOOK_TYPE_DING_DING);
return webHookDao.save(webHook);
}
return null;
} }
@Transactional @Transactional
@@ -33,4 +49,28 @@ public class WebHookService {
} }
} }
@Transactional
public List<WebHook> findByAppId(String appId) {
App app = appDao.findById(appId).get();
if (app != null) {
List<WebHook> webHookList = app.getWebHookList();
List<WebHook> webHooks = new ArrayList<>();
for (WebHook webHook :
webHookList) {
webHooks.add(webHook);
}
return webHooks;
}
return new ArrayList<>();
}
public void update(WebHookViewModel viewModel) {
WebHook webHook = webHookDao.findById(viewModel.getId()).get();
if (webHook != null) {
webHook.setName(viewModel.getName());
webHook.setUrl(viewModel.getUrl());
webHookDao.save(webHook);
}
}
} }
+27 -9
View File
@@ -2,11 +2,10 @@ package org.yzr.utils;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import okhttp3.*; import okhttp3.*;
import org.springframework.http.converter.json.GsonBuilderUtils; import org.yzr.model.App;
import org.yzr.model.WebHook;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public class DingdingUtils { public class DingdingUtils {
@@ -18,7 +17,7 @@ public class DingdingUtils {
* @param webhook 钉钉自定义机器人webhook * @param webhook 钉钉自定义机器人webhook
* @return * @return
*/ */
public static boolean sendToDingding(String jsonString, String webhook) { private static boolean sendToDingding(String jsonString, String webhook) {
try{ try{
String type = "application/json; charset=utf-8"; String type = "application/json; charset=utf-8";
RequestBody body = RequestBody.create(MediaType.parse(type), jsonString); RequestBody body = RequestBody.create(MediaType.parse(type), jsonString);
@@ -38,14 +37,33 @@ public class DingdingUtils {
} }
} }
public static boolean sendMarkdown() { public static void sendMarkdown(App app, PathManager pathManager) {
if (app.getWebHookList() == null || app.getWebHookList().size() < 1) {
return;
}
Map<String, Object> markdown = new HashMap<>(); Map<String, Object> markdown = new HashMap<>();
markdown.put("title", "时代的火车向前开"); markdown.put("title", app.getName());
markdown.put("text", "[ticket(Android)更新](https://www.baidu.com) \n\n ![alt 啊](https://ali-fir-pro-icon.fir.im/62658a54e48ea4b6115da07955c87e20ef4580b9?auth_key=1565408715-0-0-160b683eadd339c11a4ab1c701cda254&tmp=1565406915.71304) \n\n 链接:[https://fir.im/cq7f](https://fir.im/cq7f) \n\n 版本: 1.0 (Build: 1)"); String url = pathManager.getBaseURL(false) + "s/" + app.getShortCode();
String platform = "iOS";
if (app.getPlatform().equalsIgnoreCase("android")) {
platform = "Android";
}
String appInfo = String.format("[%s(%s)更新](%s)", app.getName(), platform, url);
// 将图片转为 base64, 内网 ip 钉钉无法访问,直接给图片数据
String iconPath = PathManager.getFullPath(app.getCurrentPackage()) + "icon.png";
String icon = "data:image/png;base64," + ImageUtils.convertImageToBase64(iconPath);
String pathInfo = String.format("![%s](%s)", app.getName(), icon);
String otherInfo = String.format("链接:[%s](%s) \n\n 版本:%s (Build: %s)", url, url, app.getCurrentPackage().getVersion(), app.getCurrentPackage().getBuildVersion());
String text = appInfo + " \n\n " + pathInfo + " \n\n " + otherInfo;
markdown.put("text", text);
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("msgtype", "markdown"); jsonObject.put("msgtype", "markdown");
jsonObject.put("markdown", markdown); jsonObject.put("markdown", markdown);
String json = jsonObject.toJSONString();
return sendToDingding(jsonObject.toJSONString(), "https://oapi.dingtalk.com/robot/send?access_token=a2030da1a934473cc8f950d342888321387ed65f92bcf16a6bf4c048903e5a0e"); for (WebHook webHook :
app.getWebHookList()) {
sendToDingding(json, webHook.getUrl());
}
} }
} }
@@ -0,0 +1,61 @@
package org.yzr.utils;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.util.Base64Utils;
import javax.imageio.ImageIO;
public class ImageUtils {
/**
* 将图片转换为 Base64
* @param filePath
* @return
*/
public static String convertImageToBase64(String filePath) {
InputStream in = null;
byte[] data = null;
//读取图片字节数组
try {
in = new FileInputStream(filePath);
data = new byte[in.available()];
in.read(data);
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
//对字节数组Base64编码
return Base64Utils.encodeToString(data);
}
/**
* 重置图片大小
* @param soureFilePath
* @param targetFilePath
* @param height
* @param width
*/
public static void resize(String soureFilePath, String targetFilePath, int width, int height) {
try {
File input = new File(soureFilePath);
File output = new File(targetFilePath);
output.mkdirs();
BufferedImage image = ImageIO.read(input);
Image tmp = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage resized = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = resized.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
ImageIO.write(resized, "png", output);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -22,8 +22,16 @@ public class APKParser implements PackageParser {
aPackage.setSize(file.length()); aPackage.setSize(file.length());
ApkMeta meta = apkFile.getApkMeta(); ApkMeta meta = apkFile.getApkMeta();
aPackage.setName(meta.getName()); aPackage.setName(meta.getName());
aPackage.setVersion(meta.getPlatformBuildVersionName()); String version = meta.getVersionName();
aPackage.setBuildVersion(meta.getPlatformBuildVersionCode()); String buildVersion = meta.getVersionCode() + "";
if (version.length() < 1) {
version = meta.getPlatformBuildVersionName();
}
if (buildVersion.length() < 1) {
buildVersion = meta.getPlatformBuildVersionCode();
}
aPackage.setVersion(version);
aPackage.setBuildVersion(buildVersion);
aPackage.setBundleID(meta.getPackageName()); aPackage.setBundleID(meta.getPackageName());
aPackage.setMinVersion(meta.getMinSdkVersion()); aPackage.setMinVersion(meta.getMinSdkVersion());
aPackage.setPlatform("android"); aPackage.setPlatform("android");
@@ -4,6 +4,7 @@ import lombok.Data;
@Data @Data
public class WebHookViewModel { public class WebHookViewModel {
private String id;
private String appId; private String appId;
+1 -1
View File
@@ -41,4 +41,4 @@ server.ssl.key-alias=1
server.port=443 server.port=443
server.http.port=80 server.http.port=80
config.debug=debug config.debug=debug
server.domain=127.0.0.1 server.domain=192.168.199.169
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+205
View File
@@ -0,0 +1,205 @@
/**
* 获取 webHook 列表
*/
function getWebHooks() {
var appId =$("#appId").val();
var url = "/webHook/find/" + appId;
$.post(url, function(result){
$(".configrations").children(".config-name").remove();
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>';
}
$(".configrations").append(content);
});
}
/**
* 编辑 webHook
* @param e
*/
function editWebHook(e) {
var id = $("#webHookId").val();
if (id.length > 0) {
resetForm();
} else {
var name = $(e).attr("data-name");
var url = $(e).attr("data-url");
var id = $(e).attr("data");
$("#webHookId").val(id);
$("#ding-ding-web-hook-name").val(name);
$("#ding-ding-web-hook-url").val(url);
$("#webhook-form-view").removeClass("ng-hide");
$("#webHookAdd").removeClass("ng-hide");
$("#webHookUpdate").removeClass("ng-hide");
$("#webHookRemove").removeClass("ng-hide");
$("#webHookCancel").removeClass("ng-hide");
$("#webHookAdd").addClass("ng-hide");
$("#webHookCancel").addClass("ng-hide");
}
}
/**
* 构造数据
* @returns {{appId: (*|jQuery|string|undefined), name: (*|jQuery|string|undefined), id: (*|jQuery|string|undefined), url: (*|jQuery|string|undefined)}}
*/
function buildData() {
var name = $("#ding-ding-web-hook-name").val();
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
};
return data;
}
/**
* 重置 webHook 表单
*/
function resetForm() {
$("#ding-ding-web-hook-name").val('');
$("#ding-ding-web-hook-url").val('');
$("#webHookId").val('');
$("#webHookAdd").addClass("ng-hide");
$("#webHookUpdate").addClass("ng-hide");
$("#webHookRemove").addClass("ng-hide");
$("#webHookCancel").addClass("ng-hide");
$("#webHookAdd").removeClass("ng-hide");
$("#webHookCancel").removeClass("ng-hide");
$("#webhook-form-view").addClass("ng-hide");
$("#webHookUpdate").attr("disabled", "disabled");
$("#webHookAdd").attr("disabled", "disabled");
}
/**
* 添加 webHook
*/
function add() {
postWithURL("/webHook/add")
}
/**
* 更新 webHook
*/
function update() {
postWithURL("/webHook/update")
}
/**
* 删除 webHook
*/
function remove() {
postWithURL("/webHook/delete")
}
/**
* 发送请求
*/
function postWithURL(url) {
var data = buildData();
resetForm();
$.post(url, data, function(result){
getWebHooks();
});
}
/**
* 切换面板时样式清除
*/
function removeAllPanelClass() {
$("#info-container").removeClass("app-info");
$("#info-container").removeClass("app-integration");
$("#info-container").removeClass("app-activities");
$("#info-panel").removeClass("apps-app-integration")
$("#info-panel").removeClass("apps-app-info");
$("#info-panel").removeClass("apps-app-activities");
$("#app-activity-panel").removeClass("ng-hide");
$("#app-info-panel").removeClass("ng-hide");
$("#app-integration-panel").removeClass("ng-hide");
}
$(function () {
getWebHooks();
$(".download-action").click(function () {
window.open($(this).val())
});
$(".preview").click(function () {
window.open($(this).val())
});
$(".app-delete").click(function () {
var url = "/p/delete/" + $(this).attr("data");
$.post(url, data, function(result){
window.location.href = window.location.href
window.location.reload
});
})
$("#js-app-short-copy-trigger").click(function () {
new ClipboardJS('#js-app-short-copy-trigger', {
text: function (trigger) {
return trigger.getAttribute('value');
}
});
});
$("#app-activity-icon").click(function () {
removeAllPanelClass();
$("#info-container").addClass("app-activities");
$("#info-panel").addClass("apps-app-activities");
$("#app-info-panel").addClass("ng-hide");
$("#app-integration-panel").addClass("ng-hide");
});
$("#app-info-icon").click(function () {
removeAllPanelClass();
$("#info-container").addClass("app-info");
$("#info-panel").addClass("apps-app-info");
$("#app-activity-panel").addClass("ng-hide");
$("#app-integration-panel").addClass("ng-hide");
});
$("#app-integration-icon").click(function () {
removeAllPanelClass();
$("#info-container").addClass("app-integration");
$("#info-panel").addClass("apps-app-integration");
$("#app-activity-panel").addClass("ng-hide");
$("#app-info-panel").addClass("ng-hide");
});
$("#delete-app").click(function () {
var url = "/app/delete/" + $(this).attr("data");
$.post(url, function(result){
window.location.href = "/apps"
});
});
$("#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) {
$("#webHookAdd").removeAttr("disabled");
$("#webHookUpdate").removeAttr("disabled");
}
});
$("#webHookCancel").click(function () {
resetForm();
});
$(".add-config").click(function () {
resetForm();
$("#webhook-form-view").removeClass("ng-hide");
});
});
+103 -49
View File
@@ -1,11 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Stict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!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"> <html xmlns:th="http://www.thymeleaf.org">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge"> <meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<title class="ng-binding">[[${package.name}]] - 应用动态</title> <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/bootstrap.css}">
@@ -13,7 +11,6 @@
<script type="text/javascript" th:src="@{/js/jquery-1.11.0.min.js}"></script> <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> <script type="text/javascript" th:src="@{/js/clipboard.min.js}"></script>
</head> </head>
<body class="ng-scope"> <body class="ng-scope">
<nav class="navbar navbar-transparent fade-out navbar-black"> <nav class="navbar navbar-transparent fade-out navbar-black">
<div class="navbar-header"> <div class="navbar-header">
@@ -21,11 +18,14 @@
</div> </div>
<div class="collapse navbar-collapse navbar-ex1-collapse ng-scope"> <div class="collapse navbar-collapse navbar-ex1-collapse ng-scope">
<div class="dropdown"> <div class="dropdown">
<div></div> <div>
</div>
</div> </div>
</div> </div>
</nav> </nav>
<div class="menu-toggle fade-out"><i class="icon-menu"></i></div> <div class="menu-toggle fade-out">
<i class="icon-menu"></i>
</div>
<div class="navbar-wrapper ng-scope"> <div class="navbar-wrapper ng-scope">
<div ng-controller="NavbarController" class="ng-scope"> <div ng-controller="NavbarController" class="ng-scope">
<div class="navbar-header-wrap"> <div class="navbar-header-wrap">
@@ -39,24 +39,23 @@
<a class="ng-binding" href="/apps">我的应用</a> <a class="ng-binding" href="/apps">我的应用</a>
</div> </div>
<i class="icon-angle-right"></i> <i class="icon-angle-right"></i>
<div class="navbar-title secondary-title ng-binding" <div class="navbar-title secondary-title ng-binding" style="">
style="">[[${package.name}]]</div> [[${package.name}]]
</div>
</nav> </nav>
</div> </div>
</div> </div>
</div> </div>
</div><!-- ngInclude: '/templates_manage/upload_modal.html' --> </div>
<section data-ui-view="" class="ng-scope" style=""> <!-- ngInclude: '/templates_manage/upload_modal.html' --><section data-ui-view="" class="ng-scope" style="">
<div class="page-app app-activities"> <div id="info-container" class="page-app app-activities">
<div class="banner has-devices"> <div class="banner has-devices">
<div class="middle-wrapper clearfix"> <div class="middle-wrapper clearfix">
<div class="pull-left icon-container appicon"> <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"/> <img th:src="'/' + ${package.icon}" width="100" height="100" class="change_icon ng-isolate-scope"/>
</div> </div>
<div class="badges"> <div class="badges">
<span tooltip-top="" tooltip="复制到剪贴板" id="js-app-short-copy-trigger" <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>
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,'ios')}">iOS</span>
<span class="apptype ng-binding" th:if="${#strings.containsIgnoreCase(package.platform,'android')}">Android</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">&nbsp;&nbsp;[[${package.bundleID}]]</b></span> <span class="bundleid ng-binding">BundleID<b class="ng-binding">&nbsp;&nbsp;[[${package.bundleID}]]</b></span>
@@ -64,25 +63,26 @@
</div> </div>
<div class="actions"> <div class="actions">
<a class="download ng-binding" th:href="${package.installPath}" target="_blank"> <a class="download ng-binding" th:href="${package.installPath}" target="_blank">
<i class="icon-eye"></i> <i class="icon-eye"></i> 预览
预览
</a> </a>
</div> </div>
<div class="tabs-container"> <div class="tabs-container">
<ul class="list-inline"> <ul class="list-inline">
<li> <li>
<a class="ng-binding"><i class="icon-file"></i> 基本信息</a></li> <a id="app-info-icon" class="ng-binding"><i class="icon-file"></i> 基本信息</a></li>
<li> <li>
<a class="ng-binding"><i class="icon-device"></i> 设备列表</a></li> <a id="app-integration-icon" class="ng-binding"><i class="icon-box"></i> 集成</a></li>
</ul> </ul>
</div> </div>
</div> </div>
</div><!-- uiView: --> </div>
<!-- uiView: -->
<div data-ui-view="" class="ng-scope"> <div data-ui-view="" class="ng-scope">
<div class="page-app-activities page-tabcontent ng-scope"> <div id="info-panel" class="page-app-activities page-tabcontent apps-app-info ng-scope">
<!-- ngIf: !activitiesReady --> <!-- ngIf: !activitiesReady -->
<div class="middle-wrapper" ng-show="activitiesReady"> <div class="middle-wrapper" ng-show="activitiesReady">
<ul class="list-unstyled time-line"> <!-- 更新面板-->
<ul id="app-activity-panel" class="list-unstyled time-line">
<li> <li>
<span class="dot"></span> <span class="dot"></span>
<span class="filter ng-binding">版本更新</span> <span class="filter ng-binding">版本更新</span>
@@ -131,38 +131,92 @@
<li class="more ng-hide" ng-show="currentApp.releases.current_page &lt; currentApp.releases.total_pages"> <li class="more ng-hide" ng-show="currentApp.releases.current_page &lt; currentApp.releases.total_pages">
<button ng-click="moreRelease()" class="ng-binding">显示更多版本</button></li> <button ng-click="moreRelease()" class="ng-binding">显示更多版本</button></li>
</ul> </ul>
<!--信息面板-->
<div id="app-info-panel" class="app-info-form ng-pristine ng-valid ng-valid-required ng-valid-pattern ng-hide">
<div class="field app-id">
<div class="left-label ng-binding">
应用 ID
</div>
<div class="value">
<input ng-model="currentApp.id" th:value="${package.id}" readonly="readonly" class="ng-pristine ng-untouched ng-valid">
</div>
</div>
<div class="field app-name">
<div class="left-label ng-binding">
应用名称
</div>
<div class="value">
<input ng-model="currentApp.id" th:value="${package.name}" readonly="readonly" class="ng-pristine ng-untouched ng-valid"/>
</div>
</div>
<div class="field app-short">
<div class="left-label ng-binding">
短链接
</div>
<div class="value">
<input ng-model="currentApp.id" th:value="${package.installPath}" readonly="readonly" class="ng-pristine ng-untouched ng-valid">
</div>
</div>
<div class="field app-id">
<div class="left-label">
应用图标
</div>
<div class="icon_select unploadIcon appicon" style="width: 100px; cursor: pointer">
<img width="100" height="100" id="icon_img" style="border-radius: 17%" class="change_icon ng-isolate-scope" th:src="'/' + ${package.icon}">
</div>
</div>
<div class="field app-deletion">
<div class="left-label ng-binding">
删除应用
</div>
<div class="value">
<button id="delete-app" th:data="${package.id}" class="btn btn-danger btn-circle require-confirm">
<span class="ng-scope">删除</span>
</button>
</div>
</div>
</div>
<!--集成面板-->
<div id="app-integration-panel" class="providers ng-hide">
<h2 class="ng-scope">消息推送</h2>
<div class="item item-webhook ng-scope">
<div class="logo pull-left Dingtalk">
<img alt="Dingtalk" src="/images/ding_ding.png">
</div>
<div class="content">
<p class="desc ng-binding">
钉钉,是阿里巴巴集团专为企业打造的一个专业通讯、协同办公平台, 帮助企业降低沟通与管理成本,提升办公效率,让数千万企业提前进入到云和移动办公时代。
</p>
<div class="configrations">
<a class="add-config">
<i class="icon-plus"></i>
</a>
</div>
<webhook-form-view id="webhook-form-view" class="ng-pristine ng-untouched ng-valid ng-isolate-scope ng-hide">
<div id="webhookForm" class="ng-pristine ng-invalid ng-invalid-required ng-valid-url">
<input class="ng-hide" th:value="${package.id}" name="appId" id="appId"/>
<input class="ng-hide" name="id" id="webHookId"/>
<input id="ding-ding-web-hook-name" class="config-name form-control ng-pristine ng-untouched ng-invalid ng-invalid-required" placeholder="配置名称" name="name" required=""/>
<input id="ding-ding-web-hook-url" class="config-url form-control ng-pristine ng-untouched ng-invalid ng-invalid-required ng-valid-url" placeholder="Webhook url" type="url" name="url" required=""/>
<button class="btn btn-lemon ng-binding ng-hide" disabled="disabled" onclick="update()" id="webHookUpdate">保存</button>
<button class="btn btn-lemon ng-binding" disabled="disabled" onclick="add()" id="webHookAdd">添加</button>
<button class="btn btn-link ng-hide" onclick="remove()" id="webHookRemove">
<i class="icon-trash"></i>
</button>
<button class="btn btn-link ng-binding" id="webHookCancel">取消</button>
<p class="url-invalid-tips ng-scope ng-hide">
请输入正确的 URL 地址
</p>
</div>
</webhook-form-view>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<script type="application/javascript"> <script type="text/javascript" th:src="@{/js/list.js}"></script>
$(".download-action").click(function(){
window.open($(this).val())
})
$(".preview").click(function () {
window.open($(this).val())
})
$(".app-delete").click(function () {
var url = "/p/delete/" + $(this).attr("data");
$.ajax({url:url,success:function(result){
window.location.href=window.location.href
window.location.reload
}
});
})
$("#js-app-short-copy-trigger").click(function(){
new ClipboardJS('#js-app-short-copy-trigger', {
text: function(trigger) {
return trigger.getAttribute('value');
}
});
});
</script>
</body> </body>
</html> </html>