<script setup lang="ts">
|
import type { MenuRecordRaw } from '@vben/types';
|
import type { ResearchApplicationApi } from '#/api/research/application';
|
import { onMounted, ref } from 'vue';
|
import { IconifyIcon } from '@vben/icons';
|
import { useRouter } from 'vue-router';
|
import { usePortalMenus } from '#/components/portal/use-portal-menus';
|
import { getApplicationPage } from '#/api/research/application';
|
|
const props = defineProps<{ menu: MenuRecordRaw }>();
|
const { goMenu } = usePortalMenus();
|
const router = useRouter();
|
const loading = ref(true);
|
const failed = ref(false);
|
const applications = ref<ResearchApplicationApi.Application[]>([]);
|
async function load() {
|
loading.value = true; failed.value = false;
|
try { const result = await getApplicationPage({ pageNo: 1, pageSize: 6 }); applications.value = result.list ?? []; }
|
catch { failed.value = true; applications.value = []; }
|
finally { loading.value = false; }
|
}
|
function openApplication(item: ResearchApplicationApi.Application) {
|
if (item.id && router.hasRoute('ResearchApplicationDetail')) router.push({ name: 'ResearchApplicationDetail', query: { id: item.id } });
|
else goMenu(props.menu);
|
}
|
onMounted(load);
|
</script>
|
|
<template>
|
<article class="portal-research-panel">
|
<div class="research-heading"><h2><IconifyIcon icon="lucide:newspaper" />课题动态</h2><button type="button" @click="goMenu(menu)">更多 <IconifyIcon icon="lucide:chevron-right" /></button></div>
|
<div class="research-content">
|
<button class="research-feature" type="button" @click="goMenu(menu)"><span>课题研究与申报服务</span><small>查看课题申报 <IconifyIcon icon="lucide:arrow-right" /></small></button>
|
<div class="research-list-area">
|
<div v-if="loading" class="research-status" role="status">正在加载课题动态…</div>
|
<div v-else-if="failed" class="research-status" role="status"><span>课题动态加载失败</span><button type="button" @click="load">重新加载</button></div>
|
<div v-else-if="!applications.length" class="research-status"><IconifyIcon icon="lucide:files" /><span>暂无课题申报记录</span><button type="button" @click="goMenu(menu)">进入课题申报</button></div>
|
<ul v-else><li v-for="item in applications" :key="item.id ?? item.no"><button type="button" @click="openApplication(item)"><span>{{ item.title }}</span><time>{{ (item.createTime || '').slice(0, 10) }}</time></button></li></ul>
|
</div>
|
</div>
|
</article>
|
</template>
|
|
<style scoped>
|
.portal-research-panel { min-width: 0; padding: 18px; border: 1px solid #e1ebf5; border-radius: 6px; background: #fff; box-shadow: 0 3px 10px rgb(24 66 106 / 4%); }
|
.research-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 17px; }.research-heading h2 { display: flex; align-items: center; gap: 10px; margin: 0; color: #153a62; font-size: 17px; font-weight: 700; }.research-heading h2 :deep(svg) { width: 19px; color: #bf222b; }.research-heading > button { display: inline-flex; align-items: center; gap: 2px; color: #5c7187; font-size: 11px; }
|
.research-content { display: grid; grid-template-columns: minmax(180px, .95fr) minmax(0, 1.1fr); gap: 20px; min-height: 234px; }.research-feature { position: relative; display: flex; min-height: 234px; flex-direction: column; align-items: flex-start; justify-content: flex-end; overflow: hidden; padding: 17px 16px; border-radius: 5px; color: #fff; background: url('/static/imgs/portal-modules-v2.png') left top / 200% 200%; text-align: left; }.research-feature::before { position: absolute; inset: 0; background: linear-gradient(transparent 35%, rgb(10 34 58 / 90%)); content: ''; }.research-feature span { position: relative; font-size: 16px; font-weight: 650; }.research-feature small { position: relative; display: flex; align-items: center; gap: 8px; margin-top: 9px; color: #e5f0fc; font-size: 11px; }.research-feature small :deep(svg) { width: 14px; }
|
.research-list-area { min-width: 0; }.research-status { display: flex; min-height: 230px; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: #5c7187; font-size: 13px; }.research-status > :deep(svg) { width: 32px; height: 32px; color: #b6c9dc; }.research-status button { min-height: 30px; padding: 4px 12px; border: 1px solid #d8e5f3; border-radius: 4px; color: #2b6094; background: #f6faff; font-size: 11px; }
|
ul { margin: 0; padding: 0; list-style: none; }li + li { border-top: 1px solid #eef3f8; }li button { display: flex; width: 100%; min-height: 39px; align-items: center; gap: 12px; color: #315273; text-align: left; }li span { min-width: 0; flex: 1; overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }li time { flex: none; color: #5c7187; font-size: 10px; }button { cursor: pointer; }button:focus-visible { outline: 2px solid #2c70b2; outline-offset: 3px; }li button:hover { color: #b7242d; }
|
@media (max-width: 1050px) { .research-content { grid-template-columns: minmax(150px, .85fr) minmax(0, 1fr); gap: 12px; }li time { display: none; } }
|
@media (max-width: 520px) { .research-content { grid-template-columns: 1fr; gap: 12px; }.research-feature { min-height: 180px; background-size: 200% 280%; }.research-status { min-height: 125px; }li time { display: block; } }
|
</style>
|