Sfoglia il codice sorgente

feat: 删除group概念。

删除group,改为user直接与project对应,修改界面,修改vuex等类型定义,修改相关接口与Mock接口。
Jinyao 5 anni fa
parent
commit
363694a74d

+ 0 - 1
mock/index.js

@@ -26,7 +26,6 @@ app.use(`${prefix}/users`, require('./routers/user'));
 app.use(`${prefix}/project`, require('./routers/project'));
 app.use(`${prefix}/pipelines`, require('./routers/pipeline'));
 app.use(`${prefix}/deployments`, require('./routers/deployment'));
-app.use(`${prefix}/groups`, require('./routers/group'));
 
 app.listen(4000);
 

+ 0 - 26
mock/routers/group.js

@@ -1,26 +0,0 @@
-/* eslint-disable import/no-extraneous-dependencies */
-/* eslint-disable @typescript-eslint/no-var-requires */
-const router = require('express').Router();
-const wrapper = require('../wrapper');
-
-router.get('/',
-  (req, res) => {
-    const id = req.query.groupId;
-    res.json(wrapper({
-      id,
-      groupId: `Group-${id}`,
-    }));
-  });
-module.exports = router;
-
-router.post('/', (req, res) => {
-  res.json(wrapper('success'));
-});
-
-router.get('/members', (req, res) => {
-  res.json(wrapper([101, 102, 103, 104, 105]));
-});
-
-router.post('/members', (req, res) => {
-  res.json(wrapper('success'));
-});

+ 8 - 16
mock/routers/project.js

@@ -46,25 +46,17 @@ router.get('/listByUser/:userId',
     ));
   });
 
-router.get('/listByGroup/:groupId',
-  (req, res) => {
-    const { groupId } = req.params;
-    res.json(wrapper(
-      Mock.mock(Mock.mock({
-        'data|3-5': [{
-          'id|+1': 100,
-          description: Random.csentence(5, 40),
-          gitRemoteUrl: Random.url('http', 'gitlab.seecoder.cn'),
-          groupId,
-          name: Random.cname(),
-        }],
-      }).data),
-    ));
-  });
-
 router.get('/delete/:projectId',
   (req, res) => {
     res.json(wrapper({}));
   });
 
+router.get('/members', (req, res) => {
+  res.json(wrapper([101, 102, 103, 104]));
+});
+
+router.get('/refresh', (req, res) => {
+  res.json(wrapper('success'));
+});
+
 module.exports = router;

+ 12 - 3
src/api/devcloud/project.ts

@@ -2,12 +2,21 @@ import axios from '@/utils/axios';
 
 import { PROJECT_PREFIX } from './prefix';
 
+interface AddProjectMemberPayload {
+  invitedUserId: number;
+  projectId: number;
+}
+
 export const getProjectById = (projectId: number) => axios.get(`${PROJECT_PREFIX}/${projectId}`);
 
-export const createProject = (project: Project) => axios.post(`${PROJECT_PREFIX}/create`, project);
+export const createProject = (name: string, description: string) => axios.post(`${PROJECT_PREFIX}/create`, {
+  name,
+  description,
+});
 
 export const getProjectListByUserId = (userId: number) => axios.get(`${PROJECT_PREFIX}/listByUser/${userId}`);
 
-export const getProjectListByGroupId = (groupId: number) => axios.get(`${PROJECT_PREFIX}/listByGroup/${groupId}`);
-
 export const deleteProject = (projectId: string) => axios.get(`${PROJECT_PREFIX}/delete/${projectId}`);
+
+export const addProjectMember = (addProjectMemberPayload: AddProjectMemberPayload) => axios.post(`${PROJECT_PREFIX}/members`,
+  addProjectMemberPayload);

+ 1 - 24
src/api/devcloud/user.ts

@@ -1,29 +1,6 @@
 import axios from '@/utils/axios';
 
-import { USER_PREFIX, GROUP_PREFIX } from './prefix';
-
-interface AddGroupMemberPayload {
-  invitedUserId: number;
-  groupId: number;
-}
+import { USER_PREFIX } from './prefix';
 
 // USER API
 export const getUserInfo = () => axios.get(`${USER_PREFIX}/self`);
-
-// GROUP API
-export const getGroupInfo = () => axios.get(`${GROUP_PREFIX}`);
-
-export const createGroup = (groupName: string) => axios.post(`${GROUP_PREFIX}`, null, {
-  params: {
-    groupName,
-  },
-});
-
-export const getGroupMembers = (groupId: number) => axios.get(`${GROUP_PREFIX}/members`, {
-  params: {
-    groupId,
-  },
-});
-
-export const addGroupMember = (addGroupMemberPayload: AddGroupMemberPayload) => axios.post(`${GROUP_PREFIX}/members`,
-  addGroupMemberPayload);

+ 89 - 68
src/components/Menu.vue

@@ -3,31 +3,20 @@
     <ElMenuItem class="menu-logo" index="logo" disabled>
       LOGO
     </ElMenuItem>
-    <ElSubmenu index="group">
-      <template #title>{{selectedGroup.name}}</template>
-      <template  v-if="groupList.length > 0">
-      <ElMenuItem v-for="group in groupList" :key="group.id" :index="`group-${group.id}`">{{group.name}}</ElMenuItem>
-      </template>
-      <template v-else>
-        <ElMenuItem disabled>暂未加入任何小组</ElMenuItem>
-      </template>
-    </ElSubmenu>
     <ElSubmenu index="project">
       <template #title>{{selectedProject.name}}</template>
       <template v-if="projectList.length > 0">
         <ElMenuItem v-for="project in projectList" :key="project.id" :index="`project-${project.id}`">{{project.name}}</ElMenuItem>
       </template>
-      <template v-else-if="selectedGroup.id === -1">
-        <ElMenuItem disabled>请先选择小组</ElMenuItem>
-      </template>
       <template v-else>
-        <ElMenuItem disabled>该小组暂无项目</ElMenuItem>
+        <ElMenuItem disabled>暂无项目</ElMenuItem>
       </template>
     </ElSubmenu>
       <template v-if="userLoggedIn">
         <ElSubmenu index="user" class="user">
           <template #title>{{userInfo.username}}</template>
-          <ElMenuItem index="user-group">创建小组 / 邀请成员</ElMenuItem>
+          <ElMenuItem index="user-project">创建项目</ElMenuItem>
+          <ElMenuItem index="user-invite">邀请成员</ElMenuItem>
           <ElMenuItem index="user-logout">登出</ElMenuItem>
         </ElSubmenu>
       </template>
@@ -35,35 +24,48 @@
         <ElLink type="primary" href="/login" class="user">登录</ElLink>
       </template>
   </ElMenu>
-  <ElDrawer v-model="showGroupDrawer" style="width:400px;">
-    <template #title><span>创建小组 / 邀请成员</span></template>
-    <ElRow type="flex" justify="center">
-      <ElCol :span="24">
-        <ElDivider content-position="left">创建小组</ElDivider>
-        <ElForm :inline="true" :model="createGroupForm">
-          <ElFormItem label="组名" prop="groupName">
-            <ElInput v-model="createGroupForm.groupName" placeholder="请输入要创建的小组名"></ElInput>
-          </ElFormItem>
-          <ElFormItem>
-            <ElButton @click="createGroup" type="primary">创建</ElButton>
-          </ElFormItem>
-        </ElForm>
-        <ElDivider content-position="left">邀请成员</ElDivider>
-        <ElForm :model="inviteGroupForm" label-width="72px">
-          <ElFormItem label="小组" prop="groupId">
-            <ElSelect v-model="inviteGroupForm.groupId" placeholder="请选择成员将要加入的小组">
-              <ElOption v-for="group in groupList" :key="group.id" :value="group.id" :label="group.name"></ElOption>
-            </ElSelect>
+  <ElDrawer v-model="showProjectDrawer">
+    <template #title><span>创建项目</span></template>
+    <div class="drawer-content">
+      <div class="form-container">
+        <ElForm :model="createProjectForm">
+          <ElFormItem label="项目名" prop="name">
+            <ElInput v-model="createProjectForm.name" placeholder="请输入要创建的项目名"></ElInput>
           </ElFormItem>
-          <ElFormItem label="手机号" prop="phone">
-            <ElInput v-model="inviteGroupForm.phone" placeholder="请输入成员注册所用手机号"></ElInput>
+          <ElFormItem label="项目描述" prop="description">
+            <ElInput
+              v-model="createProjectForm.description"
+              placeholder="请输入项目描述"
+              type="textarea"
+              :autosize="{ minRows: 3, maxRows: 3}"
+            ></ElInput>
           </ElFormItem>
           <ElFormItem>
-            <ElButton @click="inviteMember" type="primary">邀请</ElButton>
+            <ElButton @click="createProject" type="primary">创建</ElButton>
           </ElFormItem>
         </ElForm>
-      </ElCol>
-    </ElRow>
+      </div>
+    </div>
+  </ElDrawer>
+  <ElDrawer v-model="showInviteDrawer">
+    <template #title><span>邀请成员</span></template>
+    <div class="drawer-content">
+      <div class="form-container">
+      <ElForm :model="inviteProjectForm">
+        <ElFormItem label="项目" prop="projectId">
+          <ElSelect v-model="inviteProjectForm.projectId" placeholder="请选择成员将要加入的项目">
+            <ElOption v-for="project in projectList" :key="project.id" :value="project.id" :label="project.name"></ElOption>
+          </ElSelect>
+        </ElFormItem>
+        <ElFormItem label="手机号" prop="phone">
+          <ElInput v-model="inviteProjectForm.phone" placeholder="请输入成员注册所用手机号"></ElInput>
+        </ElFormItem>
+        <ElFormItem>
+          <ElButton @click="inviteMember" type="primary">邀请</ElButton>
+        </ElFormItem>
+      </ElForm>
+    </div>
+  </div>
   </ElDrawer>
 </template>
 
@@ -71,39 +73,46 @@
 import { ElMessage } from 'element-plus';
 
 import { useProjectList } from '@/composable/useProject';
-import { useGroupList } from '@/composable/useGroup';
 import { useUser } from '@/composable/useUser';
 import { defineComponent, ref, reactive } from 'vue';
-import { UserAPI, PortalAPI } from '@/api';
+import { PortalAPI, ProjectAPI } from '@/api';
 
 export default defineComponent({
   name: 'Menu',
   setup() {
-    const { projectListOfCurrentGroup: projectList, selectedProject, handleProjectChange } = useProjectList();
-    const { groupList, selectedGroup, handleGroupChange } = useGroupList();
+    const { projectList, selectedProject, handleProjectChange } = useProjectList();
     const { userInfo, userLoggedIn, userLogOut } = useUser();
 
-    // TODO: 自定义两个表单验证
-    const showGroupDrawer = ref(false);
+    const showProjectDrawer = ref(false);
+    const showInviteDrawer = ref(false);
 
-    const openGroupDrawer = () => {
-      showGroupDrawer.value = true;
+    const openProjectDrawer = () => {
+      showProjectDrawer.value = true;
+    };
+    const openInviteDrawer = () => {
+      showInviteDrawer.value = true;
     };
-    const createGroupForm = reactive({
-      groupName: '',
+    const createProjectForm = reactive({
+      name: '',
+      description: '',
     });
-    const createGroup = () => {
-      UserAPI.createGroup(createGroupForm.groupName);
+    const createProject = () => {
+      ProjectAPI.createProject(createProjectForm.name, createProjectForm.description);
     };
 
-    const inviteGroupForm = reactive({
-      groupId: undefined,
+    interface InviteProjectForm {
+      projectId: undefined | number;
+      phone: string;
+    }
+
+    const inviteProjectForm = reactive<InviteProjectForm>({
+      projectId: undefined,
       phone: '',
     });
     const inviteMember = async () => {
       let invitedUserId: number;
 
-      const res = await PortalAPI.getUserIdByPhoneNumber(inviteGroupForm.phone) as unknown as {id: number};
+      const res = await PortalAPI.getUserIdByPhoneNumber(inviteProjectForm.phone) as unknown as {id: number};
 
       if (res) {
         invitedUserId = res.id;
@@ -115,8 +124,16 @@ export default defineComponent({
         return;
       }
 
-      UserAPI.addGroupMember({
-        groupId: inviteGroupForm.groupId!,
+      if (!inviteProjectForm.projectId) {
+        ElMessage({
+          type: 'error',
+          message: '请选择有效的项目',
+        });
+        return;
+      }
+
+      ProjectAPI.addProjectMember({
+        projectId: inviteProjectForm.projectId,
         invitedUserId,
       });
     };
@@ -131,13 +148,11 @@ export default defineComponent({
           handleProjectChange(parseInt(id, 10));
           break;
         }
-        case 'group': {
-          handleGroupChange(parseInt(id, 10));
-          break;
-        }
         case 'user': {
-          if (id === 'group') {
-            openGroupDrawer();
+          if (id === 'project') {
+            openProjectDrawer();
+          } else if (id === 'invite') {
+            openInviteDrawer();
           } else if (id === 'logout') {
             userLogOut();
           }
@@ -153,19 +168,18 @@ export default defineComponent({
       projectList,
       selectedProject,
 
-      groupList,
-      selectedGroup,
-
       handleSelect,
 
       userInfo,
       userLoggedIn,
       userLogOut,
 
-      showGroupDrawer,
-      createGroupForm,
-      createGroup,
-      inviteGroupForm,
+      showProjectDrawer,
+      showInviteDrawer,
+
+      createProjectForm,
+      createProject,
+      inviteProjectForm,
       inviteMember,
     };
   },
@@ -193,4 +207,11 @@ export default defineComponent({
   height: 60px;
   margin: 0 20px;
 }
+.drawer-content {
+  display: flex;
+  justify-content: center;
+}
+.form-container {
+  width: 80%;
+}
 </style>

+ 0 - 19
src/composable/useGroup.ts

@@ -1,19 +0,0 @@
-import { computed } from 'vue';
-import { useStore } from '@/store';
-import { WorkspaceDispatcher } from '@/store/dispatchers';
-
-export const useGroupList = () => {
-  const store = useStore();
-
-  const groupList = computed(() => store.state.workspace.groupList);
-  const selectedGroup = computed(() => store.getters.currentGroupInfo);
-
-  const handleGroupChange = (groupId: number) => {
-    WorkspaceDispatcher.changeGroup(groupId);
-  };
-  return {
-    groupList,
-    selectedGroup,
-    handleGroupChange,
-  };
-};

+ 0 - 2
src/composable/useProject.ts

@@ -8,7 +8,6 @@ export const useProjectList = () => {
   const router = useRouter();
 
   const projectList = computed(() => store.state.workspace.projectList);
-  const projectListOfCurrentGroup = computed(() => store.getters.projectListOfCurrentGroup);
   const selectedProject = computed(() => store.getters.currentProjectInfo);
 
   const handleProjectChange = (projectId: number) => {
@@ -17,7 +16,6 @@ export const useProjectList = () => {
   };
   return {
     projectList,
-    projectListOfCurrentGroup,
     selectedProject,
     handleProjectChange,
   };

+ 1 - 3
src/composable/useUser.ts

@@ -1,11 +1,9 @@
 import { computed } from 'vue';
 import { useStore } from '@/store';
 import { UserDispatcher, TokenDispatcher } from '@/store/dispatchers';
-import { useRouter } from 'vue-router';
 
 export const useUser = () => {
   const store = useStore();
-  const router = useRouter();
 
   const userInfo = computed(() => store.state.user);
   const userLoggedIn = computed(() => store.state.user.role !== 'GUEST');
@@ -13,7 +11,7 @@ export const useUser = () => {
   const userLogOut = () => {
     UserDispatcher.userLogOut();
     TokenDispatcher.destroyToken();
-    router.push('/');
+    window.location.href = '/';
   };
   return {
     userInfo,

+ 16 - 16
src/router/index.ts

@@ -67,22 +67,22 @@ const router = createRouter({
   routes,
 });
 
-// router.beforeEach((to, from, next) => {
-//   if (to.matched.some((record) => record.meta.requiresAuth)) {
-//     // this route requires auth, check if logged in
-//     // if not, redirect to login page.
-//     if (!isUserLoggedIn()) {
-//       next({
-//         name: LOGIN,
-//         query: { redirect: to.fullPath },
-//       });
-//     } else {
-//       next();
-//     }
-//   } else {
-//     next();
-//   }
-// });
+router.beforeEach((to, from, next) => {
+  if (to.matched.some((record) => record.meta.requiresAuth)) {
+    // this route requires auth, check if logged in
+    // if not, redirect to login page.
+    if (!isUserLoggedIn()) {
+      next({
+        name: LOGIN,
+        query: { redirect: to.fullPath },
+      });
+    } else {
+      next();
+    }
+  } else {
+    next();
+  }
+});
 
 router.beforeEach((to, from, next) => {
   if (to.name !== LOGIN || !isUserLoggedIn()) {

+ 0 - 6
src/store/dispatchers/workspace.ts

@@ -4,12 +4,6 @@ export const refreshProjectList = () => {
   store.dispatch('refreshProjectList', store.state.user.id);
 };
 
-export const changeGroup = (groupId: number) => {
-  store.dispatch('changeGroup', { groupId });
-  store.dispatch('resetCurrentProject');
-};
-
 export const changeProject = (projectId: number) => {
-  changeGroup(store.getters.getGroupIdFromProjectId(projectId));
   store.dispatch('changeProject', { projectId });
 };

+ 0 - 1
src/store/modules/token.ts

@@ -17,7 +17,6 @@ const actions: ActionTree<TokenState, RootState> = {
       token: '',
     } as TokenPayload);
     destoryToken();
-    useRouter().push('/home');
   },
 };
 

+ 1 - 46
src/store/modules/workspace.ts

@@ -3,34 +3,11 @@ import {
   ActionTree, GetterTree, Module, MutationTree,
 } from 'vuex';
 import {
-  WorkspaceState, RootState, ChangeGroupPayload, ChangeProjectPayload,
+  WorkspaceState, RootState, ChangeProjectPayload,
 } from '../typings';
 
 const DEFAULT: WorkspaceState = {
   currentProjectId: -1,
-  currentGroupId: -1,
-  groupList: [
-    {
-      id: 101,
-      name: 'Group-1',
-    },
-    {
-      id: 102,
-      name: 'Group-2',
-    },
-    {
-      id: 13,
-      name: 'Group-3',
-    },
-    {
-      id: 104,
-      name: 'Group-4',
-    },
-    {
-      id: 105,
-      name: 'Group-5',
-    },
-  ],
   projectList: [],
 };
 
@@ -39,9 +16,6 @@ const actions: ActionTree<WorkspaceState, RootState> = {
     const projectList = await ProjectAPI.getProjectListByUserId(userId);
     commit('updateProjectList', projectList);
   },
-  changeGroup({ commit }, payload: ChangeGroupPayload) {
-    commit('changeGroup', payload);
-  },
   changeProject({ commit }, payload: ChangeProjectPayload) {
     commit('changeProject', payload);
   },
@@ -54,24 +28,12 @@ const mutations: MutationTree<WorkspaceState> = {
   updateProjectList(state, payload: Array<Project>) {
     state.projectList = payload;
   },
-  changeGroup(state, { groupId }: ChangeGroupPayload) {
-    state.currentGroupId = groupId;
-  },
   changeProject(state, { projectId }: ChangeProjectPayload) {
     state.currentProjectId = projectId;
   },
 };
 
 const getters: GetterTree<WorkspaceState, RootState> = {
-  projectListOfCurrentGroup(state) {
-    return state.projectList.filter((project) => project.groupId === state.currentGroupId);
-  },
-  getGroupIdFromProjectId(state) {
-    return (projectId: number) => {
-      const p = Array.prototype.find.call(state.projectList, (project) => project.id === projectId) as Project;
-      return p.groupId;
-    };
-  },
   currentProjectInfo(state) {
     return Array.prototype.find.call(state.projectList, (project) => project.id === state.currentProjectId)
       || {
@@ -79,13 +41,6 @@ const getters: GetterTree<WorkspaceState, RootState> = {
         name: '未选择项目',
       };
   },
-  currentGroupInfo(state) {
-    return Array.prototype.find.call(state.groupList, (group) => group.id === state.currentGroupId)
-      || {
-        id: -1,
-        name: '未选择小组',
-      };
-  },
 };
 
 export const workspace: Module<WorkspaceState, RootState> = {

+ 0 - 8
src/store/typings.ts

@@ -1,7 +1,5 @@
-type GroupId = number;
 type ProjectId = number;
 
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
 export interface RootState {
   token: TokenState;
   user: UserState;
@@ -21,16 +19,10 @@ export interface UserState {
 }
 
 export interface WorkspaceState {
-  currentGroupId: GroupId;
   currentProjectId: ProjectId;
-  groupList: Array<Group>;
   projectList: Array<Project>;
 }
 
-export interface ChangeGroupPayload {
-  groupId: GroupId;
-}
-
 export interface ChangeProjectPayload {
   projectId: ProjectId;
 }

+ 2 - 8
src/typings/project.d.ts

@@ -2,17 +2,11 @@ declare interface Project {
   id: number;
   name: string;
   description: string;
-  groupId: number;
   gitRemoteUrl: string;
 }
 
-declare interface Group {
-  id: number;
-  name: string;
-}
-
-declare type TreeNodeType = '0:需求' | '1:任务';
-declare type TreeNodeState = '0:已创建' | '1:进行中' | '2:已结束';
+declare type TreeNodeType = '需求' | '任务';
+declare type TreeNodeState = '已创建' | '进行中' | '已结束';
 
 declare interface TreeNode {
   deep: number;

+ 0 - 2
src/typings/vuex.d.ts

@@ -15,9 +15,7 @@ declare module '@vue/runtime-core' {
       username: string;
     };
     workspace: {
-      currentGroupId: GroupId;
       currentProjectId: ProjectId;
-      groupList: Array<Group>;
       projectList: Array<Project>;
     };
   }