Add new date filter

This commit is contained in:
johnathan 2025-06-26 17:45:56 +08:00
parent 95afadbec5
commit 2a52150c4a
9 changed files with 64 additions and 42 deletions

View File

@ -65,7 +65,7 @@ const emit = defineEmits<{
</template> </template>
导出 导出
</n-button> </n-button>
<n-popover v-if="$slots.filter" trigger="hover" placement="bottom"> <n-popover v-if="$slots.filter" trigger="hover" placement="bottom" :duration="500">
<template #trigger> <template #trigger>
<n-button type="default" ghost :round="round" :size="size"> <n-button type="default" ghost :round="round" :size="size">
<template #icon> <template #icon>

View File

@ -129,7 +129,7 @@ const handleExport = () => {
<n-scrollbar :style="{ maxHeight: `${height * 0.85}px`, minHeight: `${height * 0.85}px` }"> <n-scrollbar :style="{ maxHeight: `${height * 0.85}px`, minHeight: `${height * 0.85}px` }">
<div class="review-list-container" :style="{ minHeight: `${height * 0.8}px` }"> <div class="review-list-container" :style="{ minHeight: `${height * 0.8}px` }">
<template v-if="view.data.length > 0" v-for="review in view.data"> <template v-if="view.data.length > 0" v-for="review in view.data">
<review-card :model="review" /> <amazon-review-card :model="review" />
<div style="height: 7px" /> <div style="height: 7px" />
</template> </template>
<template v-else> <template v-else>

View File

@ -1,6 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { GlobalThemeOverrides } from 'naive-ui'; import type { GlobalThemeOverrides } from 'naive-ui';
import Options from './Options.vue'; import Options from './Options.vue';
import { zhCN, dateZhCN } from 'naive-ui';
const theme: GlobalThemeOverrides = { const theme: GlobalThemeOverrides = {
common: { common: {
@ -14,7 +15,7 @@ const theme: GlobalThemeOverrides = {
<template> <template>
<!-- Naive UI Wrapper--> <!-- Naive UI Wrapper-->
<n-config-provider :theme-overrides="theme"> <n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme-overrides="theme">
<n-loading-bar-provider> <n-loading-bar-provider>
<n-message-provider> <n-message-provider>
<n-dialog-provider> <n-dialog-provider>

View File

@ -6,8 +6,8 @@ import { useRouter } from 'vue-router';
const router = useRouter(); const router = useRouter();
const options: { label: string; value: 'amazon' | 'homedepot' }[] = [ const options: { label: string; value: 'amazon' | 'homedepot' }[] = [
{ label: 'Amazon', value: 'amazon' }, { label: 'Amazon Search&Detail', value: 'amazon' },
{ label: 'Homedepot', value: 'homedepot' }, { label: 'Homedepot Detail', value: 'homedepot' },
]; ];
watch(site, (newVal) => { watch(site, (newVal) => {

View File

@ -9,36 +9,16 @@ const message = useMessage();
const modal = useModal(); const modal = useModal();
const cloudExporter = useCloudExporter(); const cloudExporter = useCloudExporter();
const defaultFilter = { const filter = ref<{
keywords: undefined as string | undefined, keywords?: string;
search: '', search?: string;
detailOnly: false, detailOnly?: boolean;
}; searchDateRange?: [number, number];
const filter = reactive(defaultFilter); detailDateRange?: [number, number];
const filterFormItems = computed(() => { }>({});
const records = allItems.value;
return [
{
prop: 'keywords',
label: '关键词',
type: 'select',
params: {
options: [
...records.reduce((o, c) => {
c.keywords && o.add(c.keywords);
return o;
}, new Set<string>()),
].map((opt) => ({
label: opt,
value: opt,
})),
},
},
];
});
const onFilterReset = () => { const onFilterReset = () => {
Object.assign(filter, defaultFilter); filter.value = {};
}; };
const columns: TableColumn[] = [ const columns: TableColumn[] = [
@ -108,7 +88,7 @@ const columns: TableColumn[] = [
width: '80vw', width: '80vw',
height: '85vh', height: '85vh',
}, },
content: () => <review-preview asin={asin} />, content: () => <amazon-review-preview asin={asin} />,
}); });
}, },
}, },
@ -190,9 +170,9 @@ const getItemHeaders = () => {
}; };
const filteredData = computed(() => { const filteredData = computed(() => {
const { search, detailOnly, keywords } = filter; const { search, detailOnly, keywords, searchDateRange, detailDateRange } = filter.value;
let data = toRaw(allItems.value); let data = toRaw(allItems.value);
if (search.trim() !== '') { if (search && search.trim() !== '') {
data = data.filter((r) => { data = data.filter((r) => {
return [r.title, r.asin, r.keywords].some((field) => return [r.title, r.asin, r.keywords].some((field) =>
field?.toLowerCase().includes(search.toLowerCase()), field?.toLowerCase().includes(search.toLowerCase()),
@ -205,6 +185,20 @@ const filteredData = computed(() => {
if (keywords) { if (keywords) {
data = data.filter((r) => r.keywords === keywords); data = data.filter((r) => r.keywords === keywords);
} }
if (searchDateRange) {
const start = dayjs(searchDateRange[0]);
const end = dayjs(searchDateRange[1]);
data = data.filter(
(r) => dayjs(r.createTime).diff(start) >= 0 && dayjs(r.createTime).diff(end) <= 0,
);
}
if (detailDateRange) {
const start = dayjs(detailDateRange[0]);
const end = dayjs(detailDateRange[1]);
data = data.filter(
(r) => dayjs(r.createTime).diff(start) >= 0 && dayjs(r.timestamp).diff(end) <= 0,
);
}
return data; return data;
}); });
@ -351,14 +345,40 @@ const handleClearData = async () => {
<template #filter> <template #filter>
<div class="filter-section"> <div class="filter-section">
<div class="filter-title">筛选器</div> <div class="filter-title">筛选器</div>
<n-form :model="filter" label-placement="left"> <n-form
<n-form-item v-for="item in filterFormItems" :label="item.label"> :model="filter"
label-placement="left"
label-align="center"
label-width="100"
>
<n-form-item label="关键词">
<n-select <n-select
v-if="item.type === 'select'"
placeholder="" placeholder=""
v-model:value="filter.keywords" v-model:value="filter.keywords"
clearable clearable
:options="item.params.options" :options="
Array.from(allItems.reduce((o, c) => {
c.keywords && o.add(c.keywords);
return o;
}, new Set<string>()),
).map((opt) => ({
label: opt,
value: opt,
}))"
/>
</n-form-item>
<n-form-item label="日期(搜索页)">
<n-date-picker
type="daterange"
clearable
v-model:value="filter.searchDateRange"
/>
</n-form-item>
<n-form-item label="日期(详情页)">
<n-date-picker
type="daterange"
clearable
v-model:value="filter.detailDateRange"
/> />
</n-form-item> </n-form-item>
</n-form> </n-form>
@ -425,7 +445,7 @@ const handleClearData = async () => {
} }
.filter-section { .filter-section {
min-width: 250px; max-width: 360px;
.filter-title { .filter-title {
font-size: 18px; font-size: 18px;

View File

View File

@ -3,6 +3,7 @@ import type { GlobalThemeOverrides } from 'naive-ui';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useCurrentUrl } from '~/composables/useCurrentUrl'; import { useCurrentUrl } from '~/composables/useCurrentUrl';
import { site } from '~/logic/storages/global'; import { site } from '~/logic/storages/global';
import { zhCN, dateZhCN } from 'naive-ui';
const theme: GlobalThemeOverrides = { const theme: GlobalThemeOverrides = {
common: { common: {
@ -37,7 +38,7 @@ watch(currentUrl, (newVal) => {
<template> <template>
<!-- Naive UI Wrapper--> <!-- Naive UI Wrapper-->
<n-config-provider :theme-overrides="theme"> <n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme-overrides="theme">
<n-loading-bar-provider> <n-loading-bar-provider>
<n-message-provider> <n-message-provider>
<n-dialog-provider> <n-dialog-provider>