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.
100 lines
7.4 KiB
100 lines
7.4 KiB
import { defineComponent, ref, reactive, computed, useSSRContext } from 'vue';
|
|
import { ssrRenderAttrs, ssrRenderStyle, ssrIncludeBooleanAttr, ssrRenderAttr, ssrLooseContain, ssrLooseEqual, ssrRenderList, ssrInterpolate } from 'vue/server-renderer';
|
|
import { u as useApi } from './useApi-B-E5eLsI.mjs';
|
|
import { u as useToast } from './useToast-CS21XT61.mjs';
|
|
import './server.mjs';
|
|
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 'pinia';
|
|
import 'perfect-debounce';
|
|
import './useLoading-D4zrSa2m.mjs';
|
|
|
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
__name: "appconfig",
|
|
__ssrInlineRender: true,
|
|
setup(__props) {
|
|
useApi();
|
|
useToast();
|
|
const view = ref("list");
|
|
const apps = ref([]);
|
|
const curApp = ref(0);
|
|
const items = ref([]);
|
|
const loading = ref(false);
|
|
const submitting = ref(false);
|
|
const isEditing = ref(false);
|
|
const keyword = ref("");
|
|
const form = reactive({ id: 0, group: "", key: "", value: "", description: "" });
|
|
const curAppLabel = computed(() => {
|
|
const a = apps.value.find((x) => x.id === curApp.value);
|
|
return a ? a.name || a.app_name : "";
|
|
});
|
|
const filteredRows = computed(() => {
|
|
const kw = keyword.value.trim().toLowerCase();
|
|
if (!kw) return items.value;
|
|
return items.value.filter((c) => ((c.group || "") + (c.key || "")).toLowerCase().includes(kw));
|
|
});
|
|
const groupedRows = computed(() => {
|
|
const groups = {};
|
|
filteredRows.value.forEach((c) => {
|
|
const g = c.group || "";
|
|
(groups[g] = groups[g] || []).push(c);
|
|
});
|
|
const names = Object.keys(groups).sort((a, b) => {
|
|
if (a === "") return -1;
|
|
if (b === "") return 1;
|
|
return a < b ? -1 : 1;
|
|
});
|
|
return names.map((g) => ({ key: g, label: g || "未分组", items: groups[g] }));
|
|
});
|
|
return (_ctx, _push, _parent, _attrs) => {
|
|
_push(`<div${ssrRenderAttrs(_attrs)}><div style="${ssrRenderStyle(view.value === "list" ? null : { display: "none" })}"><div class="flex items-center justify-between mb-5"><div><h2 class="text-lg font-semibold text-slate-800">应用环境配置</h2><p class="text-xs text-slate-400 mt-1">应用自有的 key/value 配置(音乐、OSS 等),直接读写所选应用的业务库。结构同「全局环境配置」但不分区域。</p></div><button class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(!curApp.value) ? " disabled" : ""}>+ 新增配置</button></div><div class="flex items-center gap-3 mb-4"><span class="text-sm text-slate-500">应用</span><select class="select select-bordered select-sm min-w-48"><option${ssrRenderAttr("value", 0)} disabled${ssrIncludeBooleanAttr(Array.isArray(curApp.value) ? ssrLooseContain(curApp.value, 0) : ssrLooseEqual(curApp.value, 0)) ? " selected" : ""}>请选择应用</option><!--[-->`);
|
|
ssrRenderList(apps.value, (a) => {
|
|
_push(`<option${ssrRenderAttr("value", a.id)}${ssrIncludeBooleanAttr(Array.isArray(curApp.value) ? ssrLooseContain(curApp.value, a.id) : ssrLooseEqual(curApp.value, a.id)) ? " selected" : ""}>${ssrInterpolate(a.name || a.app_name)}</option>`);
|
|
});
|
|
_push(`<!--]--></select><input${ssrRenderAttr("value", keyword.value)} class="input input-bordered input-sm w-48" placeholder="按分组/键搜索"></div>`);
|
|
if (!curApp.value) {
|
|
_push(`<div class="bg-white rounded-xl shadow-sm border border-slate-100 text-center text-slate-400 py-16"><div class="text-4xl mb-2">🗂️</div><p class="text-sm">请先在上方选择一个应用</p></div>`);
|
|
} else {
|
|
_push(`<div class="bg-white rounded-xl shadow-sm border border-slate-100"><div class="overflow-x-auto"><table class="table"><thead><tr><th>键</th><th>值</th><th>描述</th><th class="text-right">操作</th></tr></thead><tbody>`);
|
|
if (loading.value) {
|
|
_push(`<tr><td colspan="4" class="text-center py-8"><span class="loading loading-spinner loading-sm"></span></td></tr>`);
|
|
} else if (!filteredRows.value.length) {
|
|
_push(`<tr><td colspan="4" class="text-center text-slate-400 py-8">暂无配置</td></tr>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`<!--[-->`);
|
|
ssrRenderList(groupedRows.value, (grp) => {
|
|
_push(`<!--[--><tr class="bg-slate-100/80"><td colspan="4" class="py-2"><span class="font-semibold text-slate-600 text-sm">▸ ${ssrInterpolate(grp.label)}</span><span class="text-xs text-slate-400 ml-2">${ssrInterpolate(grp.items.length)} 项</span></td></tr><!--[-->`);
|
|
ssrRenderList(grp.items, (c) => {
|
|
_push(`<tr class="hover"><td class="font-mono text-sm font-medium">${ssrInterpolate(c.key || "")}</td><td class="text-sm text-slate-500 max-w-xs truncate"${ssrRenderAttr("title", c.value || "")}>${ssrInterpolate(c.value || "")}</td><td class="text-sm text-slate-400">${ssrInterpolate(c.description || "")}</td><td class="text-right"><div class="inline-flex gap-1"><button class="btn btn-ghost btn-xs">编辑</button><button class="btn btn-ghost btn-xs text-red-500">删除</button></div></td></tr>`);
|
|
});
|
|
_push(`<!--]--><!--]-->`);
|
|
});
|
|
_push(`<!--]--></tbody></table></div></div>`);
|
|
}
|
|
_push(`</div><div style="${ssrRenderStyle(view.value === "form" ? null : { display: "none" })}"><div class="flex items-center gap-3 mb-5"><button class="btn btn-ghost btn-sm">← 返回列表</button><h2 class="text-lg font-semibold text-slate-800">${ssrInterpolate(isEditing.value ? "编辑配置" : "新增配置")}</h2><span class="text-xs text-slate-400">应用:${ssrInterpolate(curAppLabel.value)}</span></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-6 max-w-2xl"><form><div class="form-control mb-4"><label class="label"><span class="label-text font-medium">分组 (group)</span></label><input${ssrRenderAttr("value", form.group)} type="text" class="input input-bordered w-full" placeholder="如 music / oss / other"></div><div class="form-control mb-4"><label class="label"><span class="label-text font-medium">键 (key) *</span></label><input${ssrRenderAttr("value", form.key)} type="text" class="input input-bordered w-full" required placeholder="如 oss_access_key"></div><div class="form-control mb-4"><label class="label"><span class="label-text font-medium">值 (value)</span></label><textarea class="textarea textarea-bordered w-full font-mono text-sm" rows="3">${ssrInterpolate(form.value)}</textarea></div><div class="form-control mb-6"><label class="label"><span class="label-text font-medium">描述</span></label><input${ssrRenderAttr("value", form.description)} type="text" class="input input-bordered w-full"></div><div class="flex gap-3"><button type="button" class="btn btn-ghost">取消</button><button type="submit" class="btn btn-primary text-white"${ssrIncludeBooleanAttr(submitting.value) ? " disabled" : ""}>保存</button></div></form></div></div></div>`);
|
|
};
|
|
}
|
|
});
|
|
const _sfc_setup = _sfc_main.setup;
|
|
_sfc_main.setup = (props, ctx) => {
|
|
const ssrContext = useSSRContext();
|
|
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/appconfig.vue");
|
|
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
|
|
};
|
|
|
|
export { _sfc_main as default };
|
|
//# sourceMappingURL=appconfig-BTmHA76P.mjs.map
|
|
|