From eba781d15d4079a1358743d0a566494338a7fa1d Mon Sep 17 00:00:00 2001 From: "fengchuanhn@gmail.com" Date: Thu, 21 May 2026 17:19:30 +0800 Subject: [PATCH] 11 --- src/api/oemAppBranding.js | 113 ++++++++++++++++++++++++++++++ src/views/oem/OemOverviewView.vue | 12 ++-- 2 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 src/api/oemAppBranding.js diff --git a/src/api/oemAppBranding.js b/src/api/oemAppBranding.js new file mode 100644 index 0000000..587702a --- /dev/null +++ b/src/api/oemAppBranding.js @@ -0,0 +1,113 @@ +import { apiRequest } from "./client.js"; + +/** 品牌静态资源基址(与 pythonbackend 根目录 images 挂载的 /images 一致) */ +const MEDIA_BASE = + import.meta.env.VITE_MEDIA_BASE_URL || "http://127.0.0.1:8001"; + +/** + * @param {string} token + * @param {RequestInit} [options] + */ +function oemRequest(token, path, options = {}) { + return apiRequest(path, { + ...options, + headers: { + Authorization: `Bearer ${token}`, + ...options.headers, + }, + }); +} + +function emptyBrandingForm() { + return { + softwareName: "", + logo: "", + contactWechat: "", + contactQq: "", + wechatQr: "", + qqQr: "", + }; +} + +/** + * 库内路径 images/xxx → 可访问 URL(预览用) + * @param {string | null | undefined} path + */ +export function brandingImageUrl(path) { + if (!path?.trim()) return ""; + const value = path.trim(); + if (value.startsWith("data:image/") || value.startsWith("http")) return value; + const normalized = value.replace(/\\/g, "/").replace(/^\//, ""); + if (normalized.startsWith("images/")) { + return `${MEDIA_BASE}/${normalized}`; + } + return `${MEDIA_BASE}/images/${normalized}`; +} + +/** 提交前:新上传保留 data URL;已有文件只提交 images/ 相对路径 */ +function toStoredImageValue(value) { + if (!value?.trim()) return null; + const v = value.trim(); + if (v.startsWith("data:image/")) return v; + const match = v.match(/\/images\/(.+?)(?:\?.*)?$/); + if (match) return `images/${match[1]}`; + if (v.startsWith("images/")) return v; + return v; +} + +/** API 载荷 → 表单 */ +function toForm(data) { + if (!data) return emptyBrandingForm(); + return { + softwareName: data.software_name ?? "", + logo: brandingImageUrl(data.logo_path), + contactWechat: data.wechat ?? "", + contactQq: data.qq ?? "", + wechatQr: brandingImageUrl(data.wechat_qrcode), + qqQr: brandingImageUrl(data.qq_qrcode), + }; +} + +/** 表单 → API 载荷 */ +function toPayload(form) { + return { + software_name: String(form.softwareName ?? "").trim(), + logo_path: toStoredImageValue(form.logo), + wechat: form.contactWechat?.trim() || null, + qq: form.contactQq?.trim() || null, + wechat_qrcode: toStoredImageValue(form.wechatQr), + qq_qrcode: toStoredImageValue(form.qqQr), + }; +} + +/** + * 加载默认 OEM(id=1)软件配置 + * @param {string} token + */ +export async function loadOemAppBrandingApi(token) { + const res = await oemRequest(token, "/oem/oem-branding"); + if (!res.ok) { + return { ok: false, message: res.message || "加载软件配置失败" }; + } + return { ok: true, data: { form: toForm(res.data), oemId: res.data?.id ?? 1 } }; +} + +/** + * 保存默认 OEM(id=1)软件配置 + * @param {string} token + * @param {ReturnType} form + */ +export async function saveOemAppBrandingApi(token, form) { + const res = await oemRequest(token, "/oem/oem-branding", { + method: "PATCH", + body: JSON.stringify(toPayload(form)), + }); + if (!res.ok) { + return { ok: false, message: res.message || "保存软件配置失败" }; + } + return { + ok: true, + message: res.message || "软件配置已保存", + data: { form: toForm(res.data), oemId: res.data?.id ?? 1 }, + }; +} diff --git a/src/views/oem/OemOverviewView.vue b/src/views/oem/OemOverviewView.vue index 9c8bf86..c34e2de 100644 --- a/src/views/oem/OemOverviewView.vue +++ b/src/views/oem/OemOverviewView.vue @@ -1,11 +1,11 @@