张延森 4 年前
父节点
当前提交
b8f34e7b21

+ 13
- 2
config/routes.js 查看文件

177
                 hideInMenu: true,
177
                 hideInMenu: true,
178
               },
178
               },
179
               {
179
               {
180
-                path: 'bill/ticket',
180
+                path: 'repair-type',
181
+                name: '工单分类',
182
+                component: './property/ticket/type',
183
+              },
184
+              {
185
+                path: 'repair-type/edit',
186
+                name: '分类详情',
187
+                component: './property/ticket/type/Editor',
188
+                hideInMenu: true,
189
+              },
190
+              {
191
+                path: 'ticket',
181
                 name: '工单管理',
192
                 name: '工单管理',
182
                 component: './property/ticket',
193
                 component: './property/ticket',
183
               },
194
               },
184
               {
195
               {
185
-                path: 'bill/ticket/detail',
196
+                path: 'ticket/detail',
186
                 name: '工单详情',
197
                 name: '工单详情',
187
                 component: './property/ticket/Detail',
198
                 component: './property/ticket/Detail',
188
                 hideInMenu: true,
199
                 hideInMenu: true,

+ 87
- 0
src/components/EditableTagGroup/index.jsx 查看文件

1
+import React, { useEffect, useRef, useState } from 'react'
2
+import { Tag, Input, Tooltip, Icon } from 'antd'
3
+
4
+export default React.forwardRef((props,ref) => {
5
+  const [tags, setTags] = useState([])
6
+  const [inputVisible, setInputVisible] = useState(false)
7
+  const [inputValue, setInputValue] = useState()
8
+  const inputRef = useRef()
9
+  const dataInited = useRef(false)
10
+
11
+  const handleClose = removedTag => {
12
+    const newTags = tags.filter(tag => tag !== removedTag)
13
+    setTags(newTags)
14
+  }
15
+
16
+  const handleInputChange = e => {
17
+    setInputValue(e.target.value)
18
+  }
19
+
20
+  const handleInputConfirm = () => {
21
+    if (inputValue && tags.indexOf(inputValue) === -1) {
22
+      const newTags = [...tags, inputValue]
23
+      setTags(newTags)
24
+      setInputValue()
25
+    }
26
+  }
27
+
28
+  const showInput = () => {
29
+    setInputVisible(true)
30
+    if (inputRef.current) {
31
+      inputRef.current.focus()
32
+    }
33
+  }
34
+
35
+  // 如果 prop.value 有更新
36
+  useEffect(() => {
37
+    if (props.value && !dataInited.current) {
38
+      setTags((props.value || '').split(',').filter(Boolean))
39
+      dataInited.current = true
40
+    }
41
+  }, [props.value])
42
+  
43
+  // 如果 tag 有更新
44
+  useEffect(() => {
45
+    const newValue = tags.join(',')
46
+    if (props.value != newValue) {
47
+      props.onChange && props.onChange(newValue)
48
+    }
49
+  }, [tags, props.value])
50
+
51
+  return (
52
+    <div ref={ref}>
53
+      {tags.map(tag => {
54
+        const isLongTag = tag.length > 20
55
+        const tagElem = (
56
+          <Tag key={tag} closable onClose={() => handleClose(tag)}>
57
+            {isLongTag ? `${tag.slice(0, 20)}...` : tag}
58
+          </Tag>
59
+        )
60
+        return isLongTag ? (
61
+          <Tooltip title={tag} key={tag}>
62
+            {tagElem}
63
+          </Tooltip>
64
+        ) : (
65
+          tagElem
66
+        )
67
+      })}
68
+      {inputVisible && (
69
+        <Input
70
+          ref={inputRef}
71
+          type="text"
72
+          size="small"
73
+          style={{ width: 78 }}
74
+          value={inputValue}
75
+          onChange={handleInputChange}
76
+          onBlur={handleInputConfirm}
77
+          onPressEnter={handleInputConfirm}
78
+        />
79
+      )}
80
+      {!inputVisible && (
81
+        <Tag onClick={showInput} style={{ background: '#fff', borderStyle: 'dashed' }}>
82
+          <Icon type="plus" /> 新建
83
+        </Tag>
84
+      )}
85
+    </div>
86
+  )
87
+})

+ 6
- 2
src/pages/property/building/BatchImport.jsx 查看文件

1
 import React, { useRef, useState } from 'react'
1
 import React, { useRef, useState } from 'react'
2
-import { Button, Spin, Table, Icon, notification } from 'antd'
2
+import { Button, Spin, Table, Icon, notification, Modal } from 'antd'
3
 import router from 'umi/router'
3
 import router from 'umi/router'
4
 import { fetch, apis } from '@/utils/request'
4
 import { fetch, apis } from '@/utils/request'
5
 
5
 
61
 
61
 
62
     setLoading(true)
62
     setLoading(true)
63
     submitBuildingTreeExcel({ data: formData }).then(res => {
63
     submitBuildingTreeExcel({ data: formData }).then(res => {
64
-      notification.success({ message: '提交成功' })
64
+      
65
+      Modal.success({
66
+        title: '提交成功',
67
+        onOk: () => router.go(-1)
68
+      })
65
 
69
 
66
       setLoading(false)
70
       setLoading(false)
67
     }).catch(() => {
71
     }).catch(() => {

+ 1
- 1
src/pages/property/ticket/index.jsx 查看文件

159
           key="ticketTitle"
159
           key="ticketTitle"
160
           render={(_, row) => {
160
           render={(_, row) => {
161
             return (
161
             return (
162
-              <NavLink to={`/property/bill/ticket/detail?id=${row.id}`}>
162
+              <NavLink to={`/property/ticket/detail?id=${row.id}`}>
163
                 <Button type="link">{row.ticketTitle}</Button>
163
                 <Button type="link">{row.ticketTitle}</Button>
164
               </NavLink>
164
               </NavLink>
165
             )
165
             )

+ 124
- 0
src/pages/property/ticket/type/Editor.jsx 查看文件

1
+import React, { useEffect, useState } from 'react'
2
+import { Form, Input, Button, Radio, InputNumber, notification, Select } from 'antd'
3
+import router from 'umi/router'
4
+import { fetch, apis } from '@/utils/request'
5
+import ImageUpload from '@/components/uploadImage/ImageUpload'
6
+import EditableTagGroup from '@/components/EditableTagGroup'
7
+
8
+const formItemLayout = {
9
+  labelCol: {
10
+    xs: { span: 24 },
11
+    sm: { span: 6 },
12
+  },
13
+  wrapperCol: {
14
+    xs: { span: 24 },
15
+    sm: { span: 12 },
16
+  },
17
+}
18
+
19
+const tailFormItemLayout = {
20
+  wrapperCol: {
21
+    xs: {
22
+      span: 24,
23
+      offset: 0,
24
+    },
25
+    sm: {
26
+      span: 16,
27
+      offset: 6,
28
+    },
29
+  },
30
+}
31
+
32
+const getDetail = fetch(apis.ticket.repairType.getDetail)
33
+const saveType = fetch(apis.ticket.repairType.saveType)
34
+const updateType = fetch(apis.ticket.repairType.updateType)
35
+
36
+export default Form.create()(props => {
37
+  const [loading, setLoading] = useState(false)
38
+  const [detailData, setDetailData] = useState({})
39
+
40
+  const { id } = props.location.query
41
+  
42
+  const handleSubmit = e => {
43
+    // e.preventDefault();
44
+    props.form.validateFields((err, values) => {
45
+      if (!err) {
46
+        setLoading(true)
47
+        if (id) {
48
+          const data = {
49
+            ...(detailData || {}),
50
+            ...values,
51
+          }
52
+          updateType({data, urlData: {id}}).then(res => {
53
+            notification.success({ message: "修改内容成功" })
54
+            setLoading(false)
55
+          }).catch(err => {
56
+            setLoading(false)
57
+          })
58
+        } else {
59
+          saveType({data: values}).then(res => {
60
+            notification.success({ message: "保存内容成功" })
61
+            setLoading(false)
62
+            router.go(-1)
63
+          }).catch(err => {
64
+            setLoading(false)
65
+          })
66
+        }
67
+      }
68
+    });
69
+  }
70
+
71
+  useEffect(() => {
72
+    if (id) {
73
+      getDetail({urlData: {id}}).then(res => {
74
+        setDetailData(res)
75
+        props.form.setFieldsValue(res)
76
+      })
77
+    }
78
+  }, [id])
79
+  
80
+  return (
81
+    <div>
82
+      <Form {...formItemLayout} onSubmit={e => e.preventDefault()}>
83
+        <Form.Item label="名称">
84
+          {
85
+            props.form.getFieldDecorator('typeName', {
86
+              rules: [
87
+                { required: true, message: '请填写名称' },
88
+              ],
89
+            })(<Input placeholder="名称" />)
90
+          }
91
+        </Form.Item>
92
+        <Form.Item label="图标">
93
+          {
94
+            props.form.getFieldDecorator('icon')(<ImageUpload />)
95
+          }
96
+        </Form.Item>
97
+        <Form.Item label="快捷提问">
98
+          {
99
+            props.form.getFieldDecorator('tags')(<EditableTagGroup />)
100
+          }
101
+        </Form.Item>
102
+        <Form.Item label="排序">
103
+          {
104
+            props.form.getFieldDecorator('sortNum')(<InputNumber min={1} />)
105
+          }
106
+        </Form.Item>
107
+        <Form.Item label="状态">
108
+          {
109
+            props.form.getFieldDecorator('status')(
110
+              <Radio.Group>
111
+                <Radio value={0}>未发布</Radio>
112
+                <Radio value={1}>已发布</Radio>
113
+              </Radio.Group>
114
+            )
115
+          }
116
+        </Form.Item>
117
+        <Form.Item {...tailFormItemLayout} >
118
+          <Button loading={loading} type="primary" onClick={handleSubmit}>提交</Button>
119
+          <Button style={{ marginLeft: '24px' }} onClick={() => router.go(-1)}>取消</Button>
120
+        </Form.Item>
121
+      </Form>
122
+    </div>
123
+  )
124
+})

+ 99
- 0
src/pages/property/ticket/type/index.jsx 查看文件

1
+import React, { useState, useEffect } from 'react'
2
+import { Select, Spin, Table, Button, Form, Input, Divider, Popconfirm, Typography, notification } from 'antd'
3
+import NavLink from 'umi/navlink'
4
+import { fetchList, apis, fetch } from '@/utils/request'
5
+import Search from '../../components/Search'
6
+import List from '../../components/List'
7
+
8
+const StatusDict = [
9
+  {
10
+    label: '未发布',
11
+    value: 0,
12
+  },
13
+  {
14
+    label: '已发布',
15
+    value: 1,
16
+  },
17
+]
18
+
19
+const getDictValue = (dict, val) => (dict.filter(x => x.value === val)[0] || {}).label
20
+
21
+const getList = fetchList(apis.ticket.repairType.getList)
22
+const deleteType = fetch(apis.ticket.repairType.deleteType)
23
+
24
+export default props => {
25
+  const [loading, setLoading] = useState(false)
26
+  const [listData, setListData] = useState([])
27
+  const [pagination, setPagination] = useState({})
28
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
29
+
30
+  const handlePageChange = (pageNum, pageSize) => {
31
+    setQueryParams({
32
+      ...queryParams,      
33
+      pageNum,
34
+      pageSize,
35
+    })
36
+  }
37
+
38
+  const handleDeleteRow = row => {
39
+    deleteType({urlData: {id: row.typeId}}).then(res => {
40
+      notification.success({message: '删除数据成功'})
41
+      setQueryParams({...queryParams})
42
+    })
43
+  }
44
+
45
+  useEffect(() => {
46
+    setLoading(true)
47
+    getList({params: queryParams}).then(res => {
48
+      const [list, pagi] = res
49
+      setListData(list)
50
+      setPagination(pagi)
51
+      setLoading(false)
52
+    }).catch(e => setLoading(false))
53
+  }, [queryParams])
54
+
55
+  return (
56
+    <div>
57
+      <div style={{ margin: '24px 0' }}>
58
+        <NavLink to={`/property/repair-type/edit`}>
59
+          <Button type="primary">添加</Button>
60
+        </NavLink>
61
+      </div>
62
+      <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="typeId">
63
+        <Table.Column title="名称" dataIndex="typeName" key="typeName" />
64
+        <Table.Column
65
+          title="图标"
66
+          dataIndex="icon"
67
+          key="icon"
68
+          render={x => <img src={x} alt="" style={{width: '64px', height: '64px'}} />}
69
+        />
70
+        <Table.Column title="状态" dataIndex="status" key="status" render={x => getDictValue(StatusDict, x)} />
71
+        <Table.Column title="创建时间" dataIndex="createdTime" key="createdTime" />
72
+        <Table.Column title="最近操作时间" dataIndex="updatedTime" key="updatedTime" />
73
+        <Table.Column
74
+          title="操作"
75
+          key="action"
76
+          render={(_, row) => {
77
+            return (
78
+              <>
79
+                <Popconfirm
80
+                  title="确认进行删除操作?"
81
+                  onConfirm={() => handleDeleteRow(row)}
82
+                  okText="删除"
83
+                  cancelText="取消"
84
+                >
85
+                  <Button type="link">删除</Button>
86
+                </Popconfirm>
87
+                <Divider type="vertical" />
88
+                <NavLink to={`/property/repair-type/edit?id=${row.typeId}`}>
89
+                  <Button type="link">编辑</Button>
90
+                </NavLink>
91
+              </>
92
+            )
93
+          }}
94
+        />
95
+      </List>
96
+
97
+    </div>
98
+  )
99
+}

+ 74
- 43
src/pages/staff/list/editStaff.jsx 查看文件

184
       type: FieldTypes.Text,
184
       type: FieldTypes.Text,
185
       placeholder: '请输入职位',
185
       placeholder: '请输入职位',
186
       value: userData.position,
186
       value: userData.position,
187
-      rules: [
188
-        { required: true, message: '请输入职位' },
189
-      ]
187
+      // rules: [
188
+      //   { required: true, message: '请输入职位' },
189
+      // ]
190
     },
190
     },
191
     {
191
     {
192
-      label: '是否生活顾问',
193
-      name: 'isConsultant',
194
-      type: FieldTypes.Switch,
195
-      value: userData.isConsultant,
196
-      props: {disabled: userData.isConsultant},
192
+      label: '工号',
193
+      name: 'jobNumber',
194
+      type: FieldTypes.Text,
195
+      placeholder: '请输入工号',
196
+      value: userData.jobNumber,
197
+    },
198
+    // {
199
+    //   label: '是否生活顾问',
200
+    //   name: 'isConsultant',
201
+    //   type: FieldTypes.Switch,
202
+    //   value: userData.isConsultant,
203
+    //   props: {disabled: userData.isConsultant},
204
+    // },
205
+    {
206
+      label: '身份',
207
+      name: 'type',
208
+      type: FieldTypes.Select,
209
+      placeholder: '请选择身份',
210
+      value: userData.type,
211
+      rules: [
212
+        { required: true, message: '请选择身份' },
213
+      ],
214
+      dict: [
215
+        {
216
+          label: '生活管家',
217
+          value: 'life-consultant'
218
+        },
219
+        {
220
+          label: '物业相关',
221
+          value: 'prop'
222
+        },
223
+        {
224
+          label: '维修工人',
225
+          value: 'worker'
226
+        },
227
+      ]
197
     },
228
     },
198
     {
229
     {
199
       label: '电话',
230
       label: '电话',
209
         },
240
         },
210
       ]
241
       ]
211
     },
242
     },
243
+    {
244
+      label: '头像',
245
+      name: 'photo',
246
+      type: FieldTypes.ImageUploader,
247
+      extra: '建议图片尺寸:320*320px,比例1:1,格式:jpg,用于置业顾问头像,限制大小:100k',
248
+      value: userData.photo,
249
+      beforeUpload: (e) => photoBeforeUpload(e),
250
+      rules: [
251
+        { required: true, message: '请选择头像' },
252
+      ]
253
+    },
254
+    {
255
+      label: '简介',
256
+      name: 'description',
257
+      render: <TextArea className={channels.inpuitTxt} placeholder="生活管家请在此填写服务范围" ></TextArea>,
258
+      value: userData.description
259
+
260
+    },
261
+    {
262
+      label: '状态',
263
+      name: 'status',
264
+      render: <Radio.Group initialValue="1" buttonStyle="solid">
265
+        <Radio.Button value="9">禁用</Radio.Button>
266
+        <Radio.Button value="1">启用</Radio.Button>
267
+      </Radio.Group>,
268
+      value: userData.status != null ? userData.status.toString() : "1"
269
+    },
270
+    {
271
+      label: '权重',
272
+      name: 'weight',
273
+      type: FieldTypes.Number,
274
+      render: <Input type="number" style={{ width: 150}} />,
275
+      value: userData.weight,
276
+      help: '数字越大越靠前',
277
+    },
212
     {
278
     {
213
       label: '登录名',
279
       label: '登录名',
214
       name: 'loginName',
280
       name: 'loginName',
268
     //     { required: true, message: '请选择授权项目' },
334
     //     { required: true, message: '请选择授权项目' },
269
     //   ]
335
     //   ]
270
     // },
336
     // },
271
-    {
272
-      label: '生活顾问头像',
273
-      name: 'photo',
274
-      type: FieldTypes.ImageUploader,
275
-      extra: '建议图片尺寸:320*320px,比例1:1,格式:jpg,用于置业顾问头像,限制大小:100k',
276
-      value: userData.photo,
277
-      beforeUpload: (e) => photoBeforeUpload(e),
278
-      rules: [
279
-        { required: true, message: '请选择头像' },
280
-      ]
281
-    },
282
-    {
283
-      label: '简介',
284
-      name: 'description',
285
-      render: <TextArea className={channels.inpuitTxt} ></TextArea>,
286
-      value: userData.description
287
-
288
-    },
289
-    {
290
-      label: '状态',
291
-      name: 'status',
292
-      render: <Radio.Group initialValue="1" buttonStyle="solid">
293
-        <Radio.Button value="9">禁用</Radio.Button>
294
-        <Radio.Button value="1">启用</Radio.Button>
295
-      </Radio.Group>,
296
-      value: userData.status != null ? userData.status.toString() : "1"
297
-    },
298
-    {
299
-      label: '权重',
300
-      name: 'weight',
301
-      type: FieldTypes.Number,
302
-      render: <Input type="number" style={{ width: 150}} />,
303
-      value: userData.weight,
304
-      help: '数字越大越靠前',
305
-    },
306
   ]
337
   ]
307
 
338
 
308
   console.log('--------->', fields)
339
   console.log('--------->', fields)

+ 29
- 0
src/services/ticket_api.js 查看文件

47
       url: `${prefix}/endTicket`,
47
       url: `${prefix}/endTicket`,
48
       method: 'post',
48
       method: 'post',
49
       action: 'admin.ticket.endTicket'
49
       action: 'admin.ticket.endTicket'
50
+    },
51
+
52
+    repairType: {
53
+      getList: {
54
+        url: `${prefix}/tpRepairType`,
55
+        method: 'get',
56
+        action: 'admin.tpRepairType.list'
57
+      },
58
+      saveType: {
59
+        url: `${prefix}/tpRepairType`,
60
+        method: 'post',
61
+        action: 'admin.tpRepairType.save'
62
+      },
63
+      updateType: {
64
+        url: `${prefix}/tpRepairType/:id`,
65
+        method: 'put',
66
+        action: 'admin.tpRepairType.update'
67
+      },
68
+      deleteType: {
69
+        url: `${prefix}/tpRepairType/:id`,
70
+        method: 'delete',
71
+        action: 'admin.tpRepairType.delete'
72
+      },
73
+      getDetail: {
74
+        url: `${prefix}/tpRepairType/:id`,
75
+        method: 'get',
76
+        action: 'admin.tpRepairType.get'
77
+      },
78
+
50
     }
79
     }
51
   }
80
   }
52
 }
81
 }