div 選單關連模糊搜尋選單 - daniel-qa/Vue GitHub Wiki

div 選單關連模糊搜尋選單

邏輯流程圖

  • 1 .用戶點擊學區 → setActive(index) 設置選中學區 → activeIndex 更新。

  • 2 .計算屬性 filteredSubItems 根據 activeIndex 和 searchQuery 過濾學校列表。

   這裡使用 ref,動態響應數據,當改變 activeIndex 時,觸發 computed
   
   計算公式 filteredSubItems ,進行數據的過濾,更新
  • 3 .第二級菜單渲染學校列表。

用戶選擇學校 → setActive2(subIndex) 設置選中的學校。

加入接收名單 → addToColumn3() 將選中學校推入 column3Items。

<template>
    <el-row style="background-color: #FFFFFF;">
        <!-- 第一列:父级菜单 -->
        <el-col :span="8">
            <div class="list">
                <div v-for="(item, index) in items"
                     :key="index"
                     :class="{'active': activeIndex === index}"
                     class="list-item"
                     @click="setActive(index)">
                    {{ item.name }}
                    {{ item.scCnt }} 校
                    {{ item.tchCnt }} 人
                    <el-button size="small" @click.stop="addToColumn3(item, 0)" type="success">加入</el-button>
                </div>
            </div>
        </el-col>

        <!-- 第二列:子级菜单 -->
        <el-col :span="8">
            <div v-if="activeIndex !== null" class="list2">

                <!-- 搜尋框 -->
                <el-input v-model="searchQuery"
                          placeholder="搜尋子項目..."
                          size="medium"
                          clearable
                          style="margin-bottom: 10px;"></el-input>

                <!-- 学校列表 -->
                <div class="list" style="height: 450px;">

                    <div v-for="(subItem, subIndex) in filteredSubItems"
                         :key="subIndex"
                         :class="{'active': activeIndex2 === subIndex}"
                         class="list-item"
                         @click="setActive2(subIndex)">
                        {{ subItem.name }}
                        {{ subItem.tchCnt }} 人
                        <el-button size="small" @click.stop="addToColumn3(subItem)" type="success">加入</el-button>
                    </div>

                </div>

            </div>
        </el-col>

        <!-- 第三列:展示加入的项 -->
        <el-col :span="8">
            <el-card v-if="false" style="height:600px;">
                <template #header>
                    <span class="head-text">接收名單</span>
                </template>

                <div>
                    <el-scrollbar style="height: 300px; width:100% ;">
                        <el-list style="display: flex; flex-direction: column;">
                            <el-list-item v-for="(item, index) in column3Items"
                                          :key="index"
                                          class="el-list-item">
                                {{ item.name }}
                                {{ item.tchCnt }} 人


                                <div>
                                    <!-- 标签部分 -->
                                    <el-tag style="background-color: #409eff; color: white;">
                                        {{ item.receiveType === 3 ? 'ID' : '学校' }}
                                    </el-tag>

                                    <el-button size="small" @click.stop="removeFromColumn3(index)">
                                        <el-icon>
                                            <CloseBold />
                                        </el-icon>
                                    </el-button>
                                </div>
                            </el-list-item>
                        </el-list>
                    </el-scrollbar>
                </div>
            </el-card>
        </el-col>
    </el-row>

    <div v-if="false">
        <!-- 获取学区数据按钮 -->
        <el-button type="primary" @click="fetchData">获取学区信息</el-button>
    </div>
</template>

<script setup>
import { ref, computed, onMounted, provide,inject } from "vue";
import { ElMessage } from "element-plus";
import axios from "axios";
import { CloseBold } from "@element-plus/icons-vue";

// 动态获取的学区和学校数据
const items = ref([]); // 学区列表(父级菜单)
const subItems = ref([]); // 对应的学校列表(子级菜单)
const scCntitems = ref([]); // 學區的校數列表(父级菜单數據)
const tchCntitems = ref([]); // 學區的學校人數(父级菜单數據)


// 选中状态
const activeIndex = ref(null); // 当前选中的学区
const activeIndex2 = ref(null); // 当前选中的学校
const searchQuery = ref(""); // 搜索框内容


// 从父组件注入的接收名单和更新方法
const column3Items = inject("column3Items", ref([])); // 接收名單



// 过滤子级菜单项(学校)
// filteredSubItems 是一个 计算属性,当 activeIndex 或 searchQuery 更新时会自动重新计算。
const filteredSubItems = computed(() => {

    // 如果没有选中任何学区,返回空数组
    if (activeIndex.value === null) return [];

    

    // 获取当前选中的学区的学校列表
    // 如果当前学区没有学校数据,则返回一个空数组
    const currentSubItems = subItems.value[activeIndex.value] || [];

    //debugger;

    // 根据搜索框的内容过滤学校列表
    // 使用 toLowerCase() 进行不区分大小写的匹配
    return currentSubItems.filter((item) =>
        item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
    );
});

const setActive = (index) => {
    activeIndex.value = index; // 设置当前选中的学区索引
    activeIndex2.value = null; // 重置第二级子菜单的选中状态
    searchQuery.value = "";    // 清空子菜单的搜索框
};


// 选中学校
const setActive2 = (index) => {
    activeIndex2.value = index;
};

// 添加到第三列 (响应式触发更新)
    const addToColumn3 = (item) => {

        column3Items.value.push(item);
    
    //if (!column3Items.value.includes(item)) {
    //    column3Items.value.push(item);
    //    ElMessage.success(`${item} 已加入接收名單`);
    //} else {
    //    ElMessage.warning(`${item} 已存在接收名單中`);
    //}
};


// 从第三列移除
const removeFromColumn3 = (index) => {
    column3Items.value.splice(index, 1);
};

// 获取学区和学校数据
const fetchData = async () => {

    //設定 show 學校列表
    const requestData = { showSchool: true };  

    try {
        const response = await axios.post(
            "https://localhost:5001/notice/get-areas",
            requestData
        );

        const { state, result } = response.data;

        if (state === 200) {

            // 更新整合后的父级菜单数据
            items.value = result.map((area) => ({
                name: area.name,
                scCnt: area.scCnt,
                tchCnt: area.tchCnt,
                receiveType: 0, // 0 學區,1 學校, 2 地理資訊
            }));

            //// 更新子级菜单(学校)
            //subItems.value = result.map((area) =>
            //    area.schools.map((school) => school.name)
            //
            //);

            // schools ,是Array欄位名稱

            // 更新子级菜单(学校),存储完整信息
            subItems.value = result.map((area) =>
                area.schools.map((school) => ({
                    id: school.id,
                    name: school.name,
                    tchCnt: school.tchCnt,
                    receiveType: 1, // 0 學區,1 學校, 2 地理資訊
                }))
            );


            //debugger;

            console.log("学区信息获取成功!");

            // ElMessage.success("学区信息获取成功!");
            console.log("学区信息获取成功!");
        } else {
            ElMessage.error("获取学区数据失败,请稍后重试!");
        }
    } catch (error) {
        console.error("请求失败:", error);
        ElMessage.error("网络错误,请检查后重试!");
    }
};

// 页面加载时自动获取数据
onMounted(fetchData);
</script>

<style scoped>
/* 样式与原程序保持一致 */
.list {
    width: 100%;
    height: 650px;
    border: 1px solid #ccc;
    padding: 10px;
    overflow-y: auto;
}

.list2 {
    width: 100%;
    height: 650px;
    border: 1px solid #ccc;
    padding: 10px;
    /*overflow-y: auto;  只差在沒有scroll */
}

.list-item {
    min-height: 50px;
    max-height: 100px;
    line-height: 50px;
    padding: 0 10px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.list-item:hover {
    background-color: #f0f0f0;
}

.list-item.active {
    background-color: #409eff;
    color: white;
}

.head-text {
    font-weight: bold;
    font-size: 18px;
}

.el-list-item {
    padding: 5px 10px !important;
    line-height: 1.5 !important;
    height: auto !important;
    display: flex;
    justify-content: space-between;
}
</style>
⚠️ **GitHub.com Fallback** ⚠️