mirror of https://github.com/ouqiang/gocron
支持旧版本升级
parent
4f7a5cfbde
commit
0e023bd3fa
|
@ -14,7 +14,8 @@ RUN make install-vue \
|
|||
|
||||
FROM alpine:3.7
|
||||
|
||||
RUN addgroup -S app \
|
||||
RUN apk add --no-cache ca-certificates \
|
||||
&& addgroup -S app \
|
||||
&& adduser -S -g app app
|
||||
|
||||
WORKDIR /app
|
||||
|
|
|
@ -223,6 +223,7 @@ func (m *Migration) upgradeFor150(session *xorm.Session) error {
|
|||
return err
|
||||
}
|
||||
|
||||
settingModel.Id = 0
|
||||
settingModel.Code = WebhookCode
|
||||
settingModel.Key = WebhookUrlKey
|
||||
settingModel.Value = ""
|
||||
|
@ -231,6 +232,7 @@ func (m *Migration) upgradeFor150(session *xorm.Session) error {
|
|||
return err
|
||||
}
|
||||
|
||||
settingModel.Id = 0
|
||||
settingModel.Code = WebhookCode
|
||||
settingModel.Key = WebhookTemplateKey
|
||||
settingModel.Value = webhookTemplate
|
||||
|
|
|
@ -22,8 +22,6 @@ var (
|
|||
ConfDir string // 配置目录
|
||||
// LogDir 日志目录
|
||||
LogDir string // 日志目录
|
||||
// DataDir 数据目录
|
||||
DataDir string // 存放session等
|
||||
// AppConfig 配置文件
|
||||
AppConfig string // 应用配置文件
|
||||
// Installed 应用是否已安装
|
||||
|
@ -46,10 +44,9 @@ func InitEnv(versionString string) {
|
|||
}
|
||||
ConfDir = filepath.Join(AppDir, "/conf")
|
||||
LogDir = filepath.Join(AppDir, "/log")
|
||||
DataDir = filepath.Join(AppDir, "/data")
|
||||
AppConfig = filepath.Join(ConfDir, "/app.ini")
|
||||
VersionFile = filepath.Join(ConfDir, "/.version")
|
||||
createDirIfNotExists(ConfDir, LogDir, DataDir)
|
||||
createDirIfNotExists(ConfDir, LogDir)
|
||||
Installed = IsInstalled()
|
||||
VersionId = ToNumberVersion(versionString)
|
||||
}
|
||||
|
@ -107,7 +104,7 @@ func GetCurrentVersionId() int {
|
|||
|
||||
// ToNumberVersion 把字符串版本号a.b.c转换为整数版本号abc
|
||||
func ToNumberVersion(versionString string) int {
|
||||
if strings.HasPrefix("v", versionString) {
|
||||
if strings.HasPrefix(versionString, "v") {
|
||||
versionString = versionString[1:]
|
||||
}
|
||||
v := strings.Replace(versionString, ".", "", -1)
|
||||
|
|
|
@ -27,10 +27,10 @@ import (
|
|||
_ "github.com/ouqiang/gocron/internal/statik"
|
||||
)
|
||||
|
||||
// URL前缀
|
||||
const urlPrefix = "/api"
|
||||
|
||||
var staticDir = "public"
|
||||
const (
|
||||
urlPrefix = "/api"
|
||||
staticDir = "public"
|
||||
)
|
||||
|
||||
var statikFS http.FileSystem
|
||||
|
||||
|
@ -42,7 +42,7 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
// 路由注册
|
||||
// Register 路由注册
|
||||
func Register(m *macaron.Macaron) {
|
||||
m.SetURLPrefix(urlPrefix)
|
||||
// 所有GET方法,自动注册HEAD方法
|
||||
|
@ -54,6 +54,7 @@ func Register(m *macaron.Macaron) {
|
|||
ctx.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
io.Copy(ctx.Resp, file)
|
||||
|
||||
})
|
||||
|
|
|
@ -50,7 +50,7 @@ func Index(ctx *macaron.Context) string {
|
|||
|
||||
// 解析查询参数
|
||||
func parseQueryParams(ctx *macaron.Context) models.CommonMap {
|
||||
var params models.CommonMap = models.CommonMap{}
|
||||
params := models.CommonMap{}
|
||||
base.ParsePageAndPageSize(ctx, params)
|
||||
|
||||
return params
|
||||
|
@ -65,6 +65,9 @@ func Detail(ctx *macaron.Context) string {
|
|||
logger.Error(err)
|
||||
}
|
||||
jsonResp := utils.JsonResponse{}
|
||||
if userModel.Id == 0 {
|
||||
return jsonResp.Success(utils.SuccessContent, nil)
|
||||
}
|
||||
|
||||
return jsonResp.Success(utils.SuccessContent, userModel)
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ func (task Task) Initialize() {
|
|||
for page < maxPage {
|
||||
taskList, err := taskModel.ActiveList(page, pageSize)
|
||||
if err != nil {
|
||||
logger.Fatalf("定时任务初始化#获取任务列表错误-", err.Error())
|
||||
logger.Fatalf("定时任务初始化#获取任务列表错误: %s", err)
|
||||
}
|
||||
if len(taskList) == 0 {
|
||||
break
|
||||
|
|
File diff suppressed because one or more lines are too long
6
makefile
6
makefile
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
.PHONY: build
|
||||
build: gocron node
|
||||
|
||||
|
@ -41,6 +39,10 @@ enable-race:
|
|||
package: build-vue statik
|
||||
bash ./package.sh
|
||||
|
||||
.PHONY: package-all
|
||||
package-all: build-vue statik
|
||||
bash ./package.sh -p 'linux darwin windows'
|
||||
|
||||
.PHONY: build-vue
|
||||
build-vue:
|
||||
cd web/vue && yarn run build
|
||||
|
|
|
@ -103,8 +103,8 @@ init() {
|
|||
GIT_COMMIT_ID=`git_latest_commit`
|
||||
LDFLAGS="-w -X 'main.AppVersion=${VERSION}' -X 'main.BuildDate=`date '+%Y-%m-%d %H:%M:%S'`' -X 'main.GitCommit=${GIT_COMMIT_ID}'"
|
||||
|
||||
PACKAGE_DIR=${BINARY_NAME}_package
|
||||
BUILD_DIR=${BINARY_NAME}_build
|
||||
PACKAGE_DIR=${BINARY_NAME}-package
|
||||
BUILD_DIR=${BINARY_NAME}-build
|
||||
|
||||
if [[ -d ${BUILD_DIR} ]];then
|
||||
rm -rf ${BUILD_DIR}
|
||||
|
@ -178,7 +178,7 @@ run() {
|
|||
package_gocron() {
|
||||
BINARY_NAME='gocron'
|
||||
MAIN_FILE="./cmd/gocron/gocron.go"
|
||||
INCLUDE_FILE=(Dockerfile-release README.md)
|
||||
INCLUDE_FILE=()
|
||||
|
||||
|
||||
run
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
</div>
|
||||
<footer>
|
||||
<div id="copyrights">
|
||||
<div class="inset">
|
||||
<div class="bigcontainer">
|
||||
<div class="fl">
|
||||
<p>© 2017 gocron
|
||||
<i class="Github Alternate icon"></i><a href="https://github.com/ouqiang/gocron" target="_blank">
|
||||
GitHub
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script>
|
||||
$(
|
||||
function(){
|
||||
$('.ui.dropdown').dropdown();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,72 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="renderer" content="webkit">
|
||||
<title>{%.Title%}</title>
|
||||
<link type="text/css" rel="stylesheet" href="/resource/css/framework.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/resource/css/main.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/resource/sweetalert/sweetalert.css" />
|
||||
<script type="text/javascript" src="/resource/javascript/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/resource/javascript/framework.js"></script>
|
||||
<script type="text/javascript" src="/resource/javascript/form.min.js"></script>
|
||||
<script type="text/javascript" src="/resource/sweetalert/sweetalert.min.js"></script>
|
||||
<script type="text/javascript" src="/resource/javascript/vue.min.js"></script>
|
||||
<script type="text/javascript" src="/resource/javascript/handlebars-v4.0.5.js"></script>
|
||||
<script type="text/javascript" src="/resource/javascript/main.js"></script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
select {
|
||||
height: 40px;
|
||||
}
|
||||
.fields.search > .field {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
{%if not .DisableNav%}
|
||||
<!--header begin-->
|
||||
<header>
|
||||
<div class="bigcontainer">
|
||||
<div id="logo">
|
||||
{%.AppName%}
|
||||
</div>
|
||||
<div class="user">
|
||||
<div class="ui inline labeled icon top right pointing dropdown">
|
||||
{%if not .LoginUsername%}
|
||||
你好
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<a class="item" href="/user/login"><i class="sign in icon"></i>登录</a>
|
||||
</div>
|
||||
{%else%}
|
||||
你好,{%.LoginUsername%}
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<a href="/user/editMyPassword" class="item"><i class="edit icon"></i>修改密码</a>
|
||||
<a class="item" href="/user/logout"><i class="sign out icon"></i>退出</a>
|
||||
</div>
|
||||
{%end%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- the main menu-->
|
||||
<div class="ui teal inverted menu">
|
||||
<div class="bigcontainer">
|
||||
<div class="right menu">
|
||||
<a class="item {%if or (eq .Controller "task") (eq .Controller "delaytask")%}active{%end%}" href="/task"><i class="tasks icon"></i>任务</a>
|
||||
<a class="item {%if eq .Controller "host"%}active{%end%}" href="/host"><i class="linux icon"></i>任务节点</a>
|
||||
{%if .IsAdmin%}
|
||||
<a class="item {%if eq .Controller "user"%}active{%end%}" href="/user"><i class="user icon"></i>用户管理</a>
|
||||
<a class="item {%if eq .Controller "manage"%}active{%end%}" href="/manage/slack/edit"><i class="settings icon"></i>系统管理</a>
|
||||
{%end%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
|
@ -1,41 +0,0 @@
|
|||
{%if gt .Pagination.Total 0%}
|
||||
|
||||
<div class="ui pagination menu">
|
||||
{%if not .Pagination.IsFirst%}
|
||||
<a class="item" href="{%.URI%}?{% .Params.PageParams%}&page=1">
|
||||
首页
|
||||
</a>
|
||||
{%end%}
|
||||
|
||||
{%if .Pagination.HasPrevious%}
|
||||
<a class="icon item" href="{%.URI%}?{% .Params.PageParams%}&page={%.Pagination.Previous%}">
|
||||
<i class="icon left arrow"></i>
|
||||
</a>
|
||||
{%end%}
|
||||
|
||||
{%range .Pagination.Pages%}
|
||||
{%if eq .Num -1%}
|
||||
<div class="disabled item">
|
||||
...
|
||||
</div>
|
||||
{%else%}
|
||||
<a class="icon {%if .IsCurrent%}active{%end%} item" href="{%$.URI%}?{% $.Params.PageParams%}&page={%.Num%}">
|
||||
{%.Num%}
|
||||
</a>
|
||||
{%end%}
|
||||
{%end%}
|
||||
|
||||
{%if .Pagination.HasNext%}
|
||||
<a class="icon item" href="{%.URI%}?{% .Params.PageParams%}&page={%.Pagination.Next%}">
|
||||
<i class="icon right arrow"></i>
|
||||
</a>
|
||||
{%end%}
|
||||
{%if not .Pagination.IsLast%}
|
||||
<a class="icon item" href="{%.URI%}?{% .Params.PageParams%}&page={%.Pagination.TotalPages%}">
|
||||
尾页
|
||||
</a>
|
||||
{%end%}
|
||||
<div class="item">{%.Pagination.Total%}条/{%.Pagination.TotalPages%}页</div>
|
||||
</div>
|
||||
|
||||
{%end%}
|
|
@ -1,12 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<script>
|
||||
swal({
|
||||
title: "404 - NOT FOUND",
|
||||
text: "您访问的页面不存在",
|
||||
type: "warning"
|
||||
},
|
||||
function(){
|
||||
location.href = "/"
|
||||
});
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,11 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<script>
|
||||
swal({
|
||||
title: "500 - INTERNAL SERVER ERROR",
|
||||
text: "网站暂时无法访问, 请稍后再试.",
|
||||
type: "warning",
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "确定"
|
||||
});
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,3 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,116 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
<div class="ui grid">
|
||||
{% template "host/menu" . %}
|
||||
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
添加主机
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form fluid vertical segment">
|
||||
<input type="hidden" name="id" value="{%.Host.Id%}">
|
||||
<div class="four fields">
|
||||
<div class="field">
|
||||
<label>主机名</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="name" value="{%.Host.Name%}" placeholder="127.0.0.1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>端口</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="port" value="{%.Host.Port%}" placeholder="5921">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>节点名称</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="alias" value="{%.Host.Alias%}"
|
||||
placeholder="节点名称如web">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>备注</label>
|
||||
<div class="ui small input">
|
||||
<textarea rows="7" name="remark" >{%.Host.Remark%}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui primary submit button">保存</div>
|
||||
<a class="ui button" onclick="location.href='/host';">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var $uiForm = $('.ui.form');
|
||||
$($uiForm).form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/host/store', fields, function(code, message) {
|
||||
location.href = "/host"
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
identifier : 'name',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入主机名'
|
||||
},
|
||||
{
|
||||
type : 'maxLength[64]',
|
||||
prompt : '长度不能超过64'
|
||||
}
|
||||
]
|
||||
},
|
||||
alias: {
|
||||
identifier : 'alias',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入主机别名'
|
||||
},
|
||||
{
|
||||
type : 'maxLength[32]',
|
||||
prompt : '长度不能超过32'
|
||||
}
|
||||
]
|
||||
},
|
||||
port: {
|
||||
identifier : 'port',
|
||||
rules: [
|
||||
{
|
||||
type : 'integer[1..65535]',
|
||||
prompt : '请输入有效的端口号'
|
||||
}
|
||||
]
|
||||
},
|
||||
remark: {
|
||||
identifier : 'remark',
|
||||
rules: [
|
||||
{
|
||||
type : 'maxLength[100]',
|
||||
prompt : '长度不能超过100'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,86 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
<div class="ui grid">
|
||||
{% template "host/menu" . %}
|
||||
|
||||
<div class="twelve wide column">
|
||||
{%if .IsAdmin%}
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<a href="/host/create">
|
||||
<i class="large add icon"></i>
|
||||
<div class="content">
|
||||
添加节点
|
||||
</div>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
||||
<form class="ui form">
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<input type="text" placeholder="ID" name="id" value="{%if gt .Params.Id 0%}{%.Params.Id%}{%end%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="text" placeholder="主机名" name="name" value="{%.Params.Name%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui linkedin submit button">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="ui celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>主机名</th>
|
||||
<th>别名</th>
|
||||
<th>端口</th>
|
||||
<th>备注</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%range $i, $v := .Hosts%}
|
||||
<tr>
|
||||
<td>{%.Id%}</td>
|
||||
<td>{%.Name%}</td>
|
||||
<td>{%.Alias%}</td>
|
||||
<td>{%.Port%}</td>
|
||||
<td>{%.Remark%}</td>
|
||||
<td class="operation">
|
||||
{%if $.IsAdmin%}
|
||||
<a class="ui purple button" href="/host/edit/{%.Id%}">编辑</a>
|
||||
<button class="ui positive button" onclick="util.removeConfirm('/host/remove/{%.Id%}')">删除</button><br>
|
||||
{%end%}
|
||||
<div style="margin-top: 5px;">
|
||||
<a class="ui twitter button" href="/task?host_id={%.Id%}">查看任务</a>
|
||||
{%if $.IsAdmin%}
|
||||
<button class="ui blue button" @click="ping({%.Id%})">连接测试</button>
|
||||
{%end%}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{%end%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% template "common/pagination" .%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var Vue = new Vue({
|
||||
el: '.ui.celled.table',
|
||||
methods: {
|
||||
ping: function(id) {
|
||||
util.get("/host/ping/" + id, function(code, message) {
|
||||
swal('操作成功', '连接成功', 'success');
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,9 +0,0 @@
|
|||
<div class="four wide column">
|
||||
<div class="verticalMenu">
|
||||
<div class="ui vertical pointing menu fluid">
|
||||
<a class="{%if eq .URI "/host"%}active teal{%end%} item" href="/host">
|
||||
<i class="linux icon"></i> 节点列表
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,189 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
<div class="ui grid">
|
||||
{% template "install/menu" . %}
|
||||
<div class="ten wide column">
|
||||
<form class="ui form">
|
||||
<div class="ui blue center aligned segment">
|
||||
<p>数据库配置</p>
|
||||
</div>
|
||||
<br>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>数据库(目前只支持MySQL)</label>
|
||||
<div class="ui dropdown selection">
|
||||
<input type="hidden" name="db_type" value="mysql">
|
||||
<div class="default text">MySQL</div>
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<div class="item active" data-value="mysql">MySQL</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>主机名</label>
|
||||
<input type="text" name="db_host" value="127.0.0.1">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>端口</label>
|
||||
<input type="text" name="db_port" value="3306">
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>用户名</label>
|
||||
<input type="text" name="db_username">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>密码</label>
|
||||
<input type="password" name="db_password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>数据库名称</label>
|
||||
<input type="text" name="db_name">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>表前缀</label>
|
||||
<input type="text" name="db_table_prefix" value="cron_">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui blue center aligned segment">
|
||||
<p>管理员账号配置</p>
|
||||
</div>
|
||||
<br>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>管理员账号</label>
|
||||
<input type="text" name="admin_username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>管理员密码</label>
|
||||
<input type="password" name="admin_password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>确认管理员密码</label>
|
||||
<input type="password" name="confirm_admin_password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>管理员邮箱</label>
|
||||
<input type="text" name="admin_email">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui blue submit button">保存</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 表单验证规则
|
||||
$('.ui.form').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/install/store', fields, function(code, message) {
|
||||
swal('安装成功');
|
||||
setTimeout(function() {
|
||||
location.href = "/";
|
||||
}, 2000)
|
||||
});
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
dbHost: {
|
||||
identifier : 'db_host',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入主机名'
|
||||
}
|
||||
]
|
||||
},
|
||||
dbPort: {
|
||||
identifier : 'db_port',
|
||||
rules: [
|
||||
{
|
||||
type : 'integer',
|
||||
prompt : '请输入主机名'
|
||||
}
|
||||
]
|
||||
},
|
||||
dbUsername: {
|
||||
identifier : 'db_username',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入数据库账号用户名'
|
||||
}
|
||||
]
|
||||
},
|
||||
dbPassword: {
|
||||
identifier : 'db_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入数据库账号密码'
|
||||
}
|
||||
]
|
||||
},
|
||||
dbName: {
|
||||
identifier : 'db_name',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入数据库名称'
|
||||
}
|
||||
]
|
||||
},
|
||||
adminUsername: {
|
||||
identifier : 'admin_username',
|
||||
rules: [
|
||||
{
|
||||
type : 'minLength[3]',
|
||||
prompt : '管理员账号长度不能少于3位'
|
||||
}
|
||||
]
|
||||
},
|
||||
adminPassword: {
|
||||
identifier : 'admin_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'minLength[6]',
|
||||
prompt : '管理员密码长度不能少于6位'
|
||||
}
|
||||
]
|
||||
},
|
||||
confirmAdminPassword: {
|
||||
identifier : 'confirm_admin_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'match[admin_password]',
|
||||
prompt : '两次输入密码不匹配'
|
||||
}
|
||||
]
|
||||
},
|
||||
adminEmail: {
|
||||
identifier : 'admin_email',
|
||||
rules: [
|
||||
{
|
||||
type : 'email',
|
||||
prompt : '邮箱格式错误'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,9 +0,0 @@
|
|||
<div class="four wide column">
|
||||
<div class="verticalMenu">
|
||||
<div class="ui vertical pointing menu fluid">
|
||||
<a class="active teal item" href="/install">
|
||||
<i class="chevron right icon"></i> 安装
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,39 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
<div class="ui grid">
|
||||
{% template "manage/menu" . %}
|
||||
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
登录日志
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户名</th>
|
||||
<th>登录IP</th>
|
||||
<th>登录时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%range $i, $v := .LoginLogs%}
|
||||
<tr>
|
||||
<td>{%.Username%}</td>
|
||||
<td>{%.Ip%}</td>
|
||||
<td>{%.Created%}</td>
|
||||
</tr>
|
||||
{%end%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% template "common/pagination" .%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,201 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui grid">
|
||||
{%template "manage/menu" .%}
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
{%.Title%}
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form fluid vertical segment mail-server">
|
||||
<div class="content">邮件服务器配置</div><br>
|
||||
<div class="four fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
SMTP服务器
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="host" value="{%.Mail.Host%}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
端口
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="port" value="{%if gt .Mail.Port 0%}{%.Mail.Port%}{%end%}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
用户名
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="user" value="{%.Mail.User%}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
密码
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="password" value="{%.Mail.Password%}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui primary button">保存</button>
|
||||
{%if .Mail.Host%}
|
||||
<a class="ui green button" onclick="clearMailServer()">删除</a>
|
||||
{%end%}
|
||||
<br><br><br>
|
||||
<div>
|
||||
<div class="content">邮箱用户</div><p></p>
|
||||
<div class="fields">
|
||||
{%range $i, $v := .Mail.MailUsers%}
|
||||
<div class="field">
|
||||
<div class="ui segment">
|
||||
{%.Username%}-{%.Email%} <div class="ui blue button" onclick="removeMailUser({%.Id%})">删除</div>
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="ui facebook button" onclick="createMailUser();">新增用户</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui small modal">
|
||||
<div class="header">新增用户</div>
|
||||
<div class="content">
|
||||
<form class="ui form mail-user">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
用户名
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
邮箱地址
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="email">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui primary button">保存</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$('.mail-server').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/manage/mail/server',
|
||||
fields,
|
||||
function(code, message) {
|
||||
location.reload();
|
||||
}
|
||||
);
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
host: {
|
||||
identifier : 'host',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入有效主机名'
|
||||
}
|
||||
]
|
||||
},
|
||||
port: {
|
||||
identifier : 'port',
|
||||
rules: [
|
||||
{
|
||||
type : 'integer[1..65535]',
|
||||
prompt : '请输入有效端口'
|
||||
}
|
||||
]
|
||||
},
|
||||
user: {
|
||||
identifier : 'user',
|
||||
rules: [
|
||||
{
|
||||
type : 'email',
|
||||
prompt : '请输入有效用户名'
|
||||
}
|
||||
]
|
||||
},
|
||||
password: {
|
||||
identifier : 'password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入密码'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
|
||||
$('.mail-user').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/manage/mail/user',
|
||||
fields,
|
||||
function(code, message) {
|
||||
util.alertSuccess();
|
||||
location.reload();
|
||||
}
|
||||
);
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
username: {
|
||||
identifier : 'username',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入用户名'
|
||||
}
|
||||
]
|
||||
},
|
||||
email: {
|
||||
identifier : 'email',
|
||||
rules: [
|
||||
{
|
||||
type : 'email',
|
||||
prompt : '请输入有效的邮箱地址'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
|
||||
function createMailUser() {
|
||||
$('.ui.modal').modal('show');
|
||||
}
|
||||
|
||||
function removeMailUser(id) {
|
||||
util.post('/manage/mail/user/remove/' + id, {}, function(code, message) {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function clearMailServer() {
|
||||
util.post('/manage/mail/server/clear', {}, function(code, message) {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,15 +0,0 @@
|
|||
<div class="three wide column">
|
||||
<div class="verticalMenu">
|
||||
<div class="ui vertical pointing menu fluid">
|
||||
<a class="{%if eq .URI "/manage/slack/edit"%}active teal{%end%} item" href="/manage/slack/edit">
|
||||
<i class="slack icon"></i> Slack配置
|
||||
</a>
|
||||
<a class="{%if eq .URI "/manage/mail/edit"%}active teal{%end%} item" href="/manage/mail/edit">
|
||||
<i class="slack icon"></i> 邮件配置
|
||||
</a>
|
||||
<a class="{%if eq .URI "/manage/login-log"%}active teal{%end%} item" href="/manage/login-log">
|
||||
<i class="slack icon"></i> 登录日志
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,88 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui grid">
|
||||
{%template "manage/menu" .%}
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
{%.Title%}
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form fluid vertical segment">
|
||||
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">Slack WebHook URL</div>
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" id="url" value="{%.Slack.Url%}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui primary button" @click="updateUrl">保存</div>
|
||||
|
||||
<br><br><br>
|
||||
<div>
|
||||
<div class="content">Slack Channel(配置任务通知时,可选择多Channel)</div><p></p>
|
||||
<div class="fields">
|
||||
{%range $i, $v := .Slack.Channels%}
|
||||
<div class="field">
|
||||
<div class="ui segment">
|
||||
{%.Name%} <div class="ui blue button" @click="removeChannel({%.Id%})">删除</div>
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui facebook button" @click="createChannel">新增Channel</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
new Vue({
|
||||
el: '.ui.form',
|
||||
methods: {
|
||||
updateUrl: function() {
|
||||
var url = $('#url').val();
|
||||
util.post('/manage/slack/url', {"url": url}, function(code, message) {
|
||||
util.alertSuccess();
|
||||
});
|
||||
},
|
||||
createChannel: function() {
|
||||
swal({
|
||||
title: "新增Channel",
|
||||
type: "input",
|
||||
showCancelButton: true,
|
||||
closeOnConfirm: false,
|
||||
animation: "slide-from-top"
|
||||
},
|
||||
function(inputValue){
|
||||
if (inputValue === false) return false;
|
||||
|
||||
if (inputValue === "") {
|
||||
swal.showInputError("请输入Channel");
|
||||
return false
|
||||
}
|
||||
|
||||
util.post('/manage/slack/channel',
|
||||
{"channel": inputValue},
|
||||
function(code, message) {
|
||||
util.alertSuccess();
|
||||
location.reload();
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
},
|
||||
removeChannel: function(id) {
|
||||
util.post('/manage/slack/channel/remove/' + id, {}, function(code, message) {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,242 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui grid">
|
||||
{%template "task/menu" .%}
|
||||
<div class="twelve wide column">
|
||||
{%if .IsAdmin%}
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<a href="/task/create">
|
||||
<i class="large add icon"></i>
|
||||
<div class="content">
|
||||
添加任务
|
||||
</div>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
||||
<form class="ui form">
|
||||
<div class="six fields search">
|
||||
<div class="one wide field">
|
||||
<input type="text" placeholder="任务ID" name="id" value="{%if gt .Params.Id 0%}{%.Params.Id%}{%end%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="text" placeholder="任务名称" name="name" value="{%.Params.Name%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="text" placeholder="标签名称" name="tag" value="{%.Params.Tag%}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="six fields search">
|
||||
<div class="field">
|
||||
<select name="host_id" id="hostId">
|
||||
<option value="">选择节点</option>
|
||||
{%range $i, $v := .Hosts%}
|
||||
<option value="{%.Id%}" {%if eq $.Params.HostId .Id %} selected {%end%} >{%.Alias%}-{%.Name%}</option>
|
||||
{%end%}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<select name="protocol" id="protocol">
|
||||
<option value="0">执行方式</option>
|
||||
<option value="2" {%if eq .Params.Protocol 2%}selected{%end%} data-match="host_id" data-validate-type="selectProtocol">SHELL</option>
|
||||
<option value="1" {%if eq .Params.Protocol 1%}selected{%end%}>HTTP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<select name="status">
|
||||
<option value="0">状态</option>
|
||||
<option value="1" {%if eq .Params.Status 0%}selected{%end%} >停止</option>
|
||||
<option value="2" {%if eq .Params.Status 1%}selected{%end%}>激活</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui linkedin submit button">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{%if .IsAdmin%}
|
||||
<div class="field">
|
||||
<select id="batch-operation">
|
||||
<option value="0">批量操作</option>
|
||||
<option value="1">激活</option>
|
||||
<option value="2">停止</option>
|
||||
<option value="3">删除</option>
|
||||
</select>
|
||||
</div>
|
||||
{%end%}
|
||||
<br>
|
||||
<table class="ui celled table task-list">
|
||||
<thead>
|
||||
<tr>
|
||||
{%if .IsAdmin%}
|
||||
<th>
|
||||
<input type="checkbox" onclick="checkAll(this)" style="width:25px;height: 25px;">
|
||||
</th>
|
||||
{%end%}
|
||||
<th>任务ID</th>
|
||||
<th>任务名称</th>
|
||||
<th>任务类型</th>
|
||||
<th>标签</th>
|
||||
<th>cron表达式</th>
|
||||
<th>执行方式</th>
|
||||
<th>超时时间</th>
|
||||
<th>重试次数</th>
|
||||
<th>单实例运行</th>
|
||||
<th>任务节点</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%range $i, $v := .Tasks%}
|
||||
<tr>
|
||||
{%if $.IsAdmin%}
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
class="sub-check"
|
||||
data-id="{%.Id%}"
|
||||
style="width:25px;height: 25px;">
|
||||
</td>
|
||||
{%end%}
|
||||
<td>{%.Id%}</td>
|
||||
<td>{%.Name%}</td>
|
||||
<td>{%if eq .Level 1%}主任务{%else%}子任务{%end%}</td>
|
||||
<td>{%.Tag%}</td>
|
||||
<td>{%.Spec%}</td>
|
||||
<td>{%if eq .Protocol 1%} HTTP {%else if eq .Protocol 2%} SHELL {%end%}</td>
|
||||
<td>{%if eq .Timeout -1%}后台运行{%else if gt .Timeout 0%}{%.Timeout%}秒{%else%}不限制{%end%}</td>
|
||||
<td>{%.RetryTimes%}</td>
|
||||
<td>{%if gt .Multi 0%}否{%else%}是{%end%}</td>
|
||||
<td>
|
||||
{%range $k, $h := .Hosts%}
|
||||
{%$h.Alias%}<br>
|
||||
{%end%}
|
||||
</td>
|
||||
<td>
|
||||
{%if eq .Level 1%}
|
||||
{%if eq .Status 1%}<span><i class="checkmark big icon"></i></span>{%else%}<span><i class="minus big icon"></i><span>{%end%}
|
||||
{%end%}
|
||||
</td>
|
||||
<td>
|
||||
<div class="ui buttons operation">
|
||||
{%if $.IsAdmin%}
|
||||
<a href="/task/edit/{%.Id%}" ><i class="edit big icon" title="编辑"></i></a>
|
||||
{%if eq .Level 1%}
|
||||
{%if eq .Status 1%}
|
||||
<a href="javascript:void(0);" @click="changeStatus({%.Id%},{%.Status%})"><i class="pause circle big icon" title="停止"></i></a>
|
||||
{%else%}
|
||||
<a href="javascript:void(0);" @click="changeStatus({%.Id%},{%.Status%})"><i class="play big icon" title="激活"></i></a>
|
||||
{%end%}
|
||||
{%end%}
|
||||
<a href="javascript:void(0);" @click="remove({%.Id%})"><i class="remove big icon" title="删除"></i></a>
|
||||
<a href="javascript:void(0);" @click="run({%.Id%})"><i class="rocket big icon" title="手动执行"></i></a>
|
||||
{%end%}
|
||||
|
||||
<a href="/task/log?task_id={%.Id%}"><i class="bar chart icon big" title="查看日志"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{%end%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% template "common/pagination" .%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('.ui.checkbox').checkbox();
|
||||
|
||||
$('#batch-operation').change(function() {
|
||||
var type = $(this).val();
|
||||
if (type == 0) {
|
||||
return;
|
||||
}
|
||||
var ids = [];
|
||||
$('.sub-check:checked').each(function() {
|
||||
ids.push($(this).data('id'));
|
||||
});
|
||||
if (ids.length == 0) {
|
||||
swal('错误提示', '至少选择一个任务', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
util.confirm("确定要执行此操作吗", function () {
|
||||
$.ajaxSetup({
|
||||
async: false
|
||||
});
|
||||
switch (type) {
|
||||
case "1":
|
||||
for (i in ids) {
|
||||
changeStatus(ids[i], false, true);
|
||||
}
|
||||
break;
|
||||
case "2":
|
||||
for (i in ids) {
|
||||
changeStatus(ids[i], true, true);
|
||||
}
|
||||
break;
|
||||
case "3":
|
||||
for (i in ids) {
|
||||
remove(ids[i], true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
|
||||
var vue = new Vue(
|
||||
{
|
||||
el: '.task-list',
|
||||
methods: {
|
||||
changeStatus: changeStatus,
|
||||
remove: remove,
|
||||
run: function(id) {
|
||||
util.get("/task/run/" + id, function(code, message) {
|
||||
swal('操作成功', message, 'success');
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function checkAll(ele) {
|
||||
if ($(ele).is(":checked")) {
|
||||
$('.sub-check').prop("checked", true);
|
||||
} else {
|
||||
$('.sub-check').prop("checked", false);
|
||||
}
|
||||
}
|
||||
|
||||
function remove(id, stopReload) {
|
||||
var url = '/task/remove/' + id;
|
||||
if (stopReload === undefined) {
|
||||
util.removeConfirm(url);
|
||||
return;
|
||||
}
|
||||
util.post(url, {}, function () {
|
||||
if (stopReload === undefined) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changeStatus(id ,status, stopReload) {
|
||||
var url = '';
|
||||
if (status) {
|
||||
url = '/task/disable';
|
||||
} else {
|
||||
url = '/task/enable';
|
||||
}
|
||||
url += '/' + id;
|
||||
util.post(url,{}, function() {
|
||||
if (stopReload === undefined) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,174 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<style type="text/css">
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
padding:10px;
|
||||
background-color: #4C4C4C;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<div class="ui grid">
|
||||
<!--the vertical menu-->
|
||||
{% template "task/menu" . %}
|
||||
|
||||
<div class="twelve wide column">
|
||||
{%if .IsAdmin%}
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
<button class="ui small teal button" onclick="clearLog()">清空日志</button>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
||||
<form class="ui form">
|
||||
<div class="six fields search">
|
||||
<div class="field">
|
||||
<input type="text" placeholder="任务ID" name="task_id" value="{%if gt .Params.TaskId 0%}{%.Params.TaskId%}{%end%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<select name="protocol" id="protocol">
|
||||
<option value="0">执行方式</option>
|
||||
<option value="2" {%if eq .Params.Protocol 2%}selected{%end%} data-match="host_id" data-validate-type="selectProtocol">SHELL</option>
|
||||
<option value="1" {%if eq .Params.Protocol 1%}selected{%end%}>HTTP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<select name="status">
|
||||
<option value="0">状态</option>
|
||||
<option value="1" {%if eq .Params.Status 0%}selected{%end%} >失败</option>
|
||||
<option value="2" {%if eq .Params.Status 1%}selected{%end%}>执行中</option>
|
||||
<option value="3" {%if eq .Params.Status 2%}selected{%end%}>成功</option>
|
||||
<option value="4" {%if eq .Params.Status 3%}selected{%end%}>取消</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui linkedin submit button">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="ui celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>任务ID</th>
|
||||
<th>任务名称</th>
|
||||
<th>cron表达式</th>
|
||||
<th>执行方式</th>
|
||||
<th>重试次数</th>
|
||||
<th>任务节点</th>
|
||||
<th>执行时长</th>
|
||||
<th>状态</th>
|
||||
<th>执行结果</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%range $i, $v := .Logs%}
|
||||
<tr>
|
||||
<td><a href="/task?id={%.TaskId%}">{%.TaskId%}</a></td>
|
||||
<td>{%.Name%}</td>
|
||||
<td>{%.Spec%}</td>
|
||||
<td>{%if eq .Protocol 1%} HTTP {%else if eq .Protocol 2%} SHELL {%end%}</td>
|
||||
<td>{%.RetryTimes%}</td>
|
||||
<td>{%unescape .Hostname%}</td>
|
||||
<td>
|
||||
{%if and (ne .Status 3) (ne .Status 4)%}
|
||||
{%if gt .TotalTime 0%}{%.TotalTime%}秒{%else%}1秒{%end%}<br>
|
||||
开始时间: {%.StartTime.Format "2006-01-02 15:04:05" %}<br>
|
||||
{%if ne .Status 1%}
|
||||
结束时间: {%.EndTime.Format "2006-01-02 15:04:05" %}
|
||||
{%end%}
|
||||
{%end%}
|
||||
</td>
|
||||
<td>
|
||||
{%if eq .Status 2%}
|
||||
成功
|
||||
{%else if eq .Status 1%}
|
||||
<span style="color:green">执行中</span>
|
||||
{%else if eq .Status 0%}
|
||||
<span style="color:red">失败</span>
|
||||
{%else if eq .Status 3%}
|
||||
<span style="color:#4499EE">取消</span>
|
||||
{%end%}
|
||||
</td>
|
||||
<td>
|
||||
{%if or (eq .Status 2) (eq .Status 0)%}
|
||||
<button class="ui small primary button"
|
||||
onclick="showResult('{%.Name%}', '{%.Command%}', '{%.Result%}')"
|
||||
>查看结果
|
||||
</button>
|
||||
{%end%}
|
||||
|
||||
|
||||
{%if $.IsAdmin%}
|
||||
{%if and (eq .Status 1) (eq .Protocol 2) %}
|
||||
<button class="ui small blue button" onclick="stopTask({%.Id%}, {%.TaskId%})">停止任务</button>
|
||||
{%end%}
|
||||
{%end%}
|
||||
</td>
|
||||
</tr>
|
||||
{%end%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% template "common/pagination" .%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="message">
|
||||
<result></result>
|
||||
</div>
|
||||
|
||||
<script type="text/x-vue-template" id="task-result">
|
||||
<div class="ui modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="header">
|
||||
{{name}}
|
||||
</div>
|
||||
<div>
|
||||
<pre style="background-color:#04477C;color:lightslategray">{{command}}</pre>
|
||||
</div>
|
||||
<div>
|
||||
<pre>{{result}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function showResult(name, command,result) {
|
||||
$('.message').html($('#task-result').html());
|
||||
new Vue(
|
||||
{
|
||||
el: '.message',
|
||||
data: {
|
||||
result: result.replace(/\\n/,"<br>"),
|
||||
name: name,
|
||||
command: command
|
||||
}
|
||||
}
|
||||
);
|
||||
$('.ui.modal.transition').remove();
|
||||
$('.ui.modal').modal({
|
||||
detachable: false,
|
||||
observeChanges: true
|
||||
}).modal('refresh').modal('show');
|
||||
}
|
||||
|
||||
function stopTask(id, taskId) {
|
||||
util.confirm("确定要停止任务吗", function () {
|
||||
util.post("/task/log/stop/", {id: id, task_id:taskId}, function (code, message) {
|
||||
swal('提示', message, 'info');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clearLog() {
|
||||
util.confirm("确定要删除所有日志吗?", function() {
|
||||
util.post("/task/log/clear",{}, function() {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,12 +0,0 @@
|
|||
<div class="three wide column">
|
||||
<div class="verticalMenu">
|
||||
<div class="ui vertical pointing menu fluid">
|
||||
<a class="{%if eq .URI "/task"%}active teal{%end%} item" href="/task">
|
||||
<i class="tasks icon"></i> 定时任务列表
|
||||
</a>
|
||||
<a class="item {%if eq .URI "/task/log"%}active teal{%end%} " href="/task/log">
|
||||
<i class="bar chart icon"></i> 定时任务日志
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,468 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui grid">
|
||||
{%template "task/menu" .%}
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
{%.Title%}
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form fluid vertical segment">
|
||||
<input type="hidden" name="id" value="{%.Task.Id%}">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">任务名称</div>
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="name" placeholder="任务名称" value="{%.Task.Name%}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">标签名称</div>
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="tag" placeholder="标签用于任务分类" value="{%.Task.Tag%}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">任务类型</div>
|
||||
<div class="ui message">
|
||||
主任务可以配置多个子任务, 当主任务执行完成后,自动执行子任务<br>
|
||||
任务类型新增后不能变更
|
||||
</div>
|
||||
</label>
|
||||
<select name="level" id="level" {%if .Task%}disabled="disabled"{%end%}>
|
||||
<option value="1" {%if .Task%} {%if eq .Task.Level 1%}selected{%end%} {%end%}>主任务</option>
|
||||
<option value="2" {%if .Task%} {%if eq .Task.Level 2%}selected{%end%} {%end%}>子任务</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="parent-task">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">依赖关系</div>
|
||||
<div class="ui message">
|
||||
强依赖: 主任务执行成功,才会运行子任务 <br>
|
||||
弱依赖: 无论主任务执行是否成功,都会运行子任务
|
||||
</div>
|
||||
</label>
|
||||
<select name="dependency_status" id="dependency_status">
|
||||
<option value="1" {%if .Task%} {%if eq .Task.DependencyStatus 1%}selected{%end%} {%end%}>强依赖</option>
|
||||
<option value="2" {%if .Task%} {%if eq .Task.DependencyStatus 2%}selected{%end%} {%end%}>弱依赖</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">子任务ID</div>
|
||||
<div class="ui message">
|
||||
多个任务ID逗号分隔 <br>
|
||||
子任务并发执行
|
||||
</div>
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="dependency_task_id" placeholder="可选" value="{%.Task.DependencyTaskId%}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
<div class="content">
|
||||
crontab表达式
|
||||
</div>
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="spec" value="{%.Task.Spec%}" placeholder="秒 分 时 天 月 周"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>执行方式</label>
|
||||
<select name="protocol" id="protocol">
|
||||
<option value="2" {%if .Task%} {%if eq .Task.Protocol 2%}selected{%end%} {%end%}
|
||||
data-validate-type="selectProtocol">SHELL</option>
|
||||
<option value="1" {%if .Task%} {%if eq .Task.Protocol 1%}selected{%end%} {%end%}>HTTP</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields" id="hostField">
|
||||
<div class="field">
|
||||
<label>选择任务节点</label>
|
||||
<div id="hostId">
|
||||
{%range $i, $v := .Hosts%}
|
||||
<label>
|
||||
<input type="checkbox" value="{%.Id%}" {%if $.Task%}{%if $v.Selected%} checked {%end%}{%end%} style="width:25px;height: 25px;">{%.Alias%}-{%.Name%}
|
||||
{%if (HostFormat $i) %}<br>{%end%}
|
||||
</label>
|
||||
{%end%}
|
||||
</div> <br> <a class="ui blue button" href="/host/create" target="_blank">添加节点</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields" id="http-method" style="display: none">
|
||||
<div class="field">
|
||||
<label>请求方法</label>
|
||||
<select name="http_method">
|
||||
<option value="1" {%if .Task%} {%if eq .Task.HttpMethod 1%}selected{%end%} {%end%}>GET</option>
|
||||
<option value="2" {%if .Task%} {%if eq .Task.HttpMethod 2%}selected{%end%} {%end%}
|
||||
data-validate-type="selectProtocol">POST</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>命令</label>
|
||||
<textarea rows="5" name="command" placeholder="请输入系统命令" id="command">{%.Task.Command%}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>任务超时时间(秒, 0-86400)</label>
|
||||
<input type="text" name="timeout" placeholder="默认0, 不限制" value="{%if .Task%} {%.Task.Timeout%} {%else%}0{%end%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>允许多实例同时运行</label>
|
||||
<select name="multi">
|
||||
<option value="2" {%if .Task%} {%if eq .Task.Multi 0%}selected{%end%} {%end%}>否</option>
|
||||
<option value="1"{%if .Task%} {%if eq .Task.Multi 1%}selected{%end%} {%end%}>是</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>任务失败重试次数 (0-10)</label>
|
||||
<input type="text" name="retry_times" placeholder="默认0, 不重试" value="{%if .Task%} {%.Task.RetryTimes%} {%else%}0{%end%}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>任务失败重试间隔时间 (秒, 0-3600)</label>
|
||||
<input type="text" name="retry_interval" placeholder="默认0, 执行默认重试策略" value="{%if .Task%} {%.Task.RetryInterval%} {%else%}0{%end%}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>任务通知</label>
|
||||
<select name="notify_status" id="task-status">
|
||||
<option value="1"{%if .Task%} {%if eq .Task.NotifyStatus 0%}selected{%end%} {%end%}>不通知</option>
|
||||
<option value="2" {%if .Task%} {%if eq .Task.NotifyStatus 1%}selected{%end%} {%end%}>失败通知</option>
|
||||
<option value="3" {%if .Task%} {%if eq .Task.NotifyStatus 2%}selected{%end%} {%end%}>执行结束通知</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields" style="display: none" id="task-notify-type">
|
||||
<div class="field" >
|
||||
<label>通知类型</label>
|
||||
<select name="notify_type">
|
||||
<option value="1"{%if .Task%} {%if eq .Task.NotifyType 0%}selected{%end%} {%end%}>请选择</option>
|
||||
<option value="2" {%if .Task%} {%if eq .Task.NotifyType 1%}selected{%end%} {%end%}>邮件</option>
|
||||
<option value="3" {%if .Task%} {%if eq .Task.NotifyType 2%}selected{%end%} {%end%}>Slack</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline fields" style="display: none" id="receiver-id"></div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>备注</label>
|
||||
<textarea rows="5" name="remark" placeholder="任务备注信息">{%.Task.Remark%}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui primary submit button">保存</div> <a class="ui button" onclick="location.href='/task';">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="x-handlerbar-template" id="mail-template">
|
||||
{{#each MailUsers}}
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="receiver[]" {{#if checked}}checked{{/if}} value="{{Id}}" />
|
||||
<label>{{Username}}-{{Email}}</label>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<a class="ui blue button" href="/manage/mail/edit" target="_blank">邮箱配置</a><br><br>
|
||||
{{/each}}
|
||||
</script>
|
||||
|
||||
<script type="x-handlervar-template" id="slack-template">
|
||||
{{#each Channels}}
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="receiver[]" {{#if checked}}checked{{/if}} value="{{Id}}" />
|
||||
<label>{{Name}}</label>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<a class="ui blue button" href="/manage/slack/edit" target="_blank">Slack配置</a>
|
||||
{{/each}}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
changeCommandPlaceholder();
|
||||
changeLevel();
|
||||
changeProtocol();
|
||||
showNotify();
|
||||
});
|
||||
|
||||
$('#protocol').change(function() {
|
||||
changeCommandPlaceholder();
|
||||
changeProtocol();
|
||||
});
|
||||
|
||||
$('#level').change(function() {
|
||||
changeLevel();
|
||||
});
|
||||
|
||||
$('#task-status').change(function() {
|
||||
var selected = $(this).val();
|
||||
if (selected == 1) {
|
||||
$('#task-notify-type').hide();
|
||||
$('#receiver-id').hide();
|
||||
$('#task-notify-type').find('select').val('1');
|
||||
return;
|
||||
}
|
||||
$('#task-notify-type').show();
|
||||
});
|
||||
|
||||
$('#task-notify-type').change(function() {
|
||||
changeNotify();
|
||||
});
|
||||
|
||||
function changeCommandPlaceholder() {
|
||||
var selectedId = $('#protocol').val();
|
||||
switch (selectedId) {
|
||||
case '1':
|
||||
$('#command').attr('placeholder', '请输入URL地址');
|
||||
break;
|
||||
case '2':
|
||||
$('#command').attr('placeholder', '请输入shell命令');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function showNotify() {
|
||||
var notifyStatus = {%.Task.NotifyStatus%};
|
||||
if (notifyStatus > 0) {
|
||||
$('#task-notify-type').show();
|
||||
}
|
||||
var notifyReceiverIds = '{%.Task.NotifyReceiverId%}'.split(',');
|
||||
changeNotify(notifyReceiverIds);
|
||||
}
|
||||
|
||||
function changeNotify(notifyReceiverIds) {
|
||||
var selectedId = $('#task-notify-type').find('select').val();
|
||||
if (selectedId == 1) {
|
||||
$('#receiver-id').hide();
|
||||
$('#receiver-id').html('');
|
||||
return;
|
||||
}
|
||||
if (selectedId == 2) {
|
||||
showMail(notifyReceiverIds);
|
||||
} else if (selectedId == 3) {
|
||||
showSlack(notifyReceiverIds);
|
||||
}
|
||||
$('#receiver-id').show();
|
||||
}
|
||||
|
||||
function showMail(notifyReceiverIds) {
|
||||
util.get("/manage/mail", function(code, message, data) {
|
||||
renderReceiver(notifyReceiverIds, $('#mail-template'), data, 'MailUsers');
|
||||
})
|
||||
}
|
||||
|
||||
function showSlack(notifyReceiverIds) {
|
||||
util.get("/manage/slack", function(code, message, data) {
|
||||
renderReceiver(notifyReceiverIds, $('#slack-template'), data, 'Channels');
|
||||
})
|
||||
}
|
||||
|
||||
function renderReceiver(notifyReceiverIds, $element, data, key) {
|
||||
if (notifyReceiverIds !== undefined && notifyReceiverIds) {
|
||||
console.log(data[key]);
|
||||
for (i in data[key]) {
|
||||
if ($.inArray(data[key][i].Id + '', notifyReceiverIds) != -1) {
|
||||
data[key][i].checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
var html = util.renderTemplate($($element), data);
|
||||
$('#receiver-id').html(html);
|
||||
$('.ui.checkbox').checkbox();
|
||||
}
|
||||
|
||||
function changeProtocol() {
|
||||
var protocol = $('#protocol').val();
|
||||
if (protocol == 2) {
|
||||
$('#hostField').show();
|
||||
$('#http-method').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#hostField').hide();
|
||||
$('#http-method').show();
|
||||
}
|
||||
|
||||
$('.ui.checkbox')
|
||||
.checkbox()
|
||||
;
|
||||
|
||||
function validateNotify() {
|
||||
var selectedId = $('#task-status').val();
|
||||
if (selectedId == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var checkedLength = $('#receiver-id input:checked').length;
|
||||
if (checkedLength == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseNotifyReceiver() {
|
||||
var receivers = [];
|
||||
$('#receiver-id input:checked').each(function() {
|
||||
receivers.push($(this).val());
|
||||
});
|
||||
|
||||
return receivers.join(",");
|
||||
}
|
||||
|
||||
function parseHostId() {
|
||||
var hostIds = [];
|
||||
$('#hostId input:checked').each(function () {
|
||||
hostIds.push($(this).val());
|
||||
});
|
||||
|
||||
return hostIds.join(",");
|
||||
}
|
||||
|
||||
function changeLevel() {
|
||||
var selected = $('#level').val();
|
||||
if (selected == 1) {
|
||||
// 主任务
|
||||
$('#parent-task').show();
|
||||
$('#child-task').hide();
|
||||
} else {
|
||||
// 子任务
|
||||
$('#parent-task').hide();
|
||||
$('#child-task').show();
|
||||
}
|
||||
}
|
||||
|
||||
var $uiForm = $('.ui.form');
|
||||
registerSelectFormValidation("selectProtocol", $uiForm, $('#protocol'), 'protocol');
|
||||
$($uiForm).form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
if (!validateNotify()) {
|
||||
swal('错误提示', '请至少选择一个接收者', 'error');
|
||||
return false;
|
||||
}
|
||||
fields.notify_receiver_id = parseNotifyReceiver();
|
||||
fields.host_id = parseHostId();
|
||||
if (fields.protocol == 2 && fields.host_id == "") {
|
||||
swal('错误提示', '请选择任务节点');
|
||||
return false;
|
||||
}
|
||||
|
||||
util.post('/task/store', fields, function(code, message) {
|
||||
location.href = "/task"
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
identifier : 'name',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入任务名称'
|
||||
},
|
||||
{
|
||||
type : 'maxLength[32]',
|
||||
prompt : '长度不能超过32'
|
||||
}
|
||||
]
|
||||
},
|
||||
command: {
|
||||
identifier : 'command',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入任务命令'
|
||||
},
|
||||
{
|
||||
type : 'maxLength[256]',
|
||||
prompt : '长度不能超过256'
|
||||
}
|
||||
]
|
||||
},
|
||||
hosts: {
|
||||
identifier : 'host_id',
|
||||
rules: [
|
||||
{
|
||||
type : 'selectProtocol',
|
||||
prompt : '请选择主机'
|
||||
}
|
||||
]
|
||||
},
|
||||
timeout: {
|
||||
identifier : 'timeout',
|
||||
rules: [
|
||||
{
|
||||
type : 'integer[0..86400]',
|
||||
prompt : '超时范围0-86400'
|
||||
}
|
||||
]
|
||||
},
|
||||
retryTimes: {
|
||||
identifier : 'retry_times',
|
||||
rules: [
|
||||
{
|
||||
type : 'integer[0..10]',
|
||||
prompt : '重试次数0-10'
|
||||
}
|
||||
]
|
||||
},
|
||||
retryInterval: {
|
||||
identifier : 'retry_interval',
|
||||
rules: [
|
||||
{
|
||||
type : 'integer[0..3600]',
|
||||
prompt : '重试间隔时间0-3600'
|
||||
}
|
||||
]
|
||||
},
|
||||
remark: {
|
||||
identifier : 'remark',
|
||||
rules: [
|
||||
{
|
||||
type : 'maxLength[100]',
|
||||
prompt : '长度不能超过100'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,73 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui small modal">
|
||||
<div class="header">修改密码</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>原密码</label>
|
||||
<input class="small input" type="password" name="old_password" placeholder="原密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>新密码</label>
|
||||
<input type="password" name="new_password" placeholder="新密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>确认新密码</label>
|
||||
<input type="password" name="confirm_new_password" placeholder="确认新密码">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button primary button" >确定</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('.ui.modal').modal('setting', 'closable', false).modal('show');
|
||||
$('.ui.form').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/user/editMyPassword', fields, function(code, message) {
|
||||
swal("操作成功", '修改成功', 'success');
|
||||
location.href = "/task"
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
oldPassword: {
|
||||
identifier : 'old_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入原密码'
|
||||
}
|
||||
]
|
||||
},
|
||||
newPassword: {
|
||||
identifier : 'new_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入新密码'
|
||||
}
|
||||
]
|
||||
},
|
||||
confirmNewPassword: {
|
||||
identifier : 'confirm_new_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'match[new_password]',
|
||||
prompt : '两次输入密码不匹配'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,58 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui small modal">
|
||||
<div class="header">修改密码</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>新密码</label>
|
||||
<input type="password" name="new_password" placeholder="新密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>确认新密码</label>
|
||||
<input type="password" name="confirm_new_password" placeholder="确认新密码">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button primary button" >确定</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('.ui.modal').modal('setting', 'closable', false).modal('show');
|
||||
$('.ui.form').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/user/editPassword/{%.Id%}', fields, function(code, message) {
|
||||
swal("操作成功", '修改成功', 'success');
|
||||
location.href = "/user"
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
newPassword: {
|
||||
identifier : 'new_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入新密码'
|
||||
}
|
||||
]
|
||||
},
|
||||
confirmNewPassword: {
|
||||
identifier : 'confirm_new_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'match[new_password]',
|
||||
prompt : '两次输入密码不匹配'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,73 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
<div class="ui grid">
|
||||
{% template "user/menu" . %}
|
||||
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<a href="/user/create">
|
||||
<i class="large add icon"></i>
|
||||
<div class="content">
|
||||
添加用户
|
||||
</div>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户ID</th>
|
||||
<th>用户名</th>
|
||||
<th>邮箱</th>
|
||||
<th>角色</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%range $i, $v := .Users%}
|
||||
<tr>
|
||||
<td>{%.Id%}</td>
|
||||
<td>{%.Name%}</td>
|
||||
<td>{%.Email%}</td>
|
||||
<td>{%if .IsAdmin%}管理员{%else%}普通用户{%end%}</td>
|
||||
<td>{%if .Status%}启用{%else%}禁用{%end%}</td>
|
||||
<td class="operation">
|
||||
<a class="ui purple button" href="/user/edit/{%.Id%}">编辑</a>
|
||||
{%if eq .Status 1%}
|
||||
<button class="ui button red" onclick="changeStatus({%.Id%},{%.Status%})">禁用</button>
|
||||
{%else%}
|
||||
<button class="ui button twitter" onclick="changeStatus({%.Id%},{%.Status%})">启用</button>
|
||||
{%end%}
|
||||
<a href="/user/editPassword/{%.Id%}">
|
||||
<button class="ui button facebook">修改密码</button>
|
||||
</a>
|
||||
<button class="ui positive button" onclick="util.removeConfirm('/user/remove/{%.Id%}')">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
{%end%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% template "common/pagination" .%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function changeStatus(id ,status) {
|
||||
var url = '';
|
||||
if (status) {
|
||||
url = '/user/disable';
|
||||
} else {
|
||||
url = '/user/enable';
|
||||
}
|
||||
url += '/' + id;
|
||||
util.post(url,{}, function() {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -1,74 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
<div class="ui small modal">
|
||||
<div class="header">用户登录</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<input class="small input" type="text" name="username" placeholder="用户名或邮箱">
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<input type="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
{%.Captcha.CreateHtml%}
|
||||
<input type="text" name="captcha" placeholder="验证码">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button primary button" >登录</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('.ui.modal').modal('setting', 'closable', false).modal('show');
|
||||
$('.ui.form').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/user/login', fields, function(code, message) {
|
||||
location.href = "/"
|
||||
}, function (code, message) {
|
||||
if (code == 5) {
|
||||
$('.captcha-img').trigger('click');
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
username: {
|
||||
identifier : 'username',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入用户名'
|
||||
}
|
||||
]
|
||||
},
|
||||
Password: {
|
||||
identifier : 'password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入密码'
|
||||
}
|
||||
]
|
||||
},
|
||||
Captcha: {
|
||||
identifier : 'captcha',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入验证码'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
{% template "common/footer" . %}
|
|
@ -1,9 +0,0 @@
|
|||
<div class="four wide column">
|
||||
<div class="verticalMenu">
|
||||
<div class="ui vertical pointing menu fluid">
|
||||
<a class="{%if eq .URI "/user"%}active teal{%end%} item" href="/user">
|
||||
<i class="user icon"></i> 用户列表
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,142 +0,0 @@
|
|||
{% template "common/header" . %}
|
||||
|
||||
<div class="ui grid">
|
||||
{% template "user/menu" . %}
|
||||
|
||||
<div class="twelve wide column">
|
||||
<div class="pageHeader">
|
||||
<div class="segment">
|
||||
<h3 class="ui dividing header">
|
||||
<div class="content">
|
||||
添加用户
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form fluid vertical segment">
|
||||
<input type="hidden" name="id" value="{%.User.Id%}">
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>用户名</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="name" value="{%.User.Name%}" placeholder="请输入用户名">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>邮箱</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="email" value="{%.User.Email%}" placeholder="请输入邮箱">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%if eq .User.Id 0%}
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>密码</label>
|
||||
<input type="password" name="password" placeholder="请输入密码">
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>确认密码</label>
|
||||
<input type="password" name="confirm_password" placeholder="请再次输入密码">
|
||||
</div>
|
||||
</div>
|
||||
{%end%}
|
||||
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>角色</label>
|
||||
<input type="radio" name="is_admin" value="0" {%if eq .User.IsAdmin 0%}checked{%end%}> 普通用户
|
||||
<input type="radio" name="is_admin" value="1" {%if eq .User.IsAdmin 1%}checked{%end%}> 管理员
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>状态</label>
|
||||
<input type="radio" name="status" value="1" {%if eq .User.Status 1%}checked{%end%}> 启用
|
||||
<input type="radio" name="status" value="0"
|
||||
{%if eq .User.Status 0%}checked{%end%}
|
||||
> 禁用
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui primary submit button">保存</div>
|
||||
<a class="ui button" onclick="location.href='/user';">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var $uiForm = $('.ui.form');
|
||||
$($uiForm).form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/user/store', fields, function(code, message) {
|
||||
location.href = "/user"
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
identifier : 'name',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入用户名'
|
||||
},
|
||||
{
|
||||
type : 'minLength[3]',
|
||||
prompt : '长度不能少于3'
|
||||
},
|
||||
{
|
||||
type : 'maxLength[32]',
|
||||
prompt : '长度不能超过32'
|
||||
}
|
||||
]
|
||||
},
|
||||
password: {
|
||||
identifier : 'password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入密码'
|
||||
},
|
||||
{
|
||||
type : 'minLength[6]',
|
||||
prompt : '长度不能少于6位'
|
||||
}
|
||||
]
|
||||
},
|
||||
confirmPassword: {
|
||||
identifier : 'confirm_password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请再次输入密码'
|
||||
},
|
||||
{
|
||||
type : 'match[password]',
|
||||
prompt : '两次输入密码不匹配'
|
||||
}
|
||||
]
|
||||
},
|
||||
email: {
|
||||
identifier : 'email',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入邮箱'
|
||||
},
|
||||
{
|
||||
type : 'email',
|
||||
prompt : '邮箱格式错误'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
|
||||
{% template "common/footer" . %}
|
|
@ -16,7 +16,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import installService from './api/install'
|
||||
import appHeader from './components/common/header.vue'
|
||||
import appNavMenu from './components/common/navMenu.vue'
|
||||
import appFooter from './components/common/footer.vue'
|
||||
|
@ -26,7 +26,9 @@ export default {
|
|||
data () {
|
||||
return {}
|
||||
},
|
||||
|
||||
created () {
|
||||
installService.store({})
|
||||
},
|
||||
components: {
|
||||
appHeader,
|
||||
appNavMenu,
|
||||
|
|
|
@ -9,7 +9,7 @@ export default {
|
|||
httpClient.post('/task/log/clear', {}, callback)
|
||||
},
|
||||
|
||||
stop (id, callback) {
|
||||
httpClient.post('/task/log/stop', {id}, callback)
|
||||
stop (id, taskId, callback) {
|
||||
httpClient.post('/task/log/stop', {id, task_id: taskId}, callback)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,10 +102,13 @@ export default {
|
|||
this.searchParams.page_size = pageSize
|
||||
this.search()
|
||||
},
|
||||
search () {
|
||||
search (callback = null) {
|
||||
hostService.list(this.searchParams, (data) => {
|
||||
this.hosts = data.data
|
||||
this.hostTotal = data.total
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
},
|
||||
remove (item) {
|
||||
|
@ -128,7 +131,9 @@ export default {
|
|||
this.$router.push(path)
|
||||
},
|
||||
refresh () {
|
||||
this.search()
|
||||
this.search(() => {
|
||||
this.$message.success('刷新成功')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -283,11 +283,14 @@ export default {
|
|||
this.searchParams.page_size = pageSize
|
||||
this.search()
|
||||
},
|
||||
search () {
|
||||
search (callback = null) {
|
||||
taskService.list(this.searchParams, (tasks, hosts) => {
|
||||
this.tasks = tasks.data
|
||||
this.taskTotal = tasks.total
|
||||
this.hosts = hosts.data
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
},
|
||||
runTask (item) {
|
||||
|
@ -308,7 +311,9 @@ export default {
|
|||
this.$router.push(`/task/log?task_id=${item.id}`)
|
||||
},
|
||||
refresh () {
|
||||
this.search()
|
||||
this.search(() => {
|
||||
this.$message.success('刷新成功')
|
||||
})
|
||||
},
|
||||
toEdit (item) {
|
||||
let path = ''
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
</el-table-column>
|
||||
<el-table-column
|
||||
label="执行结果"
|
||||
width="120">
|
||||
width="120" v-if="this.isAdmin">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="success"
|
||||
v-if="scope.row.status === 2"
|
||||
|
@ -120,11 +120,23 @@
|
|||
v-if="scope.row.status === 0"
|
||||
@click="showTaskResult(scope.row)" >查看结果</el-button>
|
||||
<el-button type="danger"
|
||||
v-if="this.isAdmin && scope.row.status === 1 && scope.row.protocol === 2"
|
||||
v-if="scope.row.status === 1 && scope.row.protocol === 2"
|
||||
@click="stopTask(scope.row)">停止任务
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="执行结果"
|
||||
width="120" v-else>
|
||||
<template slot-scope="scope">
|
||||
<el-button type="success"
|
||||
v-if="scope.row.status === 2"
|
||||
@click="showTaskResult(scope.row)">查看结果</el-button>
|
||||
<el-button type="warning"
|
||||
v-if="scope.row.status === 0"
|
||||
@click="showTaskResult(scope.row)" >查看结果</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-dialog title="任务执行结果" :visible.sync="dialogVisible">
|
||||
<div>
|
||||
|
@ -213,10 +225,14 @@ export default {
|
|||
this.searchParams.page_size = pageSize
|
||||
this.search()
|
||||
},
|
||||
search () {
|
||||
search (callback = null) {
|
||||
taskLogService.list(this.searchParams, (data) => {
|
||||
this.logs = data.data
|
||||
this.logTotal = data.total
|
||||
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
},
|
||||
clearLog () {
|
||||
|
@ -228,7 +244,7 @@ export default {
|
|||
})
|
||||
},
|
||||
stopTask (item) {
|
||||
taskLogService.stop(item.id, () => {
|
||||
taskLogService.stop(item.id, item.task_id, () => {
|
||||
this.search()
|
||||
})
|
||||
},
|
||||
|
@ -238,7 +254,9 @@ export default {
|
|||
this.currentTaskResult.result = item.result
|
||||
},
|
||||
refresh () {
|
||||
this.search()
|
||||
this.search(() => {
|
||||
this.$message.success('刷新成功')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ export default {
|
|||
})
|
||||
},
|
||||
save () {
|
||||
console.log(this.form)
|
||||
userService.editMyPassword(this.form, () => {
|
||||
this.$router.back()
|
||||
})
|
||||
|
|
|
@ -109,10 +109,13 @@ export default {
|
|||
this.searchParams.page_size = pageSize
|
||||
this.search()
|
||||
},
|
||||
search () {
|
||||
search (callback = null) {
|
||||
userService.list(this.searchParams, (data) => {
|
||||
this.users = data.data
|
||||
this.userTotal = data.total
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
},
|
||||
remove (item) {
|
||||
|
@ -132,7 +135,9 @@ export default {
|
|||
this.$router.push(path)
|
||||
},
|
||||
refresh () {
|
||||
this.search()
|
||||
this.search(() => {
|
||||
this.$message.success('刷新成功')
|
||||
})
|
||||
},
|
||||
editPassword (item) {
|
||||
this.$router.push(`/user/edit-password/${item.id}`)
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
:visible.sync="dialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
:close-on-press-escape="false">
|
||||
:close-on-press-escape="false"
|
||||
width="40%">
|
||||
<el-form ref="form" :model="form" label-width="80px"
|
||||
:rules="formRules">
|
||||
<el-form-item label="用户名" prop="username" >
|
||||
|
|
|
@ -160,10 +160,6 @@ router.beforeEach((to, from, next) => {
|
|||
next()
|
||||
return
|
||||
}
|
||||
if (to.fullPath === '/task') {
|
||||
next()
|
||||
return
|
||||
}
|
||||
if (store.getters.user.token) {
|
||||
if ((store.getters.user.isAdmin || to.meta.noNeedAdmin)) {
|
||||
next()
|
||||
|
|
Loading…
Reference in New Issue