权限重构
This commit is contained in:
@ -6,9 +6,9 @@ VITE_APP_ENV = 'development'
|
|||||||
|
|
||||||
# 开发环境
|
# 开发环境
|
||||||
# 李陈杰 209
|
# 李陈杰 209
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.209:8899'
|
VITE_APP_BASE_API = 'http://192.168.110.209:8899'
|
||||||
# 曾涛
|
# 曾涛
|
||||||
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
|
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
|
||||||
# 罗成
|
# 罗成
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.213:8899'
|
# VITE_APP_BASE_API = 'http://192.168.110.213:8899'
|
||||||
# 朱银
|
# 朱银
|
||||||
|
@ -19,3 +19,11 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-moz-user-select: none; /* Firefox */
|
||||||
|
-ms-user-select: none; /* IE10+/Edge */
|
||||||
|
user-select: none; /* Standard syntax */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -3,9 +3,9 @@ import { AxiosPromise } from 'axios';
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
// 获取路由
|
// 获取路由
|
||||||
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
|
export function getRouters(id: string): AxiosPromise<RouteRecordRaw[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/menu/getRouters',
|
url: '/system/menu/getRouters/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -186,3 +186,14 @@ export const uploadProjectFile = (data: any) => {
|
|||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换项目
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const changeProject = (id: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/project/project/changeProject/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -68,3 +68,11 @@ export const delMenu = (menuId: string | number) => {
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取所有路由
|
||||||
|
export const getAllRouters = () => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/getAllRouters',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -75,3 +75,11 @@ export function getRoleList(deptId?: number | string): AxiosPromise<any[]> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取部门下的项目列表
|
||||||
|
export function getProjectByDeptId(deptId?: number | string): AxiosPromise<any[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/projectIdList/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -60,19 +60,20 @@ export interface UserForm {
|
|||||||
nickName?: string;
|
nickName?: string;
|
||||||
password: string;
|
password: string;
|
||||||
phonenumber?: string;
|
phonenumber?: string;
|
||||||
|
projectRoles?: any[];
|
||||||
email?: string;
|
email?: string;
|
||||||
sex?: string;
|
sex?: string;
|
||||||
status: string;
|
status: string;
|
||||||
remark?: string;
|
remark?: string;
|
||||||
postIds: string[];
|
postIds: string[];
|
||||||
roleIds: string[];
|
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserInfoVO {
|
export interface UserInfoVO {
|
||||||
user: UserVO;
|
user: UserVO;
|
||||||
roles: RoleVO[];
|
roles: RoleVO[];
|
||||||
roleIds: string[];
|
|
||||||
|
projectRoles: any[];
|
||||||
posts: PostVO[];
|
posts: PostVO[];
|
||||||
postIds: string[];
|
postIds: string[];
|
||||||
roleGroup: string;
|
roleGroup: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="select-container">
|
<div class="select-container" v-loading.fullscreen.lock="fullscreenLoading">
|
||||||
<label for="projectSelect" class="select-label">项目列表:</label>
|
<label for="projectSelect" class="select-label">项目列表:</label>
|
||||||
<el-select
|
<el-select
|
||||||
id="projectSelect"
|
id="projectSelect"
|
||||||
@ -19,12 +19,18 @@
|
|||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch } from 'vue';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { getProjectTeam } from '@/utils/projectTeam';
|
import { getProjectTeam } from '@/utils/projectTeam';
|
||||||
|
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();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const projects = computed(() => [
|
const projects = computed(() => [
|
||||||
// { id: '', name: '全部工程项目' }, // 添加空选项
|
// { id: '', name: '全部工程项目' }, // 添加空选项
|
||||||
...userStore.projects
|
...userStore.projects
|
||||||
]);
|
]);
|
||||||
|
const proxy = getCurrentInstance()?.proxy as any;
|
||||||
|
|
||||||
const selectedProjectId = ref(userStore.selectedProject?.id || '');
|
const selectedProjectId = ref(userStore.selectedProject?.id || '');
|
||||||
|
|
||||||
@ -37,13 +43,60 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSelect = (projectId: string) => {
|
/** 切换项目逻辑 */
|
||||||
|
const handleSelect = async (projectId: string) => {
|
||||||
|
proxy.$cache.local.setJSON('isCheckRole', 'true');
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
const selectedProject = projects.value.find((p) => p.id === projectId);
|
const selectedProject = projects.value.find((p) => p.id === projectId);
|
||||||
if (selectedProject) {
|
if (!selectedProject) return;
|
||||||
userStore.setSelectedProject(selectedProject);
|
const loadingInstance = ElLoading.service({
|
||||||
console.log(userStore.selectedProject); // 打印选中的项目
|
lock: true,
|
||||||
}
|
text: '项目切换中...',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
});
|
||||||
|
await changeProject(projectId);
|
||||||
|
|
||||||
|
// 更新项目 & 权限
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 刷新当前路由
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
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;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import $cache from '@/plugins/cache';
|
||||||
import { to as tos } from 'await-to-js';
|
import { to as tos } from 'await-to-js';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
@ -29,7 +30,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
} else if (isWhiteList(to.path)) {
|
} else if (isWhiteList(to.path)) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
if (useUserStore().roles.length === 0) {
|
if (useUserStore().roles.length === 0 || $cache.local.getJSON('isCheckRole')) {
|
||||||
isRelogin.show = true;
|
isRelogin.show = true;
|
||||||
// 判断当前用户是否已拉取完user_info信息
|
// 判断当前用户是否已拉取完user_info信息
|
||||||
const [err] = await tos(useUserStore().getInfo());
|
const [err] = await tos(useUserStore().getInfo());
|
||||||
@ -44,8 +45,11 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
accessRoutes.forEach((route) => {
|
accessRoutes.forEach((route) => {
|
||||||
if (!isHttp(route.path)) {
|
if (!isHttp(route.path)) {
|
||||||
router.addRoute(route); // 动态添加可访问路由表
|
router.addRoute(route); // 动态添加可访问路由表
|
||||||
|
console.log('🚀 ~ route:', route);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$cache.local.remove('isCheckRole');
|
||||||
|
|
||||||
// @ts-expect-error hack方法 确保addRoutes已完成
|
// @ts-expect-error hack方法 确保addRoutes已完成
|
||||||
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
|
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
|
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from '@/layout/index.vue';
|
import Layout from '@/layout/index.vue';
|
||||||
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: 路由配置项
|
* Note: 路由配置项
|
||||||
@ -65,11 +66,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||||||
component: () => import('@/views/register.vue'),
|
component: () => import('@/views/register.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/:pathMatch(.*)*',
|
|
||||||
component: () => import('@/views/error/404.vue'),
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/401',
|
path: '/401',
|
||||||
component: () => import('@/views/error/401.vue'),
|
component: () => import('@/views/error/401.vue'),
|
||||||
@ -134,10 +131,16 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||||||
component: () => import('@/views/gis2D/index.vue'),
|
component: () => import('@/views/gis2D/index.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/materials/purchaseDoc/uploadCode',
|
path: '/materials/purchaseDoc/uploadCode',
|
||||||
component: () => import('@/views/materials/purchaseDoc/uploadCode.vue'),
|
component: () => import('@/views/materials/purchaseDoc/uploadCode.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/:pathMatch(.*)*',
|
||||||
|
component: () => import('@/views/error/404.vue'),
|
||||||
|
hidden: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -231,3 +234,11 @@ const router = createRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
|
export function resetRouter() {
|
||||||
|
router.getRoutes().forEach((route) => {
|
||||||
|
if (route.name && !constantRoutes.find((r) => r.name === route.name)) {
|
||||||
|
router.hasRoute(route.name) && router.removeRoute(route.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ import ParentView from '@/components/ParentView/index.vue';
|
|||||||
import InnerLink from '@/layout/components/InnerLink/index.vue';
|
import InnerLink from '@/layout/components/InnerLink/index.vue';
|
||||||
|
|
||||||
import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
|
import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
|
||||||
|
import { useUserStoreHook } from './user';
|
||||||
|
|
||||||
// 匹配views里面所有的.vue文件
|
// 匹配views里面所有的.vue文件
|
||||||
const modules = import.meta.glob('./../../views/**/*.vue');
|
const modules = import.meta.glob('./../../views/**/*.vue');
|
||||||
@ -44,7 +45,7 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
sidebarRouters.value = routes;
|
sidebarRouters.value = routes;
|
||||||
};
|
};
|
||||||
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
|
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
|
||||||
const res = await getRouters();
|
const res = await getRouters(useUserStoreHook().selectedProject?.id || '0');
|
||||||
const { data } = res;
|
const { data } = res;
|
||||||
const sdata = JSON.parse(JSON.stringify(data));
|
const sdata = JSON.parse(JSON.stringify(data));
|
||||||
const rdata = JSON.parse(JSON.stringify(data));
|
const rdata = JSON.parse(JSON.stringify(data));
|
||||||
|
@ -41,7 +41,9 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
const deptId = ref<string | number>('');
|
const deptId = ref<string | number>('');
|
||||||
const avatar = ref('');
|
const avatar = ref('');
|
||||||
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
|
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
|
||||||
const permissions = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限
|
const permissions = ref<Array<any>>([]); // 用户权限编码集合 → 判断按钮权限
|
||||||
|
const permissionList = ref<Array<any>>([]); // 用户所有权限列表
|
||||||
|
const roleList = ref<Array<any>>([]); // 用户所有角色列表
|
||||||
|
|
||||||
const projects = ref<Array<{ id: string; name: string }>>([]);
|
const projects = ref<Array<{ id: string; name: string }>>([]);
|
||||||
// 从localStorage获取缓存的项目,如果没有则默认为null
|
// 从localStorage获取缓存的项目,如果没有则默认为null
|
||||||
@ -66,15 +68,36 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
const getInfo = async (): Promise<void> => {
|
const getInfo = async (): Promise<void> => {
|
||||||
|
// **新增项目数据获取**
|
||||||
|
const [projectErr, projectRes] = await to(getUserProject());
|
||||||
|
if (projectRes?.data) {
|
||||||
|
const projectList = projectRes.data.map((p) => ({
|
||||||
|
id: p.projectId,
|
||||||
|
name: p.projectName || '未知项目'
|
||||||
|
}));
|
||||||
|
|
||||||
|
setProjects(projectList);
|
||||||
|
|
||||||
|
// 如果有缓存的选中项目,且该项目在当前项目列表中存在,则使用缓存的项目
|
||||||
|
const storedProject = getSelectedProjectFromStorage();
|
||||||
|
if (storedProject && projectList.some((p) => p.id === storedProject.id)) {
|
||||||
|
setSelectedProject(storedProject);
|
||||||
|
} else if (projectList.length > 0) {
|
||||||
|
// 否则默认选择第一个项目
|
||||||
|
setSelectedProject(projectList[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
const [err, res] = await to(getUserInfo());
|
const [err, res] = await to(getUserInfo());
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
const user = data.user;
|
const user = data.user;
|
||||||
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
||||||
|
|
||||||
if (data.roles && data.roles.length > 0) {
|
if (data.roles && data.roles.length > 0) {
|
||||||
roles.value = data.roles;
|
setRoles();
|
||||||
permissions.value = data.permissions;
|
permissionList.value = data.permissions;
|
||||||
|
roleList.value = data.roles;
|
||||||
} else {
|
} else {
|
||||||
roles.value = ['ROLE_DEFAULT'];
|
roles.value = ['ROLE_DEFAULT'];
|
||||||
}
|
}
|
||||||
@ -85,31 +108,42 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
tenantId.value = user.tenantId;
|
tenantId.value = user.tenantId;
|
||||||
deptId.value = user.deptId;
|
deptId.value = user.deptId;
|
||||||
|
|
||||||
// **新增项目数据获取**
|
|
||||||
const [projectErr, projectRes] = await to(getUserProject());
|
|
||||||
if (projectRes?.data) {
|
|
||||||
const projectList = projectRes.data.map((p) => ({
|
|
||||||
id: p.projectId,
|
|
||||||
name: p.projectName || '未知项目'
|
|
||||||
}));
|
|
||||||
|
|
||||||
setProjects(projectList);
|
|
||||||
|
|
||||||
// 如果有缓存的选中项目,且该项目在当前项目列表中存在,则使用缓存的项目
|
|
||||||
const storedProject = getSelectedProjectFromStorage();
|
|
||||||
if (storedProject && projectList.some((p) => p.id === storedProject.id)) {
|
|
||||||
setSelectedProject(storedProject);
|
|
||||||
} else if (projectList.length > 0) {
|
|
||||||
// 否则默认选择第一个项目
|
|
||||||
setSelectedProject(projectList[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setInfo = async () => {
|
||||||
|
const [err, res] = await to(getUserInfo());
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
const data = res.data;
|
||||||
|
const user = data.user;
|
||||||
|
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
||||||
|
|
||||||
|
if (data.roles && data.roles.length > 0) {
|
||||||
|
setRoles();
|
||||||
|
permissionList.value = data.permissions;
|
||||||
|
roleList.value = data.roles;
|
||||||
|
} else {
|
||||||
|
roles.value = ['ROLE_DEFAULT'];
|
||||||
|
}
|
||||||
|
name.value = user.userName;
|
||||||
|
nickname.value = user.nickName;
|
||||||
|
avatar.value = profile;
|
||||||
|
userId.value = user.userId;
|
||||||
|
tenantId.value = user.tenantId;
|
||||||
|
deptId.value = user.deptId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setRoles = () => {
|
||||||
|
const projectRole = roleList.value.find((item) => item.projectId == selectedProject.value?.id)?.projectRoles || [];
|
||||||
|
roles.value = projectRole;
|
||||||
|
const projectPermissions = permissionList.value.find((item) => item.projectId == selectedProject.value?.id)?.projectPermissions || [];
|
||||||
|
permissions.value = projectPermissions;
|
||||||
|
};
|
||||||
|
|
||||||
// 注销
|
// 注销
|
||||||
const logout = async (): Promise<void> => {
|
const logout = async (): Promise<void> => {
|
||||||
await logoutApi();
|
await logoutApi();
|
||||||
@ -158,7 +192,9 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
setProjectTeamList,
|
setProjectTeamList,
|
||||||
projects,
|
projects,
|
||||||
selectedProject,
|
selectedProject,
|
||||||
ProjectTeamList
|
ProjectTeamList,
|
||||||
|
setInfo,
|
||||||
|
setRoles
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ import { LoginData, TenantVO } from '@/api/types';
|
|||||||
import { to } from 'await-to-js';
|
import { to } from 'await-to-js';
|
||||||
import { HttpStatus } from '@/enums/RespEnum';
|
import { HttpStatus } from '@/enums/RespEnum';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { getAllRouters } from '@/api/system/menu';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@ -153,6 +154,7 @@ const handleLogin = () => {
|
|||||||
if (!err) {
|
if (!err) {
|
||||||
const redirectUrl = redirect.value || '/';
|
const redirectUrl = redirect.value || '/';
|
||||||
await router.push(redirectUrl);
|
await router.push(redirectUrl);
|
||||||
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
} else {
|
} else {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -64,32 +64,32 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="计量单位" align="center" prop="unit">
|
<el-table-column label="计量单位" align="center" prop="unit">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.unit }}
|
{{ row.unitType == 0 ? '' : row.unit }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="综合单价(业主)" align="center" prop="ownerPrice">
|
<el-table-column label="综合单价(业主)" align="center" prop="ownerPrice">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.ownerPrice }}
|
{{ row.unitType == 0 ? '' : row.ownerPrice }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="综合单价(分包)" align="center" prop="constructionPrice">
|
<el-table-column label="综合单价(分包)" align="center" prop="constructionPrice">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.constructionPrice }}
|
{{ row.unitType == 0 ? '' : row.constructionPrice }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产值金额(业主)" align="center" prop="ownerOutputValue">
|
<el-table-column label="产值金额(业主)" align="center" prop="ownerOutputValue">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.ownerOutputValue }}
|
{{ row.unitType == 0 ? '' : row.ownerOutputValue }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产值金额(分包)" align="center" prop="constructionOutputValue">
|
<el-table-column label="产值金额(分包)" align="center" prop="constructionOutputValue">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.constructionOutputValue }}
|
{{ row.unitType == 0 ? '' : row.constructionOutputValue }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="总数量" align="center" prop="total">
|
<el-table-column label="总数量" align="center" prop="total">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.total }}
|
{{ row.unitType == 0 ? '' : row.total }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="关联结构" align="center" prop="relevancyStructure" width="100">
|
<el-table-column label="关联结构" align="center" prop="relevancyStructure" width="100">
|
||||||
@ -128,7 +128,7 @@
|
|||||||
check-strictly
|
check-strictly
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType">
|
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType && form.unitType != '0'">
|
||||||
<el-select v-model="form.unitType" placeholder="请选择关联数据">
|
<el-select v-model="form.unitType" placeholder="请选择关联数据">
|
||||||
<el-option v-for="dict in progress_unit_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in progress_unit_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -153,12 +153,12 @@
|
|||||||
<el-option v-for="dict in progress_work_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in progress_work_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="关联结构" prop="relevancyStructure">
|
<!-- <el-form-item label="关联结构" prop="relevancyStructure">
|
||||||
<el-select v-model="form.relevancyStructure" value-key="" placeholder="请选择关联结构" clearable filterable @change="">
|
<el-select v-model="form.relevancyStructure" value-key="" placeholder="请选择关联结构" clearable filterable @change="">
|
||||||
<el-option label="子项目" value="1"></el-option>
|
<el-option label="子项目" value="1"></el-option>
|
||||||
<el-option label="方阵" value="2"></el-option>
|
<el-option label="方阵" value="2"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item label="备注" prop="remark" v-if="!form.id">
|
<el-form-item label="备注" prop="remark" v-if="!form.id">
|
||||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -433,12 +433,12 @@ const handleUpdate = async (row: ProgressCategoryVO) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
const ids = treeRef.value.getCheckedNodes()[0].pathNodes[0].childrenData.map((item) => item.matrixId);
|
const ids = queryParams.value.projectId;
|
||||||
const fileName = treeRef.value.getCheckedNodes()[0].pathNodes[0].label;
|
const fileName = matrixOptions.value.find((item) => item.projectId == ids)?.name || currentProject.value?.name || '工程项目';
|
||||||
proxy?.download(
|
proxy?.download(
|
||||||
'/progress/progressCategory/export',
|
'/progress/progressCategory/export',
|
||||||
{
|
{
|
||||||
ids: ids
|
projectId: ids
|
||||||
},
|
},
|
||||||
`${fileName}分项工程单价导入.xlsx`,
|
`${fileName}分项工程单价导入.xlsx`,
|
||||||
true
|
true
|
||||||
|
@ -174,8 +174,6 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="手机号码" prop="phonenumber">
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
||||||
@ -186,8 +184,6 @@
|
|||||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
||||||
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
||||||
@ -198,8 +194,6 @@
|
|||||||
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
|
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="用户性别">
|
<el-form-item label="用户性别">
|
||||||
<el-select v-model="form.sex" placeholder="请选择">
|
<el-select v-model="form.sex" placeholder="请选择">
|
||||||
@ -207,15 +201,6 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="状态">
|
|
||||||
<el-radio-group v-model="form.status">
|
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="岗位">
|
<el-form-item label="岗位">
|
||||||
<el-select v-model="form.postIds" multiple placeholder="请选择">
|
<el-select v-model="form.postIds" multiple placeholder="请选择">
|
||||||
@ -229,21 +214,41 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-row :gutter="20" v-for="(item, index) in form.projectRoles">
|
||||||
|
<el-col :span="11" :offset="0">
|
||||||
|
<el-form-item label="项目列表">
|
||||||
|
<el-select v-model="item.projectId" placeholder="请选择">
|
||||||
|
<el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName" :value="dict.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="11" :offset="0">
|
||||||
|
<el-form-item label="角色">
|
||||||
|
<el-select v-model="item.roleIds" filterable multiple placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="item in roleOptions"
|
||||||
|
:key="item.roleId"
|
||||||
|
:label="item.roleName"
|
||||||
|
:value="item.roleId"
|
||||||
|
:disabled="item.status == '1'"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1" :offset="0">
|
||||||
|
<el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button>
|
||||||
|
<el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="角色" prop="roleIds">
|
<el-form-item label="状态">
|
||||||
<el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
|
<el-radio-group v-model="form.status">
|
||||||
<el-option
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
|
||||||
v-for="item in roleOptions"
|
</el-radio-group>
|
||||||
:key="item.roleId"
|
|
||||||
:label="item.roleName"
|
|
||||||
:value="item.roleId"
|
|
||||||
:disabled="item.status == '1'"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
@ -317,7 +322,7 @@ import { RoleVO } from '@/api/system/role/types';
|
|||||||
import { PostVO } from '@/api/system/post/types';
|
import { PostVO } from '@/api/system/post/types';
|
||||||
import { globalHeaders } from '@/utils/request';
|
import { globalHeaders } from '@/utils/request';
|
||||||
import { to } from 'await-to-js';
|
import { to } from 'await-to-js';
|
||||||
import { getRoleList, optionselect } from '@/api/system/post';
|
import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post';
|
||||||
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -337,6 +342,8 @@ const enabledDeptOptions = ref<DeptTreeVO[]>([]);
|
|||||||
const initPassword = ref<string>('');
|
const initPassword = ref<string>('');
|
||||||
const postOptions = ref<PostVO[]>([]);
|
const postOptions = ref<PostVO[]>([]);
|
||||||
const roleOptions = ref<RoleVO[]>([]);
|
const roleOptions = ref<RoleVO[]>([]);
|
||||||
|
const projectOptions = ref<any[]>([]);
|
||||||
|
|
||||||
/*** 用户导入参数 */
|
/*** 用户导入参数 */
|
||||||
const upload = reactive<ImportOption>({
|
const upload = reactive<ImportOption>({
|
||||||
// 是否显示弹出层(用户导入)
|
// 是否显示弹出层(用户导入)
|
||||||
@ -383,10 +390,15 @@ const initFormData: UserForm = {
|
|||||||
phonenumber: undefined,
|
phonenumber: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
sex: undefined,
|
sex: undefined,
|
||||||
|
projectRoles: [
|
||||||
|
{
|
||||||
|
projectId: '',
|
||||||
|
roleIds: []
|
||||||
|
}
|
||||||
|
],
|
||||||
status: '0',
|
status: '0',
|
||||||
remark: '',
|
remark: '',
|
||||||
postIds: [],
|
postIds: [],
|
||||||
roleIds: [],
|
|
||||||
filePath: undefined
|
filePath: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -436,8 +448,7 @@ const initData: PageData<UserForm, UserQuery> = {
|
|||||||
message: '请输入正确的手机号码',
|
message: '请输入正确的手机号码',
|
||||||
trigger: 'blur'
|
trigger: 'blur'
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
||||||
@ -494,6 +505,19 @@ const handleNodeClick = (data: DeptVO) => {
|
|||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 部门选择变化 */
|
||||||
|
const handleAddProject = () => {
|
||||||
|
form.value.projectRoles.push({
|
||||||
|
projectId: '',
|
||||||
|
roleIds: []
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除项目 */
|
||||||
|
const delProject = (index: number) => {
|
||||||
|
form.value.projectRoles.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
@ -609,6 +633,13 @@ function submitFileForm() {
|
|||||||
/** 重置操作表单 */
|
/** 重置操作表单 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
|
form.value.projectRoles = [
|
||||||
|
{
|
||||||
|
projectId: '',
|
||||||
|
roleIds: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
userFormRef.value?.resetFields();
|
userFormRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -638,12 +669,34 @@ const handleUpdate = async (row?: UserForm) => {
|
|||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
roleOptions.value = data.roles;
|
||||||
form.value.postIds = data.postIds;
|
form.value.postIds = data.postIds;
|
||||||
form.value.roleIds = data.user.roleIds;
|
form.value.projectRoles = data.projectRoles;
|
||||||
form.value.password = '';
|
form.value.password = '';
|
||||||
|
const roleList = await getRoleList(form.value.deptId);
|
||||||
|
const projectList = await getProjectByDeptId(form.value.deptId);
|
||||||
|
projectOptions.value = projectList.data;
|
||||||
|
|
||||||
|
roleOptions.value = roleList.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validate = () => {
|
||||||
|
for (let i = 0; i < form.value.projectRoles.length; i++) {
|
||||||
|
const item = form.value.projectRoles[i];
|
||||||
|
if (!item.projectId || item.projectId.length === 0) {
|
||||||
|
proxy?.$modal.msgError(`第 ${i + 1} 行“项目列表”未填写`);
|
||||||
|
return false; // 阻止提交
|
||||||
|
}
|
||||||
|
if (!item.roleIds || item.roleIds.length === 0) {
|
||||||
|
proxy?.$modal.msgError(`第 ${i + 1} 行“角色”未填写`);
|
||||||
|
return false; // 阻止提交
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
|
const isValid = validate();
|
||||||
|
if (!isValid) return;
|
||||||
userFormRef.value?.validate(async (valid: boolean) => {
|
userFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
||||||
@ -683,10 +736,18 @@ onMounted(() => {
|
|||||||
async function handleDeptChange(value: number | string) {
|
async function handleDeptChange(value: number | string) {
|
||||||
const response = await optionselect(value);
|
const response = await optionselect(value);
|
||||||
const roleList = await getRoleList(value);
|
const roleList = await getRoleList(value);
|
||||||
|
const projectList = await getProjectByDeptId(value);
|
||||||
|
projectOptions.value = projectList.data;
|
||||||
|
|
||||||
roleOptions.value = roleList.data;
|
roleOptions.value = roleList.data;
|
||||||
postOptions.value = response.data;
|
postOptions.value = response.data;
|
||||||
form.value.postIds = [];
|
form.value.postIds = [];
|
||||||
form.value.roleIds = [];
|
form.value.projectRoles = [
|
||||||
|
{
|
||||||
|
projectId: [],
|
||||||
|
roleIds: []
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const shuttleVisible = ref(false);
|
const shuttleVisible = ref(false);
|
||||||
|
Reference in New Issue
Block a user