Files
gsfdc/admin/src/views/edu/index.vue
T

177 lines
5.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-loading="loading" class="flex flex-col gap-4 min-h-40">
<ElTabs v-if="ready" v-model="activeTab" type="border-card">
<ElTabPane label="在线教育" name="platforms">
<div class="flex flex-wrap items-center justify-between gap-3 mb-4">
<p class="m-0 text-sm text-g-600"
>每张卡片一张图,图下是教育网站名称。门户点击后在新窗口打开网址。</p
>
<ElButton v-auth="'edu:edit'" type="primary" :loading="saving" @click="save"
>保存</ElButton
>
</div>
<div class="media-grid">
<article v-for="(item, index) in items" :key="index" class="media-card">
<HomeImageField
:url="item.imageUrl"
:disabled="!canEdit"
@pick="(payload) => assignImage(item, payload)"
@clear="clearImage(item)"
/>
<ElInput
v-model="item.name"
class="mt-3"
:disabled="!canEdit"
placeholder="教育网站名称"
/>
<ElInput v-model="item.url" class="mt-2" :disabled="!canEdit" placeholder="https://" />
<div class="mt-3 flex items-center justify-between gap-2">
<div class="flex items-center gap-2">
<span class="text-sm text-g-600">顺序</span>
<ElInputNumber
v-model="item.sortOrder"
:min="0"
:disabled="!canEdit"
controls-position="right"
/>
</div>
<ElButton v-if="canEdit" link type="danger" @click="items.splice(index, 1)"
>删除</ElButton
>
</div>
</article>
<button v-if="canEdit" type="button" class="media-add" @click="addItem">
<span>添加教育网站</span>
</button>
</div>
</ElTabPane>
<ElTabPane label="教育公告" name="notices">
<AboutColumnEditor
v-if="activeTab === 'notices'"
category="edu_notices"
title="教育公告"
edit-auth="edu:edit"
enable-cover
/>
</ElTabPane>
<ElTabPane label="协会教育" name="association">
<AssociationEducation v-if="activeTab === 'association'" />
</ElTabPane>
</ElTabs>
</div>
</template>
<script setup lang="ts">
import AssociationEducation from './components/AssociationEducation.vue'
import AboutColumnEditor from '@/views/about/components/AboutColumnEditor.vue'
import { fetchEduPlatforms, saveEduPlatforms } from '@/api/home'
import { useAuth } from '@/hooks/core/useAuth'
import HomeImageField from '@/views/home/components/HomeImageField.vue'
defineOptions({ name: 'ContinuingEducation' })
interface PlatformItem {
name: string
url: string
imageFileId: number | null
imageUrl: string
sortOrder: number
}
const { hasAuth } = useAuth()
const canEdit = computed(() => hasAuth('edu:edit'))
const activeTab = ref('platforms')
const loading = ref(false)
const ready = ref(false)
const saving = ref(false)
const items = ref<PlatformItem[]>([])
const load = async () => {
loading.value = true
try {
const data = await fetchEduPlatforms()
items.value = (data.items || []).map((item) => ({
name: item.name || '',
url: item.url || '',
imageFileId: item.imageFileId ?? null,
imageUrl: item.imageUrl || '',
sortOrder: item.sortOrder ?? 0
}))
ready.value = true
} finally {
loading.value = false
}
}
const assignImage = (item: PlatformItem, payload: { id: number; url: string }) => {
item.imageFileId = payload.id
item.imageUrl = payload.url
}
const clearImage = (item: PlatformItem) => {
item.imageFileId = null
item.imageUrl = ''
}
const addItem = () => {
items.value.push({
name: '',
url: '',
imageFileId: null,
imageUrl: '',
sortOrder: items.value.length + 1
})
}
const save = async () => {
if (items.value.some((item) => !item.name.trim() || !item.url.trim() || !item.imageFileId)) {
ElMessage.warning('每条在线教育都需要名称、网址和图片,或删除未完成的条目')
return
}
saving.value = true
try {
await saveEduPlatforms({
items: items.value.map((item) => ({
name: item.name.trim(),
url: item.url.trim(),
imageFileId: item.imageFileId,
sortOrder: item.sortOrder
}))
})
ElMessage.success('已保存')
await load()
} finally {
saving.value = false
}
}
onMounted(load)
</script>
<style scoped>
.media-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 12px;
}
.media-card,
.media-add {
padding: 14px;
border: 1px solid var(--el-border-color);
border-radius: 10px;
background: var(--el-bg-color);
}
.media-add {
display: flex;
align-items: center;
justify-content: center;
min-height: 168px;
border-style: dashed;
color: var(--el-color-primary);
cursor: pointer;
background: var(--el-fill-color-lighter);
}
</style>