Compare commits

..

No commits in common. "f16f1505c01a7a0a44f7e1f96ea3336e8ff8a8c3" and "d6e56afbe79237c881708422b27332e59712529d" have entirely different histories.

16 changed files with 2041 additions and 769 deletions

View File

@ -169,8 +169,6 @@ const getListData = async () => {
};
getListData();
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});
const columns = [

View File

@ -169,8 +169,6 @@ const getListData = async () => {
};
getListData();
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -170,8 +170,6 @@ const getListData = async () => {
};
getListData();
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -169,8 +169,6 @@ const getListData = async () => {
};
getListData();
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -238,8 +238,6 @@ const getListData = async () => {
}
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -238,8 +238,6 @@ const getListData = async () => {
}
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -222,8 +222,6 @@ const getListData = async () => {
}
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -236,8 +236,6 @@ const getListData = async () => {
}
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getListData();
});

View File

@ -99,40 +99,93 @@
<!-- 分页器 -->
<div class="pagination-container" v-if="state.total > 0">
<div class="pagination-info text-[#455363] mr-[15PX]">
{{ t("financialinformation.quarterlyreports.pagination.displaying", {
start: (state.currentPage - 1) * state.pageSize + 1,
end: Math.min(state.currentPage * state.pageSize, state.total),
total: state.total,
}) }}
<div class="pagination-info">
Displaying {{ displayRange.start }} - {{ displayRange.end }} of
{{ state.total }} results
</div>
<div class="pagination-controls">
<div class="pagination-buttons">
<button
class="page-btn-prev 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-page"
:class="{ active: page === state.currentPage }"
@click="goToPage(page)"
>
{{ page }}
</button>
<button v-else class="page-btn-page disabled" disabled>
...
</button>
</template>
<button
class="page-btn-next 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>
<NPagination
v-model:page="state.currentPage"
v-model:page-size="state.pageSize"
show-size-picker
show-quick-jumper
:item-count="state.total"
:page-sizes="[
{
label: t('historic_stock.pagination.perPage', { size: 10 }),
value: 10,
},
{
label: t('historic_stock.pagination.perPage', { size: 25 }),
value: 25,
},
{
label: t('historic_stock.pagination.perPage', { size: 50 }),
value: 50,
},
]"
@update:page="getPressReleasesDisplay"
@update:page-size="getPressReleasesDisplay"
>
<template #goto>{{
t("financialinformation.quarterlyreports.pagination.goto")
}}</template>
</NPagination>
</div>
</main>
</div>
@ -147,8 +200,10 @@ import {
watch,
nextTick,
ref,
computed,
onUnmounted,
} from "vue";
import { NTooltip, NPagination } from "naive-ui";
import { NTooltip } from "naive-ui";
import { useI18n } from "vue-i18n";
import axios from "axios";
@ -174,8 +229,11 @@ const state = reactive({
currentPage: 1, //
pageSize: 10,
total: 0,
gotoPage: 1,
});
const showPageSizeMenu = ref(false);
const titleRefs = ref([]);
const setTitleRef = (el, idx) => {
@ -196,12 +254,17 @@ const checkAllTitleOverflow = () => {
onMounted(() => {
getPressReleasesDisplay();
document.addEventListener("click", handleClickOutside);
nextTick(() => {
checkAllTitleOverflow();
});
});
onUnmounted(() => {
document.removeEventListener("click", handleClickOutside);
});
watch(
() => state.filterNewsData,
() => {
@ -257,8 +320,6 @@ const getPressReleasesDisplay = () => {
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getPressReleasesDisplay();
});
// watcher
@ -281,6 +342,7 @@ watch(
watch(
() => state.currentPage,
(newPage) => {
state.gotoPage = newPage;
getPressReleasesDisplay();
}
);
@ -298,6 +360,93 @@ const handleNewClick = (item) => {
},
});
};
const totalPages = computed(() => {
return Math.ceil(state.total / state.pageSize) || 1;
});
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;
}
};
const goToPrevPage = () => {
if (state.currentPage > 1) {
state.currentPage--;
}
};
const goToNextPage = () => {
if (state.currentPage < totalPages.value) {
state.currentPage++;
}
};
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>
<style scoped lang="scss">
@ -503,8 +652,8 @@ const handleNewClick = (item) => {
.pagination-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15px;
justify-content: flex-end;
margin-top: 20px;
margin-bottom: 30px;
gap: 21px;
}
@ -518,7 +667,179 @@ const handleNewClick = (item) => {
text-align: right;
}
:deep(.n-base-loading__icon) {
color: #ff7bac;
.pagination-controls {
display: flex;
align-items: center;
gap: 8px;
}
.pagination-buttons {
display: flex;
align-items: center;
gap: 8px;
}
.page-btn-prev,
.page-btn-next {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 1px solid #e0e0e6;
border-radius: 3px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
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-btn-page {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 3px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.428em;
color: #455363;
cursor: pointer;
transition: all 0.2s ease;
border: none;
&:hover:not(:disabled) {
border-color: #ff7bac;
color: #ff7bac;
}
&.active {
border-color: #ff7bac;
color: #ff7bac;
border: 1px solid #e0e0e6;
}
&: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: 18px;
padding: 4px 12px;
height: 28px;
border: 1px solid #e0e0e6;
border-radius: 3px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
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: 1px solid #e0e0e6;
border-radius: 3px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin-bottom: 2px;
}
.page-size-option {
padding: 8px 12px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
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: 8px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.428em;
color: #455363;
margin-right: 16px;
}
.goto-input {
width: 60px;
height: 28px;
padding: 4px 12px;
border: 1px solid #e0e0e6;
border-radius: 3px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.428em;
color: #455363;
text-align: center;
&:focus {
outline: none;
border-color: #ff7bac;
}
}
</style>

View File

@ -99,40 +99,93 @@
<!-- 分页器 -->
<div class="pagination-container" v-if="state.total > 0">
<div class="pagination-info text-[#455363] mr-[15PX]">
{{ t("financialinformation.quarterlyreports.pagination.displaying", {
start: (state.currentPage - 1) * state.pageSize + 1,
end: Math.min(state.currentPage * state.pageSize, state.total),
total: state.total,
}) }}
<div class="pagination-info">
Displaying {{ displayRange.start }} - {{ displayRange.end }} of
{{ state.total }} results
</div>
<div class="pagination-controls">
<div class="pagination-buttons">
<button
class="page-btn-prev 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-page"
:class="{ active: page === state.currentPage }"
@click="goToPage(page)"
>
{{ page }}
</button>
<button v-else class="page-btn-page disabled" disabled>
...
</button>
</template>
<button
class="page-btn-next 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>
<NPagination
v-model:page="state.currentPage"
v-model:page-size="state.pageSize"
show-size-picker
show-quick-jumper
:item-count="state.total"
:page-sizes="[
{
label: t('historic_stock.pagination.perPage', { size: 10 }),
value: 10,
},
{
label: t('historic_stock.pagination.perPage', { size: 25 }),
value: 25,
},
{
label: t('historic_stock.pagination.perPage', { size: 50 }),
value: 50,
},
]"
@update:page="getPressReleasesDisplay"
@update:page-size="getPressReleasesDisplay"
>
<template #goto>{{
t("financialinformation.quarterlyreports.pagination.goto")
}}</template>
</NPagination>
</div>
</main>
</div>
@ -150,7 +203,7 @@ import {
computed,
onUnmounted,
} from "vue";
import { NTooltip, NPagination } from "naive-ui";
import { NTooltip } from "naive-ui";
import { useI18n } from "vue-i18n";
import axios from "axios";
@ -176,8 +229,11 @@ const state = reactive({
currentPage: 1, //
pageSize: 10,
total: 0,
gotoPage: 1,
});
const showPageSizeMenu = ref(false);
const titleRefs = ref([]);
const setTitleRef = (el, idx) => {
@ -198,12 +254,17 @@ const checkAllTitleOverflow = () => {
onMounted(() => {
getPressReleasesDisplay();
document.addEventListener("click", handleClickOutside);
nextTick(() => {
checkAllTitleOverflow();
});
});
onUnmounted(() => {
document.removeEventListener("click", handleClickOutside);
});
watch(
() => state.filterNewsData,
() => {
@ -259,8 +320,6 @@ const getPressReleasesDisplay = () => {
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getPressReleasesDisplay();
});
@ -284,6 +343,7 @@ watch(
watch(
() => state.currentPage,
(newPage) => {
state.gotoPage = newPage;
getPressReleasesDisplay();
}
);
@ -301,6 +361,93 @@ const handleNewClick = (item) => {
},
});
};
const totalPages = computed(() => {
return Math.ceil(state.total / state.pageSize) || 1;
});
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;
}
};
const goToPrevPage = () => {
if (state.currentPage > 1) {
state.currentPage--;
}
};
const goToNextPage = () => {
if (state.currentPage < totalPages.value) {
state.currentPage++;
}
};
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>
<style scoped lang="scss">
@ -502,8 +649,8 @@ const handleNewClick = (item) => {
.pagination-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15px;
margin-top: 20px;
justify-content: flex-end;
margin-bottom: 30px;
gap: 21px;
}
@ -517,7 +664,179 @@ const handleNewClick = (item) => {
text-align: right;
}
:deep(.n-base-loading__icon) {
color: #ff7bac;
.pagination-controls {
display: flex;
align-items: center;
gap: 8px;
}
.pagination-buttons {
display: flex;
align-items: center;
gap: 8px;
}
.page-btn-prev,
.page-btn-next {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 1px solid #e0e0e6;
border-radius: 3px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
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-btn-page {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 3px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.428em;
color: #455363;
cursor: pointer;
transition: all 0.2s ease;
border: none;
&:hover:not(:disabled) {
border-color: #ff7bac;
color: #ff7bac;
}
&.active {
border-color: #ff7bac;
color: #ff7bac;
border: 1px solid #e0e0e6;
}
&: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: 18px;
padding: 4px 12px;
height: 28px;
border: 1px solid #e0e0e6;
border-radius: 3px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
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: 1px solid #e0e0e6;
border-radius: 3px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin-bottom: 2px;
}
.page-size-option {
padding: 8px 12px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
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: 8px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.428em;
color: #455363;
margin-right: 16px;
}
.goto-input {
width: 60px;
height: 28px;
padding: 4px 12px;
border: 1px solid #e0e0e6;
border-radius: 3px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.428em;
color: #455363;
text-align: center;
&:focus {
outline: none;
border-color: #ff7bac;
}
}
</style>

View File

@ -1,146 +1,206 @@
<template>
<div class="press-releases-page">
<main class="mx-auto">
<div class="title-section">
<div class="title-decoration"></div>
<div class="title mb-[20px]">
{{ t("press_releases.title") }}
<div class="title-section">
<div class="title-decoration"></div>
<div class="title">
{{ t("press_releases.title") }}
</div>
</div>
<div class="search-container">
<div class="search-select" @click="openYearPicker">
<div class="search-select-label">Year</div>
<div class="search-select-icon">
<span class="selected-year-label">{{ selectedYearLabel }}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="10"
height="10"
viewBox="0 0 10 10"
fill="none"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2.58882 9.69047C2.38633 9.48798 2.36383 9.17365 2.52132 8.9463L2.58882 8.86552L6.45447 5.00022L2.58882 1.13492C2.38633 0.932428 2.36383 0.618098 2.52132 0.390748L2.58882 0.309958C2.79132 0.107469 3.10565 0.0849685 3.33299 0.242458L3.41378 0.309958L7.69156 4.58774C7.89405 4.79023 7.91655 5.10456 7.75906 5.33191L7.69156 5.4127L3.41378 9.69047C3.18597 9.91828 2.81663 9.91828 2.58882 9.69047Z"
fill="black"
/>
</svg>
</div>
</div>
<div class="search-container">
<custom-select
:options="state.selectOptions"
v-model="state.selectedValue"
class="search-select"
/>
<input
v-model="state.inputValue"
type="text"
:placeholder="t('press_releases.search.placeholder')"
class="search-input"
/>
<button @click="handleSearch" class="search-button">
{{ t("press_releases.search.button") }}
</button>
</div>
<div class="reports-list">
<div
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>
<input
v-model="state.inputValue"
type="text"
:placeholder="t('press_releases.search.placeholder')"
class="search-input"
/>
<button @click="handleSearch" class="search-button">
{{ t("press_releases.search.button") }}
</button>
</div>
<div class="reports-list">
<div
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="
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 1;
line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
"
@click="handleNewClick(item)"
>
{{ item.title }}
</div>
<svg
class="arrow-icon"
width="7"
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>
<div
class="news-item-title text-[#000] cursor-pointer"
:ref="(el) => setTitleRef(el, idx)"
class="news-item-content file-description"
style="
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 1;
line-clamp: 1;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
"
@click="handleNewClick(item)"
>
{{ item.title }}
</div>
<svg
class="arrow-icon"
width="7"
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>
<div
:ref="(el) => setTitleRef(el, idx)"
class="news-item-content file-description"
style="
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 1;
line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{ item.summary }}
</div>
</template>
<div slot="content">
{{ item.summary }}
</div>
</n-tooltip>
<div class="download-section">
<div class="news-item-date">{{ item.date }}</div>
</template>
<div slot="content">
{{ item.summary }}
</div>
</n-tooltip>
<div class="download-section">
<div class="news-item-date">{{ item.date }}</div>
</div>
</div>
<div class="separator-line"></div>
</div>
<div class="separator-line"></div>
</div>
</div>
<!-- 分页器 -->
<div class="pagination-container" style="flex-direction: column;" v-if="state.total > 0">
<div class="pagination-info text-[#455363] mr-[15PX]">
{{ t("financialinformation.quarterlyreports.pagination.displaying", {
start: (state.currentPage - 1) * state.pageSize + 1,
end: Math.min(state.currentPage * state.pageSize, state.total),
total: state.total,
}) }}
<!-- 分页器 -->
<div class="pagination-container" v-if="state.total > 0">
<div class="pagination-controls">
<div class="pagination-buttons">
<button
class="page-btn-prev 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-page"
:class="{ active: page === state.currentPage }"
@click="goToPage(page)"
>
{{ page }}
</button>
<button v-else class="page-btn-page disabled" disabled>...</button>
</template>
<button
class="page-btn-next 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>
<NPagination
v-model:page="state.currentPage"
v-model:page-size="state.pageSize"
show-size-picker
show-quick-jumper
:item-count="state.total"
:page-sizes="[
{
label: t('historic_stock.pagination.perPage', { size: 10 }),
value: 10,
},
{
label: t('historic_stock.pagination.perPage', { size: 25 }),
value: 25,
},
{
label: t('historic_stock.pagination.perPage', { size: 50 }),
value: 50,
},
]"
@update:page="getPressReleasesDisplay"
@update:page-size="getPressReleasesDisplay"
>
<template #goto>{{
t("financialinformation.quarterlyreports.pagination.goto")
}}</template>
</NPagination>
</div>
</main>
</div>
<div class="pagination-info" v-if="state.total > 0">
Displaying {{ displayRange.start }} - {{ displayRange.end }} of
{{ state.total }} results
</div>
</div>
<year-wheel-picker
v-if="state.showYearPicker"
v-model="state.selectedValue"
:options="state.selectOptions"
@close="closeYearPicker"
@confirm="onYearConfirm"
></year-wheel-picker>
</template>
<script setup>
import customDefaultPage from "@/components/customDefaultPage/index.vue";
import customSelect from "@/components/customSelect/index.vue";
import YearWheelPicker from "@/components/YearWheelPicker.vue";
import {
reactive,
onMounted,
@ -148,8 +208,9 @@ import {
nextTick,
ref,
computed,
onUnmounted,
} from "vue";
import { NTooltip, NPagination } from "naive-ui";
import { NInput, NButton, NTooltip } from "naive-ui";
import { useI18n } from "vue-i18n";
import axios from "axios";
@ -175,9 +236,12 @@ const state = reactive({
currentPage: 1, //
pageSize: 10,
total: 0,
gotoPage: 1,
showYearPicker: false,
});
const showPageSizeMenu = ref(false);
const titleRefs = ref([]);
const selectedYearLabel = computed(() => {
@ -218,12 +282,17 @@ const checkAllTitleOverflow = () => {
onMounted(() => {
getPressReleasesDisplay();
document.addEventListener("click", handleClickOutside);
nextTick(() => {
checkAllTitleOverflow();
});
});
onUnmounted(() => {
document.removeEventListener("click", handleClickOutside);
});
watch(
() => state.filterNewsData,
() => {
@ -262,7 +331,7 @@ const getPressReleasesDisplay = () => {
if (res.status === 200) {
if (res.data.status === 0) {
res.data.data?.data?.forEach((item) => {
item.date = new Date(item.createdAt).toLocaleDateString("en-US", {
item.date = new Date(item.date).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
@ -279,8 +348,6 @@ const getPressReleasesDisplay = () => {
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getPressReleasesDisplay();
});
@ -304,6 +371,7 @@ watch(
watch(
() => state.currentPage,
(newPage) => {
state.gotoPage = newPage;
getPressReleasesDisplay();
}
);
@ -321,6 +389,69 @@ const handleNewClick = (item) => {
},
});
};
const totalPages = computed(() => {
return Math.ceil(state.total / state.pageSize) || 1;
});
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;
}
};
const goToPrevPage = () => {
if (state.currentPage > 1) {
state.currentPage--;
}
};
const goToNextPage = () => {
if (state.currentPage < totalPages.value) {
state.currentPage++;
}
};
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 total = totalPages.value;
if (total <= 4) {
const pages = [];
for (let i = 1; i <= total; i++) {
pages.push(i);
}
return pages;
}
return [1, 2, "...", total];
};
//
const handleClickOutside = (event) => {
if (!event.target.closest || !event.target.closest(".page-size-selector")) {
showPageSizeMenu.value = false;
}
};
</script>
<style scoped lang="scss">
@ -393,6 +524,26 @@ const handleNewClick = (item) => {
}
}
:deep(.n-input) {
.n-input__input {
padding: 4 * 5.12px 0;
// border: 1*5.12px solid #ccc;
border-radius: 4 * 5.12px;
}
}
:deep(.n-select) {
.n-select__input {
padding: 8 * 5.12px 12 * 5.12px;
border: 1 * 5.12px solid #ccc;
border-radius: 4 * 5.12px;
}
}
:deep(.n-button) {
padding: 20 * 5.12px 16 * 5.12px;
border-radius: 4 * 5.12px;
}
.search-button {
width: 104 * 5.12px;
height: 34 * 5.12px;
@ -403,7 +554,7 @@ const handleNewClick = (item) => {
border-radius: 3 * 5.12px;
cursor: pointer;
font-family: "PingFang SC", sans-serif;
font-weight: 500;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.375em;
letter-spacing: 0.48 * 5.12px;
@ -418,6 +569,8 @@ const handleNewClick = (item) => {
flex-direction: column;
gap: 4 * 5.12px;
background: #fff;
width: 100%;
margin-top: 40 * 5.12px;
}
.table-row {
@ -425,6 +578,12 @@ const handleNewClick = (item) => {
flex-direction: column;
position: relative;
border-radius: 8 * 5.12px;
// &:last-child {
// .separator-line {
// display: none;
// }
// }
}
.content {
@ -440,7 +599,6 @@ const handleNewClick = (item) => {
align-items: center;
justify-content: space-between;
gap: 0;
padding: 0 16 * 5.12px;
&:hover {
background: #fff8fb;
}
@ -451,7 +609,6 @@ const handleNewClick = (item) => {
display: flex;
flex-direction: column;
overflow: hidden;
padding-right: 16 * 5.12px;
}
.file-info {
@ -462,13 +619,6 @@ const handleNewClick = (item) => {
flex: 1;
}
.vertical-line {
width: 1 * 5.12px;
height: 20 * 5.12px;
background: #ff7bac;
flex-shrink: 0;
}
.news-item-title {
font-family: "PingFang SC", sans-serif;
font-weight: 500;
@ -478,31 +628,30 @@ const handleNewClick = (item) => {
color: #000000;
}
.news-item-content {
.arrow-icon {
margin-right: 16 * 5.12px;
flex-shrink: 0;
cursor: pointer;
}
.vertical-line {
width: 1 * 5.12px;
height: 20 * 5.12px;
background: #ff7bac;
flex-shrink: 0;
}
.file-description {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.375em;
letter-spacing: 0.48 * 5.12px;
color: #455363;
margin-top: 4 * 5.12px;
margin: 8 * 5.12px 0;
padding: 0 16 * 5.12px;
}
.arrow-icon {
margin-left: auto;
flex-shrink: 0;
cursor: pointer;
}
.download-section {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
padding: 4 * 5.12px 16 * 5.12px;
}
.news-item-date {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
@ -512,15 +661,24 @@ const handleNewClick = (item) => {
color: #455363;
}
.download-section {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
padding: 0 16 * 5.12px;
margin-bottom: 8 * 5.12px;
}
.separator-line {
width: 100%;
height: 1 * 5.12px;
background: repeating-linear-gradient(
to right,
#e6eaee 0px,
#e6eaee 4 * 5.12px,
transparent 4 * 5.12px,
transparent 8 * 5.12px
#e6eaee 0 * 5.12px,
#e6eaee 2 * 5.12px,
transparent 2 * 5.12px,
transparent 4 * 5.12px
);
margin-top: 16 * 5.12px;
}
@ -529,10 +687,11 @@ const handleNewClick = (item) => {
.pagination-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15 * 5.12px;
margin-bottom: 30 * 5.12px;
gap: 21 * 5.12px;
margin: 16 * 5.12px 0;
justify-content: flex-end;
padding: 0 16 * 5.12px;
flex-wrap: wrap;
gap: 16 * 5.12px;
}
.pagination-info {
@ -542,9 +701,201 @@ const handleNewClick = (item) => {
line-height: 1.4375em;
color: #455363;
text-align: right;
margin-bottom: 30 * 5.12px;
padding: 0 16 * 5.12px;
width: 100%;
}
:deep(.n-base-loading__icon) {
color: #ff7bac;
.pagination-controls {
display: flex;
align-items: center;
gap: 8 * 5.12px;
flex-wrap: wrap;
justify-content: flex-end;
}
.pagination-buttons {
display: flex;
align-items: center;
gap: 8 * 5.12px;
}
.page-btn-prev,
.page-btn-next {
display: flex;
align-items: center;
justify-content: center;
width: 28 * 5.12px;
height: 28 * 5.12px;
border: 1 * 5.12px solid #e0e0e6;
border-radius: 3 * 5.12px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
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-btn-page {
display: flex;
align-items: center;
justify-content: center;
width: 28 * 5.12px;
height: 28 * 5.12px;
border-radius: 3 * 5.12px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.428em;
color: #455363;
cursor: pointer;
transition: all 0.2s ease;
border: none;
&:hover:not(:disabled) {
border-color: #ff7bac;
color: #ff7bac;
}
&.active {
border-color: #ff7bac;
color: #ff7bac;
border: 1 * 5.12px solid #e0e0e6;
}
&: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 * 5.12px;
padding: 4 * 5.12px 12 * 5.12px;
height: 28 * 5.12px;
border: 1 * 5.12px solid #e0e0e6;
border-radius: 3 * 5.12px;
background: #ffffff;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
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 * 5.12px solid #e0e0e6;
border-radius: 3 * 5.12px;
box-shadow: 0 2 * 5.12px 8 * 5.12px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin-bottom: 2 * 5.12px;
}
.page-size-option {
padding: 8 * 5.12px 12 * 5.12px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
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 * 5.12px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.428em;
color: #455363;
}
.goto-input {
width: 60 * 5.12px;
height: 28 * 5.12px;
padding: 4 * 5.12px 12 * 5.12px;
border: 1 * 5.12px solid #e0e0e6;
border-radius: 3 * 5.12px;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.428em;
color: #455363;
text-align: center;
&:focus {
outline: none;
border-color: #ff7bac;
}
}
.selected-year-label {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.428em;
color: #000;
margin-right: 16 * 5.12px;
}
.search-select-label {
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 5.12px;
line-height: 1.428em;
color: #000;
}
</style>

View File

@ -3,7 +3,7 @@
<main class="mx-auto">
<div class="title-section">
<div class="title-decoration"></div>
<div class="title mb-[20px]">
<div class="title">
{{ t("press_releases.title") }}
</div>
</div>
@ -74,8 +74,8 @@
style="
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 1;
line-clamp: 1;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
@ -99,40 +99,93 @@
<!-- 分页器 -->
<div class="pagination-container" v-if="state.total > 0">
<div class="pagination-info text-[#455363] mr-[15PX]">
{{ t("financialinformation.quarterlyreports.pagination.displaying", {
start: (state.currentPage - 1) * state.pageSize + 1,
end: Math.min(state.currentPage * state.pageSize, state.total),
total: state.total,
}) }}
<div class="pagination-controls">
<div class="pagination-buttons">
<button
class="page-btn-prev 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-page"
:class="{ active: page === state.currentPage }"
@click="goToPage(page)"
>
{{ page }}
</button>
<button v-else class="page-btn-page disabled" disabled>
...
</button>
</template>
<button
class="page-btn-next 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>
<NPagination
v-model:page="state.currentPage"
v-model:page-size="state.pageSize"
show-size-picker
show-quick-jumper
:item-count="state.total"
:page-sizes="[
{
label: t('historic_stock.pagination.perPage', { size: 10 }),
value: 10,
},
{
label: t('historic_stock.pagination.perPage', { size: 25 }),
value: 25,
},
{
label: t('historic_stock.pagination.perPage', { size: 50 }),
value: 50,
},
]"
@update:page="getPressReleasesDisplay"
@update:page-size="getPressReleasesDisplay"
>
<template #goto>{{
t("financialinformation.quarterlyreports.pagination.goto")
}}</template>
</NPagination>
</div>
<div class="pagination-info" v-if="state.total > 0">
Displaying {{ displayRange.start }} - {{ displayRange.end }} of
{{ state.total }} results
</div>
</main>
</div>
@ -148,8 +201,9 @@ import {
nextTick,
ref,
computed,
onUnmounted,
} from "vue";
import { NTooltip, NPagination } from "naive-ui";
import { NTooltip } from "naive-ui";
import { useI18n } from "vue-i18n";
import axios from "axios";
@ -175,31 +229,13 @@ const state = reactive({
currentPage: 1, //
pageSize: 10,
total: 0,
showYearPicker: false,
gotoPage: 1,
});
const showPageSizeMenu = ref(false);
const titleRefs = ref([]);
const selectedYearLabel = computed(() => {
const option = state.selectOptions.find(
(opt) => opt.value === state.selectedValue
);
return option ? option.label : "";
});
const openYearPicker = () => {
state.showYearPicker = true;
};
const closeYearPicker = () => {
state.showYearPicker = false;
};
const onYearConfirm = (year) => {
state.selectedValue = year;
closeYearPicker();
};
const setTitleRef = (el, idx) => {
if (el) titleRefs.value[idx] = el;
};
@ -218,12 +254,17 @@ const checkAllTitleOverflow = () => {
onMounted(() => {
getPressReleasesDisplay();
document.addEventListener("click", handleClickOutside);
nextTick(() => {
checkAllTitleOverflow();
});
});
onUnmounted(() => {
document.removeEventListener("click", handleClickOutside);
});
watch(
() => state.filterNewsData,
() => {
@ -262,7 +303,7 @@ const getPressReleasesDisplay = () => {
if (res.status === 200) {
if (res.data.status === 0) {
res.data.data?.data?.forEach((item) => {
item.date = new Date(item.createdAt).toLocaleDateString("en-US", {
item.date = new Date(item.date).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
@ -279,8 +320,6 @@ const getPressReleasesDisplay = () => {
};
watch(locale, (newLocale, oldLocale) => {
//
state.currentPage = 1;
getPressReleasesDisplay();
});
@ -304,6 +343,7 @@ watch(
watch(
() => state.currentPage,
(newPage) => {
state.gotoPage = newPage;
getPressReleasesDisplay();
}
);
@ -321,13 +361,99 @@ const handleNewClick = (item) => {
},
});
};
const totalPages = computed(() => {
return Math.ceil(state.total / state.pageSize) || 1;
});
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;
}
};
const goToPrevPage = () => {
if (state.currentPage > 1) {
state.currentPage--;
}
};
const goToNextPage = () => {
if (state.currentPage < totalPages.value) {
state.currentPage++;
}
};
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>
<style scoped lang="scss">
.press-releases-page {
width: 650 * 2.5px;
margin: 0 auto;
background: #fff;
}
.title-section {
display: flex;
@ -339,6 +465,7 @@ const handleNewClick = (item) => {
width: 58 * 2.5px;
height: 7 * 2.5px;
background: #ff7bac;
margin: auto 0;
margin-top: 43 * 2.5px;
}
.title {
@ -347,36 +474,21 @@ const handleNewClick = (item) => {
}
.search-container {
margin-top: 32 * 2.5px;
margin-bottom: 20 * 2.5px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
flex-flow: wrap;
justify-content: flex-start;
gap: 16 * 2.5px;
padding: 0 16 * 2.5px;
}
.search-select {
width: 201 * 2.5px;
height: 34 * 2.5px;
padding: 0 12 * 2.5px;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
font-family: "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14 * 2.5px;
color: #455363;
}
.search-select-icon {
display: flex;
align-items: center;
width: 134 * 2.5px;
}
.search-input {
width: 401 * 2.5px;
width: 292 * 2.5px;
height: 34 * 2.5px;
padding: 7 * 2.5px 12 * 2.5px;
border: 1 * 2.5px solid #e0e0e6;
@ -387,6 +499,7 @@ const handleNewClick = (item) => {
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
color: #455363;
box-sizing: border-box;
&::placeholder {
color: #b6b6b6;
@ -394,19 +507,20 @@ const handleNewClick = (item) => {
}
.search-button {
width: 201 * 2.5px;
height: 34 * 2.5px;
padding: 7 * 2.5px 12 * 2.5px;
min-width: 160 * 2.5px;
background: #ff7bac;
color: #fff;
border: none;
border-radius: 3 * 2.5px;
cursor: pointer;
font-family: "PingFang SC", sans-serif;
font-weight: 500;
font-weight: 400;
font-size: 14 * 2.5px;
line-height: 1.375em;
letter-spacing: 0.48 * 2.5px;
box-sizing: border-box;
&:hover {
background: #ff7bac;
color: #fff;
@ -418,6 +532,7 @@ const handleNewClick = (item) => {
flex-direction: column;
gap: 4 * 2.5px;
background: #fff;
width: 650 * 2.5px;
}
.table-row {
@ -425,6 +540,12 @@ const handleNewClick = (item) => {
flex-direction: column;
position: relative;
border-radius: 8 * 2.5px;
// &:last-child {
// .separator-line {
// display: none;
// }
// }
}
.content {
@ -440,7 +561,6 @@ const handleNewClick = (item) => {
align-items: center;
justify-content: space-between;
gap: 0;
padding: 0 16 * 2.5px;
&:hover {
background: #fff8fb;
}
@ -462,13 +582,6 @@ const handleNewClick = (item) => {
flex: 1;
}
.vertical-line {
width: 1 * 2.5px;
height: 20 * 2.5px;
background: #ff7bac;
flex-shrink: 0;
}
.news-item-title {
font-family: "PingFang SC", sans-serif;
font-weight: 500;
@ -478,29 +591,29 @@ const handleNewClick = (item) => {
color: #000000;
}
.news-item-content {
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-top: 4 * 2.5px;
padding: 0 16 * 2.5px;
}
.arrow-icon {
margin-left: auto;
flex-shrink: 0;
cursor: pointer;
}
.download-section {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
padding: 4 * 2.5px 16 * 2.5px;
.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: 0 16 * 2.5px;
margin-top: 8 * 2.5px;
}
.news-item-date {
@ -512,15 +625,23 @@ const handleNewClick = (item) => {
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 0px,
#e6eaee 4 * 2.5px,
transparent 4 * 2.5px,
transparent 8 * 2.5px
#e6eaee 0 * 2.5px,
#e6eaee 2 * 2.5px,
transparent 2 * 2.5px,
transparent 4 * 2.5px
);
margin-top: 16 * 2.5px;
}
@ -529,10 +650,9 @@ const handleNewClick = (item) => {
.pagination-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15 * 2.5px;
margin-bottom: 30 * 2.5px;
gap: 21 * 2.5px;
margin: 20 * 2.5px 0;
justify-content: flex-end;
padding: 0 16 * 2.5px;
}
.pagination-info {
@ -542,9 +662,182 @@ const handleNewClick = (item) => {
line-height: 1.4375em;
color: #455363;
text-align: right;
margin-bottom: 30 * 2.5px;
padding: 0 16 * 2.5px;
}
:deep(.n-base-loading__icon) {
color: #ff7bac;
.pagination-controls {
display: flex;
align-items: center;
gap: 8 * 2.5px;
}
.pagination-buttons {
display: flex;
align-items: center;
gap: 8 * 2.5px;
}
.page-btn-prev,
.page-btn-next {
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-btn-page {
display: flex;
align-items: center;
justify-content: center;
width: 28 * 2.5px;
height: 28 * 2.5px;
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;
border: none;
&:hover:not(:disabled) {
border-color: #ff7bac;
color: #ff7bac;
}
&.active {
border-color: #ff7bac;
color: #ff7bac;
border: 1 * 2.5px solid #e0e0e6;
}
&: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>

View File

@ -37,8 +37,10 @@ const trimTrailingLetter = (val) => {
stockQuote.change
? String(stockQuote.change).includes('-')
? 'negative-change'
: 'positive-change'
: String(stockQuote.change).includes('+')
? 'positive-change'
: 'neutral-change'
: 'neutral-change'
"
>
{{ stockQuote.change }}

View File

@ -38,8 +38,10 @@ const trimTrailingLetter = (val) => {
stockQuote.change
? String(stockQuote.change).includes('-')
? 'negative-change'
: 'positive-change'
: String(stockQuote.change).includes('+')
? 'positive-change'
: 'neutral-change'
: 'neutral-change'
"
>
{{ stockQuote.change }}

View File

@ -51,7 +51,7 @@ const trimTrailingLetter = (val) => {
class="detail-value"
:class="{
'text-red': String(stockQuote.change).includes('-'),
'!text-green': !String(stockQuote.change).includes('-'),
'text-green': String(stockQuote.change).includes('+'),
}"
>
{{ stockQuote.change }}

View File

@ -50,7 +50,7 @@ const trimTrailingLetter = (val) => {
class="detail-value"
:class="{
'text-red': String(stockQuote.change).includes('-'),
'!text-green': !String(stockQuote.change).includes('-'),
'text-green': String(stockQuote.change).includes('+'),
}"
>
{{ stockQuote.change }}