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-DMQewX5_.mjs'; import { u as useToast } from './useToast-CS21XT61.mjs'; import { u as useAuthStore } from './auth-QFkCoU1C.mjs'; import { _ as _export_sfc, b as useRouter } from './server.mjs'; import './useLoading-D4zrSa2m.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] : "-"; } function isPinnedVer(tag) { const t = (tag || "").trim(); return !!t && t !== "latest"; } 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: "", tags: [], // 从仓库拉取的可用版本 tagMode: "list", tagsLoading: false, tagsError: "", log: "", show: false, running: false, ok: false, canRun: false, btnText: "开始升级" }); return (_ctx, _push, _parent, _attrs) => { _push(`

应用管理

应用 是一个产品(如 Voitrans);其下挂多条 部署(各区域一份)。 卡片 = 应用;卡片内表格 = 该应用的区域部署。

`); if (loading.value) { _push(`
`); } else if (!groups.value.length) { _push(`
暂无应用,先「添加应用」
`); } else { _push(`
`); ssrRenderList(groups.value, (g) => { _push(`
${ssrInterpolate(g.product ? (g.product.name || "?").charAt(0).toUpperCase() : "?")}
应用${ssrInterpolate(g.product ? g.product.name : "未分组部署")}`); if (g.product) { _push(`${ssrInterpolate(g.product.enabled ? "启用" : "停用")}`); } else { _push(``); } if (g.product && g.product.image_name) { _push(`🐳 ${ssrInterpolate(g.product.image_name)}`); } else { _push(``); } _push(`${ssrInterpolate(g.deployments.length)} 个部署

${ssrInterpolate(g.product ? g.product.remark || "—" : "未填所属应用名、或应用已删除的历史部署;编辑部署可归位到某个应用")}

`); if (g.product) { _push(`
`); } else { _push(``); } _push(`
`); if (!g.deployments.length) { _push(`
该应用暂无部署`); if (g.product) { _push(`,点右上「+ 部署」添加`); } else { _push(``); } _push(`
`); } else { _push(`
`); ssrRenderList(g.deployments, (a) => { _push(``); }); _push(`
部署区域环境状态当前版本业务库启用操作
部署${ssrInterpolate(a.name || "部署#" + a.id)}#${ssrInterpolate(a.id)}${ssrInterpolate(a.region || "—")}`); if (a.status === "pending") { _push(`待部署`); } else { _push(`已接入`); } _push(``); if (isPinnedVer(a.image_tag)) { _push(`${ssrInterpolate(a.image_tag)}`); } else { _push(`${ssrInterpolate(a.image_tag || "latest")} ⚠`); } _push(`${ssrInterpolate(dbName(a.service_dsn))}`); if (a.enabled) { _push(`是`); } else { _push(`否`); } _push(`
`); if (a.status !== "pending") { _push(``); } else { _push(``); } _push(`
`); } _push(`
`); }); _push(`
`); } _push(`

${ssrInterpolate(pIsEditing.value ? "编辑应用" : "添加应用")}

账号作用域按应用名绑定,尽量与统计/账号里一致。

${ssrInterpolate(dIsEditing.value ? "编辑部署" : "添加部署")}

`); if (!dIsEditing.value) { _push(``); } else { _push(``); } _push(`

`); if (dIsEditing.value) { _push(`编辑该区域部署的配置(镜像 Tag / 部署目录 / 环境节点 等);改好后回列表点「升级」执行远程部署(拉新镜像并重启)。`); } else if (dMode.value === "existing") { _push(`把「已经部署好的应用区域」加进来:填地址与业务库 DSN,测试通过后保存。`); } else { _push(`选一个「部署目标环境」,先建关联并标记待部署;保存后回列表点「升级」执行远程部署。`); } _push(`

已部署的区域不再出现(一个应用每区域一份部署)。
用于读取业务数据(重置设备码时清 userdevice/product_stat)
`); if (dMode.value === "existing") { _push(`
用于通知应用业务服务事件(如配置更新)
${ssrInterpolate(testResult.apiOk ? "✓" : "✗")} 应用地址:${ssrInterpolate(testResult.apiMsg)}
${ssrInterpolate(testResult.dbOk ? "✓" : "✗")} 业务库:${ssrInterpolate(testResult.dbMsg)}
`); } else { _push(``); } _push(`
`); if (dMode.value === "existing") { _push(``); } else { _push(``); } _push(`
`); if (!dIsEditing.value && dMode.value === "existing") { _push(`

需先「测试连接」通过(应用地址可达 + 业务库可连)才能保存。

`); } else { _push(``); } _push(`
`); }; } }); 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-955faaec"]]); export { apps as default }; //# sourceMappingURL=apps-M35AvXEe.mjs.map