feat(项目管理): 项目权限基本信息页面搭建和修改成员细节style

This commit is contained in:
xinxin.wu 2023-08-30 10:09:30 +08:00 committed by fit2-zhao
parent 5eb2c77d79
commit edb20d4341
14 changed files with 364 additions and 14 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -1,6 +1,8 @@
<template> <template>
<a-dropdown trigger="hover" @select="selectHandler"> <a-dropdown trigger="hover" @select="selectHandler">
<MsButton><icon-more /></MsButton> <MsButton>
<slot><icon-more /></slot>
</MsButton>
<template #content> <template #content>
<template v-for="item of props.list"> <template v-for="item of props.list">
<a-divider v-if="item.isDivider" :key="`${item.label}-divider`" class="ms-dropdown-divider" /> <a-divider v-if="item.isDivider" :key="`${item.label}-divider`" class="ms-dropdown-divider" />

View File

@ -0,0 +1,5 @@
export interface TreeDataItem {
key: string;
title: string;
children?: TreeDataItem[];
}

View File

@ -0,0 +1,77 @@
<template>
<MsDialog
v-model:visible="updateVisible"
dialog-size="medium"
title="project.basicInfo.updateProjectTitle"
:close="closeHandler"
:confirm="confirmHandler"
:switch-props="{
enable: isEnable,
switchName: t('project.basicInfo.status'),
switchTooltip: t('project.basicInfo.createTip'),
showSwitch: true,
}"
>
<div class="form">
<a-form ref="memberFormRef" :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-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 />
</a-form-item>
</a-form>
</div>
</MsDialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsDialog from '@/components/pure/ms-dialog/index.vue';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const initForm = {
name: '',
userRoleIds: [],
description: '',
};
const form = ref({ ...initForm });
const updateVisible = ref<boolean>(false);
const isEnable = ref<boolean>(false);
const confirmHandler = (enable: boolean | undefined) => {
console.log(enable);
};
const closeHandler = () => {
updateVisible.value = false;
};
const userGroupOptions = ref([
{
name: '',
id: '',
},
]);
</script>
<style scoped></style>

View File

@ -1,9 +1,168 @@
<template> <template>
<div> 基本信息 waiting for development</div> <div v-if="isDelete" 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>
<span>
<MsTableMoreAction :list="tableActions" @select="handleSelect($event)">
<a-button type="outline">{{ t('project.basicInfo.action') }}</a-button>
</MsTableMoreAction>
</span>
</div>
<div class="project-info mb-6 h-[112px] bg-white p-1">
<div class="inner-wrapper p-4">
<div class="detail-info flex flex-col justify-between 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>
</div>
<div class="one-line-text text-xs text-[--color-text-4]"
>描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述</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>
</div>
<div class="label-item">
<span class="label">{{ t('project.basicInfo.organization') }}</span>
<span class="rounded bg-[--color-text-n8] px-2 py-[2px]">疯狂的刚子</span>
</div>
<div class="label-item">
<span class="label">{{ t('project.basicInfo.createTime') }}</span>
<span>2023-04-23 15:33:23</span>
</div>
</div>
<UpdateProjectModal v-model:visible="isVisible" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; 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 { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import UpdateProjectModal from './components/updateProjectModal.vue';
const { t } = useI18n();
const { openModal } = useModal();
const tableActions: ActionsItem[] = [
{
label: 'project.basicInfo.edit',
eventTag: 'edit',
},
{
label: 'project.basicInfo.finish',
eventTag: 'finish',
},
{
isDivider: true,
},
{
label: 'project.basicInfo.delete',
eventTag: 'delete',
danger: true,
},
];
const isDelete = ref<boolean>(true);
const isVisible = ref<boolean>(false);
const editHandler = () => {
isVisible.value = true;
};
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,
});
};
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> </script>
<style scoped></style> <style scoped lang="less">
.project-info {
border-radius: 4px;
box-shadow: 0 0 10px rgb(120 56 135/5%);
.inner-wrapper {
height: 100%;
background: rgb(var(--primary-1));
.detail-info {
height: 100%;
background: url('@/assets/images/basic_bg.png');
background-size: cover;
.button {
border-radius: 2px;
@apply inline-block px-2 py-1 text-xs;
}
.enable-button {
color: rgb(var(--success-5));
background: rgb(var(--success-1));
}
.delete-button {
color: rgb(var(--danger-5));
background: rgb(var(--danger-1));
}
}
}
}
.label-item {
margin-bottom: 16px;
height: 22px;
line-height: 22px;
span {
float: left;
}
.label {
margin-right: 16px;
width: 120px;
color: var(--color-text-3);
}
}
</style>

View File

@ -0,0 +1,29 @@
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.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',
};

View File

@ -0,0 +1,27 @@
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.createTime': '创建时间',
'project.basicInfo.enable': '启用',
'project.basicInfo.disabled': '禁用',
'project.basicInfo.deleted': '已删除',
'project.basicInfo.updateProjectTitle': '更新项目',
'project.basicInfo.status': '状态',
'project.basicInfo.createTip': '项目启用后,将展示在项目切换列表',
'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天 后执行删除项目 (含项目下所有业务数据),请谨慎操作!',
};

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="wrapper flex" :style="{ height: 'calc(100vh - 90px)' }"> <div class="wrapper flex min-h-[500px]" :style="{ height: 'calc(100vh - 90px)' }">
<div class="left-menu-wrapper mr-[16px] w-[208px] min-w-[208px] bg-white p-[24px]"> <div class="left-menu-wrapper mr-[16px] w-[208px] min-w-[208px] bg-white p-[24px]">
<div class="left-content"> <div class="left-content">
<div class="mb-2 font-medium">{{ t('project.permission.projectAndPermission') }}</div> <div class="mb-2 font-medium">{{ t('project.permission.projectAndPermission') }}</div>

View File

@ -38,7 +38,6 @@
import { ref } from 'vue'; import { ref } from 'vue';
import MsDialog from '@/components/pure/ms-dialog/index.vue'; import MsDialog from '@/components/pure/ms-dialog/index.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { addOrUpdate } from '@/api/modules/setting/serviceIntegration';
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
const { t } = useI18n(); const { t } = useI18n();

View File

@ -17,6 +17,7 @@
<a-input-search <a-input-search
:max-length="250" :max-length="250"
:placeholder="t('project.member.searchMember')" :placeholder="t('project.member.searchMember')"
allow-clear
@search="searchHandler" @search="searchHandler"
@press-enter="searchHandler" @press-enter="searchHandler"
></a-input-search ></a-input-search
@ -72,6 +73,15 @@
</template> </template>
</ms-base-table> </ms-base-table>
<AddMemberModal v-model:visible="addMemberVisible" /> <AddMemberModal v-model:visible="addMemberVisible" />
<MSBatchModal
ref="batchModalRef"
v-model:visible="batchVisible"
:table-selected="tableSelected"
:action="batchAction"
:tree-data="treeData"
:select-data="selectData"
@add-user-group="addUserGroup"
/>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -83,11 +93,15 @@
import { getMemberList } from '@/api/modules/setting/member'; import { getMemberList } from '@/api/modules/setting/member';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { useTableStore, useUserStore } from '@/store'; import { useTableStore, useUserStore } from '@/store';
import useModal from '@/hooks/useModal';
import type { MsTableColumn } from '@/components/pure/ms-table/type'; import type { MsTableColumn } from '@/components/pure/ms-table/type';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import AddMemberModal from './components/addMemberModal.vue'; import AddMemberModal from './components/addMemberModal.vue';
import MSBatchModal from '@/components/business/ms-batch-modal/index.vue';
import type { TreeDataItem } from '@/models/projectManagement/member';
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal();
const tableStore = useTableStore(); const tableStore = useTableStore();
const userStore = useUserStore(); const userStore = useUserStore();
@ -149,14 +163,14 @@
const tableBatchActions = { const tableBatchActions = {
baseAction: [ baseAction: [
{
label: 'project.member.batchActionAddProject',
eventTag: 'batchAddProject',
},
{ {
label: 'project.member.batchActionAddUserGroup', label: 'project.member.batchActionAddUserGroup',
eventTag: 'batchAddUserGroup', eventTag: 'batchAddUserGroup',
}, },
{
label: 'project.member.batchActionRemove',
eventTag: 'batchActionRemove',
},
], ],
}; };
@ -186,7 +200,39 @@
const searchHandler = () => {}; const searchHandler = () => {};
const handleTableBatch = (actionItem: any) => {}; //
const batchRemoveMember = () => {
openModal({
type: 'error',
title: t('project.member.batchRemoveTip', { number: tableSelected.value.length }),
content: t('project.member.batchRemoveContent'),
okText: t('project.member.deleteMemberConfirm'),
cancelText: t('project.member.Cancel'),
okButtonProps: {
status: 'danger',
},
onBeforeOk: async () => {},
hideCancel: false,
});
};
const batchVisible = ref<boolean>(false);
const selectData = ref<string[]>([]);
const batchAction = ref('');
const treeData = ref<TreeDataItem[]>([]);
//
const addUserGroup = () => {};
const handleTableBatch = (actionItem: any) => {
if (actionItem.eventTag === 'batchActionRemove') {
batchRemoveMember();
}
if (actionItem.eventTag === 'batchAddUserGroup') {
batchVisible.value = true;
addUserGroup();
}
};
const userGroupOptions = ref([ const userGroupOptions = ref([
{ {

View File

@ -35,5 +35,8 @@ export default {
'project.member.selectUserScope': 'Please select a user group for the above members', 'project.member.selectUserScope': 'Please select a user group for the above members',
'project.member.statusEnable': 'Normal', 'project.member.statusEnable': 'Normal',
'project.member.statusDisable': 'Disabled', 'project.member.statusDisable': 'Disabled',
'project.member.subTitle': 'When removed, you lose your organization privileges', 'project.member.subTitle': 'When removed, you lose your project privileges',
'project.member.batchActionRemove': 'Batch Remove',
'project.member.batchRemoveTip': 'Are you sure to remove {number} selected members?',
'project.member.batchRemoveContent': 'When removed, project permissions are lost',
}; };

View File

@ -34,5 +34,8 @@ export default {
'project.member.selectUserScope': '请为以上成员选择用户组', 'project.member.selectUserScope': '请为以上成员选择用户组',
'project.member.statusEnable': '正常', 'project.member.statusEnable': '正常',
'project.member.statusDisable': '禁用', 'project.member.statusDisable': '禁用',
'project.member.subTitle': '移除后,将失去组织权限', 'project.member.subTitle': '移除后,将失去项目权限',
'project.member.batchActionRemove': '从项目移除',
'project.member.batchRemoveTip': '确认移除已选中的 {number} 个成员吗?',
'project.member.batchRemoveContent': '移除后,将失去项目权限',
}; };

View File

@ -96,7 +96,7 @@
const memberFormRef = ref<FormInstance | null>(null); const memberFormRef = ref<FormInstance | null>(null);
const initFormValue = { const initFormValue = {
organizationId: userStore.$state?.lastOrganizationId, organizationId: userStore.$state?.lastOrganizationId,
userRoleIds: [], userRoleIds: ['org_member'],
memberIds: [], memberIds: [],
projectIds: [], projectIds: [],
}; };

View File

@ -9,7 +9,7 @@
> >
<MsCodeEditor <MsCodeEditor
v-model:model-value="pluginScript" v-model:model-value="pluginScript"
title="YAML" title="JSON"
width="100%" width="100%"
height="calc(100vh - 155px)" height="calc(100vh - 155px)"
theme="MS-text" theme="MS-text"