Adds consultation leads, section editors, and the one-time content reset for this release. Co-authored-by: Cursor <cursoragent@cursor.com>
75 lines
2.2 KiB
Vue
75 lines
2.2 KiB
Vue
<template>
|
||
<div>
|
||
<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 />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { onMounted, ref } from "vue";
|
||
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";
|
||
|
||
interface SectionRow {
|
||
key: SectionKey;
|
||
updatedAt: string | null;
|
||
isDefault: boolean;
|
||
}
|
||
|
||
const router = useRouter();
|
||
const rows = ref<SectionRow[]>([]);
|
||
const loading = ref(true);
|
||
|
||
onMounted(async () => {
|
||
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;
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.section-card {
|
||
height: 100%;
|
||
}
|
||
.meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin-top: 14px;
|
||
}
|
||
</style>
|