-
{gettext('Content Scan Records')}
+
+
+
+
+
+
{gettext('Content Scan Records')}
+
+
+
+
+
);
}
}
diff --git a/frontend/src/pages/sys-admin/main-panel.js b/frontend/src/pages/sys-admin/main-panel.js
index a83b54728b..2c579ea438 100644
--- a/frontend/src/pages/sys-admin/main-panel.js
+++ b/frontend/src/pages/sys-admin/main-panel.js
@@ -1,7 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
-import Account from '../../components/common/account';
-
const propTypes = {
children: PropTypes.array.isRequired,
@@ -12,14 +10,6 @@ class MainPanel extends Component {
render() {
return (
);
diff --git a/frontend/src/pages/sys-admin/side-panel.js b/frontend/src/pages/sys-admin/side-panel.js
index 4cc0746c31..f3ac2e2065 100644
--- a/frontend/src/pages/sys-admin/side-panel.js
+++ b/frontend/src/pages/sys-admin/side-panel.js
@@ -172,7 +172,7 @@ class SidePanel extends React.Component {
{isDefaultAdmin && enableWorkWeixinDepartments &&
-
+
{'企业微信集成'}
diff --git a/frontend/src/pages/sys-admin/work-weixin-departments.js b/frontend/src/pages/sys-admin/work-weixin-departments.js
index 6fa3d4678f..b313a96108 100644
--- a/frontend/src/pages/sys-admin/work-weixin-departments.js
+++ b/frontend/src/pages/sys-admin/work-weixin-departments.js
@@ -1,225 +1,12 @@
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import {seafileAPI} from '../../utils/seafile-api';
-import {gettext, siteRoot} from '../../utils/constants';
+import React, { Component, Fragment } from 'react';
+import { Button } from 'reactstrap';
+import _ from 'lodash';
+import { seafileAPI } from '../../utils/seafile-api';
+import { gettext, siteRoot } from '../../utils/constants';
import toaster from '../../components/toast';
-import Loading from '../../components/loading';
-import {Button, Table} from 'reactstrap';
-
-
-class WorkWeixinDepartmentMembersList extends Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- render() {
- const membersList = this.props.membersList.map((member, index) => {
- let avatar = member.avatar;
- if (member.avatar.length > 0) {
- // get smaller avatar
- avatar = member.avatar.substring(0, member.avatar.length - 1) + '100';
- } else {
- avatar = siteRoot + 'media/avatars/default.png';
- }
- const userCheckBox = member.email ? '' :
-
this.props.onUserChecked(member)}
- >;
- return (
-
- {userCheckBox} |
-  |
- {member.name} |
- {member.mobile} |
- {member.contact_email} |
- {member.email ? : ''} |
-
- );
- });
-
- const allUsersCheckBox = !this.props.canCheckUserIds.length ? '' :
-
this.props.onAllUsersChecked()}
- >;
-
- return (
-
-
- {this.props.isMembersListLoading &&
}
-
- {!this.props.isMembersListLoading &&
-
-
-
- {allUsersCheckBox} |
- |
- {'名称'} |
- {'手机号'} |
- {'邮箱'} |
- {'已添加'} |
-
-
-
- {membersList}
-
-
- }
- {!this.props.isMembersListLoading && this.props.membersList.length === 0 &&
-
-
{'无成员'}
-
- }
-
-
- );
- }
-}
-
-const WorkWeixinDepartmentMembersListPropTypes = {
- isMembersListLoading: PropTypes.bool.isRequired,
- membersList: PropTypes.array.isRequired,
- newUsersTempObj: PropTypes.object.isRequired,
- checkedDepartmentId: PropTypes.number.isRequired,
- onUserChecked: PropTypes.func.isRequired,
- onAllUsersChecked: PropTypes.func.isRequired,
- isCheckedAll: PropTypes.bool.isRequired,
- canCheckUserIds: PropTypes.array.isRequired,
-};
-
-WorkWeixinDepartmentMembersList.propTypes = WorkWeixinDepartmentMembersListPropTypes;
-
-
-class WorkWeixinDepartmentsTreeNode extends Component {
- constructor(props) {
- super(props);
- this.state = {
- isChildrenShow: false,
- };
- }
-
- toggleChildren = () => {
- this.setState({
- isChildrenShow: !this.state.isChildrenShow,
- });
- };
-
- renderTreeNodes = (departmentsTree) => {
- if (departmentsTree.length > 0) {
- return departmentsTree.map((department) => {
- return (
-
- );
- });
- }
- };
-
- componentDidMount() {
- if (this.props.index === 0) {
- this.toggleChildren();
- this.props.onChangeDepartment(this.props.department.id);
- }
- }
-
- render() {
- let toggleIconClass = '';
- if (this.props.department.children) {
- if (this.state.isChildrenShow) {
- toggleIconClass = 'folder-toggle-icon fa fa-caret-down';
- } else {
- toggleIconClass = 'folder-toggle-icon fa fa-caret-right';
- }
- }
- let departmentStyle = this.props.checkedDepartmentId === this.props.department.id ? {color: 'blue'} : {};
-
- return (
-
- {this.props.isChildrenShow &&
-
- this.toggleChildren()}>{' '}
- this.props.onChangeDepartment(this.props.department.id)}
- >{this.props.department.name}
-
- }
- {this.state.isChildrenShow &&
-
- {this.props.department.children && this.renderTreeNodes(this.props.department.children)}
-
- }
-
- );
- }
-}
-
-const WorkWeixinDepartmentsTreeNodePropTypes = {
- index: PropTypes.number,
- department: PropTypes.object.isRequired,
- isChildrenShow: PropTypes.bool.isRequired,
- onChangeDepartment: PropTypes.func.isRequired,
- checkedDepartmentId: PropTypes.number.isRequired,
-};
-
-WorkWeixinDepartmentsTreeNode.propTypes = WorkWeixinDepartmentsTreeNodePropTypes;
-
-
-class WorkWeixinDepartmentsTreePanel extends Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- render() {
- const departmentsTree = this.props.departmentsTree.map((department, index) => {
- return (
-
- );
- });
-
- return (
-
-
- {this.props.isTreeLoading &&
}
- {!this.props.isTreeLoading &&
-
- {this.props.departmentsTree.length > 0 && departmentsTree}
-
- }
-
-
- );
- }
-}
-
-const WorkWeixinDepartmentsTreePanelPropTypes = {
- isTreeLoading: PropTypes.bool.isRequired,
- departmentsTree: PropTypes.array.isRequired,
- onChangeDepartment: PropTypes.func.isRequired,
- checkedDepartmentId: PropTypes.number.isRequired,
-};
-
-WorkWeixinDepartmentsTreePanel.propTypes = WorkWeixinDepartmentsTreePanelPropTypes;
-
+import Account from '../../components/common/account';
+import { WorkWeixinDepartmentMembersList, WorkWeixinDepartmentsTreePanel } from './work-weixin';
+import '../../css/work-weixin-departments.css';
class WorkWeixinDepartments extends Component {
@@ -255,8 +42,7 @@ class WorkWeixinDepartments extends Component {
let rootIds = parentIds.concat(intersection).filter((v) => {
return parentIds.indexOf(v) === -1 || intersection.indexOf(v) === -1;
});
-
- let cloneData = JSON.parse(JSON.stringify(list));
+ let cloneData = _.cloneDeep(list);
return cloneData.filter(father => {
let branchArr = cloneData.filter(child => father.id === child.parentid);
branchArr.length > 0 ? father.children = branchArr : '';
@@ -272,16 +58,12 @@ class WorkWeixinDepartments extends Component {
departmentsTree: departmentsTree,
});
}).catch((error) => {
+ this.handleError(error);
this.setState({
isTreeLoading: false,
isMembersListLoading: false,
});
- if (error.response) {
- toaster.danger(error.response.data.error_msg || error.response.data.detail || gettext('Error'), {duration: 3});
- } else {
- toaster.danger(gettext('Please check the network.'), {duration: 3});
- }
- if (error.response.status === 403) {
+ if (error.response && error.response.status === 403) {
window.location = siteRoot + 'sys/useradmin/';
}
});
@@ -291,7 +73,7 @@ class WorkWeixinDepartments extends Component {
this.setState({
isMembersListLoading: true,
});
- seafileAPI.adminListWorkWeixinDepartmentMembers(department_id.toString(), {fetch_child: true}).then((res) => {
+ seafileAPI.adminListWorkWeixinDepartmentMembers(department_id, {fetch_child: true}).then((res) => {
let membersTempObj = this.state.membersTempObj;
membersTempObj[department_id] = res.data.userlist;
let canCheckUserIds = this.getCanCheckUserIds(res.data.userlist);
@@ -303,23 +85,16 @@ class WorkWeixinDepartments extends Component {
});
}).catch((error) => {
this.setState({isMembersListLoading: false});
- if (error.response) {
- toaster.danger(error.response.data.error_msg || error.response.data.detail || gettext('Error'), {duration: 3});
- } else {
- toaster.danger(gettext('Please check the network.'), {duration: 3});
- }
+ this.handleError(error);
});
};
getCanCheckUserIds = (membersList) => {
- let canCheckUserIds = [];
- for (let i = 0; i < membersList.length; i++) {
- let user = membersList[i];
- if (!user.email) {
- canCheckUserIds.push(user.userid);
- }
- }
- return canCheckUserIds;
+ let userIds = [];
+ membersList.forEach((member) => {
+ if (!member.email) userIds.push(member.userid);
+ });
+ return userIds;
};
onChangeDepartment = (department_id) => {
@@ -345,21 +120,15 @@ class WorkWeixinDepartments extends Component {
if (user.userid in newUsersTempObj) {
delete newUsersTempObj[user.userid];
if (this.state.isCheckedAll) {
- this.setState({
- isCheckedAll: false,
- });
+ this.setState({ isCheckedAll: false });
}
} else {
newUsersTempObj[user.userid] = user;
if (Object.keys(newUsersTempObj).length === this.state.canCheckUserIds.length) {
- this.setState({
- isCheckedAll: true,
- });
+ this.setState({ isCheckedAll: true });
}
}
- this.setState({
- newUsersTempObj: newUsersTempObj,
- });
+ this.setState({ newUsersTempObj: newUsersTempObj });
}
};
@@ -372,124 +141,139 @@ class WorkWeixinDepartments extends Component {
let newUsersTempList = this.state.membersList.filter(user => {
return this.state.canCheckUserIds.indexOf(user.userid) !== -1;
});
-
for (let i = 0; i < newUsersTempList.length; i++) {
newUsersTempObj[newUsersTempList[i].userid] = newUsersTempList[i];
}
- this.setState({
- newUsersTempObj: newUsersTempObj,
- });
+ this.setState({ newUsersTempObj: newUsersTempObj });
} else {
- this.setState({
- newUsersTempObj: {},
- });
+ this.setState({ newUsersTempObj: {} });
}
});
};
onSubmit = () => {
+ const { newUsersTempObj } = this.state;
+ if (JSON.stringify(newUsersTempObj) === '{}') return;
let userList = [];
- for (let i in this.state.newUsersTempObj) {
- userList.push(this.state.newUsersTempObj[i]);
+ for (let i in newUsersTempObj) {
+ userList.push(newUsersTempObj[i]);
}
- if (!userList.length) {
+ if (userList.length === 0) {
toaster.danger('未选择成员', {duration: 3});
- } else {
- seafileAPI.adminAddWorkWeixinUsersBatch(userList).then((res) => {
- this.setState({
- newUsersTempObj: {},
- isCheckedAll: false,
- });
- if (res.data.success) {
- let membersTempObj = this.state.membersTempObj;
- let membersList = this.state.membersList;
- let canCheckUserIds = this.state.canCheckUserIds;
- for (let i = 0; i < res.data.success.length; i++) {
- let userid = res.data.success[i].userid;
- let name = res.data.success[i].name;
- let email = res.data.success[i].email;
- toaster.success(name + ' 成功导入', {duration: 1});
- // refresh all temp
- if (canCheckUserIds.indexOf(userid) !== -1) {
- canCheckUserIds.splice(canCheckUserIds.indexOf(userid), 1);
- }
- for (let j = 0; j < membersList.length; j++) {
- if (membersList[j].userid === userid) {
- membersList[j].email = email;
- break;
- }
- }
- for (let departmentId in membersTempObj) {
- for (let k = 0; k < membersTempObj[departmentId].length; k++) {
- if (membersTempObj[departmentId][k].userid === userid) {
- membersTempObj[departmentId][k].email = email;
- break;
- }
- }
- }
- }
- this.setState({
- membersTempObj: membersTempObj,
- membersList: membersList,
- canCheckUserIds: canCheckUserIds,
- });
- }
- if (res.data.failed) {
- for (let i = 0; i < res.data.failed.length; i++) {
- let name = res.data.failed[i].name;
- let errorMsg = res.data.failed[i].error_msg;
- toaster.danger(name + ' ' + errorMsg, {duration: 3});
- }
- }
- }).catch((error) => {
- if (error.response) {
- toaster.danger(error.response.data.error_msg || error.response.data.detail || gettext('Error'), {duration: 3});
- } else {
- toaster.danger(gettext('Please check the network.'), {duration: 3});
- }
- });
+ return;
}
+ seafileAPI.adminAddWorkWeixinUsersBatch(userList).then((res) => {
+ this.setState({
+ newUsersTempObj: {},
+ isCheckedAll: false,
+ });
+ if (res.data.success) {
+ this.handleSubmitSuccess(res.data.success);
+ }
+ if (res.data.failed) {
+ const fails= res.data.failed;
+ for (let i = 0; i < fails.length; i++) {
+ toaster.danger(fails[i].name + ' ' + fails[i].error_msg, {duration: 3});
+ }
+ }
+ }).catch((error) => {
+ this.handleError(error);
+ });
};
+ handleSubmitSuccess = (success) => {
+ let { membersTempObj, membersList, canCheckUserIds } = this.state;
+ for (let i = 0; i < success.length; i++) {
+ let { userid, name, email } = success[i];
+ toaster.success(name + ' 成功导入', {duration: 1});
+ // refresh all temp
+ if (canCheckUserIds.indexOf(userid) !== -1) {
+ canCheckUserIds.splice(canCheckUserIds.indexOf(userid), 1);
+ }
+ for (let j = 0; j < membersList.length; j++) {
+ if (membersList[j].userid === userid) {
+ membersList[j].email = email;
+ break;
+ }
+ }
+ for (let departmentId in membersTempObj) {
+ for (let k = 0; k < membersTempObj[departmentId].length; k++) {
+ if (membersTempObj[departmentId][k].userid === userid) {
+ membersTempObj[departmentId][k].email = email;
+ break;
+ }
+ }
+ }
+ }
+ this.setState({
+ membersTempObj: membersTempObj,
+ membersList: membersList,
+ canCheckUserIds: canCheckUserIds,
+ });
+ }
+
+ handleError = (e) => {
+ if (e.response) {
+ toaster.danger(e.response.data.error_msg || e.response.data.detail || gettext('Error'), {duration: 3});
+ } else {
+ toaster.danger(gettext('Please check the network.'), {duration: 3});
+ }
+ }
+
componentDidMount() {
this.getWorkWeixinDepartmentsList();
}
- render() {
+ renderNav() {
+ const btnClass = 'btn btn-secondary operation-item ';
return (
-
-
-
-
{'企业微信集成'}
- {JSON.stringify(this.state.newUsersTempObj) !== '{}' &&
-
- }
-
-
+
+
+
+
+
+
+
);
}
+
+ render() {
+ return (
+
+ {this.renderNav()}
+
+
+ );
+ }
}
export default WorkWeixinDepartments;
-
diff --git a/frontend/src/pages/sys-admin/work-weixin/index.js b/frontend/src/pages/sys-admin/work-weixin/index.js
new file mode 100644
index 0000000000..e7fbbddf23
--- /dev/null
+++ b/frontend/src/pages/sys-admin/work-weixin/index.js
@@ -0,0 +1,5 @@
+import WorkWeixinDepartmentMembersList from './work-weixin-department-members-list';
+import WorkWeixinDepartmentsTreePanel from './work-weixin-departments-tree-panel';
+import WorkWeixinDepartmentsTreeNode from './work-weixin-departments-tree-node';
+
+export { WorkWeixinDepartmentMembersList, WorkWeixinDepartmentsTreePanel, WorkWeixinDepartmentsTreeNode };
\ No newline at end of file
diff --git a/frontend/src/pages/sys-admin/work-weixin/work-weixin-department-members-list.js b/frontend/src/pages/sys-admin/work-weixin/work-weixin-department-members-list.js
new file mode 100644
index 0000000000..8238892ffb
--- /dev/null
+++ b/frontend/src/pages/sys-admin/work-weixin/work-weixin-department-members-list.js
@@ -0,0 +1,84 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Table } from 'reactstrap';
+import { siteRoot } from '../../../utils/constants';
+import Loading from '../../../components/loading';
+
+const WorkWeixinDepartmentMembersListPropTypes = {
+ isMembersListLoading: PropTypes.bool.isRequired,
+ membersList: PropTypes.array.isRequired,
+ newUsersTempObj: PropTypes.object.isRequired,
+ checkedDepartmentId: PropTypes.number.isRequired,
+ onUserChecked: PropTypes.func.isRequired,
+ onAllUsersChecked: PropTypes.func.isRequired,
+ isCheckedAll: PropTypes.bool.isRequired,
+ canCheckUserIds: PropTypes.array.isRequired,
+};
+
+class WorkWeixinDepartmentMembersList extends Component {
+
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ const { newUsersTempObj, checkedDepartmentId, isMembersListLoading, canCheckUserIds } = this.props;
+ const membersList = this.props.membersList.map((member, index) => {
+ let avatar = member.avatar;
+ if (member.avatar.length > 0) {
+ avatar = member.avatar.substring(0, member.avatar.length - 1) + '100';// get smaller avatar
+ } else {
+ avatar = siteRoot + 'media/avatars/default.png';
+ }
+ return (
+
+
+ {!member.email &&
+ this.props.onUserChecked(member)}
+ checked={(member.userid in newUsersTempObj) ? 'checked' : ''}>}
+ |
+  |
+ {member.name} |
+ {member.mobile} |
+ {member.contact_email} |
+ {member.email && } |
+
+ );
+ });
+
+ return (
+
+ {isMembersListLoading &&
}
+ {!isMembersListLoading && this.props.membersList.length > 0 &&
+
+ }
+ {!isMembersListLoading && this.props.membersList.length === 0 &&
+
+

+
{'成员列表为空'}
+
+ }
+
+ );
+ }
+}
+
+WorkWeixinDepartmentMembersList.propTypes = WorkWeixinDepartmentMembersListPropTypes;
+
+export default WorkWeixinDepartmentMembersList;
diff --git a/frontend/src/pages/sys-admin/work-weixin/work-weixin-departments-tree-node.js b/frontend/src/pages/sys-admin/work-weixin/work-weixin-departments-tree-node.js
new file mode 100644
index 0000000000..a8495f415c
--- /dev/null
+++ b/frontend/src/pages/sys-admin/work-weixin/work-weixin-departments-tree-node.js
@@ -0,0 +1,81 @@
+import React, { Component, Fragment } from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+
+const WorkWeixinDepartmentsTreeNodePropTypes = {
+ index: PropTypes.number,
+ department: PropTypes.object.isRequired,
+ isChildrenShow: PropTypes.bool.isRequired,
+ onChangeDepartment: PropTypes.func.isRequired,
+ checkedDepartmentId: PropTypes.number.isRequired,
+};
+
+class WorkWeixinDepartmentsTreeNode extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isChildrenShow: false,
+ };
+ }
+
+ toggleChildren = () => {
+ this.setState({
+ isChildrenShow: !this.state.isChildrenShow,
+ });
+ };
+
+ componentDidMount() {
+ if (this.props.index === 0) {
+ this.toggleChildren();
+ this.props.onChangeDepartment(this.props.department.id);
+ }
+ }
+
+ renderTreeNodes = (departmentsTree) => {
+ if (departmentsTree.length > 0) {
+ return departmentsTree.map((department) => {
+ return (
+
+ );
+ });
+ }
+ };
+
+ render() {
+ const { isChildrenShow, department, checkedDepartmentId } = this.props;
+ let toggleClass = classNames({
+ 'folder-toggle-icon fa fa-caret-down': department.children && this.state.isChildrenShow,
+ 'folder-toggle-icon fa fa-caret-right': department.children && !this.state.isChildrenShow,
+ })
+ let nodeInnerClass = classNames({
+ 'tree-node-inner': true,
+ 'tree-node-hight-light': checkedDepartmentId === department.id
+ });
+ return (
+
+ {isChildrenShow &&
+
+ this.toggleChildren()}>{' '}
+ this.props.onChangeDepartment(department.id)}>{department.name}
+
+ }
+ {this.state.isChildrenShow &&
+
+ {department.children && this.renderTreeNodes(department.children)}
+
+ }
+
+ );
+ }
+}
+
+WorkWeixinDepartmentsTreeNode.propTypes = WorkWeixinDepartmentsTreeNodePropTypes;
+
+export default WorkWeixinDepartmentsTreeNode;
diff --git a/frontend/src/pages/sys-admin/work-weixin/work-weixin-departments-tree-panel.js b/frontend/src/pages/sys-admin/work-weixin/work-weixin-departments-tree-panel.js
new file mode 100644
index 0000000000..080d6e39a5
--- /dev/null
+++ b/frontend/src/pages/sys-admin/work-weixin/work-weixin-departments-tree-panel.js
@@ -0,0 +1,49 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import Loading from '../../../components/loading';
+import WorkWeixinDepartmentsTreeNode from './work-weixin-departments-tree-node';
+
+const WorkWeixinDepartmentsTreePanelPropTypes = {
+ isTreeLoading: PropTypes.bool.isRequired,
+ departmentsTree: PropTypes.array.isRequired,
+ onChangeDepartment: PropTypes.func.isRequired,
+ checkedDepartmentId: PropTypes.number.isRequired,
+};
+
+class WorkWeixinDepartmentsTreePanel extends Component {
+
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ const { departmentsTree } = this.props;
+ return (
+
+
+ {this.props.isTreeLoading ?
+
:
+
+ {departmentsTree.length > 0 && departmentsTree.map((department, index) => {
+ return (
+
+ );
+ })}
+
+ }
+
+
+ );
+ }
+}
+
+WorkWeixinDepartmentsTreePanel.propTypes = WorkWeixinDepartmentsTreePanelPropTypes;
+
+export default WorkWeixinDepartmentsTreePanel;
diff --git a/media/img/member-list-empty.png b/media/img/member-list-empty.png
new file mode 100644
index 0000000000..8731b889f9
Binary files /dev/null and b/media/img/member-list-empty.png differ