feat(项目管理): 基本信息需求调整
This commit is contained in:
parent
03a03e80ff
commit
c4994e5ad1
|
@ -0,0 +1,13 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import { ProjectBasicInfoUrl, UpdateProjectUrl } from '@/api/requrls/project-management/basicInfo';
|
||||
import type { ProjectBasicInfoModel, UpdateProject } from '@/models/projectManagement/basicInfo';
|
||||
|
||||
// 获取项目详情
|
||||
export function getProjectInfo(id: string) {
|
||||
return MSR.get<ProjectBasicInfoModel>({ url: ProjectBasicInfoUrl, params: id });
|
||||
}
|
||||
|
||||
// 更新项目
|
||||
export function updateProject(data: UpdateProject) {
|
||||
return MSR.post({ url: UpdateProjectUrl, data });
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export const ProjectBasicInfoUrl = '/project/get';
|
||||
export const UpdateProjectUrl = '/project/update';
|
|
@ -59,7 +59,7 @@
|
|||
export interface SwitchProps {
|
||||
switchTooltip?: string; // 展示开关提示信息描述
|
||||
switchName?: string; // 开关后边的名称
|
||||
enable: boolean | undefined; // 开关绑定值
|
||||
enable?: boolean | undefined; // 开关绑定值
|
||||
showSwitch: boolean; // 是否展示开关
|
||||
}
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, Ref, onBeforeMount } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { IconCompass, IconQuestionCircle, IconFile, IconInfoCircle } from '@arco-design/web-vue/es/icon';
|
||||
// import { Message } from '@arco-design/web-vue';
|
||||
// import { useFullscreen } from '@vueuse/core';
|
||||
|
@ -204,6 +204,7 @@
|
|||
const appStore = useAppStore();
|
||||
// const { logout } = useUser();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
||||
const projectList: Ref<ProjectListItem[]> = ref([]);
|
||||
|
@ -227,6 +228,13 @@
|
|||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
appStore.setCurrentProjectId(value as string);
|
||||
router.replace({
|
||||
path: route.path,
|
||||
query: {
|
||||
organizationId: appStore.currentOrgId,
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const helpCenterList = [
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
export interface AdminList {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
enable: boolean;
|
||||
createTime: string;
|
||||
updateTime: number;
|
||||
language: string;
|
||||
lastOrganizationId: string;
|
||||
phone: string;
|
||||
source: string;
|
||||
lastProjectId: string;
|
||||
createUser: string;
|
||||
updateUser: string;
|
||||
deleted: boolean; // 是否删除
|
||||
adminFlag: boolean; // 是否组织/项目管理员
|
||||
memberFlag: boolean; // 是否组织/项目成员
|
||||
checkRoleFlag: boolean; // 是否属于用户组
|
||||
sourceId: string; // 资源id
|
||||
}
|
||||
|
||||
export interface ProjectBasicInfoModel {
|
||||
id: string;
|
||||
num: number;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
description: string;
|
||||
createTime: string;
|
||||
updateTime: number;
|
||||
updateUser: string;
|
||||
createUser: string;
|
||||
deleteTime: number;
|
||||
deleted: boolean;
|
||||
deleteUser: string;
|
||||
enable: boolean;
|
||||
moduleSetting: string; // 模块设置
|
||||
memberCount: number; // 项目成员数量
|
||||
organizationName: string;
|
||||
adminList: AdminList[]; // 管理员
|
||||
projectCreateUserIsAdmin: boolean; // 创建人是否是管理员
|
||||
moduleIds: string[];
|
||||
}
|
||||
|
||||
export interface UpdateProject {
|
||||
organizationId?: string;
|
||||
name: string;
|
||||
description: string;
|
||||
enable?: boolean;
|
||||
moduleIds?: string[]; // 模块设置
|
||||
id?: string;
|
||||
userIds?: string[]; // 成员数
|
||||
}
|
|
@ -6,31 +6,18 @@
|
|||
:close="closeHandler"
|
||||
:confirm="confirmHandler"
|
||||
:switch-props="{
|
||||
enable: isEnable,
|
||||
switchName: t('project.basicInfo.status'),
|
||||
switchTooltip: t('project.basicInfo.createTip'),
|
||||
showSwitch: true,
|
||||
showSwitch: false,
|
||||
}"
|
||||
>
|
||||
<div class="form">
|
||||
<a-form ref="memberFormRef" :model="form" layout="vertical">
|
||||
<a-form ref="projectFormRef" :model="form" layout="vertical">
|
||||
<a-form-item
|
||||
field="name"
|
||||
:label="t('project.basicInfo.projectName')"
|
||||
asterisk-position="end"
|
||||
:rules="[{ required: true, message: t('project.basicInfo.projectNameTip') }]"
|
||||
>
|
||||
<a-input v-model="form.name" allow-clear />
|
||||
</a-form-item>
|
||||
<a-form-item field="userRoleIds" :label="t('project.basicInfo.organization')" asterisk-position="end">
|
||||
<a-select
|
||||
v-model="form.userRoleIds"
|
||||
multiple
|
||||
allow-clear
|
||||
:placeholder="t('project.basicInfo.selectOrganization')"
|
||||
>
|
||||
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
|
||||
</a-select>
|
||||
<a-input v-model="form.name" allow-clear :max-length="250" />
|
||||
</a-form-item>
|
||||
<a-form-item field="description" :label="t('project.basicInfo.Description')" asterisk-position="end">
|
||||
<a-textarea v-model="form.description" allow-clear auto-size />
|
||||
|
@ -41,37 +28,76 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import MsDialog from '@/components/pure/ms-dialog/index.vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { updateProject } from '@/api/modules/project-management/basicInfo';
|
||||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
import type { UpdateProject, ProjectBasicInfoModel } from '@/models/projectManagement/basicInfo';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
(e: 'success'): void;
|
||||
}>();
|
||||
|
||||
const initForm = {
|
||||
organizationId: '',
|
||||
name: '',
|
||||
userRoleIds: [],
|
||||
description: '',
|
||||
enable: false,
|
||||
moduleIds: [], // 模块设置
|
||||
id: '',
|
||||
userIds: [], // 成员数
|
||||
};
|
||||
const form = ref({ ...initForm });
|
||||
const form = ref<UpdateProject>({ ...initForm });
|
||||
|
||||
const updateVisible = ref<boolean>(false);
|
||||
|
||||
const isEnable = ref<boolean>(false);
|
||||
|
||||
const confirmHandler = (enable: boolean | undefined) => {
|
||||
console.log(enable);
|
||||
};
|
||||
const projectFormRef = ref<FormInstance | null>(null);
|
||||
|
||||
const closeHandler = () => {
|
||||
projectFormRef.value?.resetFields();
|
||||
updateVisible.value = false;
|
||||
form.value = { ...initForm };
|
||||
};
|
||||
|
||||
const userGroupOptions = ref([
|
||||
{
|
||||
name: '',
|
||||
id: '',
|
||||
},
|
||||
]);
|
||||
const confirmHandler = async () => {
|
||||
await projectFormRef.value?.validate().then(async (error) => {
|
||||
if (!error) {
|
||||
try {
|
||||
await updateProject(form.value);
|
||||
Message.success(t('project.basicInfo.updateContentTip'));
|
||||
emits('success');
|
||||
closeHandler();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const editProject = (projectItem: ProjectBasicInfoModel) => {
|
||||
const { id, name, description } = projectItem;
|
||||
form.value = {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
};
|
||||
};
|
||||
|
||||
watch(
|
||||
() => updateVisible.value,
|
||||
(val) => {
|
||||
emits('update:visible', val);
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
editProject,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,132 +1,94 @@
|
|||
<template>
|
||||
<div v-if="isDelete" class="mb-6">
|
||||
<div v-if="projectDetail?.deleted" class="mb-6">
|
||||
<a-alert type="error">{{ t('project.basicInfo.alertDescription') }}</a-alert>
|
||||
</div>
|
||||
<div class="wrapper mb-6 flex justify-between">
|
||||
<span class="font-medium text-[var(--color-text-000)]">{{ t('project.basicInfo.basicInfo') }}</span>
|
||||
<MsTableMoreAction :list="tableActions" @select="handleSelect($event)">
|
||||
<a-button type="outline">{{ t('project.basicInfo.action') }}</a-button>
|
||||
</MsTableMoreAction>
|
||||
<a-button v-if="!projectDetail?.deleted" type="outline" @click="editHandler">{{
|
||||
t('project.basicInfo.edit')
|
||||
}}</a-button>
|
||||
</div>
|
||||
<div class="project-info mb-6 h-[112px] bg-white p-1">
|
||||
<div class="inner-wrapper rounded-md p-4">
|
||||
<div class="detail-info flex flex-col justify-between rounded-md p-4">
|
||||
<div class="flex items-center">
|
||||
<span class="mr-1 font-medium text-[var(--color-text-000)]">具体的项目名称</span>
|
||||
<span v-if="!isDelete" class="button enable-button mr-1">{{ t('project.basicInfo.enable') }}</span>
|
||||
<span v-else class="button delete-button">{{ t('project.basicInfo.deleted') }}</span>
|
||||
<span class="one-line-text mr-1 max-w-[300px] font-medium text-[var(--color-text-000)]">{{
|
||||
projectDetail?.name
|
||||
}}</span>
|
||||
<span v-if="!projectDetail?.deleted && projectDetail?.enable" class="button enable-button mr-1">{{
|
||||
t('project.basicInfo.enable')
|
||||
}}</span>
|
||||
<span v-if="!projectDetail?.deleted && !projectDetail?.enable" class="button disabled-button mr-1">{{
|
||||
t('project.basicInfo.disabled')
|
||||
}}</span>
|
||||
<span v-if="projectDetail?.deleted" class="button delete-button">{{ t('project.basicInfo.deleted') }}</span>
|
||||
</div>
|
||||
<div class="one-line-text text-xs text-[--color-text-4]"
|
||||
>描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述</div
|
||||
>
|
||||
<div class="one-line-text text-xs text-[--color-text-4]">{{ projectDetail?.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-1 flex flex-col">
|
||||
<div class="label-item">
|
||||
<span class="label">{{ t('project.basicInfo.createBy') }}</span>
|
||||
<span>罗老师</span>
|
||||
<span>{{ projectDetail?.createUser }}</span>
|
||||
</div>
|
||||
<div class="label-item">
|
||||
<span class="label">{{ t('project.basicInfo.organization') }}</span>
|
||||
<MsTag>疯狂的刚子疯狂的刚子疯狂的刚子疯狂的刚子疯狂的刚子疯狂的刚子</MsTag>
|
||||
<MsTag>{{ projectDetail?.organizationName }}</MsTag>
|
||||
</div>
|
||||
<div class="label-item">
|
||||
<span class="label">{{ t('project.basicInfo.resourcePool') }}</span>
|
||||
<MsTag>资源池</MsTag>
|
||||
</div>
|
||||
<div class="label-item">
|
||||
<span class="label">{{ t('project.basicInfo.createTime') }}</span>
|
||||
<span>2023-04-23 15:33:23</span>
|
||||
<span>{{ getTime(projectDetail?.createTime as string) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<UpdateProjectModal v-model:visible="isVisible" />
|
||||
<UpdateProjectModal ref="projectDetailRef" v-model:visible="isVisible" @success="getProjectDetail()" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import { ref, onBeforeMount } from 'vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import UpdateProjectModal from './components/updateProjectModal.vue';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { getProjectInfo } from '@/api/modules/project-management/basicInfo';
|
||||
import type { ProjectBasicInfoModel } from '@/models/projectManagement/basicInfo';
|
||||
import { getTime } from '@/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const tableActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'project.basicInfo.edit',
|
||||
eventTag: 'edit',
|
||||
},
|
||||
{
|
||||
label: 'project.basicInfo.enable',
|
||||
eventTag: 'enable',
|
||||
},
|
||||
{
|
||||
label: 'project.basicInfo.finish',
|
||||
eventTag: 'finish',
|
||||
},
|
||||
{
|
||||
isDivider: true,
|
||||
},
|
||||
{
|
||||
label: 'project.basicInfo.delete',
|
||||
eventTag: 'delete',
|
||||
danger: true,
|
||||
},
|
||||
];
|
||||
const emits = defineEmits<{
|
||||
(e: 'updateLoading', loading: boolean): void;
|
||||
}>();
|
||||
|
||||
const isDelete = ref<boolean>(true);
|
||||
const projectDetail = ref<ProjectBasicInfoModel>();
|
||||
|
||||
const getProjectDetail = async () => {
|
||||
emits('updateLoading', true);
|
||||
try {
|
||||
projectDetail.value = await getProjectInfo(appStore.currentProjectId);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
emits('updateLoading', false);
|
||||
}
|
||||
};
|
||||
|
||||
const isVisible = ref<boolean>(false);
|
||||
const projectDetailRef = ref();
|
||||
|
||||
const editHandler = () => {
|
||||
isVisible.value = true;
|
||||
projectDetailRef.value.editProject(projectDetail.value);
|
||||
};
|
||||
|
||||
const finishHandler = () => {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.basicInfo.finishedProject'),
|
||||
content: t('project.basicInfo.finishedProjectTip'),
|
||||
okText: t('project.basicInfo.confirmFinish'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'normal',
|
||||
},
|
||||
onBeforeOk: async () => {},
|
||||
hideCancel: false,
|
||||
onBeforeMount(async () => {
|
||||
getProjectDetail();
|
||||
});
|
||||
};
|
||||
|
||||
const deleteHandler = () => {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('project.member.deleteTip', { name: '此项目' }),
|
||||
content: t('project.member.deleteContentTip'),
|
||||
okText: t('project.basicInfo.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'normal',
|
||||
},
|
||||
onBeforeOk: async () => {},
|
||||
hideCancel: false,
|
||||
});
|
||||
};
|
||||
|
||||
function handleSelect(item: ActionsItem) {
|
||||
switch (item.eventTag) {
|
||||
case 'edit':
|
||||
editHandler();
|
||||
break;
|
||||
case 'finish':
|
||||
finishHandler();
|
||||
break;
|
||||
case 'delete':
|
||||
deleteHandler();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
@ -139,7 +101,7 @@
|
|||
.detail-info {
|
||||
height: 100%;
|
||||
background: url('@/assets/images/basic_bg.png');
|
||||
background-size: cover;
|
||||
background-size: auto;
|
||||
.button {
|
||||
border-radius: 2px;
|
||||
@apply inline-block px-2 py-1 text-xs;
|
||||
|
@ -148,6 +110,10 @@
|
|||
color: rgb(var(--success-5));
|
||||
background: rgb(var(--success-1));
|
||||
}
|
||||
.disabled-button {
|
||||
color: var(--color-text-4);
|
||||
background: var(--color-text-n8);
|
||||
}
|
||||
.delete-button {
|
||||
color: rgb(var(--danger-5));
|
||||
background: rgb(var(--danger-1));
|
||||
|
|
|
@ -1,29 +1,20 @@
|
|||
export default {
|
||||
'project.basicInfo.edit': 'Edit',
|
||||
'project.basicInfo.finish': 'Finished',
|
||||
'project.basicInfo.delete': 'Delete',
|
||||
'project.basicInfo.basicInfo': 'Basic Info',
|
||||
'project.basicInfo.action': 'Action',
|
||||
'project.basicInfo.createBy': 'Created By',
|
||||
'project.basicInfo.organization': 'Organization',
|
||||
'project.basicInfo.resourcePool': 'Resource Pool',
|
||||
'project.basicInfo.createTime': 'Created Time',
|
||||
'project.basicInfo.enable': 'Enable',
|
||||
'project.basicInfo.disabled': 'Disabled',
|
||||
'project.basicInfo.deleted': 'Deleted',
|
||||
'project.basicInfo.updateProjectTitle': 'update Project',
|
||||
'project.basicInfo.status': 'Status',
|
||||
'project.basicInfo.createTip': 'After the project is enabled, it will be displayed in the project switching list',
|
||||
'project.basicInfo.projectName': 'Project Name',
|
||||
'project.basicInfo.projectNameTip': 'The project name cannot be empty',
|
||||
'project.basicInfo.Description': 'Description',
|
||||
'project.basicInfo.alertDescription':
|
||||
'The organization will be deleted 30 days later. To cancel the deletion, contact the administrator',
|
||||
'project.basicInfo.selectOrganization': 'Please select the organization',
|
||||
'project.basicInfo.finishedProject': 'Finished project',
|
||||
'project.basicInfo.finishedProjectTip': 'The end of the project is not displayed in the project switch list',
|
||||
'project.basicInfo.confirmFinish': 'Confirm finished',
|
||||
'project.basicInfo.confirmDelete': 'Confirm',
|
||||
'project.member.deleteTip': 'Are you sure you want to delete the {name} project?',
|
||||
'project.member.deleteContentTip':
|
||||
'After the project is deleted, the system deletes the project (including all service data) 30 days later. Exercise caution when performing this operation',
|
||||
'project.basicInfo.updateContentTip': 'Update successfully!',
|
||||
};
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
export default {
|
||||
'project.basicInfo.edit': '编辑',
|
||||
'project.basicInfo.finish': '结束',
|
||||
'project.basicInfo.delete': '删除',
|
||||
'project.basicInfo.basicInfo': '基本信息',
|
||||
'project.basicInfo.action': '操作',
|
||||
'project.basicInfo.createBy': '创建人',
|
||||
'project.basicInfo.organization': '所属组织',
|
||||
'project.basicInfo.resourcePool': '资源池',
|
||||
'project.basicInfo.createTime': '创建时间',
|
||||
'project.basicInfo.enable': '启用',
|
||||
'project.basicInfo.disabled': '禁用',
|
||||
'project.basicInfo.deleted': '已删除',
|
||||
'project.basicInfo.updateProjectTitle': '更新项目',
|
||||
'project.basicInfo.status': '状态',
|
||||
|
@ -16,12 +15,6 @@ export default {
|
|||
'project.basicInfo.projectName': '项目名称',
|
||||
'project.basicInfo.projectNameTip': '项目名称不能为空',
|
||||
'project.basicInfo.Description': '描述',
|
||||
'project.basicInfo.alertDescription': '所属组织将于 30 日后删除,如需撤销删除,请联系管理员',
|
||||
'project.basicInfo.selectOrganization': '请选择组织',
|
||||
'project.basicInfo.finishedProject': '结束项目',
|
||||
'project.basicInfo.finishedProjectTip': '结束后的项目不展示在项目切换列表',
|
||||
'project.basicInfo.confirmFinish': '确认结束',
|
||||
'project.basicInfo.confirmDelete': '确认删除',
|
||||
'project.member.deleteTip': '确认删除 {name} 这个项目吗?',
|
||||
'project.member.deleteContentTip': '删除后,系统会在 30天 后执行删除项目 (含项目下所有业务数据),请谨慎操作!',
|
||||
'project.basicInfo.alertDescription': '所属项目将于 30 日后删除,如需撤销删除,请联系管理员',
|
||||
'project.basicInfo.updateContentTip': '更新成功!',
|
||||
};
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MsCard simple :other-width="290" :min-width="700">
|
||||
<router-view></router-view>
|
||||
<MsCard simple :other-width="290" :min-width="700" :loading="loading">
|
||||
<router-view @update-loading="updateLoading"></router-view>
|
||||
</MsCard>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -92,6 +92,11 @@
|
|||
router.push({ name: itemName });
|
||||
}
|
||||
};
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const updateLoading = (flag: boolean) => {
|
||||
loading.value = flag;
|
||||
};
|
||||
|
||||
const setInitRoute = () => {
|
||||
if (route?.name) currentKey.value = route.name as string;
|
||||
|
|
Loading…
Reference in New Issue