fix historic-stock 375,press-releases 375
This commit is contained in:
parent
ad91c54d8d
commit
4f59eb52e1
397
src/components/DateWheelPicker.vue
Normal file
397
src/components/DateWheelPicker.vue
Normal file
@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div class="picker-mask" @click.self="emit('close')">
|
||||
<div class="picker-panel">
|
||||
<div class="picker-title">
|
||||
Select Time
|
||||
<svg
|
||||
@click="emit('close')"
|
||||
style="cursor: pointer"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M0.666016 9.74935C0.666016 4.59469 4.84469 0.416016 9.99935 0.416016C15.154 0.416016 19.3327 4.59469 19.3327 9.74935C19.3327 14.904 15.154 19.0827 9.99935 19.0827C4.84469 19.0827 0.666016 14.904 0.666016 9.74935Z"
|
||||
fill="#CCCCCC"
|
||||
/>
|
||||
<path
|
||||
d="M12.833 5.84961C13.1273 5.55596 13.6042 5.55565 13.8965 5.84863C14.1907 6.14223 14.1893 6.61848 13.8965 6.91211L11.0615 9.74609L13.9043 12.5898C14.1973 12.8848 14.1986 13.3607 13.9043 13.6543C13.6114 13.947 13.1344 13.9471 12.8408 13.6543L9.99707 10.8105L7.1582 13.6504C6.86386 13.9444 6.38729 13.9446 6.09375 13.6504C5.8002 13.3574 5.80045 12.8809 6.09473 12.5859L8.93359 9.74707L6.10254 6.91602C5.80956 6.62236 5.80889 6.1452 6.10254 5.85156C6.39486 5.55817 6.87209 5.55802 7.16699 5.85156L9.99805 8.68262L12.833 5.84961Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="picker-columns"
|
||||
:style="{ height: wheelViewportHeight + 'px' }"
|
||||
>
|
||||
<div class="center-lines" :style="{ height: wheelItemHeight + 'px' }">
|
||||
<div class="line"></div>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
<div
|
||||
class="picker-col year-col"
|
||||
ref="yearColRef"
|
||||
@scroll.passive="(e) => handleWheelScroll('year', e)"
|
||||
@wheel.prevent="(e) => handleWheelStep('year', e)"
|
||||
:style="{
|
||||
scrollPaddingTop: wheelCenterPad + 'px',
|
||||
scrollPaddingBottom: wheelCenterPad + 'px',
|
||||
}"
|
||||
>
|
||||
<div :style="{ height: wheelCenterPad + 'px' }"></div>
|
||||
<div
|
||||
v-for="y in years"
|
||||
:key="'y' + y"
|
||||
class="picker-item"
|
||||
:class="{ active: y === localYear }"
|
||||
:style="{
|
||||
height: wheelItemHeight + 'px',
|
||||
}"
|
||||
@click="localYear = y"
|
||||
>
|
||||
{{ y }}
|
||||
</div>
|
||||
<div :style="{ height: wheelCenterPad + 'px' }"></div>
|
||||
</div>
|
||||
<div
|
||||
class="picker-col month-col"
|
||||
ref="monthColRef"
|
||||
@scroll.passive="(e) => handleWheelScroll('month', e)"
|
||||
@wheel.prevent="(e) => handleWheelStep('month', e)"
|
||||
:style="{
|
||||
scrollPaddingTop: wheelCenterPad + 'px',
|
||||
scrollPaddingBottom: wheelCenterPad + 'px',
|
||||
}"
|
||||
>
|
||||
<div :style="{ height: wheelCenterPad + 'px' }"></div>
|
||||
<div
|
||||
v-for="m in months"
|
||||
:key="'m' + m"
|
||||
class="picker-item"
|
||||
:class="{ active: m === localMonth }"
|
||||
:style="{
|
||||
height: wheelItemHeight + 'px',
|
||||
}"
|
||||
@click="localMonth = m"
|
||||
>
|
||||
{{ m }}
|
||||
</div>
|
||||
<div :style="{ height: wheelCenterPad + 'px' }"></div>
|
||||
</div>
|
||||
<div
|
||||
class="picker-col day-col"
|
||||
ref="dayColRef"
|
||||
@scroll.passive="(e) => handleWheelScroll('day', e)"
|
||||
@wheel.prevent="(e) => handleWheelStep('day', e)"
|
||||
:style="{
|
||||
scrollPaddingTop: wheelCenterPad + 'px',
|
||||
scrollPaddingBottom: wheelCenterPad + 'px',
|
||||
}"
|
||||
>
|
||||
<div :style="{ height: wheelCenterPad + 'px' }"></div>
|
||||
<div
|
||||
v-for="d in daysInMonth(localYear, localMonth)"
|
||||
:key="'d' + d"
|
||||
class="picker-item"
|
||||
:class="{ active: d === localDay }"
|
||||
:style="{
|
||||
height: wheelItemHeight + 'px',
|
||||
}"
|
||||
@click="localDay = d"
|
||||
>
|
||||
{{ d }}
|
||||
</div>
|
||||
<div :style="{ height: wheelCenterPad + 'px' }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="picker-actions">
|
||||
<button class="picker-confirm" @click="confirm">
|
||||
Confirm Selection
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, nextTick } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, required: true }, // { year, month, day }
|
||||
minYear: { type: Number, default: 2009 },
|
||||
maxYear: { type: Number, default: new Date().getFullYear() },
|
||||
});
|
||||
const emit = defineEmits(["update:modelValue", "close", "confirm"]);
|
||||
|
||||
const wheelItemBase = 8 * 5.12;
|
||||
const wheelItemHeight = Math.round(wheelItemBase); // use integer px to avoid fractional rounding
|
||||
const wheelViewportHeight = wheelItemHeight * 5;
|
||||
const wheelCenterPad = (wheelViewportHeight - wheelItemHeight) / 2;
|
||||
const isUserScrolling = ref(false);
|
||||
|
||||
const years = computed(() =>
|
||||
Array.from(
|
||||
{ length: props.maxYear - props.minYear + 1 },
|
||||
(_, i) => props.minYear + i
|
||||
)
|
||||
);
|
||||
const months = Array.from({ length: 12 }, (_, i) => i + 1);
|
||||
|
||||
const localYear = ref(props.modelValue.year);
|
||||
const localMonth = ref(props.modelValue.month);
|
||||
const localDay = ref(props.modelValue.day);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(v) => {
|
||||
localYear.value = v.year;
|
||||
localMonth.value = v.month;
|
||||
localDay.value = v.day;
|
||||
nextTick(syncWheelPositions);
|
||||
}
|
||||
);
|
||||
|
||||
const yearColRef = ref(null);
|
||||
const monthColRef = ref(null);
|
||||
const dayColRef = ref(null);
|
||||
|
||||
function daysInMonth(year, month) {
|
||||
return new Date(year, month, 0).getDate();
|
||||
}
|
||||
|
||||
watch([localYear, localMonth], () => {
|
||||
const dim = daysInMonth(localYear.value, localMonth.value);
|
||||
if (localDay.value > dim) localDay.value = dim;
|
||||
if (!isUserScrolling.value) {
|
||||
nextTick(syncWheelPositions);
|
||||
}
|
||||
});
|
||||
|
||||
function syncWheelPositions() {
|
||||
const yearIdx = years.value.indexOf(localYear.value);
|
||||
const monthIdx = localMonth.value - 1;
|
||||
const dayIdx = localDay.value - 1;
|
||||
if (yearColRef.value) yearColRef.value.scrollTop = yearIdx * wheelItemHeight;
|
||||
if (monthColRef.value)
|
||||
monthColRef.value.scrollTop = monthIdx * wheelItemHeight;
|
||||
if (dayColRef.value) dayColRef.value.scrollTop = dayIdx * wheelItemHeight;
|
||||
}
|
||||
|
||||
const scrollTimers = { year: null, month: null, day: null };
|
||||
const isAnimating = { year: false, month: false, day: false };
|
||||
function getCenteredIndex(el) {
|
||||
if (!el) return 0;
|
||||
const raw = (el.scrollTop - wheelCenterPad) / wheelItemHeight;
|
||||
return Math.round(raw);
|
||||
}
|
||||
function clamp(n, min, max) {
|
||||
return Math.max(min, Math.min(n, max));
|
||||
}
|
||||
function getCenteredIndexByRect(el) {
|
||||
if (!el) return 0;
|
||||
const items = el.querySelectorAll(".picker-item");
|
||||
if (!items || items.length === 0) return 0;
|
||||
const containerRect = el.getBoundingClientRect();
|
||||
const centerY = containerRect.top + containerRect.height / 2;
|
||||
let nearestIdx = 0;
|
||||
let nearestDist = Number.POSITIVE_INFINITY;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const r = items[i].getBoundingClientRect();
|
||||
const mid = r.top + r.height / 2;
|
||||
const dist = Math.abs(mid - centerY);
|
||||
if (dist < nearestDist) {
|
||||
nearestDist = dist;
|
||||
nearestIdx = i;
|
||||
}
|
||||
}
|
||||
return nearestIdx;
|
||||
}
|
||||
function handleWheelStep(type, e) {
|
||||
const refMap = { year: yearColRef, month: monthColRef, day: dayColRef };
|
||||
const el = refMap[type].value;
|
||||
if (!el || isAnimating[type]) return;
|
||||
const direction = e.deltaY > 0 ? 1 : -1;
|
||||
let idx = getCenteredIndexByRect(el);
|
||||
if (type === "year") {
|
||||
idx = clamp(idx + direction, 0, years.value.length - 1);
|
||||
localYear.value = years.value[idx];
|
||||
} else if (type === "month") {
|
||||
idx = clamp(idx + direction, 0, 11);
|
||||
localMonth.value = idx + 1;
|
||||
} else {
|
||||
const dim = daysInMonth(localYear.value, localMonth.value);
|
||||
idx = clamp(idx + direction, 0, dim - 1);
|
||||
localDay.value = idx + 1;
|
||||
}
|
||||
isAnimating[type] = true;
|
||||
isUserScrolling.value = true;
|
||||
el.scrollTo({ top: idx * wheelItemHeight, behavior: "smooth" });
|
||||
setTimeout(() => {
|
||||
isAnimating[type] = false;
|
||||
isUserScrolling.value = false;
|
||||
}, 180);
|
||||
}
|
||||
function handleWheelScroll(type, e) {
|
||||
clearTimeout(scrollTimers[type]);
|
||||
isUserScrolling.value = true;
|
||||
scrollTimers[type] = setTimeout(() => {
|
||||
const el = e.target;
|
||||
const idx = getCenteredIndexByRect(el);
|
||||
if (type === "year") {
|
||||
localYear.value = years.value[clamp(idx, 0, years.value.length - 1)];
|
||||
} else if (type === "month") {
|
||||
localMonth.value = clamp(idx + 1, 1, 12);
|
||||
} else if (type === "day") {
|
||||
const dim = daysInMonth(localYear.value, localMonth.value);
|
||||
localDay.value = clamp(idx + 1, 1, dim);
|
||||
}
|
||||
isUserScrolling.value = false;
|
||||
}, 120);
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
// 以滚轮当前“水平线”居中项为最终值(基于 DOM 位置,避免像素取整误差)
|
||||
if (yearColRef.value) {
|
||||
const idx = clamp(
|
||||
getCenteredIndexByRect(yearColRef.value),
|
||||
0,
|
||||
years.value.length - 1
|
||||
);
|
||||
localYear.value = years.value[idx];
|
||||
}
|
||||
if (monthColRef.value) {
|
||||
const idx = clamp(getCenteredIndexByRect(monthColRef.value) + 1, 1, 12);
|
||||
localMonth.value = idx;
|
||||
}
|
||||
if (dayColRef.value) {
|
||||
const dim = daysInMonth(localYear.value, localMonth.value);
|
||||
const idx = clamp(getCenteredIndexByRect(dayColRef.value) + 1, 1, dim);
|
||||
localDay.value = idx;
|
||||
}
|
||||
// 输出固定为本地日期,不跨时区
|
||||
const payload = {
|
||||
year: localYear.value,
|
||||
month: localMonth.value,
|
||||
day: localDay.value,
|
||||
};
|
||||
emit("update:modelValue", payload);
|
||||
nextTick(() => emit("confirm", payload));
|
||||
}
|
||||
|
||||
nextTick(syncWheelPositions);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.picker-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.picker-panel {
|
||||
width: 311 * 5.12px;
|
||||
background: #fff;
|
||||
border-radius: 8 * 5.12px;
|
||||
box-shadow: 0 3 * 5.12px 14 * 5.12px rgba(0, 0, 0, 0.16);
|
||||
padding: 16 * 5.12px;
|
||||
}
|
||||
.picker-title {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14 * 5.12px;
|
||||
color: #455363;
|
||||
margin-bottom: 16 * 5.12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.picker-columns {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
column-gap: 32 * 5.12px;
|
||||
align-items: stretch;
|
||||
justify-items: stretch;
|
||||
padding: 0;
|
||||
}
|
||||
.center-lines {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 0;
|
||||
}
|
||||
.center-lines .line {
|
||||
position: absolute;
|
||||
left: 16 * 5.12px; /* align with design padding */
|
||||
right: 16 * 5.12px;
|
||||
height: 1px; /* crisp hairline */
|
||||
background: #ededed;
|
||||
}
|
||||
.center-lines .line:first-child {
|
||||
top: 0;
|
||||
}
|
||||
.center-lines .line:last-child {
|
||||
bottom: 0;
|
||||
}
|
||||
.picker-col {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
z-index: 1; /* paint above guide lines */
|
||||
scroll-snap-type: y mandatory;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
.picker-col::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.picker-item {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
color: #9da3ad;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
scroll-snap-align: center;
|
||||
scroll-snap-stop: always;
|
||||
}
|
||||
.year-col .picker-item {
|
||||
justify-content: flex-start;
|
||||
padding-left: 16 * 5.12px;
|
||||
}
|
||||
.month-col .picker-item {
|
||||
justify-content: center;
|
||||
}
|
||||
.day-col .picker-item {
|
||||
justify-content: flex-end;
|
||||
padding-right: 16 * 5.12px;
|
||||
}
|
||||
.picker-item.active {
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
}
|
||||
.picker-actions {
|
||||
margin-top: 16 * 5.12px;
|
||||
}
|
||||
.picker-confirm {
|
||||
width: 100%;
|
||||
height: 44 * 5.12px;
|
||||
background: #ff7bac;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8 * 5.12px;
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14 * 5.12px;
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
@ -1,94 +1,184 @@
|
||||
<template>
|
||||
<div class="historic-data-container" style="margin-bottom: 40px">
|
||||
<div class="historic-data-container">
|
||||
<div class="echarts-container">
|
||||
<customEcharts></customEcharts>
|
||||
</div>
|
||||
|
||||
<div class="header mt-[80px]">
|
||||
<div class="title">Historical Data</div>
|
||||
<div class="filter-container">
|
||||
<!-- <n-dropdown
|
||||
trigger="click"
|
||||
:options="periodOptions"
|
||||
@select="handlePeriodChange"
|
||||
:value="state.selectedPeriod"
|
||||
>
|
||||
<n-button>
|
||||
{{ state.selectedPeriod }}
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown> -->
|
||||
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
:options="durationOptions"
|
||||
@select="handleDurationChange"
|
||||
:value="state.selectedDuration"
|
||||
>
|
||||
<n-button>
|
||||
{{ state.selectedDuration }}
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
<div class="header">
|
||||
<!-- 标题区域 -->
|
||||
<div class="title-section">
|
||||
<div class="title-decoration"></div>
|
||||
<div class="title-text">Historical Data</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<n-data-table
|
||||
:columns="columns"
|
||||
:data="paginatedData"
|
||||
:bordered="false"
|
||||
:single-line="false"
|
||||
:scroll-x="600"
|
||||
/>
|
||||
<div class="filter-container">
|
||||
<span class="range-label">Range</span>
|
||||
<div class="filter-row">
|
||||
<div
|
||||
v-for="option in durationOptions"
|
||||
:key="option.key"
|
||||
class="filter-option"
|
||||
:class="{ active: state.selectedDuration === option.key }"
|
||||
@click="handleDurationChange(option.key)"
|
||||
>
|
||||
{{
|
||||
option.label
|
||||
.replace(" Months", "m")
|
||||
.replace(" Years", "Y")
|
||||
.replace(" Year", "Y")
|
||||
.replace(" to Date", "TD")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- reports-table from annualreports -->
|
||||
<div class="reports-table">
|
||||
<div class="table-container">
|
||||
<div class="table-header">
|
||||
<div
|
||||
class="column"
|
||||
v-for="col in columns"
|
||||
:key="col.key"
|
||||
:style="{
|
||||
width: col.width ? col.width + 'px' : 'auto',
|
||||
flex: col.width ? '0 0 ' + col.width + 'px' : '1 0 116px',
|
||||
'text-align': col.align,
|
||||
}"
|
||||
>
|
||||
{{ col.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="reports-list">
|
||||
<div
|
||||
class="table-row"
|
||||
v-for="(row, index) in paginatedData"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="column"
|
||||
v-for="col in columns"
|
||||
:key="col.key"
|
||||
:style="{
|
||||
width: col.width ? col.width + 'px' : 'auto',
|
||||
flex: col.width ? '0 0 ' + col.width + 'px' : '1 0 116px',
|
||||
'text-align': col.align,
|
||||
}"
|
||||
>
|
||||
<span
|
||||
v-if="col.key === 'change'"
|
||||
:style="{
|
||||
color:
|
||||
parseFloat(row.change) < 0
|
||||
? '#cf3050'
|
||||
: parseFloat(row.change) > 0
|
||||
? '#18a058'
|
||||
: '',
|
||||
}"
|
||||
>
|
||||
{{ row[col.key] }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ row[col.key] }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- pagination-container from annualreports -->
|
||||
<div class="pagination-container">
|
||||
<n-button class="page-btn prev-btn" @click="handlePrevPage">
|
||||
<n-icon><chevron-back-outline /></n-icon>
|
||||
</n-button>
|
||||
<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>
|
||||
|
||||
<div class="page-info mr-[40px]">
|
||||
{{ state.currentPage }} of {{ totalPages }}
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<div class="right-controls">
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
:options="pageSizeOptions"
|
||||
@select="handlePageSizeChange"
|
||||
>
|
||||
<n-button class="rows-dropdown">
|
||||
{{ state.pageSize }} Rows
|
||||
<n-icon><chevron-down-outline /></n-icon>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
|
||||
<n-button class="page-btn next-btn" @click="handleNextPage">
|
||||
<n-icon><chevron-forward-outline /></n-icon>
|
||||
</n-button>
|
||||
<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 4.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, 50, 100, 500, 1000]"
|
||||
:key="size"
|
||||
class="page-size-option"
|
||||
:class="{ active: state.pageSize === size }"
|
||||
@click="handlePageSizeChange(size)"
|
||||
>
|
||||
{{ size }}/page
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination-info">
|
||||
Displaying {{ displayRange.start }} - {{ displayRange.end }} of
|
||||
{{ state.tableData.length }} results
|
||||
</div>
|
||||
|
||||
<div class="back-to-top-link">
|
||||
<!-- <div class="back-to-top-link">
|
||||
<a href="#" @click.prevent="scrollToTop">
|
||||
Back to Top
|
||||
<n-icon><arrow-up-outline /></n-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { NDataTable, NButton, NDropdown, NIcon } from "naive-ui";
|
||||
import { reactive, onMounted, h, computed } from "vue";
|
||||
import { NDropdown, NIcon } from "naive-ui";
|
||||
import { reactive, onMounted, h, computed, ref, watch, onUnmounted } from "vue";
|
||||
import axios from "axios";
|
||||
import {
|
||||
ChevronDownOutline,
|
||||
ChevronBackOutline,
|
||||
ChevronForwardOutline,
|
||||
ArrowUpOutline,
|
||||
} from "@vicons/ionicons5";
|
||||
import { ChevronDownOutline, ArrowUpOutline } from "@vicons/ionicons5";
|
||||
import defaultTableData from "../data";
|
||||
// console.log('defaultTableData', defaultTableData)
|
||||
import customEcharts from "@/components/customEcharts/index.vue";
|
||||
|
||||
// 数据筛选选项
|
||||
@ -103,15 +193,15 @@ const periodOptions = [
|
||||
const durationOptions = [
|
||||
{ label: "3 Months", key: "3 Months" },
|
||||
{ label: "6 Months", key: "6 Months" },
|
||||
{ label: "Year to Date", key: "Year to Date" },
|
||||
{ label: "YTD", key: "Year to Date" },
|
||||
{ label: "1 Year", key: "1 Year" },
|
||||
{ label: "5 Years", key: "5 Years" },
|
||||
{ label: "10 Years", key: "10 Years" },
|
||||
// { label: 'Full History', key: 'Full History', disabled: true },
|
||||
];
|
||||
|
||||
// 分页大小选项
|
||||
const pageSizeOptions = [
|
||||
{ label: "10", key: 10 },
|
||||
{ label: "50", key: 50 },
|
||||
{ label: "100", key: 100 },
|
||||
{ label: "500", key: 500 },
|
||||
@ -123,9 +213,12 @@ const state = reactive({
|
||||
selectedDuration: "6 Months",
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 50,
|
||||
pageSize: 10,
|
||||
gotoPage: 1,
|
||||
});
|
||||
|
||||
const showPageSizeMenu = ref(false);
|
||||
|
||||
// 计算总页数
|
||||
const totalPages = computed(() => {
|
||||
return Math.ceil(state.tableData.length / state.pageSize);
|
||||
@ -145,47 +238,49 @@ const columns = [
|
||||
key: "date",
|
||||
align: "left",
|
||||
fixed: "left",
|
||||
width: 150,
|
||||
width: 152,
|
||||
},
|
||||
{
|
||||
title: "Open",
|
||||
key: "open",
|
||||
align: "center",
|
||||
width: 116,
|
||||
},
|
||||
{
|
||||
title: "High",
|
||||
key: "high",
|
||||
align: "center",
|
||||
width: 116,
|
||||
},
|
||||
{
|
||||
title: "Low",
|
||||
key: "low",
|
||||
align: "center",
|
||||
width: 116,
|
||||
},
|
||||
{
|
||||
title: "Close",
|
||||
key: "close",
|
||||
align: "center",
|
||||
width: 116,
|
||||
},
|
||||
{
|
||||
title: "Adj. Close",
|
||||
key: "adjClose",
|
||||
align: "center",
|
||||
width: 116,
|
||||
},
|
||||
{
|
||||
title: "Change",
|
||||
key: "change",
|
||||
align: "center",
|
||||
render(row) {
|
||||
const value = parseFloat(row.change);
|
||||
const color = value < 0 ? "#ff4d4f" : value > 0 ? "#52c41a" : "";
|
||||
return h("span", { style: { color } }, row.change);
|
||||
},
|
||||
width: 116,
|
||||
},
|
||||
{
|
||||
title: "Volume",
|
||||
key: "volume",
|
||||
align: "center",
|
||||
width: 116,
|
||||
},
|
||||
];
|
||||
|
||||
@ -213,26 +308,62 @@ const handleDurationChange = (key) => {
|
||||
getPageData();
|
||||
};
|
||||
|
||||
const displayRange = computed(() => {
|
||||
const start = (state.currentPage - 1) * state.pageSize + 1;
|
||||
const end = Math.min(
|
||||
state.currentPage * state.pageSize,
|
||||
state.tableData.length
|
||||
);
|
||||
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 handlePrevPage = () => {
|
||||
if (state.currentPage === 1) {
|
||||
return;
|
||||
}
|
||||
state.currentPage--;
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (state.currentPage >= totalPages.value) {
|
||||
return;
|
||||
}
|
||||
state.currentPage++;
|
||||
};
|
||||
|
||||
const handlePageSizeChange = (size) => {
|
||||
state.pageSize = size;
|
||||
state.currentPage = 1; // 重置到第一页
|
||||
};
|
||||
|
||||
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 scrollToTop = () => {
|
||||
// 尝试多种方法
|
||||
@ -248,8 +379,32 @@ const scrollToTop = () => {
|
||||
};
|
||||
onMounted(() => {
|
||||
getPageData();
|
||||
document.addEventListener("click", handleClickOutside);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener("click", handleClickOutside);
|
||||
});
|
||||
|
||||
const handleClickOutside = (event) => {
|
||||
if (!event.target.closest(".page-size-selector")) {
|
||||
showPageSizeMenu.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => state.pageSize,
|
||||
() => {
|
||||
state.currentPage = 1;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => state.currentPage,
|
||||
(newPage) => {
|
||||
state.gotoPage = newPage;
|
||||
}
|
||||
);
|
||||
|
||||
const getPageDefaultData = async () => {
|
||||
try {
|
||||
let url =
|
||||
@ -341,24 +496,25 @@ const getPageData = async () => {
|
||||
String(fromDate.getMonth() + 1).padStart(2, "0") +
|
||||
"-" +
|
||||
String(fromDate.getDate()).padStart(2, "0");
|
||||
// let url = `https://stockanalysis.com/api/symbol/a/OTC-MINM/history?period=${state.selectedPeriod}&range=${range}`
|
||||
let url =
|
||||
"https://common.szjixun.cn/api/stock/history/list?from=" +
|
||||
finalFromDate +
|
||||
"&to=" +
|
||||
toDate;
|
||||
const res = await axios.get(url);
|
||||
// console.error(res)
|
||||
if (res.status === 200) {
|
||||
if (res.data.status === 0) {
|
||||
// 转换为日期格式:"Nov 26, 2024"
|
||||
let resultData = res.data.data.map((item) => {
|
||||
return {
|
||||
date: new Date(item.date).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
}),
|
||||
date: new Date(item.date.replace(/-/g, "/")).toLocaleDateString(
|
||||
"en-US",
|
||||
{
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
}
|
||||
),
|
||||
open: item.open != null ? Number(item.open).toFixed(2) : "",
|
||||
high: item.high != null ? Number(item.high).toFixed(2) : "",
|
||||
low: item.low != null ? Number(item.low).toFixed(2) : "",
|
||||
@ -379,82 +535,83 @@ const getPageData = async () => {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.historic-data-container {
|
||||
padding: 80px;
|
||||
width: 343 * 5.12px;
|
||||
margin: 0 auto;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.title {
|
||||
font-size: 80px;
|
||||
font-size: 40 * 2.5 * 5.12px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
.filter-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 60px;
|
||||
padding: 10px 16px;
|
||||
border-radius: 4px;
|
||||
background-color: #ffffff;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8 * 5.12px;
|
||||
padding: 0 16 * 5.12px;
|
||||
margin-bottom: 32 * 5.12px;
|
||||
|
||||
.page-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 6px 12px;
|
||||
font-size: 92px;
|
||||
|
||||
&.prev-btn {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
&.next-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.range-label {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 0.48 * 5.12px;
|
||||
color: #455363;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
font-size: 72px;
|
||||
color: #374151;
|
||||
.filter-row {
|
||||
width: 311 * 5.12px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 16 * 5.12px;
|
||||
row-gap: 8 * 5.12px;
|
||||
}
|
||||
|
||||
.right-controls {
|
||||
.filter-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 34 * 5.12px;
|
||||
border-radius: 3 * 5.12px;
|
||||
background-color: #efefef;
|
||||
cursor: pointer;
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.4;
|
||||
color: #000000;
|
||||
transition: all 0.2s ease;
|
||||
width: 93 * 5.12px;
|
||||
|
||||
.rows-dropdown {
|
||||
font-size: 72px;
|
||||
&:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #ff7bac;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.back-to-top-link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 56px;
|
||||
margin-top: 16 * 5.12px;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
gap: 5 * 5.12px;
|
||||
color: #2563eb;
|
||||
font-size: 92px;
|
||||
font-size: 20 * 5.12px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
|
||||
@ -463,11 +620,300 @@ const getPageData = async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-data-table) {
|
||||
.n-data-table-td {
|
||||
padding: 12px 8px;
|
||||
}
|
||||
.reports-table {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 16 * 5.12px;
|
||||
box-shadow: 0 * 5.12px 3 * 5.12px 14 * 5.12px 0 * 5.12px rgba(0, 0, 0, 0.16);
|
||||
padding: 16 * 5.12px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar {
|
||||
height: 8 * 5.12px;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 4 * 5.12px;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar-thumb {
|
||||
background: #ccc;
|
||||
border-radius: 4 * 5.12px;
|
||||
}
|
||||
|
||||
.table-container::-webkit-scrollbar-thumb:hover {
|
||||
background: #fff0f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
.column {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 0.48 * 5.12px;
|
||||
color: #455363;
|
||||
padding: 16 * 5.12px;
|
||||
position: relative;
|
||||
font-variant-numeric: tabular-nums; /* 让数字等宽对齐 */
|
||||
}
|
||||
.table-header {
|
||||
display: flex;
|
||||
border-radius: 8 * 5.12px;
|
||||
margin-bottom: 4 * 5.12px;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
|
||||
.column {
|
||||
background: #fff0f5;
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 0.48 * 5.12px;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-radius: 8 * 5.12px;
|
||||
&:hover .column {
|
||||
background: #fff8fb;
|
||||
}
|
||||
|
||||
// &:last-child {
|
||||
// border-bottom: none;
|
||||
// }
|
||||
|
||||
&:nth-child(even) {
|
||||
margin: 4 * 5.12px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.reports-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4 * 5.12px;
|
||||
}
|
||||
|
||||
.table-row .column:not(:last-child)::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
height: 40 * 5.12px;
|
||||
border-right: 1 * 5.12px dashed #e0e0e6;
|
||||
}
|
||||
|
||||
.table-header .column:first-child {
|
||||
border-radius: 8 * 5.12px 0 0 8 * 5.12px;
|
||||
}
|
||||
.table-header .column:last-child,
|
||||
.table-row .column:last-child {
|
||||
border-radius: 0 8 * 5.12px 8 * 5.12px 0;
|
||||
}
|
||||
|
||||
.table-row .column:first-child {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.table-row:hover .column:first-child {
|
||||
background: #fff8fb;
|
||||
}
|
||||
|
||||
// 分页器样式
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 16 * 5.12px;
|
||||
justify-content: flex-end;
|
||||
padding: 0 4 * 5.12px;
|
||||
}
|
||||
|
||||
.pagination-info {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.4;
|
||||
color: #455363;
|
||||
text-align: right;
|
||||
margin-top: 16 * 5.12px;
|
||||
margin-bottom: 16 * 5.12px;
|
||||
padding: 0 4 * 5.12px;
|
||||
}
|
||||
|
||||
.pagination-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8 * 5.12px;
|
||||
}
|
||||
|
||||
.pagination-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8 * 5.12px;
|
||||
}
|
||||
.page-btn {
|
||||
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.4;
|
||||
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 * 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.4;
|
||||
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: 5 * 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.4;
|
||||
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.4;
|
||||
color: #455363;
|
||||
margin-right: 16 * 5.12px;
|
||||
}
|
||||
|
||||
.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.4;
|
||||
color: #455363;
|
||||
text-align: center;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #ff7bac;
|
||||
}
|
||||
}
|
||||
|
||||
.title-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16 * 5.12px;
|
||||
margin-bottom: 32 * 5.12px;
|
||||
margin-top: 43 * 5.12px;
|
||||
padding: 0 16 * 5.12px;
|
||||
}
|
||||
|
||||
.title-decoration {
|
||||
width: 58 * 5.12px;
|
||||
height: 7 * 5.12px;
|
||||
background: #ff7bac;
|
||||
margin: auto 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 24 * 5.12px;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 0.03em;
|
||||
color: #000000;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,59 +1,80 @@
|
||||
<template>
|
||||
<div class="press-releases-page">
|
||||
<n-infinite-scroll :distance="0" @load="doLoadMore">
|
||||
<main class="p-[80px] mx-auto" style="max-width: 100vw; min-width: 285px">
|
||||
<div class="title mb-[24px]">
|
||||
{{ t("press_releases.title") }}
|
||||
</div>
|
||||
<div class="search-container">
|
||||
<n-select
|
||||
:options="state.selectOptions"
|
||||
v-model:value="state.selectedValue"
|
||||
class="search-select"
|
||||
:font-size="72"
|
||||
/>
|
||||
<n-input
|
||||
v-model:value="state.inputValue"
|
||||
type="text"
|
||||
:placeholder="t('press_releases.search.placeholder')"
|
||||
class="search-input"
|
||||
clearable
|
||||
:font-size="72"
|
||||
/>
|
||||
<n-button @click="handleSearch" class="search-button" :font-size="72">
|
||||
{{ t("press_releases.search.button") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div v-for="(item, idx) in state.filterNewsData" :key="idx">
|
||||
<div class="news-item mt-[10px]">
|
||||
<div class="news-item-date">{{ item.date }}</div>
|
||||
<div
|
||||
class="news-item-title text-[#0078d7] cursor-pointer"
|
||||
style="
|
||||
word-break: break-word;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
@click="handleNewClick(item)"
|
||||
>
|
||||
{{ item.title }}
|
||||
<div class="title-section">
|
||||
<div class="title-decoration"></div>
|
||||
<div class="title">
|
||||
{{ t("press_releases.title") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-container">
|
||||
<n-select
|
||||
:options="state.selectOptions"
|
||||
v-model:value="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>
|
||||
<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="click"
|
||||
:disabled="!item.showTooltip"
|
||||
width="trigger"
|
||||
>
|
||||
<n-tooltip trigger="hover" :disabled="true" width="trigger">
|
||||
<template #trigger>
|
||||
<div
|
||||
:ref="(el) => setTitleRef(el, idx)"
|
||||
class="news-item-content"
|
||||
class="news-item-content file-description"
|
||||
style="
|
||||
word-break: break-word;
|
||||
word-break: break-all;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -66,17 +87,118 @@
|
||||
{{ item.summary }}
|
||||
</div>
|
||||
</n-tooltip>
|
||||
<div class="download-section">
|
||||
<div class="news-item-date">{{ item.date }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</n-infinite-scroll>
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import customDefaultPage from "@/components/customDefaultPage/index.vue";
|
||||
import { reactive, onMounted, watch, nextTick, ref } from "vue";
|
||||
import { NSelect, NInput, NButton, NInfiniteScroll, NTooltip } from "naive-ui";
|
||||
import {
|
||||
reactive,
|
||||
onMounted,
|
||||
watch,
|
||||
nextTick,
|
||||
ref,
|
||||
computed,
|
||||
onUnmounted,
|
||||
} from "vue";
|
||||
import { NSelect, NInput, NButton, NTooltip } from "naive-ui";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import axios from "axios";
|
||||
|
||||
@ -97,32 +219,16 @@ const state = reactive({
|
||||
}),
|
||||
], //下拉选项
|
||||
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: [],
|
||||
loading: false, //是否正在加载数据
|
||||
hasMore: true, //是否还有更多数据
|
||||
currentPage: 1, //当前页码
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
gotoPage: 1,
|
||||
});
|
||||
|
||||
const showPageSizeMenu = ref(false);
|
||||
|
||||
const titleRefs = ref([]);
|
||||
|
||||
const setTitleRef = (el, idx) => {
|
||||
@ -142,14 +248,18 @@ const checkAllTitleOverflow = () => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// state.filterNewsData = state.newsData;
|
||||
getPressReleasesDisplay();
|
||||
document.addEventListener("click", handleClickOutside);
|
||||
|
||||
nextTick(() => {
|
||||
checkAllTitleOverflow();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener("click", handleClickOutside);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => state.filterNewsData,
|
||||
() => {
|
||||
@ -162,93 +272,68 @@ watch(
|
||||
|
||||
// 获取新闻列表
|
||||
const getPressReleasesDisplay = () => {
|
||||
state.loading = true;
|
||||
let url = "https://erpapi.fiee.com/api/fiee/pressreleases/display";
|
||||
let params = {
|
||||
query: state.inputValue,
|
||||
page: state.currentPage,
|
||||
pageSize: 10,
|
||||
pageSize: state.pageSize,
|
||||
timeStart: state.selectedValue
|
||||
? state.selectedValue === "all_years"
|
||||
? null
|
||||
: new Date(state.selectedValue).getTime()
|
||||
: null,
|
||||
};
|
||||
// console.log(params)
|
||||
axios.post(url, params).then((res) => {
|
||||
// console.log(res)
|
||||
if (res.status === 200) {
|
||||
if (res.data.status === 0) {
|
||||
res.data.data?.data?.forEach((item) => {
|
||||
item.date = new Date(item.createdAt).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
axios
|
||||
.post(url, params)
|
||||
.then((res) => {
|
||||
if (res.status === 200) {
|
||||
if (res.data.status === 0) {
|
||||
res.data.data?.data?.forEach((item) => {
|
||||
item.date = new Date(item.createdAt).toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
});
|
||||
});
|
||||
if (state.currentPage === 1) {
|
||||
state.filterNewsData = res.data.data?.data || [];
|
||||
} else {
|
||||
state.filterNewsData = [
|
||||
...state.filterNewsData,
|
||||
...(res.data.data?.data || []),
|
||||
];
|
||||
}
|
||||
if (state.filterNewsData.length < (res.data.data?.total || 0)) {
|
||||
state.hasMore = true;
|
||||
} else {
|
||||
state.hasMore = false;
|
||||
state.total = res.data.data?.total || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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;
|
||||
})
|
||||
.finally(() => {
|
||||
state.loading = 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 来实现自动筛选
|
||||
watch(
|
||||
() => [state.selectedValue, state.inputValue],
|
||||
() => {
|
||||
// handleFilter();
|
||||
state.currentPage = 1;
|
||||
getPressReleasesDisplay();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => state.pageSize,
|
||||
() => {
|
||||
state.currentPage = 1;
|
||||
getPressReleasesDisplay();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => state.currentPage,
|
||||
(newPage) => {
|
||||
state.gotoPage = newPage;
|
||||
getPressReleasesDisplay();
|
||||
}
|
||||
);
|
||||
|
||||
const handleSearch = () => {
|
||||
// 手动触发筛选(保留这个函数以保持兼容性)
|
||||
// handleFilter();
|
||||
state.currentPage = 1;
|
||||
getPressReleasesDisplay();
|
||||
// console.log("筛选结果:", state.filterNewsData);
|
||||
};
|
||||
|
||||
const handleNewClick = (item) => {
|
||||
@ -260,102 +345,468 @@ const handleNewClick = (item) => {
|
||||
});
|
||||
};
|
||||
|
||||
//加载更多数据
|
||||
const doLoadMore = () => {
|
||||
if (!state.hasMore || state.loading) {
|
||||
return;
|
||||
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;
|
||||
}
|
||||
// console.log('触底了')
|
||||
state.loading = true;
|
||||
state.currentPage++;
|
||||
getPressReleasesDisplay().finally(() => {
|
||||
state.loading = false;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.press-releases-page {
|
||||
width: 343 * 5.12px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
}
|
||||
.title-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16 * 5.12px;
|
||||
padding: 0 16 * 5.12px;
|
||||
}
|
||||
.title-decoration {
|
||||
width: 58 * 5.12px;
|
||||
height: 7 * 5.12px;
|
||||
background: #ff7bac;
|
||||
margin-top: 43 * 5.12px;
|
||||
}
|
||||
.title {
|
||||
font-size: 113px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
font-size: 32 * 5.12px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
margin-bottom: 24px;
|
||||
margin-top: 32 * 5.12px;
|
||||
margin-bottom: 20 * 5.12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: #f6f7f9;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
gap: 16px;
|
||||
justify-content: flex-start;
|
||||
gap: 16 * 5.12px;
|
||||
padding: 0 16 * 5.12px;
|
||||
}
|
||||
|
||||
.search-select {
|
||||
width: 1000px;
|
||||
:deep(.n-base-selection) {
|
||||
padding: 4px 0;
|
||||
}
|
||||
width: 100%;
|
||||
height: 34 * 5.12px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 34 * 5.12px;
|
||||
padding: 7 * 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.375em;
|
||||
letter-spacing: 0.48 * 5.12px;
|
||||
color: #455363;
|
||||
|
||||
&::placeholder {
|
||||
color: #b6b6b6;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-input) {
|
||||
.n-input__input {
|
||||
padding: 4px 0;
|
||||
border-radius: 4px;
|
||||
padding: 4 * 5.12px 0;
|
||||
// border: 1*5.12px solid #ccc;
|
||||
border-radius: 4 * 5.12px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-select) {
|
||||
.n-select__input {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 8 * 5.12px 12 * 5.12px;
|
||||
border: 1 * 5.12px solid #ccc;
|
||||
border-radius: 4 * 5.12px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-button) {
|
||||
width: 260px;
|
||||
padding: 20px 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.news-item {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.news-item-date {
|
||||
font-size: 72px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.news-item-title {
|
||||
font-size: 92px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.news-item-content {
|
||||
font-size: 72px;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
padding: 20 * 5.12px 16 * 5.12px;
|
||||
border-radius: 4 * 5.12px;
|
||||
}
|
||||
.search-button {
|
||||
width: 100%;
|
||||
height: 34 * 5.12px;
|
||||
padding: 7 * 5.12px 12 * 5.12px;
|
||||
background: #ff7bac;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 3 * 5.12px;
|
||||
cursor: pointer;
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.375em;
|
||||
letter-spacing: 0.48 * 5.12px;
|
||||
&:hover {
|
||||
background: #ff7bac;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.reports-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4 * 5.12px;
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
padding: 0 16 * 5.12px;
|
||||
margin-top: 40 * 5.12px;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
border-radius: 8 * 5.12px;
|
||||
|
||||
// &:last-child {
|
||||
// .separator-line {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16 * 5.12px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16 * 5.12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.news-item-title {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.375em;
|
||||
letter-spacing: 0.48 * 5.12px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
margin-left: auto;
|
||||
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: 0;
|
||||
padding: 0;
|
||||
margin-top: 8 * 5.12px;
|
||||
}
|
||||
|
||||
.news-item-date {
|
||||
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;
|
||||
}
|
||||
|
||||
.download-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
padding: 4 * 5.12px 0 * 5.12px;
|
||||
}
|
||||
|
||||
.separator-line {
|
||||
width: 100%;
|
||||
height: 1 * 5.12px;
|
||||
background: repeating-linear-gradient(
|
||||
to right,
|
||||
#e6eaee 0 * 5.12px,
|
||||
#e6eaee 2 * 5.12px,
|
||||
transparent 2 * 5.12px,
|
||||
transparent 4 * 5.12px
|
||||
);
|
||||
margin-top: 16 * 5.12px;
|
||||
}
|
||||
|
||||
// 分页器样式
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 40 * 5.12px 0;
|
||||
justify-content: flex-end;
|
||||
padding: 0 16 * 5.12px;
|
||||
flex-wrap: wrap;
|
||||
gap: 16 * 5.12px;
|
||||
}
|
||||
|
||||
.pagination-info {
|
||||
font-family: "PingFang SC", sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14 * 5.12px;
|
||||
line-height: 1.4375em;
|
||||
color: #455363;
|
||||
text-align: right;
|
||||
margin-bottom: 30 * 5.12px;
|
||||
padding: 0 16 * 5.12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.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 {
|
||||
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-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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user