heavyrian2012 %!s(int64=2) %!d(string=hai) anos
pai
achega
08e314725f
Modificáronse 20 ficheiros con 239 adicións e 437 borrados
  1. 9 11
      organization-server/src/main/java/cn/wildfirechat/org/ServiceImpl.java
  2. 3 0
      organization-web/src/api/api.js
  3. 0 59
      organization-web/src/components/common/AppCard.vue
  4. 0 114
      organization-web/src/components/page/Index.vue
  5. 4 0
      organization-web/src/components/page/organization/Department.vue
  6. 5 5
      organization-web/src/components/page/organization/DepartmentAndMember.vue
  7. 0 0
      organization-web/src/components/page/organization/DepartmentInfo.vue
  8. 0 0
      organization-web/src/components/page/organization/ImportMember.vue
  9. 47 13
      organization-web/src/components/page/organization/Member.vue
  10. 0 0
      organization-web/src/components/page/organization/MemberInfo.vue
  11. 0 0
      organization-web/src/components/page/organization/TransferMember.vue
  12. 3 3
      organization-web/src/components/page/organization/dialog/AddDepartmentMember.vue
  13. 0 0
      organization-web/src/components/page/organization/dialog/AddSubDepartment.vue
  14. 0 0
      organization-web/src/components/page/organization/dialog/ChooseDepartment.vue
  15. 0 0
      organization-web/src/components/page/organization/dialog/ChooseMember.vue
  16. 151 0
      organization-web/src/components/page/organization/dialog/UpdateDepartment.vue
  17. 0 0
      organization-web/src/components/page/organization/drawer/DeleteEmployee.vue
  18. 0 224
      organization-web/src/components/page/robot/robot.vue
  19. 7 7
      organization-web/src/router/index.js
  20. 10 1
      organization-web/src/store/components/org_store.js

+ 9 - 11
organization-server/src/main/java/cn/wildfirechat/org/ServiceImpl.java

@@ -651,7 +651,7 @@ public class ServiceImpl implements Service {
     }
 
     private void quitGroup(String groupId, Collection<String> members) throws IMServerException {
-        if(members == null || members.isEmpty()) {
+        if (members == null || members.isEmpty()) {
             return;
         }
 
@@ -667,7 +667,7 @@ public class ServiceImpl implements Service {
         if (StringUtils.isNullOrEmpty(groupId)) {
             return;
         }
-        if(members == null || members.isEmpty()) {
+        if (members == null || members.isEmpty()) {
             return;
         }
 
@@ -814,9 +814,7 @@ public class ServiceImpl implements Service {
         }
         OrganizationEntity entity = optional.get();
         if (!StringUtils.isNullOrEmpty(entity.groupId)) {
-            if (!optional.isPresent()) {
-                return RestResult.error(ERROR_ALREADY_EXIST);
-            }
+            return RestResult.error(ERROR_ALREADY_EXIST);
         }
 
         if (StringUtils.isNullOrEmpty(entity.managerId)) {
@@ -919,9 +917,9 @@ public class ServiceImpl implements Service {
 
             //修正群组头像
             boolean portraitEquals = false;
-            if(StringUtils.isNullOrEmpty(entity.portraitUrl) && StringUtils.isNullOrEmpty(groupInfoIMResult.getResult().getPortrait())) {
+            if (StringUtils.isNullOrEmpty(entity.portraitUrl) && StringUtils.isNullOrEmpty(groupInfoIMResult.getResult().getPortrait())) {
                 portraitEquals = true;
-            } else if(!StringUtils.isNullOrEmpty(entity.portraitUrl)) {
+            } else if (!StringUtils.isNullOrEmpty(entity.portraitUrl)) {
                 portraitEquals = entity.portraitUrl.equals(groupInfoIMResult.getResult().getPortrait());
             }
 
@@ -1071,10 +1069,10 @@ public class ServiceImpl implements Service {
             } else {
                 //用户已经存在,同步用户信息
                 UserAdmin.updateUserInfo(inputOutputUserInfo, ProtoConstants.UpdateUserInfoMask.Update_User_DisplayName
-                        | ProtoConstants.UpdateUserInfoMask.Update_User_Gender
-                        | ProtoConstants.UpdateUserInfoMask.Update_User_Portrait
-                        | ProtoConstants.UpdateUserInfoMask.Update_User_Mobile
-                        | ProtoConstants.UpdateUserInfoMask.Update_User_Email);
+                    | ProtoConstants.UpdateUserInfoMask.Update_User_Gender
+                    | ProtoConstants.UpdateUserInfoMask.Update_User_Portrait
+                    | ProtoConstants.UpdateUserInfoMask.Update_User_Mobile
+                    | ProtoConstants.UpdateUserInfoMask.Update_User_Email);
             }
         } catch (Exception e) {
             e.printStackTrace();

+ 3 - 0
organization-web/src/api/api.js

@@ -17,6 +17,9 @@ export default {
     async createEmployee(employee) {
         return axios.post('/employee/create', employee);
     },
+    async queryEmployee(employeeId) {
+        return axios.post('/employee/query', {employeeId});
+    },
     async deleteEmployee(employeeId, destroyIMUser = true) {
         return axios.post('/employee/delete', {employeeId, destroyIMUser});
     },

+ 0 - 59
organization-web/src/components/common/AppCard.vue

@@ -1,59 +0,0 @@
-<template>
-    <div class="app-card">
-        <el-avatar shape="square" :size="60" style="margin: 0 10px" :src="app.portraitUrl">
-        </el-avatar>
-        <div>
-            <p class="title">{{ app.name }}</p>
-            <p class="desc">{{ app.description }}</p>
-        </div>
-    </div>
-</template>
-
-<script>
-export default {
-    name: "AppCard",
-    props: {
-        app: {
-            type: Object,
-            required: true,
-        }
-    },
-    methods: {}
-}
-</script>
-
-<style lang="css" scoped>
-.app-card {
-    display: flex;
-    flex-direction: row;
-    align-items: center;
-    width: 250px;
-    height: 100px;
-    margin: 20px 10px;
-}
-
-.app-card:hover {
-    background: #EEF5FE;
-}
-
-.app-card div {
-    flex: 1;
-    height: 60px;
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-}
-
-.app-card .title {
-    font-size: 18px;
-}
-
-.app-card .desc {
-    font-size: 14px;
-}
-
->>>.el-avatar > img {
-    width: 100%;
-}
-
-</style>

+ 0 - 114
organization-web/src/components/page/Index.vue

@@ -1,114 +0,0 @@
-<template>
-    <el-main class="hello">
-        <h2>应用</h2>
-        <div>
-            <el-row v-if="apps && apps.length > 0" :gutter="20">
-                <el-col :span="6" v-for="(app, index) in apps" :key="index">
-                    <AppCard :app="app" @click.native="showAppInfo(app)"/>
-                </el-col>
-            </el-row>
-            <el-empty v-else description="暂无应用" image="">
-                <el-button @click="createApp(0)" type="primary">创建应用</el-button>
-            </el-empty>
-        </div>
-        <div>
-            <h2>频道</h2>
-            <el-row v-if="channels && channels.length > 0" :gutter="20">
-                <el-col :span="6" v-for="(app, index) in channels" :key="index">
-                    <AppCard :app="app" @click.native="showAppInfo(app)"/>
-                </el-col>
-            </el-row>
-            <el-empty v-else description="暂无频道">
-                <el-button @click="createApp(1)" type="primary">创建频道</el-button>
-            </el-empty>
-        </div>
-        <div>
-            <h2>机器人</h2>
-            <el-row v-if="robots && robots.length > 0" :gutter="20">
-                <el-col :span="6" v-for="(app, index) in robots" :key="index">
-                    <AppCard :app="app" @click.native="showAppInfo(app)"/>
-                </el-col>
-            </el-row>
-            <el-empty v-else description="暂无机器人">
-                <el-button @click="createApp(2)" type="primary">创建机器人</el-button>
-            </el-empty>
-        </div>
-        <el-dialog title="应用信息" :visible.sync="appInfoDialogVisible">
-            <el-form :model="appInfo">
-                <el-form-item label="targetId" :label-width="formLabelWidth">
-                    <p>{{ appInfo.targetId }}</p>
-                </el-form-item>
-                <el-form-item label="secret" :label-width="formLabelWidth">
-                    <p>{{ appInfo.secret }}</p>
-                </el-form-item>
-                <el-form-item label="应用图标地址" :label-width="formLabelWidth">
-                    <el-input v-model="appInfo.portraitUrl" disabled autocomplete="off" placeholder="https://"></el-input>
-                </el-form-item>
-                <el-form-item label="应用名称" :label-width="formLabelWidth">
-                    <el-input v-model="appInfo.name" disabled autocomplete="off" placeholder="测试应用"></el-input>
-                </el-form-item>
-                <el-form-item label="应用描述" :label-width="formLabelWidth">
-                    <el-input v-model="appInfo.description" disabled autocomplete="off" placeholder="应用的一句话描述"></el-input>
-                </el-form-item>
-                <el-form-item label="移动端地址" :label-width="formLabelWidth">
-                    <el-input v-model="appInfo.mobileUrl" disabled autocomplete="off" placeholder="https://wildfirechat.cn"></el-input>
-                </el-form-item>
-                <el-form-item label="桌面端地址" :label-width="formLabelWidth">
-                    <el-input v-model="appInfo.desktopUrl" disabled autocomplete="off" placeholder="https://wildfirechat.cn"></el-input>
-                </el-form-item>
-                <el-form-item label="回调/服务端地址" :label-width="formLabelWidth">
-                    <el-input v-model="appInfo.serverUrl" disabled autocomplete="off" placeholder="https://wildfirechat.cn"></el-input>
-                </el-form-item>
-                <el-checkbox label="是否是全局应用" v-model="appInfo.global" disabled></el-checkbox>
-            </el-form>
-            <div slot="footer" class="dialog-footer">
-                <el-button type="primary" @click="appInfoDialogVisible = false">确 定</el-button>
-            </div>
-        </el-dialog>
-    </el-main>
-</template>
-
-<script>
-import AppCard from "@/components/common/AppCard";
-import {mapState} from "vuex";
-import AppInfo from "@/model/appInfo";
-
-export default {
-    name: 'Index',
-    components: {AppCard},
-    data() {
-        return {
-            appInfoDialogVisible: false,
-            appInfo: new AppInfo(),
-            formLabelWidth: '120px'
-        }
-    },
-    computed: mapState({
-        apps: state => state.app.apps,
-        channels: state => state.app.channels,
-        robots: state => state.app.robots,
-    }),
-    methods: {
-        showAppInfo(app) {
-            this.appInfo = app;
-            this.appInfoDialogVisible = true;
-        },
-
-        createApp(type = 0) {
-            let paths = ['/dev/app', '/dev/channel', '/dev/robot'];
-            this.$router.replace(paths[type]);
-        }
-    }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped>
-h1, h2 {
-    font-weight: normal;
-}
-
->>>.el-empty__image{
-    display: none;
-}
-</style>

+ 4 - 0
organization-web/src/components/page/contact/dialog/CreateDepartment.vue → organization-web/src/components/page/organization/Department.vue

@@ -88,6 +88,10 @@ export default {
                 resolve(data.children ? data.children : data);
             }
         },
+
+        handleClickEmployee(){
+
+        }
     }
 }
 </script>

+ 5 - 5
organization-web/src/components/page/contact/DepartmentAndMember.vue → organization-web/src/components/page/organization/DepartmentAndMember.vue

@@ -7,20 +7,20 @@
             </el-menu>
         </el-header>
         <el-main>
-            <user v-show="activeIndex === '1'"/>
-            <create-department v-show="activeIndex === '2'"/>
+            <member v-show="activeIndex === '1'"/>
+            <department v-show="activeIndex === '2'"/>
         </el-main>
     </el-container>
 
 </template>
 
 <script>
-import User from "@/components/page/contact/Member";
-import CreateDepartment from "@/components/page/contact/dialog/CreateDepartment";
+import Member from "@/components/page/organization/Member";
+import Department from "@/components/page/organization/Department.vue";
 
 export default {
     name: "departmentAndUser",
-    components: {CreateDepartment, User},
+    components: {Department, Member},
     data() {
         return {
             activeIndex: '1',

+ 0 - 0
organization-web/src/components/page/contact/DepartmentInfo.vue → organization-web/src/components/page/organization/DepartmentInfo.vue


+ 0 - 0
organization-web/src/components/page/contact/ImportMember.vue → organization-web/src/components/page/organization/ImportMember.vue


+ 47 - 13
organization-web/src/components/page/contact/Member.vue → organization-web/src/components/page/organization/Member.vue

@@ -18,6 +18,7 @@
                             <el-icon class="el-icon-more"/>
                         </span>
                         <el-dropdown-menu slot="dropdown">
+                            <el-dropdown-item v-if="!node.data.groupId" :command="{c:'create-org-group', node: node, depart:node.data}">创建组织官方群</el-dropdown-item>
                             <el-dropdown-item :command="{c:'edit', node: node, depart:node.data}">编辑部门</el-dropdown-item>
                             <el-dropdown-item :command="{c:'add-sub', node: node, depart:node.data}">添加子部门</el-dropdown-item>
                             <el-dropdown-item style="color: red" :command="{c:'remove', node: node, depart:node.data}">删除部门</el-dropdown-item>
@@ -86,6 +87,20 @@
                 :on-delete-employee="onDeleteEmployee"/>
         </el-drawer>
 
+        <el-dialog :visible.sync="showUpdateDepartmentDialog" :before-close="() => this.showUpdateDepartmentDialog= false">
+            <UpdateDepartment
+                :managers="checkedMembers"
+                :current-department="targetDepartment"
+                :parent-department="targetDepartment"
+                :on-update-department="onUpdateDepartment"
+                :on-choose-member="() => {this.checkedMembers = []; this.showChooseMemberDialog = true}"
+                :on-uncheck-member="onUncheckMember"
+            />
+            <el-dialog ref="dialog" :visible.sync="showChooseMemberDialog" append-to-body @hook:mounted="$refs.dialog.rendered = true">>
+                <ChooseMember :initial-checked-members="initialCheckedMembers" :max-choose-count="1" :on-cancel="()=> this.showChooseMemberDialog = false" :on-confirm="onCheckMember"/>
+            </el-dialog>
+        </el-dialog>
+
         <el-dialog :visible.sync="showAddSubDepartmentDialog" :before-close="() => this.showAddSubDepartmentDialog = false">
             <AddSubDepartment
                 :managers="checkedMembers"
@@ -118,15 +133,18 @@
 <script>
 
 import {mapState} from "vuex";
-import AddSubDepartment from "@/components/page/contact/dialog/AddSubDepartment";
-import AddDepartmentMember from "@/components/page/contact/dialog/AddDepartmentMember";
-import ChooseDepartment from "@/components/page/contact/dialog/ChooseDepartment";
-import ChooseMember from "@/components/page/contact/dialog/ChooseMember";
-import DeleteEmployee from "@/components/page/contact/drawer/DeleteEmployee";
+import AddSubDepartment from "@/components/page/organization/dialog/AddSubDepartment";
+import AddDepartmentMember from "@/components/page/organization/dialog/AddDepartmentMember";
+import ChooseDepartment from "@/components/page/organization/dialog/ChooseDepartment";
+import ChooseMember from "@/components/page/organization/dialog/ChooseMember";
+import DeleteEmployee from "@/components/page/organization/drawer/DeleteEmployee";
+import UpdateDepartment from "@/components/page/organization/dialog/UpdateDepartment.vue";
+import fa from "element-ui/src/locale/lang/fa";
+import api from "@/api/api";
 
 export default {
-    name: "user",
-    components: {DeleteEmployee, AddDepartmentMember, AddSubDepartment, ChooseDepartment, ChooseMember},
+    name: "Member",
+    components: {UpdateDepartment, DeleteEmployee, AddDepartmentMember, AddSubDepartment, ChooseDepartment, ChooseMember},
     data() {
         return {
             defaultProps: {
@@ -141,12 +159,14 @@ export default {
 
             showDeleteEmployeeDrawer: false,
 
-            // 添加子部门
+            showUpdateDepartmentDialog: false,
+
             showAddSubDepartmentDialog: false,
+            showAddDepartmentMemberDialog: false,
+
             targetParentDepartment: null,
             targetParentNode: null,
-
-            showAddDepartmentMemberDialog: false,
+            targetNode: null,
             targetDepartment: null,
 
             showChooseDepartmentDialog: false,
@@ -228,22 +248,24 @@ export default {
             console.log('click employee', data)
             this.showDeleteEmployeeDrawer = true;
             this.currentEmployee = data;
-            // this.$router.push('/contact/departmentanduser/department')
+            // this.$router.push('/organization/departmentanduser/department')
         },
         importMember() {
-            this.$router.push('/contact/departmentanduser/import-member')
+            this.$router.push('/organization/departmentanduser/import-member')
         },
 
         handleDepartmentCommand(command) {
             console.log('handleDepartmentCommand', command)
             switch (command.c) {
                 case "add-sub":
-                    console.log(command.depart);
                     this.showAddSubDepartmentDialog = true;
                     this.targetParentDepartment = command.depart;
                     this.targetParentNode = command.node;
                     break;
                 case "edit":
+                    this.showUpdateDepartmentDialog = true;
+                    this.targetDepartment = command.depart;
+                    this.targetNode = command.node;
                     break;
                 case "remove":
                     this.$store.dispatch('removeOrganization', {organization: command.depart, dismissGroup: true})
@@ -252,6 +274,11 @@ export default {
                             this.updateTreeNode(parentNode);
                         });
                     break;
+                case 'create-org-group':
+                    api.createOrganizationGroup(command.depart.id, '');
+                    break;
+                default:
+                    break;
             }
         },
         onCheckDepartment(departments) {
@@ -269,6 +296,13 @@ export default {
             this.checkedDepartments = this.checkedDepartments.filter(d => d.id !== department.id);
         },
 
+        onUpdateDepartment(success) {
+            if (success) {
+                this.updateTreeNode(this.targetNode);
+            }
+            this.showUpdateDepartmentDialog = false;
+        },
+
         onAddDepartment(success) {
             if (success) {
                 this.updateTreeNode(this.targetParentNode);

+ 0 - 0
organization-web/src/components/page/contact/MemberInfo.vue → organization-web/src/components/page/organization/MemberInfo.vue


+ 0 - 0
organization-web/src/components/page/contact/TransferMember.vue → organization-web/src/components/page/organization/TransferMember.vue


+ 3 - 3
organization-web/src/components/page/contact/dialog/AddDepartmentMember.vue → organization-web/src/components/page/organization/dialog/AddDepartmentMember.vue

@@ -113,15 +113,15 @@ export default {
         },
         onConfirm() {
             this.checkedDepartments.forEach(department => {
-                this.$store.dispatch('createMember', {
+                this.$store.dispatch('createEmployee', {
                     employee: this.employee,
                     targetOrg: department,
                 })
                     .then(res => {
-                        console.log('create member success', res)
+                        console.log('create employee success', res)
                     })
                     .catch(err => {
-                        console.log('create member error', err)
+                        console.log('create employee error', err)
                     })
             })
             this.onCancel();

+ 0 - 0
organization-web/src/components/page/contact/dialog/AddSubDepartment.vue → organization-web/src/components/page/organization/dialog/AddSubDepartment.vue


+ 0 - 0
organization-web/src/components/page/contact/dialog/ChooseDepartment.vue → organization-web/src/components/page/organization/dialog/ChooseDepartment.vue


+ 0 - 0
organization-web/src/components/page/contact/dialog/ChooseMember.vue → organization-web/src/components/page/organization/dialog/ChooseMember.vue


+ 151 - 0
organization-web/src/components/page/organization/dialog/UpdateDepartment.vue

@@ -0,0 +1,151 @@
+<template>
+    <div>
+        <p class="title">更新部门</p>
+        <el-form
+            label-position="right"
+            :model="updatedOrganization"
+            size="medium"
+            class="demo-form-inline">
+            <el-form-item label="部门名称">
+                <el-input v-model.trim="updatedOrganization.name" placeholder="部门名称"></el-input>
+            </el-form-item>
+            <el-form-item label="上级部门">
+                <el-input disabled :value="parentDepartment.name">
+                </el-input>
+            </el-form-item>
+            <el-form-item label="部门负责人">
+                <el-input disabled>
+                    <div v-if="managers && managers.length > 0" slot="prepend">
+                        <el-tag
+                            v-for="(member, index) in managers"
+                            :key="index"
+                            closable
+                            @close="handleCloseTag(member)"
+                            type="info">
+                            {{ member.name }}
+                        </el-tag>
+                    </div>
+                    <el-button slot="append" type="text" icon="el-icon-edit" @click="onChooseMember"></el-button>
+                </el-input>
+            </el-form-item>
+            <el-form-item v-if="!currentDepartment.groupId" label="是否创建部门群">
+                <el-checkbox v-model="createOrganizationGroup"></el-checkbox>
+            </el-form-item>
+        </el-form>
+        <div class="action-container">
+            <el-button @click="onUpdateDepartment(false)">取消</el-button>
+            <el-button type="primary" :disabled="!confirmButtonEnable" @click="onConfirm">确定</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+
+import api from "@/api/api";
+import fa from "element-ui/src/locale/lang/fa";
+
+export default {
+    name: "UpdateDepartment",
+    props: {
+        currentDepartment: {
+            type: Object,
+            required: true,
+        },
+        parentDepartment: {
+            type: Object,
+            required: true,
+        },
+        managers: {
+            type: Array,
+            required: true,
+        },
+        onUpdateDepartment: {
+            type: Function,
+            required: true,
+        },
+        onChooseMember: {
+            type: Function,
+            required: true,
+        },
+        onUncheckMember: {
+            type: Function,
+            required: true,
+        }
+    },
+    data() {
+        return {
+            updatedOrganization: {
+                name: this.currentDepartment.name,
+            },
+            createOrganizationGroup: !this.currentDepartment.groupId,
+        }
+    },
+    computed: {
+        fa() {
+            return fa
+        },
+        confirmButtonEnable() {
+            return this.updatedOrganization.name && this.managers.length === 1
+        },
+    },
+    async mounted() {
+    },
+
+    methods: {
+        handleCloseTag(tag) {
+            this.onUncheckMember(tag);
+        },
+        onConfirm() {
+            this.updatedOrganization.managerId = this.managers[0].employeeId;
+            this.currentDepartment.name = this.updatedOrganization.name;
+            this.currentDepartment.managerId = this.managers[0].employeeId;
+            this.$store.dispatch('updateOrganization', {
+                organization: this.currentDepartment
+            })
+                .then(res => {
+                    console.log('create organization success', res)
+                    this.onUpdateDepartment(true);
+                })
+                .catch(err => {
+                    console.log('create organization error', err)
+                    this.onUpdateDepartment(false);
+                })
+            if (this.createOrganizationGroup) {
+                api.createOrganizationGroup(this.currentDepartment.id, '')
+            }
+        },
+    },
+
+    watch: {
+        organization: {
+            async handler() {
+                let employee = await api.queryEmployee(this.currentDepartment.managerId)
+                this.managers.push(employee);
+            },
+            immediate: true,
+        }
+    }
+}
+</script>
+
+<style scoped>
+
+.title {
+    position: absolute;
+    top: 20px;
+    left: 20px;
+    font-size: 16px;
+    color: #1f2329;
+}
+
+/*>>> .el-form-item__content {*/
+/*    width: 300px;*/
+/*}*/
+
+.action-container {
+    display: flex;
+    justify-content: flex-end;
+    margin-right: 10px;
+}
+
+</style>

+ 0 - 0
organization-web/src/components/page/contact/drawer/DeleteEmployee.vue → organization-web/src/components/page/organization/drawer/DeleteEmployee.vue


+ 0 - 224
organization-web/src/components/page/robot/robot.vue

@@ -1,224 +0,0 @@
-<template>
-    <div style="height: 100%">
-        <el-main>
-            <el-card>
-                <h2>机器人</h2>
-                <div style="display: flex; flex-direction: row; justify-content: space-between; align-items: center">
-                    <p>对应机器人服务,开发文档请看
-                        <el-link href="https://docs.wildfirechat.cn/open" style="flex: 1" target="_blank" type="primary">开发文档</el-link>
-                    </p>
-                    <el-button type="primary" @click="createAppDialogVisible = true">创建机器人</el-button>
-                </div>
-                <el-row :gutter="20" v-if="apps && apps.length > 0">
-                    <el-col :span="6" v-for="(app, index) in apps" :key="index" @click.native="showAppInfo(app)">
-                        <AppCard :app="app"/>
-                    </el-col>
-                </el-row>
-                <el-empty v-else description="暂无机器人" image=""></el-empty>
-            </el-card>
-            <el-dialog title="创建机器人" :visible.sync="createAppDialogVisible">
-                <el-form :model="createAppInfo" :rules="rules" ref="createAppForm">
-                    <el-form-item label="机器人图标地址" :label-width="formLabelWidth" prop="portraitUrl">
-                        <el-input v-model.trim="createAppInfo.portraitUrl" autocomplete="off" disabled placeholder="机器人图标地址"></el-input>
-                        <el-upload
-                            class="upload-demo"
-                            :action="uploadMediaUrl"
-                            :with-credentials="true"
-                            :on-success="onPortraitUploaded"
-                            :before-upload="beforePortraitUpload"
-                            :show-file-list="false">
-                            <el-button size="small" type="primary" style="margin-top: 8px">点击上传</el-button>
-                            <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
-                        </el-upload>
-                    </el-form-item>
-                    <el-form-item label="机器人名称" :label-width="formLabelWidth" prop="name">
-                        <el-input v-model.trim="createAppInfo.name" autocomplete="off" placeholder="机器人名称"></el-input>
-                    </el-form-item>
-                    <el-form-item label="机器人描述" :label-width="formLabelWidth" prop="description">
-                        <el-input v-model.trim="createAppInfo.description" autocomplete="off" placeholder="机器人的一句话描述"></el-input>
-                    </el-form-item>
-                    <el-form-item label="回调/服务端地址" :label-width="formLabelWidth" prop="serverUrl">
-                        <el-input v-model.trim="createAppInfo.serverUrl" autocomplete="off" placeholder="https://wildfirechat.cn"></el-input>
-                    </el-form-item>
-                </el-form>
-                <div slot="footer" class="dialog-footer">
-                    <el-button @click="createAppDialogVisible = false">取 消</el-button>
-                    <el-button type="primary" @click="submitForm('createAppForm')">确 定</el-button>
-                </div>
-            </el-dialog>
-
-            <el-dialog title="修改机器人" :visible.sync="modifyAppDialogVisible">
-                <el-form :model="modifyAppInfo" :rules="rules" ref="modifyAppForm">
-                    <el-form-item label="targetId" :label-width="formLabelWidth">
-                        <p>{{ modifyAppInfo.targetId }}</p>
-                    </el-form-item>
-                    <el-form-item label="secret" :label-width="formLabelWidth">
-                        <p>{{ modifyAppInfo.secret }}</p>
-                    </el-form-item>
-                    <el-form-item label="机器人图标地址" :label-width="formLabelWidth" prop="portraitUrl">
-                        <el-input v-model.trim="modifyAppInfo.portraitUrl" autocomplete="off" disabled placeholder="机器人图标地址"></el-input>
-                        <el-upload
-                            class="upload-demo"
-                            :action="uploadMediaUrl"
-                            :with-credentials="true"
-                            :on-success="onPortraitUpdated"
-                            :before-upload="beforePortraitUpload"
-                            :show-file-list="false">
-                            <el-button size="small" type="primary" style="margin-top: 8px">点击上传</el-button>
-                            <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
-                        </el-upload>
-                    </el-form-item>
-                    <el-form-item label="机器人名称" :label-width="formLabelWidth" prop="name">
-                        <el-input v-model.trim="modifyAppInfo.name" autocomplete="off" placeholder="测试机器人"></el-input>
-                    </el-form-item>
-                    <el-form-item label="机器人描述" :label-width="formLabelWidth" prop="description">
-                        <el-input v-model.trim="modifyAppInfo.description" autocomplete="off" placeholder="机器人的一句话描述"></el-input>
-                    </el-form-item>
-                    <el-form-item label="回调/服务端地址" :label-width="formLabelWidth" prop="serverUrl">
-                        <el-input v-model.trim="modifyAppInfo.serverUrl" autocomplete="off" placeholder="https://wildfirechat.cn"></el-input>
-                    </el-form-item>
-                </el-form>
-                <div slot="footer" class="dialog-footer">
-                    <el-button @click="modifyAppDialogVisible = false">取 消</el-button>
-                    <el-button type="danger" @click="deleteApp">删 除</el-button>
-                    <el-button type="primary" @click="updateApp('modifyAppForm')">修 改</el-button>
-                </div>
-            </el-dialog>
-        </el-main>
-    </div>
-</template>
-
-<script>
-import {mapState} from "vuex";
-import AppCard from "@/components/common/AppCard";
-import AppInfo from "@/model/appInfo";
-
-export default {
-    name: "Robot",
-    data() {
-        return {
-            currentApp: null,
-            createAppDialogVisible: false,
-            modifyAppDialogVisible: false,
-            createAppInfo: new AppInfo(2),
-            modifyAppInfo: new AppInfo(2),
-            formLabelWidth: '140px',
-            uploadMediaUrl: '/api/application/media/upload/',
-            // 本地调试
-            // uploadMediaUrl: 'http://localhost:8880/api/application/media/upload/',
-
-            rules: {
-                portraitUrl: [
-                    {required: true, message: '请上传头像', trigger: 'blur'},
-                ],
-                name: [
-                    {required: true, message: '请输入机器人名称', trigger: 'blur'},
-                    {min: 1, max: 10, message: '长度在 1 到 10 个字符', trigger: 'blur'}
-                ],
-                description: [
-                    {required: true, message: '请输入机器人描述', trigger: 'blur'},
-                    {min: 1, max: 20, message: '长度在 1 到 20 个字符', trigger: 'blur'}
-                ],
-                serverUrl: [
-                    {required: false, message: '请输入回调地址', trigger: 'blur'},
-                ],
-            }
-        }
-    },
-    methods: {
-        submitForm(formName) {
-            console.log('submitForm', formName)
-            this.$refs[formName].validate((valid) => {
-                if (valid) {
-                    this.createAppDialogVisible = false;
-                    this.$store.dispatch('createApp', this.createAppInfo);
-                    this.createAppInfo = new AppInfo(2);
-                } else {
-                    console.log('error submit!!');
-                    return false;
-                }
-            });
-        },
-        showAppInfo(app) {
-            this.modifyAppInfo = app;
-            this.modifyAppDialogVisible = true;
-        },
-        updateApp(formName) {
-            this.$refs[formName].validate((valid) => {
-                if (valid) {
-                    this.modifyAppDialogVisible = false;
-                    this.$store.dispatch('updateApp', this.modifyAppInfo);
-                    this.modifyAppInfo = new AppInfo(2);
-                } else {
-                    console.log('error submit!!');
-                    return false;
-                }
-            });
-
-        },
-        deleteApp() {
-            this.modifyAppDialogVisible = false;
-            this.$store.dispatch("deleteApp", this.modifyAppInfo.targetId)
-        },
-
-        onPortraitUploaded(res, file) {
-            if (res.code === 0) {
-                this.createAppInfo.portraitUrl = res.result.url;
-            } else {
-                this.$message.error('头像上传失败 ' + res);
-            }
-            console.log('res, file', res, file)
-        },
-
-        onPortraitUpdated(res, file) {
-            if (res.code === 0) {
-                this.modifyAppInfo.portraitUrl = res.result.url;
-            } else {
-                this.$message.error('头像上传失败 ' + res);
-            }
-            console.log('res, file', res, file)
-        },
-        beforePortraitUpload(file) {
-            const isJPG = file.type === 'image/jpeg';
-            const isPNG = file.type === 'image/png';
-            const isLt2M = file.size / 1024 / 1024 < 2;
-
-            if (!isJPG && !isPNG) {
-                this.$message.error('上传头像图片只能是 JPG/PNG 格式!');
-            }
-            if (!isLt2M) {
-                this.$message.error('上传头像图片大小不能超过 2MB!');
-            }
-            return (isJPG || isPNG) && isLt2M;
-        }
-    },
-    computed: mapState({
-        apps: state => state.app.robots,
-    }),
-    components: {
-        AppCard,
-    }
-
-}
-</script>
-
-<style lang="css" scoped>
-
-.create-button-container {
-    display: flex;
-    width: 250px;
-    height: 100px;
-    margin: 20px 10px;
-    justify-content: center;
-    align-items: center;
-}
-
-.create-button-container .button {
-    padding: 20px 30px;
-}
-
->>> .el-empty__image {
-    display: none;
-}
-
-</style>

+ 7 - 7
organization-web/src/router/index.js

@@ -25,24 +25,24 @@ export default new Router({
                 // },
                 {
                     path: '/index',
-                    component: resolve => require(['../components/page/contact/DepartmentAndMember.vue'], resolve),
+                    component: resolve => require(['../components/page/organization/DepartmentAndMember.vue'], resolve),
                     meta: {title: '成员与部门'}
                 },
                 {
-                    path: '/contact/departmentanduser',
-                    component: resolve => require(['../components/page/contact/DepartmentAndMember.vue'], resolve),
+                    path: '/organization/departmentanduser',
+                    component: resolve => require(['../components/page/organization/DepartmentAndMember.vue'], resolve),
                     meta: {title: '成员与部门'},
                     // children: [
                     //     {
-                    //         path: '/contact/departmentanduser/import-member',
-                    //         component: resolve => require(['../components/page/contact/ImportMember.vue'], resolve),
+                    //         path: '/organization/departmentanduser/import-member',
+                    //         component: resolve => require(['../components/page/organization/ImportMember.vue'], resolve),
                     //         meta: {title: '批量导入成员'}
                     //     },
                     // ]
                 },
                 {
-                    path: '/contact/departmentanduser/import-member',
-                    component: resolve => require(['../components/page/contact/ImportMember.vue'], resolve),
+                    path: '/organization/departmentanduser/import-member',
+                    component: resolve => require(['../components/page/organization/ImportMember.vue'], resolve),
                     meta: {title: '批量导入成员'}
                 },
                 {

+ 10 - 1
organization-web/src/store/components/org_store.js

@@ -47,7 +47,7 @@ export default {
             console.log('queryOrganizationWithChildren', org.id, state)
         },
 
-        async createMember({dispatch}, {employee, targetOrg}) {
+        async createEmployee({dispatch}, {employee, targetOrg}) {
             employee.organizationId = targetOrg.id;
             await Api.createEmployee(employee);
             dispatch('queryOrganizationWithChildren', targetOrg)
@@ -62,6 +62,10 @@ export default {
             }
         },
 
+        async updateOrganization({dispatch}, organization) {
+            await Api.updateOrganization(organization);
+        },
+
         async removeOrganization({state}, {organization, dismissGroup}) {
             await Api.deleteOrganization(organization);
             // let parent = state._findOrganization(state.rootOrganizations[0], organization.parentId)
@@ -75,6 +79,11 @@ export default {
             }
         },
 
+        async queryEmployee({state}, {employeeId}) {
+            await Api.queryEmployee(employeeId);
+            // TODO 更新当前部门?
+        },
+
         async deleteEmployee({state}, {employeeId, destroyIMUser}) {
             await Api.deleteEmployee(employeeId, destroyIMUser);
             // TODO 更新当前部门?