feat(系统设置): 项目表格页面

This commit is contained in:
RubyLiu 2023-08-16 19:14:34 +08:00 committed by 刘瑞斌
parent 92047fd3d7
commit 77a56344a3
9 changed files with 370 additions and 84 deletions

View File

@ -57,3 +57,8 @@ export function deleteUserFromOrgOrProject(sourceId: string, userId: string, isO
url: `${isOrg ? orgUrl.getDeleteOrgMemberUrl : orgUrl.getDeleteProjectMemberUrl}${sourceId}/${userId}`, url: `${isOrg ? orgUrl.getDeleteOrgMemberUrl : orgUrl.getDeleteProjectMemberUrl}${sourceId}/${userId}`,
}); });
} }
// TODO: 等待后端同学的接口 启用或禁用项目
export function enableOrDisableProject(id: string, isEnable = true) {
return MSR.get({ url: `${isEnable ? orgUrl.getEnableOrgUrl : orgUrl.getDisableOrgUrl}${id}` });
}

View File

@ -29,7 +29,7 @@ export const getOrgDefaultUrl = '/system/organization/default';
// 更新项目信息 // 更新项目信息
export const postModifyProjectUrl = '/system/project/update'; export const postModifyProjectUrl = '/system/project/update';
// 获取项目列表 // 获取项目列表
export const postProjectTableUrl = '/system/project/list'; export const postProjectTableUrl = '/system/project/page';
// 获取项目成员 // 获取项目成员
export const postProjectMemberUrl = '/system/project/member/list'; export const postProjectMemberUrl = '/system/project/member/list';
// 添加项目 // 添加项目

View File

@ -121,7 +121,7 @@
const { redirect, ...othersQuery } = router.currentRoute.value.query; const { redirect, ...othersQuery } = router.currentRoute.value.query;
setLoginExpires(); setLoginExpires();
router.push({ router.push({
name: (redirect as string) || 'setting', name: (redirect as string) || 'settingSystemUser',
query: { query: {
...othersQuery, ...othersQuery,
}, },

View File

@ -0,0 +1,121 @@
<template>
<a-modal
v-model:visible="currentVisible"
width="680px"
class="ms-modal-form ms-modal-medium"
:ok-text="t('system.organization.create')"
unmount-on-close
@cancel="handleCancel"
>
<template #title>
<span v-if="isEdit">
{{ t('system.organization.updateOrganization') }}
<span class="text-[var(--color-text-4)]">({{ props.currentOrganization?.name }})</span>
</span>
<span v-else>
{{ t('system.organization.createOrganization') }}
</span>
</template>
<div class="form">
<a-form ref="formRef" :model="form" size="large" :style="{ width: '600px' }" layout="vertical">
<a-form-item
field="name"
required
:label="t('system.organization.organizationName')"
:rules="[{ required: true, message: t('system.organization.organizationNameRequired') }]"
>
<a-input v-model="form.name" :placeholder="t('system.organization.organizationNamePlaceholder')" />
</a-form-item>
<a-form-item field="name" :label="t('system.organization.organizationAdmin')">
<MsUserSelector
v-model:value="form.memberIds"
placeholder="system.organization.organizationAdminPlaceholder"
/>
</a-form-item>
<a-form-item field="description" :label="t('system.organization.description')">
<a-input v-model="form.description" :placeholder="t('system.organization.descriptionPlaceholder')" />
</a-form-item>
</a-form>
</div>
<template #footer>
<a-button type="secondary" :loading="loading" @click="handleCancel">
{{ t('common.cancel') }}
</a-button>
<a-button type="primary" :loading="loading" @click="handleBeforeOk">
{{ isEdit ? t('common.confirm') : t('common.create') }}
</a-button>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { useI18n } from '@/hooks/useI18n';
import { reactive, ref, watchEffect, computed } from 'vue';
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
import MsUserSelector from '@/components/bussiness/ms-user-selector/index.vue';
import { createOrUpdateOrg } from '@/api/modules/setting/system/organizationAndProject';
import { Message } from '@arco-design/web-vue';
import { CreateOrUpdateSystemOrgParams } from '@/models/setting/system/orgAndProject';
const { t } = useI18n();
const props = defineProps<{
visible: boolean;
currentOrganization?: CreateOrUpdateSystemOrgParams;
}>();
const formRef = ref<FormInstance>();
const loading = ref(false);
const emit = defineEmits<{
(e: 'cancel'): void;
}>();
const form = reactive<{ name: string; memberIds: string[]; description: string }>({
name: '',
memberIds: [],
description: '',
});
const currentVisible = ref(props.visible);
watchEffect(() => {
currentVisible.value = props.visible;
});
const handleCancel = () => {
emit('cancel');
};
const handleBeforeOk = () => {
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
if (errors) {
return false;
}
try {
loading.value = true;
await createOrUpdateOrg({ id: props.currentOrganization?.id, ...form });
Message.success(
props.currentOrganization?.id
? t('system.organization.updateOrganizationSuccess')
: t('system.organization.createOrganizationSuccess')
);
handleCancel();
return true;
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
return false;
} finally {
loading.value = false;
}
});
};
watchEffect(() => {
if (props.currentOrganization) {
form.name = props.currentOrganization.name;
form.memberIds = props.currentOrganization.memberIds;
form.description = props.currentOrganization.description;
}
});
const isEdit = computed(() => !!props.currentOrganization?.id);
</script>

View File

@ -173,7 +173,7 @@
openDeleteModal({ openDeleteModal({
title: t('system.organization.deleteName', { name: record.name }), title: t('system.organization.deleteName', { name: record.name }),
content: t('system.organization.deleteTip'), content: t('system.organization.deleteTip'),
onOk: async () => { onBeforeOk: async () => {
try { try {
await deleteOrg(record.id); await deleteOrg(record.id);
Message.success(t('common.deleteSuccess')); Message.success(t('common.deleteSuccess'));

View File

@ -1,19 +1,47 @@
<template> <template>
<MsBaseTable v-bind="propsRes" v-on="propsEvent"> <MsBaseTable v-bind="propsRes" v-on="propsEvent">
<template #name="{ record }">
<span>{{ record.name }}</span>
<a-tooltip background-color="#FFFFFF">
<template #content>
<span class="text-[var(--color-text-1)]">{{ t('system.organization.revokeDeleteToolTip') }}</span>
<MsButton class="ml-[8px]" @click="handleRevokeDelete(record)">{{ t('common.revokeDelete') }}</MsButton>
</template>
<MsIcon v-if="record.deleted" type="icon-icon_alarm_clock" class="ml-[4px] text-[rgb(var(--danger-6))]" />
</a-tooltip>
</template>
<template #creator="{ record }">
<span>{{ record.createUser }}</span>
<span v-if="record.creatorAdmin" class="text-[var(--color-text-4)]">{{ `&nbsp;(${t('common.admin')})` }}</span>
</template>
<template #memberCount="{ record }">
<span class="primary-color" @click="showUserDrawer(record)">{{ record.memberCount }}</span>
</template>
<template #operation="{ record }"> <template #operation="{ record }">
<template v-if="!record.enable"> <template v-if="record.deleted">
<MsButton @click="handleEnable(record)">{{ t('system.organization.enable') }}</MsButton> <MsButton @click="handleRevokeDelete(record)">{{ t('common.revokeDelete') }}</MsButton>
<MsButton @click="handleDelete(record)">{{ t('system.organization.delete') }}</MsButton> </template>
<template v-else-if="!record.enable">
<MsButton @click="handleEnableOrDisableOrg(record)">{{ t('common.enable') }}</MsButton>
<MsButton @click="handleDelete(record)">{{ t('common.delete') }}</MsButton>
</template> </template>
<template v-else> <template v-else>
<MsButton @click="showOrganizationModal(record)">{{ t('system.organization.edit') }}</MsButton> <MsButton @click="showOrganizationModal(record)">{{ t('common.edit') }}</MsButton>
<MsButton @click="showAddUserModal(record)">{{ t('system.organization.addUser') }}</MsButton> <MsButton @click="showAddUserModal(record)">{{ t('system.organization.addMember') }}</MsButton>
<MsButton @click="handleEnd(record)">{{ t('system.organization.end') }}</MsButton> <MsButton @click="handleEnableOrDisableOrg(record, false)">{{ t('common.end') }}</MsButton>
<MsTableMoreAction :list="tableActions" @select="handleMoreAction($event, record)"></MsTableMoreAction> <MsTableMoreAction :list="tableActions" @select="handleMoreAction($event, record)"></MsTableMoreAction>
</template> </template>
</template> </template>
</MsBaseTable> </MsBaseTable>
<AddOrganizationModal :visible="userVisible" @cancel="handleAddUserModalCancel" /> <AddOrganizationModal
type="edit"
:current-organization="currentUpdateOrganization"
:visible="orgVisible"
@cancel="handleAddOrgModalCancel"
/>
<AddUserModal :organization-id="currentOrganizationId" :visible="userVisible" @cancel="handleAddUserModalCancel" />
<ProjectDrawer v-bind="currentProjectDrawer" @cancel="handleProjectDrawerCancel" />
<UserDrawer v-bind="currentUserDrawer" @cancel="handleUserDrawerCancel" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -21,18 +49,117 @@
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { useTableStore } from '@/store'; import { useTableStore } from '@/store';
import { watchEffect, ref } from 'vue'; import { ref, reactive, watch } from 'vue';
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import {
import MsButton from '@/components/pure/ms-button/index.vue'; postProjectTable,
import { postUserByUserGroup } from '@/api/modules/setting/usergroup'; deleteOrg,
enableOrDisableProject,
revokeDeleteOrg,
} from '@/api/modules/setting/system/organizationAndProject';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { MsTableColumn } from '@/components/pure/ms-table/type'; import { MsTableColumn } from '@/components/pure/ms-table/type';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import AddOrganizationModal from './addOrganizationModal.vue'; import AddOrganizationModal from './addOrganizationModal.vue';
import ProjectDrawer from './projectDrawer.vue';
import { Message, TableData } from '@arco-design/web-vue';
import UserDrawer from './userDrawer.vue';
import AddUserModal from './addUserModal.vue';
import useModal from '@/hooks/useModal';
import { CreateOrUpdateSystemOrgParams } from '@/models/setting/system/orgAndProject';
export interface SystemOrganizationProps {
keyword: string;
}
const props = defineProps<SystemOrganizationProps>();
const { t } = useI18n(); const { t } = useI18n();
const tableStore = useTableStore(); const tableStore = useTableStore();
const userVisible = ref(false); const userVisible = ref(false);
const orgVisible = ref(false);
const currentOrganizationId = ref('');
const currentUpdateOrganization = ref<CreateOrUpdateSystemOrgParams>();
const { openDeleteModal, openModal } = useModal();
const organizationColumns: MsTableColumn = [
{
title: 'system.organization.ID',
dataIndex: 'num',
width: 100,
},
{
title: 'system.organization.name',
slotName: 'name',
editable: true,
},
{
title: 'system.organization.member',
slotName: 'memberCount',
},
{
title: 'system.organization.status',
dataIndex: 'enable',
},
{
title: 'system.organization.description',
dataIndex: 'description',
ellipsis: true,
tooltip: true,
},
{
title: 'system.organization.subordinateOrg',
dataIndex: 'organizationName',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: 'system.organization.creator',
slotName: 'creator',
dataIndex: 'createUser',
},
{
title: 'system.organization.createTime',
dataIndex: 'createTime',
width: 230,
},
{
title: 'system.organization.operation',
slotName: 'operation',
fixed: 'right',
width: 208,
},
];
tableStore.initColumn(TableKeyEnum.SYSTEM_PROJECT, organizationColumns, 'drawer');
const { propsRes, propsEvent, loadList, setKeyword, setLoading } = useTable(postProjectTable, {
tableKey: TableKeyEnum.SYSTEM_PROJECT,
scroll: { y: 'auto', x: '1300px' },
selectable: false,
noDisable: false,
debug: true,
size: 'default',
showSetting: true,
});
const fetchData = async () => {
setKeyword(props.keyword);
await loadList();
};
const currentProjectDrawer = reactive({
visible: false,
organizationId: '',
currentName: '',
});
const currentUserDrawer = reactive({
visible: false,
organizationId: '',
});
const tableActions: ActionsItem[] = [ const tableActions: ActionsItem[] = [
{ {
@ -42,96 +169,125 @@
}, },
]; ];
const handleDelete = (record: any) => { const handleDelete = (record: TableData) => {
// eslint-disable-next-line no-console openDeleteModal({
console.log(record); title: t('system.organization.deleteName', { name: record.name }),
content: t('system.organization.deleteTip'),
onBeforeOk: async () => {
try {
await deleteOrg(record.id);
Message.success(t('common.deleteSuccess'));
fetchData();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
});
}; };
const handleMoreAction = (tag: string, record: any) => { const handleMoreAction = (tag: ActionsItem, record: TableData) => {
if (tag === 'delete') { if (tag.eventTag === 'delete') {
handleDelete(record); handleDelete(record);
} }
}; };
const handleEnable = (record: any) => { const handleEnableOrDisableOrg = async (record: any, isEnable = true) => {
// eslint-disable-next-line no-console const title = isEnable ? t('system.organization.enableTitle') : t('system.organization.enableTitle');
console.log(record); const content = isEnable ? t('system.organization.enableContent') : t('system.organization.endContent');
}; const okText = isEnable ? t('common.confirmEnable') : t('common.confirmClose');
openModal({
const handleEnd = (record: any) => { type: 'error',
// eslint-disable-next-line no-console cancelText: t('common.cancel'),
console.log(record); title,
content,
okText,
onBeforeOk: async () => {
try {
await enableOrDisableProject(record.id, isEnable);
Message.success(isEnable ? t('common.enableSuccess') : t('common.closeSuccess'));
fetchData();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}; };
const showOrganizationModal = (record: any) => { const showOrganizationModal = (record: any) => {
// eslint-disable-next-line no-console currentOrganizationId.value = record.id;
console.log(record); orgVisible.value = true;
currentUpdateOrganization.value = {
id: record.id,
name: record.name,
description: record.description,
memberIds: record.orgAdmins.map((item: any) => item.id) || [],
};
}; };
const showAddUserModal = (record: any) => { const showAddUserModal = (record: any) => {
// eslint-disable-next-line no-console currentOrganizationId.value = record.id;
console.log(record);
userVisible.value = true; userVisible.value = true;
}; };
const projectColumn: MsTableColumn = [ const handleProjectDrawerCancel = () => {
{ currentProjectDrawer.visible = false;
title: 'system.organization.ID', fetchData();
dataIndex: 'id', };
},
{
title: 'system.organization.name',
dataIndex: 'name',
},
{
title: 'system.organization.member',
dataIndex: 'name',
},
{
title: 'system.organization.project',
dataIndex: 'project',
},
{
title: 'system.organization.enabled',
dataIndex: 'enabled',
},
{
title: 'system.organization.description',
dataIndex: 'description',
},
{
title: 'system.organization.createUser',
dataIndex: 'createUser',
},
{
title: 'system.organization.createTime',
dataIndex: 'createTime',
},
{
title: 'system.organization.operation',
slotName: 'operation',
fixed: 'right',
width: 200,
},
];
tableStore.initColumn(TableKeyEnum.SYSTEM_PROJECT, projectColumn, 'drawer'); const showProjectDrawer = (record: TableData) => {
currentProjectDrawer.visible = true;
currentProjectDrawer.organizationId = record.id;
currentProjectDrawer.currentName = record.name;
};
const { propsRes, propsEvent, loadList } = useTable(postUserByUserGroup, { const showUserDrawer = (record: TableData) => {
tableKey: TableKeyEnum.SYSTEM_PROJECT, currentUserDrawer.visible = true;
scroll: { y: 'auto', x: '600px' }, currentUserDrawer.organizationId = record.id;
selectable: false, };
noDisable: false,
});
const fetchData = async () => { const handleUserDrawerCancel = () => {
await loadList(); currentUserDrawer.visible = false;
fetchData();
}; };
const handleAddUserModalCancel = () => { const handleAddUserModalCancel = () => {
userVisible.value = false; userVisible.value = false;
};
watchEffect(() => {
fetchData(); fetchData();
}); };
const handleAddOrgModalCancel = () => {
orgVisible.value = false;
fetchData();
};
const handleRevokeDelete = async (record: TableData) => {
try {
setLoading(true);
await revokeDeleteOrg(record.id);
Message.success(t('common.revokeDeleteSuccess'));
fetchData();
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
} finally {
setLoading(false);
}
};
watch(
() => props.keyword,
() => {
fetchData();
},
{ immediate: true }
);
</script> </script>
<style lang="scss" scoped>
.primary-color {
color: rgb(var(--primary-5));
cursor: pointer;
}
</style>

View File

@ -40,7 +40,7 @@
import SystemProject from './components/systemProject.vue'; import SystemProject from './components/systemProject.vue';
const { t } = useI18n(); const { t } = useI18n();
const currentTable = ref('organization'); const currentTable = ref('project');
const organizationVisible = ref(false); const organizationVisible = ref(false);
const organizationCount = ref(0); const organizationCount = ref(0);
const projectCount = ref(0); const projectCount = ref(0);

View File

@ -52,4 +52,6 @@ export default {
'The organization after closing is not displayed in the organization switching list', 'The organization after closing is not displayed in the organization switching list',
'system.organization.updateOrganization': 'Update organization', 'system.organization.updateOrganization': 'Update organization',
'system.organization.updateOrganizationSuccess': 'Update organization success', 'system.organization.updateOrganizationSuccess': 'Update organization success',
'system.organization.createProject': 'Create project',
'system.organization.subordinateOrg': 'Subordinate organization',
}; };

View File

@ -48,4 +48,6 @@ export default {
'system.organization.endContent': '关闭后的组织不展示在组织切换列表', 'system.organization.endContent': '关闭后的组织不展示在组织切换列表',
'system.organization.updateOrganization': '更新组织', 'system.organization.updateOrganization': '更新组织',
'system.organization.updateOrganizationSuccess': '更新组织成功', 'system.organization.updateOrganizationSuccess': '更新组织成功',
'system.organization.createProject': '创建项目',
'system.organization.subordinateOrg': '所属组织',
}; };