smart-admin-web 10.21.0 → 10.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/icons/ph-subset.json.js +1 -1
- package/dist/components/FormContainer/index.vue.js +67 -67
- package/dist/components/FormContainer/index.vue.js.map +1 -1
- package/dist/components/SidePanelDrawer/index.vue.d.ts +25 -0
- package/dist/components/SidePanelDrawer/index.vue.js +40 -0
- package/dist/components/SidePanelDrawer/index.vue.js.map +1 -0
- package/dist/components/SidePanelDrawer/index3.vue.js +6 -0
- package/dist/components/SidePanelDrawer/index3.vue.js.map +1 -0
- package/dist/composables/authMenuRoute.d.ts +10 -0
- package/dist/composables/authMenuRoute.js +39 -23
- package/dist/composables/authMenuRoute.js.map +1 -1
- package/dist/composables/useModule.d.ts +3 -1
- package/dist/composables/useModule.js +44 -32
- package/dist/composables/useModule.js.map +1 -1
- package/dist/composables/useShellBreakpoint.js +14 -13
- package/dist/composables/useShellBreakpoint.js.map +1 -1
- package/dist/composables/useSidePanel.d.ts +9 -0
- package/dist/composables/useSidePanel.js +12 -0
- package/dist/composables/useSidePanel.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +297 -290
- package/dist/index.js.map +1 -1
- package/dist/layouts/components/SideNav.vue.js +2 -2
- package/dist/layouts/components/SideNav2.vue.js.map +1 -1
- package/dist/layouts/default.vue.js +2 -2
- package/dist/layouts/default2.vue.js.map +1 -1
- package/dist/lib/runtime.js +1 -1
- package/dist/locales/en-US.d.ts +6 -0
- package/dist/locales/en-US.js +9 -2
- package/dist/locales/en-US.js.map +1 -1
- package/dist/locales/zh-CN.d.ts +6 -0
- package/dist/locales/zh-CN.js +9 -2
- package/dist/locales/zh-CN.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/tree.d.ts +15 -0
- package/dist/utils/tree.js +43 -29
- package/dist/utils/tree.js.map +1 -1
- package/dist/utils/treeCard.d.ts +6 -0
- package/dist/utils/treeCard.js +9 -0
- package/dist/utils/treeCard.js.map +1 -0
- package/dist/views/error/404.vue.js +2 -2
- package/dist/views/error/4042.vue.js +81 -24
- package/dist/views/error/4042.vue.js.map +1 -1
- package/dist/views/login/components/LoginDesk.vue.js +2 -2
- package/dist/views/login/components/LoginDesk2.vue.js.map +1 -1
- package/dist/views/login/components/LoginHeroPanel.vue.js +2 -2
- package/dist/views/login/components/LoginHeroPanel2.vue.js.map +1 -1
- package/dist/views/system/job-monitor/index.vue.js +2 -2
- package/dist/views/system/job-monitor/index2.vue.js +46 -46
- package/dist/views/system/job-monitor/index2.vue.js.map +1 -1
- package/dist/views/system/menu/index.vue.js +2 -2
- package/dist/views/system/menu/index2.vue.js +161 -150
- package/dist/views/system/menu/index2.vue.js.map +1 -1
- package/dist/views/system/org/index.vue.js +2 -2
- package/dist/views/system/org/index2.vue.js +182 -176
- package/dist/views/system/org/index2.vue.js.map +1 -1
- package/dist/views/system/user/index.vue.js +1 -1
- package/dist/views/system/user/index2.vue.js +296 -277
- package/dist/views/system/user/index2.vue.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { defineComponent as
|
|
1
|
+
import { defineComponent as J, computed as u, ref as j, onMounted as V, onActivated as W, onDeactivated as G, onUnmounted as U, openBlock as g, createElementBlock as _, normalizeClass as b, createElementVNode as l, normalizeStyle as y, Fragment as Y, renderList as q, createBlock as K, unref as r, withCtx as p, createVNode as c, toDisplayString as T, h as N } from "vue";
|
|
2
2
|
import { useMessage as P, NCard as A, NSpin as Q, NTag as X } from "naive-ui";
|
|
3
3
|
import { SmartTable as C } from "smart-naive-table";
|
|
4
|
-
import { Icon as
|
|
5
|
-
import { useShellBreakpoint as
|
|
6
|
-
import { useI18n as
|
|
7
|
-
import
|
|
8
|
-
import { jobApi as
|
|
9
|
-
import { translateError as
|
|
10
|
-
import { fmtDateTime as
|
|
11
|
-
import { TABLE_MIN_ROW_HEIGHT as
|
|
12
|
-
import
|
|
13
|
-
const
|
|
4
|
+
import { Icon as Z } from "@iconify/vue";
|
|
5
|
+
import { useShellBreakpoint as ee } from "../../../composables/useShellBreakpoint.js";
|
|
6
|
+
import { useI18n as te } from "vue-i18n";
|
|
7
|
+
import oe from "../../../components/Chart/index.vue.js";
|
|
8
|
+
import { jobApi as ae } from "../../../api/index.js";
|
|
9
|
+
import { translateError as ne } from "../../../utils/error.js";
|
|
10
|
+
import { fmtDateTime as re } from "../../../utils/format.js";
|
|
11
|
+
import { TABLE_MIN_ROW_HEIGHT as S, TABLE_TOOLBAR as I } from "../../../utils/tableToolbar.js";
|
|
12
|
+
import L from "../../../components/TableTotal/index.vue.js";
|
|
13
|
+
const ie = { class: "stat" }, le = { class: "stat-val tabular" }, se = { class: "stat-label" }, xe = /* @__PURE__ */ J({
|
|
14
14
|
__name: "index",
|
|
15
|
-
setup(
|
|
16
|
-
const { t } =
|
|
15
|
+
setup(ce) {
|
|
16
|
+
const { t } = te(), B = P(), { bp: E, width: h } = ee(), i = u(() => E.value === "narrow"), R = u(() => h.value < 520 ? 1 : h.value < 1e3 ? 2 : 4), M = { gridTemplateColumns: "minmax(0, 1fr)" }, H = u(() => {
|
|
17
17
|
const e = h.value < 1e3, a = e ? 488 : 240;
|
|
18
18
|
return {
|
|
19
19
|
flex: `1 1 ${a}px`,
|
|
@@ -24,25 +24,25 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
24
24
|
}), s = j(null), f = j(!0);
|
|
25
25
|
async function w(e = !0) {
|
|
26
26
|
try {
|
|
27
|
-
s.value = await
|
|
27
|
+
s.value = await ae.dashboard();
|
|
28
28
|
} catch (a) {
|
|
29
|
-
e ||
|
|
29
|
+
e || B.error(ne(a));
|
|
30
30
|
} finally {
|
|
31
31
|
f.value = !1;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
let
|
|
34
|
+
let m = null;
|
|
35
35
|
function k() {
|
|
36
|
-
|
|
36
|
+
m == null && (m = window.setInterval(() => void w(), 15e3));
|
|
37
37
|
}
|
|
38
38
|
function x() {
|
|
39
|
-
|
|
39
|
+
m != null && (window.clearInterval(m), m = null);
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
V(() => {
|
|
42
42
|
w(!1), k();
|
|
43
|
-
}),
|
|
44
|
-
const v = (e) => e === void 0 ? "—" : e,
|
|
45
|
-
var e, a, o,
|
|
43
|
+
}), W(k), G(x), U(x);
|
|
44
|
+
const v = (e) => e === void 0 ? "—" : e, $ = u(() => {
|
|
45
|
+
var e, a, o, d;
|
|
46
46
|
return [
|
|
47
47
|
{
|
|
48
48
|
key: "todaySuccess",
|
|
@@ -65,11 +65,11 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
65
65
|
{
|
|
66
66
|
key: "totalJobs",
|
|
67
67
|
icon: "ph:clock-countdown",
|
|
68
|
-
value: v((
|
|
68
|
+
value: v((d = s.value) == null ? void 0 : d.totalJobs),
|
|
69
69
|
color: "var(--signal)"
|
|
70
70
|
}
|
|
71
71
|
];
|
|
72
|
-
}),
|
|
72
|
+
}), D = u(() => {
|
|
73
73
|
var a;
|
|
74
74
|
const e = ((a = s.value) == null ? void 0 : a.trend) ?? [];
|
|
75
75
|
return {
|
|
@@ -92,7 +92,7 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
92
92
|
]
|
|
93
93
|
};
|
|
94
94
|
});
|
|
95
|
-
function
|
|
95
|
+
function O(e) {
|
|
96
96
|
const a = Math.max(0, Date.now() - new Date(e).getTime()), o = Math.floor(a / 1e3);
|
|
97
97
|
return o < 10 ? t("job.monitor.justNow") : o < 60 ? t("job.monitor.secondsAgo", { n: o }) : o < 3600 ? t("job.monitor.minutesAgo", { n: Math.floor(o / 60) }) : t("job.monitor.hoursAgo", { n: Math.floor(o / 3600) });
|
|
98
98
|
}
|
|
@@ -109,9 +109,9 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
109
109
|
title: () => t("job.monitor.upcomingTime"),
|
|
110
110
|
key: "nextRunTime",
|
|
111
111
|
width: 170,
|
|
112
|
-
render: (e) => N("span", { class: "tabular" },
|
|
112
|
+
render: (e) => N("span", { class: "tabular" }, re(e.nextRunTime, { empty: "—" }))
|
|
113
113
|
}
|
|
114
|
-
],
|
|
114
|
+
], z = [
|
|
115
115
|
{ type: "index", title: () => t("common.rowNo"), width: 64, align: "center" },
|
|
116
116
|
{
|
|
117
117
|
title: () => t("job.monitor.nodeName"),
|
|
@@ -133,40 +133,40 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
133
133
|
title: () => t("job.monitor.lastHeartbeat"),
|
|
134
134
|
key: "lastHeartbeat",
|
|
135
135
|
width: 110,
|
|
136
|
-
render: (e) =>
|
|
136
|
+
render: (e) => O(e.lastHeartbeat)
|
|
137
137
|
},
|
|
138
138
|
{ title: () => t("job.monitor.workerId"), key: "workerId", width: 90, align: "center" },
|
|
139
139
|
{ title: () => t("job.monitor.pid"), key: "pid", width: 90, align: "center" }
|
|
140
140
|
];
|
|
141
141
|
return (e, a) => {
|
|
142
|
-
var o,
|
|
142
|
+
var o, d;
|
|
143
143
|
return g(), _("div", {
|
|
144
144
|
class: b(["view", { "fill-page fill-page--soft": !i.value }])
|
|
145
145
|
}, [
|
|
146
146
|
l("div", {
|
|
147
147
|
class: "stats",
|
|
148
|
-
style: y({ gridTemplateColumns: `repeat(${
|
|
148
|
+
style: y({ gridTemplateColumns: `repeat(${R.value}, minmax(0, 1fr))` })
|
|
149
149
|
}, [
|
|
150
|
-
(g(!0), _(
|
|
150
|
+
(g(!0), _(Y, null, q($.value, (n) => (g(), K(r(A), {
|
|
151
151
|
key: n.key,
|
|
152
152
|
bordered: !0,
|
|
153
153
|
class: "a-card",
|
|
154
154
|
"content-style": "padding: 14px 16px"
|
|
155
155
|
}, {
|
|
156
156
|
default: p(() => [
|
|
157
|
-
l("div",
|
|
157
|
+
l("div", ie, [
|
|
158
158
|
l("div", {
|
|
159
159
|
class: "stat-ico",
|
|
160
160
|
style: y({ color: n.color })
|
|
161
161
|
}, [
|
|
162
|
-
c(r(
|
|
162
|
+
c(r(Z), {
|
|
163
163
|
icon: n.icon,
|
|
164
164
|
width: 28
|
|
165
165
|
}, null, 8, ["icon"])
|
|
166
166
|
], 4),
|
|
167
167
|
l("div", null, [
|
|
168
|
-
l("div",
|
|
169
|
-
l("div",
|
|
168
|
+
l("div", le, T(n.value), 1),
|
|
169
|
+
l("div", se, T(r(t)(`job.monitor.${n.key}`)), 1)
|
|
170
170
|
])
|
|
171
171
|
])
|
|
172
172
|
]),
|
|
@@ -181,7 +181,7 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
181
181
|
default: p(() => [
|
|
182
182
|
c(r(Q), { show: f.value }, {
|
|
183
183
|
default: p(() => [
|
|
184
|
-
c(
|
|
184
|
+
c(oe, { option: D.value }, null, 8, ["option"])
|
|
185
185
|
]),
|
|
186
186
|
_: 1
|
|
187
187
|
}, 8, ["show"])
|
|
@@ -190,7 +190,7 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
190
190
|
}, 8, ["title"]),
|
|
191
191
|
l("div", {
|
|
192
192
|
class: b(["job-tables", { "fill-main": !i.value }]),
|
|
193
|
-
style: y(i.value ?
|
|
193
|
+
style: y(i.value ? M : H.value)
|
|
194
194
|
}, [
|
|
195
195
|
l("div", {
|
|
196
196
|
class: b(["job-table", { "fill-main": !i.value }])
|
|
@@ -201,14 +201,14 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
201
201
|
"row-key": (n) => `${n.jobId}-${n.nextRunTime}`,
|
|
202
202
|
loading: f.value,
|
|
203
203
|
search: { container: "table" },
|
|
204
|
-
toolbar: r(
|
|
204
|
+
toolbar: r(I),
|
|
205
205
|
"fill-height": !i.value,
|
|
206
|
-
"min-row-height": r(
|
|
206
|
+
"min-row-height": r(S),
|
|
207
207
|
"card-on-narrow": i.value,
|
|
208
208
|
"storage-key": "sys-job-monitor-upcoming"
|
|
209
209
|
}, {
|
|
210
210
|
"pagination-prefix": p(({ itemCount: n }) => [
|
|
211
|
-
c(
|
|
211
|
+
c(L, { count: n }, null, 8, ["count"])
|
|
212
212
|
]),
|
|
213
213
|
_: 1
|
|
214
214
|
}, 8, ["data", "row-key", "loading", "toolbar", "fill-height", "min-row-height", "card-on-narrow"])
|
|
@@ -217,19 +217,19 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
217
217
|
class: b(["job-table", { "fill-main": !i.value }])
|
|
218
218
|
}, [
|
|
219
219
|
c(r(C), {
|
|
220
|
-
columns:
|
|
221
|
-
data: ((
|
|
220
|
+
columns: z,
|
|
221
|
+
data: ((d = s.value) == null ? void 0 : d.nodes) ?? [],
|
|
222
222
|
"row-key": "nodeName",
|
|
223
223
|
loading: f.value,
|
|
224
224
|
search: { container: "table" },
|
|
225
|
-
toolbar: r(
|
|
225
|
+
toolbar: r(I),
|
|
226
226
|
"fill-height": !i.value,
|
|
227
|
-
"min-row-height": r(
|
|
227
|
+
"min-row-height": r(S),
|
|
228
228
|
"card-on-narrow": i.value,
|
|
229
229
|
"storage-key": "sys-job-monitor-nodes"
|
|
230
230
|
}, {
|
|
231
231
|
"pagination-prefix": p(({ itemCount: n }) => [
|
|
232
|
-
c(
|
|
232
|
+
c(L, { count: n }, null, 8, ["count"])
|
|
233
233
|
]),
|
|
234
234
|
_: 1
|
|
235
235
|
}, 8, ["data", "loading", "toolbar", "fill-height", "min-row-height", "card-on-narrow"])
|
|
@@ -240,6 +240,6 @@ const re = { class: "stat" }, ie = { class: "stat-val tabular" }, le = { class:
|
|
|
240
240
|
}
|
|
241
241
|
});
|
|
242
242
|
export {
|
|
243
|
-
|
|
243
|
+
xe as default
|
|
244
244
|
};
|
|
245
245
|
//# sourceMappingURL=index2.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/job-monitor/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 任务监控 = 4 张 stat 卡 + 近 14 日成败趋势 + 即将执行 + 集群节点,整页吃一个 dashboard 端点。\n// 15 秒轮询:页面被 keep-alive,切走的标签没必要继续打点 → onDeactivated 也要停,回来再启;\n// onUnmounted 兜底清定时器,防组件销毁后计时器泄漏还在发请求。\nimport { computed, h, onActivated, onDeactivated, onMounted, onUnmounted, ref } from 'vue'\nimport { NCard, NSpin, NTag, useMessage } from 'naive-ui'\nimport { SmartTable, type SmartTableColumn } from 'smart-naive-table'\nimport { Icon } from '@iconify/vue'\nimport { useShellBreakpoint } from '#/composables/useShellBreakpoint'\nimport { useI18n } from 'vue-i18n'\nimport BaseChart from '#/components/Chart/index.vue'\nimport type { EChartsOption } from 'echarts'\nimport { jobApi } from '#/api'\nimport { translateError } from '#/utils/error'\nimport { fmtDateTime } from '#/utils/format'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport type { JobDashboard, JobNodeItem, JobUpcomingItem } from '#/types/api'\n\nconst { t } = useI18n()\nconst message = useMessage()\n\n// 栅格按内容区宽度分档(不是视口)\nconst { bp, width: pw } = useShellBreakpoint()\nconst narrow = computed(() => bp.value === 'narrow')\nconst statCols = computed(() => (pw.value < 520 ? 1 : pw.value < 1000 ? 2 : 4))\nconst tablesStyle = computed(() => {\n const stacked = pw.value < 1000\n const basis = stacked ? 488 : 240\n return {\n flex: `1 1 ${basis}px`,\n minHeight: `${basis}px`,\n gridTemplateColumns: stacked ? 'minmax(0, 1fr)' : 'repeat(2, minmax(0, 1fr))',\n gridTemplateRows: stacked ? 'repeat(2, minmax(0, 1fr))' : 'minmax(0, 1fr)',\n }\n})\n\nconst data = ref<JobDashboard | null>(null)\nconst loading = ref(true)\n\nasync function load(silent = true) {\n try {\n data.value = await jobApi.dashboard()\n } catch (e) {\n // 首次失败要让用户知道;轮询失败静默(网络抖一下不必每 15 秒糊一脸红)\n if (!silent) message.error(translateError(e))\n } finally {\n loading.value = false\n }\n}\n\nlet timer: number | null = null\nfunction start() {\n if (timer != null) return\n timer = window.setInterval(() => void load(), 15_000)\n}\nfunction stop() {\n if (timer != null) {\n window.clearInterval(timer)\n timer = null\n }\n}\nonMounted(() => {\n void load(false)\n start()\n})\nonActivated(start)\nonDeactivated(stop)\nonUnmounted(stop)\n\n/** 计数未到位时显示 —,而不是先闪个 0。 */\nconst num = (v: number | undefined) => (v === undefined ? '—' : v)\nconst stats = computed(() => [\n {\n key: 'todaySuccess',\n icon: 'ph:check-circle',\n value: num(data.value?.todaySuccess),\n color: 'var(--ok)',\n },\n {\n key: 'todayFailed',\n icon: 'ph:x-circle',\n value: num(data.value?.todayFailed),\n color: 'var(--err)',\n },\n {\n key: 'running',\n icon: 'ph:circle-notch',\n value: num(data.value?.running),\n color: 'var(--color-info)',\n },\n {\n key: 'totalJobs',\n icon: 'ph:clock-countdown',\n value: num(data.value?.totalJobs),\n color: 'var(--signal)',\n },\n])\n\n// 柱线组合:成功是当日总量,用柱;失败通常小一个量级,压在柱上会看不见,用线单独描出来。\nconst trendOption = computed<EChartsOption>(() => {\n const trend = data.value?.trend ?? []\n return {\n tooltip: { trigger: 'axis' },\n // 图例位置写死在顶部:留给默认值时它会落到绘图区底部、压在 x 轴日期标签上。\n // grid.top 的 32 就是给它留的位置。\n legend: { top: 0 },\n grid: { left: 8, right: 16, bottom: 8, top: 32, containLabel: true },\n xAxis: { type: 'category', data: trend.map(p => p.date.slice(5)) }, // MM-dd 足够,14 天跨年概率忽略\n yAxis: { type: 'value', minInterval: 1 },\n series: [\n { name: t('job.monitor.trendSuccess'), type: 'bar', data: trend.map(p => p.success) },\n {\n name: t('job.monitor.trendFailed'),\n type: 'line',\n smooth: true,\n data: trend.map(p => p.failed),\n },\n ],\n }\n})\n\n/** 最后心跳的相对时间(轮询 15 秒一刷,精确到秒/分/时够用)。 */\nfunction relative(iso: string): string {\n const diff = Math.max(0, Date.now() - new Date(iso).getTime())\n const sec = Math.floor(diff / 1000)\n if (sec < 10) return t('job.monitor.justNow')\n if (sec < 60) return t('job.monitor.secondsAgo', { n: sec })\n if (sec < 3600) return t('job.monitor.minutesAgo', { n: Math.floor(sec / 60) })\n return t('job.monitor.hoursAgo', { n: Math.floor(sec / 3600) })\n}\n\nconst upcomingColumns: SmartTableColumn<JobUpcomingItem>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n {\n title: () => t('job.monitor.upcomingJob'),\n key: 'name',\n ellipsis: { tooltip: true },\n search: {}, // 静态数据:条件由 SmartTable 前端求值\n },\n {\n title: () => t('job.monitor.upcomingTime'),\n key: 'nextRunTime',\n width: 170,\n render: r => h('span', { class: 'tabular' }, fmtDateTime(r.nextRunTime, { empty: '—' })),\n },\n]\n\nconst nodeColumns: SmartTableColumn<JobNodeItem>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n {\n title: () => t('job.monitor.nodeName'),\n key: 'nodeName',\n ellipsis: { tooltip: true },\n search: {},\n },\n {\n title: () => t('job.monitor.role'),\n key: 'isLeader',\n width: 90,\n render: r =>\n h(NTag, { size: 'small', bordered: false, type: r.isLeader ? 'primary' : 'default' }, () =>\n t(r.isLeader ? 'job.monitor.leader' : 'job.monitor.standby'),\n ),\n },\n {\n title: () => t('job.monitor.lastHeartbeat'),\n key: 'lastHeartbeat',\n width: 110,\n render: r => relative(r.lastHeartbeat),\n },\n { title: () => t('job.monitor.workerId'), key: 'workerId', width: 90, align: 'center' },\n { title: () => t('job.monitor.pid'), key: 'pid', width: 90, align: 'center' },\n]\n</script>\n\n<template>\n <!-- 窄档(内容区 < 600)整页自然滚动,不锁一屏;表格换成卡片列表 -->\n <div class=\"view\" :class=\"{ 'fill-page fill-page--soft': !narrow }\">\n <!-- 统计卡按内容区宽度分档:< 520 一列,< 1000 两列,否则四列 -->\n <div class=\"stats\" :style=\"{ gridTemplateColumns: `repeat(${statCols}, minmax(0, 1fr))` }\">\n <n-card\n v-for=\"s in stats\"\n :key=\"s.key\"\n :bordered=\"true\"\n class=\"a-card\"\n content-style=\"padding: 14px 16px\"\n >\n <div class=\"stat\">\n <div class=\"stat-ico\" :style=\"{ color: s.color }\">\n <Icon :icon=\"s.icon\" :width=\"28\" />\n </div>\n <div>\n <div class=\"stat-val tabular\">{{ s.value }}</div>\n <div class=\"stat-label\">{{ t(`job.monitor.${s.key}`) }}</div>\n </div>\n </div>\n </n-card>\n </div>\n\n <n-card :title=\"t('job.monitor.trendTitle')\" :bordered=\"true\" class=\"a-card\">\n <n-spin :show=\"loading\">\n <BaseChart :option=\"trendOption\" />\n </n-spin>\n </n-card>\n\n <!-- 统计条与趋势图按内容定高(.fill-page > * 已是 flex-shrink:0),\n 底部这一栏吃掉剩余高度,两张表各自在卡片里滚。\n 这页是仪表盘不是列表页:统计条 + 320px 趋势图不参与瓜分,1080p 上给两张表还剩 200 来 px,\n 768p 上就只剩一条缝了 —— 所以外壳叠 .fill-page--soft,再给这一栏一个下限(内容区 < 1000 时两张表\n 上下排,下限 488 = 每张 240 + 间距;>= 1000 并排,下限 240)。 -->\n <div\n class=\"job-tables\"\n :class=\"{ 'fill-main': !narrow }\"\n :style=\"narrow ? undefined : tablesStyle\"\n >\n <!-- 两张表都是 SmartTable 静态数据模式;不放表名(设计:表格工具栏没有标题),列头已能分辨。\n 窄档(内容区 < 600)整页自然滚动,卡片列表由 card-on-narrow 内置。\n card-on-narrow 跟页面窄档走而不是让库按表格自身宽度判:宽屏下两张表并排各约半宽,会被误判成窄 -->\n <div class=\"job-table\" :class=\"{ 'fill-main': !narrow }\">\n <SmartTable\n :columns=\"upcomingColumns\"\n :data=\"data?.upcoming ?? []\"\n :row-key=\"(r: JobUpcomingItem) => `${r.jobId}-${r.nextRunTime}`\"\n :loading=\"loading\"\n :search=\"{ container: 'table' }\"\n :toolbar=\"TABLE_TOOLBAR\"\n :fill-height=\"!narrow\"\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n :card-on-narrow=\"narrow\"\n storage-key=\"sys-job-monitor-upcoming\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n </SmartTable>\n </div>\n <div class=\"job-table\" :class=\"{ 'fill-main': !narrow }\">\n <SmartTable\n :columns=\"nodeColumns\"\n :data=\"data?.nodes ?? []\"\n row-key=\"nodeName\"\n :loading=\"loading\"\n :search=\"{ container: 'table' }\"\n :toolbar=\"TABLE_TOOLBAR\"\n :fill-height=\"!narrow\"\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n :card-on-narrow=\"narrow\"\n storage-key=\"sys-job-monitor-nodes\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n </SmartTable>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* display / flex-direction / 整屏高度链都在 styles/layout.css 的 .fill-page,这里只留卡片间距。 */\n.view {\n gap: var(--gap-card);\n}\n\n/*\n * .fill-page--soft 把「恰好一屏」放宽成「至少一屏」,这里再给两张表所在的那一栏一个下限:\n * 卡片头尾约 62px + small 表头 34px + 4 行 x 34px ≈ 240px,少于这个就不叫表了。\n * 高屏上剩余高度本来就大于下限,页面仍然恰好一屏;矮屏上顶到下限后由 .page 正常出滚动条。\n * 容器和栅格项都要给:容器是 flex 子项(.fill-main 带 min-height:0,不设下限会被压过内容),\n * 栅格项则决定单列(l 断点以下两张表上下排)时每张表各自的下限。\n */\n.stats {\n display: grid;\n gap: var(--gap-card);\n flex-shrink: 0;\n}\n.job-tables {\n display: grid;\n gap: var(--gap-card);\n}\n.stat {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n/* 图标底盘:取语义色 12% 作浅底,同工作台手法,避免图标\"裸浮\" */\n.stat-ico {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n border-radius: var(--radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, currentColor 12%, transparent);\n}\n.stat-val {\n font-size: 28px;\n font-weight: 600;\n letter-spacing: -0.04em;\n color: var(--text-1);\n line-height: 34px;\n}\n.stat-label {\n font-size: 14px;\n color: var(--text-2);\n}\n</style>\n"],"names":["useI18n","message","useMessage","bp","pw","useShellBreakpoint","narrow","computed","statCols","tablesStyle","stacked","basis","data","ref","loading","load","silent","jobApi","e","translateError","timer","start","stop","onMounted","onActivated","onDeactivated","onUnmounted","num","v","stats","_a","_b","_c","_d","trendOption","trend","p","relative","iso","diff","sec","upcomingColumns","r","h","fmtDateTime","nodeColumns","NTag","_createElementBlock","_normalizeClass","_createElementVNode","_Fragment","_renderList","s","_createBlock","_unref","NCard","_hoisted_1","_normalizeStyle","_createVNode","Icon","_hoisted_2","_toDisplayString","_hoisted_3","NSpin","BaseChart","SmartTable","TABLE_TOOLBAR","TABLE_MIN_ROW_HEIGHT","_withCtx","itemCount","TableTotal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/job-monitor/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 任务监控 = 4 张 stat 卡 + 近 14 日成败趋势 + 即将执行 + 集群节点,整页吃一个 dashboard 端点。\n// 15 秒轮询:页面被 keep-alive,切走的标签没必要继续打点 → onDeactivated 也要停,回来再启;\n// onUnmounted 兜底清定时器,防组件销毁后计时器泄漏还在发请求。\nimport { computed, h, onActivated, onDeactivated, onMounted, onUnmounted, ref } from 'vue'\nimport { NCard, NSpin, NTag, useMessage } from 'naive-ui'\nimport { SmartTable, type SmartTableColumn } from 'smart-naive-table'\nimport { Icon } from '@iconify/vue'\nimport { useShellBreakpoint } from '#/composables/useShellBreakpoint'\nimport { useI18n } from 'vue-i18n'\nimport BaseChart from '#/components/Chart/index.vue'\nimport type { EChartsOption } from 'echarts'\nimport { jobApi } from '#/api'\nimport { translateError } from '#/utils/error'\nimport { fmtDateTime } from '#/utils/format'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport type { JobDashboard, JobNodeItem, JobUpcomingItem } from '#/types/api'\n\nconst { t } = useI18n()\nconst message = useMessage()\n\n// 栅格按内容区宽度分档(不是视口)\nconst { bp, width: pw } = useShellBreakpoint()\nconst narrow = computed(() => bp.value === 'narrow')\nconst statCols = computed(() => (pw.value < 520 ? 1 : pw.value < 1000 ? 2 : 4))\n// 窄档必须显式给单列:网格默认的 auto 列会被表格的最小内容宽撑到 600,而库判卡片的条件是表格根宽 < 600,\n// 于是表格永远不换成卡片、页面横向溢出,还自己维持住这个状态。\nconst NARROW_TABLES_STYLE = { gridTemplateColumns: 'minmax(0, 1fr)' }\nconst tablesStyle = computed(() => {\n const stacked = pw.value < 1000\n const basis = stacked ? 488 : 240\n return {\n flex: `1 1 ${basis}px`,\n minHeight: `${basis}px`,\n gridTemplateColumns: stacked ? 'minmax(0, 1fr)' : 'repeat(2, minmax(0, 1fr))',\n gridTemplateRows: stacked ? 'repeat(2, minmax(0, 1fr))' : 'minmax(0, 1fr)',\n }\n})\n\nconst data = ref<JobDashboard | null>(null)\nconst loading = ref(true)\n\nasync function load(silent = true) {\n try {\n data.value = await jobApi.dashboard()\n } catch (e) {\n // 首次失败要让用户知道;轮询失败静默(网络抖一下不必每 15 秒糊一脸红)\n if (!silent) message.error(translateError(e))\n } finally {\n loading.value = false\n }\n}\n\nlet timer: number | null = null\nfunction start() {\n if (timer != null) return\n timer = window.setInterval(() => void load(), 15_000)\n}\nfunction stop() {\n if (timer != null) {\n window.clearInterval(timer)\n timer = null\n }\n}\nonMounted(() => {\n void load(false)\n start()\n})\nonActivated(start)\nonDeactivated(stop)\nonUnmounted(stop)\n\n/** 计数未到位时显示 —,而不是先闪个 0。 */\nconst num = (v: number | undefined) => (v === undefined ? '—' : v)\nconst stats = computed(() => [\n {\n key: 'todaySuccess',\n icon: 'ph:check-circle',\n value: num(data.value?.todaySuccess),\n color: 'var(--ok)',\n },\n {\n key: 'todayFailed',\n icon: 'ph:x-circle',\n value: num(data.value?.todayFailed),\n color: 'var(--err)',\n },\n {\n key: 'running',\n icon: 'ph:circle-notch',\n value: num(data.value?.running),\n color: 'var(--color-info)',\n },\n {\n key: 'totalJobs',\n icon: 'ph:clock-countdown',\n value: num(data.value?.totalJobs),\n color: 'var(--signal)',\n },\n])\n\n// 柱线组合:成功是当日总量,用柱;失败通常小一个量级,压在柱上会看不见,用线单独描出来。\nconst trendOption = computed<EChartsOption>(() => {\n const trend = data.value?.trend ?? []\n return {\n tooltip: { trigger: 'axis' },\n // 图例位置写死在顶部:留给默认值时它会落到绘图区底部、压在 x 轴日期标签上。\n // grid.top 的 32 就是给它留的位置。\n legend: { top: 0 },\n grid: { left: 8, right: 16, bottom: 8, top: 32, containLabel: true },\n xAxis: { type: 'category', data: trend.map(p => p.date.slice(5)) }, // MM-dd 足够,14 天跨年概率忽略\n yAxis: { type: 'value', minInterval: 1 },\n series: [\n { name: t('job.monitor.trendSuccess'), type: 'bar', data: trend.map(p => p.success) },\n {\n name: t('job.monitor.trendFailed'),\n type: 'line',\n smooth: true,\n data: trend.map(p => p.failed),\n },\n ],\n }\n})\n\n/** 最后心跳的相对时间(轮询 15 秒一刷,精确到秒/分/时够用)。 */\nfunction relative(iso: string): string {\n const diff = Math.max(0, Date.now() - new Date(iso).getTime())\n const sec = Math.floor(diff / 1000)\n if (sec < 10) return t('job.monitor.justNow')\n if (sec < 60) return t('job.monitor.secondsAgo', { n: sec })\n if (sec < 3600) return t('job.monitor.minutesAgo', { n: Math.floor(sec / 60) })\n return t('job.monitor.hoursAgo', { n: Math.floor(sec / 3600) })\n}\n\nconst upcomingColumns: SmartTableColumn<JobUpcomingItem>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n {\n title: () => t('job.monitor.upcomingJob'),\n key: 'name',\n ellipsis: { tooltip: true },\n search: {}, // 静态数据:条件由 SmartTable 前端求值\n },\n {\n title: () => t('job.monitor.upcomingTime'),\n key: 'nextRunTime',\n width: 170,\n render: r => h('span', { class: 'tabular' }, fmtDateTime(r.nextRunTime, { empty: '—' })),\n },\n]\n\nconst nodeColumns: SmartTableColumn<JobNodeItem>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n {\n title: () => t('job.monitor.nodeName'),\n key: 'nodeName',\n ellipsis: { tooltip: true },\n search: {},\n },\n {\n title: () => t('job.monitor.role'),\n key: 'isLeader',\n width: 90,\n render: r =>\n h(NTag, { size: 'small', bordered: false, type: r.isLeader ? 'primary' : 'default' }, () =>\n t(r.isLeader ? 'job.monitor.leader' : 'job.monitor.standby'),\n ),\n },\n {\n title: () => t('job.monitor.lastHeartbeat'),\n key: 'lastHeartbeat',\n width: 110,\n render: r => relative(r.lastHeartbeat),\n },\n { title: () => t('job.monitor.workerId'), key: 'workerId', width: 90, align: 'center' },\n { title: () => t('job.monitor.pid'), key: 'pid', width: 90, align: 'center' },\n]\n</script>\n\n<template>\n <!-- 窄档(内容区 < 600)整页自然滚动,不锁一屏;表格换成卡片列表 -->\n <div class=\"view\" :class=\"{ 'fill-page fill-page--soft': !narrow }\">\n <!-- 统计卡按内容区宽度分档:< 520 一列,< 1000 两列,否则四列 -->\n <div class=\"stats\" :style=\"{ gridTemplateColumns: `repeat(${statCols}, minmax(0, 1fr))` }\">\n <n-card\n v-for=\"s in stats\"\n :key=\"s.key\"\n :bordered=\"true\"\n class=\"a-card\"\n content-style=\"padding: 14px 16px\"\n >\n <div class=\"stat\">\n <div class=\"stat-ico\" :style=\"{ color: s.color }\">\n <Icon :icon=\"s.icon\" :width=\"28\" />\n </div>\n <div>\n <div class=\"stat-val tabular\">{{ s.value }}</div>\n <div class=\"stat-label\">{{ t(`job.monitor.${s.key}`) }}</div>\n </div>\n </div>\n </n-card>\n </div>\n\n <n-card :title=\"t('job.monitor.trendTitle')\" :bordered=\"true\" class=\"a-card\">\n <n-spin :show=\"loading\">\n <BaseChart :option=\"trendOption\" />\n </n-spin>\n </n-card>\n\n <!-- 统计条与趋势图按内容定高(.fill-page > * 已是 flex-shrink:0),\n 底部这一栏吃掉剩余高度,两张表各自在卡片里滚。\n 这页是仪表盘不是列表页:统计条 + 320px 趋势图不参与瓜分,1080p 上给两张表还剩 200 来 px,\n 768p 上就只剩一条缝了 —— 所以外壳叠 .fill-page--soft,再给这一栏一个下限(内容区 < 1000 时两张表\n 上下排,下限 488 = 每张 240 + 间距;>= 1000 并排,下限 240)。 -->\n <div\n class=\"job-tables\"\n :class=\"{ 'fill-main': !narrow }\"\n :style=\"narrow ? NARROW_TABLES_STYLE : tablesStyle\"\n >\n <!-- 两张表都是 SmartTable 静态数据模式;不放表名(设计:表格工具栏没有标题),列头已能分辨。\n 窄档(内容区 < 600)整页自然滚动,卡片列表由 card-on-narrow 内置。\n card-on-narrow 跟页面窄档走而不是让库按表格自身宽度判:宽屏下两张表并排各约半宽,会被误判成窄 -->\n <div class=\"job-table\" :class=\"{ 'fill-main': !narrow }\">\n <SmartTable\n :columns=\"upcomingColumns\"\n :data=\"data?.upcoming ?? []\"\n :row-key=\"(r: JobUpcomingItem) => `${r.jobId}-${r.nextRunTime}`\"\n :loading=\"loading\"\n :search=\"{ container: 'table' }\"\n :toolbar=\"TABLE_TOOLBAR\"\n :fill-height=\"!narrow\"\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n :card-on-narrow=\"narrow\"\n storage-key=\"sys-job-monitor-upcoming\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n </SmartTable>\n </div>\n <div class=\"job-table\" :class=\"{ 'fill-main': !narrow }\">\n <SmartTable\n :columns=\"nodeColumns\"\n :data=\"data?.nodes ?? []\"\n row-key=\"nodeName\"\n :loading=\"loading\"\n :search=\"{ container: 'table' }\"\n :toolbar=\"TABLE_TOOLBAR\"\n :fill-height=\"!narrow\"\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n :card-on-narrow=\"narrow\"\n storage-key=\"sys-job-monitor-nodes\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n </SmartTable>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* display / flex-direction / 整屏高度链都在 styles/layout.css 的 .fill-page,这里只留卡片间距。 */\n.view {\n gap: var(--gap-card);\n}\n\n/*\n * .fill-page--soft 把「恰好一屏」放宽成「至少一屏」,这里再给两张表所在的那一栏一个下限:\n * 卡片头尾约 62px + small 表头 34px + 4 行 x 34px ≈ 240px,少于这个就不叫表了。\n * 高屏上剩余高度本来就大于下限,页面仍然恰好一屏;矮屏上顶到下限后由 .page 正常出滚动条。\n * 容器和栅格项都要给:容器是 flex 子项(.fill-main 带 min-height:0,不设下限会被压过内容),\n * 栅格项则决定单列(l 断点以下两张表上下排)时每张表各自的下限。\n */\n.stats {\n display: grid;\n gap: var(--gap-card);\n flex-shrink: 0;\n}\n.job-tables {\n display: grid;\n gap: var(--gap-card);\n}\n.stat {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n/* 图标底盘:取语义色 12% 作浅底,同工作台手法,避免图标\"裸浮\" */\n.stat-ico {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n border-radius: var(--radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, currentColor 12%, transparent);\n}\n.stat-val {\n font-size: 28px;\n font-weight: 600;\n letter-spacing: -0.04em;\n color: var(--text-1);\n line-height: 34px;\n}\n.stat-label {\n font-size: 14px;\n color: var(--text-2);\n}\n</style>\n"],"names":["useI18n","message","useMessage","bp","pw","useShellBreakpoint","narrow","computed","statCols","NARROW_TABLES_STYLE","tablesStyle","stacked","basis","data","ref","loading","load","silent","jobApi","e","translateError","timer","start","stop","onMounted","onActivated","onDeactivated","onUnmounted","num","v","stats","_a","_b","_c","_d","trendOption","trend","p","relative","iso","diff","sec","upcomingColumns","r","h","fmtDateTime","nodeColumns","NTag","_createElementBlock","_normalizeClass","_createElementVNode","_Fragment","_renderList","s","_createBlock","_unref","NCard","_hoisted_1","_normalizeStyle","_createVNode","Icon","_hoisted_2","_toDisplayString","_hoisted_3","NSpin","BaseChart","SmartTable","TABLE_TOOLBAR","TABLE_MIN_ROW_HEIGHT","_withCtx","itemCount","TableTotal"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import o from "./index2.vue.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import t from "../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
const
|
|
4
|
+
const p = /* @__PURE__ */ t(o, [["__scopeId", "data-v-61aa809c"]]);
|
|
5
5
|
export {
|
|
6
|
-
|
|
6
|
+
p as default
|
|
7
7
|
};
|
|
8
8
|
//# sourceMappingURL=index.vue.js.map
|