2025-05-21 11:24:53 +08:00
|
|
|
<template>
|
2025-08-28 03:35:18 +08:00
|
|
|
<div class="select-container" v-loading.fullscreen.lock="fullscreenLoading">
|
2025-05-21 11:24:53 +08:00
|
|
|
<label for="projectSelect" class="select-label">项目列表:</label>
|
|
|
|
<el-select
|
|
|
|
id="projectSelect"
|
|
|
|
v-model="selectedProjectId"
|
|
|
|
placeholder="全部工程项目"
|
|
|
|
clearable
|
|
|
|
filterable
|
|
|
|
@change="handleSelect"
|
|
|
|
style="width: 150px; margin-right: 20px"
|
|
|
|
>
|
|
|
|
<el-option v-for="project in projects" :key="project.id" :label="project.name" :value="project.id" />
|
|
|
|
</el-select>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
import { ref, computed, watch } from 'vue';
|
|
|
|
import { useUserStore } from '@/store/modules/user';
|
|
|
|
import { getProjectTeam } from '@/utils/projectTeam';
|
2025-08-28 03:35:18 +08:00
|
|
|
import router, { resetRouter } from '@/router';
|
|
|
|
import usePermissionStore from '@/store/modules/permission';
|
|
|
|
import { isHttp } from '@/utils/validate';
|
|
|
|
import { changeProject } from '@/api/project/project';
|
|
|
|
const fullscreenLoading = ref(false);
|
|
|
|
const route = useRoute();
|
2025-05-21 11:24:53 +08:00
|
|
|
const userStore = useUserStore();
|
|
|
|
const projects = computed(() => [
|
|
|
|
// { id: '', name: '全部工程项目' }, // 添加空选项
|
|
|
|
...userStore.projects
|
|
|
|
]);
|
2025-08-28 03:35:18 +08:00
|
|
|
const proxy = getCurrentInstance()?.proxy as any;
|
2025-05-21 11:24:53 +08:00
|
|
|
|
|
|
|
const selectedProjectId = ref(userStore.selectedProject?.id || '');
|
|
|
|
|
|
|
|
// 监听 userStore.selectedProject 变化,更新 selectedProjectId
|
|
|
|
watch(
|
|
|
|
() => userStore.selectedProject,
|
|
|
|
(newProject) => {
|
|
|
|
selectedProjectId.value = newProject?.id ?? ''; // 避免 undefined 导致 placeholder 显示
|
|
|
|
},
|
|
|
|
{ deep: true }
|
|
|
|
);
|
|
|
|
|
2025-08-28 03:35:18 +08:00
|
|
|
/** 切换项目逻辑 */
|
|
|
|
const handleSelect = async (projectId: string) => {
|
|
|
|
proxy.$cache.local.setJSON('isCheckRole', 'true');
|
|
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
|
const permissionStore = usePermissionStore();
|
2025-05-21 11:24:53 +08:00
|
|
|
const selectedProject = projects.value.find((p) => p.id === projectId);
|
2025-08-28 03:35:18 +08:00
|
|
|
if (!selectedProject) return;
|
|
|
|
const loadingInstance = ElLoading.service({
|
|
|
|
lock: true,
|
|
|
|
text: '项目切换中...',
|
|
|
|
background: 'rgba(0, 0, 0, 0.7)'
|
|
|
|
});
|
2025-08-28 20:10:46 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
if (loadingInstance && loadingInstance.visible) {
|
|
|
|
loadingInstance.close();
|
|
|
|
}
|
|
|
|
}, 3000);
|
2025-08-28 03:35:18 +08:00
|
|
|
await changeProject(projectId);
|
2025-08-28 20:10:46 +08:00
|
|
|
console.log('切换项目', selectedProject);
|
2025-08-28 03:35:18 +08:00
|
|
|
|
|
|
|
// 更新项目 & 权限
|
|
|
|
userStore.setSelectedProject(selectedProject);
|
|
|
|
await userStore.setInfo();
|
|
|
|
await userStore.setRoles(); // 这里会刷新 permissions/roles
|
|
|
|
// 重新生成路由
|
|
|
|
permissionStore.generateRoutes().then((routeList) => {
|
|
|
|
const currentPath = router.currentRoute.value.fullPath;
|
|
|
|
const exist = currentPath == '/' || currentPath == '/index' ? true : routeExists(currentPath, routeList);
|
|
|
|
if (exist) return loadingInstance.close();
|
|
|
|
|
|
|
|
proxy?.$tab.closeAllPage();
|
|
|
|
router.push('/index');
|
|
|
|
loadingInstance.close();
|
|
|
|
|
|
|
|
// 刷新当前路由
|
|
|
|
});
|
2025-05-21 11:24:53 +08:00
|
|
|
};
|
2025-08-28 03:35:18 +08:00
|
|
|
function routeExists(fullPath: string, routes: any[], parentPath = ''): boolean {
|
|
|
|
for (const route of routes) {
|
|
|
|
// 拼接完整 path
|
|
|
|
let currentPath = route.path.startsWith('/') ? route.path : `${parentPath}/${route.path}`;
|
|
|
|
|
|
|
|
// 处理多余的 "//"
|
|
|
|
currentPath = currentPath.replace(/\/+/g, '/');
|
|
|
|
|
|
|
|
// 判断
|
|
|
|
if (currentPath === fullPath) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 递归子路由
|
|
|
|
if (route.children && route.children.length > 0) {
|
|
|
|
if (routeExists(fullPath, route.children, currentPath)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2025-05-21 11:24:53 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.select-container {
|
|
|
|
display: flex;
|
|
|
|
align-items: center; // 上下居中对齐
|
|
|
|
gap: 10px; // label 和 select 之间的间距
|
|
|
|
}
|
|
|
|
|
|
|
|
.select-label {
|
|
|
|
font-weight: bold;
|
|
|
|
color: #333;
|
|
|
|
white-space: nowrap; // 防止 label 换行
|
|
|
|
font-size: 14px; // 设置字体大小
|
|
|
|
}
|
|
|
|
|
|
|
|
#projectSelect {
|
|
|
|
.el-select {
|
|
|
|
width: 400px; // 保持宽度
|
|
|
|
|
|
|
|
.el-input__inner {
|
|
|
|
height: 38px;
|
|
|
|
border-radius: 4px;
|
|
|
|
border: 1px solid #dcdfe6;
|
|
|
|
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
border-color: #409eff;
|
|
|
|
}
|
|
|
|
|
|
|
|
&:focus {
|
|
|
|
border-color: #409eff;
|
|
|
|
box-shadow: 0 0 5px rgba(64, 158, 255, 0.3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-input__icon {
|
|
|
|
line-height: 38px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&.is-focus .el-input__inner {
|
|
|
|
border-color: #409eff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 响应式设计(可选)
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
.select-container {
|
|
|
|
flex-direction: column; // 栈式布局
|
|
|
|
align-items: flex-start; // 左对齐
|
|
|
|
|
|
|
|
.select-label {
|
|
|
|
margin-bottom: 5px; // label 和 select 之间的垂直间距
|
|
|
|
}
|
|
|
|
|
|
|
|
#projectSelect .el-select {
|
|
|
|
width: 100%; // 在小屏幕上占满宽度
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|