Files
Montech_Landing/apps/adm/src/views/SettingsView.vue
T
MahdiandCursor c33a757af4 Sync admin settings and media with the public landing site.
Show logo in the navbar, add image upload fields for logo/team/work/blog/gallery, and drive site chrome from settings everywhere.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-30 22:10:45 +03:30

138 lines
4.6 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<h1>تنظیمات سایت</h1>
<p class="muted">این مقادیر روی هدر، فوتر و کل سایت اعمال می‌شوند.</p>
<form v-if="form" class="card" @submit.prevent="save">
<div class="grid-2">
<div class="field">
<label class="label">نام برند</label>
<input v-model="form.brandName" class="input" />
</div>
<div class="field">
<label class="label">تگ‌لاین</label>
<input v-model="form.tagline" class="input" />
</div>
<div class="field">
<label class="label">ایمیل</label>
<input v-model="form.email" class="input" dir="ltr" />
</div>
<div class="field">
<label class="label">تلفن</label>
<input v-model="form.phone" class="input" dir="ltr" />
</div>
<div class="field">
<label class="label">آدرس</label>
<input v-model="form.address" class="input" />
</div>
<div class="field">
<label class="label">منطقه زمانی</label>
<select v-model="form.timezone" class="input" dir="ltr">
<option value="Asia/Tehran">Asia/Tehran (ایران)</option>
<option value="UTC">UTC</option>
</select>
</div>
</div>
<ImageField
v-model="form.logoUrl"
label="لوگو"
placeholder="/api/uploads/..."
hint="لوگو در هدر سایت نمایش داده می‌شود. اگر خالی باشد نام برند نشان داده می‌شود."
/>
<h2 style="margin: 1.25rem 0 0.75rem; font-size: 1rem">شبکه‌های اجتماعی</h2>
<div v-for="(s, i) in socials" :key="i" class="item-box">
<div class="row" style="justify-content: space-between; margin-bottom: 0.5rem">
<strong>مورد {{ i + 1 }}</strong>
<button type="button" class="btn danger" @click="socials.splice(i, 1)">حذف</button>
</div>
<div class="grid-2">
<div class="field">
<label class="label">نام</label>
<input v-model="s.label" class="input" />
</div>
<div class="field">
<label class="label">لینک</label>
<input v-model="s.url" class="input" dir="ltr" placeholder="https://..." />
</div>
</div>
</div>
<button type="button" class="btn ghost" @click="socials.push({ label: '', url: '' })">+ افزودن</button>
<p v-if="msg" class="muted" style="margin-top: 1rem">{{ msg }}</p>
<button class="btn" style="margin-top: 0.75rem">ذخیره</button>
</form>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { api } from "../lib/api";
import ImageField from "../components/ImageField.vue";
const form = ref<{
brandName: string;
tagline: string;
email: string;
phone: string;
address: string;
timezone: string;
logoUrl: string;
} | null>(null);
const socials = reactive<Array<{ label: string; url: string }>>([]);
const msg = ref("");
onMounted(async () => {
const { data } = await api.get("/admin/settings");
form.value = {
brandName: data.brandName || "",
tagline: data.tagline || "",
email: data.email || "",
phone: data.phone || "",
address: data.address || "",
timezone: data.timezone || "Asia/Tehran",
logoUrl: data.logoUrl || "",
};
socials.splice(0, socials.length, ...(Array.isArray(data.socials) ? data.socials : []));
if (!socials.length) socials.push({ label: "", url: "" });
});
async function save() {
if (!form.value) return;
msg.value = "";
try {
const payload = {
brandName: form.value.brandName,
tagline: form.value.tagline,
email: form.value.email,
phone: form.value.phone,
address: form.value.address,
timezone: form.value.timezone,
logoUrl: form.value.logoUrl || null,
socials: socials.filter((s) => s.label.trim() || s.url.trim()),
};
const { data } = await api.put("/admin/settings", payload);
form.value.logoUrl = data.logoUrl || "";
msg.value = "ذخیره شد. برای دیدن در سایت صفحه را رفرش کنید.";
} catch (e: any) {
const detail = e?.response?.data?.message;
msg.value = Array.isArray(detail)
? `خطا: ${detail.join("، ")}`
: detail
? `خطا: ${detail}`
: "خطا در ذخیره.";
}
}
</script>
<style scoped>
.item-box {
border: 1px solid var(--border);
border-radius: 10px;
padding: 0.9rem;
margin-bottom: 0.9rem;
background: #12151b;
}
</style>