|
@@ -0,0 +1,617 @@
|
|
|
+import React, { useCallback, useEffect, useState, useMemo } from 'react'
|
|
|
+import {
|
|
|
+ Select as AntdSelect,
|
|
|
+ Form,
|
|
|
+ Row,
|
|
|
+ Col,
|
|
|
+ Input,
|
|
|
+ Button,
|
|
|
+ message,
|
|
|
+ Divider,
|
|
|
+ Typography,
|
|
|
+ notification,
|
|
|
+ Tree,
|
|
|
+ Upload, Collapse, Checkbox
|
|
|
+} from 'antd'
|
|
|
+import { SaveOutlined, UserOutlined } from '@ant-design/icons'
|
|
|
+import httpService from '../../../services/httpService'
|
|
|
+import { respuestas } from '../../../utilities'
|
|
|
+import { useNavigate } from 'react-router-dom'
|
|
|
+import { useApp, useAuth, useModels } from '../../../hooks'
|
|
|
+import { ArbolPermisos, InputPass, Select } from '../../../components'
|
|
|
+import { emptyRequest } from '../../../constants/requests'
|
|
|
+import Avatar from 'antd/es/avatar/avatar'
|
|
|
+
|
|
|
+const baseUrl = import.meta.env.VITE_API_URL
|
|
|
+
|
|
|
+const { Option } = AntdSelect
|
|
|
+const { Panel } = Collapse
|
|
|
+
|
|
|
+const Formulario = ({ setGuardando, endPoint, model, editing, id }) => {
|
|
|
+ const [form] = Form.useForm()
|
|
|
+ const navigate = useNavigate()
|
|
|
+ const { Title } = Typography
|
|
|
+ const { user } = useAuth()
|
|
|
+ const { token } = useApp()
|
|
|
+
|
|
|
+ //Estados
|
|
|
+ const [saveLoading, setSaveLoading] = useState(false)
|
|
|
+
|
|
|
+ //Permisos
|
|
|
+ const [checkedList, setCheckedList] = useState([])
|
|
|
+ const [estatusRequest, setEstatusRequest] = useState(emptyRequest)
|
|
|
+
|
|
|
+ const [arbolEstatus, setArbolEstatus] = useState([])
|
|
|
+ const [arbolRecurso, setArbolRecurso] = useState([])
|
|
|
+ const [listaCheckSolicitud, setListaCheckSolicitud] = useState([])
|
|
|
+ const [listaCheckRecurso, setListaCheckRecurso] = useState([])
|
|
|
+ // const [aee, setAee] = useState([]); //Arbol estatus expandido
|
|
|
+
|
|
|
+ const [urlFoto, setUrlFoto] = useState(null)
|
|
|
+ const [listaArchivosFotoPerfil, setListaArchivosFotoPerfil] = useState([])
|
|
|
+ // const [archivoCargando, setArchivoCargando] = useState(null)
|
|
|
+
|
|
|
+ const [correoValidadoChecked, setCorreoValidadoChecked] = useState(false)
|
|
|
+
|
|
|
+ //Parámetros de estatus.
|
|
|
+ const estatusParams = useMemo(
|
|
|
+ () => ({
|
|
|
+ name: 'estatus',
|
|
|
+ expand: 'subestatus',
|
|
|
+ }),
|
|
|
+ []
|
|
|
+ )
|
|
|
+
|
|
|
+ const onChangePicturePerfil = ({ fileList: newFileList }) => {
|
|
|
+ let _archivo = newFileList[0]?.originFileObj
|
|
|
+ const isImage = _archivo.type.includes('image/')
|
|
|
+
|
|
|
+ if (!isImage) {
|
|
|
+ message.error(`${_archivo.name} no es un archivo de Imagen`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ subirImagenPerfil(newFileList)
|
|
|
+
|
|
|
+ // setListaArchivosFotoPerfil(newFileList);
|
|
|
+ }
|
|
|
+
|
|
|
+ const subirImagenPerfil = async (file, idDocumento) => {
|
|
|
+ try {
|
|
|
+ // setArchivoCargando(true)
|
|
|
+
|
|
|
+ let _archivo = file[0]?.originFileObj
|
|
|
+
|
|
|
+ if (!_archivo) {
|
|
|
+ message.info({
|
|
|
+ content: 'Debes de seleccionarun archivo',
|
|
|
+ style: { marginTop: '20vh' },
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const form = new FormData()
|
|
|
+ form.append('archivo', _archivo)
|
|
|
+
|
|
|
+ const response = await fetch(baseUrl + '/v1/perfil/cambiar-foto-perfil', {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${token}`,
|
|
|
+ },
|
|
|
+ body: form,
|
|
|
+ })
|
|
|
+
|
|
|
+ const data = await response.json()
|
|
|
+
|
|
|
+ setUrlFoto(data?.resultado[0])
|
|
|
+ } catch (error) {
|
|
|
+ console.log('error al cargar archivo: ', error)
|
|
|
+ } finally {
|
|
|
+ // setArchivoCargando(false)
|
|
|
+ // window.location.reload(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const { models: estatus } = useModels(estatusRequest)
|
|
|
+
|
|
|
+ const onCheckSolicitud = useCallback((checkedList) => {
|
|
|
+ setListaCheckSolicitud(checkedList)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ const onCheckRecurso = useCallback((checkedList) => {
|
|
|
+ setListaCheckRecurso(checkedList)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ const onFinish = async (values) => {
|
|
|
+ try {
|
|
|
+ const { clave1, clave, rol } = values
|
|
|
+
|
|
|
+ setSaveLoading(true)
|
|
|
+ setGuardando(true)
|
|
|
+ let body = {
|
|
|
+ ...values,
|
|
|
+ permisos: checkedList,
|
|
|
+ foto: urlFoto,
|
|
|
+ verificarCorreo: correoValidadoChecked
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!editing) {
|
|
|
+ if (clave1 !== clave) {
|
|
|
+ message.error('Las contraseñas no coinciden.')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (user?.rol !== 'admin' && rol === 'admin') {
|
|
|
+ notification.info({
|
|
|
+ message: 'Atención',
|
|
|
+ description: 'No puede asignar el rol de Administrador',
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ body.pwd = clave1 ? clave1 : ''
|
|
|
+
|
|
|
+ delete body.clave1
|
|
|
+ delete body.clave
|
|
|
+
|
|
|
+ if (listaCheckSolicitud || listaCheckRecurso) {
|
|
|
+ body.permisoEstatus = [...listaCheckSolicitud, ...listaCheckRecurso]
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (clave1 && clave) {
|
|
|
+ if (clave1 !== clave) {
|
|
|
+ message.error('Las contraseñas no coinciden.')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // let _body = {
|
|
|
+ // clave: clave1,
|
|
|
+ // confirmarClave: clave,
|
|
|
+ // idUsuario: id,
|
|
|
+ // };
|
|
|
+
|
|
|
+ // const resClave = await httpService.post(
|
|
|
+ // `${endPoint}/cambiar-clave`,
|
|
|
+ // _body
|
|
|
+ // );
|
|
|
+ // if (resClave?.status !== 200) {
|
|
|
+ // respuestas(resClave);
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+
|
|
|
+ if (user?.rol !== 'admin' && rol === 'admin') {
|
|
|
+ notification.info({
|
|
|
+ message: 'Atención',
|
|
|
+ description: 'No puede asignar el rol de Super Administrador',
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ body.id = id;
|
|
|
+
|
|
|
+ /* body = {
|
|
|
+ ...values,
|
|
|
+ id: id ? id : '',
|
|
|
+ pwd: clave1 ? clave1 : '',
|
|
|
+ permisos: checkedList,
|
|
|
+ foto: urlFoto,
|
|
|
+ verificarCorreo: correoValidadoChecked
|
|
|
+ } */
|
|
|
+ delete body.clave1
|
|
|
+ delete body.clave
|
|
|
+
|
|
|
+ if (listaCheckSolicitud || listaCheckRecurso) {
|
|
|
+ body.permisoEstatus = [...listaCheckSolicitud, ...listaCheckRecurso]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await httpService.post(endPoint, body)
|
|
|
+ respuestas(res)
|
|
|
+ if (res?.status === 200) {
|
|
|
+ navigate(`/administracion/usuarios`)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e)
|
|
|
+ } finally {
|
|
|
+ setSaveLoading(false)
|
|
|
+ setGuardando(false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const onFinishFailed = ({ values, errorFields, outOfDate }) => {
|
|
|
+ message.warning({
|
|
|
+ content: 'Verifica que todos los campos estén correctos.',
|
|
|
+ style: {
|
|
|
+ marginTop: '10vh',
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // const onCheck = useCallback(
|
|
|
+ // (checkedList, info) => {
|
|
|
+ // checkedList = checkedList.map((item) => {
|
|
|
+ // const val = item?.replace("p-", "");
|
|
|
+ // return val;
|
|
|
+ // });
|
|
|
+
|
|
|
+ // let _checkedList = [];
|
|
|
+ // for (let i = 0, l = listaPermisos.length; i < l; i++) {
|
|
|
+ // const _permiso = listaPermisos[i];
|
|
|
+ // if (checkedList.includes(_permiso["id"])) {
|
|
|
+ // _checkedList.push(_permiso["id"]);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ // setCheckedList(_checkedList);
|
|
|
+ // },
|
|
|
+ // [listaPermisos]
|
|
|
+ // );
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (editing && model) {
|
|
|
+ form.setFieldsValue({
|
|
|
+ ...model,
|
|
|
+ clave: '',
|
|
|
+ unidadesAdministrativas: model?.unidadAdministrativaUsuarios,
|
|
|
+ })
|
|
|
+
|
|
|
+ if (model?.foto) {
|
|
|
+ setUrlFoto(model?.foto)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (model?.verificarCorreo !== null) {
|
|
|
+ setCorreoValidadoChecked(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ setCheckedList(model?.permisos?.map((i) => i))
|
|
|
+ }
|
|
|
+ }, [editing, form, model])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (estatus) {
|
|
|
+ let arbolEstatus = estatus.map((_estatus) => {
|
|
|
+ if (_estatus?.idEstatusPadre === null) {
|
|
|
+ return {
|
|
|
+ title: _estatus?.nombre,
|
|
|
+ key: _estatus?.id,
|
|
|
+ id: _estatus?.id,
|
|
|
+ tipo: _estatus?.tipo,
|
|
|
+ children: _estatus?.subestatus?.map((subestatus) => ({
|
|
|
+ title: subestatus?.nombre,
|
|
|
+ key: subestatus?.id,
|
|
|
+ id: subestatus?.id,
|
|
|
+ tipo: _estatus?.tipo,
|
|
|
+ })),
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ })
|
|
|
+ let arbolFiltrado = arbolEstatus.filter((item) => item !== null)
|
|
|
+ let arbolSolicitud = arbolFiltrado.filter((item) => item.tipo === 'S')
|
|
|
+ let arbolRecurso = arbolFiltrado.filter((item) => item.tipo === 'RR')
|
|
|
+ setArbolEstatus(arbolSolicitud)
|
|
|
+ setArbolRecurso(arbolRecurso)
|
|
|
+ }
|
|
|
+ }, [estatus])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (model?.estatusPermiso) {
|
|
|
+ let permisosMarcadosS = []
|
|
|
+ let permisosMarcadosRR = []
|
|
|
+ let estatus = model?.estatusPermiso
|
|
|
+
|
|
|
+ estatus.forEach((permiso) => {
|
|
|
+ if (permiso?.estatus?.tipo === 'S') {
|
|
|
+ permisosMarcadosS.push(permiso.idEstatus)
|
|
|
+ } else {
|
|
|
+ permisosMarcadosRR.push(permiso.idEstatus)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ setListaCheckSolicitud(permisosMarcadosS)
|
|
|
+ setListaCheckRecurso(permisosMarcadosRR)
|
|
|
+ }
|
|
|
+ }, [model])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ setEstatusRequest(estatusParams)
|
|
|
+ return () => setEstatusRequest({})
|
|
|
+ }, [estatusParams])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Form
|
|
|
+ form={form}
|
|
|
+ name="form"
|
|
|
+ layout="vertical"
|
|
|
+ onFinish={onFinish}
|
|
|
+ onFinishFailed={onFinishFailed}
|
|
|
+ >
|
|
|
+ <Row gutter={[16, 0]}>
|
|
|
+ <Col span={24} md={6}>
|
|
|
+ <Form.Item
|
|
|
+ label={'Elegir foto de Perfil:'}
|
|
|
+ >
|
|
|
+ <Upload
|
|
|
+ beforeUpload={() => false}
|
|
|
+ multiple={true}
|
|
|
+ listType="picture-card"
|
|
|
+ fileList={listaArchivosFotoPerfil}
|
|
|
+ onChange={onChangePicturePerfil}
|
|
|
+ onRemove={() => {
|
|
|
+ setListaArchivosFotoPerfil([])
|
|
|
+ setUrlFoto(null)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Avatar size={100} icon={
|
|
|
+ <UserOutlined />} src={urlFoto} />
|
|
|
+ </Upload>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={18}>
|
|
|
+ <Row gutter={[16, 0]}>
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <Form.Item
|
|
|
+ name="nombre"
|
|
|
+ label="Nombre"
|
|
|
+ rules={[
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ message: 'Por favor ingresar nombre de Usuario',
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <Input autoComplete="one-time-code" />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ {/* <Col span={24} md={12}>
|
|
|
+ <Form.Item
|
|
|
+ name="usuario"
|
|
|
+ label="Usuario"
|
|
|
+ rules={[
|
|
|
+ { required: true, message: "Por favor ingresar el usuario" },
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <Input autocomplete="one-time-code" />
|
|
|
+ </Form.Item>
|
|
|
+ </Col> */}
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <Form.Item
|
|
|
+ label="Correo Electronico"
|
|
|
+ name="correo"
|
|
|
+ rules={[{ required: true, message: 'Por favor escriba su correo' }]}
|
|
|
+ >
|
|
|
+ <Input autoComplete="one-time-code" disabled={editing} />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <Form.Item
|
|
|
+ label="Rol"
|
|
|
+ name="rol"
|
|
|
+ rules={[{ required: true, message: 'Por favor Seleccionar Rol' }]}
|
|
|
+ >
|
|
|
+ <AntdSelect>
|
|
|
+ <Option value={'admin'}>Super Administrador</Option>
|
|
|
+ <Option value={'unidadAdministrativa'}>
|
|
|
+ Unidad Administrativa
|
|
|
+ </Option>
|
|
|
+ <Option value={'usuario'}>Usuario</Option>
|
|
|
+ </AntdSelect>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <Form.Item
|
|
|
+ label="Teléfono"
|
|
|
+ name="telefono"
|
|
|
+ rules={[
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ message: 'Es necesario ingresar un número telefónico',
|
|
|
+ },
|
|
|
+ // solo numeros
|
|
|
+ ({ getFieldValue }) => ({
|
|
|
+ validator(_, value) {
|
|
|
+ if (!value || /^[0-9]*$/.test(value)) {
|
|
|
+ return Promise.resolve()
|
|
|
+ }
|
|
|
+ return Promise.reject(new Error('Solo se permiten números'))
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ // maximo 10 caracteres minimo 10
|
|
|
+ ({ getFieldValue }) => ({
|
|
|
+ validator(_, value) {
|
|
|
+ if (!value || value.length === 10) {
|
|
|
+ return Promise.resolve()
|
|
|
+ }
|
|
|
+ return Promise.reject(
|
|
|
+ new Error('El teléfono debe tener 10 dígitos')
|
|
|
+ )
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <Input autoComplete="one-time-code" maxLength={10} />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <Form.Item label="Sujeto Obligado" name="idSujetoObligado">
|
|
|
+ <Select
|
|
|
+ modelsParams={{
|
|
|
+ name: 'sujeto-obligado',
|
|
|
+ limite: 20,
|
|
|
+ ordenar: 'nombre-asc',
|
|
|
+ }}
|
|
|
+ labelProp="nombre"
|
|
|
+ valueProp="id"
|
|
|
+ placeholder="Seleccione un perfil"
|
|
|
+ append={[model?.sujetoObligado]}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <Form.Item name={'idPonencia'} label="Ponencia">
|
|
|
+ <Select
|
|
|
+ modelsParams={{
|
|
|
+ name: 'ponencia',
|
|
|
+ ordenar: 'nombre-asc',
|
|
|
+ }}
|
|
|
+ labelProp={'nombre'}
|
|
|
+ valueProp={'id'}
|
|
|
+ append={[model?.ponencia]}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col>
|
|
|
+ <Form.Item label={"Correo Verificado"} name="verificarCorreo">
|
|
|
+ <Checkbox
|
|
|
+ checked={correoValidadoChecked}
|
|
|
+ onChange={(e) => setCorreoValidadoChecked(e.target.checked)}
|
|
|
+ />
|
|
|
+ </ Form.Item>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Divider />
|
|
|
+ <Row gutter={[16, 0]}>
|
|
|
+ {!editing ? (
|
|
|
+ <>
|
|
|
+ <Col
|
|
|
+ xs={{ span: 24 }}
|
|
|
+ sm={{ span: 24 }}
|
|
|
+ md={{ span: 12 }}
|
|
|
+ lg={{ span: 12 }}
|
|
|
+ >
|
|
|
+ <InputPass
|
|
|
+ label="Contraseña"
|
|
|
+ name="clave"
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ <Col
|
|
|
+ xs={{ span: 24 }}
|
|
|
+ sm={{ span: 24 }}
|
|
|
+ md={{ span: 12 }}
|
|
|
+ lg={{ span: 12 }}
|
|
|
+ >
|
|
|
+ <InputPass
|
|
|
+ label="Repetir Contraseña"
|
|
|
+ name="clave1"
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ </>
|
|
|
+ ) :
|
|
|
+ <Col span={24}>
|
|
|
+ <Collapse>
|
|
|
+ <Panel header={'Cambiar la contraseña'} key="1">
|
|
|
+ <p
|
|
|
+ style={{
|
|
|
+ color: '#777',
|
|
|
+ marginBottom: '20px',
|
|
|
+ marginTop: '-10px',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ Si no desea cambiar la contraseña, deje los campos en blanco.
|
|
|
+ </p>
|
|
|
+ <Row gutter={[16, 0]}>
|
|
|
+ {/* <Col
|
|
|
+ xs={{ span: 24 }}
|
|
|
+ sm={{ span: 24 }}
|
|
|
+ md={{ span: 12 }}
|
|
|
+ lg={{ span: 12 }}
|
|
|
+ >
|
|
|
+ <Form.Item label="Contraseña Actual" name="claveActual">
|
|
|
+ <Input.Password
|
|
|
+ autocomplete="one-time-code"
|
|
|
+ visibilitytoggle="false"
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ </Col> */}
|
|
|
+ <Col span={24} md={12}>
|
|
|
+ <InputPass
|
|
|
+ label="Confirmar Contraseña"
|
|
|
+ name="clave"
|
|
|
+ obligatorio={false}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ <Col
|
|
|
+ xs={{ span: 24 }}
|
|
|
+ sm={{ span: 24 }}
|
|
|
+ md={{ span: 12 }}
|
|
|
+ lg={{ span: 12 }}
|
|
|
+ >
|
|
|
+ <InputPass
|
|
|
+ label="Contraseña"
|
|
|
+ name="clave1"
|
|
|
+ obligatorio={false}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ </Panel>
|
|
|
+ </Collapse>
|
|
|
+ </Col>
|
|
|
+ }
|
|
|
+ </Row>
|
|
|
+ <Divider />
|
|
|
+ <Row gutter={[10, 10]}>
|
|
|
+ <Col span={24}>
|
|
|
+ <Title level={5}>Permisos</Title>
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={8}>
|
|
|
+ <Typography.Title style={{ margin: 0 }} level={5}>
|
|
|
+ Permisos del Sistema
|
|
|
+ </Typography.Title>
|
|
|
+ <ArbolPermisos
|
|
|
+ conPerfil={true}
|
|
|
+ urlPerfil='coleccion-permiso'
|
|
|
+ urlModulo={'modulo'}
|
|
|
+ permisosCargados={model?.permisos}
|
|
|
+ alMarcar={(v) => setCheckedList(v)}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={8}>
|
|
|
+ <Typography.Title style={{ margin: 0 }} level={5}>
|
|
|
+ Permisos de Estatus de Solicitud
|
|
|
+ </Typography.Title>
|
|
|
+ <Tree
|
|
|
+ checkable
|
|
|
+ // defaultExpandedKeys={aee}
|
|
|
+ checkedKeys={listaCheckSolicitud}
|
|
|
+ onCheck={onCheckSolicitud}
|
|
|
+ treeData={arbolEstatus}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ <Col span={24} md={8}>
|
|
|
+ <Typography.Title style={{ margin: 0 }} level={5}>
|
|
|
+ Permisos de Estatus de Recurso de Revisión
|
|
|
+ </Typography.Title>
|
|
|
+ <Tree
|
|
|
+ checkable
|
|
|
+ // defaultExpandedKeys={aee}
|
|
|
+ checkedKeys={listaCheckRecurso}
|
|
|
+ onCheck={onCheckRecurso}
|
|
|
+ treeData={arbolRecurso}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Divider />
|
|
|
+ <Row gutter={[16, 0]}>
|
|
|
+ <Col span={6}>
|
|
|
+ <Form.Item>
|
|
|
+ <Button
|
|
|
+ icon={<SaveOutlined />}
|
|
|
+ type="primary"
|
|
|
+ block
|
|
|
+ size="large"
|
|
|
+ htmlType="submit"
|
|
|
+ loading={saveLoading}
|
|
|
+ >
|
|
|
+ Guardar
|
|
|
+ </Button>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ </Form>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+export default Formulario
|