add 项目管理
This commit is contained in:
parent
09eb888093
commit
c7a5299466
@ -1,6 +1,7 @@
|
|||||||
import { ServiceResponse } from './response';
|
import { ServiceResponse } from './response';
|
||||||
import { ServiceRequestPage } from './pageInput'
|
import { ServiceRequestPage } from './pageInput'
|
||||||
import { PageResponse } from './pageResponse'
|
import { PageResponse } from './pageResponse'
|
||||||
|
import { ProjectUser, ProjectPrincipal } from './projectUserType'
|
||||||
|
|
||||||
// 过滤条件
|
// 过滤条件
|
||||||
export interface ProjectFilter {
|
export interface ProjectFilter {
|
||||||
@ -30,8 +31,18 @@ export interface ProjectDto {
|
|||||||
status?: boolean
|
status?: boolean
|
||||||
/** 创建时间 */
|
/** 创建时间 */
|
||||||
createdTime?: string | null
|
createdTime?: string | null
|
||||||
|
|
||||||
|
/** 创建人姓名 */
|
||||||
|
createdUserName?: string | null
|
||||||
|
|
||||||
/** 修改时间 */
|
/** 修改时间 */
|
||||||
modifiedTime?: string | null
|
modifiedTime?: string | null
|
||||||
|
|
||||||
|
/** 项目成员 */
|
||||||
|
projectUsers?: ProjectUser[]
|
||||||
|
|
||||||
|
/** 项目负责人 */
|
||||||
|
projectPrincipals?: ProjectPrincipal[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 项目添加和更新输入接口 */
|
/** 项目添加和更新输入接口 */
|
||||||
@ -48,11 +59,17 @@ export interface ProjectAddInputAndUpdateInput {
|
|||||||
principalId?: number
|
principalId?: number
|
||||||
/** 状态 */
|
/** 状态 */
|
||||||
status?: boolean
|
status?: boolean
|
||||||
|
|
||||||
|
/** 项目成员 */
|
||||||
|
projectUsers?: ProjectUser[]
|
||||||
|
|
||||||
|
/** 项目负责人 */
|
||||||
|
projectPrincipals?: ProjectPrincipal[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// API 类型定义
|
// API 类型定义
|
||||||
export type ProjectPageInput = ServiceRequestPage<ProjectFilter>;
|
export type ProjectPageInput = ServiceRequestPage<ProjectFilter>;
|
||||||
export type ProjectPageResponse = PageResponse<ProjectDto>;
|
export type ProjectPageResponse = ServiceResponse<PageResponse<ProjectDto>>;
|
||||||
export type ProjectOutput = ServiceResponse<ProjectDto>;
|
export type ProjectOutput = ServiceResponse<ProjectDto>;
|
||||||
export type ProjectAddInput = ProjectAddInputAndUpdateInput;
|
export type ProjectAddInput = ProjectAddInputAndUpdateInput;
|
||||||
export type ProjectUpdateInput = ProjectAddInputAndUpdateInput;
|
export type ProjectUpdateInput = ProjectAddInputAndUpdateInput;
|
61
src/api/types/projectUserType.ts
Normal file
61
src/api/types/projectUserType.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 项目用户权限类型定义
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目用户权限信息
|
||||||
|
*/
|
||||||
|
export interface ProjectUser {
|
||||||
|
/** ID */
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
/** 项目ID */
|
||||||
|
projectId?: number;
|
||||||
|
|
||||||
|
/** 所属组ID */
|
||||||
|
groupId?: number;
|
||||||
|
|
||||||
|
/** 用户ID */
|
||||||
|
userId: number;
|
||||||
|
|
||||||
|
/** 用户过期时间 */
|
||||||
|
limitToDate?: string;
|
||||||
|
|
||||||
|
/** 上传权限 */
|
||||||
|
upload: boolean;
|
||||||
|
|
||||||
|
/** 撤回上传权限 */
|
||||||
|
revokeUpload: boolean;
|
||||||
|
|
||||||
|
/** 审核权限 */
|
||||||
|
review: boolean;
|
||||||
|
|
||||||
|
/** 撤回审核权限 */
|
||||||
|
revokeReview: boolean;
|
||||||
|
|
||||||
|
/** 签名权限 */
|
||||||
|
signature: boolean;
|
||||||
|
|
||||||
|
/** 撤回签名权限 */
|
||||||
|
revokeSignature: boolean;
|
||||||
|
|
||||||
|
/** 审核(二)权限 */
|
||||||
|
verify: boolean;
|
||||||
|
|
||||||
|
/** 撤回审核(二)权限 */
|
||||||
|
revokeVerify: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目负责人信息
|
||||||
|
*/
|
||||||
|
export interface ProjectPrincipal {
|
||||||
|
/** ID */
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
/** 项目ID */
|
||||||
|
projectId?: number;
|
||||||
|
|
||||||
|
/** 用户ID */
|
||||||
|
userId: number;
|
||||||
|
}
|
@ -1,19 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="dialogVisible" :title="title" width="600px" append-to-body class="project-form-dialog">
|
<el-dialog
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" class="project-form">
|
v-model="dialogVisible"
|
||||||
<el-form-item label="部门" prop="departmentId">
|
destroy-on-close
|
||||||
<el-select v-model="form.departmentId" placeholder="请选择部门" style="width: 100%" filterable>
|
:title="title"
|
||||||
<el-option v-for="item in state.departmentOptions" :key="item.id" :label="item.name" :value="item.id" />
|
draggable
|
||||||
</el-select>
|
:close-on-click-modal="false"
|
||||||
</el-form-item>
|
:close-on-press-escape="false"
|
||||||
|
width="1400px"
|
||||||
|
>
|
||||||
|
<div class="project-form-container">
|
||||||
|
<!-- 左侧:项目基础信息 -->
|
||||||
|
<div class="left-panel">
|
||||||
|
<h4 class="panel-title">基础信息</h4>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" size="default">
|
||||||
<el-form-item label="项目编号" prop="projectNo">
|
<el-form-item label="项目编号" prop="projectNo">
|
||||||
<el-input v-model="form.projectNo" placeholder="请输入项目编号" />
|
<el-input v-model="form.projectNo" placeholder="请输入项目编号" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="项目名称" prop="projectName">
|
<el-form-item label="项目名称" prop="projectName">
|
||||||
<el-input v-model="form.projectName" placeholder="请输入项目名称" />
|
<el-input v-model="form.projectName" placeholder="请输入项目名称" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="责任人" prop="principalId">
|
<el-form-item label="责任人" prop="principalIds">
|
||||||
<el-select v-model="form.principalId" placeholder="请选择责任人" style="width: 100%" filterable>
|
<el-select v-model="form.principalIds" multiple placeholder="请选择责任人" style="width: 100%" filterable clearable>
|
||||||
<el-option v-for="item in state.principalOptions" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in state.principalOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -21,23 +28,101 @@
|
|||||||
<el-switch v-model="form.status" />
|
<el-switch v-model="form.status" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:项目人员列表 -->
|
||||||
|
<div class="right-panel">
|
||||||
|
<h4 class="panel-title">项目人员列表</h4>
|
||||||
|
<div class="user-actions">
|
||||||
|
<el-button type="primary" size="default" @click="handleAddUser">添加人员</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
:data="form.projectUsers"
|
||||||
|
style="width: 100%"
|
||||||
|
size="default"
|
||||||
|
border
|
||||||
|
max-height="500"
|
||||||
|
>
|
||||||
|
<el-table-column prop="userName" label="用户名称" min-width="120" />
|
||||||
|
<el-table-column label="审核权限" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="permission-grid">
|
||||||
|
<el-checkbox v-model="row.upload" size="default">上传</el-checkbox>
|
||||||
|
<el-checkbox v-model="row.verify" size="default">审核</el-checkbox>
|
||||||
|
<el-checkbox v-model="row.review" size="default">下游审核</el-checkbox>
|
||||||
|
<el-checkbox v-model="row.signature" size="default">签名</el-checkbox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="撤回权限" width="230">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="permission-grid">
|
||||||
|
<el-checkbox v-model="row.revokeUpload" size="default">撤回上传</el-checkbox>
|
||||||
|
<el-checkbox v-model="row.revokeVerify" size="default">撤回审核</el-checkbox>
|
||||||
|
<el-checkbox v-model="row.revokeReview" size="default">撤回下游审核</el-checkbox>
|
||||||
|
<el-checkbox v-model="row.revokeSignature" size="default">撤回签名</el-checkbox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="limitToDate" label="有效日期" min-width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="row.limitToDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="有效日期"
|
||||||
|
size="default"
|
||||||
|
style="width: 100%"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="80" fixed="right">
|
||||||
|
<template #default="{ $index }">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="default"
|
||||||
|
text
|
||||||
|
@click="handleRemoveUser($index)"
|
||||||
|
>删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
<el-button @click="OnCancel" size="default">取 消</el-button>
|
<el-button @click="OnCancel" size="default">取 消</el-button>
|
||||||
<el-button type="primary" :loading="state.sureLoading" @click="submitForm" size="default">确 定</el-button>
|
<el-button type="primary" :loading="state.sureLoading" @click="submitForm" size="default">确 定</el-button>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<user-select
|
||||||
|
ref="userSelectRef"
|
||||||
|
:title="`添加【${form.projectName}】人员`"
|
||||||
|
multiple
|
||||||
|
:sure-loading="state.sureLoading"
|
||||||
|
@sure="onSureUser"
|
||||||
|
></user-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="admin/project/form">
|
<script setup lang="ts" name="admin/project/form">
|
||||||
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
|
import { ref, reactive, onMounted, getCurrentInstance, defineAsyncComponent } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import { ProjectApi } from '../../../../api/admin/ProjectApi'
|
import { ProjectApi } from '/@/api/admin/ProjectApi'
|
||||||
import { OrgApi } from '/@/api/admin/Org'
|
import { OrgApi } from '/@/api/admin/Org'
|
||||||
import { UserApi } from '/@/api/admin/User'
|
import { UserApi } from '/@/api/admin/User'
|
||||||
import { ProjectAddInputAndUpdateInput } from '/@/api/types/projectType'
|
import { ProjectAddInputAndUpdateInput } from '/@/api/types/projectType'
|
||||||
|
import { ProjectUser } from '/@/api/types/projectUserType'
|
||||||
|
import {
|
||||||
|
UserGetPageOutput,
|
||||||
|
} from '/@/api/admin/data-contracts'
|
||||||
import eventBus from '/@/utils/mitt'
|
import eventBus from '/@/utils/mitt'
|
||||||
|
|
||||||
|
const UserSelect = defineAsyncComponent(() => import('/@/views/admin/user/components/user-select.vue'))
|
||||||
const { proxy } = getCurrentInstance() as any
|
const { proxy } = getCurrentInstance() as any
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@ -46,42 +131,51 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const form = reactive<ProjectAddInputAndUpdateInput>({
|
const userSelectRef = ref()
|
||||||
departmentId: undefined,
|
|
||||||
|
// 扩展项目表单接口
|
||||||
|
interface ProjectFormData {
|
||||||
|
id?: number
|
||||||
|
projectNo: string
|
||||||
|
projectName: string
|
||||||
|
principalIds: number[]
|
||||||
|
projectUsers: Array<{
|
||||||
|
id?: number
|
||||||
|
userId: number
|
||||||
|
userName?: string
|
||||||
|
groupId?: number
|
||||||
|
groupName?: string
|
||||||
|
limitToDate?: string
|
||||||
|
upload: boolean
|
||||||
|
revokeUpload: boolean
|
||||||
|
review: boolean
|
||||||
|
revokeReview: boolean
|
||||||
|
signature: boolean
|
||||||
|
revokeSignature: boolean
|
||||||
|
verify: boolean
|
||||||
|
revokeVerify: boolean
|
||||||
|
}>
|
||||||
|
status: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = reactive<ProjectFormData>({
|
||||||
projectNo: '',
|
projectNo: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
principalId: undefined,
|
principalIds: [],
|
||||||
|
projectUsers: [],
|
||||||
status: true
|
status: true
|
||||||
})
|
})
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
sureLoading: false,
|
sureLoading: false,
|
||||||
departmentOptions: [] as Array<{ id: number; name: string }>,
|
|
||||||
principalOptions: [] as Array<{ id: number; name: string }>
|
principalOptions: [] as Array<{ id: number; name: string }>
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
departmentId: [{ required: true, message: '请选择部门', trigger: 'change' }],
|
|
||||||
projectNo: [{ required: true, message: '请输入项目编号', trigger: 'blur' }],
|
projectNo: [{ required: true, message: '请输入项目编号', trigger: 'blur' }],
|
||||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }]
|
||||||
principalId: [{ required: true, message: '请选择责任人', trigger: 'change' }]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 获取部门列表 */
|
|
||||||
const getDepartmentOptions = async () => {
|
|
||||||
try {
|
|
||||||
const res = await new OrgApi().getList()
|
|
||||||
if (res?.success && res.data) {
|
|
||||||
state.departmentOptions = res.data.map((item: any) => ({
|
|
||||||
id: item.id,
|
|
||||||
name: item.name
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取部门列表失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取负责人列表 */
|
/** 获取负责人列表 */
|
||||||
const getPrincipalOptions = async () => {
|
const getPrincipalOptions = async () => {
|
||||||
try {
|
try {
|
||||||
@ -101,30 +195,55 @@ const getPrincipalOptions = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const open = async (id?: number) => {
|
const open = async (id?: number) => {
|
||||||
proxy.$modal.loading()
|
// 先打开弹窗,避免loading遮罩造成的刷新感
|
||||||
|
dialogVisible.value = true
|
||||||
|
|
||||||
|
// 如果是编辑模式且有ID,才显示loading
|
||||||
if (id && id > 0) {
|
if (id && id > 0) {
|
||||||
const res = await new ProjectApi().get({ id }, { loading: true })
|
state.sureLoading = true
|
||||||
|
try {
|
||||||
|
const res = await new ProjectApi().get({ id }, { loading: false })
|
||||||
if (res?.success && res.data) {
|
if (res?.success && res.data) {
|
||||||
const formData = res.data as unknown as ProjectAddInputAndUpdateInput
|
const formData = res.data as any
|
||||||
Object.assign(form, formData)
|
form.principalIds = Array.isArray(res.data.projectPrincipals)
|
||||||
|
? res.data.projectPrincipals.map((item: any) => item.userId)
|
||||||
|
: []
|
||||||
|
|
||||||
|
// TODO 负责人多选控件不能加载问题
|
||||||
|
console.log("form.principalIds", form.principalIds)
|
||||||
|
|
||||||
|
form.projectUsers = Array.isArray(formData.projectUsers) ? formData.projectUsers : []
|
||||||
|
form.projectUsers.forEach((item: any) => {
|
||||||
|
item.userName = state.principalOptions.find((a) => a.id === item.userId)?.name || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.assign(form, {
|
||||||
|
id: formData.id,
|
||||||
|
projectNo: formData.projectNo || '',
|
||||||
|
projectName: formData.projectName || '',
|
||||||
|
principalIds: formData.projectPrincipalIds || [],
|
||||||
|
projectUsers: formData.projectUsers || [],
|
||||||
|
status: formData.status !== undefined ? formData.status : true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取项目详情失败:', error)
|
||||||
|
} finally {
|
||||||
|
state.sureLoading = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 新增模式,直接重置表单
|
||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
departmentId: undefined,
|
|
||||||
projectNo: '',
|
projectNo: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
principalId: undefined,
|
principalIds: [],
|
||||||
|
projectUsers: [],
|
||||||
status: true
|
status: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
proxy.$modal.closeLoading()
|
if (state.principalOptions.length === 0) {
|
||||||
dialogVisible.value = true
|
await getPrincipalOptions()
|
||||||
|
}
|
||||||
await Promise.all([
|
|
||||||
getDepartmentOptions(),
|
|
||||||
getPrincipalOptions()
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 取消 */
|
/** 取消 */
|
||||||
@ -141,7 +260,16 @@ const submitForm = async () => {
|
|||||||
state.sureLoading = true
|
state.sureLoading = true
|
||||||
try {
|
try {
|
||||||
const api = new ProjectApi()
|
const api = new ProjectApi()
|
||||||
const res = form.id ? await api.update(form) : await api.add(form)
|
// 转换数据格式以匹配后端API
|
||||||
|
const submitData = {
|
||||||
|
id: form.id,
|
||||||
|
projectNo: form.projectNo,
|
||||||
|
projectName: form.projectName,
|
||||||
|
status: form.status,
|
||||||
|
projectPrincipals: form.principalIds.map((id: number) => ({ userId: id })),
|
||||||
|
projectUsers: form.projectUsers.length > 0 ? form.projectUsers : []
|
||||||
|
}
|
||||||
|
const res = form.id ? await api.update(submitData as any) : await api.add(submitData as any)
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
ElMessage.success(form.id ? '修改成功' : '新增成功')
|
ElMessage.success(form.id ? '修改成功' : '新增成功')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
@ -159,9 +287,53 @@ const submitForm = async () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
const handleAddUser = () => {
|
||||||
getDepartmentOptions()
|
userSelectRef.value.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSureUser = async (users: UserGetPageOutput[]) => {
|
||||||
|
if (!(users?.length > 0)) {
|
||||||
|
userSelectRef.value.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state.sureLoading = true
|
||||||
|
// 过滤掉 id 为 undefined 的用户,保证 userId 类型安全
|
||||||
|
const validUsers = users?.filter((u) => typeof u.id === 'number') ?? []
|
||||||
|
|
||||||
|
// 避免重复添加
|
||||||
|
const existingUserIds = form.projectUsers.map((u) => u.userId)
|
||||||
|
const newUsers = validUsers.filter((u) => !existingUserIds.includes(u.id as number))
|
||||||
|
|
||||||
|
const newUserList = newUsers.map((u) => ({
|
||||||
|
userId: u.id as number, // 明确断言为 number,避免类型错误
|
||||||
|
userName: u.userName ?? '',
|
||||||
|
groupName: '',
|
||||||
|
limitToDate: '',
|
||||||
|
upload: false,
|
||||||
|
revokeUpload: false,
|
||||||
|
review: false,
|
||||||
|
revokeReview: false,
|
||||||
|
signature: false,
|
||||||
|
revokeSignature: false,
|
||||||
|
verify: false,
|
||||||
|
revokeVerify: false
|
||||||
|
}))
|
||||||
|
form.projectUsers.push(...newUserList)
|
||||||
|
state.sureLoading = false
|
||||||
|
userSelectRef.value.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除用户 */
|
||||||
|
const handleRemoveUser = (index: number) => {
|
||||||
|
form.projectUsers.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 组件挂载时就加载选项数据,避免弹窗打开时的延迟
|
||||||
|
await Promise.all([
|
||||||
getPrincipalOptions()
|
getPrincipalOptions()
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@ -170,15 +342,105 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.project-form-dialog {
|
.project-form-container {
|
||||||
:deep(.el-dialog__body) {
|
display: flex;
|
||||||
padding: 20px 30px;
|
gap: 20px;
|
||||||
|
min-height: 650px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-panel {
|
||||||
|
flex: 0 0 350px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 2px solid #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-actions {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table) {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table .el-table__body-wrapper) {
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #c1c1c1 #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table .el-table__body-wrapper::-webkit-scrollbar) {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table .el-table__body-wrapper::-webkit-scrollbar-track) {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table .el-table__body-wrapper::-webkit-scrollbar-thumb) {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table .el-table__body-wrapper::-webkit-scrollbar-thumb:hover) {
|
||||||
|
background: #a0a0a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.el-checkbox {
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-form {
|
@media (max-width: 768px) {
|
||||||
.el-form-item {
|
:deep(.el-dialog) {
|
||||||
margin-bottom: 22px;
|
height: 95vh;
|
||||||
|
width: 95vw !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-form-container {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-panel,
|
||||||
|
.right-panel {
|
||||||
|
flex: none;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,37 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<my-layout>
|
<my-layout>
|
||||||
<el-card class="box-card">
|
<!-- 查询区 -->
|
||||||
<template #header>
|
<el-card class="my-query-box mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
|
||||||
<div class="card-header">
|
<el-form :inline="true" label-width="auto" :model="state.filter" class="demo-form-inline" @submit.stop.prevent>
|
||||||
<el-form :inline="true" :model="state.filter" class="demo-form-inline">
|
|
||||||
<el-form-item label="关键字">
|
<el-form-item label="关键字">
|
||||||
<el-input v-model="state.filter.keyWord" placeholder="请输入关键字" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="state.filter.keyWord" placeholder="请输入关键字" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="部门">
|
|
||||||
<el-select v-model="state.filter.departmentId" placeholder="请选择部门" clearable filterable>
|
|
||||||
<el-option v-for="item in state.departmentOptions" :key="item.id" :label="item.name" :value="item.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
|
||||||
<el-button @click="resetQuery">重置</el-button>
|
<el-button v-auth="'api:admin:project:add'" type="primary" icon="ele-Plus" @click="handleAdd"> 新增 </el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-button v-auth="'api:admin:project:add'" type="primary" @click="handleAdd">新增</el-button>
|
</el-card>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="state.projectList" style="width: 100%">
|
<!-- 表格区 -->
|
||||||
<el-table-column type="index" label="序号" width="60" />
|
<el-card class="my-fill mt8" shadow="never">
|
||||||
|
<div class="my-tools-box mb8 my-flex my-flex-between">
|
||||||
|
<!-- 可添加工具栏内容,如批量操作等 -->
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="loading" :data="state.projectList" style="width: 100%" border row-key="projectNo">
|
||||||
<el-table-column prop="projectNo" label="项目编号" />
|
<el-table-column prop="projectNo" label="项目编号" />
|
||||||
<el-table-column prop="projectName" label="项目名称" />
|
<el-table-column prop="projectName" label="项目名称" />
|
||||||
<el-table-column prop="departmentName" label="部门" />
|
<el-table-column prop="createdUserName" label="创建人" />
|
||||||
<el-table-column prop="principalName" label="责任人" />
|
|
||||||
<el-table-column prop="status" label="状态" width="80">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-tag :type="row.status ? 'success' : 'danger'">{{ row.status ? '启用' : '禁用' }}</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="createdTime" label="创建时间" width="180" />
|
<el-table-column prop="createdTime" label="创建时间" width="180" />
|
||||||
<el-table-column label="操作" width="180" fixed="right" header-align="center" align="center">
|
<el-table-column label="操作" width="180" fixed="right" header-align="center" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
@ -72,14 +62,12 @@ const state = reactive({
|
|||||||
total: 0,
|
total: 0,
|
||||||
filter: {
|
filter: {
|
||||||
keyWord: '',
|
keyWord: '',
|
||||||
departmentId: undefined as number | undefined
|
|
||||||
},
|
},
|
||||||
pageInput: {
|
pageInput: {
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
} as ProjectPageInput,
|
} as ProjectPageInput,
|
||||||
projectList: [] as Array<ProjectDto>,
|
projectList: [] as Array<ProjectDto>
|
||||||
departmentOptions: [] as Array<{ id: number; name: string }>
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
@ -88,8 +76,8 @@ const getList = async () => {
|
|||||||
state.pageInput.filter = state.filter
|
state.pageInput.filter = state.filter
|
||||||
try {
|
try {
|
||||||
const res = await new ProjectApi().getPage(state.pageInput)
|
const res = await new ProjectApi().getPage(state.pageInput)
|
||||||
state.projectList = res.list || []
|
state.projectList = res.data?.list || []
|
||||||
state.total = res.total || 0
|
state.total = res.data?.total || 0
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取列表失败:', error)
|
console.error('获取列表失败:', error)
|
||||||
} finally {
|
} finally {
|
||||||
@ -97,21 +85,6 @@ const getList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取部门列表 */
|
|
||||||
const getDepartmentOptions = async () => {
|
|
||||||
try {
|
|
||||||
const res = await new OrgApi().getList()
|
|
||||||
if (res?.success && res.data) {
|
|
||||||
state.departmentOptions = res.data.map((item: any) => ({
|
|
||||||
id: item.id,
|
|
||||||
name: item.name
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取部门列表失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
state.pageInput.currentPage = 1
|
state.pageInput.currentPage = 1
|
||||||
@ -122,7 +95,6 @@ const handleQuery = () => {
|
|||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
state.filter = {
|
state.filter = {
|
||||||
keyWord: '',
|
keyWord: '',
|
||||||
departmentId: undefined
|
|
||||||
}
|
}
|
||||||
handleQuery()
|
handleQuery()
|
||||||
}
|
}
|
||||||
@ -172,7 +144,6 @@ const handleCurrentChange = (val: number) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
getDepartmentOptions()
|
|
||||||
eventBus.on('refreshProject', getList)
|
eventBus.on('refreshProject', getList)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user