项目列表完整功能
This commit is contained in:
		| @ -5,7 +5,7 @@ VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统 | ||||
| VITE_APP_ENV = 'development' | ||||
|  | ||||
| # 开发环境 | ||||
| VITE_APP_BASE_API = '/dev-api' | ||||
| VITE_APP_BASE_API = 'http://192.168.110.5:8899' | ||||
|  | ||||
| # 应用访问路径 例如使用前缀 /admin/ | ||||
| VITE_APP_CONTEXT_PATH = '/' | ||||
|  | ||||
| @ -14,7 +14,7 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications' | ||||
| VITE_APP_SNAILJOB_ADMIN = '/snail-job' | ||||
|  | ||||
| # 生产环境 | ||||
| VITE_APP_BASE_API = '/prod-api' | ||||
| VITE_APP_BASE_API = 'http://192.168.110.5:8899' | ||||
|  | ||||
| # 是否在打包时开启压缩,支持 gzip 和 brotli | ||||
| VITE_BUILD_COMPRESS = gzip | ||||
|  | ||||
| @ -32,6 +32,7 @@ | ||||
|     "didi": "9.0.2", | ||||
|     "echarts": "5.5.0", | ||||
|     "element-plus": "2.8.8", | ||||
|     "esbuild": "^0.25.0", | ||||
|     "file-saver": "2.0.5", | ||||
|     "fuse.js": "7.0.0", | ||||
|     "highlight.js": "11.9.0", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import request from '@/utils/request'; | ||||
| import { AxiosPromise } from 'axios'; | ||||
| import { LoginData, LoginResult, VerifyCodeResult, TenantInfo } from './types'; | ||||
| import { LoginData, LoginResult, VerifyCodeResult, TenantInfo,UserProject } from './types'; | ||||
| import { UserInfo } from '@/api/system/user/types'; | ||||
|  | ||||
| // pc端固定客户端授权id | ||||
| @ -111,3 +111,11 @@ export function getTenantList(isToken: boolean): AxiosPromise<TenantInfo> { | ||||
|     method: 'get' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| //获取用户项目信息 | ||||
| export function getUserProject(): AxiosPromise<UserProject[]> { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/login/list', | ||||
|     method: 'get' | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										63
									
								
								src/api/project/project/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/api/project/project/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| import request from '@/utils/request'; | ||||
| import { AxiosPromise } from 'axios'; | ||||
| import { ProjectVO, ProjectForm, ProjectQuery } from '@/api/project/project/types'; | ||||
|  | ||||
| /** | ||||
|  * 查询项目列表 | ||||
|  * @param query | ||||
|  * @returns {*} | ||||
|  */ | ||||
|  | ||||
| export const listProject = (query?: ProjectQuery): AxiosPromise<ProjectVO[]> => { | ||||
|   return request({ | ||||
|     url: '/project/project/list', | ||||
|     method: 'get', | ||||
|     params: query | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 查询项目详细 | ||||
|  * @param id | ||||
|  */ | ||||
| export const getProject = (id: string | number): AxiosPromise<ProjectVO> => { | ||||
|   return request({ | ||||
|     url: '/project/project/' + id, | ||||
|     method: 'get' | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 新增项目 | ||||
|  * @param data | ||||
|  */ | ||||
| export const addProject = (data: ProjectForm) => { | ||||
|   return request({ | ||||
|     url: '/project/project', | ||||
|     method: 'post', | ||||
|     data: data | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 修改项目 | ||||
|  * @param data | ||||
|  */ | ||||
| export const updateProject = (data: ProjectForm) => { | ||||
|   return request({ | ||||
|     url: '/project/project', | ||||
|     method: 'put', | ||||
|     data: data | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 删除项目 | ||||
|  * @param id | ||||
|  */ | ||||
| export const delProject = (id: string | number | Array<string | number>) => { | ||||
|   return request({ | ||||
|     url: '/project/project/' + id, | ||||
|     method: 'delete' | ||||
|   }); | ||||
| }; | ||||
							
								
								
									
										336
									
								
								src/api/project/project/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/api/project/project/types.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,336 @@ | ||||
| export interface ProjectVO { | ||||
|   /** | ||||
|    *  | ||||
|    */ | ||||
|   id: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 项目名称 | ||||
|    */ | ||||
|   projectName: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目简称 | ||||
|    */ | ||||
|   shortName: string; | ||||
|  | ||||
|   /** | ||||
|    * 父项目id | ||||
|    */ | ||||
|   pId: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 状态(0正常 1停用) | ||||
|    */ | ||||
|   status: number; | ||||
|  | ||||
|   /** | ||||
|    * 项目图片 | ||||
|    */ | ||||
|   picUrl: string; | ||||
|  | ||||
|   /** | ||||
|    * 备注 | ||||
|    */ | ||||
|   remark: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目类型 | ||||
|    */ | ||||
|   type: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目类型(1光伏 2风电) | ||||
|    */ | ||||
|   isType: number; | ||||
|  | ||||
|   /** | ||||
|    * 删除时间 | ||||
|    */ | ||||
|   deletedAt: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目地址 | ||||
|    */ | ||||
|   projectSite: string; | ||||
|  | ||||
|   /** | ||||
|    * 负责人 | ||||
|    */ | ||||
|   principal: string; | ||||
|  | ||||
|   /** | ||||
|    * 负责人电话 | ||||
|    */ | ||||
|   principalPhone: string; | ||||
|  | ||||
|   /** | ||||
|    * 实际容量 | ||||
|    */ | ||||
|   actual: string; | ||||
|  | ||||
|   /** | ||||
|    * 计划容量 | ||||
|    */ | ||||
|   plan: string; | ||||
|  | ||||
|   /** | ||||
|    * 开工时间 | ||||
|    */ | ||||
|   onStreamTime: string; | ||||
|  | ||||
|   /** | ||||
|    * 打卡范围(09:00,18:00) | ||||
|    */ | ||||
|   punchRange: string; | ||||
|  | ||||
|   /** | ||||
|    * 设计总量 | ||||
|    */ | ||||
|   designTotal: number; | ||||
|  | ||||
|   /** | ||||
|    * 安全协议书 | ||||
|    */ | ||||
|   securityAgreement: string; | ||||
|  | ||||
|   /** | ||||
|    * 排序字段 | ||||
|    */ | ||||
|   sort: number; | ||||
|  | ||||
|   /** | ||||
|    * 显示隐藏(1显示 2隐藏) | ||||
|    */ | ||||
|   showHidden: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 是否删除(0正常 1删除) | ||||
|    */ | ||||
|   isDelete: number; | ||||
|  | ||||
| } | ||||
|  | ||||
| export interface ProjectForm extends BaseEntity { | ||||
|   /** | ||||
|    *  | ||||
|    */ | ||||
|   id?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 项目名称 | ||||
|    */ | ||||
|   projectName?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目简称 | ||||
|    */ | ||||
|   shortName?: string; | ||||
|  | ||||
|   /** | ||||
|    * 父项目id | ||||
|    */ | ||||
|   pId?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 状态(0正常 1停用) | ||||
|    */ | ||||
|   status?: number; | ||||
|  | ||||
|   /** | ||||
|    * 项目图片 | ||||
|    */ | ||||
|   picUrl?: string; | ||||
|  | ||||
|   /** | ||||
|    * 备注 | ||||
|    */ | ||||
|   remark?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目类型 | ||||
|    */ | ||||
|   type?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目类型(1光伏 2风电) | ||||
|    */ | ||||
|   isType?: number; | ||||
|  | ||||
|   /** | ||||
|    * 删除时间 | ||||
|    */ | ||||
|   deletedAt?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目地址 | ||||
|    */ | ||||
|   projectSite?: string; | ||||
|  | ||||
|   /** | ||||
|    * 负责人 | ||||
|    */ | ||||
|   principal?: string; | ||||
|  | ||||
|   /** | ||||
|    * 负责人电话 | ||||
|    */ | ||||
|   principalPhone?: string; | ||||
|  | ||||
|   /** | ||||
|    * 实际容量 | ||||
|    */ | ||||
|   actual?: string; | ||||
|  | ||||
|   /** | ||||
|    * 计划容量 | ||||
|    */ | ||||
|   plan?: string; | ||||
|  | ||||
|   /** | ||||
|    * 开工时间 | ||||
|    */ | ||||
|   onStreamTime?: string; | ||||
|  | ||||
|   /** | ||||
|    * 打卡范围(09:00,18:00) | ||||
|    */ | ||||
|   punchRange?: string; | ||||
|  | ||||
|   /** | ||||
|    * 设计总量 | ||||
|    */ | ||||
|   designTotal?: number; | ||||
|  | ||||
|   /** | ||||
|    * 安全协议书 | ||||
|    */ | ||||
|   securityAgreement?: string; | ||||
|  | ||||
|   /** | ||||
|    * 排序字段 | ||||
|    */ | ||||
|   sort?: number; | ||||
|  | ||||
|   /** | ||||
|    * 显示隐藏(1显示 2隐藏) | ||||
|    */ | ||||
|   showHidden?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 是否删除(0正常 1删除) | ||||
|    */ | ||||
|   isDelete?: number; | ||||
|  | ||||
| } | ||||
|  | ||||
| export interface ProjectQuery extends PageQuery { | ||||
|  | ||||
|   /** | ||||
|    * 项目名称 | ||||
|    */ | ||||
|   projectName?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目简称 | ||||
|    */ | ||||
|   shortName?: string; | ||||
|  | ||||
|   /** | ||||
|    * 父项目id | ||||
|    */ | ||||
|   pId?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 状态(0正常 1停用) | ||||
|    */ | ||||
|   status?: number; | ||||
|  | ||||
|   /** | ||||
|    * 项目图片 | ||||
|    */ | ||||
|   picUrl?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目类型 | ||||
|    */ | ||||
|   type?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目类型(1光伏 2风电) | ||||
|    */ | ||||
|   isType?: number; | ||||
|  | ||||
|   /** | ||||
|    * 删除时间 | ||||
|    */ | ||||
|   deletedAt?: string; | ||||
|  | ||||
|   /** | ||||
|    * 项目地址 | ||||
|    */ | ||||
|   projectSite?: string; | ||||
|  | ||||
|   /** | ||||
|    * 负责人 | ||||
|    */ | ||||
|   principal?: string; | ||||
|  | ||||
|   /** | ||||
|    * 负责人电话 | ||||
|    */ | ||||
|   principalPhone?: string; | ||||
|  | ||||
|   /** | ||||
|    * 实际容量 | ||||
|    */ | ||||
|   actual?: string; | ||||
|  | ||||
|   /** | ||||
|    * 计划容量 | ||||
|    */ | ||||
|   plan?: string; | ||||
|  | ||||
|   /** | ||||
|    * 开工时间 | ||||
|    */ | ||||
|   onStreamTime?: string; | ||||
|  | ||||
|   /** | ||||
|    * 打卡范围(09:00,18:00) | ||||
|    */ | ||||
|   punchRange?: string; | ||||
|  | ||||
|   /** | ||||
|    * 设计总量 | ||||
|    */ | ||||
|   designTotal?: number; | ||||
|  | ||||
|   /** | ||||
|    * 安全协议书 | ||||
|    */ | ||||
|   securityAgreement?: string; | ||||
|  | ||||
|   /** | ||||
|    * 排序字段 | ||||
|    */ | ||||
|   sort?: number; | ||||
|  | ||||
|   /** | ||||
|    * 显示隐藏(1显示 2隐藏) | ||||
|    */ | ||||
|   showHidden?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 是否删除(0正常 1删除) | ||||
|    */ | ||||
|   isDelete?: number; | ||||
|  | ||||
|     /** | ||||
|      * 日期范围参数 | ||||
|      */ | ||||
|     params?: any; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										103
									
								
								src/api/project/projectRelevancy/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/api/project/projectRelevancy/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | ||||
| import request from '@/utils/request'; | ||||
| import { AxiosPromise } from 'axios'; | ||||
| import { ProjectRelevancyVO, ProjectRelevancyForm, ProjectRelevancyQuery } from '@/api/project/projectRelevancy/types'; | ||||
|  | ||||
| /** | ||||
|  * 查询系统用户与项目关联列表 | ||||
|  * @param query | ||||
|  * @returns {*} | ||||
|  */ | ||||
|  | ||||
| export const listProjectRelevancy = (query?: ProjectRelevancyQuery): AxiosPromise<ProjectRelevancyVO[]> => { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/login/page', | ||||
|     method: 'get', | ||||
|     params: query | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 查询系统用户与项目关联详细 | ||||
|  * @param id | ||||
|  */ | ||||
| export const getProjectRelevancy = (id: string | number): AxiosPromise<ProjectRelevancyVO> => { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/' + id, | ||||
|     method: 'get' | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 新增系统用户与项目关联 | ||||
|  * @param data | ||||
|  */ | ||||
| export const addProjectRelevancy = (data: ProjectRelevancyForm) => { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy', | ||||
|     method: 'post', | ||||
|     data: data | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 修改系统用户与项目关联 | ||||
|  * @param data | ||||
|  */ | ||||
| export const updateProjectRelevancy = (data: ProjectRelevancyForm) => { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy', | ||||
|     method: 'put', | ||||
|     data: data | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 删除系统用户与项目关联 | ||||
|  * @param id | ||||
|  */ | ||||
| export const delProjectRelevancy = (id: string | number | Array<string | number>) => { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/' + id, | ||||
|     method: 'delete' | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 穿梭框接口 | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * 获取用户已关联的项目列表 | ||||
|  * @param params { userId: number } | ||||
|  */ | ||||
| export function listUserProjects(params: { userId: number }) { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/list', | ||||
|     method: 'get', | ||||
|     params | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 添加项目关联 | ||||
|  * @param data { userId: number; projectIds: number[] } | ||||
|  */ | ||||
| export function addNewProjectRelevancy(data: { userId: number; projectIds: number[] }) { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/add/project/list', | ||||
|     method: 'post', | ||||
|     data | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 移除项目关联 | ||||
|  * @param data { userId: number; projectIds: number[] } | ||||
|  */ | ||||
| export function removeNewProjectRelevancy(data: { userId: number; projectIds: number[] }) { | ||||
|   return request({ | ||||
|     url: '/project/projectRelevancy/remove/project/list', | ||||
|     method: 'delete', | ||||
|     data | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										71
									
								
								src/api/project/projectRelevancy/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/api/project/projectRelevancy/types.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| export interface ProjectRelevancyVO { | ||||
|   /** | ||||
|    * 主键ID | ||||
|    */ | ||||
|   id: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 用户ID | ||||
|    */ | ||||
|   userId: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 项目ID | ||||
|    */ | ||||
|   projectId: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 删除时间 | ||||
|    */ | ||||
|   deletedAt: string; | ||||
|  | ||||
| } | ||||
|  | ||||
| export interface ProjectRelevancyForm extends BaseEntity { | ||||
|   /** | ||||
|    * 主键ID | ||||
|    */ | ||||
|   id?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 用户ID | ||||
|    */ | ||||
|   userId?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 项目ID | ||||
|    */ | ||||
|   projectId?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 删除时间 | ||||
|    */ | ||||
|   deletedAt?: string; | ||||
|  | ||||
| } | ||||
|  | ||||
| export interface ProjectRelevancyQuery extends PageQuery { | ||||
|  | ||||
|   /** | ||||
|    * 用户ID | ||||
|    */ | ||||
|   userId?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 项目ID | ||||
|    */ | ||||
|   projectId?: string | number; | ||||
|  | ||||
|   /** | ||||
|    * 删除时间 | ||||
|    */ | ||||
|   deletedAt?: string; | ||||
|  | ||||
|     /** | ||||
|      * 日期范围参数 | ||||
|      */ | ||||
|     params?: any; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -57,3 +57,14 @@ export interface TenantInfo { | ||||
|   tenantEnabled: boolean; | ||||
|   voList: TenantVO[]; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 根据用户获得工程列表 | ||||
|  * */ | ||||
| export interface UserProject { | ||||
|   id: string; | ||||
|   userId: number; | ||||
|   projectId: string; | ||||
|   projectName: string; | ||||
|   shortName: string; | ||||
| } | ||||
|  | ||||
							
								
								
									
										103
									
								
								src/components/ProjectSelector/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/components/ProjectSelector/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | ||||
| <template> | ||||
|   <div class="select-container"> | ||||
|     <label for="projectSelect" class="select-label">项目列表:</label> | ||||
|     <el-select  | ||||
|       id="projectSelect" | ||||
|       v-model="selectedProjectId"  | ||||
|       placeholder="选择工程"  | ||||
|       clearable | ||||
|       filterable | ||||
|       @change="handleSelect" | ||||
|       style="width: 120px;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'; | ||||
|  | ||||
| const userStore = useUserStore(); | ||||
| const projects = computed(() => userStore.projects); | ||||
| const selectedProjectId = ref(userStore.selectedProject?.id || ''); | ||||
|  | ||||
| // 监听 userStore.selectedProject 变化,更新 selectedProjectId | ||||
| watch(() => userStore.selectedProject, (newProject) => { | ||||
|   selectedProjectId.value = newProject?.id || ''; | ||||
| }, { deep: true }); | ||||
|  | ||||
| const handleSelect = (projectId: string) => { | ||||
|   const selectedProject = projects.value.find(p => p.id === projectId); | ||||
|   if (selectedProject) { | ||||
|     userStore.setSelectedProject(selectedProject); | ||||
|   } | ||||
| }; | ||||
| </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> | ||||
| @ -1,13 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <svg-icon icon-class="question" @click="goto" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| const url = ref('https://plus-doc.dromara.org/'); | ||||
|  | ||||
| function goto() { | ||||
|   window.open(url.value); | ||||
| } | ||||
| </script> | ||||
| @ -1,13 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <svg-icon icon-class="github" @click="goto" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus'); | ||||
|  | ||||
| function goto() { | ||||
|   window.open(url.value); | ||||
| } | ||||
| </script> | ||||
| @ -23,11 +23,14 @@ | ||||
|  | ||||
|         <!-- <header-search id="header-search" class="right-menu-item" /> --> | ||||
|         <search-menu ref="searchMenuRef" /> | ||||
|         <el-tooltip content="搜索" effect="dark" placement="bottom"> | ||||
|         <el-tooltip  effect="dark" placement="bottom"> | ||||
|           <ProjectSelector /> | ||||
|         </el-tooltip> | ||||
|         <!-- <el-tooltip content="搜索" effect="dark" placement="bottom"> | ||||
|           <div class="right-menu-item hover-effect" @click="openSearchMenu"> | ||||
|             <svg-icon class-name="search-icon" icon-class="search" /> | ||||
|           </div> | ||||
|         </el-tooltip> | ||||
|         </el-tooltip> --> | ||||
|         <!-- 消息 --> | ||||
|         <el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom"> | ||||
|           <div> | ||||
| @ -43,22 +46,12 @@ | ||||
|             </el-popover> | ||||
|           </div> | ||||
|         </el-tooltip> | ||||
|         <el-tooltip content="Github" effect="dark" placement="bottom"> | ||||
|           <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" /> | ||||
|         </el-tooltip> | ||||
|  | ||||
|         <el-tooltip :content="proxy.$t('navbar.document')" effect="dark" placement="bottom"> | ||||
|           <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" /> | ||||
|         </el-tooltip> | ||||
|  | ||||
|         <el-tooltip :content="proxy.$t('navbar.full')" effect="dark" placement="bottom"> | ||||
|           <screenfull id="screenfull" class="right-menu-item hover-effect" /> | ||||
|         </el-tooltip> | ||||
|  | ||||
|         <el-tooltip :content="proxy.$t('navbar.language')" effect="dark" placement="bottom"> | ||||
|           <lang-select id="lang-select" class="right-menu-item hover-effect" /> | ||||
|         </el-tooltip> | ||||
|  | ||||
|         <el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom"> | ||||
|           <size-select id="size-select" class="right-menu-item hover-effect" /> | ||||
|         </el-tooltip> | ||||
| @ -99,7 +92,7 @@ import { dynamicClear, dynamicTenant } from '@/api/system/tenant'; | ||||
| import { TenantVO } from '@/api/types'; | ||||
| import notice from './notice/index.vue'; | ||||
| import router from '@/router'; | ||||
|  | ||||
| import ProjectSelector from '@/components/ProjectSelector/index.vue'; | ||||
| const appStore = useAppStore(); | ||||
| const userStore = useUserStore(); | ||||
| const settingsStore = useSettingsStore(); | ||||
|  | ||||
| @ -26,6 +26,19 @@ import Layout from '@/layout/index.vue'; | ||||
|  | ||||
| // 公共路由 | ||||
| export const constantRoutes: RouteRecordRaw[] = [ | ||||
|   { | ||||
|     path: '/', | ||||
|     component: Layout, | ||||
|     redirect: '/index', // 登录成功后默认跳转到 index | ||||
|     children: [ | ||||
|       { | ||||
|         path: 'index', | ||||
|         component: () => import('@/views/index.vue'), | ||||
|         name: 'Index', | ||||
|         meta: { title: '首页', icon: 'dashboard', affix: true } | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     path: '/redirect', | ||||
|     component: Layout, | ||||
| @ -62,19 +75,6 @@ export const constantRoutes: RouteRecordRaw[] = [ | ||||
|     component: () => import('@/views/error/401.vue'), | ||||
|     hidden: true | ||||
|   }, | ||||
|   { | ||||
|     path: '', | ||||
|     component: Layout, | ||||
|     redirect: '/index', | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/index', | ||||
|         component: () => import('@/views/index.vue'), | ||||
|         name: 'Index', | ||||
|         meta: { title: '首页', icon: 'dashboard', affix: true } | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     path: '/user', | ||||
|     component: Layout, | ||||
| @ -88,6 +88,11 @@ export const constantRoutes: RouteRecordRaw[] = [ | ||||
|         meta: { title: '个人中心', icon: 'user' } | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     path: '/test', | ||||
|     component: () => import('@/views/personnelManagement/project/projectRelevancy/component/ShuttleFrame.vue'), | ||||
|     hidden: true | ||||
|   } | ||||
| ]; | ||||
|  | ||||
| @ -162,34 +167,6 @@ export const dynamicRoutes: RouteRecordRaw[] = [ | ||||
|         meta: { title: '修改生成配置', activeMenu: '/tool/gen', icon: '', noCache: true } | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     path: '/workflow/leaveEdit', | ||||
|     component: Layout, | ||||
|     hidden: true, | ||||
|     permissions: ['workflow:leave:edit'], | ||||
|     children: [ | ||||
|       { | ||||
|         path: 'index', | ||||
|         component: () => import('@/views/workflow/leave/leaveEdit.vue'), | ||||
|         name: 'leaveEdit', | ||||
|         meta: { title: '请假申请', activeMenu: '/workflow/leave', noCache: true } | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     path: '/workflow/design', | ||||
|     component: Layout, | ||||
|     hidden: true, | ||||
|     permissions: ['workflow:leave:edit'], | ||||
|     children: [ | ||||
|       { | ||||
|         path: 'index', | ||||
|         component: () => import('@/views/workflow/processDefinition/design.vue'), | ||||
|         name: 'design', | ||||
|         meta: { title: '流程设计', activeMenu: '/workflow/processDefinition', noCache: true } | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ]; | ||||
|  | ||||
|  | ||||
| @ -1,9 +1,10 @@ | ||||
| import { to } from 'await-to-js'; | ||||
| import { getToken, removeToken, setToken } from '@/utils/auth'; | ||||
| import { login as loginApi, logout as logoutApi, getInfo as getUserInfo } from '@/api/login'; | ||||
| import { LoginData } from '@/api/types'; | ||||
| import { login as loginApi, logout as logoutApi, getInfo as getUserInfo, getUserProject } from '@/api/login'; | ||||
| import { LoginData, UserProject } from '@/api/types'; | ||||
| import defAva from '@/assets/images/profile.jpg'; | ||||
| import store from '@/store'; | ||||
| import { defineStore } from 'pinia'; | ||||
|  | ||||
| export const useUserStore = defineStore('user', () => { | ||||
|   const token = ref(getToken()); | ||||
| @ -15,6 +16,8 @@ export const useUserStore = defineStore('user', () => { | ||||
|   const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限 | ||||
|   const permissions = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限 | ||||
|  | ||||
|   const projects = ref<Array<{ id: string; name: string }>>([]); | ||||
|   const selectedProject = ref<{ id: string; name: string } | null>(projects.value[0]); // 默认选中第一个 | ||||
|   /** | ||||
|    * 登录 | ||||
|    * @param userInfo | ||||
| @ -40,7 +43,6 @@ export const useUserStore = defineStore('user', () => { | ||||
|       const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar; | ||||
|  | ||||
|       if (data.roles && data.roles.length > 0) { | ||||
|         // 验证返回的roles是否是一个非空数组 | ||||
|         roles.value = data.roles; | ||||
|         permissions.value = data.permissions; | ||||
|       } else { | ||||
| @ -51,11 +53,31 @@ export const useUserStore = defineStore('user', () => { | ||||
|       avatar.value = profile; | ||||
|       userId.value = user.userId; | ||||
|       tenantId.value = user.tenantId; | ||||
|  | ||||
|  | ||||
|       // **新增项目数据获取** | ||||
|       const [projectErr, projectRes] = await to(getUserProject()); | ||||
|       if (projectRes?.data) { | ||||
|         const projectList = projectRes.data.map(p => ({ | ||||
|           id: p.projectId, | ||||
|           name: p.projectName || '未知项目' | ||||
|         })); | ||||
|  | ||||
|         setProjects(projectList); | ||||
|  | ||||
|         if (projectList.length > 0) { | ||||
|           setSelectedProject(projectList[0]); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|  | ||||
|  | ||||
|       return Promise.resolve(); | ||||
|     } | ||||
|     return Promise.reject(err); | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   // 注销 | ||||
|   const logout = async (): Promise<void> => { | ||||
|     await logoutApi(); | ||||
| @ -69,6 +91,19 @@ export const useUserStore = defineStore('user', () => { | ||||
|     avatar.value = value; | ||||
|   }; | ||||
|  | ||||
|   const setProjects = (projectList: Array<{ id: string; name: string }>) => { | ||||
|     projects.value = projectList; | ||||
|   }; | ||||
|  | ||||
|   const setSelectedProject = (project: { id: string; name: string }) => { | ||||
|     selectedProject.value = project; | ||||
|     // ** 切换项目后,需要清空当前项目下的所有缓存数据 ** | ||||
|     // 清空 pinia 缓存 | ||||
|     // store.$reset(); | ||||
|     // console.log("选择的新项目名称:" + selectedProject.value.name)   | ||||
|     // console.log("选择的新项目id:" + selectedProject.value.id)   | ||||
|   }; | ||||
|  | ||||
|   return { | ||||
|     userId, | ||||
|     tenantId, | ||||
| @ -80,12 +115,17 @@ export const useUserStore = defineStore('user', () => { | ||||
|     login, | ||||
|     getInfo, | ||||
|     logout, | ||||
|     setAvatar | ||||
|     setAvatar, | ||||
|     setProjects, | ||||
|     setSelectedProject, | ||||
|     projects, | ||||
|     selectedProject | ||||
|   }; | ||||
| }); | ||||
|  | ||||
| export default useUserStore; | ||||
| // 非setup | ||||
|  | ||||
| // 非 setup 方式 | ||||
| export function useUserStoreHook() { | ||||
|   return useUserStore(store); | ||||
| } | ||||
|  | ||||
| @ -1,254 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="部门id" prop="deptId"> | ||||
|               <el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="用户id" prop="userId"> | ||||
|               <el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="排序号" prop="orderNum"> | ||||
|               <el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="key键" prop="testKey"> | ||||
|               <el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="值" prop="value"> | ||||
|               <el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="hover"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" | ||||
|               >删除</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['demo:demo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column v-if="true" label="主键" align="center" prop="id" /> | ||||
|         <el-table-column label="部门id" align="center" prop="deptId" /> | ||||
|         <el-table-column label="用户id" align="center" prop="userId" /> | ||||
|         <el-table-column label="排序号" align="center" prop="orderNum" /> | ||||
|         <el-table-column label="key键" align="center" prop="testKey" /> | ||||
|         <el-table-column label="值" align="center" prop="value" /> | ||||
|         <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-tooltip content="修改" placement="top"> | ||||
|               <el-button v-hasPermi="['demo:demo:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="删除" placement="top"> | ||||
|               <el-button v-hasPermi="['demo:demo:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> | ||||
|             </el-tooltip> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|  | ||||
|       <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> | ||||
|     </el-card> | ||||
|     <!-- 添加或修改测试单对话框 --> | ||||
|     <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> | ||||
|       <el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="部门id" prop="deptId"> | ||||
|           <el-input v-model="form.deptId" placeholder="请输入部门id" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="用户id" prop="userId"> | ||||
|           <el-input v-model="form.userId" placeholder="请输入用户id" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="排序号" prop="orderNum"> | ||||
|           <el-input v-model="form.orderNum" placeholder="请输入排序号" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="key键" prop="testKey"> | ||||
|           <el-input v-model="form.testKey" placeholder="请输入key键" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="值" prop="value"> | ||||
|           <el-input v-model="form.value" placeholder="请输入值" /> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Demo" lang="ts"> | ||||
| import { listDemo, getDemo, delDemo, addDemo, updateDemo } from '@/api/demo/demo'; | ||||
| import { DemoVO, DemoQuery, DemoForm } from '@/api/demo/demo/types'; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
|  | ||||
| const demoList = ref<DemoVO[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const demoFormRef = ref<ElFormInstance>(); | ||||
|  | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
|  | ||||
| const initFormData: DemoForm = { | ||||
|   id: undefined, | ||||
|   deptId: undefined, | ||||
|   userId: undefined, | ||||
|   orderNum: undefined, | ||||
|   testKey: undefined, | ||||
|   value: undefined | ||||
| }; | ||||
| const data = reactive<PageData<DemoForm, DemoQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     deptId: undefined, | ||||
|     userId: undefined, | ||||
|     orderNum: undefined, | ||||
|     testKey: undefined, | ||||
|     value: undefined | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键不能为空', trigger: 'blur' }], | ||||
|     deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }], | ||||
|     userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }], | ||||
|     orderNum: [{ required: true, message: '排序号不能为空', trigger: 'blur' }], | ||||
|     testKey: [{ required: true, message: 'key键不能为空', trigger: 'blur' }], | ||||
|     value: [{ required: true, message: '值不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| /** 查询测试单列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listDemo(queryParams.value); | ||||
|   demoList.value = res.rows; | ||||
|   total.value = res.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| /** 取消按钮 */ | ||||
| const cancel = () => { | ||||
|   reset(); | ||||
|   dialog.visible = false; | ||||
| }; | ||||
|  | ||||
| /** 表单重置 */ | ||||
| const reset = () => { | ||||
|   form.value = { ...initFormData }; | ||||
|   demoFormRef.value?.resetFields(); | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 多选框选中数据 */ | ||||
| const handleSelectionChange = (selection: DemoVO[]) => { | ||||
|   ids.value = selection.map((item) => item.id); | ||||
|   single.value = selection.length != 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = () => { | ||||
|   reset(); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '添加测试单'; | ||||
| }; | ||||
|  | ||||
| /** 修改按钮操作 */ | ||||
| const handleUpdate = async (row?: DemoVO) => { | ||||
|   reset(); | ||||
|   const _id = row?.id || ids.value[0]; | ||||
|   const res = await getDemo(_id); | ||||
|   Object.assign(form.value, res.data); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '修改测试单'; | ||||
| }; | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = () => { | ||||
|   demoFormRef.value?.validate(async (valid: boolean) => { | ||||
|     if (valid) { | ||||
|       buttonLoading.value = true; | ||||
|       if (form.value.id) { | ||||
|         await updateDemo(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } else { | ||||
|         await addDemo(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } | ||||
|       proxy?.$modal.msgSuccess('修改成功'); | ||||
|       dialog.visible = false; | ||||
|       await getList(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row?: DemoVO) => { | ||||
|   const _ids = row?.id || ids.value; | ||||
|   await proxy?.$modal.confirm('是否确认删除测试单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); | ||||
|   await delDemo(_ids); | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
|   await getList(); | ||||
| }; | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = () => { | ||||
|   proxy?.download( | ||||
|     'demo/demo/export', | ||||
|     { | ||||
|       ...queryParams.value | ||||
|     }, | ||||
|     `demo_${new Date().getTime()}.xlsx` | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,258 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="树节点名" prop="treeName"> | ||||
|               <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="hover"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['demo:tree:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|       <el-table | ||||
|         ref="treeTableRef" | ||||
|         v-loading="loading" | ||||
|         :data="treeList" | ||||
|         row-key="id" | ||||
|         :default-expand-all="isExpandAll" | ||||
|         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" | ||||
|       > | ||||
|         <el-table-column label="父id" align="center" prop="parentId" /> | ||||
|         <el-table-column label="部门id" align="center" prop="deptId" /> | ||||
|         <el-table-column label="用户id" align="center" prop="userId" /> | ||||
|         <el-table-column label="树节点名" align="center" prop="treeName" /> | ||||
|         <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-tooltip content="修改" placement="top"> | ||||
|               <el-button v-hasPermi="['demo:tree:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="新增" placement="top"> | ||||
|               <el-button v-hasPermi="['demo:tree:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="删除" placement="top"> | ||||
|               <el-button v-hasPermi="['demo:tree:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" /> | ||||
|             </el-tooltip> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|     </el-card> | ||||
|     <!-- 添加或修改测试树对话框 --> | ||||
|     <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> | ||||
|       <el-form ref="treeFormRef" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="父id" prop="parentId"> | ||||
|           <el-tree-select | ||||
|             v-model="form.parentId" | ||||
|             :data="treeOptions" | ||||
|             :props="{ value: 'id', label: 'treeName', children: 'children' }" | ||||
|             value-key="id" | ||||
|             placeholder="请选择父id" | ||||
|             check-strictly | ||||
|           /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="部门id" prop="deptId"> | ||||
|           <el-input v-model="form.deptId" placeholder="请输入部门id" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="用户id" prop="userId"> | ||||
|           <el-input v-model="form.userId" placeholder="请输入用户id" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="值" prop="treeName"> | ||||
|           <el-input v-model="form.treeName" placeholder="请输入值" /> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Tree" lang="ts"> | ||||
| import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree'; | ||||
| import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types'; | ||||
|  | ||||
| type TreeOption = { | ||||
|   id: number; | ||||
|   treeName: string; | ||||
|   children?: TreeOption[]; | ||||
| }; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
|  | ||||
| const treeList = ref<TreeVO[]>([]); | ||||
| const treeOptions = ref<TreeOption[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const showSearch = ref(true); | ||||
| const isExpandAll = ref(true); | ||||
| const loading = ref(false); | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const treeFormRef = ref<ElFormInstance>(); | ||||
| const treeTableRef = ref<ElTableInstance>(); | ||||
|  | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
|  | ||||
| const initFormData: TreeForm = { | ||||
|   id: undefined, | ||||
|   parentId: undefined, | ||||
|   deptId: undefined, | ||||
|   userId: undefined, | ||||
|   treeName: undefined | ||||
| }; | ||||
|  | ||||
| const data = reactive<PageData<TreeForm, TreeQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     parentId: undefined, | ||||
|     deptId: undefined, | ||||
|     userId: undefined, | ||||
|     treeName: undefined | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键不能为空', trigger: 'blur' }], | ||||
|     parentId: [{ required: true, message: '父id不能为空', trigger: 'blur' }], | ||||
|     deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }], | ||||
|     userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }], | ||||
|     treeName: [{ required: true, message: '值不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| /** 查询测试树列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listTree(queryParams.value); | ||||
|   const data = proxy?.handleTree<TreeVO>(res.data, 'id', 'parentId'); | ||||
|   if (data) { | ||||
|     treeList.value = data; | ||||
|     loading.value = false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** 查询测试树下拉树结构 */ | ||||
| const getTreeselect = async () => { | ||||
|   const res = await listTree(); | ||||
|   treeOptions.value = []; | ||||
|   const data: TreeOption = { id: 0, treeName: '顶级节点', children: [] }; | ||||
|   data.children = proxy?.handleTree<TreeOption>(res.data, 'id', 'parentId'); | ||||
|   treeOptions.value.push(data); | ||||
| }; | ||||
|  | ||||
| // 取消按钮 | ||||
| const cancel = () => { | ||||
|   reset(); | ||||
|   dialog.visible = false; | ||||
| }; | ||||
|  | ||||
| // 表单重置 | ||||
| const reset = () => { | ||||
|   form.value = { ...initFormData }; | ||||
|   treeFormRef.value?.resetFields(); | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = (row?: TreeVO) => { | ||||
|   reset(); | ||||
|   getTreeselect(); | ||||
|   if (row && row.id) { | ||||
|     form.value.parentId = row.id; | ||||
|   } else { | ||||
|     form.value.parentId = 0; | ||||
|   } | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '添加测试树'; | ||||
| }; | ||||
|  | ||||
| /** 展开/折叠操作 */ | ||||
| const handleToggleExpandAll = () => { | ||||
|   isExpandAll.value = !isExpandAll.value; | ||||
|   toggleExpandAll(treeList.value, isExpandAll.value); | ||||
| }; | ||||
|  | ||||
| /** 展开/折叠操作 */ | ||||
| const toggleExpandAll = (data: TreeVO[], status: boolean) => { | ||||
|   data.forEach((item) => { | ||||
|     treeTableRef.value?.toggleRowExpansion(item, status); | ||||
|     if (item.children && item.children.length > 0) toggleExpandAll(item.children, status); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 修改按钮操作 */ | ||||
| const handleUpdate = async (row: TreeVO) => { | ||||
|   reset(); | ||||
|   await getTreeselect(); | ||||
|   if (row) { | ||||
|     form.value.parentId = row.id; | ||||
|   } | ||||
|   const res = await getTree(row.id); | ||||
|   Object.assign(form.value, res.data); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '修改测试树'; | ||||
| }; | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = () => { | ||||
|   treeFormRef.value?.validate(async (valid: boolean) => { | ||||
|     if (valid) { | ||||
|       buttonLoading.value = true; | ||||
|       if (form.value.id) { | ||||
|         await updateTree(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } else { | ||||
|         await addTree(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } | ||||
|       proxy?.$modal.msgSuccess('操作成功'); | ||||
|       dialog.visible = false; | ||||
|       await getList(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row: TreeVO) => { | ||||
|   await proxy?.$modal.confirm('是否确认删除测试树编号为"' + row.id + '"的数据项?'); | ||||
|   loading.value = true; | ||||
|   await delTree(row.id).finally(() => (loading.value = false)); | ||||
|   await getList(); | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,164 +1,95 @@ | ||||
| <template> | ||||
|   <div class="app-container home"> | ||||
|     <el-row :gutter="20"> | ||||
|       <el-col :sm="24" :lg="12" style="padding-left: 20px"> | ||||
|         <h2>RuoYi-Vue-Plus多租户管理系统</h2> | ||||
|         <p> | ||||
|           RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架) | ||||
|           <br /> | ||||
|           * 前端开发框架 Vue3、TS、Element Plus<br /> | ||||
|           * 后端开发框架 Spring Boot<br /> | ||||
|           * 容器框架 Undertow 基于 Netty 的高性能容器<br /> | ||||
|           * 权限认证框架 Sa-Token 支持多终端认证系统<br /> | ||||
|           * 关系数据库 MySQL 适配 8.X 最低 5.7<br /> | ||||
|           * 缓存数据库 Redis 适配 6.X 最低 4.X<br /> | ||||
|           * 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br /> | ||||
|           * 数据库框架 p6spy 更强劲的 SQL 分析<br /> | ||||
|           * 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br /> | ||||
|           * 序列化框架 Jackson 统一使用 jackson 高效可靠<br /> | ||||
|           * Redis客户端 Redisson 性能强劲、API丰富<br /> | ||||
|           * 分布式限流 Redisson 全局、请求IP、集群ID 多种限流<br /> | ||||
|           * 分布式锁 Lock4j 注解锁、工具锁 多种多样<br /> | ||||
|           * 分布式幂等 Lock4j 基于分布式锁实现<br /> | ||||
|           * 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br /> | ||||
|           * 分布式任务调度 SnailJob 高性能 高可靠 易扩展<br /> | ||||
|           * 文件存储 Minio 本地存储<br /> | ||||
|           * 文件存储 七牛、阿里、腾讯 云存储<br /> | ||||
|           * 监控框架 SpringBoot-Admin 全方位服务监控<br /> | ||||
|           * 校验框架 Validation 增强接口安全性 严谨性<br /> | ||||
|           * Excel框架 Alibaba EasyExcel 性能优异 扩展性强<br /> | ||||
|           * 文档框架 SpringDoc、javadoc 无注解零入侵基于java注释<br /> | ||||
|           * 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性<br /> | ||||
|           * 代码生成器 适配MP、SpringDoc规范化代码 一键生成前后端代码<br /> | ||||
|           * 部署方式 Docker 容器编排 一键部署业务集群<br /> | ||||
|           * 国际化 SpringMessage Spring标准国际化方案<br /> | ||||
|         </p> | ||||
|         <p><b>当前版本:</b> <span>v5.3.0</span></p> | ||||
|         <p> | ||||
|           <el-tag type="danger">¥免费开源</el-tag> | ||||
|         </p> | ||||
|         <p> | ||||
|           <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button> | ||||
|           <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button> | ||||
|           <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')" | ||||
|             >更新日志</el-button | ||||
|           > | ||||
|         </p> | ||||
|       </el-col> | ||||
|   <div class="dashboard"> | ||||
|     <h2 class="title">后台管理系统</h2> | ||||
|  | ||||
|       <el-col :sm="24" :lg="12" style="padding-left: 20px"> | ||||
|         <h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2> | ||||
|         <p> | ||||
|           RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架) | ||||
|           <br /> | ||||
|           * 前端开发框架 Vue3、TS、Element UI<br /> | ||||
|           * 后端开发框架 Spring Boot<br /> | ||||
|           * 微服务开发框架 Spring Cloud、Spring Cloud Alibaba<br /> | ||||
|           * 容器框架 Undertow 基于 XNIO 的高性能容器<br /> | ||||
|           * 权限认证框架 Sa-Token、Jwt 支持多终端认证系统<br /> | ||||
|           * 关系数据库 MySQL 适配 8.X 最低 5.7<br /> | ||||
|           * 关系数据库 Oracle 适配 11g 12c<br /> | ||||
|           * 关系数据库 PostgreSQL 适配 13 14<br /> | ||||
|           * 关系数据库 SQLServer 适配 2017 2019<br /> | ||||
|           * 缓存数据库 Redis 适配 6.X 最低 5.X<br /> | ||||
|           * 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br /> | ||||
|           * 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br /> | ||||
|           * 服务网关 Spring Cloud Gateway 响应式高性能网关<br /> | ||||
|           * 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br /> | ||||
|           * RPC远程调用 Apache Dubbo 原生态使用体验、高性能<br /> | ||||
|           * 分布式限流熔断 Alibaba Sentinel 无侵入、高扩展<br /> | ||||
|           * 分布式事务 Alibaba Seata 无侵入、高扩展 支持 四种模式<br /> | ||||
|           * 分布式消息队列 Apache Kafka 高性能高速度<br /> | ||||
|           * 分布式消息队列 Apache RocketMQ 高可用功能多样<br /> | ||||
|           * 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br /> | ||||
|           * 分布式搜索引擎 ElasticSearch 业界知名<br /> | ||||
|           * 分布式链路追踪 Apache SkyWalking 链路追踪、网格分析、度量聚合、可视化<br /> | ||||
|           * 分布式日志中心 ELK 业界成熟解决方案<br /> | ||||
|           * 分布式监控 Prometheus、Grafana 全方位性能监控<br /> | ||||
|           * 其余与 Vue 版本一致<br /> | ||||
|         </p> | ||||
|         <p><b>当前版本:</b> <span>v2.3.0</span></p> | ||||
|         <p> | ||||
|           <el-tag type="danger">¥免费开源</el-tag> | ||||
|         </p> | ||||
|         <p> | ||||
|           <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button> | ||||
|           <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button> | ||||
|           <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')" | ||||
|             >更新日志</el-button | ||||
|           > | ||||
|         </p> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|     <el-divider /> | ||||
|     <div class="stats"> | ||||
|       <div class="stat-card"> | ||||
|         <h3>用户总数</h3> | ||||
|         <p>{{ userCount }}</p> | ||||
|       </div> | ||||
|       <div class="stat-card"> | ||||
|         <h3>今日订单</h3> | ||||
|         <p>{{ orderCount }}</p> | ||||
|       </div> | ||||
|       <div class="stat-card"> | ||||
|         <h3>系统访问量</h3> | ||||
|         <p>{{ visitCount }}</p> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Index" lang="ts"> | ||||
| const goTarget = (url: string) => { | ||||
|   window.open(url, '__blank'); | ||||
| import { ref } from "vue"; | ||||
| import { useRouter } from "vue-router"; | ||||
|  | ||||
| const router = useRouter(); | ||||
|  | ||||
| // 模拟数据 | ||||
| const userCount = ref(1234); | ||||
| const orderCount = ref(567); | ||||
| const visitCount = ref(8901); | ||||
|  | ||||
| const goToPage = (page: string) => { | ||||
|   router.push(`/${page}`); | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .home { | ||||
|   blockquote { | ||||
|     padding: 10px 20px; | ||||
|     margin: 0 0 20px; | ||||
|     font-size: 17.5px; | ||||
|     border-left: 5px solid #eee; | ||||
|   } | ||||
|   hr { | ||||
|     margin-top: 20px; | ||||
|     margin-bottom: 20px; | ||||
|     border: 0; | ||||
|     border-top: 1px solid #eee; | ||||
|   } | ||||
|   .col-item { | ||||
|     margin-bottom: 20px; | ||||
|   } | ||||
| .dashboard { | ||||
|   padding: 20px; | ||||
|   background-color: #f8f9fa; | ||||
| } | ||||
|  | ||||
|   ul { | ||||
|     padding: 0; | ||||
|     margin: 0; | ||||
|   } | ||||
| .title { | ||||
|   text-align: center; | ||||
|   font-size: 24px; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
|  | ||||
|   font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; | ||||
|   font-size: 13px; | ||||
|   color: #676a6c; | ||||
|   overflow-x: hidden; | ||||
| .stats { | ||||
|   display: flex; | ||||
|   justify-content: space-around; | ||||
|   margin-bottom: 20px; | ||||
|  | ||||
|   ul { | ||||
|     list-style-type: none; | ||||
|   } | ||||
|   .stat-card { | ||||
|     background: white; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||||
|     text-align: center; | ||||
|     width: 200px; | ||||
|  | ||||
|   h4 { | ||||
|     margin-top: 0px; | ||||
|   } | ||||
|     h3 { | ||||
|       font-size: 16px; | ||||
|       color: #333; | ||||
|     } | ||||
|  | ||||
|   h2 { | ||||
|     margin-top: 10px; | ||||
|     font-size: 26px; | ||||
|     font-weight: 100; | ||||
|   } | ||||
|  | ||||
|   p { | ||||
|     margin-top: 10px; | ||||
|  | ||||
|     b { | ||||
|       font-weight: 700; | ||||
|     p { | ||||
|       font-size: 20px; | ||||
|       font-weight: bold; | ||||
|       margin-top: 10px; | ||||
|       color: #007bff; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|   .update-log { | ||||
|     ol { | ||||
|       display: block; | ||||
|       list-style-type: decimal; | ||||
|       margin-block-start: 1em; | ||||
|       margin-block-end: 1em; | ||||
|       margin-inline-start: 0; | ||||
|       margin-inline-end: 0; | ||||
|       padding-inline-start: 40px; | ||||
| .actions { | ||||
|   text-align: center; | ||||
|  | ||||
|   button { | ||||
|     margin: 0 10px; | ||||
|     padding: 10px 20px; | ||||
|     font-size: 16px; | ||||
|     border: none; | ||||
|     border-radius: 5px; | ||||
|     cursor: pointer; | ||||
|     background-color: #007bff; | ||||
|     color: white; | ||||
|     transition: 0.3s; | ||||
|  | ||||
|     &:hover { | ||||
|       background-color: #0056b3; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										383
									
								
								src/views/personnelManagement/project/project/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										383
									
								
								src/views/personnelManagement/project/project/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,383 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="项目名称" prop="projectName"> | ||||
|               <el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="项目简称" prop="shortName"> | ||||
|               <el-input v-model="queryParams.shortName" placeholder="请输入项目简称" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <!-- <el-form-item label="父项目id" prop="pId"> | ||||
|               <el-input v-model="queryParams.pId" placeholder="请输入父项目id" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="项目图片" prop="picUrl"> | ||||
|               <el-input v-model="queryParams.picUrl" placeholder="请输入项目图片" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="删除时间" prop="deletedAt"> | ||||
|               <el-date-picker clearable v-model="queryParams.deletedAt" type="date" value-format="YYYY-MM-DD" placeholder="请选择删除时间" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="项目地址" prop="projectSite"> | ||||
|               <el-input v-model="queryParams.projectSite" placeholder="请输入项目地址" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="负责人" prop="principal"> | ||||
|               <el-input v-model="queryParams.principal" placeholder="请输入负责人" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="负责人电话" prop="principalPhone"> | ||||
|               <el-input v-model="queryParams.principalPhone" placeholder="请输入负责人电话" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="实际容量" prop="actual"> | ||||
|               <el-input v-model="queryParams.actual" placeholder="请输入实际容量" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="计划容量" prop="plan"> | ||||
|               <el-input v-model="queryParams.plan" placeholder="请输入计划容量" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="开工时间" prop="onStreamTime"> | ||||
|               <el-input v-model="queryParams.onStreamTime" placeholder="请输入开工时间" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="打卡范围" prop="punchRange"> | ||||
|               <el-input v-model="queryParams.punchRange" placeholder="请输入打卡范围" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="设计总量" prop="designTotal"> | ||||
|               <el-input v-model="queryParams.designTotal" placeholder="请输入设计总量" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="安全协议书" prop="securityAgreement"> | ||||
|               <el-input v-model="queryParams.securityAgreement" placeholder="请输入安全协议书" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="排序字段" prop="sort"> | ||||
|               <el-input v-model="queryParams.sort" placeholder="请输入排序字段" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="显示隐藏" prop="showHidden"> | ||||
|               <el-input v-model="queryParams.showHidden" placeholder="请输入显示隐藏" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="是否删除" prop="isDelete">  | ||||
|               <el-input v-model="queryParams.isDelete" placeholder="请输入是否删除" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> --> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:project:add']">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:project:edit']" | ||||
|               >修改</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['project:project:remove']" | ||||
|               >删除</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['project:project:export']">导出</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column label="" align="center" prop="id" v-if="true" /> | ||||
|         <el-table-column label="项目名称" align="center" prop="projectName" /> | ||||
|         <el-table-column label="项目简称" align="center" prop="shortName" /> | ||||
|         <el-table-column label="父项目id" align="center" prop="pId" /> | ||||
|         <el-table-column label="状态" align="center" prop="status" /> | ||||
|         <el-table-column label="项目图片" align="center" prop="picUrl" /> | ||||
|         <el-table-column label="备注" align="center" prop="remark" /> | ||||
|         <el-table-column label="项目类型" align="center" prop="type" /> | ||||
|         <el-table-column label="项目类型" align="center" prop="isType" /> | ||||
|         <!-- <el-table-column label="删除时间" align="center" prop="deletedAt" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.deletedAt, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> --> | ||||
|         <el-table-column label="项目地址" align="center" prop="projectSite" /> | ||||
|         <el-table-column label="负责人" align="center" prop="principal" /> | ||||
|         <el-table-column label="负责人电话" align="center" prop="principalPhone" /> | ||||
|         <el-table-column label="实际容量" align="center" prop="actual" /> | ||||
|         <el-table-column label="计划容量" align="center" prop="plan" /> | ||||
|         <el-table-column label="开工时间" align="center" prop="onStreamTime" /> | ||||
|         <el-table-column label="打卡范围" align="center" prop="punchRange" /> | ||||
|         <el-table-column label="设计总量" align="center" prop="designTotal" /> | ||||
|         <el-table-column label="安全协议书" align="center" prop="securityAgreement" /> | ||||
|         <el-table-column label="排序字段" align="center" prop="sort" /> | ||||
|         <el-table-column label="显示隐藏" align="center" prop="showHidden" /> | ||||
|         <el-table-column label="是否删除" align="center" prop="isDelete" /> | ||||
|         <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-tooltip content="修改" placement="top"> | ||||
|               <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']"></el-button> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="删除" placement="top"> | ||||
|               <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']"></el-button> | ||||
|             </el-tooltip> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|  | ||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||
|     </el-card> | ||||
|     <!-- 添加或修改项目对话框 --> | ||||
|     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||
|       <el-form ref="projectFormRef" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="项目名称" prop="projectName"> | ||||
|           <el-input v-model="form.projectName" placeholder="请输入项目名称" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="项目简称" prop="shortName"> | ||||
|           <el-input v-model="form.shortName" placeholder="请输入项目简称" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="父项目id" prop="pId"> | ||||
|           <el-input v-model="form.pId" placeholder="请输入父项目id" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="项目图片" prop="picUrl"> | ||||
|           <el-input v-model="form.picUrl" placeholder="请输入项目图片" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="备注" prop="remark"> | ||||
|           <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> | ||||
|         </el-form-item> | ||||
|         <!-- <el-form-item label="删除时间" prop="deletedAt"> | ||||
|           <el-date-picker clearable v-model="form.deletedAt" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择删除时间"> | ||||
|           </el-date-picker> | ||||
|         </el-form-item> --> | ||||
|         <el-form-item label="项目地址" prop="projectSite"> | ||||
|           <el-input v-model="form.projectSite" placeholder="请输入项目地址" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="负责人" prop="principal"> | ||||
|           <el-input v-model="form.principal" placeholder="请输入负责人" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="负责人电话" prop="principalPhone"> | ||||
|           <el-input v-model="form.principalPhone" placeholder="请输入负责人电话" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="实际容量" prop="actual"> | ||||
|           <el-input v-model="form.actual" placeholder="请输入实际容量" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="计划容量" prop="plan"> | ||||
|           <el-input v-model="form.plan" placeholder="请输入计划容量" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="开工时间" prop="onStreamTime"> | ||||
|           <el-input v-model="form.onStreamTime" placeholder="请输入开工时间" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="打卡范围" prop="punchRange"> | ||||
|           <el-input v-model="form.punchRange" placeholder="请输入打卡范围" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="设计总量" prop="designTotal"> | ||||
|           <el-input v-model="form.designTotal" placeholder="请输入设计总量" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="安全协议书" prop="securityAgreement"> | ||||
|           <el-input v-model="form.securityAgreement" placeholder="请输入安全协议书" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="排序字段" prop="sort"> | ||||
|           <el-input v-model="form.sort" placeholder="请输入排序字段" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="显示隐藏" prop="showHidden"> | ||||
|           <el-input v-model="form.showHidden" placeholder="请输入显示隐藏" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="是否删除" prop="isDelete"> | ||||
|           <el-input v-model="form.isDelete" placeholder="请输入是否删除" /> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Project" lang="ts"> | ||||
| import { listProject, getProject, delProject, addProject, updateProject } from '@/api/project/project'; | ||||
| import { ProjectVO, ProjectQuery, ProjectForm } from '@/api/project/project/types'; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
|  | ||||
| const projectList = ref<ProjectVO[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const projectFormRef = ref<ElFormInstance>(); | ||||
|  | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
|  | ||||
| const initFormData: ProjectForm = { | ||||
|   id: undefined, | ||||
|   projectName: undefined, | ||||
|   shortName: undefined, | ||||
|   pId: undefined, | ||||
|   status: undefined, | ||||
|   picUrl: undefined, | ||||
|   remark: undefined, | ||||
|   type: undefined, | ||||
|   isType: undefined, | ||||
|   deletedAt: undefined, | ||||
|   projectSite: undefined, | ||||
|   principal: undefined, | ||||
|   principalPhone: undefined, | ||||
|   actual: undefined, | ||||
|   plan: undefined, | ||||
|   onStreamTime: undefined, | ||||
|   punchRange: undefined, | ||||
|   designTotal: undefined, | ||||
|   securityAgreement: undefined, | ||||
|   sort: undefined, | ||||
|   showHidden: undefined, | ||||
|   isDelete: undefined | ||||
| }; | ||||
| const data = reactive<PageData<ProjectForm, ProjectQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     projectName: undefined, | ||||
|     shortName: undefined, | ||||
|     pId: undefined, | ||||
|     status: undefined, | ||||
|     picUrl: undefined, | ||||
|     type: undefined, | ||||
|     isType: undefined, | ||||
|     deletedAt: undefined, | ||||
|     projectSite: undefined, | ||||
|     principal: undefined, | ||||
|     principalPhone: undefined, | ||||
|     actual: undefined, | ||||
|     plan: undefined, | ||||
|     onStreamTime: undefined, | ||||
|     punchRange: undefined, | ||||
|     designTotal: undefined, | ||||
|     securityAgreement: undefined, | ||||
|     sort: undefined, | ||||
|     showHidden: undefined, | ||||
|     isDelete: undefined, | ||||
|     params: {} | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '不能为空', trigger: 'blur' }], | ||||
|     punchRange: [{ required: true, message: '打卡范围不能为空', trigger: 'blur' }], | ||||
|     designTotal: [{ required: true, message: '设计总量不能为空', trigger: 'blur' }], | ||||
|     sort: [{ required: true, message: '排序字段不能为空', trigger: 'blur' }], | ||||
|     showHidden: [{ required: true, message: '显示隐藏不能为空', trigger: 'blur' }], | ||||
|     isDelete: [{ required: true, message: '是否删除不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| /** 查询项目列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listProject(queryParams.value); | ||||
|   projectList.value = res.records; | ||||
|   total.value = res.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
| /** 取消按钮 */ | ||||
| const cancel = () => { | ||||
|   reset(); | ||||
|   dialog.visible = false; | ||||
| }; | ||||
| /** 表单重置 */ | ||||
| const reset = () => { | ||||
|   form.value = { ...initFormData }; | ||||
|   projectFormRef.value?.resetFields(); | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 多选框选中数据 */ | ||||
| const handleSelectionChange = (selection: ProjectVO[]) => { | ||||
|   ids.value = selection.map((item) => item.id); | ||||
|   single.value = selection.length != 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = () => { | ||||
|   reset(); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '添加项目'; | ||||
|    | ||||
| }; | ||||
|  | ||||
| /** 修改按钮操作 */ | ||||
| const handleUpdate = async (row?: ProjectVO) => { | ||||
|   reset(); | ||||
|   const _id = row?.id || ids.value[0]; | ||||
|   const res = await getProject(_id); | ||||
|   Object.assign(form.value, res.data); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '修改项目'; | ||||
| }; | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = () => { | ||||
|   projectFormRef.value?.validate(async (valid: boolean) => { | ||||
|     if (valid) { | ||||
|       buttonLoading.value = true; | ||||
|       if (form.value.id) { | ||||
|         await updateProject(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } else { | ||||
|         await addProject(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } | ||||
|       proxy?.$modal.msgSuccess('操作成功'); | ||||
|       dialog.visible = false; | ||||
|       await getList(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row?: ProjectVO) => { | ||||
|   const _ids = row?.id || ids.value; | ||||
|   await proxy?.$modal.confirm('是否确认删除项目编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); | ||||
|   await delProject(_ids); | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
|   await getList(); | ||||
| }; | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = () => { | ||||
|   proxy?.download( | ||||
|     'project/project/export', | ||||
|     { | ||||
|       ...queryParams.value | ||||
|     }, | ||||
|     `project_${new Date().getTime()}.xlsx` | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
| }); | ||||
| </script> | ||||
| @ -0,0 +1,88 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div> | ||||
|       <el-transfer v-model="selectedProjects" :data="allProjects" filterable :titles="['项目列表', '已关联项目']" @change="handleTransferChange" /> | ||||
|     </div> | ||||
|     <div style="text-align: right; margin-top: 20px"> | ||||
|       <el-button type="primary" @click="$emit('close')">关闭</el-button> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { ref, onMounted, defineProps, watch } from 'vue'; | ||||
| import { listProject } from '@/api/project/project'; | ||||
| import { listUserProjects, addNewProjectRelevancy, removeNewProjectRelevancy } from '@/api/project/projectRelevancy'; | ||||
|  | ||||
| // **从父组件接收 `userId`** | ||||
| const props = defineProps<{ userId: number }>(); | ||||
|  | ||||
| // **所有项目列表** | ||||
| const allProjects = ref<{ key: number; label: string }[]>([]); | ||||
|  | ||||
| // **已关联的项目 ID 列表** | ||||
| const selectedProjects = ref<number[]>([]); | ||||
|  | ||||
| // **获取所有项目列表** | ||||
| const getProjectList = async () => { | ||||
|   try { | ||||
|     const res = await listProject(); | ||||
|     allProjects.value = res.records.map((project) => ({ | ||||
|       key: project.id, | ||||
|       label: project.projectName | ||||
|     })); | ||||
|   } catch (error) { | ||||
|     console.error('获取项目列表失败:', error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const getUserProjects = async () => { | ||||
|   if (!props.userId) return; | ||||
|   try { | ||||
|     const res = await listUserProjects({ userId: props.userId }); | ||||
|  | ||||
|     // **确保 `res.rows` 是数组** | ||||
|     selectedProjects.value = Array.isArray(res.rows) ? res.rows.map((item) => item.projectId) : []; | ||||
|   } catch (error) { | ||||
|     console.error('获取用户关联的项目失败:', error); | ||||
|     selectedProjects.value = []; // **请求失败时清空列表** | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // **监听 `userId` 变化,重新加载关联数据** | ||||
| watch( | ||||
|   () => props.userId, | ||||
|   async (newUserId) => { | ||||
|     if (newUserId) { | ||||
|       await getUserProjects(); | ||||
|     } | ||||
|   }, | ||||
|   { immediate: true } | ||||
| ); | ||||
|  | ||||
| // **处理穿梭框变更** | ||||
| const handleTransferChange = async (newValue: number[], direction: 'left' | 'right', movedKeys: number[]) => { | ||||
|   try { | ||||
|     if (direction === 'right') { | ||||
|       // **添加关联** | ||||
|       await addNewProjectRelevancy({ | ||||
|         userId: props.userId, | ||||
|         projectIdList: movedKeys | ||||
|       }); | ||||
|     } else { | ||||
|       // **移除关联** | ||||
|       await removeNewProjectRelevancy({ | ||||
|         userId: props.userId, | ||||
|         projectIdList: movedKeys | ||||
|       }); | ||||
|     } | ||||
|   } catch (error) { | ||||
|     console.error('更新项目关联失败:', error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // **初始化数据** | ||||
| onMounted(async () => { | ||||
|   await getProjectList(); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										323
									
								
								src/views/personnelManagement/project/projectRelevancy/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								src/views/personnelManagement/project/projectRelevancy/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,323 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="用户ID" prop="userId"> | ||||
|               <el-input v-model="queryParams.userId" placeholder="请输入用户ID" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="项目ID" prop="projectId"> | ||||
|               <el-input v-model="queryParams.projectId" placeholder="请输入项目ID" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <!--            <el-form-item label="删除时间" prop="deletedAt">--> | ||||
|             <!--              <el-date-picker clearable v-model="queryParams.deletedAt" type="date" value-format="YYYY-MM-DD" placeholder="请选择删除时间" />--> | ||||
|             <!--            </el-form-item>--> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:projectRelevancy:add']">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:projectRelevancy:edit']" | ||||
|               >修改</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['project:projectRelevancy:remove']" | ||||
|               >删除</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['project:projectRelevancy:export']">导出</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" :data="projectRelevancyList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column prop="id" label="关联ID" width="180" /> | ||||
|         <el-table-column prop="userId" label="用户ID" width="100" /> | ||||
|         <el-table-column prop="projectId" label="项目ID" width="180" /> | ||||
|         <el-table-column prop="project.projectName" label="项目名称" width="200" /> | ||||
|         <el-table-column prop="project.type" label="项目类型" width="150" /> | ||||
|         <el-table-column prop="project.projectSite" label="项目地址" width="200" /> | ||||
|         <el-table-column prop="project.principal" label="负责人" width="120" /> | ||||
|         <el-table-column prop="project.principalPhone" label="联系电话" width="150" /> | ||||
|         <el-table-column prop="project.onStreamTime" label="上线时间" width="150" /> | ||||
|         <!-- <el-table-column label="删除时间" align="center" prop="deletedAt" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.deletedAt, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> --> | ||||
|         <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-tooltip content="修改" placement="top"> | ||||
|               <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:projectRelevancy:edit']"></el-button> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="删除" placement="top"> | ||||
|               <el-button | ||||
|                 link | ||||
|                 type="primary" | ||||
|                 icon="Delete" | ||||
|                 @click="handleDelete(scope.row)" | ||||
|                 v-hasPermi="['project:projectRelevancy:remove']" | ||||
|               ></el-button> | ||||
|             </el-tooltip> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|       <!-- 添加 ShuttleFrame 弹窗 --> | ||||
|       <el-dialog v-model="shuttleVisible" title="编辑关联项目" width="auto" destroy-on-close> | ||||
|         <shuttle-frame :userId="selectedUserId" @close="shuttleVisible = false" /> | ||||
|       </el-dialog> | ||||
|  | ||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||
|     </el-card> | ||||
|  | ||||
|     <!-- 添加或修改系统用户与项目关联对话框 --> | ||||
|     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||
|       <el-form ref="projectRelevancyFormRef" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="用户ID" prop="userId"> | ||||
|           <el-select v-model="form.userId" placeholder="请选择用户"> | ||||
|             <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|  | ||||
|         <el-form-item label="项目ID" prop="projectId"> | ||||
|           <!-- 项目ID下拉选择框 --> | ||||
|           <el-select v-model="form.projectId" placeholder="请选择项目ID" @change="onProjectChange"> | ||||
|             <el-option v-for="project in projectList" :key="project.id" :label="project.projectName" :value="project.id" /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <!-- <el-form-item label="删除时间" prop="deletedAt"> | ||||
|           <el-date-picker clearable v-model="form.deletedAt" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" | ||||
|             placeholder="请选择删除时间"> | ||||
|           </el-date-picker> | ||||
|         </el-form-item> --> | ||||
|       </el-form> | ||||
|       <div v-if="selectedProject" style="padding: 0px 100px"> | ||||
|         <p><strong>项目名称:</strong> {{ selectedProject.projectName }}</p> | ||||
|         <p><strong>项目类型:</strong> {{ selectedProject.type }}</p> | ||||
|         <p><strong>项目地址:</strong> {{ selectedProject.projectSite }}</p> | ||||
|         <p><strong>负责人:</strong> {{ selectedProject.principal }}</p> | ||||
|         <p><strong>联系电话:</strong> {{ selectedProject.principalPhone }}</p> | ||||
|       </div> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="ProjectRelevancy" lang="ts"> | ||||
| import { listProjectRelevancy, delProjectRelevancy, addProjectRelevancy, updateProjectRelevancy } from '@/api/project/projectRelevancy'; | ||||
| import { listProject } from '@/api/project/project'; | ||||
| import { listUser } from '@/api/system/user'; | ||||
| import { ProjectRelevancyVO, ProjectRelevancyQuery, ProjectRelevancyForm } from '@/api/project/projectRelevancy/types'; | ||||
| import ShuttleFrame from './component/ShuttleFrame.vue'; | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
|  | ||||
| const projectRelevancyList = ref<ProjectRelevancyVO[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const projectRelevancyFormRef = ref<ElFormInstance>(); | ||||
|  | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
|  | ||||
| const initFormData: ProjectRelevancyForm = { | ||||
|   id: undefined, | ||||
|   userId: undefined, | ||||
|   projectId: undefined, | ||||
|   deletedAt: undefined | ||||
| }; | ||||
| const data = reactive<PageData<ProjectRelevancyForm, ProjectRelevancyQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     userId: undefined, | ||||
|     projectId: undefined, | ||||
|     deletedAt: undefined, | ||||
|     params: {} | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }], | ||||
|     userId: [{ required: true, message: '用户ID不能为空', trigger: 'blur' }], | ||||
|     projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| /** 查询系统用户与项目关联列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listProjectRelevancy(queryParams.value); | ||||
|   projectRelevancyList.value = res.data.records; | ||||
|   total.value = res.data.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| /** 取消按钮 */ | ||||
| const cancel = () => { | ||||
|   reset(); | ||||
|   dialog.visible = false; | ||||
| }; | ||||
|  | ||||
| /** 表单重置 */ | ||||
| const reset = () => { | ||||
|   form.value = { ...initFormData }; | ||||
|   projectRelevancyFormRef.value?.resetFields(); | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 多选框选中数据 */ | ||||
| const handleSelectionChange = (selection: ProjectRelevancyVO[]) => { | ||||
|   ids.value = selection.map((item) => item.id); | ||||
|   single.value = selection.length != 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = () => { | ||||
|   reset(); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '添加系统用户与项目关联'; | ||||
| }; | ||||
|  | ||||
| const shuttleVisible = ref(false); | ||||
| const selectedUserId = ref<number>(); | ||||
|  | ||||
| const handleUpdate = (row?: ProjectRelevancyVO) => { | ||||
|   const currentRow = row || projectRelevancyList.value.find((item) => item.id === ids.value[0]); | ||||
|   if (currentRow) { | ||||
|     selectedUserId.value = currentRow.userId;  | ||||
|     shuttleVisible.value = true;  | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = () => { | ||||
|   projectRelevancyFormRef.value?.validate(async (valid: boolean) => { | ||||
|     if (valid) { | ||||
|       buttonLoading.value = true; | ||||
|       if (form.value.id) { | ||||
|         await updateProjectRelevancy(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } else { | ||||
|         await addProjectRelevancy(form.value).finally(() => (buttonLoading.value = false)); | ||||
|       } | ||||
|       proxy?.$modal.msgSuccess('操作成功'); | ||||
|       dialog.visible = false; | ||||
|       await getList(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row?: ProjectRelevancyVO) => { | ||||
|   const _ids = row?.id || ids.value; | ||||
|   await proxy?.$modal.confirm('是否确认删除系统用户与项目关联编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); | ||||
|   await delProjectRelevancy(_ids); | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
|   await getList(); | ||||
| }; | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = () => { | ||||
|   proxy?.download( | ||||
|     'project/projectRelevancy/export', | ||||
|     { | ||||
|       ...queryParams.value | ||||
|     }, | ||||
|     `projectRelevancy_${new Date().getTime()}.xlsx` | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| const projectList = ref<any[]>([]);  | ||||
| const projectItem = new Map();  | ||||
| const selectedProject = ref<any | null>(null);  | ||||
|  | ||||
| // 获取项目列表的方法 | ||||
| const getProjectList = async () => { | ||||
|   try { | ||||
|     const res = await listProject(); | ||||
|     const projectListData = res.records; | ||||
|     projectList.value = projectListData; | ||||
|  | ||||
|     // 将项目详情存入 Map | ||||
|     projectListData.forEach((project) => { | ||||
|       projectItem.set(project.id, { | ||||
|         projectName: project.projectName, | ||||
|         type: project.type, | ||||
|         projectSite: project.projectSite, | ||||
|         principal: project.principal, | ||||
|         principalPhone: project.principalPhone | ||||
|       }); | ||||
|     }); | ||||
|   } catch (error) { | ||||
|     console.error('获取项目列表失败:', error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // 当选择项目时触发 | ||||
| const onProjectChange = (projectId: string) => { | ||||
|   selectedProject.value = projectItem.get(projectId) || null; | ||||
| }; | ||||
|  | ||||
| //获取新增用户列表方法 | ||||
|  | ||||
| const userList = ref<{ label: string; value: string }[]>([]); | ||||
| const getUserList = async () => { | ||||
|   try { | ||||
|     const response = await listUser({}); | ||||
|     userList.value = response.rows.map((user: any) => ({ | ||||
|       userId: user.userId, | ||||
|       nickName: user.nickName | ||||
|     })); | ||||
|   } catch (error) { | ||||
|     console.error('获取用户列表失败:', error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
|   getProjectList(); | ||||
|   getUserList(); | ||||
| }); | ||||
| </script> | ||||
| <style></style> | ||||
| @ -1,11 +0,0 @@ | ||||
| <script setup lang="ts"> | ||||
|  | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   $END$ | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|  | ||||
| </style> | ||||
| @ -1,10 +1,44 @@ | ||||
| <script setup lang="ts"> | ||||
| // 模拟分包单位数据列表 | ||||
| const subcontractedUnits = [ | ||||
|   { id: 1, name: '分包单位A' }, | ||||
|   { id: 2, name: '分包单位B' }, | ||||
|   { id: 3, name: '分包单位C' } | ||||
| ]; | ||||
|  | ||||
| // 模拟一个方法,点击按钮时触发 | ||||
| const handleButtonClick = () => { | ||||
|   console.log('点击了按钮,对分包单位进行操作'); | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|  | ||||
|   <div> | ||||
|     <h1>分包单位</h1> | ||||
|     <ul> | ||||
|       <li v-for="unit in subcontractedUnits" :key="unit.id">{{ unit.name }}</li> | ||||
|     </ul> | ||||
|     <button @click="handleButtonClick">操作分包单位</button> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| /* 这里可以添加一些样式,比如设置列表样式和按钮样式 */ | ||||
| ul { | ||||
|   list-style-type: none; | ||||
|   padding: 0; | ||||
| } | ||||
|  | ||||
| li { | ||||
|   margin: 5px 0; | ||||
| } | ||||
|  | ||||
| button { | ||||
|   padding: 8px 16px; | ||||
|   background-color: #007bff; | ||||
|   color: white; | ||||
|   border: none; | ||||
|   border-radius: 4px; | ||||
|   cursor: pointer; | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|  | ||||
|   <div><h1>班组分配</h1></div> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|  | ||||
| @ -1,10 +1,151 @@ | ||||
| <script setup lang="ts"> | ||||
| import { computed } from 'vue'; | ||||
| import { useUserStore } from '@/store/modules/user'; | ||||
| import { storeToRefs } from 'pinia'; | ||||
|  | ||||
| // 获取用户存储 | ||||
| const userStore = useUserStore(); | ||||
|  | ||||
| // 使 selectedProject 保持响应式 | ||||
| const { selectedProject } = storeToRefs(userStore); | ||||
|  | ||||
| // 模拟不同项目的施工人员数据 | ||||
| const projectWorkers = [ | ||||
|   { | ||||
|     projectId: '1897160897167638529', | ||||
|     workers: [ | ||||
|       { id: 1, name: '张三', role: '工头', phone: '13800000001' }, | ||||
|       { id: 2, name: '李四', role: '电工', phone: '13800000002' }, | ||||
|       { id: 3, name: '王五', role: '焊工', phone: '13800000003' } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     projectId: '1897161054676336641', | ||||
|     workers: [ | ||||
|       { id: 4, name: '赵六', role: '木工', phone: '13800000004' }, | ||||
|       { id: 5, name: '孙七', role: '油漆工', phone: '13800000005' }, | ||||
|       { id: 6, name: '周八', role: '瓦工', phone: '13800000006' } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     projectId: '1897161104060071938', | ||||
|     workers: [ | ||||
|       { id: 7, name: '吴九', role: '钢筋工', phone: '13800000007' }, | ||||
|       { id: 8, name: '郑十', role: '施工员', phone: '13800000008' }, | ||||
|       { id: 9, name: '冯十一', role: '安全员', phone: '13800000009' } | ||||
|     ] | ||||
|   } | ||||
| ]; | ||||
|  | ||||
| // 计算当前项目的施工人员 | ||||
| const workers = computed(() => { | ||||
|   const project = projectWorkers.find((p) => p.projectId === selectedProject.value?.id); | ||||
|   return project ? project.workers : []; | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div class="container"> | ||||
|     <h1>施工人员列表</h1> | ||||
|     <div class="project-info"> | ||||
|       <span class="label">当前选中的项目:</span> | ||||
|       <span class="project-name">{{ selectedProject?.name || '未选择项目' }}</span> | ||||
|     </div> | ||||
|  | ||||
|     <div class="workers-list"> | ||||
|       <h2>施工人员</h2> | ||||
|       <ul v-if="workers.length > 0"> | ||||
|         <li v-for="worker in workers" :key="worker.id"> | ||||
|           <span class="worker-name">{{ worker.name }}</span> | ||||
|           <span class="worker-role">({{ worker.role }})</span> | ||||
|           <span class="worker-phone">{{ worker.phone }}</span> | ||||
|         </li> | ||||
|       </ul> | ||||
|       <p v-else class="no-workers">暂无施工人员数据</p> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .container { | ||||
|   padding: 20px; | ||||
|   background-color: #f9f9f9; | ||||
|   border-radius: 10px; | ||||
|   box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| h1 { | ||||
|   font-size: 24px; | ||||
|   color: #333; | ||||
|   margin-bottom: 15px; | ||||
| } | ||||
|  | ||||
| .project-info { | ||||
|   padding: 10px; | ||||
|   background: #fff; | ||||
|   border-radius: 8px; | ||||
|   display: inline-block; | ||||
|   box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); | ||||
| } | ||||
|  | ||||
| .label { | ||||
|   font-size: 16px; | ||||
|   color: #666; | ||||
| } | ||||
|  | ||||
| .project-name { | ||||
|   font-size: 18px; | ||||
|   font-weight: bold; | ||||
|   color: #007bff; | ||||
|   margin-left: 5px; | ||||
| } | ||||
|  | ||||
| .workers-list { | ||||
|   margin-top: 20px; | ||||
|   background: #fff; | ||||
|   padding: 15px; | ||||
|   border-radius: 10px; | ||||
|   box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); | ||||
|   text-align: left; | ||||
| } | ||||
|  | ||||
| h2 { | ||||
|   font-size: 20px; | ||||
|   color: #444; | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
|  | ||||
| ul { | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
| } | ||||
|  | ||||
| li { | ||||
|   padding: 8px 0; | ||||
|   border-bottom: 1px solid #ddd; | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
| } | ||||
|  | ||||
| .worker-name { | ||||
|   font-size: 16px; | ||||
|   font-weight: bold; | ||||
|   color: #333; | ||||
| } | ||||
|  | ||||
| .worker-role { | ||||
|   font-size: 14px; | ||||
|   color: #666; | ||||
| } | ||||
|  | ||||
| .worker-phone { | ||||
|   font-size: 14px; | ||||
|   color: #888; | ||||
| } | ||||
|  | ||||
| .no-workers { | ||||
|   font-size: 16px; | ||||
|   color: #999; | ||||
|   margin-top: 10px; | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -1,257 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="search"> | ||||
|         <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|           <el-form-item label="分类名称" prop="categoryName"> | ||||
|             <el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable @keyup.enter="handleQuery" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item> | ||||
|             <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|             <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['workflow:category:add']">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|       <el-table | ||||
|         ref="categoryTableRef" | ||||
|         v-loading="loading" | ||||
|         :data="categoryList" | ||||
|         row-key="categoryId" | ||||
|         :default-expand-all="isExpandAll" | ||||
|         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" | ||||
|       > | ||||
|         <el-table-column label="分类名称" prop="categoryName" width="260"/> | ||||
|         <el-table-column label="显示顺序" align="center" prop="orderNum" width="200" /> | ||||
|         <el-table-column label="创建时间" align="center" prop="createTime" width="180" /> | ||||
|         <el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-tooltip content="修改" placement="top"> | ||||
|               <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['workflow:category:edit']" /> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="新增" placement="top"> | ||||
|               <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['workflow:category:add']" /> | ||||
|             </el-tooltip> | ||||
|             <el-tooltip content="删除" placement="top"> | ||||
|               <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['workflow:category:remove']" /> | ||||
|             </el-tooltip> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|     </el-card> | ||||
|     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||
|       <el-form ref="categoryFormRef" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="上级分类" prop="parentId"> | ||||
|           <el-tree-select | ||||
|             v-model="form.parentId" | ||||
|             :data="categoryOptions" | ||||
|             :props="{ value: 'categoryId', label: 'categoryName', children: 'children' }" | ||||
|             value-key="categoryId" | ||||
|             placeholder="请选择上级分类" | ||||
|             check-strictly | ||||
|           /> | ||||
|         </el-form-item> | ||||
|         <el-row :gutter="20"> | ||||
|           <el-col :span="12"> | ||||
|             <el-form-item label="分类名称" prop="categoryName"> | ||||
|               <el-input v-model="form.categoryName" placeholder="请输入分类名称" /> | ||||
|             </el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <el-form-item label="排序" prop="orderNum"> | ||||
|               <el-input-number v-model="form.orderNum" controls-position="right" :min="0" /> | ||||
|             </el-form-item> | ||||
|           </el-col> | ||||
|         </el-row> | ||||
|       </el-form> | ||||
|     <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Category" lang="ts"> | ||||
| import { listCategory, getCategory, delCategory, addCategory, updateCategory } from "@/api/workflow/category"; | ||||
| import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/workflow/category/types'; | ||||
|  | ||||
| type CategoryOption = { | ||||
|   categoryId: number; | ||||
|   categoryName: string; | ||||
|   children?: CategoryOption[]; | ||||
| } | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance;; | ||||
|  | ||||
|  | ||||
| const categoryList = ref<CategoryVO[]>([]); | ||||
| const categoryOptions = ref<CategoryOption[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const showSearch = ref(true); | ||||
| const isExpandAll = ref(true); | ||||
| const loading = ref(false); | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const categoryFormRef = ref<ElFormInstance>(); | ||||
| const categoryTableRef = ref<ElTableInstance>() | ||||
|  | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
|  | ||||
|  | ||||
| const initFormData: CategoryForm = { | ||||
|   categoryId: undefined, | ||||
|   categoryName: "", | ||||
|   parentId: undefined, | ||||
|   orderNum: 0, | ||||
| } | ||||
|  | ||||
| const data = reactive<PageData<CategoryForm, CategoryQuery>>({ | ||||
|   form: {...initFormData}, | ||||
|   queryParams: { | ||||
|     categoryName: undefined, | ||||
|   }, | ||||
|   rules: { | ||||
|     categoryId: [ | ||||
|       { required: true, message: "流程分类ID不能为空", trigger: "blur" } | ||||
|     ], | ||||
|     parentId: [{ required: true, message: "请选择上级分类", trigger: "change" }], | ||||
|     categoryName: [{ required: true, message: "请输入分类名称", trigger: "blur" }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| /** 查询流程分类列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listCategory(queryParams.value); | ||||
|   const data = proxy?.handleTree<CategoryVO>(res.data, "categoryId", "parentId"); | ||||
|   if (data) { | ||||
|     categoryList.value = data; | ||||
|     loading.value = false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** 查询流程分类下拉树结构 */ | ||||
| const getTreeselect = async () => { | ||||
|   const res = await listCategory(); | ||||
|   categoryOptions.value = []; | ||||
|   // 处理树形数据 | ||||
|   const data = proxy?.handleTree<CategoryOption>(res.data, "categoryId", "parentId"); | ||||
|   if (data) { | ||||
|     categoryOptions.value = data; // 将处理后的树形数据赋值 | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // 取消按钮 | ||||
| const cancel = () => { | ||||
|   reset(); | ||||
|   dialog.visible = false; | ||||
| } | ||||
|  | ||||
| // 表单重置 | ||||
| const reset = () => { | ||||
|   form.value = {...initFormData} | ||||
|   categoryFormRef.value?.resetFields(); | ||||
| } | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   getList(); | ||||
| } | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| } | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = (row?: CategoryVO) => { | ||||
|   reset(); | ||||
|   getTreeselect(); | ||||
|   if (row?.categoryId) { | ||||
|     form.value.parentId = row.categoryId; | ||||
|   } else { | ||||
|     form.value.parentId = undefined; | ||||
|   } | ||||
|   dialog.visible = true; | ||||
|   dialog.title = "添加流程分类"; | ||||
| } | ||||
|  | ||||
| /** 展开/折叠操作 */ | ||||
| const handleToggleExpandAll = () => { | ||||
|   isExpandAll.value = !isExpandAll.value; | ||||
|   toggleExpandAll(categoryList.value, isExpandAll.value) | ||||
| } | ||||
|  | ||||
| /** 展开/折叠操作 */ | ||||
| const toggleExpandAll = (data: CategoryVO[], status: boolean) => { | ||||
|   data.forEach((item) => { | ||||
|     categoryTableRef.value?.toggleRowExpansion(item, status) | ||||
|     if (item.children && item.children.length > 0) toggleExpandAll(item.children, status) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| /** 修改按钮操作 */ | ||||
| const handleUpdate = async (row: CategoryVO) => { | ||||
|   reset(); | ||||
|   await getTreeselect(); | ||||
|   if (row != null) { | ||||
|     form.value.parentId = row.parentId; | ||||
|   } | ||||
|   const res = await getCategory(row.categoryId); | ||||
|   Object.assign(form.value, res.data); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = "修改流程分类"; | ||||
| } | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = () => { | ||||
|   categoryFormRef.value?.validate(async (valid: boolean) => { | ||||
|     if (valid) { | ||||
|       buttonLoading.value = true; | ||||
|       if (form.value.categoryId) { | ||||
|         await updateCategory(form.value).finally(() => buttonLoading.value = false); | ||||
|       } else { | ||||
|         await addCategory(form.value).finally(() => buttonLoading.value = false); | ||||
|       } | ||||
|       proxy?.$modal.msgSuccess("操作成功"); | ||||
|       dialog.visible = false; | ||||
|       getList(); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row: CategoryVO) => { | ||||
|   await proxy?.$modal.confirm('是否确认删除"' + row.categoryName + '"的分类?'); | ||||
|   loading.value = true; | ||||
|   await delCategory(row.categoryId).finally(() => loading.value = false); | ||||
|   await getList(); | ||||
|   proxy?.$modal.msgSuccess("删除成功"); | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,236 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="search"> | ||||
|         <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|           <el-form-item label="请假天数" prop="startLeaveDays"> | ||||
|             <el-input v-model="queryParams.startLeaveDays" placeholder="请输入请假天数" clearable @keyup.enter="handleQuery" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item prop="endLeaveDays"> 至 </el-form-item> | ||||
|           <el-form-item prop="endLeaveDays"> | ||||
|             <el-input v-model="queryParams.endLeaveDays" placeholder="请输入请假天数" clearable @keyup.enter="handleQuery" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item> | ||||
|             <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|             <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['workflow:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button v-hasPermi="['workflow:leave:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" border :data="leaveList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column v-if="false" label="主键" align="center" prop="id" /> | ||||
|         <el-table-column label="请假类型" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-tag>{{ options.find((e) => e.value === scope.row.leaveType)?.label }}</el-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="开始时间" align="center" prop="startDate"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ proxy.parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="结束时间" align="center" prop="endDate"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ proxy.parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="请假天数" align="center" prop="leaveDays" /> | ||||
|         <el-table-column label="请假原因" align="center" prop="remark" /> | ||||
|         <el-table-column align="center" label="流程状态" min-width="70"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="wf_business_status" :value="scope.row.status"></dict-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="操作" align="center" width="162"> | ||||
|           <template #default="scope"> | ||||
|             <el-row :gutter="10" class="mb8"> | ||||
|               <el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'"> | ||||
|                 <el-button v-hasPermi="['workflow:leave:edit']" size="small" type="primary" icon="Edit" @click="handleUpdate(scope.row)" | ||||
|                   >修改</el-button | ||||
|                 > | ||||
|               </el-col> | ||||
|               <el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'"> | ||||
|                 <el-button v-hasPermi="['workflow:leave:remove']" size="small" type="primary" icon="Delete" @click="handleDelete(scope.row)" | ||||
|                   >删除</el-button | ||||
|                 > | ||||
|               </el-col> | ||||
|             </el-row> | ||||
|             <el-row :gutter="10" class="mb8"> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> | ||||
|               </el-col> | ||||
|               <el-col :span="1.5" v-if="scope.row.status === 'waiting'"> | ||||
|                 <el-button size="small" type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.id)">撤销</el-button> | ||||
|               </el-col> | ||||
|             </el-row> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|  | ||||
|       <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> | ||||
|     </el-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Leave" lang="ts"> | ||||
| import { delLeave, listLeave } from '@/api/workflow/leave'; | ||||
| import { cancelProcessApply } from '@/api/workflow/instance'; | ||||
| import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types'; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| const leaveList = ref<LeaveVO[]>([]); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
| const options = [ | ||||
|   { | ||||
|     value: '1', | ||||
|     label: '事假' | ||||
|   }, | ||||
|   { | ||||
|     value: '2', | ||||
|     label: '调休' | ||||
|   }, | ||||
|   { | ||||
|     value: '3', | ||||
|     label: '病假' | ||||
|   }, | ||||
|   { | ||||
|     value: '4', | ||||
|     label: '婚假' | ||||
|   } | ||||
| ]; | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
|  | ||||
| const data = reactive<PageData<LeaveForm, LeaveQuery>>({ | ||||
|   form: {}, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     startLeaveDays: undefined, | ||||
|     endLeaveDays: undefined | ||||
|   }, | ||||
|   rules: {} | ||||
| }); | ||||
|  | ||||
| const { queryParams } = toRefs(data); | ||||
|  | ||||
| /** 查询请假列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listLeave(queryParams.value); | ||||
|   leaveList.value = res.rows; | ||||
|   total.value = res.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 多选框选中数据 */ | ||||
| const handleSelectionChange = (selection: LeaveVO[]) => { | ||||
|   ids.value = selection.map((item) => item.id); | ||||
|   single.value = selection.length != 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = () => { | ||||
|   proxy.$tab.closePage(proxy.$route); | ||||
|   proxy.$router.push({ | ||||
|     path: `/workflow/leaveEdit/index`, | ||||
|     query: { | ||||
|       type: 'add' | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 修改按钮操作 */ | ||||
| const handleUpdate = (row?: LeaveVO) => { | ||||
|   proxy.$tab.closePage(proxy.$route); | ||||
|   proxy.$router.push({ | ||||
|     path: `/workflow/leaveEdit/index`, | ||||
|     query: { | ||||
|       id: row.id, | ||||
|       type: 'update' | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 查看按钮操作 */ | ||||
| const handleView = (row?: LeaveVO) => { | ||||
|   proxy.$tab.closePage(proxy.$route); | ||||
|   proxy.$router.push({ | ||||
|     path: `/workflow/leaveEdit/index`, | ||||
|     query: { | ||||
|       id: row.id, | ||||
|       type: 'view' | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row?: LeaveVO) => { | ||||
|   const _ids = row?.id || ids.value; | ||||
|   await proxy?.$modal.confirm('是否确认删除请假编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); | ||||
|   await delLeave(_ids); | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
|   await getList(); | ||||
| }; | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = () => { | ||||
|   proxy?.download( | ||||
|     'workflow/leave/export', | ||||
|     { | ||||
|       ...queryParams.value | ||||
|     }, | ||||
|     `leave_${new Date().getTime()}.xlsx` | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| /** 撤销按钮操作 */ | ||||
| const handleCancelProcessApply = async (id: string) => { | ||||
|   await proxy?.$modal.confirm('是否确认撤销当前单据?'); | ||||
|   loading.value = true; | ||||
|   let data = { | ||||
|     businessId: id, | ||||
|     message: '申请人撤销流程!' | ||||
|   }; | ||||
|   await cancelProcessApply(data).finally(() => (loading.value = false)); | ||||
|   await getList(); | ||||
|   proxy?.$modal.msgSuccess('撤销成功'); | ||||
| }; | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,308 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <el-card shadow="never"> | ||||
|       <div style="display: flex; justify-content: space-between"> | ||||
|         <div> | ||||
|           <el-button v-if="submitButtonShow" :loading="buttonLoading" type="info" @click="submitForm('draft')">暂存</el-button> | ||||
|           <el-button v-if="submitButtonShow" :loading="buttonLoading" type="primary" @click="submitForm('submit')">提 交</el-button> | ||||
|           <el-button v-if="approvalButtonShow" :loading="buttonLoading" type="primary" @click="approvalVerifyOpen">审批</el-button> | ||||
|           <el-button v-if="form && form.id && form.status !== 'draft'" type="primary" @click="handleApprovalRecord">流程进度</el-button> | ||||
|         </div> | ||||
|         <div> | ||||
|           <el-button style="float: right" @click="goBack()">返回</el-button> | ||||
|         </div> | ||||
|       </div> | ||||
|     </el-card> | ||||
|     <el-card shadow="never" style="height: 78vh; overflow-y: auto"> | ||||
|       <el-form ref="leaveFormRef" v-loading="loading" :disabled="routeParams.type === 'view'" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="请假类型" prop="leaveType"> | ||||
|           <el-select v-model="form.leaveType" placeholder="请选择请假类型" style="width: 100%"> | ||||
|             <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="请假时间"> | ||||
|           <el-date-picker | ||||
|             v-model="leaveTime" | ||||
|             value-format="YYYY-MM-DD HH:mm:ss" | ||||
|             type="daterange" | ||||
|             range-separator="To" | ||||
|             start-placeholder="开始时间" | ||||
|             end-placeholder="结束时间" | ||||
|             :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" | ||||
|             @change="changeLeaveTime()" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="请假天数" prop="leaveDays"> | ||||
|           <el-input v-model="form.leaveDays" disabled type="number" placeholder="请输入请假天数" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="请假原因" prop="remark"> | ||||
|           <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入请假原因" /> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </el-card> | ||||
|     <!-- 提交组件 --> | ||||
|     <submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" /> | ||||
|     <!-- 审批记录 --> | ||||
|     <approvalRecord ref="approvalRecordRef" /> | ||||
|     <el-dialog v-model="dialogVisible.visible" :title="dialogVisible.title" :before-close="handleClose" width="500"> | ||||
|       <el-select v-model="flowCode" placeholder="Select" style="width: 240px"> | ||||
|         <el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" /> | ||||
|       </el-select> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button @click="handleClose">取消</el-button> | ||||
|           <el-button type="primary" @click="submitFlow()"> 确认 </el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Leave" lang="ts"> | ||||
| import { addLeave, getLeave, updateLeave } from '@/api/workflow/leave'; | ||||
| import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types'; | ||||
| import { startWorkFlow } from '@/api/workflow/task'; | ||||
| import SubmitVerify from '@/components/Process/submitVerify.vue'; | ||||
| import ApprovalRecord from '@/components/Process/approvalRecord.vue'; | ||||
| import { AxiosResponse } from 'axios'; | ||||
| import { StartProcessBo } from '@/api/workflow/workflowCommon/types'; | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
|  | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const leaveTime = ref<Array<string>>([]); | ||||
| //路由参数 | ||||
| const routeParams = ref<Record<string, any>>({}); | ||||
| const options = [ | ||||
|   { | ||||
|     value: '1', | ||||
|     label: '事假' | ||||
|   }, | ||||
|   { | ||||
|     value: '2', | ||||
|     label: '调休' | ||||
|   }, | ||||
|   { | ||||
|     value: '3', | ||||
|     label: '病假' | ||||
|   }, | ||||
|   { | ||||
|     value: '4', | ||||
|     label: '婚假' | ||||
|   } | ||||
| ]; | ||||
| const flowCodeOptions = [ | ||||
|   { | ||||
|     value: 'leave1', | ||||
|     label: '请假申请-普通' | ||||
|   }, | ||||
|   { | ||||
|     value: 'leave2', | ||||
|     label: '请假申请-排他网关' | ||||
|   }, | ||||
|   { | ||||
|     value: 'leave3', | ||||
|     label: '请假申请-并行网关' | ||||
|   }, | ||||
|   { | ||||
|     value: 'leave4', | ||||
|     label: '请假申请-会签' | ||||
|   }, | ||||
|   { | ||||
|     value: 'leave5', | ||||
|     label: '请假申请-并行会签网关' | ||||
|   } | ||||
| ]; | ||||
|  | ||||
| const flowCode = ref<string>(''); | ||||
|  | ||||
| const dialogVisible = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '流程定义' | ||||
| }); | ||||
| //提交组件 | ||||
| const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>(); | ||||
| //审批记录组件 | ||||
| const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); | ||||
|  | ||||
| const leaveFormRef = ref<ElFormInstance>(); | ||||
|  | ||||
| const submitFormData = ref<StartProcessBo>({ | ||||
|   businessId: '', | ||||
|   flowCode: '', | ||||
|   variables: {} | ||||
| }); | ||||
| const taskVariables = ref<Record<string, any>>({}); | ||||
|  | ||||
| const initFormData: LeaveForm = { | ||||
|   id: undefined, | ||||
|   leaveType: undefined, | ||||
|   startDate: undefined, | ||||
|   endDate: undefined, | ||||
|   leaveDays: undefined, | ||||
|   remark: undefined, | ||||
|   status: undefined | ||||
| }; | ||||
| const data = reactive<PageData<LeaveForm, LeaveQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     startLeaveDays: undefined, | ||||
|     endLeaveDays: undefined | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键不能为空', trigger: 'blur' }], | ||||
|     leaveType: [{ required: true, message: '请假类型不能为空', trigger: 'blur' }], | ||||
|     leaveTime: [{ required: true, message: '请假时间不能为空', trigger: 'blur' }], | ||||
|     leaveDays: [{ required: true, message: '请假天数不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const handleClose = () => { | ||||
|   dialogVisible.visible = false; | ||||
|   flowCode.value = ''; | ||||
|   buttonLoading.value = false; | ||||
| }; | ||||
| const { form, rules } = toRefs(data); | ||||
|  | ||||
| /** 表单重置 */ | ||||
| const reset = () => { | ||||
|   form.value = { ...initFormData }; | ||||
|   leaveTime.value = []; | ||||
|   leaveFormRef.value?.resetFields(); | ||||
| }; | ||||
|  | ||||
| const changeLeaveTime = () => { | ||||
|   const startDate = new Date(leaveTime.value[0]).getTime(); | ||||
|   const endDate = new Date(leaveTime.value[1]).getTime(); | ||||
|   const diffInMilliseconds = endDate - startDate; | ||||
|   form.value.leaveDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24)) + 1; | ||||
| }; | ||||
| /** 获取详情 */ | ||||
| const getInfo = () => { | ||||
|   loading.value = true; | ||||
|   buttonLoading.value = false; | ||||
|   nextTick(async () => { | ||||
|     const res = await getLeave(routeParams.value.id); | ||||
|     Object.assign(form.value, res.data); | ||||
|     leaveTime.value = []; | ||||
|     leaveTime.value.push(form.value.startDate); | ||||
|     leaveTime.value.push(form.value.endDate); | ||||
|     loading.value = false; | ||||
|     buttonLoading.value = false; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = (status: string) => { | ||||
|   if (leaveTime.value.length === 0) { | ||||
|     proxy?.$modal.msgError('请假时间不能为空'); | ||||
|     return; | ||||
|   } | ||||
|   try { | ||||
|     leaveFormRef.value?.validate(async (valid: boolean) => { | ||||
|       form.value.startDate = leaveTime.value[0]; | ||||
|       form.value.endDate = leaveTime.value[1]; | ||||
|       if (valid) { | ||||
|         buttonLoading.value = true; | ||||
|         let res: AxiosResponse<LeaveVO>; | ||||
|         if (form.value.id) { | ||||
|           res = await updateLeave(form.value); | ||||
|         } else { | ||||
|           res = await addLeave(form.value); | ||||
|         } | ||||
|         form.value = res.data; | ||||
|         if (status === 'draft') { | ||||
|           buttonLoading.value = false; | ||||
|           proxy?.$modal.msgSuccess('暂存成功'); | ||||
|           proxy.$tab.closePage(proxy.$route); | ||||
|           proxy.$router.go(-1); | ||||
|         } else { | ||||
|           if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') { | ||||
|             flowCode.value = flowCodeOptions[0].value; | ||||
|             dialogVisible.visible = true; | ||||
|             return; | ||||
|           } | ||||
|           //说明启动过先随意穿个参数 | ||||
|           if (flowCode.value === '' || flowCode.value === null) { | ||||
|             flowCode.value = 'xx'; | ||||
|           } | ||||
|           await handleStartWorkFlow(res.data); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   } finally { | ||||
|     buttonLoading.value = false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const submitFlow = async () => { | ||||
|   handleStartWorkFlow(form.value); | ||||
|   dialogVisible.visible = false; | ||||
| }; | ||||
| //提交申请 | ||||
| const handleStartWorkFlow = async (data: LeaveForm) => { | ||||
|   try { | ||||
|     submitFormData.value.flowCode = flowCode.value; | ||||
|     submitFormData.value.businessId = data.id; | ||||
|     //流程变量 | ||||
|     taskVariables.value = { | ||||
|       leaveDays: data.leaveDays, | ||||
|       userList: ['1', '3', '4'] | ||||
|     }; | ||||
|     submitFormData.value.variables = taskVariables.value; | ||||
|     const resp = await startWorkFlow(submitFormData.value); | ||||
|     if (submitVerifyRef.value) { | ||||
|       buttonLoading.value = false; | ||||
|       submitVerifyRef.value.openDialog(resp.data.taskId); | ||||
|     } | ||||
|   } finally { | ||||
|     buttonLoading.value = false; | ||||
|   } | ||||
| }; | ||||
| //审批记录 | ||||
| const handleApprovalRecord = () => { | ||||
|   approvalRecordRef.value.init(form.value.id); | ||||
| }; | ||||
| //提交回调 | ||||
| const submitCallback = async () => { | ||||
|   await proxy.$tab.closePage(proxy.$route); | ||||
|   proxy.$router.go(-1); | ||||
| }; | ||||
|  | ||||
| //返回 | ||||
| const goBack = () => { | ||||
|   proxy.$tab.closePage(proxy.$route); | ||||
|   proxy.$router.go(-1); | ||||
| }; | ||||
| //审批 | ||||
| const approvalVerifyOpen = async () => { | ||||
|   submitVerifyRef.value.openDialog(routeParams.value.taskId); | ||||
| }; | ||||
| //校验提交按钮是否显示 | ||||
| const submitButtonShow = computed(() => { | ||||
|   return ( | ||||
|     routeParams.value.type === 'add' || | ||||
|     (routeParams.value.type === 'update' && | ||||
|       form.value.status && | ||||
|       (form.value.status === 'draft' || form.value.status === 'cancel' || form.value.status === 'back')) | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| //校验审批按钮是否显示 | ||||
| const approvalButtonShow = computed(() => { | ||||
|   return routeParams.value.type === 'approval' && form.value.status && form.value.status === 'waiting'; | ||||
| }); | ||||
|  | ||||
| onMounted(() => { | ||||
|   nextTick(async () => { | ||||
|     routeParams.value = proxy.$route.query; | ||||
|     reset(); | ||||
|     loading.value = false; | ||||
|     if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') { | ||||
|       getInfo(); | ||||
|     } | ||||
|   }); | ||||
| }); | ||||
| </script> | ||||
| @ -1,46 +0,0 @@ | ||||
| <template> | ||||
|   <div ref="container" class="w-full h-[calc(100vh-88px)]"> | ||||
|     <iframe ref="iframe" :src="iframeUrl" frameborder="0" height="100%" style="height: 100%; width: inherit"></iframe> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="WarmFlow"> | ||||
| const { proxy } = getCurrentInstance(); | ||||
| import { onMounted } from 'vue'; | ||||
| import { getToken } from '@/utils/auth'; | ||||
|  | ||||
| // definitionId为需要查询的流程定义id, | ||||
| // disabled为是否可编辑, 例如:查看的时候不可编辑,不可保存 | ||||
| const iframeUrl = ref(''); | ||||
| const baseUrl = import.meta.env.VITE_APP_BASE_API; | ||||
| const iframeLoaded = () => { | ||||
|   // iframe监听组件内设计器保存事件 | ||||
|   window.onmessage = (event) => { | ||||
|     switch (event.data.method) { | ||||
|       case 'close': | ||||
|         close(); | ||||
|         break; | ||||
|     } | ||||
|   }; | ||||
| }; | ||||
| const open = async (definitionId, disabled) => { | ||||
|   let url = baseUrl + `/warm-flow-ui/index.html?id=${definitionId}&disabled=${disabled}`; | ||||
|   iframeUrl.value = url + '&Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID; | ||||
| }; | ||||
| /** 关闭按钮 */ | ||||
| function close() { | ||||
|   const obj = { path: '/workflow/processDefinition', query: {activeName: proxy.$route.query.activeName}}; | ||||
|   proxy.$tab.closeOpenPage(obj); | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
|   iframeLoaded(); | ||||
|   open(proxy.$route.query.definitionId, proxy.$route.query.disabled); | ||||
| }); | ||||
| /** | ||||
|  * 对外暴露子组件方法 | ||||
|  */ | ||||
| defineExpose({ | ||||
|   open | ||||
| }); | ||||
| </script> | ||||
| @ -1,517 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <el-row :gutter="20"> | ||||
|       <!-- 流程分类树 --> | ||||
|       <el-col :lg="4" :xs="24" style=""> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable /> | ||||
|           <el-tree | ||||
|             ref="categoryTreeRef" | ||||
|             class="mt-2" | ||||
|             node-key="id" | ||||
|             :data="categoryOptions" | ||||
|             :props="{ label: 'label', children: 'children' }" | ||||
|             :expand-on-click-node="false" | ||||
|             :filter-node-method="filterNode" | ||||
|             highlight-current | ||||
|             default-expand-all | ||||
|             @node-click="handleNodeClick" | ||||
|           ></el-tree> | ||||
|         </el-card> | ||||
|       </el-col> | ||||
|       <el-col :lg="20" :xs="24"> | ||||
|         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|           <div v-show="showSearch" class="mb-[10px]"> | ||||
|             <el-card shadow="hover"> | ||||
|               <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px"> | ||||
|                 <el-form-item label="流程定义名称" prop="flowName"> | ||||
|                   <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" clearable @keyup.enter="handleQuery" /> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item label="流程定义KEY" prop="flowCode"> | ||||
|                   <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义KEY" clearable @keyup.enter="handleQuery" /> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item> | ||||
|                   <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|                   <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|                 </el-form-item> | ||||
|               </el-form> | ||||
|             </el-card> | ||||
|           </div> | ||||
|         </transition> | ||||
|         <el-card shadow="hover"> | ||||
|           <template #header> | ||||
|             <el-row :gutter="10" class="mb8"> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="primary" icon="Plus" @click="handleAdd()">添加</el-button> | ||||
|               </el-col> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="success" icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button> | ||||
|               </el-col> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="danger" icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button> | ||||
|               </el-col> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="primary" icon="UploadFilled" @click="uploadDialog.visible = true">部署流程文件</el-button> | ||||
|               </el-col> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="warning" icon="Download" :disabled="single" @click="handleExportDef">导出</el-button> | ||||
|               </el-col> | ||||
|               <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|             </el-row> | ||||
|           </template> | ||||
|           <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> | ||||
|             <el-tab-pane label="已发布" name="0"></el-tab-pane> | ||||
|             <el-tab-pane label="未发布" name="1"></el-tab-pane> | ||||
|             <el-table v-loading="loading" border :data="processDefinitionList" @selection-change="handleSelectionChange"> | ||||
|               <el-table-column type="selection" width="55" align="center" /> | ||||
|               <el-table-column align="center" prop="id" label="主键" v-if="false"></el-table-column> | ||||
|               <el-table-column align="center" prop="flowName" label="流程定义名称" :show-overflow-tooltip="true"></el-table-column> | ||||
|               <el-table-column align="center" prop="flowCode" label="标识KEY" :show-overflow-tooltip="true"></el-table-column> | ||||
|               <el-table-column align="center" prop="version" label="版本号" width="80"> | ||||
|                 <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|               </el-table-column> | ||||
|               <el-table-column align="center" prop="activityStatus" label="激活状态" width="130"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-switch | ||||
|                     v-model="scope.row.activityStatus" | ||||
|                     :active-value="1" | ||||
|                     :inactive-value="0" | ||||
|                     @change="(status) => handleProcessDefState(scope.row, status)" | ||||
|                   /> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column align="center" prop="isPublish" label="发布状态" width="100"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-tag v-if="scope.row.isPublish == 0" type="danger">未发布</el-tag> | ||||
|                   <el-tag v-else-if="scope.row.isPublish == 1" type="success">已发布</el-tag> | ||||
|                   <el-tag v-else type="danger">失效</el-tag> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column fixed="right" label="操作" align="center" width="170" class-name="small-padding fixed-width"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-row :gutter="10" class="mb8"> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">删除流程</el-button> | ||||
|                     </el-col> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-button link type="primary" size="small" icon="CopyDocument" @click="handleCopyDef(scope.row)">复制流程</el-button> | ||||
|                     </el-col> | ||||
|                   </el-row> | ||||
|                   <el-row :gutter="10" class="mb8"> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-button link type="primary" v-if="scope.row.isPublish === 0" icon="Pointer" size="small" @click="design(scope.row)" | ||||
|                         >流程设计</el-button | ||||
|                       > | ||||
|                       <el-button link type="primary" v-else icon="View" size="small" @click="designView(scope.row)">查看流程</el-button> | ||||
|                     </el-col> | ||||
|                     <el-col v-if="scope.row.isPublish !== 1" :span="1.5"> | ||||
|                       <el-button link type="primary" size="small" icon="CircleCheck" @click="handlePublish(scope.row)">发布流程</el-button> | ||||
|                     </el-col> | ||||
|                   </el-row> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </el-table> | ||||
|             <pagination | ||||
|               v-show="total > 0" | ||||
|               v-model:page="queryParams.pageNum" | ||||
|               v-model:limit="queryParams.pageSize" | ||||
|               :total="total" | ||||
|               @pagination="getPageList" | ||||
|             /> | ||||
|           </el-tabs> | ||||
|         </el-card> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|  | ||||
|     <!-- 部署文件 --> | ||||
|     <el-dialog v-if="uploadDialog.visible" v-model="uploadDialog.visible" :title="uploadDialog.title" width="30%"> | ||||
|       <div v-loading="uploadDialogLoading"> | ||||
|         <div class="mb5"> | ||||
|           <el-text class="mx-1" size="large"><span class="text-danger">*</span>请选择部署流程分类:</el-text> | ||||
|           <el-tree-select | ||||
|             v-model="selectCategory" | ||||
|             :data="categoryOptions" | ||||
|             :props="{ value: 'id', label: 'label', children: 'children' }" | ||||
|             filterable | ||||
|             value-key="id" | ||||
|             :render-after-expand="false" | ||||
|             check-strictly | ||||
|             style="width: 240px" | ||||
|           /> | ||||
|         </div> | ||||
|         <el-upload | ||||
|           class="upload-demo" | ||||
|           drag | ||||
|           multiple | ||||
|           accept="application/json,application/text" | ||||
|           :before-upload="handlerBeforeUpload" | ||||
|           :http-request="handlerImportDefinition" | ||||
|         > | ||||
|           <el-icon class="UploadFilled"><upload-filled /></el-icon> | ||||
|           <div class="el-upload__text"><em>点击上传,选择JSON流程文件</em></div> | ||||
|           <div class="el-upload__text">仅支持json格式文件</div> | ||||
|           <div class="el-upload__text">PS:如若部署请部署从本项目模型管理导出的数据</div> | ||||
|         </el-upload> | ||||
|       </div> | ||||
|     </el-dialog> | ||||
|  | ||||
|     <!-- 新增/编辑流程定义 --> | ||||
|     <el-dialog v-model="modelDialog.visible" :title="modelDialog.title" width="650px" append-to-body :close-on-click-modal="false"> | ||||
|       <template #footer> | ||||
|         <el-form ref="defFormRef" :model="form" :rules="rules" label-width="110px"> | ||||
|           <el-form-item label="流程类别" prop="category"> | ||||
|             <el-tree-select | ||||
|               v-model="form.category" | ||||
|               :data="categoryOptions" | ||||
|               :props="{ value: 'id', label: 'label', children: 'children' }" | ||||
|               filterable | ||||
|               value-key="id" | ||||
|               :render-after-expand="false" | ||||
|               check-strictly | ||||
|               style="width: 100%" | ||||
|             /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="流程编码" prop="flowCode"> | ||||
|             <el-input v-model="form.flowCode" placeholder="请输入流程编码" maxlength="40" show-word-limit /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="流程名称" prop="flowName"> | ||||
|             <el-input v-model="form.flowName" placeholder="请输入流程名称" maxlength="100" show-word-limit /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="表单路径" prop="flowName"> | ||||
|             <el-input v-model="form.formPath" placeholder="请输入表单路径" maxlength="100" show-word-limit /> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button @click="modelDialog.visible = false">取消</el-button> | ||||
|           <el-button type="primary" @click="handleSubmit">保存</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup name="processDefinition"> | ||||
| import { listDefinition, deleteDefinition, active, importDef, unPublishList, publish, add, edit, getInfo, copy } from '@/api/workflow/definition'; | ||||
| import { categoryTree } from '@/api/workflow/category'; | ||||
| import { CategoryTreeVO } from '@/api/workflow/category/types'; | ||||
| import { FlowDefinitionQuery, FlowDefinitionVo, FlowDefinitionForm } from '@/api/workflow/definition/types'; | ||||
| import { UploadRequestOptions, TabsPaneContext } from 'element-plus'; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const categoryTreeRef = ref<ElTreeInstance>(); | ||||
|  | ||||
| const loading = ref(true); | ||||
| const ids = ref<Array<any>>([]); | ||||
| const flowCodeList = ref<Array<any>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const total = ref(0); | ||||
| const uploadDialogLoading = ref(false); | ||||
| const processDefinitionList = ref<FlowDefinitionVo[]>([]); | ||||
| const categoryOptions = ref<CategoryTreeVO[]>([]); | ||||
| const categoryName = ref(''); | ||||
| /** 部署文件分类选择 */ | ||||
| const selectCategory = ref(); | ||||
| const defFormRef = ref<ElFormInstance>(); | ||||
| const activeName = ref('0'); | ||||
| const uploadDialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '部署流程文件' | ||||
| }); | ||||
|  | ||||
| const processDefinitionDialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '历史版本' | ||||
| }); | ||||
|  | ||||
| const modelDialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
|  | ||||
| // 查询参数 | ||||
| const queryParams = ref<FlowDefinitionQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   flowName: undefined, | ||||
|   flowCode: undefined, | ||||
|   category: undefined | ||||
| }); | ||||
| const rules = { | ||||
|   category: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }], | ||||
|   flowName: [{ required: true, message: '流程定义名称不能为空', trigger: 'blur' }], | ||||
|   flowCode: [{ required: true, message: '流程定义编码不能为空', trigger: 'blur' }] | ||||
| }; | ||||
| const initFormData: FlowDefinitionForm = { | ||||
|   id: '', | ||||
|   flowName: '', | ||||
|   flowCode: '', | ||||
|   category: '', | ||||
|   formPath: '' | ||||
| }; | ||||
| //流程定义参数 | ||||
| const form = ref<FlowDefinitionForm>({ | ||||
|   id: '', | ||||
|   flowName: '', | ||||
|   flowCode: '', | ||||
|   category: '', | ||||
|   formPath: '' | ||||
| }); | ||||
| onMounted(() => { | ||||
|   getPageList(); | ||||
|   getTreeselect(); | ||||
| }); | ||||
|  | ||||
| /** 节点单击事件 */ | ||||
| const handleNodeClick = (data: CategoryTreeVO) => { | ||||
|   queryParams.value.category = data.id; | ||||
|   if (data.id === '0') { | ||||
|     queryParams.value.category = ''; | ||||
|   } | ||||
|   handleQuery(); | ||||
| }; | ||||
| /** 通过条件过滤节点  */ | ||||
| const filterNode = (value: string, data: any) => { | ||||
|   if (!value) return true; | ||||
|   return data.categoryName.indexOf(value) !== -1; | ||||
| }; | ||||
| /** 根据名称筛选部门树 */ | ||||
| watchEffect( | ||||
|   () => { | ||||
|     categoryTreeRef.value.filter(categoryName.value); | ||||
|   }, | ||||
|   { | ||||
|     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行 | ||||
|   } | ||||
| ); | ||||
|  | ||||
| /** 查询流程分类下拉树结构 */ | ||||
| const getTreeselect = async () => { | ||||
|   const res = await categoryTree(); | ||||
|   categoryOptions.value = res.data; | ||||
| }; | ||||
| const handleClick = (tab: TabsPaneContext, event: Event) => { | ||||
|   // v-model处理有延迟 需要手动处理 | ||||
|   activeName.value = tab.index; | ||||
|   handleQuery(); | ||||
| }; | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   if (activeName.value === '0') { | ||||
|     getList(); | ||||
|   } else { | ||||
|     getUnPublishList(); | ||||
|   } | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.category = ''; | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: any) => { | ||||
|   ids.value = selection.map((item: any) => item.id); | ||||
|   flowCodeList.value = selection.map((item: any) => item.flowCode); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| //分页 | ||||
| const getPageList = async () => { | ||||
|   console.log(proxy.$route.query.activeName) | ||||
|   if (proxy.$route.query.activeName) { | ||||
|     activeName.value = proxy.$route.query.activeName; | ||||
|   } | ||||
|   if (activeName.value === '0') { | ||||
|     getList(); | ||||
|   } else { | ||||
|     getUnPublishList(); | ||||
|   } | ||||
| }; | ||||
| //分页 | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const resp = await listDefinition(queryParams.value); | ||||
|   processDefinitionList.value = resp.rows; | ||||
|   total.value = resp.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
| //查询未发布的流程定义列表 | ||||
| const getUnPublishList = async () => { | ||||
|   loading.value = true; | ||||
|   const resp = await unPublishList(queryParams.value); | ||||
|   processDefinitionList.value = resp.rows; | ||||
|   total.value = resp.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row?: FlowDefinitionVo) => { | ||||
|   const id = row?.id || ids.value; | ||||
|   const defList = processDefinitionList.value.filter((x) => id.indexOf(x.id) != -1).map((x) => x.flowCode); | ||||
|   await proxy?.$modal.confirm('是否确认删除流程定义KEY为【' + defList + '】的数据项?'); | ||||
|   loading.value = true; | ||||
|   await deleteDefinition(id).finally(() => (loading.value = false)); | ||||
|   await handleQuery(); | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
| }; | ||||
|  | ||||
| /** 发布流程定义 */ | ||||
| const handlePublish = async (row?: FlowDefinitionVo) => { | ||||
|   await proxy?.$modal.confirm( | ||||
|     '是否确认发布流程定义KEY为【' + row.flowCode + '】版本为【' + row.version + '】的数据项?,发布后会将已发布流程定义改为失效!' | ||||
|   ); | ||||
|   loading.value = true; | ||||
|   await publish(row.id).finally(() => (loading.value = false)); | ||||
|   processDefinitionDialog.visible = false; | ||||
|   activeName.value = "0" | ||||
|   await handleQuery(); | ||||
|   proxy?.$modal.msgSuccess('发布成功'); | ||||
| }; | ||||
| /** 挂起/激活 */ | ||||
| const handleProcessDefState = async (row: FlowDefinitionVo, status: number | string | boolean) => { | ||||
|   let msg: string; | ||||
|   if (status === 0) { | ||||
|     msg = `暂停后,此流程下的所有任务都不允许往后流转,您确定挂起【${row.flowName || row.flowCode}】吗?`; | ||||
|   } else { | ||||
|     msg = `启动后,此流程下的所有任务都允许往后流转,您确定激活【${row.flowName || row.flowCode}】吗?`; | ||||
|   } | ||||
|   try { | ||||
|     loading.value = true; | ||||
|     await proxy?.$modal.confirm(msg); | ||||
|     await active(row.id, !!status); | ||||
|     await handleQuery(); | ||||
|     proxy?.$modal.msgSuccess('操作成功'); | ||||
|   } catch (error) { | ||||
|     row.activityStatus = status === 0 ? 1 : 0; | ||||
|     console.error(error); | ||||
|   } finally { | ||||
|     loading.value = false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| //上传文件前的钩子 | ||||
| const handlerBeforeUpload = () => { | ||||
|   if (selectCategory.value === 'ALL') { | ||||
|     proxy?.$modal.msgError('顶级节点不可作为分类!'); | ||||
|     return false; | ||||
|   } | ||||
|   if (!selectCategory.value) { | ||||
|     proxy?.$modal.msgError('请选择左侧要上传的分类!'); | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
| //部署文件 | ||||
| const handlerImportDefinition = (data: UploadRequestOptions): XMLHttpRequest => { | ||||
|   let formData = new FormData(); | ||||
|   uploadDialogLoading.value = true; | ||||
|   formData.append('file', data.file); | ||||
|   formData.append('category', selectCategory.value); | ||||
|   importDef(formData) | ||||
|     .then(() => { | ||||
|       uploadDialog.visible = false; | ||||
|       proxy?.$modal.msgSuccess('部署成功'); | ||||
|       activeName.value = "1" | ||||
|       handleQuery(); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       uploadDialogLoading.value = false; | ||||
|     }); | ||||
|   return; | ||||
| }; | ||||
| /** | ||||
|  * 设计流程 | ||||
|  * @param row | ||||
|  */ | ||||
| const design = async (row: FlowDefinitionVo) => { | ||||
|   proxy.$router.push({ | ||||
|     path: `/workflow/design/index`, | ||||
|     query: { | ||||
|       definitionId: row.id, | ||||
|       disabled: false, | ||||
|       activeName: activeName.value | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 查看流程 | ||||
|  * @param row | ||||
|  */ | ||||
| const designView = async (row: FlowDefinitionVo) => { | ||||
|   proxy.$router.push({ | ||||
|     path: `/workflow/design/index`, | ||||
|     query: { | ||||
|       definitionId: row.id, | ||||
|       disabled: true, | ||||
|       activeName: activeName.value | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
| /** 表单重置 */ | ||||
| const reset = () => { | ||||
|   form.value = { ...initFormData }; | ||||
|   defFormRef.value?.resetFields(); | ||||
| }; | ||||
| /** | ||||
|  * 新增 | ||||
|  */ | ||||
| const handleAdd = async () => { | ||||
|   reset(); | ||||
|   modelDialog.visible = true; | ||||
|   modelDialog.title = '新增流程'; | ||||
| }; | ||||
| /** 修改按钮操作 */ | ||||
| const handleUpdate = async (row?: FlowDefinitionVo) => { | ||||
|   reset(); | ||||
|   const id = row?.id || ids.value[0]; | ||||
|   const res = await getInfo(id); | ||||
|   Object.assign(form.value, res.data); | ||||
|   modelDialog.visible = true; | ||||
|   modelDialog.title = '修改流程'; | ||||
| }; | ||||
|  | ||||
| const handleSubmit = async () => { | ||||
|   defFormRef.value.validate(async (valid: boolean) => { | ||||
|     if (valid) { | ||||
|       loading.value = true; | ||||
|       if (form.value.id) { | ||||
|         await edit(form.value).finally(() => loading.value = false); | ||||
|       } else { | ||||
|         await add(form.value).finally(() => loading.value = false); | ||||
|       } | ||||
|       proxy?.$modal.msgSuccess('操作成功'); | ||||
|       modelDialog.visible = false; | ||||
|       handleQuery(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
| //复制 | ||||
| const handleCopyDef = async (row: FlowDefinitionVo) => { | ||||
|   ElMessageBox.confirm(`是否确认复制【${row.flowCode}】版本为【${row.version}】的流程定义!`, '提示', { | ||||
|     confirmButtonText: '确认', | ||||
|     cancelButtonText: '取消', | ||||
|     type: 'warning' | ||||
|   }).then(() => { | ||||
|     loading.value = true; | ||||
|     copy(row.id).then((resp) => { | ||||
|       if (resp.code === 200) { | ||||
|         proxy?.$modal.msgSuccess('操作成功'); | ||||
|         activeName.value = "1" | ||||
|         handleQuery(); | ||||
|       } | ||||
|     }).finally(() => loading.value = false); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExportDef = () => { | ||||
|   proxy?.download(`/workflow/definition/exportDef/${ids.value[0]}`, {}, `${flowCodeList.value[0]}.json`); | ||||
| }; | ||||
| </script> | ||||
| @ -1,417 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <el-row :gutter="20"> | ||||
|       <!-- 流程分类树 --> | ||||
|       <el-col :lg="4" :xs="24" style=""> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable /> | ||||
|           <el-tree | ||||
|             ref="categoryTreeRef" | ||||
|             class="mt-2" | ||||
|             node-key="id" | ||||
|             :data="categoryOptions" | ||||
|             :props="{ label: 'label', children: 'children' }" | ||||
|             :expand-on-click-node="false" | ||||
|             :filter-node-method="filterNode" | ||||
|             highlight-current | ||||
|             default-expand-all | ||||
|             @node-click="handleNodeClick" | ||||
|           ></el-tree> | ||||
|         </el-card> | ||||
|       </el-col> | ||||
|       <el-col :lg="20" :xs="24"> | ||||
|         <!--        <div class="mb-[10px]"> | ||||
|                   <el-card shadow="hover" class="text-center"> | ||||
|                     <el-radio-group v-model="tab" @change="changeTab(tab)"> | ||||
|                       <el-radio-button value="running">运行中</el-radio-button> | ||||
|                       <el-radio-button value="finish">已完成</el-radio-button> | ||||
|                     </el-radio-group> | ||||
|                   </el-card> | ||||
|                 </div>--> | ||||
|         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|           <div v-show="showSearch" class="mb-[10px]"> | ||||
|             <el-card shadow="hover"> | ||||
|               <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|                 <el-form-item> | ||||
|                   <el-badge :value="userSelectCount" :max="10" class="item"> | ||||
|                     <el-button type="primary" @click="openUserSelect">选择申请人</el-button> | ||||
|                   </el-badge> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item label="任务名称" prop="nodeName"> | ||||
|                   <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" /> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item label="流程定义名称" label-width="100" prop="flowName"> | ||||
|                   <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" /> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item label="流程定义编码" label-width="100" prop="flowCode"> | ||||
|                   <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" /> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item> | ||||
|                   <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|                   <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|                 </el-form-item> | ||||
|               </el-form> | ||||
|             </el-card> | ||||
|           </div> | ||||
|         </transition> | ||||
|         <el-card shadow="hover"> | ||||
|           <template #header> | ||||
|             <el-row :gutter="10" class="mb8"> | ||||
|               <el-col :span="1.5"> | ||||
|                 <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button> | ||||
|               </el-col> | ||||
|               <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|             </el-row> | ||||
|           </template> | ||||
|           <el-tabs v-model="tab" @tab-click="changeTab"> | ||||
|             <el-tab-pane name="running" label="运行中"></el-tab-pane> | ||||
|             <el-tab-pane name="finish" label="已完成"></el-tab-pane> | ||||
|             <el-table v-loading="loading" border :data="processInstanceList" @selection-change="handleSelectionChange"> | ||||
|               <el-table-column type="selection" width="55" align="center" /> | ||||
|               <el-table-column align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|               <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> | ||||
|                 <template #default="scope"> | ||||
|                   <span>{{ scope.row.flowName }}v{{ scope.row.version }}</span> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column> | ||||
|               <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column> | ||||
|               <el-table-column align="center" prop="createByName" label="申请人"></el-table-column> | ||||
|               <el-table-column align="center" prop="version" label="版本号" width="90"> | ||||
|                 <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|               </el-table-column> | ||||
|               <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="状态" min-width="70"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-tag v-if="!scope.row.isSuspended" type="success">激活</el-tag> | ||||
|                   <el-tag v-else type="danger">挂起</el-tag> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column align="center" label="流程状态" min-width="70"> | ||||
|                 <template #default="scope"> | ||||
|                   <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column align="center" prop="createTime" label="启动时间" width="160"></el-table-column> | ||||
|               <el-table-column v-if="tab === 'finish'" align="center" prop="updateTime" label="结束时间" width="160"></el-table-column> | ||||
|               <el-table-column label="操作" align="center" :width="165"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-row v-if="tab === 'running'" :gutter="10" class="mb8"> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-popover :ref="`popoverRef${scope.$index}`" trigger="click" placement="left" :width="300"> | ||||
|                         <el-input v-model="deleteReason" resize="none" :rows="3" type="textarea" placeholder="请输入作废原因" /> | ||||
|                         <div style="text-align: right; margin: 5px 0px 0px 0px"> | ||||
|                           <el-button size="small" text @click="cancelPopover(scope.$index)">取消</el-button> | ||||
|                           <el-button size="small" type="primary" @click="handleInvalid(scope.row)">确认</el-button> | ||||
|                         </div> | ||||
|                         <template #reference> | ||||
|                           <el-button type="danger" size="small" icon="CircleClose">作废</el-button> | ||||
|                         </template> | ||||
|                       </el-popover> | ||||
|                     </el-col> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-button type="danger" size="small" icon="Delete" @click="handleDelete(scope.row)">删除 </el-button> | ||||
|                     </el-col> | ||||
|                   </el-row> | ||||
|                   <el-row :gutter="10" class="mb8"> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> | ||||
|                     </el-col> | ||||
|                     <el-col :span="1.5"> | ||||
|                       <el-button type="primary" size="small" icon="Document" @click="handleInstanceVariable(scope.row)"> 变量 </el-button> | ||||
|                     </el-col> | ||||
|                   </el-row> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </el-table> | ||||
|             <pagination | ||||
|               v-show="total > 0" | ||||
|               v-model:page="queryParams.pageNum" | ||||
|               v-model:limit="queryParams.pageSize" | ||||
|               :total="total" | ||||
|               @pagination="handleQuery" | ||||
|             /> | ||||
|           </el-tabs> | ||||
|         </el-card> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|     <el-dialog v-if="processDefinitionDialog.visible" v-model="processDefinitionDialog.visible" :title="processDefinitionDialog.title" width="70%"> | ||||
|       <el-table v-loading="loading" :data="processDefinitionHistoryList"> | ||||
|         <el-table-column fixed align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|         <el-table-column fixed align="center" prop="name" label="流程定义名称"></el-table-column> | ||||
|         <el-table-column fixed align="center" prop="nodeName" label="任务名称"></el-table-column> | ||||
|         <el-table-column align="center" prop="key" label="标识Key"></el-table-column> | ||||
|         <el-table-column align="center" prop="version" label="版本号" width="90"> | ||||
|           <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" prop="suspensionState" label="状态" min-width="70"> | ||||
|           <template #default="scope"> | ||||
|             <el-tag v-if="scope.row.suspensionState == 1" type="success">激活</el-tag> | ||||
|             <el-tag v-else type="danger">挂起</el-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" prop="deploymentTime" label="部署时间" :show-overflow-tooltip="true"></el-table-column> | ||||
|       </el-table> | ||||
|     </el-dialog> | ||||
|     <!-- 流程变量开始 --> | ||||
|     <el-dialog v-model="variableVisible" draggable title="流程变量" width="60%" :close-on-click-modal="false"> | ||||
|       <el-card v-loading="variableLoading" class="box-card"> | ||||
|         <template #header> | ||||
|           <div class="clearfix"> | ||||
|             <span | ||||
|               >流程定义名称:<el-tag>{{ processDefinitionName }}</el-tag></span | ||||
|             > | ||||
|           </div> | ||||
|         </template> | ||||
|         <div class="max-h-500px overflow-y-auto"> | ||||
|           <VueJsonPretty :data="formatToJsonObject(variables)" /> | ||||
|         </div> | ||||
|       </el-card> | ||||
|     </el-dialog> | ||||
|     <!-- 流程变量结束 --> | ||||
|  | ||||
|     <!-- 申请人 --> | ||||
|     <UserSelect ref="userSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { pageByRunning, pageByFinish, deleteByInstanceIds, instanceVariable, invalid } from '@/api/workflow/instance'; | ||||
| import { categoryTree } from '@/api/workflow/category'; | ||||
| import { CategoryTreeVO } from '@/api/workflow/category/types'; | ||||
| import { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types'; | ||||
| import workflowCommon from '@/api/workflow/workflowCommon'; | ||||
| import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; | ||||
| import VueJsonPretty from 'vue-json-pretty'; | ||||
| import 'vue-json-pretty/lib/styles.css'; | ||||
| import UserSelect from '@/components/UserSelect/index.vue'; | ||||
| //审批记录组件 | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const categoryTreeRef = ref<ElTreeInstance>(); | ||||
| import { ref } from 'vue'; | ||||
| import { UserVO } from '@/api/system/user/types'; | ||||
|  | ||||
| const userSelectRef = ref<InstanceType<typeof UserSelect>>(); | ||||
| // 遮罩层 | ||||
| const loading = ref(true); | ||||
| // 选中数组 | ||||
| const ids = ref<Array<any>>([]); | ||||
| // 选中实例id数组 | ||||
| const instanceIds = ref<Array<number | string>>([]); | ||||
| // 非单个禁用 | ||||
| const single = ref(true); | ||||
| // 非多个禁用 | ||||
| const multiple = ref(true); | ||||
| // 显示搜索条件 | ||||
| const showSearch = ref(true); | ||||
| // 总条数 | ||||
| const total = ref(0); | ||||
|  | ||||
| // 流程变量是否显示 | ||||
| const variableVisible = ref(false); | ||||
| const variableLoading = ref(true); | ||||
| const variables = ref<string>(''); | ||||
| //流程定义名称 | ||||
| const processDefinitionName = ref(); | ||||
| // 模型定义表格数据 | ||||
| const processInstanceList = ref<FlowInstanceVO[]>([]); | ||||
| const processDefinitionHistoryList = ref<Array<any>>([]); | ||||
| const categoryOptions = ref<CategoryOption[]>([]); | ||||
| const categoryName = ref(''); | ||||
|  | ||||
| const processDefinitionDialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '流程定义' | ||||
| }); | ||||
|  | ||||
| type CategoryOption = { | ||||
|   id: string; | ||||
|   categoryName: string; | ||||
|   children?: CategoryOption[]; | ||||
| }; | ||||
|  | ||||
| const tab = ref('running'); | ||||
| // 作废原因 | ||||
| const deleteReason = ref(''); | ||||
|  | ||||
| //申请人id | ||||
| const selectUserIds = ref<Array<number | string>>([]); | ||||
| //申请人选择数量 | ||||
| const userSelectCount = ref(0); | ||||
| // 查询参数 | ||||
| const queryParams = ref<FlowInstanceQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   nodeName: undefined, | ||||
|   flowName: undefined, | ||||
|   flowCode: undefined, | ||||
|   createByIds: [], | ||||
|   category: undefined | ||||
| }); | ||||
|  | ||||
| /** 节点单击事件 */ | ||||
| const handleNodeClick = (data: CategoryTreeVO) => { | ||||
|   queryParams.value.category = data.id; | ||||
|   if (data.id === '0') { | ||||
|     queryParams.value.category = ''; | ||||
|   } | ||||
|   handleQuery(); | ||||
| }; | ||||
| /** 通过条件过滤节点  */ | ||||
| const filterNode = (value: string, data: any) => { | ||||
|   if (!value) return true; | ||||
|   return data.categoryName.indexOf(value) !== -1; | ||||
| }; | ||||
| /** 根据名称筛选部门树 */ | ||||
| watchEffect( | ||||
|   () => { | ||||
|     categoryTreeRef.value.filter(categoryName.value); | ||||
|   }, | ||||
|   { | ||||
|     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行 | ||||
|   } | ||||
| ); | ||||
|  | ||||
| /** 查询流程分类下拉树结构 */ | ||||
| const getTreeselect = async () => { | ||||
|   const res = await categoryTree(); | ||||
|   categoryOptions.value = res.data; | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   if ('running' === tab.value) { | ||||
|     getProcessInstanceRunningList(); | ||||
|   } else { | ||||
|     getProcessInstanceFinishList(); | ||||
|   } | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.category = ''; | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   queryParams.value.createByIds = []; | ||||
|   userSelectCount.value = 0; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: FlowInstanceVO[]) => { | ||||
|   ids.value = selection.map((item: any) => item.id); | ||||
|   instanceIds.value = selection.map((item: FlowInstanceVO) => item.id); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| //分页 | ||||
| const getProcessInstanceRunningList = () => { | ||||
|   loading.value = true; | ||||
|   pageByRunning(queryParams.value).then((resp) => { | ||||
|     processInstanceList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
| //分页 | ||||
| const getProcessInstanceFinishList = () => { | ||||
|   loading.value = true; | ||||
|   pageByFinish(queryParams.value).then((resp) => { | ||||
|     processInstanceList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row: FlowInstanceVO) => { | ||||
|   const instanceIdList = row.id || instanceIds.value; | ||||
|   await proxy?.$modal.confirm('是否确认删除?'); | ||||
|   loading.value = true; | ||||
|   if ('running' === tab.value) { | ||||
|     await deleteByInstanceIds(instanceIdList).finally(() => (loading.value = false)); | ||||
|     getProcessInstanceRunningList(); | ||||
|   } else { | ||||
|     await deleteByInstanceIds(instanceIdList).finally(() => (loading.value = false)); | ||||
|     getProcessInstanceFinishList(); | ||||
|   } | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
| }; | ||||
| const changeTab = async (data: string) => { | ||||
|   processInstanceList.value = []; | ||||
|   queryParams.value.pageNum = 1; | ||||
|   if ('running' === data.paneName) { | ||||
|     getProcessInstanceRunningList(); | ||||
|   } else { | ||||
|     getProcessInstanceFinishList(); | ||||
|   } | ||||
| }; | ||||
| /** 作废按钮操作 */ | ||||
| const handleInvalid = async (row: FlowInstanceVO) => { | ||||
|   await proxy?.$modal.confirm('是否确认作废?'); | ||||
|   loading.value = true; | ||||
|   if ('running' === tab.value) { | ||||
|     let param = { | ||||
|       id: row.id, | ||||
|       comment: deleteReason.value | ||||
|     }; | ||||
|     await invalid(param).finally(() => (loading.value = false)); | ||||
|     getProcessInstanceRunningList(); | ||||
|     proxy?.$modal.msgSuccess('操作成功'); | ||||
|   } | ||||
| }; | ||||
| const cancelPopover = async (index: any) => { | ||||
|   (proxy?.$refs[`popoverRef${index}`] as any).hide(); //关闭弹窗 | ||||
| }; | ||||
| /** 查看按钮操作 */ | ||||
| const handleView = (row) => { | ||||
|   const routerJumpVo = reactive<RouterJumpVo>({ | ||||
|     businessId: row.businessId, | ||||
|     taskId: row.id, | ||||
|     type: 'view', | ||||
|     formCustom: row.formCustom, | ||||
|     formPath: row.formPath | ||||
|   }); | ||||
|   workflowCommon.routerJump(routerJumpVo, proxy); | ||||
| }; | ||||
|  | ||||
| //查询流程变量 | ||||
| const handleInstanceVariable = async (row: FlowInstanceVO) => { | ||||
|   variableLoading.value = true; | ||||
|   variableVisible.value = true; | ||||
|   processDefinitionName.value = row.flowName; | ||||
|   let data = await instanceVariable(row.id); | ||||
|   variables.value = data.data.variable; | ||||
|   variableLoading.value = false; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * json转为对象 | ||||
|  * @param data 原始数据 | ||||
|  */ | ||||
| function formatToJsonObject(data: string) { | ||||
|   try { | ||||
|     return JSON.parse(data); | ||||
|   } catch (error) { | ||||
|     return data; | ||||
|   } | ||||
| } | ||||
|  | ||||
| //打开申请人选择 | ||||
| const openUserSelect = () => { | ||||
|   userSelectRef.value.open(); | ||||
| }; | ||||
| //确认选择申请人 | ||||
| const userSelectCallBack = (data: UserVO[]) => { | ||||
|   userSelectCount.value = 0; | ||||
|   if (data && data.length > 0) { | ||||
|     userSelectCount.value = data.length; | ||||
|     selectUserIds.value = data.map((item) => item.userId); | ||||
|     queryParams.value.createByIds = selectUserIds.value; | ||||
|   } | ||||
| }; | ||||
| onMounted(() => { | ||||
|   getProcessInstanceRunningList(); | ||||
|   getTreeselect(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,252 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item> | ||||
|               <el-badge :value="userSelectCount" :max="10" class="item"> | ||||
|                 <el-button type="primary" @click="openUserSelect">选择申请人</el-button> | ||||
|               </el-badge> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="任务名称" prop="nodeName"> | ||||
|               <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义名称" label-width="100" prop="flowName"> | ||||
|               <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|     <el-card shadow="hover"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5" v-if="tab === 'waiting'"> | ||||
|             <el-button type="primary" plain icon="Edit" :disabled="multiple" @click="handleUpdate">修改办理人 </el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|       <el-tabs v-model="tab" @tab-click="changeTab"> | ||||
|         <el-tab-pane name="waiting" label="待办任务"> </el-tab-pane> | ||||
|         <el-tab-pane name="finish" label="已办任务"> </el-tab-pane> | ||||
|         <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange"> | ||||
|           <el-table-column type="selection" width="55" align="center" /> | ||||
|           <el-table-column align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|           <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column> | ||||
|           <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column> | ||||
|           <el-table-column align="center" prop="version" label="版本号" width="90"> | ||||
|             <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column> | ||||
|           <el-table-column align="center" prop="createByName" label="申请人"></el-table-column> | ||||
|           <el-table-column align="center" label="办理人"> | ||||
|             <template #default="scope"> | ||||
|               <template v-if="tab === 'waiting'"> | ||||
|                 <template v-if="scope.row.assigneeNames"> | ||||
|                   <el-tag v-for="(name, index) in scope.row.assigneeNames.split(',')" :key="index" type="success"> | ||||
|                     {{ name }} | ||||
|                   </el-tag> | ||||
|                 </template> | ||||
|                 <template v-else> | ||||
|                   <el-tag type="success"> 无</el-tag> | ||||
|                 </template> | ||||
|               </template> | ||||
|               <template v-else> | ||||
|                 <el-tag type="success"> {{ scope.row.approveName }}</el-tag> | ||||
|               </template> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" label="流程状态" prop="flowStatus" min-width="70"> | ||||
|             <template #default="scope"> | ||||
|               <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column v-if="tab === 'finish'" align="center" label="任务状态" prop="flowTaskStatus" min-width="70"> | ||||
|             <template #default="scope"> | ||||
|               <dict-tag :options="wf_task_status" :value="scope.row.flowTaskStatus"></dict-tag> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" prop="createTime" label="创建时间" width="160"></el-table-column> | ||||
|           <el-table-column label="操作" align="center" :width="tab === 'finish' ? '88' : '188'"> | ||||
|             <template #default="scope"> | ||||
|               <el-row :gutter="10" class="mb8"> | ||||
|                 <el-col :span="1.5" v-if="tab === 'waiting' || tab === 'finish'"> | ||||
|                   <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> | ||||
|                 </el-col> | ||||
|                 <el-col :span="1.5" v-if="tab === 'waiting'"> | ||||
|                   <el-button type="primary" size="small" icon="Setting" @click="handleMeddle(scope.row)">流程干预 </el-button> | ||||
|                 </el-col> | ||||
|               </el-row> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </el-table> | ||||
|         <pagination | ||||
|           v-show="total > 0" | ||||
|           v-model:page="queryParams.pageNum" | ||||
|           v-model:limit="queryParams.pageSize" | ||||
|           :total="total" | ||||
|           @pagination="handleQuery" | ||||
|         /> | ||||
|       </el-tabs> | ||||
|     </el-card> | ||||
|     <!-- 选人组件 --> | ||||
|     <UserSelect ref="userSelectRef" :multiple="false" @confirm-call-back="submitCallback"></UserSelect> | ||||
|     <!-- 选人组件 --> | ||||
|     <processMeddle ref="processMeddleRef" @submitCallback="getWaitingList"></processMeddle> | ||||
|     <!-- 申请人 --> | ||||
|     <UserSelect ref="applyUserSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { pageByAllTaskWait, pageByAllTaskFinish, updateAssignee } from '@/api/workflow/task'; | ||||
| import UserSelect from '@/components/UserSelect'; | ||||
| import { TaskQuery } from '@/api/workflow/task/types'; | ||||
| import workflowCommon from '@/api/workflow/workflowCommon'; | ||||
| import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; | ||||
| import processMeddle from '@/components/Process/processMeddle'; | ||||
| import { UserVO } from '@/api/system/user/types'; | ||||
| import { TabsPaneContext } from 'element-plus'; | ||||
| //选人组件 | ||||
| const userSelectRef = ref<InstanceType<typeof UserSelect>>(); | ||||
| //流程干预组件 | ||||
| const processMeddleRef = ref<InstanceType<typeof processMeddle>>(); | ||||
| //选人组件 | ||||
| const applyUserSelectRef = ref<InstanceType<typeof UserSelect>>(); | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status')); | ||||
| // 遮罩层 | ||||
| const loading = ref(true); | ||||
| // 选中数组 | ||||
| const ids = ref<Array<any>>([]); | ||||
| // 非单个禁用 | ||||
| const single = ref(true); | ||||
| // 非多个禁用 | ||||
| const multiple = ref(true); | ||||
| // 显示搜索条件 | ||||
| const showSearch = ref(true); | ||||
| // 总条数 | ||||
| const total = ref(0); | ||||
| // 模型定义表格数据 | ||||
| const taskList = ref([]); | ||||
| const title = ref(''); | ||||
| //申请人id | ||||
| const selectUserIds = ref<Array<number | string>>([]); | ||||
| //申请人选择数量 | ||||
| const userSelectCount = ref(0); | ||||
| // 查询参数 | ||||
| const queryParams = ref<TaskQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   nodeName: undefined, | ||||
|   flowName: undefined, | ||||
|   flowCode: undefined, | ||||
|   createByIds: [] | ||||
| }); | ||||
| const tab = ref('waiting'); | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   if ('waiting' === tab.value) { | ||||
|     getWaitingList(); | ||||
|   } else { | ||||
|     getFinishList(); | ||||
|   } | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   queryParams.value.createByIds = []; | ||||
|   userSelectCount.value = 0; | ||||
|   selectUserIds.value = []; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: any) => { | ||||
|   ids.value = selection.map((item: any) => item.id); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| const changeTab = async (data: TabsPaneContext) => { | ||||
|   taskList.value = []; | ||||
|   queryParams.value.pageNum = 1; | ||||
|   if ('waiting' === data.paneName) { | ||||
|     getWaitingList(); | ||||
|   } else { | ||||
|     getFinishList(); | ||||
|   } | ||||
| }; | ||||
| //分页 | ||||
| const getWaitingList = () => { | ||||
|   loading.value = true; | ||||
|   pageByAllTaskWait(queryParams.value).then((resp) => { | ||||
|     taskList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
| const getFinishList = () => { | ||||
|   loading.value = true; | ||||
|   pageByAllTaskFinish(queryParams.value).then((resp) => { | ||||
|     taskList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
| //打开修改选人 | ||||
| const handleUpdate = () => { | ||||
|   userSelectRef.value.open(); | ||||
| }; | ||||
| //修改办理人 | ||||
| const submitCallback = async (data) => { | ||||
|   if (data && data.length > 0) { | ||||
|     await proxy?.$modal.confirm('是否确认提交?'); | ||||
|     loading.value = true; | ||||
|     await updateAssignee(ids.value, data[0].userId); | ||||
|     handleQuery(); | ||||
|     proxy?.$modal.msgSuccess('操作成功'); | ||||
|   } else { | ||||
|     proxy?.$modal.msgWarning('请选择用户!'); | ||||
|   } | ||||
| }; | ||||
| /** 查看按钮操作 */ | ||||
| const handleView = (row) => { | ||||
|   const routerJumpVo = reactive<RouterJumpVo>({ | ||||
|     businessId: row.businessId, | ||||
|     taskId: row.id, | ||||
|     type: 'view', | ||||
|     formCustom: row.formCustom, | ||||
|     formPath: row.formPath | ||||
|   }); | ||||
|   workflowCommon.routerJump(routerJumpVo, proxy); | ||||
| }; | ||||
| const handleMeddle = (row) => { | ||||
|   processMeddleRef.value.open(row.id); | ||||
| }; | ||||
| //打开申请人选择 | ||||
| const openUserSelect = () => { | ||||
|   applyUserSelectRef.value.open(); | ||||
| }; | ||||
| //确认选择申请人 | ||||
| const userSelectCallBack = (data: UserVO[]) => { | ||||
|   userSelectCount.value = 0; | ||||
|   if (data && data.length > 0) { | ||||
|     userSelectCount.value = data.length; | ||||
|     selectUserIds.value = data.map((item) => item.userId); | ||||
|     queryParams.value.createByIds = selectUserIds.value; | ||||
|   } | ||||
| }; | ||||
| onMounted(() => { | ||||
|   getWaitingList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,245 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <el-row :gutter="20"> | ||||
|       <!-- 流程分类树 --> | ||||
|       <el-col :lg="4" :xs="24" style=""> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable /> | ||||
|           <el-tree | ||||
|             ref="categoryTreeRef" | ||||
|             class="mt-2" | ||||
|             node-key="id" | ||||
|             :data="categoryOptions" | ||||
|             :props="{ label: 'label', children: 'children' }" | ||||
|             :expand-on-click-node="false" | ||||
|             :filter-node-method="filterNode" | ||||
|             highlight-current | ||||
|             default-expand-all | ||||
|             @node-click="handleNodeClick" | ||||
|           ></el-tree> | ||||
|         </el-card> | ||||
|       </el-col> | ||||
|       <el-col :lg="20" :xs="24"> | ||||
|         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|           <div v-show="showSearch" class="mb-[10px]"> | ||||
|             <el-card shadow="hover"> | ||||
|               <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px"> | ||||
|                 <el-form-item label="流程定义编码" prop="flowCode"> | ||||
|                   <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" /> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item> | ||||
|                   <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|                   <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|                 </el-form-item> | ||||
|               </el-form> | ||||
|             </el-card> | ||||
|           </div> | ||||
|         </transition> | ||||
|         <el-card shadow="hover"> | ||||
|           <template #header> | ||||
|             <el-row :gutter="10" class="mb8"> | ||||
|               <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|             </el-row> | ||||
|           </template> | ||||
|  | ||||
|           <el-table v-loading="loading" border :data="processInstanceList" @selection-change="handleSelectionChange"> | ||||
|             <el-table-column type="selection" width="55" align="center" /> | ||||
|             <el-table-column align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|             <el-table-column v-if="false" align="center" prop="id" label="id"></el-table-column> | ||||
|             <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"> </el-table-column> | ||||
|             <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column> | ||||
|             <el-table-column align="center" prop="version" label="版本号" width="90"> | ||||
|               <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|             </el-table-column> | ||||
|             <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="状态" min-width="70"> | ||||
|               <template #default="scope"> | ||||
|                 <el-tag v-if="!scope.row.isSuspended" type="success">激活</el-tag> | ||||
|                 <el-tag v-else type="danger">挂起</el-tag> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column align="center" label="流程状态" min-width="70"> | ||||
|               <template #default="scope"> | ||||
|                 <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column align="center" prop="createTime" label="启动时间" width="160"></el-table-column> | ||||
|             <el-table-column label="操作" align="center" width="162"> | ||||
|               <template #default="scope"> | ||||
|                 <el-row :gutter="10" class="mb8"> | ||||
|                   <el-col :span="1.5" v-if="scope.row.flowStatus === 'draft' || scope.row.flowStatus === 'cancel' || scope.row.flowStatus === 'back'"> | ||||
|                     <el-button type="primary" size="small" icon="Edit" @click="handleOpen(scope.row, 'update')">编辑</el-button> | ||||
|                   </el-col> | ||||
|                   <el-col :span="1.5" v-if="scope.row.flowStatus === 'draft' || scope.row.flowStatus === 'cancel' || scope.row.flowStatus === 'back'"> | ||||
|                     <el-button type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">删除</el-button> | ||||
|                   </el-col> | ||||
|                 </el-row> | ||||
|                 <el-row :gutter="10" class="mb8"> | ||||
|                   <el-col :span="1.5"> | ||||
|                     <el-button type="primary" size="small" icon="View" @click="handleOpen(scope.row, 'view')">查看</el-button> | ||||
|                   </el-col> | ||||
|                   <el-col :span="1.5" v-if="scope.row.flowStatus === 'waiting'"> | ||||
|                     <el-button type="primary" size="small" icon="Notification" @click="handleCancelProcessApply(scope.row.businessId)" | ||||
|                       >撤销</el-button | ||||
|                     > | ||||
|                   </el-col> | ||||
|                 </el-row> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </el-table> | ||||
|           <pagination | ||||
|             v-show="total > 0" | ||||
|             v-model:page="queryParams.pageNum" | ||||
|             v-model:limit="queryParams.pageSize" | ||||
|             :total="total" | ||||
|             @pagination="getList" | ||||
|           /> | ||||
|         </el-card> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|     <!-- 提交组件 --> | ||||
|     <submitVerify ref="submitVerifyRef" @submit-callback="getList" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { pageByCurrent, deleteByInstanceIds, cancelProcessApply } from '@/api/workflow/instance'; | ||||
| import { categoryTree } from '@/api/workflow/category'; | ||||
| import { CategoryTreeVO } from '@/api/workflow/category/types'; | ||||
| import { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types'; | ||||
| import workflowCommon from '@/api/workflow/workflowCommon'; | ||||
| import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const categoryTreeRef = ref<ElTreeInstance>(); | ||||
|  | ||||
| // 遮罩层 | ||||
| const loading = ref(true); | ||||
| // 选中数组 | ||||
| const businessIds = ref<Array<number | string>>([]); | ||||
| const instanceIds = ref<Array<number | string>>([]); | ||||
| // 非单个禁用 | ||||
| const single = ref(true); | ||||
| // 非多个禁用 | ||||
| const multiple = ref(true); | ||||
| // 显示搜索条件 | ||||
| const showSearch = ref(true); | ||||
| // 总条数 | ||||
| const total = ref(0); | ||||
| // 模型定义表格数据 | ||||
| const processInstanceList = ref<FlowInstanceVO[]>([]); | ||||
|  | ||||
| const categoryOptions = ref<CategoryTreeVO[]>([]); | ||||
| const categoryName = ref(''); | ||||
|  | ||||
| const tab = ref('running'); | ||||
| // 查询参数 | ||||
| const queryParams = ref<FlowInstanceQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   flowCode: undefined, | ||||
|   category: undefined | ||||
| }); | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
|   getTreeselect(); | ||||
| }); | ||||
|  | ||||
| /** 节点单击事件 */ | ||||
| const handleNodeClick = (data: CategoryTreeVO) => { | ||||
|   queryParams.value.category = data.id; | ||||
|   if (data.id === '0') { | ||||
|     queryParams.value.category = ''; | ||||
|   } | ||||
|   handleQuery(); | ||||
| }; | ||||
| /** 通过条件过滤节点  */ | ||||
| const filterNode = (value: string, data: any) => { | ||||
|   if (!value) return true; | ||||
|   return data.categoryName.indexOf(value) !== -1; | ||||
| }; | ||||
| /** 根据名称筛选部门树 */ | ||||
| watchEffect( | ||||
|   () => { | ||||
|     categoryTreeRef.value.filter(categoryName.value); | ||||
|   }, | ||||
|   { | ||||
|     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行 | ||||
|   } | ||||
| ); | ||||
|  | ||||
| /** 查询流程分类下拉树结构 */ | ||||
| const getTreeselect = async () => { | ||||
|   const res = await categoryTree(); | ||||
|   categoryOptions.value = res.data; | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   getList(); | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.category = ''; | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: FlowInstanceVO[]) => { | ||||
|   businessIds.value = selection.map((item: any) => item.businessId); | ||||
|   instanceIds.value = selection.map((item: FlowInstanceVO) => item.id); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| //分页 | ||||
| const getList = () => { | ||||
|   loading.value = true; | ||||
|   pageByCurrent(queryParams.value).then((resp) => { | ||||
|     processInstanceList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (row: FlowInstanceVO) => { | ||||
|   const instanceIdList = row.id || instanceIds.value; | ||||
|   await proxy?.$modal.confirm('是否确认删除?'); | ||||
|   loading.value = true; | ||||
|   if ('running' === tab.value) { | ||||
|     await deleteByInstanceIds(instanceIdList).finally(() => (loading.value = false)); | ||||
|     getList(); | ||||
|   } | ||||
|   proxy?.$modal.msgSuccess('删除成功'); | ||||
| }; | ||||
|  | ||||
| /** 撤销按钮操作 */ | ||||
| const handleCancelProcessApply = async (businessId: string) => { | ||||
|   await proxy?.$modal.confirm('是否确认撤销当前单据?'); | ||||
|   loading.value = true; | ||||
|   if ('running' === tab.value) { | ||||
|     let data = { | ||||
|       businessId: businessId, | ||||
|       message: '申请人撤销流程!' | ||||
|     }; | ||||
|     await cancelProcessApply(data).finally(() => (loading.value = false)); | ||||
|     getList(); | ||||
|   } | ||||
|   proxy?.$modal.msgSuccess('撤销成功'); | ||||
| }; | ||||
|  | ||||
| //办理 | ||||
| const handleOpen = async (row, type) => { | ||||
|   const routerJumpVo = reactive<RouterJumpVo>({ | ||||
|     businessId: row.businessId, | ||||
|     taskId: row.id, | ||||
|     type: type, | ||||
|     formCustom: row.formCustom, | ||||
|     formPath: row.formPath | ||||
|   }); | ||||
|   workflowCommon.routerJump(routerJumpVo, proxy); | ||||
| }; | ||||
| </script> | ||||
| @ -1,135 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="任务名称" prop="nodeName"> | ||||
|               <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义名称" label-width="100" prop="flowName"> | ||||
|               <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义编码" label-width="100" prop="flowCode"> | ||||
|               <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|     <el-card shadow="hover"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|         <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column> | ||||
|         <el-table-column align="center" prop="flowCode" label="流程定义KEY"></el-table-column> | ||||
|         <el-table-column align="center" prop="version" label="版本号" width="90"> | ||||
|           <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column> | ||||
|         <el-table-column align="center" label="流程状态" min-width="70"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="操作" align="center" width="200"> | ||||
|           <template #default="scope"> | ||||
|             <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|       <pagination | ||||
|         v-show="total > 0" | ||||
|         v-model:page="queryParams.pageNum" | ||||
|         v-model:limit="queryParams.pageSize" | ||||
|         :total="total" | ||||
|         @pagination="handleQuery" | ||||
|       /> | ||||
|     </el-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { pageByTaskCopy } from '@/api/workflow/task'; | ||||
| import { TaskQuery } from '@/api/workflow/task/types'; | ||||
| import workflowCommon from '@/api/workflow/workflowCommon'; | ||||
| import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; | ||||
| //审批记录组件 | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| // 遮罩层 | ||||
| const loading = ref(true); | ||||
| // 选中数组 | ||||
| const ids = ref<Array<any>>([]); | ||||
| // 非单个禁用 | ||||
| const single = ref(true); | ||||
| // 非多个禁用 | ||||
| const multiple = ref(true); | ||||
| // 显示搜索条件 | ||||
| const showSearch = ref(true); | ||||
| // 总条数 | ||||
| const total = ref(0); | ||||
| // 模型定义表格数据 | ||||
| const taskList = ref([]); | ||||
| // 查询参数 | ||||
| const queryParams = ref<TaskQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   nodeName: undefined, | ||||
|   flowName: undefined, | ||||
|   flowCode: undefined | ||||
| }); | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   getTaskCopyList(); | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: any) => { | ||||
|   ids.value = selection.map((item: any) => item.id); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| //分页 | ||||
| const getTaskCopyList = () => { | ||||
|   loading.value = true; | ||||
|   pageByTaskCopy(queryParams.value).then((resp) => { | ||||
|     taskList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** 查看按钮操作 */ | ||||
| const handleView = (row) => { | ||||
|   const routerJumpVo = reactive<RouterJumpVo>({ | ||||
|     businessId: row.businessId, | ||||
|     taskId: row.id, | ||||
|     type: 'view', | ||||
|     formCustom: row.formCustom, | ||||
|     formPath: row.formPath | ||||
|   }); | ||||
|   workflowCommon.routerJump(routerJumpVo, proxy); | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getTaskCopyList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,180 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item> | ||||
|               <el-badge :value="userSelectCount" :max="10" class="item"> | ||||
|                 <el-button type="primary" @click="openUserSelect">选择申请人</el-button> | ||||
|               </el-badge> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="任务名称" prop="nodeName"> | ||||
|               <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义名称" label-width="100" prop="flowName"> | ||||
|               <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义编码" label-width="100" prop="flowCode"> | ||||
|               <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|     <el-card shadow="hover"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|         <el-table-column align="center" prop="flowName" label="流程定义名称"></el-table-column> | ||||
|         <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column> | ||||
|         <el-table-column align="center" prop="version" label="版本号" width="90"> | ||||
|           <template #default="scope"> v{{ scope.row.version }}.0</template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column> | ||||
|         <el-table-column align="center" prop="createByName" label="申请人"></el-table-column> | ||||
|         <el-table-column align="center" prop="approverName" label="办理人"> | ||||
|           <template #default="scope"> | ||||
|             <el-tag type="success"> | ||||
|               {{ scope.row.approveName || '无' }} | ||||
|             </el-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" label="流程状态" prop="flowStatus" min-width="70"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" label="任务状态" prop="flowTaskStatus" min-width="70"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="wf_task_status" :value="scope.row.flowTaskStatus"></dict-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" prop="createTime" label="创建时间" width="160"></el-table-column> | ||||
|         <el-table-column label="操作" align="center" width="200"> | ||||
|           <template #default="scope"> | ||||
|             <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|       <pagination | ||||
|         v-show="total > 0" | ||||
|         v-model:page="queryParams.pageNum" | ||||
|         v-model:limit="queryParams.pageSize" | ||||
|         :total="total" | ||||
|         @pagination="handleQuery" | ||||
|       /> | ||||
|     </el-card> | ||||
|     <!-- 申请人 --> | ||||
|     <UserSelect ref="userSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { pageByTaskFinish } from '@/api/workflow/task'; | ||||
| import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types'; | ||||
| import workflowCommon from '@/api/workflow/workflowCommon'; | ||||
| import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; | ||||
| //审批记录组件 | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status')); | ||||
| import UserSelect from '@/components/UserSelect'; | ||||
| import { ref } from 'vue'; | ||||
| import { UserVO } from '@/api/system/user/types'; | ||||
|  | ||||
| const userSelectRef = ref<InstanceType<typeof UserSelect>>(); | ||||
| // 遮罩层 | ||||
| const loading = ref(true); | ||||
| // 选中数组 | ||||
| const ids = ref<Array<any>>([]); | ||||
| // 非单个禁用 | ||||
| const single = ref(true); | ||||
| // 非多个禁用 | ||||
| const multiple = ref(true); | ||||
| // 显示搜索条件 | ||||
| const showSearch = ref(true); | ||||
| // 总条数 | ||||
| const total = ref(0); | ||||
| // 模型定义表格数据 | ||||
| const taskList = ref([]); | ||||
| // 查询参数 | ||||
| const queryParams = ref<TaskQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   nodeName: undefined, | ||||
|   flowName: undefined, | ||||
|   flowCode: undefined, | ||||
|   createByIds: [] | ||||
| }); | ||||
| //申请人id | ||||
| const selectUserIds = ref<Array<number | string>>([]); | ||||
| //申请人选择数量 | ||||
| const userSelectCount = ref(0); | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   getFinishList(); | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   queryParams.value.createByIds = []; | ||||
|   userSelectCount.value = 0; | ||||
|   selectUserIds.value = []; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: any) => { | ||||
|   ids.value = selection.map((item: any) => item.id); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| const getFinishList = () => { | ||||
|   loading.value = true; | ||||
|   pageByTaskFinish(queryParams.value).then((resp) => { | ||||
|     taskList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
| /** 查看按钮操作 */ | ||||
| const handleView = (row: FlowTaskVO) => { | ||||
|   const routerJumpVo = reactive<RouterJumpVo>({ | ||||
|     businessId: row.businessId, | ||||
|     taskId: row.id, | ||||
|     type: 'view', | ||||
|     formCustom: row.formCustom, | ||||
|     formPath: row.formPath | ||||
|   }); | ||||
|   workflowCommon.routerJump(routerJumpVo, proxy); | ||||
| }; | ||||
| //打开申请人选择 | ||||
| const openUserSelect = () => { | ||||
|   userSelectRef.value.open(); | ||||
| }; | ||||
| //确认选择申请人 | ||||
| const userSelectCallBack = (data: UserVO[]) => { | ||||
|   userSelectCount.value = 0; | ||||
|   if (data && data.length > 0) { | ||||
|     userSelectCount.value = data.length; | ||||
|     selectUserIds.value = data.map((item) => item.userId); | ||||
|     queryParams.value.createByIds = selectUserIds.value; | ||||
|   } | ||||
| }; | ||||
| onMounted(() => { | ||||
|   getFinishList(); | ||||
| }); | ||||
| </script> | ||||
| @ -1,179 +0,0 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item> | ||||
|               <el-badge :value="userSelectCount" :max="10" class="item"> | ||||
|                 <el-button type="primary" @click="openUserSelect">选择申请人</el-button> | ||||
|               </el-badge> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="任务名称" prop="nodeName"> | ||||
|               <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义名称" label-width="100" prop="flowName"> | ||||
|               <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="流程定义编码" label-width="100" prop="flowCode"> | ||||
|               <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|     <el-card shadow="hover"> | ||||
|       <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> | ||||
|  | ||||
|       <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column align="center" type="index" label="序号" width="60"></el-table-column> | ||||
|         <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column> | ||||
|         <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column> | ||||
|         <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column> | ||||
|         <el-table-column align="center" prop="createByName" label="申请人"></el-table-column> | ||||
|         <el-table-column align="center" label="办理人"> | ||||
|           <template #default="scope"> | ||||
|             <template v-if="scope.row.assigneeNames"> | ||||
|               <el-tag v-for="(name, index) in scope.row.assigneeNames.split(',')" :key="index" type="success"> | ||||
|                 {{ name }} | ||||
|               </el-tag> | ||||
|             </template> | ||||
|             <template v-else> | ||||
|               <el-tag type="success"> 无</el-tag> | ||||
|             </template> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" label="流程状态" prop="flowStatusName" min-width="70"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="center" prop="createTime" label="创建时间" width="160"></el-table-column> | ||||
|         <el-table-column label="操作" align="center" width="200"> | ||||
|           <template #default="scope"> | ||||
|             <el-button type="primary" size="small" icon="Edit" @click="handleOpen(scope.row)">办理</el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|       <pagination | ||||
|         v-show="total > 0" | ||||
|         v-model:page="queryParams.pageNum" | ||||
|         v-model:limit="queryParams.pageSize" | ||||
|         :total="total" | ||||
|         @pagination="handleQuery" | ||||
|       /> | ||||
|     </el-card> | ||||
|     <!-- 申请人 --> | ||||
|     <UserSelect ref="userSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { pageByTaskWait } from '@/api/workflow/task'; | ||||
| import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types'; | ||||
| import workflowCommon from '@/api/workflow/workflowCommon'; | ||||
| import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); | ||||
| import UserSelect from '@/components/UserSelect'; | ||||
| import { ref } from 'vue'; | ||||
| import { UserVO } from '@/api/system/user/types'; | ||||
|  | ||||
| const userSelectRef = ref<InstanceType<typeof UserSelect>>(); | ||||
| //提交组件 | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| // 遮罩层 | ||||
| const loading = ref(true); | ||||
| // 选中数组 | ||||
| const ids = ref<Array<any>>([]); | ||||
| // 非单个禁用 | ||||
| const single = ref(true); | ||||
| // 非多个禁用 | ||||
| const multiple = ref(true); | ||||
| // 显示搜索条件 | ||||
| const showSearch = ref(true); | ||||
| // 总条数 | ||||
| const total = ref(0); | ||||
| // 模型定义表格数据 | ||||
| const taskList = ref([]); | ||||
|  | ||||
| //申请人id | ||||
| const selectUserIds = ref<Array<number | string>>([]); | ||||
| //申请人选择数量 | ||||
| const userSelectCount = ref(0); | ||||
| // 查询参数 | ||||
| const queryParams = ref<TaskQuery>({ | ||||
|   pageNum: 1, | ||||
|   pageSize: 10, | ||||
|   nodeName: undefined, | ||||
|   flowName: undefined, | ||||
|   flowCode: undefined, | ||||
|   createByIds: [] | ||||
| }); | ||||
| onMounted(() => { | ||||
|   getWaitingList(); | ||||
| }); | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   getWaitingList(); | ||||
| }; | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   queryParams.value.pageNum = 1; | ||||
|   queryParams.value.pageSize = 10; | ||||
|   queryParams.value.createByIds = []; | ||||
|   userSelectCount.value = 0; | ||||
|   selectUserIds.value = []; | ||||
|   handleQuery(); | ||||
| }; | ||||
| // 多选框选中数据 | ||||
| const handleSelectionChange = (selection: any) => { | ||||
|   ids.value = selection.map((item: any) => item.id); | ||||
|   single.value = selection.length !== 1; | ||||
|   multiple.value = !selection.length; | ||||
| }; | ||||
| //分页 | ||||
| const getWaitingList = () => { | ||||
|   loading.value = true; | ||||
|   pageByTaskWait(queryParams.value).then((resp) => { | ||||
|     taskList.value = resp.rows; | ||||
|     total.value = resp.total; | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
| //办理 | ||||
| const handleOpen = async (row: FlowTaskVO) => { | ||||
|   const routerJumpVo = reactive<RouterJumpVo>({ | ||||
|     businessId: row.businessId, | ||||
|     taskId: row.id, | ||||
|     type: 'approval', | ||||
|     formCustom: row.formCustom, | ||||
|     formPath: row.formPath | ||||
|   }); | ||||
|   workflowCommon.routerJump(routerJumpVo, proxy); | ||||
| }; | ||||
| //打开申请人选择 | ||||
| const openUserSelect = () => { | ||||
|   userSelectRef.value.open(); | ||||
| }; | ||||
| //确认选择申请人 | ||||
| const userSelectCallBack = (data: UserVO[]) => { | ||||
|   userSelectCount.value = 0; | ||||
|   if (data && data.length > 0) { | ||||
|     userSelectCount.value = data.length; | ||||
|     selectUserIds.value = data.map((item) => item.userId); | ||||
|     queryParams.value.createByIds = selectUserIds.value; | ||||
|   } | ||||
| }; | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user
	 zhuer
					zhuer