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.
260 lines
17 KiB
260 lines
17 KiB
import { defineComponent, reactive, ref, computed, useSSRContext } from 'vue';
|
|
import { ssrRenderAttrs, ssrInterpolate, ssrRenderList, ssrRenderStyle, ssrRenderAttr, ssrRenderClass, ssrIncludeBooleanAttr, ssrLooseContain, ssrLooseEqual, ssrRenderDynamicModel } from 'vue/server-renderer';
|
|
import { u as useToast } from './useToast-MBvLaNjH.mjs';
|
|
import { u as useApi } from './useApi-BNSkSrat.mjs';
|
|
import { _ as _export_sfc } from './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';
|
|
|
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
__name: "systemconfig",
|
|
__ssrInlineRender: true,
|
|
setup(__props) {
|
|
useToast();
|
|
useApi();
|
|
function mk(id, provider, name, short, tag, color, fields) {
|
|
return { id, provider, name, short, tag, color, enable: false, is_default: false, fields };
|
|
}
|
|
const CATALOG = reactive([
|
|
{
|
|
id: "storage",
|
|
label: "对象存储",
|
|
desc: "固件 / 头像等文件直传(默认阿里云 OSS)",
|
|
color: "#6366f1",
|
|
icon: "M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8",
|
|
multi: true,
|
|
services: [
|
|
mk("storage_aliyun_oss", "aliyun_oss", "阿里云 OSS", "OSS", "Aliyun · 固件/头像上传所用", "#ff6a00", [
|
|
{ key: "endpoint", label: "Endpoint", value: "", placeholder: "oss-cn-shanghai.aliyuncs.com", mono: true, required: true },
|
|
{ key: "bucket", label: "Bucket", value: "", placeholder: "yunyan-firmware", mono: true, required: true },
|
|
{ key: "access_key_id", label: "AccessKey ID", value: "", mono: true, encrypted: true, required: true },
|
|
{ key: "access_key_secret", label: "AccessKey Secret", value: "", mono: true, encrypted: true, required: true },
|
|
{ key: "domain", label: "自定义域名 (CDN)", value: "", placeholder: "cdn.yunyan.com", wide: true, hint: "可选,配置后文件下载 URL 走该域名" }
|
|
]),
|
|
mk("storage_tencent_cos", "tencent_cos", "腾讯云 COS", "COS", "Tencent", "#00a4ff", [
|
|
{ key: "region", label: "Region", value: "", placeholder: "ap-guangzhou", mono: true, required: true },
|
|
{ key: "appid", label: "AppId", value: "", mono: true, required: true },
|
|
{ key: "bucket", label: "Bucket", value: "", mono: true, required: true },
|
|
{ key: "secret_id", label: "SecretId", value: "", mono: true, encrypted: true, required: true },
|
|
{ key: "secret_key", label: "SecretKey", value: "", mono: true, encrypted: true, required: true },
|
|
{ key: "domain", label: "自定义域名 (CDN)", value: "", wide: true, hint: "可选" }
|
|
])
|
|
]
|
|
},
|
|
{
|
|
id: "email",
|
|
label: "邮件服务",
|
|
desc: "生产通知 / 账号告警发信(支持 SMTP 与 Resend)",
|
|
color: "#f59e0b",
|
|
icon: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z",
|
|
multi: false,
|
|
services: [
|
|
mk("email", "auto", "邮件服务", "MAIL", "生产通知 / 账号告警", "#f59e0b", [
|
|
{ key: "EmailType", label: "邮箱类型", value: "1", type: "select", required: true, options: [
|
|
{ value: "0", label: "QQ 邮箱 (SMTP)" },
|
|
{ value: "1", label: "腾讯企业邮箱 (SMTP)" },
|
|
{ value: "2", label: "Gmail (SMTP)" },
|
|
{ value: "3", label: "Resend(HTTP API,海外送达率优)" }
|
|
] },
|
|
{ key: "FromEmail", label: "发件人邮箱", value: "", mono: true, required: true, placeholder: "noreply@yourdomain.com", hint: "Resend 须为已在其后台验证域名下的地址" },
|
|
{ key: "FromName", label: "发件人昵称", value: "", placeholder: "云岩科技" },
|
|
{ key: "Password", label: "SMTP 授权码 / Resend API Key", value: "", mono: true, encrypted: true, required: true, hint: "SMTP 类型填邮箱授权码;Resend 填 re_ 开头的 API Key" }
|
|
])
|
|
]
|
|
},
|
|
{
|
|
id: "translate",
|
|
label: "翻译服务",
|
|
desc: "后台文案多语言同步",
|
|
color: "#14b8a6",
|
|
icon: "M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129",
|
|
multi: true,
|
|
services: [
|
|
mk("translate_volc", "volc", "火山引擎翻译", "火山", "Volcengine MT", "#1664ff", [
|
|
{ key: "region", label: "Region", value: "cn-beijing", mono: true, required: true },
|
|
{ key: "access_key", label: "AccessKey", value: "", mono: true, encrypted: true, required: true },
|
|
{ key: "secret_key", label: "SecretKey", value: "", mono: true, encrypted: true, required: true }
|
|
]),
|
|
mk("translate_aliyun", "aliyun_mt", "阿里云翻译", "阿里", "Aliyun MT", "#ff6a00", [
|
|
{ key: "region", label: "Region", value: "cn-hangzhou", mono: true, required: true },
|
|
{ key: "access_key_id", label: "AccessKey ID", value: "", mono: true, encrypted: true, required: true },
|
|
{ key: "access_key_secret", label: "AccessKey Secret", value: "", mono: true, encrypted: true, required: true }
|
|
]),
|
|
mk("translate_google", "google_mt", "Google 翻译", "G", "Cloud Translation", "#ea4335", [
|
|
{ key: "project", label: "Project ID", value: "", mono: true, required: true },
|
|
{ key: "api_key", label: "API Key", value: "", mono: true, encrypted: true, required: true }
|
|
]),
|
|
mk("translate_deepl", "deepl", "DeepL", "DL", "DeepL API", "#0f2b46", [
|
|
{ key: "auth_key", label: "Auth Key", value: "", mono: true, encrypted: true, required: true }
|
|
])
|
|
]
|
|
}
|
|
]);
|
|
const view = ref("cards");
|
|
const editCatId = ref("");
|
|
const curProviderId = ref("");
|
|
const saving = ref(false);
|
|
const testing = ref(false);
|
|
const testTo = ref("");
|
|
const curCat = computed(() => CATALOG.find((c) => c.id === editCatId.value) || CATALOG[0]);
|
|
const curProviders = computed(() => curCat.value.services);
|
|
const curService = computed(() => {
|
|
if (!curCat.value.multi) return curCat.value.services[0];
|
|
return curCat.value.services.find((s) => s.id === curProviderId.value) || curCat.value.services[0];
|
|
});
|
|
function catServices(catId) {
|
|
return CATALOG.find((c) => c.id === catId)?.services || [];
|
|
}
|
|
function catEnabled(catId) {
|
|
return catServices(catId).some((s) => s.enable);
|
|
}
|
|
function catDefaultName(catId) {
|
|
const cat = CATALOG.find((c) => c.id === catId);
|
|
if (!cat) return "";
|
|
if (!cat.multi) {
|
|
const s = cat.services[0];
|
|
return s.enable ? s.name : "";
|
|
}
|
|
const def = cat.services.find((s) => s.is_default && s.enable);
|
|
return def ? def.name : "";
|
|
}
|
|
return (_ctx, _push, _parent, _attrs) => {
|
|
_push(`<div${ssrRenderAttrs(_attrs)} data-v-6ea4e757><div class="flex items-center gap-2 mb-1" data-v-6ea4e757>`);
|
|
if (view.value === "edit") {
|
|
_push(`<button class="btn btn-ghost btn-sm" data-v-6ea4e757>← 返回</button>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`<h2 class="text-lg font-semibold text-slate-800" data-v-6ea4e757>系统配置`);
|
|
if (view.value === "edit") {
|
|
_push(`<span class="text-slate-400 font-normal" data-v-6ea4e757> / ${ssrInterpolate(curCat.value.label)}</span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</h2></div><p class="text-xs text-slate-400 mb-5" data-v-6ea4e757> 平台自用服务配置(与「第三方服务配置」分库存储,不下发客户端):对象存储(固件 / 头像直传)、邮件服务(生产通知发信)、翻译服务(后台文案多语言)。 </p>`);
|
|
if (view.value === "cards") {
|
|
_push(`<div class="grid grid-cols-3 gap-4" data-v-6ea4e757><!--[-->`);
|
|
ssrRenderList(CATALOG, (cat) => {
|
|
_push(`<div class="cat-card" data-v-6ea4e757><div class="flex items-start justify-between" data-v-6ea4e757><div class="cat-icon" style="${ssrRenderStyle({ background: cat.color })}" data-v-6ea4e757><svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor" data-v-6ea4e757><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"${ssrRenderAttr("d", cat.icon)} data-v-6ea4e757></path></svg></div>`);
|
|
if (catEnabled(cat.id)) {
|
|
_push(`<span class="badge badge-success badge-sm text-white" data-v-6ea4e757>已启用</span>`);
|
|
} else {
|
|
_push(`<span class="badge badge-ghost badge-sm" data-v-6ea4e757>未配置</span>`);
|
|
}
|
|
_push(`</div><div class="text-base font-semibold text-slate-800 mt-3" data-v-6ea4e757>${ssrInterpolate(cat.label)}</div><div class="text-xs text-slate-400 mt-1" data-v-6ea4e757>${ssrInterpolate(cat.desc)}</div><div class="text-[11px] text-slate-400 mt-3 pt-3 border-t border-slate-100" data-v-6ea4e757>`);
|
|
if (catDefaultName(cat.id)) {
|
|
_push(`<span data-v-6ea4e757>当前:<b class="text-slate-600" data-v-6ea4e757>${ssrInterpolate(catDefaultName(cat.id))}</b></span>`);
|
|
} else {
|
|
_push(`<span class="text-slate-300" data-v-6ea4e757>尚未配置,点击设置</span>`);
|
|
}
|
|
_push(`</div></div>`);
|
|
});
|
|
_push(`<!--]--></div>`);
|
|
} else if (view.value === "edit") {
|
|
_push(`<div data-v-6ea4e757>`);
|
|
if (curCat.value.multi) {
|
|
_push(`<!--[--><div class="text-xs font-semibold text-slate-500 mb-2" data-v-6ea4e757>选择服务商 <span class="text-slate-400 font-normal" data-v-6ea4e757>(勾选设为默认,平台调用走默认项)</span></div><div class="grid grid-cols-4 gap-3 mb-5" data-v-6ea4e757><!--[-->`);
|
|
ssrRenderList(curProviders.value, (p) => {
|
|
_push(`<div class="${ssrRenderClass([{ active: curProviderId.value === p.id, "is-default": p.is_default }, "provider-card"])}" data-v-6ea4e757><div class="flex items-center justify-between" data-v-6ea4e757><div class="provider-logo" style="${ssrRenderStyle({ background: p.color })}" data-v-6ea4e757>${ssrInterpolate(p.short)}</div>`);
|
|
if (p.enable) {
|
|
_push(`<span class="text-[10px] text-emerald-500 font-semibold" data-v-6ea4e757>已配置</span>`);
|
|
} else {
|
|
_push(`<span class="text-[10px] text-slate-300 font-semibold" data-v-6ea4e757>未配置</span>`);
|
|
}
|
|
_push(`</div><div class="text-sm font-semibold text-slate-700 mt-2" data-v-6ea4e757>${ssrInterpolate(p.name)}</div><div class="text-[11px] text-slate-400 mb-2.5" data-v-6ea4e757>${ssrInterpolate(p.tag)}</div><label class="${ssrRenderClass([{ on: p.is_default }, "default-pick"])}" data-v-6ea4e757><input type="radio" class="radio radio-xs radio-primary"${ssrIncludeBooleanAttr(p.is_default) ? " checked" : ""} data-v-6ea4e757><span data-v-6ea4e757>${ssrInterpolate(p.is_default ? "默认使用" : "设为默认")}</span></label></div>`);
|
|
});
|
|
_push(`<!--]--></div><!--]-->`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
if (curService.value) {
|
|
_push(`<div class="bg-white rounded-2xl border border-slate-100 shadow-sm p-6 max-w-3xl" data-v-6ea4e757><div class="flex items-center justify-between mb-5" data-v-6ea4e757><div class="flex items-center gap-3" data-v-6ea4e757><div class="provider-logo" style="${ssrRenderStyle({ background: curService.value.color, width: "44px", height: "44px", fontSize: "14px" })}" data-v-6ea4e757>${ssrInterpolate(curService.value.short)}</div><div data-v-6ea4e757><h3 class="text-base font-semibold text-slate-800" data-v-6ea4e757>${ssrInterpolate(curService.value.name)}</h3><p class="text-xs text-slate-400 mt-0.5" data-v-6ea4e757>${ssrInterpolate(curService.value.tag)}</p></div></div><div class="flex items-center gap-2" data-v-6ea4e757><label class="flex items-center gap-2 mr-1" data-v-6ea4e757><span class="text-xs text-slate-500" data-v-6ea4e757>启用</span><input${ssrIncludeBooleanAttr(Array.isArray(curService.value.enable) ? ssrLooseContain(curService.value.enable, null) : curService.value.enable) ? " checked" : ""} type="checkbox" class="toggle toggle-primary toggle-sm" data-v-6ea4e757></label><button class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(saving.value) ? " disabled" : ""} data-v-6ea4e757>`);
|
|
if (saving.value) {
|
|
_push(`<span class="loading loading-spinner loading-xs" data-v-6ea4e757></span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`保存 </button></div></div><div class="divider text-xs text-slate-400 my-3" data-v-6ea4e757>配置项</div><div class="grid grid-cols-2 gap-x-5 gap-y-4" data-v-6ea4e757><!--[-->`);
|
|
ssrRenderList(curService.value.fields, (f) => {
|
|
_push(`<div class="${ssrRenderClass([{ "col-span-2": f.wide }, "form-control"])}" data-v-6ea4e757><label class="label py-1" data-v-6ea4e757><span class="label-text text-sm" data-v-6ea4e757>${ssrInterpolate(f.label)}`);
|
|
if (f.required) {
|
|
_push(`<span class="text-rose-500 ml-0.5" data-v-6ea4e757>*</span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
if (f.encrypted) {
|
|
_push(`<span class="lock-tag ml-1.5" data-v-6ea4e757>🔒 加密存储</span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</span></label>`);
|
|
if (f.type === "select") {
|
|
_push(`<select class="select select-bordered select-sm" data-v-6ea4e757><!--[-->`);
|
|
ssrRenderList(f.options, (o) => {
|
|
_push(`<option${ssrRenderAttr("value", o.value)} data-v-6ea4e757${ssrIncludeBooleanAttr(Array.isArray(f.value) ? ssrLooseContain(f.value, o.value) : ssrLooseEqual(f.value, o.value)) ? " selected" : ""}>${ssrInterpolate(o.label)}</option>`);
|
|
});
|
|
_push(`<!--]--></select>`);
|
|
} else {
|
|
_push(`<div class="relative" data-v-6ea4e757><input${ssrRenderDynamicModel(f.encrypted && !f._show ? "password" : "text", f.value, null)}${ssrRenderAttr("type", f.encrypted && !f._show ? "password" : "text")} class="${ssrRenderClass([{ "font-mono": f.mono, "pr-14": f.encrypted }, "input input-bordered input-sm w-full"])}"${ssrRenderAttr("placeholder", f.placeholder)} data-v-6ea4e757>`);
|
|
if (f.encrypted) {
|
|
_push(`<button type="button" class="absolute right-3 top-1/2 -translate-y-1/2 text-xs text-slate-400 hover:text-slate-700" data-v-6ea4e757>${ssrInterpolate(f._show ? "隐藏" : "显示")}</button>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
}
|
|
if (f.hint) {
|
|
_push(`<span class="text-[11px] text-slate-400 mt-1" data-v-6ea4e757>${ssrInterpolate(f.hint)}</span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
});
|
|
_push(`<!--]--></div>`);
|
|
if (curCat.value.id === "email") {
|
|
_push(`<!--[--><div class="divider text-xs text-slate-400 my-4" data-v-6ea4e757>测试发信</div><div class="flex items-end gap-3" data-v-6ea4e757><div class="form-control flex-1" data-v-6ea4e757><label class="label py-1" data-v-6ea4e757><span class="label-text text-sm" data-v-6ea4e757>测试收件邮箱</span></label><input${ssrRenderAttr("value", testTo.value)} class="input input-bordered input-sm font-mono" placeholder="填一个邮箱,发送测试邮件验证配置(需先保存)" data-v-6ea4e757></div><button class="btn btn-outline btn-sm"${ssrIncludeBooleanAttr(testing.value) ? " disabled" : ""} data-v-6ea4e757>`);
|
|
if (testing.value) {
|
|
_push(`<span class="loading loading-spinner loading-xs" data-v-6ea4e757></span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`发送测试 </button></div><!--]-->`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
};
|
|
}
|
|
});
|
|
const _sfc_setup = _sfc_main.setup;
|
|
_sfc_main.setup = (props, ctx) => {
|
|
const ssrContext = useSSRContext();
|
|
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/systemconfig.vue");
|
|
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
|
|
};
|
|
const systemconfig = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6ea4e757"]]);
|
|
|
|
export { systemconfig as default };
|
|
//# sourceMappingURL=systemconfig-CCKY3oG5.mjs.map
|
|
|