diff --git a/web-react/src/pages/system/org/index.jsx b/web-react/src/pages/system/org/index.jsx
index 34c8a4d..de26cad 100644
--- a/web-react/src/pages/system/org/index.jsx
+++ b/web-react/src/pages/system/org/index.jsx
@@ -20,6 +20,12 @@ const name = '机构'
export default class index extends Component {
+ state = {
+ codes: {
+ orgType: []
+ }
+ }
+
// 表格实例
table = React.createRef()
@@ -174,7 +180,7 @@ export default class index extends Component {
name = toCamelCase(name)
const codes = this.state.codes[name]
if (codes) {
- const c = codes.find((p) => p.code == code)
+ const c = codes.find((p) => p.code === code)
if (c) {
return c.value
}
diff --git a/web-react/src/pages/system/user/form.jsx b/web-react/src/pages/system/user/form.jsx
new file mode 100644
index 0000000..63b94d3
--- /dev/null
+++ b/web-react/src/pages/system/user/form.jsx
@@ -0,0 +1,227 @@
+import React, { Component } from 'react'
+import { Cascader, Form, Input, InputNumber, Select, Spin, TreeSelect } from 'antd'
+import { AntIcon } from 'components'
+import { cloneDeep } from 'lodash'
+import getDicData from 'util/dic'
+import { EMPTY_ID } from 'util/global'
+import { api } from 'common/api'
+
+const initialValues = {
+ sort: 100
+}
+
+export default class form extends Component {
+
+ state = {
+ // 加载状态
+ loading: true,
+
+ codes: {
+ orgType: []
+ },
+
+ options: {
+ orgData: [],
+ areaData: []
+ }
+ }
+
+ // 表单实例
+ form = React.createRef()
+
+ // 初始化数据
+ record = {}
+
+ /**
+ * mount后回调
+ */
+ componentDidMount() {
+ this.props.created && this.props.created(this)
+ }
+
+ /**
+ * 填充数据
+ * 可以在设置this.record之后对其作出数据结构调整
+ * [异步,必要]
+ * @param {*} params
+ */
+ async fillData(params) {
+
+ this.record = cloneDeep(params.record)
+ //#region 从后端转换成前段所需格式
+ const orgData = await this.loadOrgData()
+ const areaData = await this.loadAreaData()
+
+ const codes = await getDicData('org_type')
+ this.setState({
+ codes,
+ options: {
+ orgData,
+ areaData
+ }
+ })
+
+ const areaCode = [];
+ const findCode = (data, level) => {
+ level = level || 0;
+ for (let i = 0; i < data.length; i++) {
+ const item = data[i];
+ areaCode[level] = item.code;
+
+ if (item.code === params.record.areaCode) {
+ areaCode.length = level + 1;
+ return true;
+ }
+
+ if (item.children && item.children.length) {
+ const found = findCode(item.children, level + 1);
+ if (found) {
+ return true;
+ }
+ }
+ }
+ };
+
+ if (params.record && params.record.areaCode) {
+ findCode(areaData);
+ }
+
+ this.record = {
+ pid: params.orgId,
+ ...this.record,
+ areaCode
+ }
+ this.record.areaCode = areaCode
+ //#endregion
+
+ this.form.current.setFieldsValue(this.record)
+
+ this.setState({
+ loading: false
+ })
+ }
+
+ /**
+ * 获取数据
+ * 可以对postData进行数据结构调整
+ * [异步,必要]
+ * @returns
+ */
+ async getData() {
+ const form = this.form.current
+
+ const valid = await form.validateFields()
+ if (valid) {
+ const postData = form.getFieldsValue()
+ if (this.record) {
+ postData.id = this.record.id
+ }
+ //#region 从前段转换后端所需格式
+ postData.areaCode = postData.areaCode[postData.areaCode.length - 1]
+ //#endregion
+ return postData
+ }
+ }
+
+ //#region 自定义方法
+ async loadOrgData() {
+ const { data } = await api.getOrgTree()
+ return [{
+ id: EMPTY_ID,
+ parentId: undefined,
+ title: '顶级',
+ value: EMPTY_ID,
+ pid: undefined,
+ children: data,
+ }]
+ }
+
+ async loadAreaData() {
+ const { data } = await api.getAreaTree()
+ const clearChiildren = (data) => {
+ data.forEach((item) => {
+ if (item.children && item.children.length) {
+ clearChiildren(item.children);
+ } else {
+ delete item.children;
+ }
+ });
+ };
+ clearChiildren(data);
+ return data
+ }
+
+ onAreaCodeChange(selectedOptions) {
+ const data = selectedOptions[selectedOptions.length - 1]
+ this.form.current.setFieldsValue({
+ name: data.name,
+ code: data.code
+ })
+ }
+ //#endregion
+
+ render() {
+ return (
+
+ )
+ }
+}
diff --git a/web-react/src/pages/system/user/index.jsx b/web-react/src/pages/system/user/index.jsx
new file mode 100644
index 0000000..e3e284e
--- /dev/null
+++ b/web-react/src/pages/system/user/index.jsx
@@ -0,0 +1,319 @@
+import React, { Component } from 'react'
+import { Button, Card, Descriptions, Form, Input, List, message as Message, Popconfirm, Select, Switch } from 'antd'
+import { AntIcon, Auth, Container, Image, ModalForm, QueryList, QueryTreeLayout } from 'components'
+import { api } from 'common/api'
+import { toCamelCase } from 'util/format'
+import { isEqual } from 'lodash'
+import getDicData from 'util/dic'
+import FormBody from './form'
+
+// 配置页面所需接口函数
+const apiAction = {
+ tree: api.getOrgTree,
+ page: api.getUserPage,
+ add: api.sysUserAdd,
+ edit: api.sysUserEdit,
+ delete: api.sysUserDelete,
+
+ changeStatus: api.sysUserChangeStatus,
+ resetPwd: api.sysUserResetPwd
+}
+
+// 用于弹窗标题
+const name = '用户'
+
+export default class index extends Component {
+
+ state = {
+ codes: {
+ sex: [],
+ commonStatus: []
+ }
+ }
+
+ // 表格实例
+ list = React.createRef()
+
+ // 新增窗口实例
+ addForm = React.createRef()
+ // 编辑窗口实例
+ editForm = React.createRef()
+
+ // 树选中节点
+ selectId = undefined
+
+ /**
+ * 阻止外部组件引发的渲染,提升性能
+ * 可自行添加渲染条件
+ * [必要]
+ * @param {*} props
+ * @param {*} state
+ * @returns
+ */
+ shouldComponentUpdate(props, state) {
+ return !isEqual(this.state, state)
+ }
+
+ /**
+ * 加载字典数据,之后开始加载表格数据
+ * 如果必须要加载字典数据,可直接对表格设置autoLoad=true
+ */
+ componentDidMount() {
+ this.list.current.onLoading()
+ getDicData('sex', 'common_status').then(res => {
+ this.setState({
+ codes: res
+ }, () => {
+ this.list.current.onLoadData()
+ })
+ })
+ }
+
+ /**
+ * 调用加载数据接口,可在调用前对query进行处理
+ * [异步,必要]
+ * @param {*} params
+ * @param {*} query
+ * @returns
+ */
+ loadData = async (params, query) => {
+
+ query = {
+ ...query,
+ sysEmpParam: {
+ orgId: this.selectId
+ }
+ }
+
+ const { data } = await apiAction.page({
+ ...params,
+ ...query,
+ })
+ return data
+ }
+
+ /**
+ * 调用树结构数据接口
+ * [异步,必要]
+ * @returns
+ */
+ loadTreeData = async () => {
+ const { data } = await apiAction.tree()
+ return data
+ }
+
+ /**
+ * 树节点选中事件
+ * [必要]
+ * @param {*} id
+ */
+ onSelectTree(id) {
+ this.selectId = id
+ this.list.current.onReloadData()
+ }
+
+ /**
+ * 绑定字典数据
+ * @param {*} code
+ * @param {*} name
+ * @returns
+ */
+ bindCodeValue(code, name) {
+ name = toCamelCase(name)
+ const codes = this.state.codes[name]
+ if (codes) {
+ const c = codes.find((p) => p.code == code)
+ if (c) {
+ return c.value
+ }
+ }
+ return null
+ }
+
+ /**
+ * 打开新增/编辑弹窗
+ * @param {*} modal
+ * @param {*} record
+ */
+ onOpen(modal, record) {
+ modal.current.open({
+ orgId: this.selectId,
+ record
+ })
+ }
+
+ /**
+ * 对表格上的操作进行统一处理
+ * [异步]
+ * @param {*} action
+ * @param {*} successMessage
+ */
+ async onAction(action, successMessage) {
+ this.list.current.onLoading()
+ try {
+ await action
+ Message.success(successMessage)
+ this.list.current.onReloadData()
+ } catch {
+ this.list.current.onLoaded()
+ }
+ }
+
+ /**
+ * 删除
+ * @param {*} record
+ */
+ onDelete(record) {
+ this.onAction(
+ apiAction.delete(record),
+ '删除成功'
+ )
+ }
+
+ //#region 自定义方法
+ renderItem(record) {
+ return (
+
+ this.onOpen(this.editForm, record)}>编辑
+ ,
+
+ this.onDelete(record)}
+ >
+ 删除
+
+ ,
+
+ this.onResetPassword(record)}>重置密码
+
+ ]
+ }
+ >
+ }
+ />
+ }
+ title={record.nickName || record.name}
+ description={record.account}
+ />
+
+ {this.bindCodeValue(record.sex, 'sex')}
+ {record.phone || '未设置'}
+ {record.email || '未设置'}
+
+
+
+
+ this.onSetUserStatus(record, checked)}
+ />
+
+
+
+
+ )
+
+ }
+
+ onSetUserStatus(record, checked) {
+ this.onAction(
+ apiAction.changeStatus({ id: record.id, status: +!checked }),
+ '设置成功'
+ )
+ }
+
+ onResetPassword(record) {
+ this.onAction(
+ apiAction.resetPwd(record),
+ '重置成功'
+ )
+ }
+ //#endregion
+
+ render() {
+ return (
+
this.onSelectTree(key)}
+ >
+
+
+
+
+
+
+
+
+
+
+ }
+ operator={
+ }
+ onClick={() => this.onOpen(this.addForm)}
+ >新增{name}
+ }
+ renderItem={(record) => this.renderItem(record)}
+ />
+
+
+
+ this.list.current.onReloadData()}
+ >
+
+
+
+ this.list.current.onReloadData()}
+ >
+
+
+
+ )
+ }
+}
diff --git a/web-react/src/store/index.js b/web-react/src/store/index.js
index 101e479..0dae1fe 100644
--- a/web-react/src/store/index.js
+++ b/web-react/src/store/index.js
@@ -29,11 +29,11 @@ store.subscribe = (...args) => {
if (path) {
const resultState = cloneDeep(result(state, path))
if (!isEqual(snapshot, resultState)) {
- listener.apply(this, [...args, resultState])
+ listener.apply(this, [resultState, ...args])
}
snapshot = resultState
} else {
- listener.apply(this, [...args, state])
+ listener.apply(this, [state, ...args])
}
})
}
diff --git a/web-react/src/store/reducer.js b/web-react/src/store/reducer.js
index 4bb1151..86c6d66 100644
--- a/web-react/src/store/reducer.js
+++ b/web-react/src/store/reducer.js
@@ -11,7 +11,9 @@ const user = (state = {}, action) => {
}
}
-const layout = (state = {}, action) => {
+const layout = (state = {
+ siderCollapsed: false
+}, action) => {
switch (action.type) {
// 打开窗口
case 'OPEN_WINDOW':
@@ -24,7 +26,8 @@ const layout = (state = {}, action) => {
return state
// 侧边收起状态
case 'TOGGLE_COLLAPSED':
- return state
+ const _state = { ...state, siderCollapsed: action.siderCollapsed }
+ return _state
default:
return state
}