2026-09-30 18:42:28 +03:30
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
2026-10-01 20:36:06 +03:30
|
|
|
|
<div class="page-header">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h1>محتوای لندینگ</h1>
|
|
|
|
|
|
<p>هر بخش صفحه اصلی را مثل یک فرم ساده ویرایش کنید.</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<a-button href="/" target="_blank">
|
|
|
|
|
|
<template #icon><GlobalOutlined /></template>
|
|
|
|
|
|
مشاهده لندینگ
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<a-row :gutter="[16, 16]">
|
|
|
|
|
|
<a-col v-for="s in rows" :key="s.key" :xs="24" :md="12" :xl="8">
|
|
|
|
|
|
<a-card hoverable class="section-card" @click="router.push(`/sections/${s.key}`)">
|
|
|
|
|
|
<a-card-meta :title="SECTION_TITLES_FA[s.key]" :description="SECTION_SCHEMAS[s.key].description" />
|
|
|
|
|
|
<div class="meta">
|
|
|
|
|
|
<a-tag v-if="s.isDefault" color="default">محتوای پیشفرض</a-tag>
|
|
|
|
|
|
<a-tag v-else color="blue">سفارشیشده</a-tag>
|
|
|
|
|
|
<a-typography-text v-if="s.updatedAt && !s.isDefault" type="secondary">
|
|
|
|
|
|
{{ new Date(s.updatedAt).toLocaleString("fa-IR") }}
|
|
|
|
|
|
</a-typography-text>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-card>
|
|
|
|
|
|
</a-col>
|
|
|
|
|
|
</a-row>
|
|
|
|
|
|
<a-skeleton v-if="loading" active />
|
2026-09-30 18:42:28 +03:30
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { onMounted, ref } from "vue";
|
2026-10-01 20:36:06 +03:30
|
|
|
|
import { useRouter } from "vue-router";
|
|
|
|
|
|
import { message } from "ant-design-vue";
|
|
|
|
|
|
import { GlobalOutlined } from "@ant-design/icons-vue";
|
|
|
|
|
|
import { SECTION_KEYS, SECTION_TITLES_FA, type SectionKey } from "@montech/shared";
|
|
|
|
|
|
import { SECTION_SCHEMAS } from "../sections/schema";
|
|
|
|
|
|
import { api, apiErrorMessage } from "../lib/api";
|
2026-09-30 18:42:28 +03:30
|
|
|
|
|
2026-10-01 20:36:06 +03:30
|
|
|
|
interface SectionRow {
|
|
|
|
|
|
key: SectionKey;
|
|
|
|
|
|
updatedAt: string | null;
|
|
|
|
|
|
isDefault: boolean;
|
2026-09-30 20:33:37 +03:30
|
|
|
|
}
|
2026-10-01 20:36:06 +03:30
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const rows = ref<SectionRow[]>([]);
|
|
|
|
|
|
const loading = ref(true);
|
|
|
|
|
|
|
2026-09-30 18:42:28 +03:30
|
|
|
|
onMounted(async () => {
|
2026-10-01 20:36:06 +03:30
|
|
|
|
try {
|
|
|
|
|
|
const { data } = await api.get<SectionRow[]>("/admin/sections");
|
|
|
|
|
|
const byKey = new Map(data.map((s) => [s.key, s]));
|
|
|
|
|
|
rows.value = SECTION_KEYS.map((key) => byKey.get(key) ?? { key, updatedAt: null, isDefault: true });
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
message.error(apiErrorMessage(e));
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
}
|
2026-09-30 18:42:28 +03:30
|
|
|
|
});
|
|
|
|
|
|
</script>
|
2026-10-01 20:36:06 +03:30
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.section-card {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.meta {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|