11
This commit is contained in:
113
src/api/oemAppBranding.js
Normal file
113
src/api/oemAppBranding.js
Normal file
@@ -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<typeof emptyBrandingForm>} 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 },
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { useAuthStore } from "../../stores/auth.js";
|
import { useAuthStore } from "../../stores/auth.js";
|
||||||
import AdminImageUpload from "../../components/admin/AdminImageUpload.vue";
|
import AdminImageUpload from "../../components/oem/OemImageUpload.vue";
|
||||||
import {
|
import {
|
||||||
loadAdminAppBrandingApi,
|
loadOemAppBrandingApi,
|
||||||
saveAdminAppBrandingApi,
|
saveOemAppBrandingApi,
|
||||||
} from "../../api/adminAppBranding.js";
|
} from "../../api/oemAppBranding.js";
|
||||||
|
|
||||||
const auth = useAuthStore();
|
const auth = useAuthStore();
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ function onImageError(message) {
|
|||||||
async function loadSettings() {
|
async function loadSettings() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
feedback.value = { severity: "", message: "" };
|
feedback.value = { severity: "", message: "" };
|
||||||
const res = await loadAdminAppBrandingApi(auth.token);
|
const res = await loadOemAppBrandingApi(auth.token);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
@@ -47,7 +47,7 @@ async function loadSettings() {
|
|||||||
async function saveSettings() {
|
async function saveSettings() {
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
feedback.value = { severity: "", message: "" };
|
feedback.value = { severity: "", message: "" };
|
||||||
const res = await saveAdminAppBrandingApi(auth.token, form.value);
|
const res = await saveOemAppBrandingApi(auth.token, form.value);
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
|||||||
Reference in New Issue
Block a user