diff --git a/plugin/think-plugs-static/stc/public/static/plugs/system/queue.js b/plugin/think-plugs-static/stc/public/static/plugs/system/queue.js index df342d2b2..0a3784da3 100644 --- a/plugin/think-plugs-static/stc/public/static/plugs/system/queue.js +++ b/plugin/think-plugs-static/stc/public/static/plugs/system/queue.js @@ -15,12 +15,16 @@ layui.define(function (exports) { let template = [ - '
',
@@ -33,32 +37,49 @@ layui.define(function (exports) {
let style = document.createElement('style');
style.id = 'ta-queue-style';
style.innerHTML = [
- '.ta-queue-layer{border-radius:10px;overflow:hidden;}',
- '.ta-queue-layer .layui-layer-title{height:48px;line-height:48px;font-weight:600;border-bottom:1px solid #edf0f5;background:#fff;}',
- '.ta-queue-layer .layui-layer-content{overflow:hidden;background:#f6f8fb;}',
- '.ta-queue-box{padding:18px 20px 20px;background:#f6f8fb;}',
- '.ta-queue-status{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:13px 15px;background:#fff;border:1px solid #edf0f5;border-radius:10px;box-shadow:0 4px 18px rgba(15,35,60,.04);}',
- '.ta-queue-status-title{min-width:0;flex:1;font-weight:600;}',
- '.ta-queue-status-title b{font-weight:600;}',
- '.ta-queue-status-code{flex-shrink:0;max-width:220px;color:#8c98a8;font-size:12px;line-height:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}',
- '.ta-queue-progress{height:12px;margin:14px 2px 0;border-radius:999px;background:#e8edf5;overflow:hidden;}',
- '.ta-queue-progress .layui-progress-bar{border-radius:999px;}',
- '.ta-queue-progress .layui-progress-text{top:-6px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2);}',
- '.ta-queue-log{margin-top:14px;border-radius:10px;background:#222b33;border:1px solid #1a222a;overflow:hidden;box-shadow:inset 0 0 0 1px rgba(255,255,255,.02);}',
- '.ta-queue-log-head{height:36px;display:flex;align-items:center;justify-content:space-between;padding:0 14px;background:#172027;color:#dce5ee;font-size:13px;}',
- '.ta-queue-log-head small{font-size:12px;font-weight:400;color:#7f8b98;}',
- '.ta-queue-log code{display:block;height:185px;margin:0;padding:12px 14px;border:0;background:#222b33;color:#dce5ee;font-family:Consolas,Monaco,Menlo,monospace;font-size:12px;line-height:22px;white-space:normal;overflow:auto;}',
- '.ta-queue-log code p{height:22px;line-height:22px;margin:0;color:#dce5ee;}',
- '.ta-queue-log code .color-desc{color:#8c98a8!important;}'
+ '@keyframes taQueuePulse{0%{box-shadow:0 0 0 0 rgba(59,130,246,.28);}70%{box-shadow:0 0 0 8px rgba(59,130,246,0);}100%{box-shadow:0 0 0 0 rgba(59,130,246,0);}}',
+ '.ta-queue-layer{border-radius:12px;overflow:hidden;box-shadow:0 18px 45px rgba(15,23,42,.22);}',
+ '.ta-queue-layer .layui-layer-title{height:50px;line-height:50px;padding:0 50px 0 18px;color:#1f2937;font-size:15px;font-weight:700;border-bottom:1px solid var(--ta-border-color,#edf0f5);background:linear-gradient(180deg,#fff,#f8fbfc);}',
+ '.ta-queue-layer .layui-layer-setwin{top:17px;right:16px;}',
+ '.ta-queue-layer .layui-layer-content{overflow:hidden;background:var(--ta-body-bg,#f4f7fb);}',
+ '.ta-queue-box{height:100%;min-height:0;box-sizing:border-box;display:flex;flex-direction:column;padding:18px 20px 20px;background:var(--ta-body-bg,#f4f7fb);}',
+ '.ta-queue-status{min-height:50px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;gap:14px;box-sizing:border-box;padding:12px 14px;background:var(--ta-surface,#fff);border:1px solid var(--ta-border-color,#edf0f5);border-radius:12px;box-shadow:0 8px 22px rgba(15,35,60,.06);}',
+ '.ta-queue-status-main{display:flex;align-items:center;gap:10px;min-width:0;flex:1;}',
+ '.ta-queue-status-dot{width:8px;height:8px;display:inline-block;flex:0 0 8px;border-radius:50%;background:#94a3b8;}',
+ '.ta-queue-status-title{min-width:0;flex:1;color:#334155;font-size:13px;font-weight:600;text-align:left!important;}',
+ '.ta-queue-status-title b{font-weight:700;}',
+ '.ta-queue-status-code{flex-shrink:0;max-width:220px;padding:2px 8px;color:#8c98a8;font-size:12px;line-height:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:999px;background:#f3f6fa;}',
+ '.ta-queue-box[data-queue-state="1"] .ta-queue-status-dot,.ta-queue-box[data-queue-state="2"] .ta-queue-status-dot{background:#3b82f6;animation:taQueuePulse 1.6s ease-out infinite;}',
+ '.ta-queue-box[data-queue-state="3"] .ta-queue-status{border-color:#b7ebc6;background:linear-gradient(135deg,#f6ffed,#fff);}',
+ '.ta-queue-box[data-queue-state="3"] .ta-queue-status-dot{background:#16a34a;box-shadow:0 0 0 5px rgba(22,163,74,.12);}',
+ '.ta-queue-box[data-queue-state="4"] .ta-queue-status{border-color:#ffd6d6;background:linear-gradient(135deg,#fff5f5,#fff);}',
+ '.ta-queue-box[data-queue-state="4"] .ta-queue-status-dot{background:#ff4d4f;box-shadow:0 0 0 5px rgba(255,77,79,.12);}',
+ '.ta-queue-box[data-queue-state="4"] .ta-queue-status-title,.ta-queue-box[data-queue-state="4"] .ta-queue-status-title b{color:#ff4d4f!important;}',
+ '.ta-queue-progress-meta{flex-shrink:0;display:flex;align-items:center;justify-content:space-between;margin:12px 2px 6px;color:#7b8794;font-size:12px;line-height:18px;}',
+ '.ta-queue-progress-meta b{color:#475569;font-size:12px;font-weight:600;}',
+ '.ta-queue-progress{flex-shrink:0;height:10px;border-radius:999px;background:#e7edf5;overflow:hidden;}',
+ '.ta-queue-progress .layui-progress-bar{height:10px;border-radius:999px;box-shadow:0 2px 6px rgba(30,64,175,.22);}',
+ '.ta-queue-log{flex:1 1 auto;min-height:230px;display:flex;flex-direction:column;margin-top:14px;border-radius:12px;background:#202a33;border:1px solid #19232c;overflow:hidden;box-shadow:inset 0 0 0 1px rgba(255,255,255,.02),0 10px 24px rgba(15,23,42,.12);}',
+ '.ta-queue-log-head{height:38px;flex:0 0 38px;display:flex;align-items:center;justify-content:space-between;padding:0 14px;background:#15202a;color:#e5edf5;font-size:13px;font-weight:600;}',
+ '.ta-queue-log-head small{font-size:12px;font-weight:400;color:#94a3b8;}',
+ '.ta-queue-log code{flex:1 1 auto;display:block;height:auto;min-height:0;margin:0;padding:12px 14px;border:0;box-sizing:border-box;background:#202a33;color:#e5edf5;font-family:Consolas,Monaco,Menlo,monospace;font-size:12px;line-height:22px;white-space:normal;overflow:auto;}',
+ '.ta-queue-log code p{min-height:22px;height:auto;line-height:22px;margin:0;color:#e5edf5;overflow:visible;text-overflow:clip;white-space:pre-wrap;word-break:break-word;}',
+ '.ta-queue-log code .color-desc{color:#94a3b8!important;}'
].join('');
document.head.appendChild(style);
}
+ function escapeHtml(value) {
+ return String(value).replace(/[&<>"']/g, function (char) {
+ return {'&': '&', '<': '<', '>': '>', '"': '"', "'": '''}[char];
+ });
+ }
+
function Queue(code, doScript, element) {
let queue = this;
injectStyle();
(this.doAjax = true) && (this.doReload = false) || layer.open({
- type: 1, title: '任务执行进度', area: ['620px', '390px'], skin: 'ta-queue-layer', anim: 2, shadeClose: false, end: function () {
+ type: 1, title: '任务执行进度', area: ['640px', '520px'], skin: 'ta-queue-layer', anim: 2, shadeClose: false, end: function () {
queue.doAjax = queue.doReload && doScript && $.layTable.reload(((element || {}).dataset || {}).tableId || true) && false;
}, content: laytpl(template).render({code: code}), success: function ($elem) {
new Progress($elem, code, queue, doScript);
@@ -74,6 +95,7 @@ layui.define(function (exports) {
this.$code = this.$box.find('code');
this.$title = this.$box.find('[data-message-title]');
+ this.$progressText = this.$box.find('[data-progress-text]');
this.$percent = this.$box.find('.layui-progress div');
// 设置数据缓存
@@ -84,6 +106,7 @@ layui.define(function (exports) {
// 更新任务显示状态
this.SetState = function (status, message) {
+ that.$box.attr('data-queue-state', status);
if (message.indexOf('javascript:') === -1) if (status === 1) {
that.$title.html('' + message + '').addClass('text-center');
that.$percent.addClass('layui-bg-blue').removeClass('layui-bg-green layui-bg-red');
@@ -121,7 +144,7 @@ layui.define(function (exports) {
continue;
}
if (text.indexOf('javascript:') === -1) {
- lines.push(text.indexOf('>>>') > -1 ? text : percent + text);
+ lines.push(escapeHtml(text.indexOf('>>>') > -1 ? text : percent + text));
} else if (!that.SetCache(code, idx) && doScript !== false) {
that.SetCache(code, idx, 1)
$.form.goto(text);
@@ -130,14 +153,18 @@ layui.define(function (exports) {
if (!isFinite(progress)) {
progress = 0;
}
- that.$code.html(lines.length ? '' + lines.join('
') + '
' : '暂无执行日志
').animate({scrollTop: that.$code[0].scrollHeight + 'px'}, 200); + progress = Math.max(0, Math.min(100, progress)); + let percentText = progress.toFixed(2) + '%'; + that.$code.html(lines.length ? '' + lines.join('
') + '
' : '暂无执行日志
').animate({scrollTop: that.$code[0].scrollHeight + 'px'}, 200); + that.$progressText.text(percentText); if (status > 0) { that.SetState(status, message); - that.$percent.attr('lay-percent', progress.toFixed(2) + '%') && layui.element.render(); + that.$percent.attr('lay-percent', percentText) && layui.element.render(); status === 3 || status === 4 || setTimeout(that.LoadProgress, Math.floor(Math.random() * 200)); } else { + that.$box.attr('data-queue-state', '0'); that.$title.html('' + message + '').addClass('text-center'); - that.$percent.attr('lay-percent', progress.toFixed(2) + '%') && layui.element.render(); + that.$percent.attr('lay-percent', percentText) && layui.element.render(); setTimeout(that.LoadProgress, Math.floor(Math.random() * 500) + 200); } return false; diff --git a/plugin/think-plugs-system/src/builder/QueueBuilder.php b/plugin/think-plugs-system/src/builder/QueueBuilder.php index a5c62c894..596ea1b68 100644 --- a/plugin/think-plugs-system/src/builder/QueueBuilder.php +++ b/plugin/think-plugs-system/src/builder/QueueBuilder.php @@ -124,16 +124,19 @@ function (d) { SCRIPT, self::json(BuilderLang::text('循环')), self::json(BuilderLang::text('单次')), self::json(BuilderLang::text('任务编号:')), self::json(BuilderLang::text('任务名称:'))))]) ->column(['field' => 'exec_time', 'title' => '任务计划', 'minWidth' => 220, 'templet' => PageBuilder::js(sprintf(<<<'SCRIPT' function (d) { - d.html = %s + d.command + '