Prechádzať zdrojové kódy

feat: 账号设置相关

lanjianrong 4 rokov pred
rodič
commit
efa2f271cf

+ 12 - 8
src/assets/css/common.scss

@@ -1,19 +1,27 @@
-.pi-success {
+.pi-bg-success {
   background-color: #28a745;
 }
 
-.pi-gray {
+.pi-bg-gray {
   background-color: #bbbbbb;
 }
 
-.pi-blue {
+.pi-bg-blue {
   background-color: #007bff;
 }
 
-.pi-red {
+.pi-bg-red {
   background-color: #dc3545;
 }
 
+.pi-gray {
+  color: #757575;
+}
+
+.pi-red {
+  color: #dc3545;
+}
+
 .pi-link-blue {
   color: #007bff;
   &:hover {
@@ -351,10 +359,6 @@
   border-color: #6c757d;
 }
 
-.pi-gray-color {
-  color: #757575;
-}
-
 .pi-circle-gray {
   position: relative;
   padding-right: 14px;

+ 3 - 3
src/pages/Contract/Content/Income/components/TableContent/index.tsx

@@ -229,7 +229,7 @@ const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) =>
     <div className={styles.modalTemplateContent}>
       <div className={styles.leftTemplate}>
         <div className="pi-pd-20">
-          <Radio value="1" checked={sectionTemplate.template === '1'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray-color">项目节模板1</span></Radio>
+          <Radio value="1" checked={sectionTemplate.template === '1'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray">项目节模板1</span></Radio>
         </div>
         <div className={styles.projectTable}>
           {
@@ -249,8 +249,8 @@ const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) =>
 
       </div>
       <div className={styles.rightTemplate}>
-        <div className="pi-pd-20 pi-gray-color">
-          <Radio value="2" checked={sectionTemplate.template === '2'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray-color">项目节模板2</span></Radio>
+        <div className="pi-pd-20 pi-gray">
+          <Radio value="2" checked={sectionTemplate.template === '2'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray">项目节模板2</span></Radio>
         </div>
         <div className={styles.projectTable}>
           {

+ 2 - 2
src/pages/Contract/Content/Income/components/Tabs/Detail/index.tsx

@@ -10,8 +10,8 @@ export default function Detail() {
           <tr><th>合同金额</th><td>6,557,000.00 </td><th>创建时间</th><td>2020-08-02 14:23 </td></tr>
           <tr><th>回款金额</th><td>3,787,300.07</td><th>未回款金额</th><td>2,769,700.00</td></tr>
           <tr><th>回款进度</th><td className={styles.progressContainer} colSpan={3}><div className={styles.progressContent}>
-            <div className={[ styles.progressBar, 'pi-success' ].join(' ')} style={{ width: '57.7%' }} >57.7%</div>
-            <div className={[ styles.progressBar, 'pi-gray' ].join(' ')} style={{ width: '42.3%' }}>42.3%</div>
+            <div className={[ styles.progressBar, 'pi-bg-success' ].join(' ')} style={{ width: '57.7%' }} >57.7%</div>
+            <div className={[ styles.progressBar, 'pi-bg-gray' ].join(' ')} style={{ width: '42.3%' }}>42.3%</div>
           </div></td></tr>
           <tr><th>甲方</th><td></td><th>甲方签约人</th><td></td></tr>
           <tr><th>乙方</th><td></td><th>乙方签约人</th><td></td></tr>

+ 7 - 16
src/pages/Management/Setting/api.ts

@@ -1,13 +1,12 @@
-import { iAccountChange, iAccountCreatePayload, iAccountEdit, iAccountEnable } from "@/types/setting"
+import { iAccountChange, iAccountEdit, iAccountEnable } from "@/types/setting"
 import request from "@/utils/common/request"
 
 /**
  * 获取账号列表
- * @param id - 当前用户id
  * @returns {Promise<data>}
  */
-export async function apiAccountList(id: string) {
-  const { data } = await request.get('/api/projectSetting/account', { id })
+export async function apiAccountList() {
+  const { data } = await request.get('/api/projectSetting/account')
   return data
 }
 
@@ -17,16 +16,16 @@ export async function apiAccountList(id: string) {
  * @param payload - 载荷
  */
 export async function apiAccountChange(payload: iAccountChange) {
-  const { data } = await request.post('/api/projectSetting/account/change', payload)
+  const { data } = await request.post('/api/projectSetting/account/change', { id: payload.id, account: payload.ps_account, password: payload.ps_password })
   return data
 }
 
 /**
- * 创建账号
+ * 新增/编辑账号
  * @param payload - 载荷
  */
-export async function apiAccountCreate(payload: iAccountCreatePayload) {
-  const { data } = await request.post('/api/projectSetting/account/create', payload)
+export async function apiAccountEdit(type:string, payload: iAccountEdit) {
+  const { data } = await request.post(`/api/projectSetting/account/${type === 'add' ? 'create' : 'save'}`, payload)
   return data
 }
 
@@ -49,14 +48,6 @@ export async function apiAccountEnable(payload: iAccountEnable) {
   return data
 }
 
-/**
- * 编辑账号
- * @param payload - 载荷
- */
-export async function apiAccountEdit(payload: iAccountEdit) {
-  const { data } = await request.post('/api/projectSetting/account/save', payload)
-  return data
-}
 
 /**
  * 检索账号信息

+ 125 - 0
src/pages/Management/Setting/components/Modal.tsx

@@ -0,0 +1,125 @@
+import { iUserInfo } from '@/types/setting'
+import consts from '@/utils/consts'
+import { EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons'
+import { Button, Form, Input, Modal, Select } from 'antd'
+import React, { useEffect, useState } from 'react'
+import { apiAccountDelete } from '../api'
+import styles from '../index.module.scss'
+import PswModal from './PswModal'
+const { Option } = Select
+export interface iUserModal {
+  visible: boolean
+  loading: boolean
+  userInfo: iUserInfo
+  onCreate: (values: any) => void
+  onCancel: () => void
+  initData: () => void
+}
+const userModal:React.FC<iUserModal> = ({ visible, loading, onCreate, onCancel, userInfo, initData }) => {
+  const [ form ] = Form.useForm()
+  const [ delLoading, setDelLoading ] = useState<boolean>(false)
+  const [ showPswModal, setShowPswModal ] = useState<boolean>(false)
+  useEffect(() => {
+    form.setFieldsValue(userInfo)
+  }, [ visible ])
+  const delBtnHandler = async () => {
+    setDelLoading(true)
+    const { code = -1 } = await apiAccountDelete(userInfo.id)
+    if (code === consts.RET_CODE.SUCCESS) {
+      onCancel()
+      initData()
+    }
+    setDelLoading(false)
+  }
+  return (
+    <>
+      <Modal
+        getContainer={false}
+        visible={visible}
+        title={userInfo.id ? '编辑账号' : '新增账号'}
+        onCancel={onCancel}
+        footer={
+          <div>
+            {
+              userInfo.id ?
+              <>
+                <Button size="small" danger onClick={() => delBtnHandler()} loading={delLoading}>删除账号</Button>
+                <Button size="small" type="primary" ghost onClick={() => {
+                  onCancel()
+                  setShowPswModal(true)
+                }}>修改账号/密码</Button>
+              </>
+              : ''
+            }
+            <Button size="small" className={styles.grayBtn} onClick={() => onCancel()}>关闭</Button>
+            <Button size="small" type="primary" loading={loading} onClick={() => {
+              form.validateFields().then(values => {
+                form.resetFields()
+                onCreate(values)
+              })
+            }}>{userInfo.id ? '提交修改' : '确认添加'}</Button>
+          </div>
+        }
+    >
+    <Form
+      form={form}
+      layout="vertical"
+      className={styles.FormContent}
+    >
+      {
+        userInfo.id ?
+        <Form.Item name="id" hidden>
+          <Input></Input>
+        </Form.Item>
+        : ''
+      }
+      <Form.Item name="accountGroup" label="账号组" rules={[ { required: true, message: '请选择账号组' } ]}>
+        <Select
+          showSearch
+          placeholder="请选择"
+          size="small"
+          optionFilterProp="children"
+          filterOption={(input, option) => option?.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
+          <Option value={1}>建设单位</Option>
+          <Option value={2}>监理单位</Option>
+          <Option value={3}>施工单位</Option>
+          <Option value={4}>设计单位</Option>
+        </Select>
+      </Form.Item>
+      <Form.Item name="account" label="登录账号" rules={[ { required: true, message: '请输入登录账号' } ]}>
+        <Input size="small" placeholder="支持英文数字组合" disabled={userInfo.id ? true : false}></Input>
+      </Form.Item>
+      {
+        !userInfo.id ?
+        <Form.Item name="password" label="登录密码" rules={[ { required: true, message: '请输入登录密码' } ]}>
+          <Input.Password
+            placeholder="密码支持英文数字及符号"
+            addonAfter={<span>随机密码</span>}
+            iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
+          />
+        </Form.Item>
+        : ''
+      }
+      <Form.Item name="name" label="姓名" rules={[ { required: true, message: '请输入姓名' } ]}>
+        <Input size="small"></Input>
+      </Form.Item>
+      <Form.Item name="company" label="单位名称" rules={[ { required: true, message: '请输入单位名称' } ]}>
+        <Input size="small"></Input>
+      </Form.Item>
+      <Form.Item name="position" label="职位名称" rules={[ { required: true, message: '请输入职位名称' } ]}>
+        <Input size="small"></Input>
+      </Form.Item>
+      <Form.Item name="mobile" label="手机" rules={[ { required: true, message: '请输入手机号码' } ]}>
+        <Input size="small"></Input>
+      </Form.Item>
+      <Form.Item name="telephone" label="电话">
+        <Input size="small" placeholder="格式000-0000000"></Input>
+      </Form.Item>
+    </Form>
+  </Modal>
+      <PswModal visible={showPswModal} onCancel={() => setShowPswModal(false)} userInfo={userInfo}></PswModal>
+    </>
+
+  )
+}
+export default userModal

+ 74 - 0
src/pages/Management/Setting/components/PswModal.tsx

@@ -0,0 +1,74 @@
+import { iUserInfo } from '@/types/setting'
+import consts from '@/utils/consts'
+import { EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons'
+import { Form, Input, message, Modal } from 'antd'
+import React, { useEffect, useState } from 'react'
+import { apiAccountChange } from '../api'
+import styles from '../index.module.scss'
+interface iPswModalProps {
+  visible: boolean
+  onCancel: () => void
+  userInfo: iUserInfo
+}
+interface iValues {
+  id: string
+  ps_account: string
+  ps_password: string
+}
+const PswModal:React.FC<iPswModalProps> = ({ visible, onCancel, userInfo: { id, account } }) => {
+  const [ loading, setLoading ] = useState(false)
+  const [ form ] = Form.useForm()
+  const onCreate = async (values: iValues) => {
+    setLoading(true)
+    const { code = -1 } = await apiAccountChange(values)
+    if ( code === consts.RET_CODE.SUCCESS) {
+      message.success('修改成功')
+      onCancel()
+    }
+    setLoading(false)
+  }
+  useEffect(() => {
+    form.setFieldsValue({ id, ps_account: account })
+  }, [ visible ])
+  return (
+    <div>
+      <Modal
+        getContainer={false}
+        visible={visible}
+        title="修改账号/密码"
+        okText="提交修改"
+        cancelText="关闭"
+        confirmLoading={loading}
+        onCancel={onCancel}
+        onOk={() => {
+          form.validateFields().then((values: any) => {
+            form.setFieldsValue({ ps_password: '' })
+            onCreate(values)
+          })
+        }}
+        >
+          <Form
+            form={form}
+            layout="vertical"
+            className={styles.FormContent}
+            >
+            <Form.Item name="id" hidden>
+              <Input></Input>
+            </Form.Item>
+            <Form.Item name="ps_account" label="登录账号" rules={[ { required: true, message: '请输入账号' } ]}>
+              <Input></Input>
+            </Form.Item>
+            <Form.Item name="ps_password" label="登录密码" rules={[ { required: true, message: '请输入登录密码' } ]}>
+              <Input.Password
+                placeholder="密码支持英文数字及符号"
+                addonAfter={<span>随机密码</span>}
+                iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
+              />
+        </Form.Item>
+          </Form>
+      </Modal>
+    </div>
+  )
+}
+
+export default PswModal

+ 21 - 0
src/pages/Management/Setting/index.module.scss

@@ -22,3 +22,24 @@
   //   border-right: 1px solid #dee2e6;
   // }
 }
+.grayBtn {
+  color: #ffffff;
+  background-color: #bbbbbb;
+}
+
+.FormContent {
+  :global(.ant-form-item) {
+    margin-bottom: 0.5rem;
+  }
+
+  :global(.ant-input-group-addon) {
+    &:hover {
+      color: #ffffff;
+      background-color: #6c757d;
+      border-color: #6c757d;
+    }
+    &:not(:disabled) {
+      cursor: pointer;
+    }
+  }
+}

+ 72 - 9
src/pages/Management/Setting/index.tsx

@@ -1,15 +1,36 @@
 import Header from '@/components/Header'
 import Slot from '@/components/Header/slot'
 import SvgIcon from '@/components/SvgIcon'
-import { userStore } from '@/store/mobx'
 import { iUserInfo } from '@/types/setting'
 import consts from '@/utils/consts'
 import { Button, Input, Table, Tooltip } from 'antd'
 import { ColumnsType } from 'antd/lib/table'
 import React, { useEffect, useState } from 'react'
-import { apiAccountList } from './api'
+import { apiAccountEdit, apiAccountEnable, apiAccountList } from './api'
+import UserModal from './components/Modal'
 import styles from './index.module.scss'
+interface iModalStatus {
+  visible: boolean
+  loading: boolean
+  type: string
+}
 export default function Info() {
+  const initUserState = {
+    account: '',
+    accountGroup: undefined,
+    company: '',
+    csrf: '',
+    enable: 0,
+    id: '',
+    isAdmin: 0,
+    mobile: '',
+    name: '',
+    password: '',
+    position: '',
+    projectId: '',
+    role: '',
+    telephone: ''
+  }
   const { Search } = Input
   const [ userList, setUserList ] = useState<iUserInfo[]>([ {
     "account": "",
@@ -28,14 +49,48 @@ export default function Info() {
     "telephone": ""
   } ])
   const initData = async () => {
-    const { code = -1, data } = await apiAccountList(userStore.userInfo.id)
+    const { code = -1, data } = await apiAccountList()
     if (code === consts.RET_CODE.SUCCESS) {
-      setUserList(data)
+      setUserList(data.sort((a: iUserInfo, b: iUserInfo) => b.isAdmin - a.isAdmin))
     }
   }
+  const [ row, setRow ] = useState<iUserInfo>(initUserState)
   useEffect(() => {
     initData()
   }, [])
+  const [ modalStatus, setModalStatus ] = useState<iModalStatus>({
+    visible: false,
+    loading: false,
+    type: ''
+  })
+  const onCreate = async (values: iUserInfo) => {
+    setModalStatus({ ...modalStatus, loading: true })
+    const { code = -1 } = await apiAccountEdit(modalStatus.type, values)
+    if (code === consts.RET_CODE.SUCCESS) {
+      initData()
+    }
+    setModalStatus({
+      ...modalStatus,
+      visible: false,
+      loading: false,
+      type: ''
+    })
+  }
+  const onCancel = () => {
+    setModalStatus({ ...modalStatus, visible: false })
+
+  }
+  const editHandler = (user: iUserInfo) => {
+    setRow(user)
+    setModalStatus({ ...modalStatus, visible: true, type: 'edit' })
+  }
+  const enableHandler = async (record: iUserInfo, enable: 0 | 1) => {
+    const { code = -1 } = await apiAccountEnable({ id: record.id, enable })
+    if ( code === consts.RET_CODE.SUCCESS) {
+      // setUserList([ ...userList, { ...record, enable } ])
+      initData()
+    }
+  }
   const columns: ColumnsType<iUserInfo> = [
     {
       title: '账号',
@@ -47,7 +102,7 @@ export default function Info() {
             <span>{text}</span>
             {
               record.isAdmin ?
-                <Tooltip title="管理员"><span><SvgIcon iconClass="user-circle" fontSize="13"></SvgIcon></span></Tooltip>
+                <Tooltip title="管理员"><span className="pi-mg-left-5"><SvgIcon iconClass="user-circle" fontSize="13"></SvgIcon></span></Tooltip>
               : ''
             }
           </div>
@@ -81,9 +136,13 @@ export default function Info() {
       render: (_: any, record: iUserInfo) => {
         return (
           <div>
-            <Button size="small" className="pi-mg-right-5">编辑</Button>
+            <Button size="small" className="pi-mg-right-5" onClick={() => editHandler(record)}>编辑</Button>
             {
-              !record.isAdmin && record.enable ? <Button danger size="small">停用</Button> : <Button size="small" className={styles.greenBtn}>启用</Button>
+              !record.isAdmin ?
+              record.enable ?
+              <Button danger size="small" onClick={() => enableHandler(record, 0)}>停用</Button>
+              : <Button size="small" className={styles.greenBtn} onClick={() => enableHandler(record, 1)}>启用</Button>
+              : ''
             }
           </div>
         )
@@ -94,7 +153,10 @@ export default function Info() {
     <div className="content-wrap">
       <Header>
         <Slot position="right">
-          <Button type="primary" size="small">添加账号</Button>
+          <Button type="primary" size="small" onClick={() => {
+            setRow({ ...row, ...initUserState })
+            setModalStatus({ ...modalStatus, visible: true, type: 'add' })
+          }}>添加账号</Button>
         </Slot>
         <Slot position="left">
           <Search placeholder="账号/姓名/单位/手机 搜索" loading={false} size="small"></Search>
@@ -105,10 +167,11 @@ export default function Info() {
           dataSource={userList}
           columns={columns}
           bordered
-          rowClassName={(record: iUserInfo) => record.enable ? 'pi-red' : ''}
+          rowClassName={(record: iUserInfo) => !record.enable ? 'pi-red' : ''}
           rowKey={record => record.id}
         ></Table>
       </div>
+      <UserModal {...modalStatus} userInfo={row} onCreate={onCreate} onCancel={onCancel} initData={initData}></UserModal>
     </div>
   )
 }

+ 1 - 1
src/store/mobx/user/index.ts

@@ -10,7 +10,7 @@ import { action, computed, observable } from 'mobx'
 class UserState {
   initUserState = {
     account: '',
-    accountGroup: 0,
+    accountGroup: undefined,
     company: '',
     csrf: '',
     enable: 0,

+ 0 - 0
src/store/mobx/user/types.ts


+ 4 - 4
src/types/setting.d.ts

@@ -14,7 +14,7 @@ export interface iAccountEdit extends accountCreatePayload {
 
 export interface iUserInfo {
   account: string;
-  accountGroup: number;
+  accountGroup: number | undefined;
   company: string;
   csrf: string;
   enable: number;
@@ -31,11 +31,11 @@ export interface iUserInfo {
 
 export interface iAccountChange {
   id: string
-  account: string
-  password: string
+  ps_account: string
+  ps_password: string
 }
 
 export interface iAccountEnable {
   id: string
-  enable: string
+  enable: number
 }