2025-04-22 10:22:33 +08:00

332 lines
8.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="wh-full">
<!-- Remove :filters and @filter-change -->
<BasicListLayout @register="register">
<!-- Add #top slot for filters -->
<template #top>
<view class="filter-section">
<!-- Group Filter (Assuming 'group' key exists) -->
<view class="filter-item" @click="openFilterPopup('group')">
<text>全部分组</text>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<!-- Sending Department Filter -->
<view class="filter-item" @click="openFilterPopup('sendingDept')">
<text>发文部门</text>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<!-- Receiving Department Filter -->
<view class="filter-item" @click="openFilterPopup('receivingDept')">
<text>收文部门</text>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</view>
</template>
<!-- Define how each item is displayed using the slot -->
<template v-slot:default="{ data }">
<view
class="document-item white-bg-color r-md p-15 mb-15"
@click="goToDetail(data.id)"
>
<view class="item-title font-bold text-lg mb-5">{{
data.title
}}</view>
<view class="item-meta color-9">
<text>发文{{ data.sendingDept }} {{ data.publishDate }}</text>
<text>收文{{ data.receivingDept }}</text>
</view>
</view>
</template>
</BasicListLayout>
<!-- Filter Popup -->
<uni-popup ref="filterPopupRef" type="bottom" background-color="#fff">
<view class="popup-content">
<view class="popup-header">
<text>{{ currentFilterTitle }}</text>
<uni-icons
type="closeempty"
size="20"
@click="closeFilterPopup"
></uni-icons>
</view>
<scroll-view scroll-y class="popup-options">
<view
class="option-item"
v-for="option in currentFilterOptions"
:key="option.value"
:class="{ active: isOptionSelected(option) }"
@click="selectFilterOption(option)"
>
{{ option.label }}
</view>
</scroll-view>
</view>
</uni-popup>
</view>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from "vue";
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
// Placeholder types - replace with actual imports if found
interface FilterOption {
label: string;
value: string | number | null;
}
interface FilterConfig {
label: string;
key: string;
options: FilterOption[];
}
type Filters = FilterConfig[];
// Define the structure for a document item
interface DocumentItem {
id: string;
title: string;
sendingDept: string;
receivingDept: string;
publishDate: string;
// Add other relevant fields as needed
}
const mockTodoList = [
{
id: "1",
title: "公文1",
sendingDept: "办公室1",
receivingDept: "教务处1",
publishDate: "2024-01-01",
},
];
const testList = async (param: any): Promise<Requests<any>> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ message: "测试", resultCode: 1, rows: mockTodoList });
}, 1000);
});
};
const [register, { reload, setParam }] = useLayout({
api: testList,
componentProps: {},
});
// --- Event Handlers ---
const goToDetail = (id: string) => {
console.log("Navigating to detail for ID:", id);
uni.navigateTo({
url: `/pages/view/routine/GongWenLiuZhuan/detail?id=${id}`,
});
};
// --- Filter Popup Methods ---
const openFilterPopup = (type: "group" | "sendingDept" | "receivingDept") => {
currentFilterType.value = type;
filterPopupRef.value?.open();
};
const closeFilterPopup = () => {
filterPopupRef.value?.close();
};
const selectFilterOption = (option: FilterOption) => {
let paramsToSet: Record<string, any> = {};
switch (currentFilterType.value) {
case "group":
selectedGroup.value = option;
paramsToSet = { group: option.value };
break;
case "sendingDept":
selectedSendingDept.value = option;
paramsToSet = { sendingDept: option.value };
break;
case "receivingDept":
selectedReceivingDept.value = option;
paramsToSet = { receivingDept: option.value };
break;
}
setParam(paramsToSet);
reload(true); // Reload from page 1
closeFilterPopup();
};
// --- Filter State ---
const groups = ref<FilterOption[]>([
{ label: "全部分组", value: null },
{ label: "分组A", value: "groupA" },
{ label: "分组B", value: "groupB" },
]);
const sendingDepts = ref<FilterOption[]>([
{ label: "发文部门", value: null },
{ label: "办公室1", value: "办公室1" },
{ label: "办公室2", value: "办公室2" },
{ label: "办公室3", value: "办公室3" },
{ label: "办公室4", value: "办公室4" },
{ label: "办公室5", value: "办公室5" },
]);
const receivingDepts = ref<FilterOption[]>([
{ label: "收文部门", value: null },
{ label: "教务处1", value: "教务处1" },
{ label: "教务处2", value: "教务处2" },
{ label: "教务处3", value: "教务处3" },
]);
// --- Filter State ---
const selectedGroup = ref<FilterOption | null>(groups.value[0]);
const selectedSendingDept = ref<FilterOption | null>(sendingDepts.value[0]);
const selectedReceivingDept = ref<FilterOption | null>(receivingDepts.value[0]);
const filterPopupRef = ref<any>(null);
const currentFilterType = ref<"group" | "sendingDept" | "receivingDept" | null>(
null
);
// --- Computed Properties for Popup ---
const currentFilterOptions = computed(() => {
switch (currentFilterType.value) {
case "group":
return groups.value;
case "sendingDept":
return sendingDepts.value;
case "receivingDept":
return receivingDepts.value;
default:
return [];
}
});
const currentFilterTitle = computed(() => {
switch (currentFilterType.value) {
case "group":
return "选择分组";
case "sendingDept":
return "选择发文部门";
case "receivingDept":
return "选择收文部门";
default:
return "选择选项";
}
});
const isOptionSelected = (option: FilterOption) => {
switch (currentFilterType.value) {
case "group":
return selectedGroup.value?.value === option.value;
case "sendingDept":
return selectedSendingDept.value?.value === option.value;
case "receivingDept":
return selectedReceivingDept.value?.value === option.value;
default:
return false;
}
};
</script>
<style lang="scss" scoped>
.document-item {
// Add specific styles for document items if needed
cursor: pointer; // Indicate items are clickable
transition: background-color 0.2s ease;
&:hover {
background-color: #f9f9f9; // Slight hover effect
}
}
.item-title {
// Style for the title
}
.item-meta {
// Style for the metadata line
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
font-size: 24rpx;
}
.filter-section {
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 30rpx;
background-color: #ffffff;
border-bottom: 1rpx solid #e0e0e0;
position: sticky;
top: 0; // Adjust if necessary based on NavBar height
z-index: 10;
.filter-item {
display: flex;
align-items: center;
font-size: 28rpx;
color: #333;
padding: 10rpx;
cursor: pointer;
text {
margin-right: 8rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180rpx; // Adjust width as needed
}
uni-icons {
color: #999;
}
}
}
.popup-content {
background-color: #fff;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
padding: 20rpx;
padding-bottom: 40rpx;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 10rpx;
font-size: 32rpx;
font-weight: bold;
border-bottom: 1rpx solid #eee;
margin-bottom: 10rpx;
}
.popup-options {
max-height: 60vh;
}
.option-item {
padding: 25rpx 20rpx;
font-size: 28rpx;
color: #333;
border-bottom: 1rpx solid #f5f5f5;
cursor: pointer;
&:last-child {
border-bottom: none;
}
&.active {
color: #409eff;
font-weight: bold;
}
&:hover {
background-color: #f9f9f9;
}
}
</style>