You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

273 lines
30 KiB

import { defineComponent, ref, reactive, computed, useSSRContext } from 'vue';
import { ssrRenderAttrs, ssrRenderStyle, ssrRenderList, ssrRenderClass, ssrInterpolate, ssrIncludeBooleanAttr, ssrRenderAttr, ssrLooseContain, ssrLooseEqual } from 'vue/server-renderer';
import { u as useApi } from './useApi-B6h53Mkt.mjs';
import { u as useToast } from './useToast-C76a6bSX.mjs';
import { u as useAuthStore } from './auth-QFkCoU1C.mjs';
import { _ as _export_sfc, b as useRouter } from './server.mjs';
import './useLoading-D6mc40Wj.mjs';
import './state-DQnwRar-.mjs';
import 'pinia';
import '../nitro/nitro.mjs';
import 'node:http';
import 'node:https';
import 'node:events';
import 'node:buffer';
import 'node:fs';
import 'node:path';
import 'node:crypto';
import 'node:url';
import '../routes/renderer.mjs';
import 'vue-bundle-renderer/runtime';
import 'unhead/server';
import 'devalue';
import 'unhead/utils';
import 'perfect-debounce';
const ORPHAN_KEY = "__orphan__";
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "apps",
__ssrInlineRender: true,
setup(__props) {
useApi();
useToast();
useAuthStore();
useRouter();
const view = ref("list");
const products = ref([]);
const apps2 = ref([]);
const envs = ref([]);
const loading = ref(false);
const envSavingId = ref(0);
const expanded = reactive({});
const regionOptions = ["中国", "美国", "东亚", "东南亚", "南亚", "中东", "欧洲", "俄罗斯", "非洲", "南美", "北美", "大洋洲", "巴西", "印度"];
const groups = computed(() => {
const byName = /* @__PURE__ */ new Map();
for (const d of apps2.value) {
const name = d.app_name || "";
if (!byName.has(name)) byName.set(name, []);
byName.get(name).push(d);
}
const known = new Set(products.value.map((p) => p.name));
const res = products.value.map((p) => ({ key: p.name, product: p, deployments: byName.get(p.name) || [] }));
const orphan = [];
for (const [name, ds] of byName) {
if (name === "" || !known.has(name)) orphan.push(...ds);
}
if (orphan.length) res.push({ key: ORPHAN_KEY, product: null, deployments: orphan });
return res;
});
function isExpanded(key) {
return expanded[key] !== false;
}
function dbName(dsn) {
const m = (dsn || "").match(/\/([^/?]+)\?/);
return m ? m[1] : "-";
}
const pIsEditing = ref(false);
const pForm = reactive({ id: 0, name: "", image_name: "", remark: "", enabled: true });
const dIsEditing = ref(false);
const dMode = ref("existing");
const dForm = reactive({ id: 0, app_name: "", name: "", region: "", env_id: 0, base_url: "", service_dsn: "", deploy_dir: "", image_name: "", image_tag: "", remark: "", enabled: true });
const availableRegions = computed(() => {
const used = new Set(
apps2.value.filter((d) => d.app_name === dForm.app_name && d.id !== dForm.id).map((d) => d.region).filter(Boolean)
);
return regionOptions.filter((r) => !used.has(r));
});
const testPassed = ref(false);
const testing = ref(false);
const testResult = reactive({ show: false, apiOk: false, apiMsg: "", dbOk: false, dbMsg: "" });
ref(null);
const az = reactive({
appId: 0,
appLabel: "",
start: "",
end: "",
resultShow: false,
resultClass: "",
mode: "",
steps: [],
curIndex: 0,
curTotal: 0,
curName: "",
pct: 0,
errMsg: "",
report: null,
running: false,
btnText: "开始分析"
});
ref(null);
ref(null);
const up = reactive({
id: 0,
label: "",
envName: "",
deployDir: "",
tag: "",
log: "",
show: false,
running: false,
ok: false,
canRun: false,
btnText: "开始升级"
});
return (_ctx, _push, _parent, _attrs) => {
_push(`<div${ssrRenderAttrs(_attrs)} data-v-f8779360><div style="${ssrRenderStyle(view.value === "list" ? null : { display: "none" })}" data-v-f8779360><div class="flex items-center justify-between mb-5" data-v-f8779360><div data-v-f8779360><h2 class="text-lg font-semibold text-slate-800" data-v-f8779360>应用管理</h2><p class="text-sm text-slate-400 mt-1" data-v-f8779360><span class="chip-app" data-v-f8779360>应用</span> 是一个产品(如 Voitrans);其下挂多条 <span class="chip-dep" data-v-f8779360>部署</span>(各区域一份)。 卡片 = 应用;卡片内表格 = 该应用的区域部署。 </p></div><button class="btn btn-primary btn-sm text-white" data-v-f8779360>+ 添加应用</button></div>`);
if (loading.value) {
_push(`<div class="bg-white rounded-xl border border-slate-100 py-14 text-center" data-v-f8779360><span class="loading loading-spinner loading-sm" data-v-f8779360></span></div>`);
} else if (!groups.value.length) {
_push(`<div class="bg-white rounded-xl border border-slate-100 py-14 text-center text-slate-400" data-v-f8779360>暂无应用,先「添加应用」</div>`);
} else {
_push(`<div class="space-y-4" data-v-f8779360><!--[-->`);
ssrRenderList(groups.value, (g) => {
_push(`<div class="${ssrRenderClass([{ orphan: !g.product }, "app-card"])}" data-v-f8779360><div class="app-head" data-v-f8779360><button class="chev" data-v-f8779360>${ssrInterpolate(isExpanded(g.key) ? "▾" : "▸")}</button><div class="${ssrRenderClass([{ "orphan-logo": !g.product }, "app-logo"])}" data-v-f8779360>${ssrInterpolate(g.product ? (g.product.name || "?").charAt(0).toUpperCase() : "?")}</div><div class="min-w-0 flex-1" data-v-f8779360><div class="flex items-center gap-2 flex-wrap" data-v-f8779360><span class="chip-app" data-v-f8779360>应用</span><span class="app-name" data-v-f8779360>${ssrInterpolate(g.product ? g.product.name : "未分组部署")}</span>`);
if (g.product) {
_push(`<span class="${ssrRenderClass([g.product.enabled ? "badge-success" : "badge-ghost", "badge badge-xs"])}" data-v-f8779360>${ssrInterpolate(g.product.enabled ? "启用" : "停用")}</span>`);
} else {
_push(`<!---->`);
}
if (g.product && g.product.image_name) {
_push(`<span class="chip-mono" data-v-f8779360>🐳 ${ssrInterpolate(g.product.image_name)}</span>`);
} else {
_push(`<!---->`);
}
_push(`<span class="chip-count" data-v-f8779360>${ssrInterpolate(g.deployments.length)} 个部署</span></div><p class="text-xs text-slate-400 mt-0.5 truncate" data-v-f8779360>${ssrInterpolate(g.product ? g.product.remark || "—" : "未填所属应用名、或应用已删除的历史部署;编辑部署可归位到某个应用")}</p></div>`);
if (g.product) {
_push(`<div class="flex gap-1 shrink-0" data-v-f8779360><button class="btn btn-primary btn-xs text-white" data-v-f8779360>+ 部署</button><button class="btn btn-ghost btn-xs" data-v-f8779360>编辑应用</button><button class="btn btn-ghost btn-xs text-red-500" data-v-f8779360>删除</button></div>`);
} else {
_push(`<!---->`);
}
_push(`</div><div class="app-body" style="${ssrRenderStyle(isExpanded(g.key) ? null : { display: "none" })}" data-v-f8779360>`);
if (!g.deployments.length) {
_push(`<div class="text-center text-slate-300 py-5 text-xs" data-v-f8779360> 该应用暂无部署`);
if (g.product) {
_push(`<!--[-->,点右上「+ 部署」添加<!--]-->`);
} else {
_push(`<!---->`);
}
_push(`</div>`);
} else {
_push(`<div class="overflow-x-auto" data-v-f8779360><table class="table table-sm text-sm" data-v-f8779360><thead data-v-f8779360><tr class="text-slate-400" data-v-f8779360><th data-v-f8779360>部署</th><th data-v-f8779360>区域</th><th data-v-f8779360>环境</th><th data-v-f8779360>状态</th><th data-v-f8779360>业务库</th><th data-v-f8779360>启用</th><th class="text-right" data-v-f8779360>操作</th></tr></thead><tbody data-v-f8779360><!--[-->`);
ssrRenderList(g.deployments, (a) => {
_push(`<tr class="dep-row hover" data-v-f8779360><td data-v-f8779360><span class="chip-dep" data-v-f8779360>部署</span><span class="font-medium text-slate-700 ml-1" data-v-f8779360>${ssrInterpolate(a.name || "部署#" + a.id)}</span><span class="text-xs text-slate-400 ml-1 font-mono" data-v-f8779360>#${ssrInterpolate(a.id)}</span></td><td data-v-f8779360>${ssrInterpolate(a.region || "—")}</td><td data-v-f8779360><select class="select select-bordered select-xs w-36 text-xs"${ssrIncludeBooleanAttr(envSavingId.value === a.id) ? " disabled" : ""} data-v-f8779360><option${ssrRenderAttr("value", 0)} data-v-f8779360${ssrIncludeBooleanAttr(Array.isArray(a.env_id) ? ssrLooseContain(a.env_id, 0) : ssrLooseEqual(a.env_id, 0)) ? " selected" : ""}>未绑定</option><!--[-->`);
ssrRenderList(envs.value, (e) => {
_push(`<option${ssrRenderAttr("value", e.id)} data-v-f8779360${ssrIncludeBooleanAttr(Array.isArray(a.env_id) ? ssrLooseContain(a.env_id, e.id) : ssrLooseEqual(a.env_id, e.id)) ? " selected" : ""}>${ssrInterpolate(e.name)}</option>`);
});
_push(`<!--]--></select></td><td data-v-f8779360>`);
if (a.status === "pending") {
_push(`<span class="badge badge-warning badge-sm text-amber-900" data-v-f8779360>待部署</span>`);
} else {
_push(`<span class="badge badge-success badge-sm text-white" data-v-f8779360>已接入</span>`);
}
_push(`</td><td class="font-mono text-xs" data-v-f8779360>${ssrInterpolate(dbName(a.service_dsn))}</td><td data-v-f8779360>`);
if (a.enabled) {
_push(`<span class="text-green-600" data-v-f8779360>是</span>`);
} else {
_push(`<span class="text-slate-400" data-v-f8779360>否</span>`);
}
_push(`</td><td class="text-right" data-v-f8779360><div class="flex gap-1 justify-end" data-v-f8779360>`);
if (a.status !== "pending") {
_push(`<!--[--><button class="btn btn-ghost btn-xs text-indigo-600" data-v-f8779360>服务配置</button><button class="btn btn-ghost btn-xs text-slate-500" data-v-f8779360>编辑</button><button class="btn btn-ghost btn-xs text-amber-600" data-v-f8779360>升级</button><button class="btn btn-ghost btn-xs text-emerald-600" data-v-f8779360>分析</button><button class="btn btn-ghost btn-xs text-indigo-500" data-v-f8779360>发事件</button><!--]-->`);
} else {
_push(`<button class="btn btn-ghost btn-xs text-amber-600" data-v-f8779360>编辑</button>`);
}
_push(`<button class="btn btn-ghost btn-xs text-red-500" data-v-f8779360>删除</button></div></td></tr>`);
});
_push(`<!--]--></tbody></table></div>`);
}
_push(`</div></div>`);
});
_push(`<!--]--></div>`);
}
_push(`</div><div style="${ssrRenderStyle(view.value === "productForm" ? null : { display: "none" })}" data-v-f8779360><div class="flex items-center gap-3 mb-5" data-v-f8779360><button class="btn btn-ghost btn-sm" data-v-f8779360>← 返回</button><h2 class="text-lg font-semibold text-slate-800" data-v-f8779360>${ssrInterpolate(pIsEditing.value ? "编辑应用" : "添加应用")}</h2></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-6 max-w-xl" data-v-f8779360><form data-v-f8779360><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>应用名 *</span></label><input${ssrRenderAttr("value", pForm.name)} type="text" class="input input-bordered w-full" required placeholder="如 Voitrans" data-v-f8779360><span class="text-xs text-slate-400 mt-1" data-v-f8779360>账号作用域按应用名绑定,尽量与统计/账号里一致。</span></div><div class="form-control mt-4" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>默认镜像名</span></label><input${ssrRenderAttr("value", pForm.image_name)} type="text" class="input input-bordered w-full" placeholder="voitrans-a11(部署时用,可留空)" data-v-f8779360></div><div class="form-control mt-4" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>备注</span></label><input${ssrRenderAttr("value", pForm.remark)} type="text" class="input input-bordered w-full" data-v-f8779360></div><div class="flex items-center gap-2 mt-4" data-v-f8779360><label class="flex items-center gap-2 cursor-pointer" data-v-f8779360><input${ssrIncludeBooleanAttr(Array.isArray(pForm.enabled) ? ssrLooseContain(pForm.enabled, null) : pForm.enabled) ? " checked" : ""} type="checkbox" class="toggle toggle-primary toggle-sm" data-v-f8779360><span class="text-sm" data-v-f8779360>启用</span></label></div><div class="flex gap-3 mt-6" data-v-f8779360><button type="button" class="btn btn-ghost" data-v-f8779360>取消</button><button type="submit" class="btn btn-primary text-white" data-v-f8779360>保存</button></div></form></div></div><div style="${ssrRenderStyle(view.value === "deployForm" ? null : { display: "none" })}" data-v-f8779360><div class="flex items-center gap-3 mb-5" data-v-f8779360><button class="btn btn-ghost btn-sm" data-v-f8779360>← 返回</button><h2 class="text-lg font-semibold text-slate-800" data-v-f8779360>${ssrInterpolate(dIsEditing.value ? "编辑部署" : "添加部署")}</h2></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-6 max-w-3xl" data-v-f8779360><form data-v-f8779360>`);
if (!dIsEditing.value) {
_push(`<div class="tabs tabs-boxed bg-slate-100 w-fit mb-5" data-v-f8779360><a class="${ssrRenderClass([dMode.value === "existing" ? "tab-active" : "", "tab"])}" data-v-f8779360>添加现有</a><a class="${ssrRenderClass([dMode.value === "deploy" ? "tab-active" : "", "tab"])}" data-v-f8779360>部署到目标环境</a></div>`);
} else {
_push(`<!---->`);
}
_push(`<p class="${ssrRenderClass([dIsEditing.value ? "" : "-mt-3", "text-xs text-slate-400 mb-4"])}" data-v-f8779360>`);
if (dIsEditing.value) {
_push(`<!--[-->编辑该区域部署的配置(镜像 Tag / 部署目录 / 环境节点 等);改好后回列表点「升级」执行远程部署(拉新镜像并重启)。<!--]-->`);
} else if (dMode.value === "existing") {
_push(`<!--[-->把「已经部署好的应用区域」加进来:填地址与业务库 DSN,测试通过后保存。<!--]-->`);
} else {
_push(`<!--[-->选一个「部署目标环境」,先建关联并标记<b data-v-f8779360>待部署</b>;保存后回列表点「升级」执行远程部署。<!--]-->`);
}
_push(`</p><div class="grid grid-cols-2 gap-4" data-v-f8779360><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>所属应用</span></label><input${ssrRenderAttr("value", dForm.app_name)} type="text" class="input input-bordered w-full bg-slate-100" readonly data-v-f8779360></div><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>部署名称 *</span></label><input${ssrRenderAttr("value", dForm.name)} type="text" class="input input-bordered w-full" required placeholder="如 Voitrans(国内)" data-v-f8779360></div></div><div class="grid grid-cols-2 gap-4 mt-4" data-v-f8779360><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>区域</span></label><select class="select select-bordered w-full" data-v-f8779360><option value="" data-v-f8779360${ssrIncludeBooleanAttr(Array.isArray(dForm.region) ? ssrLooseContain(dForm.region, "") : ssrLooseEqual(dForm.region, "")) ? " selected" : ""}>未指定</option><!--[-->`);
ssrRenderList(availableRegions.value, (r) => {
_push(`<option${ssrRenderAttr("value", r)} data-v-f8779360${ssrIncludeBooleanAttr(Array.isArray(dForm.region) ? ssrLooseContain(dForm.region, r) : ssrLooseEqual(dForm.region, r)) ? " selected" : ""}>${ssrInterpolate(r)}</option>`);
});
_push(`<!--]--></select><span class="text-xs text-slate-400 mt-1" data-v-f8779360>已部署的区域不再出现(一个应用每区域一份部署)。</span></div><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>部署环境${ssrInterpolate(dMode.value === "deploy" ? " *" : "")}</span></label><select class="select select-bordered w-full" data-v-f8779360><option${ssrRenderAttr("value", 0)} data-v-f8779360${ssrIncludeBooleanAttr(Array.isArray(dForm.env_id) ? ssrLooseContain(dForm.env_id, 0) : ssrLooseEqual(dForm.env_id, 0)) ? " selected" : ""}>${ssrInterpolate(dMode.value === "deploy" ? "请选择目标环境" : "未关联")}</option><!--[-->`);
ssrRenderList(envs.value, (e) => {
_push(`<option${ssrRenderAttr("value", e.id)} data-v-f8779360${ssrIncludeBooleanAttr(Array.isArray(dForm.env_id) ? ssrLooseContain(dForm.env_id, e.id) : ssrLooseEqual(dForm.env_id, e.id)) ? " selected" : ""}>${ssrInterpolate(e.name)}(${ssrInterpolate(e.code || "-")})</option>`);
});
_push(`<!--]--></select></div></div><div class="grid grid-cols-3 gap-4 mt-4" data-v-f8779360><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>部署目录</span></label><input${ssrRenderAttr("value", dForm.deploy_dir)} type="text" class="input input-bordered w-full font-mono text-xs" placeholder="/home/work/voitrans-a11" data-v-f8779360></div><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>镜像名</span></label><input${ssrRenderAttr("value", dForm.image_name)} type="text" class="input input-bordered w-full" placeholder="voitrans-a11(默认取应用)" data-v-f8779360></div><div class="form-control" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>镜像 Tag</span></label><input${ssrRenderAttr("value", dForm.image_tag)} type="text" class="input input-bordered w-full" placeholder="0.1.1 / latest" data-v-f8779360></div></div><div class="form-control mt-4" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>业务库 DSN${ssrInterpolate(dMode.value === "existing" ? " *" : "")}</span></label><input${ssrRenderAttr("value", dForm.service_dsn)} type="text" class="input input-bordered w-full font-mono text-xs" placeholder="root:pwd@tcp(host:3306)/earphone?charset=utf8mb4&amp;parseTime=True&amp;loc=Local" data-v-f8779360><span class="text-xs text-slate-400 mt-1" data-v-f8779360>用于读取业务数据(重置设备码时清 userdevice/product_stat)</span></div>`);
if (dMode.value === "existing") {
_push(`<!--[--><div class="form-control mt-4" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>应用地址 *</span></label><input${ssrRenderAttr("value", dForm.base_url)} type="text" class="input input-bordered w-full" placeholder="https://api.xxx.com/" data-v-f8779360><span class="text-xs text-slate-400 mt-1" data-v-f8779360>用于通知应用业务服务事件(如配置更新)</span></div><div class="mt-4 text-sm" style="${ssrRenderStyle(testResult.show ? null : { display: "none" })}" data-v-f8779360><div class="${ssrRenderClass(testResult.apiOk ? "text-green-700" : "text-red-600")}" data-v-f8779360><span class="${ssrRenderClass(testResult.apiOk ? "text-green-600" : "text-red-500")}" data-v-f8779360>${ssrInterpolate(testResult.apiOk ? "✓" : "✗")}</span> 应用地址:${ssrInterpolate(testResult.apiMsg)}</div><div class="${ssrRenderClass(testResult.dbOk ? "text-green-700" : "text-red-600")}" data-v-f8779360><span class="${ssrRenderClass(testResult.dbOk ? "text-green-600" : "text-red-500")}" data-v-f8779360>${ssrInterpolate(testResult.dbOk ? "✓" : "✗")}</span> 业务库:${ssrInterpolate(testResult.dbMsg)}</div></div><!--]-->`);
} else {
_push(`<!---->`);
}
_push(`<div class="form-control mt-4" data-v-f8779360><label class="label" data-v-f8779360><span class="label-text font-medium" data-v-f8779360>备注</span></label><input${ssrRenderAttr("value", dForm.remark)} type="text" class="input input-bordered w-full" data-v-f8779360></div><div class="flex items-center gap-2 mt-4" data-v-f8779360><label class="flex items-center gap-2 cursor-pointer" data-v-f8779360><input${ssrIncludeBooleanAttr(Array.isArray(dForm.enabled) ? ssrLooseContain(dForm.enabled, null) : dForm.enabled) ? " checked" : ""} type="checkbox" class="toggle toggle-primary toggle-sm" data-v-f8779360><span class="text-sm" data-v-f8779360>启用</span></label></div><div class="flex gap-3 mt-6" data-v-f8779360><button type="button" class="btn btn-ghost" data-v-f8779360>取消</button>`);
if (dMode.value === "existing") {
_push(`<button type="button" class="btn btn-outline"${ssrIncludeBooleanAttr(testing.value) ? " disabled" : ""} data-v-f8779360>${ssrInterpolate(testing.value ? "测试中..." : "测试连接")}</button>`);
} else {
_push(`<!---->`);
}
_push(`<button type="submit" class="btn btn-primary text-white"${ssrIncludeBooleanAttr(!dIsEditing.value && dMode.value === "existing" && !testPassed.value) ? " disabled" : ""} data-v-f8779360>保存</button></div>`);
if (!dIsEditing.value && dMode.value === "existing") {
_push(`<p class="text-xs text-slate-400 mt-2" data-v-f8779360>需先「测试连接」通过(应用地址可达 + 业务库可连)才能保存。</p>`);
} else {
_push(`<!---->`);
}
_push(`</form></div></div><dialog class="modal" data-v-f8779360><div class="modal-box" data-v-f8779360><h3 class="font-bold text-lg" data-v-f8779360>分析历史数据</h3><p class="text-sm text-slate-500 mt-1" data-v-f8779360>${ssrInterpolate(az.appLabel)}</p><div class="text-xs text-amber-700 mt-3 bg-amber-50 border border-amber-100 rounded-lg p-3 leading-relaxed" data-v-f8779360> 扫描该应用业务库,按 <b data-v-f8779360>天 + 产品 + 区域</b> 生成历史统计(新增用户 / 订单 / 资源发放·使用 / 激活绑定设备),汇入 console 主库。<br data-v-f8779360> · <b data-v-f8779360>分析前会先清理该应用+区域在所选区间内的旧统计行</b>,避免数据重叠。<br data-v-f8779360> · 登录、活跃用户、AI对话等无每日原始记录,历史无法还原(由实时管道往后采集)。<br data-v-f8779360> · 仅对实时管道上线前的区间运行。留空 = 全部历史。大库可能耗时。 </div><div class="grid grid-cols-2 gap-3 mt-4" data-v-f8779360><div data-v-f8779360><label class="text-xs text-slate-500" data-v-f8779360>起始日(含)</label><input${ssrRenderAttr("value", az.start)} type="date" class="input input-bordered input-sm w-full" data-v-f8779360></div><div data-v-f8779360><label class="text-xs text-slate-500" data-v-f8779360>结束日(含)</label><input${ssrRenderAttr("value", az.end)} type="date" class="input input-bordered input-sm w-full" data-v-f8779360></div></div><div class="${ssrRenderClass([az.resultClass, "text-sm mt-3"])}" style="${ssrRenderStyle(az.resultShow ? null : { display: "none" })}" data-v-f8779360>`);
if (az.mode === "progress") {
_push(`<div class="bg-slate-50 border border-slate-200 rounded-lg p-3" data-v-f8779360><div class="flex justify-between items-center text-xs mb-1.5" data-v-f8779360><span class="text-slate-600" data-v-f8779360>`);
if (az.curName) {
_push(`<!--[--><span class="loading loading-spinner loading-xs" data-v-f8779360></span> 正在:${ssrInterpolate(az.curName)} (${ssrInterpolate(az.curIndex)}/${ssrInterpolate(az.curTotal)}) <!--]-->`);
} else {
_push(`<!--[-->准备中...<!--]-->`);
}
_push(`</span><span class="font-mono text-slate-400" data-v-f8779360>${ssrInterpolate(az.pct)}%</span></div><progress class="progress progress-primary w-full h-2"${ssrRenderAttr("value", az.pct)} max="100" data-v-f8779360></progress><div class="mt-2 text-xs space-y-0.5" data-v-f8779360><!--[-->`);
ssrRenderList(az.steps, (nm, i) => {
_push(`<div class="${ssrRenderClass(i === az.curIndex - 1 ? "text-slate-600" : "text-green-600")}" data-v-f8779360>`);
if (i === az.curIndex - 1) {
_push(`<!--[--><span class="loading loading-spinner loading-xs" data-v-f8779360></span> ${ssrInterpolate(nm)}<!--]-->`);
} else {
_push(`<!--[-->✓ ${ssrInterpolate(nm)}<!--]-->`);
}
_push(`</div>`);
});
_push(`<!--]--></div></div>`);
} else if (az.mode === "error") {
_push(`<div class="text-red-600" data-v-f8779360>✗ ${ssrInterpolate(az.errMsg)}</div>`);
} else if (az.mode === "done" && az.report) {
_push(`<div class="bg-green-50 border border-green-100 rounded-lg p-3" data-v-f8779360><div class="font-semibold text-green-700 mb-2" data-v-f8779360>✓ 分析完成</div><div class="grid grid-cols-2 gap-x-4 gap-y-1 text-xs text-slate-600 mb-2" data-v-f8779360><div data-v-f8779360>应用:<b data-v-f8779360>${ssrInterpolate(az.report.app_name || "")}</b></div><div data-v-f8779360>区域:${ssrInterpolate(az.report.region || "未指定")}</div><div data-v-f8779360>区间:${ssrInterpolate((az.report.start_day || "不限") + " ~ " + (az.report.end_day || "不限"))}</div><div data-v-f8779360>清理旧行:${ssrInterpolate(az.report.cleared_rows || 0)}</div><div data-v-f8779360>写入天数:<b data-v-f8779360>${ssrInterpolate(az.report.days_written || 0)}</b></div><div data-v-f8779360>写入行数:${ssrInterpolate(az.report.rows_written || 0)}</div></div><div class="border-t border-green-100 pt-2 text-xs" data-v-f8779360><!--[-->`);
ssrRenderList(az.report.steps || [], (s, i) => {
_push(`<div class="flex justify-between py-0.5" data-v-f8779360><span class="text-slate-500" data-v-f8779360>${ssrInterpolate(s.name)}</span><span class="font-mono text-slate-700" data-v-f8779360>${ssrInterpolate((s.groups || 0) + " 组")}</span></div>`);
});
_push(`<!--]--></div></div>`);
} else {
_push(`<!---->`);
}
_push(`</div><div class="modal-action" data-v-f8779360><button class="btn btn-ghost btn-sm" data-v-f8779360>关闭</button><button class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(az.running) ? " disabled" : ""} data-v-f8779360>${ssrInterpolate(az.btnText)}</button></div></div><form method="dialog" class="modal-backdrop" data-v-f8779360><button data-v-f8779360>close</button></form></dialog><dialog class="modal" data-v-f8779360><div class="modal-box max-w-2xl" data-v-f8779360><h3 class="font-bold text-lg" data-v-f8779360>升级部署</h3><p class="text-sm text-slate-500 mt-1" data-v-f8779360>${ssrInterpolate(up.label)}</p><div class="text-xs text-amber-700 mt-3 bg-amber-50 border border-amber-100 rounded-lg p-3 leading-relaxed" data-v-f8779360> 将 <b data-v-f8779360>SSH 连接到该部署绑定的环境节点</b>,进入部署目录执行:<span class="font-mono" data-v-f8779360>docker login → compose pull → up -d 重启 → 清理旧镜像</span>。<br data-v-f8779360> · 需服务器上已维护好 <span class="font-mono" data-v-f8779360>docker-compose.yml / .env / confs</span>(本操作不上传真实配置)。<br data-v-f8779360> · 会<b data-v-f8779360>重启该部署的容器</b>,请确认无误后再执行。 </div><div class="grid grid-cols-1 gap-2 mt-4 text-xs" data-v-f8779360><div class="flex" data-v-f8779360><span class="w-20 text-slate-400 shrink-0" data-v-f8779360>环境节点</span><span class="${ssrRenderClass(up.envName ? "font-medium text-slate-700" : "font-medium text-red-500")}" data-v-f8779360>${ssrInterpolate(up.envName || "未绑定 —— 请先在「编辑」里选择环境节点")}</span></div><div class="flex" data-v-f8779360><span class="w-20 text-slate-400 shrink-0" data-v-f8779360>部署目录</span><span class="${ssrRenderClass(up.deployDir ? "font-mono text-slate-700" : "font-medium text-red-500")}" data-v-f8779360>${ssrInterpolate(up.deployDir || "未填 —— 请先在「编辑」里填写远端部署目录")}</span></div></div><div class="mt-3" data-v-f8779360><label class="text-xs text-slate-500" data-v-f8779360>镜像 Tag(留空 = latest)</label><input${ssrRenderAttr("value", up.tag)} type="text" class="input input-bordered input-sm w-full font-mono" placeholder="latest"${ssrIncludeBooleanAttr(up.running) ? " disabled" : ""} data-v-f8779360></div><div class="mt-3" style="${ssrRenderStyle(up.show ? null : { display: "none" })}" data-v-f8779360><div class="flex items-center gap-2 text-xs mb-1" data-v-f8779360>`);
if (up.running) {
_push(`<span class="loading loading-spinner loading-xs text-amber-500" data-v-f8779360></span>`);
} else if (up.ok) {
_push(`<span class="text-green-600 font-semibold" data-v-f8779360>✓ 部署完成</span>`);
} else {
_push(`<span class="text-red-600 font-semibold" data-v-f8779360>✗ 部署失败</span>`);
}
_push(`<span class="text-slate-400" data-v-f8779360>${ssrInterpolate(up.running ? "执行中…" : "")}</span></div><pre class="bg-slate-900 text-slate-100 text-[11px] leading-relaxed rounded-lg p-3 h-64 overflow-auto font-mono whitespace-pre-wrap" data-v-f8779360>${ssrInterpolate(up.log || "(等待输出…)")}</pre></div><div class="modal-action" data-v-f8779360><button class="btn btn-ghost btn-sm"${ssrIncludeBooleanAttr(up.running) ? " disabled" : ""} data-v-f8779360>关闭</button><button class="btn btn-warning btn-sm"${ssrIncludeBooleanAttr(up.running) ? " disabled" : ""} data-v-f8779360>${ssrInterpolate(up.btnText)}</button></div></div><form method="dialog" class="modal-backdrop" data-v-f8779360><button${ssrIncludeBooleanAttr(up.running) ? " disabled" : ""} data-v-f8779360>close</button></form></dialog></div>`);
};
}
});
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/apps.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const apps = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f8779360"]]);
export { apps as default };
//# sourceMappingURL=apps-DkgvJNjV.mjs.map