Compare commits

...

3 Commits

Author SHA1 Message Date
yuanshan
60d228c3d8 fix contacts 768 2025-10-11 10:55:18 +08:00
yuanshan
000b23f4a8 fix events-calendar 768 2025-10-11 10:40:57 +08:00
yuanshan
51d2364e38 fix press-releases 768 2025-10-11 09:20:54 +08:00
7 changed files with 984 additions and 206 deletions

View File

@ -74,7 +74,7 @@ function copyEmail() {
gap: 4px; gap: 4px;
background-color: white; background-color: white;
border-radius: 1rem; border-radius: 1rem;
background-image: url("@/assets/image/1920/contacts-bg.png"); background-image: url("@/assets/image/1440/contacts-bg.png");
background-size: 64% auto; background-size: 64% auto;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;

View File

@ -1,67 +1,148 @@
<script setup> <script setup>
import { NCarousel, NDivider, NMarquee, NPopselect } from "naive-ui";
import { onUnmounted, ref, watch, onMounted, computed } from "vue"; import { onUnmounted, ref, watch, onMounted, computed } from "vue";
function copyEmail() { function copyEmail() {
navigator.clipboard.writeText("fiee@dlkadvisory.com"); navigator.clipboard.writeText("fiee@dlkadvisory.com");
} }
</script> </script>
<template> <template>
<main <div class="contact-container">
ref="main" <!-- Title Section -->
class="flex flex-col items-center from-primary to-accent w-[100vw] mt-12 animate-fade-in px-6 py-10 pt-500px" <div class="title-section">
> <div class="title-decoration"></div>
<div class="w-full flex flex-col items-center gap-5 px-4"> <div class="contact-title">Investor Contacts</div>
<h1
class="text-3xl font-bold text-primary animate-fade-in-down animate-delay-0"
>
Investor Contacts
</h1>
<div
class="text-xl font-semibold text-gray-800 animate-fade-in-down animate-delay-200"
>
FiEE Inc.
</div> </div>
<div class="text-lg text-#ff7bac animate-fade-in-down animate-delay-400">
Investor Relations <!-- Card Section -->
</div> <div class="contact-card">
<div <div class="logo-text">FiEE Inc.</div>
class="text-base text-gray-600 flex items-center gap-2 animate-fade-in-down animate-delay-600" <div class="relation-text">Investor Relations</div>
> <div class="email-section">
<span>Email:</span> <span>Email:</span>
<span <span class="email-address" @click="copyEmail"
class="transition-colors duration-300 cursor-pointer text-#00baff hover:text-primary active:text-secondary select-all"
@click="copyEmail"
>fiee@dlkadvisory.com</span >fiee@dlkadvisory.com</span
> >
</div> </div>
</div> </div>
</main> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.contact-container {
width: 650 * 2.5px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
}
.title-section {
width: 100%;
display: flex;
flex-direction: column;
gap: 16 * 2.5px;
padding: 0 16 * 2.5px;
margin-bottom: 32 * 2.5px;
}
.title-decoration {
width: 58 * 2.5px;
height: 7 * 2.5px;
background: #ff7bac;
margin: auto 0;
margin-top: 43 * 2.5px;
}
.contact-title {
font-family: "PingFang SC", sans-serif;
font-weight: 500;
font-size: 32 * 2.5px;
line-height: 1.4em;
letter-spacing: 0.03em;
color: #000000;
}
.contact-card {
display: flex;
width: 100%;
height: 511 * 2.5px;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 4px;
background-color: white;
border-radius: 1rem;
background-image: url("@/assets/image/768/contacts-bg.png");
background-size: 64% auto;
background-position: center;
background-repeat: no-repeat;
box-shadow: 0px 3 * 2.5px 14 * 2.5px 0px rgba(0, 0, 0, 0.16);
animation: fade-in 0.8s cubic-bezier(0.23, 1, 0.32, 1) both;
}
.logo-text {
width: 100%;
text-align: center;
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 110 * 2.5px;
font-style: normal;
font-weight: 600;
line-height: normal;
letter-spacing: 0.48 * 2.5px;
background: linear-gradient(90deg, #ff7bac 0%, #0ff 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
animation: fade-in-down 0.8s cubic-bezier(0.23, 1, 0.32, 1) both;
animation-delay: 0.2s;
}
.relation-text {
font-family: "PingFang SC", sans-serif;
font-size: 24 * 2.5px;
color: #000000;
font-weight: 600;
animation: fade-in-down 0.8s cubic-bezier(0.23, 1, 0.32, 1) both;
animation-delay: 0.4s;
}
.email-section {
font-size: 18 * 2.5px;
color: #4a5568;
display: flex;
align-items: center;
gap: 8 * 2.5px;
animation: fade-in-down 0.8s cubic-bezier(0.23, 1, 0.32, 1) both;
animation-delay: 0.6s;
margin-top: 16 * 2.5px;
}
.email-address {
color: #ff7bac;
cursor: pointer;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-in-down { @keyframes fade-in-down {
0% { 0% {
opacity: 0; opacity: 0;
transform: translateY(-20px); transform: translateY(-20 * 2.5px);
} }
100% { 100% {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
} }
} }
.animate-fade-in-down {
animation: fade-in-down 0.8s cubic-bezier(0.23, 1, 0.32, 1) both;
}
.animate-delay-0 {
animation-delay: 0s;
}
.animate-delay-200 {
animation-delay: 0.2s;
}
.animate-delay-400 {
animation-delay: 0.4s;
}
.animate-delay-600 {
animation-delay: 0.6s;
}
</style> </style>

View File

@ -245,7 +245,7 @@ async function handleSubmit(e) {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-image: url("@/assets/image/1920/email-alerts-submit.png"); background-image: url("@/assets/image/1440/email-alerts-submit.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: bottom; background-position: bottom;
background-size: 100%; background-size: 100%;

View File

@ -5,7 +5,7 @@
</template> </template>
<script setup> <script setup>
import size375 from "@/views/events-calendar/size375/index.vue"; import size375 from "@/views/events-calendar/size375/index.vue";
import size768 from "@/views/events-calendar/size375/index.vue"; import size768 from "@/views/events-calendar/size768/index.vue";
import size1440 from "@/views/events-calendar/size1440/index.vue"; import size1440 from "@/views/events-calendar/size1440/index.vue";
import size1920 from "@/views/events-calendar/size1920/index.vue"; import size1920 from "@/views/events-calendar/size1920/index.vue";
import { computed } from "vue"; import { computed } from "vue";

View File

@ -79,7 +79,7 @@
<!-- 背景图片区域 --> <!-- 背景图片区域 -->
<div class="background-image-container"> <div class="background-image-container">
<img <img
src="@/assets/image/1920/events-calendar-bg.png" src="@/assets/image/1440/events-calendar-bg.png"
alt="Events Calendar Background" alt="Events Calendar Background"
class="background-image" class="background-image"
/> />

View File

@ -0,0 +1,218 @@
<template>
<div class="events-calendar-page">
<main class="page-container">
<div class="events-container">
<!-- 标题区域 -->
<div class="title-section">
<div class="title-decoration"></div>
<div class="events-title">
{{ t("events_calendar.title") }}
</div>
</div>
<!-- 搜索区域 -->
<div class="search-container">
<div class="date-picker-wrapper">
<n-date-picker
v-model:value="state.selectedDateValue"
type="date"
class="search-date-picker"
placeholder="Select Date"
>
<template #prefix>
<svg
class="calendar-icon"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
>
<g clip-path="url(#clip0_134_3094)">
<path
d="M17.5 3.33398H2.5C2.08333 3.33398 1.66667 3.66732 1.66667 4.08398V17.5007C1.66667 17.9173 2.08333 18.2507 2.5 18.2507H17.5C17.9167 18.2507 18.3333 17.9173 18.3333 17.5007V4.08398C18.3333 3.66732 17.9167 3.33398 17.5 3.33398Z"
stroke="#78777B"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M13.3333 1.66602V5.00018"
stroke="#78777B"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M6.66669 1.66602V5.00018"
stroke="#78777B"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M1.66669 8.33398H18.3334"
stroke="#78777B"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</g>
<defs>
<clipPath id="clip0_134_3094">
<rect
width="20"
height="20"
fill="white"
transform="translate(0 0.000976562)"
></rect>
</clipPath>
</defs>
</svg>
</template>
</n-date-picker>
</div>
<button @click="handleSearch" class="search-button">
{{ t("events_calendar.search.button") }}
</button>
</div>
<!-- 背景图片区域 -->
<div class="background-image-container">
<img
src="@/assets/image/768/events-calendar-bg.png"
alt="Events Calendar Background"
class="background-image"
/>
</div>
</div>
</main>
</div>
</template>
<script setup>
import { reactive } from "vue";
import { NDatePicker, NButton } from "naive-ui";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const state = reactive({
selectedDateValue: null, //
});
const handleSearch = () => {
//
// console.log(':', state.selectedDateValue)
};
</script>
<style scoped lang="scss">
.page-container {
background-size: 100% 100%;
background-position: center;
background-repeat: no-repeat;
}
.events-container {
width: 650 * 2.5px;
margin: 0 auto;
}
.title-section {
display: flex;
flex-direction: column;
gap: 16 * 2.5px;
margin-bottom: 32 * 2.5px;
padding: 0 16 * 2.5px;
}
.title-decoration {
width: 58 * 2.5px;
height: 7 * 2.5px;
background: #ff7bac;
margin: auto 0;
margin-top: 43 * 2.5px;
}
.events-title {
font-family: "PingFang SC", sans-serif;
font-weight: 500;
font-size: 32 * 2.5px;
line-height: 1.4em;
letter-spacing: 0.03em;
color: #000000;
}
.search-container {
margin-bottom: 20 * 2.5px;
display: flex;
align-items: center;
gap: 16 * 2.5px;
padding: 0 16 * 2.5px;
}
.date-picker-wrapper {
flex: 1;
position: relative;
}
.search-date-picker {
width: 100%;
}
:deep(.n-input) {
height: 34 * 2.5px;
border-radius: 3 * 2.5px;
border: 1 * 2.5px solid #e0e0e6;
&:hover {
border-color: #ff7bac;
}
}
:deep(.n-input--focus) {
border-color: #ff7bac;
box-shadow: 0 0 0 2px rgba(255, 123, 172, 0.2);
}
.calendar-icon {
margin-left: 12 * 2.5px;
}
.search-button {
height: 34 * 2.5px;
padding: 7 * 2.5px 12 * 2.5px;
color: #fff;
background-color: #ff7bac;
border: none;
border-radius: 3 * 2.5px;
cursor: pointer;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.03em;
min-width: 160 * 2.5px;
&:hover {
background-color: #e66f9a;
}
}
.background-image-container {
background: #fff;
width: 100%;
height: 511 * 2.5px;
margin-top: 20 * 2.5px;
box-shadow: 0px 3px 14px 0px rgba(0, 0, 0, 0.16);
border-radius: 16 * 2.5px;
display: flex;
justify-content: center;
align-items: center;
}
.background-image {
width: 300 * 2.5px;
height: 170 * 2.5px;
flex-shrink: 0;
aspect-ratio: 83/47;
}
</style>

View File

@ -1,35 +1,45 @@
<template> <template>
<div class="press-releases-page"> <div class="press-releases-page">
<n-infinite-scroll :distance="0" @load="doLoadMore"> <main class="mx-auto">
<main class="p-[35px] mx-auto" style="max-width: calc(100% - 100px)"> <div class="title-section">
<div class="title mb-[20px]"> <div class="title-decoration"></div>
<div class="title">
{{ t("press_releases.title") }} {{ t("press_releases.title") }}
</div> </div>
</div>
<div class="search-container"> <div class="search-container">
<n-select <n-select
:options="state.selectOptions" :options="state.selectOptions"
v-model:value="state.selectedValue" v-model:value="state.selectedValue"
class="search-select" class="search-select"
/> />
<n-input <input
v-model:value="state.inputValue" v-model="state.inputValue"
type="text" type="text"
:placeholder="t('press_releases.search.placeholder')" :placeholder="t('press_releases.search.placeholder')"
class="search-input" class="search-input"
/> />
<n-button @click="handleSearch" class="search-button w-[120px]"> <button @click="handleSearch" class="search-button">
{{ t("press_releases.search.button") }} {{ t("press_releases.search.button") }}
</n-button> </button>
</div> </div>
<div v-for="(item, idx) in state.filterNewsData" :key="idx"> <div class="reports-list">
<div class="news-item mt-[10px]">
<div class="news-item-date">{{ item.date }}</div>
<div <div
class="news-item-title text-[#0078d7] cursor-pointer" v-for="(item, idx) in state.filterNewsData"
:key="idx"
class="news-item table-row"
>
<div class="content">
<div class="file-content">
<div class="file-info">
<div class="vertical-line"></div>
<div
class="news-item-title text-[#000] cursor-pointer"
style=" style="
word-break: break-word; word-break: break-all;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 1;
line-clamp: 1;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -38,19 +48,34 @@
> >
{{ item.title }} {{ item.title }}
</div> </div>
<n-tooltip <svg
trigger="click" class="arrow-icon"
:disabled="!item.showTooltip" width="7"
width="trigger" height="14"
viewBox="0 0 7 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
@click="handleNewClick(item)"
> >
<path
d="M1 1L6 7L1 13"
stroke="#FF7BAC"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<n-tooltip trigger="hover" :disabled="true" width="trigger">
<template #trigger> <template #trigger>
<div <div
:ref="(el) => setTitleRef(el, idx)" :ref="(el) => setTitleRef(el, idx)"
class="news-item-content" class="news-item-content file-description"
style=" style="
word-break: break-word; word-break: break-all;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -63,17 +88,119 @@
{{ item.summary }} {{ item.summary }}
</div> </div>
</n-tooltip> </n-tooltip>
<div class="download-section">
<div class="news-item-date">{{ item.date }}</div>
</div> </div>
</div> </div>
</div>
<div class="separator-line"></div>
</div>
</div>
<!-- 分页器 -->
<div class="pagination-container" v-if="state.total > 0">
<div class="pagination-controls">
<div class="pagination-buttons">
<button
class="page-btn prev-btn"
:disabled="state.currentPage === 1"
@click="goToPrevPage"
>
<svg width="5" height="9" viewBox="0 0 5 9" fill="none">
<path
d="M4 1L1 4.5L4 8"
stroke="#455363"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<template v-for="page in getVisiblePages()" :key="page">
<button
v-if="page !== '...'"
class="page-btn"
:class="{ active: page === state.currentPage }"
@click="goToPage(page)"
>
{{ page }}
</button>
<button v-else class="page-btn disabled" disabled>...</button>
</template>
<button
class="page-btn next-btn"
:disabled="state.currentPage === totalPages"
@click="goToNextPage"
>
<svg width="5" height="9" viewBox="0 0 5 9" fill="none">
<path
d="M1 1L4 5L1 8"
stroke="#455363"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
<div class="page-size-selector" @click="togglePageSizeMenu">
<span>{{ state.pageSize }}/page</span>
<svg width="10" height="5" viewBox="0 0 10 5" fill="none">
<path
d="M1 1L5 4L9 1"
stroke="#455363"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<div v-if="showPageSizeMenu" class="page-size-menu">
<div
v-for="size in [10, 20, 50]"
:key="size"
class="page-size-option"
:class="{ active: state.pageSize === size }"
@click="changePageSize(size)"
>
{{ size }}/page
</div>
</div>
</div>
<div class="goto-section">
<span>Goto</span>
<input
type="number"
v-model="state.gotoPage"
class="goto-input"
:min="1"
:max="totalPages"
@keyup.enter="handleGoto"
/>
</div>
</div>
</div>
<div class="pagination-info" v-if="state.total > 0">
Displaying {{ displayRange.start }} - {{ displayRange.end }} of
{{ state.total }} results
</div>
</main> </main>
</n-infinite-scroll>
</div> </div>
</template> </template>
<script setup> <script setup>
import customDefaultPage from "@/components/customDefaultPage/index.vue"; import customDefaultPage from "@/components/customDefaultPage/index.vue";
import { reactive, onMounted, watch, nextTick, ref } from "vue"; import {
import { NSelect, NInput, NButton, NInfiniteScroll, NTooltip } from "naive-ui"; reactive,
onMounted,
watch,
nextTick,
ref,
computed,
onUnmounted,
} from "vue";
import { NSelect, NInput, NButton, NTooltip } from "naive-ui";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import axios from "axios"; import axios from "axios";
@ -94,32 +221,16 @@ const state = reactive({
}), }),
], // ], //
inputValue: "", // inputValue: "", //
newsData: [
{
date: "June 3, 2025",
title: "FiEE, Inc. seized market opportunities through 2025 Osaka Expo",
content:
"Hong Kong, 3 June 2025 — FiEE, Inc. (NASDAQ:FIEE) (“FiEE, Inc.” or the “Company”), a technology company integrating IoT, connectivity and AI to redefine brand management solutions in the digital era, is pleased to announce significant business updates....",
},
{
date: "June 2, 2025",
title: "FiEE, Inc. Closes Its First Day of Trading on NASDAQ",
content:
"Hong Kong, 2 June 2025 — FiEE, Inc. (NASDAQ:FIEE) (“FiEE, Inc.” or the “Company”), a technology company integrating IoT, connectivity and AI to redefine brand management solutions in the digital era, commenced...",
},
{
date: "May 30, 2025",
title: "FiEE, Inc. Announces Reinitiation of Trading on Nasdaq",
content:
"Hong Kong, May 30, 2025 — FiEE, Inc. (“FiEE, Inc.” or the “Company”), a technology company integrating IoT, connectivity and AI to redefine brand management solutions...",
},
],
filterNewsData: [], filterNewsData: [],
loading: false, // loading: false, //
hasMore: true, //
currentPage: 1, // currentPage: 1, //
pageSize: 10,
total: 0,
gotoPage: 1,
}); });
const showPageSizeMenu = ref(false);
const titleRefs = ref([]); const titleRefs = ref([]);
const setTitleRef = (el, idx) => { const setTitleRef = (el, idx) => {
@ -139,14 +250,18 @@ const checkAllTitleOverflow = () => {
}; };
onMounted(() => { onMounted(() => {
// state.filterNewsData = state.newsData;
getPressReleasesDisplay(); getPressReleasesDisplay();
document.addEventListener("click", handleClickOutside);
nextTick(() => { nextTick(() => {
checkAllTitleOverflow(); checkAllTitleOverflow();
}); });
}); });
onUnmounted(() => {
document.removeEventListener("click", handleClickOutside);
});
watch( watch(
() => state.filterNewsData, () => state.filterNewsData,
() => { () => {
@ -159,20 +274,21 @@ watch(
// //
const getPressReleasesDisplay = () => { const getPressReleasesDisplay = () => {
state.loading = true;
let url = "https://erpapi.fiee.com/api/fiee/pressreleases/display"; let url = "https://erpapi.fiee.com/api/fiee/pressreleases/display";
let params = { let params = {
query: state.inputValue, query: state.inputValue,
page: state.currentPage, page: state.currentPage,
pageSize: 10, pageSize: state.pageSize,
timeStart: state.selectedValue timeStart: state.selectedValue
? state.selectedValue === "all_years" ? state.selectedValue === "all_years"
? null ? null
: new Date(state.selectedValue).getTime() : new Date(state.selectedValue).getTime()
: null, : null,
}; };
// console.log(params) axios
axios.post(url, params).then((res) => { .post(url, params)
// console.log(res) .then((res) => {
if (res.status === 200) { if (res.status === 200) {
if (res.data.status === 0) { if (res.data.status === 0) {
res.data.data?.data?.forEach((item) => { res.data.data?.data?.forEach((item) => {
@ -182,70 +298,44 @@ const getPressReleasesDisplay = () => {
year: "numeric", year: "numeric",
}); });
}); });
if (state.currentPage === 1) {
state.filterNewsData = res.data.data?.data || []; state.filterNewsData = res.data.data?.data || [];
} else { state.total = res.data.data?.total || 0;
state.filterNewsData = [
...state.filterNewsData,
...(res.data.data?.data || []),
];
}
if (state.filterNewsData.length < (res.data.data?.total || 0)) {
state.hasMore = true;
} else {
state.hasMore = false;
}
} }
} }
})
.finally(() => {
state.loading = false;
}); });
}; };
const handleFilter = () => {
//
let filteredData = [...state.newsData];
//
if (state.selectedValue !== "all_years") {
filteredData = filteredData.filter((item) => {
// "May 30, 2025"
const dateMatch = item.date.match(/\b\d{4}\b/);
if (dateMatch) {
const year = dateMatch[0];
return year === state.selectedValue;
}
return false;
});
}
// title content
if (state.inputValue && state.inputValue.trim() !== "") {
const searchText = state.inputValue.toLowerCase().trim();
filteredData = filteredData.filter((item) => {
const titleMatch = item.title.toLowerCase().includes(searchText);
const contentMatch = item.content.toLowerCase().includes(searchText);
return titleMatch || contentMatch;
});
}
state.filterNewsData = filteredData;
};
// watcher // watcher
watch( watch(
() => [state.selectedValue, state.inputValue], () => [state.selectedValue, state.inputValue],
() => { () => {
// handleFilter();
state.currentPage = 1; state.currentPage = 1;
getPressReleasesDisplay(); getPressReleasesDisplay();
} }
); );
const handleSearch = () => { watch(
// () => state.pageSize,
// handleFilter(); () => {
state.currentPage = 1;
getPressReleasesDisplay();
}
);
watch(
() => state.currentPage,
(newPage) => {
state.gotoPage = newPage;
getPressReleasesDisplay();
}
);
const handleSearch = () => {
state.currentPage = 1; state.currentPage = 1;
getPressReleasesDisplay(); getPressReleasesDisplay();
// console.log(":", state.filterNewsData);
}; };
const handleNewClick = (item) => { const handleNewClick = (item) => {
@ -257,72 +347,461 @@ const handleNewClick = (item) => {
}); });
}; };
// const totalPages = computed(() => {
const doLoadMore = () => { return Math.ceil(state.total / state.pageSize) || 1;
if (!state.hasMore || state.loading) { });
return;
const displayRange = computed(() => {
if (state.total === 0) return { start: 0, end: 0 };
const start = (state.currentPage - 1) * state.pageSize + 1;
const end = Math.min(state.currentPage * state.pageSize, state.total);
return { start, end };
});
const goToPage = (page) => {
if (page >= 1 && page <= totalPages.value) {
state.currentPage = page;
} }
// console.log('') };
state.loading = true;
const goToPrevPage = () => {
if (state.currentPage > 1) {
state.currentPage--;
}
};
const goToNextPage = () => {
if (state.currentPage < totalPages.value) {
state.currentPage++; state.currentPage++;
getPressReleasesDisplay().finally(() => { }
state.loading = false; };
});
const changePageSize = (size) => {
state.pageSize = size;
};
const handleGoto = () => {
const page = parseInt(state.gotoPage);
if (page >= 1 && page <= totalPages.value) {
state.currentPage = page;
}
};
const togglePageSizeMenu = () => {
showPageSizeMenu.value = !showPageSizeMenu.value;
};
const getVisiblePages = () => {
const current = state.currentPage;
const total = totalPages.value;
const pages = [];
if (total <= 7) {
for (let i = 1; i <= total; i++) {
pages.push(i);
}
} else {
pages.push(1);
if (current <= 4) {
for (let i = 2; i <= 5; i++) {
pages.push(i);
}
pages.push("...");
pages.push(total);
} else if (current >= total - 3) {
pages.push("...");
for (let i = total - 4; i <= total; i++) {
pages.push(i);
}
} else {
pages.push("...");
for (let i = current - 1; i <= current + 1; i++) {
pages.push(i);
}
pages.push("...");
pages.push(total);
}
}
return pages;
};
//
const handleClickOutside = (event) => {
if (!event.target.closest || !event.target.closest(".page-size-selector")) {
showPageSizeMenu.value = false;
}
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.press-releases-page {
width: 650 * 2.5px;
margin: 0 auto;
}
.title-section {
display: flex;
flex-direction: column;
gap: 16 * 2.5px;
padding: 0 16 * 2.5px;
}
.title-decoration {
width: 58 * 2.5px;
height: 7 * 2.5px;
background: #ff7bac;
margin: auto 0;
margin-top: 43 * 2.5px;
}
.title { .title {
font-size: 63px; font-size: 32 * 2.5px;
color: #333; color: #000;
} }
.search-container { .search-container {
margin-bottom: 20px; margin-bottom: 20 * 2.5px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
gap: 25px; gap: 16 * 2.5px;
padding: 0 16 * 2.5px;
} }
.search-select { .search-select {
width: 360px; width: 134 * 2.5px;
:deep(.n-base-selection) { height: 34 * 2.5px;
padding: 4px 0;
}
} }
.search-input { .search-input {
width: 360px; width: 292 * 2.5px;
height: 34 * 2.5px;
padding: 7 * 2.5px 12 * 2.5px;
border: 1 * 2.5px solid #e0e0e6;
border-radius: 3 * 2.5px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
color: #455363;
&::placeholder {
color: #b6b6b6;
}
} }
:deep(.n-input) { :deep(.n-input) {
.n-input__input { .n-input__input {
padding: 4px 0; padding: 4 * 2.5px 0;
// border: 1px solid #ccc; // border: 1*2.5px solid #ccc;
border-radius: 4px; border-radius: 4 * 2.5px;
} }
} }
:deep(.n-select) { :deep(.n-select) {
.n-select__input { .n-select__input {
padding: 8px 12px; padding: 8 * 2.5px 12 * 2.5px;
border: 1px solid #ccc; border: 1 * 2.5px solid #ccc;
border-radius: 4px; border-radius: 4 * 2.5px;
} }
} }
:deep(.n-button) { :deep(.n-button) {
padding: 20px 16px; padding: 20 * 2.5px 16 * 2.5px;
border-radius: 4px; border-radius: 4 * 2.5px;
} }
.search-button { .search-button {
height: 34 * 2.5px;
padding: 7 * 2.5px 12 * 2.5px;
min-width: 160 * 2.5px;
background: #ff7bac; background: #ff7bac;
color: #fff; color: #fff;
border: none;
border-radius: 3 * 2.5px;
cursor: pointer;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
&:hover { &:hover {
background: #ff7bac; background: #ff7bac;
color: #fff; color: #fff;
} }
} }
.reports-list {
display: flex;
flex-direction: column;
gap: 4 * 2.5px;
background: #fff;
width: 650 * 2.5px;
}
.table-row {
display: flex;
flex-direction: column;
position: relative;
border-radius: 8 * 2.5px;
// &:last-child {
// .separator-line {
// display: none;
// }
// }
}
.content {
flex: 1;
display: flex;
flex-direction: column;
gap: 16 * 2.5px;
}
.table-row .content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 0;
&:hover {
background: #fff8fb;
}
}
.file-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding-right: 16 * 2.5px;
}
.file-info {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16 * 2.5px;
flex: 1;
}
.news-item-title {
font-family: "PingFang SC", sans-serif;
font-weight: 500;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
color: #000000;
}
.arrow-icon {
margin-left: auto;
flex-shrink: 0;
cursor: pointer;
}
.vertical-line {
width: 1 * 2.5px;
height: 20 * 2.5px;
background: #ff7bac;
flex-shrink: 0;
}
.file-description {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
color: #455363;
margin: 0;
padding-left: 17 * 2.5px;
margin-top: 8 * 2.5px;
}
.news-item-date {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
color: #455363;
}
.download-section {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
padding: 4 * 2.5px 16 * 2.5px;
}
.separator-line {
width: 100%;
height: 1 * 2.5px;
background: repeating-linear-gradient(
to right,
#e6eaee 0 * 2.5px,
#e6eaee 2 * 2.5px,
transparent 2 * 2.5px,
transparent 4 * 2.5px
);
margin-top: 16 * 2.5px;
}
//
.pagination-container {
display: flex;
align-items: center;
margin: 20 * 2.5px 0;
justify-content: flex-end;
padding: 0 16 * 2.5px;
}
.pagination-info {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.4375em;
color: #455363;
text-align: right;
margin-bottom: 30 * 2.5px;
padding: 0 16 * 2.5px;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 8 * 2.5px;
}
.pagination-buttons {
display: flex;
align-items: center;
gap: 8 * 2.5px;
}
.page-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28 * 2.5px;
height: 28 * 2.5px;
border: 1 * 2.5px solid #e0e0e6;
border-radius: 3 * 2.5px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.428em;
color: #455363;
cursor: pointer;
transition: all 0.2s ease;
&:hover:not(:disabled) {
border-color: #ff7bac;
color: #ff7bac;
}
&.active {
border-color: #ff7bac;
color: #ff7bac;
background: #fff0f5;
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
&.disabled {
cursor: not-allowed;
opacity: 0.5;
}
}
.page-size-selector {
position: relative;
display: flex;
align-items: center;
gap: 18 * 2.5px;
padding: 4 * 2.5px 12 * 2.5px;
height: 28 * 2.5px;
border: 1 * 2.5px solid #e0e0e6;
border-radius: 3 * 2.5px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.428em;
color: #455363;
cursor: pointer;
&:hover {
border-color: #ff7bac;
}
}
.page-size-menu {
position: absolute;
bottom: 100%;
left: 0;
right: 0;
background: #ffffff;
border: 1 * 2.5px solid #e0e0e6;
border-radius: 3 * 2.5px;
box-shadow: 0 2 * 2.5px 8 * 2.5px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin-bottom: 2 * 2.5px;
}
.page-size-option {
padding: 8 * 2.5px 12 * 2.5px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.428em;
color: #455363;
cursor: pointer;
transition: background-color 0.2s ease;
&:hover {
background: #fff0f5;
}
&.active {
background: #fff0f5;
color: #ff7bac;
}
}
.goto-section {
display: flex;
align-items: center;
gap: 8 * 2.5px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.428em;
color: #455363;
}
.goto-input {
width: 60 * 2.5px;
height: 28 * 2.5px;
padding: 4 * 2.5px 12 * 2.5px;
border: 1 * 2.5px solid #e0e0e6;
border-radius: 3 * 2.5px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.428em;
color: #455363;
text-align: center;
&:focus {
outline: none;
border-color: #ff7bac;
}
}
</style> </style>