Files
boursecu_admin/src/pages/menuPages/banners/index.vue
T

209 lines
6.4 KiB
Vue

<template>
<div class="p-4">
<AdminFieldHelp :text="bannersPageIntro" root-class="mb-4 text-xs md:text-sm" />
<BaseButton size="small" type="primary" @click="addRow">
<span>افزودن بنر</span>
<BaseIcon icon="vuesax-linear:add" size="17" />
</BaseButton>
<AdminFieldHelp
text="هر بار «افزودن بنر» یک اسلاید جدید به انتهای لیست اضافه می‌کند."
root-class="mt-2"
/>
<div class="my-4 flex flex-col gap-2">
<div
class="grid max-h-52vh grid-cols-1 gap-4 overflow-y-scroll md:max-h-75vh md:grid-cols-3"
>
<Card v-for="(item, index) in benefitsList" :key="index">
<div class="mt-3 grid grid-cols-1 gap-4">
<div class="my-2 flex items-center justify-between gap-2">
<div class="flex flex-col gap-0.5">
<div class="text-sm font-medium">نسبت تصویر ۱۶:۹</div>
<AdminFieldHelp :text="bannersAspectHelp" />
</div>
<div class="flex shrink-0 flex-col items-end gap-0.5">
<div class="flex items-center gap-2">
<span>نمایش:</span>
<a-switch v-model:checked="item.show" />
</div>
<AdminFieldHelp :text="bannersShowHelp" root-class="text-left" />
</div>
</div>
<div class="text-center">
<AdminFieldHelp :text="bannersImageHelp" root-class="mb-2 text-center" />
<UploadPic
:compressed="true"
@upload="handleUpload($event, index, 'icon')"
@remove="handelRemoveFile(index, 'icon')"
:imageUrl="item.icon"
/>
</div>
</div>
<div class="mt-3 flex flex-col gap-1">
<div class="text-sm font-medium">انتخاب رویداد (پس از کلیک):</div>
<AdminFieldHelp :text="bannersEventHelp" />
<BasicSelect
v-model:value="item.typeClick"
:items="typeList"
value-name="lable"
key-name="value"
/>
<AdminFieldHelp v-if="item.typeClick === 'link'" :text="bannersLinkHelp" />
<AdminFieldHelp v-else-if="item.typeClick === 'modal'" :text="bannersModalHelp" />
<AdminFieldHelp v-else-if="item.typeClick === 'share'" :text="bannersShareHelp" />
<AdminFieldHelp v-else :text="bannersNoEventHelp" />
</div>
<div v-if="item.typeClick == 'link'" class="mt-2 flex flex-col gap-1">
<div class="text-sm font-medium">آدرس لینک</div>
<BasicInput v-model:value="item.link" placeholder="https://..." />
</div>
<div v-if="item.typeClick == 'modal'" class="mt-2 flex flex-col gap-1">
<div class="text-sm font-medium">متن پیام</div>
<QuillEditor
placeholder="متن پیام"
v-model:content="item.modalText"
toolbar="full"
theme="snow"
content-type="html"
class="editor-box2"
/>
</div>
</Card>
</div>
</div>
<div class="mt-5 text-left md:mt-0">
<BaseButton type="primary" @click="handleSubmit">
<span>ذخیره تغییرات</span>
</BaseButton>
<AdminFieldHelp
text="بدون زدن این دکمه، هیچ‌کدام از تغییرات بالا در اپ مشتری دیده نمی‌شود."
root-class="mt-2"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { Card, message } from 'ant-design-vue'
import type { IBenefits } from '@/model/banner'
import UploadPic from '@/components/UploadPic.vue'
import AdminFieldHelp from '@/components/AdminFieldHelp.vue'
import { updateBannerConst, getHeaderBannerConst } from '@/api/consts'
import {
bannersAspectHelp,
bannersEventHelp,
bannersImageHelp,
bannersLinkHelp,
bannersModalHelp,
bannersNoEventHelp,
bannersPageIntro,
bannersShareHelp,
bannersShowHelp,
} from '@/utils/adminHelpCopy'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
import { QuillEditor } from '@vueup/vue-quill'
import { normalizeUploadFileResponse } from '@/utils/file'
const benefitsList = ref<IBenefits[]>([])
let id: number | null = null
const typeList = ref([
{ lable: 'باز شدن لینک', value: 'link' },
{ lable: 'پنجره بازشو', value: 'modal' },
{ lable: 'اشتراک گذاری', value: 'share' },
{ lable: 'بدون رویداد', value: null },
])
function parseBannerList(value: string | null | undefined): IBenefits[] {
if (!value) return []
try {
const parsed = JSON.parse(value)
return Array.isArray(parsed) ? parsed : []
} catch {
return []
}
}
function addRow() {
if (!Array.isArray(benefitsList.value)) {
benefitsList.value = []
}
benefitsList.value.push({
icon: null,
show: true,
caption: null,
link: null,
typeClick: null,
modalText: null,
})
}
function handleUpload(response: unknown, index: number, field: keyof IBenefits) {
const fileResource = normalizeUploadFileResponse(response)
if (!fileResource?.full_src) {
message.error('خطا در ساخت آدرس تصویر')
return
}
benefitsList.value[index][field] = fileResource.full_src
}
function handelRemoveFile(index: number, field: keyof IBenefits) {
benefitsList.value[index][field] = null
}
async function handleSubmit() {
if (!id) {
message.error('شناسه بنر یافت نشد؛ صفحه را رفرش کنید')
return
}
try {
await updateBannerConst({
id,
value: JSON.stringify(benefitsList.value),
key: 'header_banner',
})
message.success('اطلاعات با موفقیت ذخیره شد')
} catch (error) {
message.error('خطا در ذخیره اطلاعات')
}
}
onMounted(async () => {
try {
const res = await getHeaderBannerConst()
if (!res) {
return
}
id = res.id ?? res.const_id ?? null
benefitsList.value = parseBannerList(res.value)
} catch (error) {
console.error('خطا در دریافت بنرها:', error)
}
})
</script>
<style lang="less">
.editor-box2 {
max-height: 40vh;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 8px;
padding: 10px;
}
.editor-box2 .ql-editor {
min-height: 10vh;
overflow-y: auto;
box-sizing: border-box;
}
</style>