Sfoglia il codice sorgente

Merge branch 'master' of http://git.ycjcjy.com/civilized_city/pc-admin

fangmingyue 2 anni fa
parent
commit
dcec7681bd

+ 1
- 0
package.json Vedi File

@@ -17,6 +17,7 @@
17 17
     "antd": "^5.0.5",
18 18
     "axios": "^1.2.0",
19 19
     "classnames": "^2.3.2",
20
+    "dayjs": "^1.11.7",
20 21
     "echarts": "^5.4.0",
21 22
     "md5": "^2.3.0",
22 23
     "react": "18.1.0",

+ 3
- 3
src/components/Wangeditor/index.jsx Vedi File

@@ -12,11 +12,11 @@ const defaultStyle = {
12 12
 }
13 13
 
14 14
 function MyEditor(props) {
15
-
16 15
   const style = React.useMemo(() => ({ ...defaultStyle, ...(props.style || {}) }), [props.style])
17 16
 
18 17
   const {
19
-    value = "",
18
+    value = '',
19
+    height = '500px',
20 20
     onChange = (e) => {
21 21
       setHtml(e);
22 22
     },
@@ -76,7 +76,7 @@ function MyEditor(props) {
76 76
         onCreated={setEditor}
77 77
         onChange={handleChange}
78 78
         mode="default"
79
-        style={{ height: "500px" }}
79
+        style={{ height }}
80 80
       />
81 81
     </div>
82 82
   ) : (

+ 6
- 1
src/main.jsx Vedi File

@@ -1,11 +1,16 @@
1 1
 import React from 'react'
2 2
 import ReactDOM from 'react-dom/client'
3
+import 'dayjs/locale/zh-cn';
4
+import locale from 'antd/locale/zh_CN';
5
+import { ConfigProvider } from 'antd';
3 6
 import Router from './routes/Router'
4 7
 import './index.less'
5 8
 import { Provider } from './store'
6 9
 
7 10
 ReactDOM.createRoot(document.getElementById('root')).render(
8 11
   <Provider>
9
-    <Router />
12
+    <ConfigProvider locale={locale}>
13
+      <Router />
14
+    </ConfigProvider>
10 15
   </Provider>
11 16
 )

+ 40
- 0
src/pages/check/Edit.jsx Vedi File

@@ -0,0 +1,40 @@
1
+import React from 'react';
2
+import { Row, Col, Card, Button } from 'antd';
3
+import { PlusOutlined } from '@ant-design/icons';
4
+import Page from '@/components/Page';
5
+import CheckForm from './components/CheckForm';
6
+import { useSearchParams } from 'react-router-dom';
7
+import { getTaCheckById } from '@/service/tacheck';
8
+import LocForm from './components/LocForm';
9
+
10
+export default (props) => {
11
+  const [searchParams] = useSearchParams();
12
+
13
+  const [checkInfo, setCheckInfo] = React.useState();
14
+  const locRef = React.useRef();
15
+
16
+  const id = searchParams.get('id');
17
+
18
+  React.useEffect(() => {
19
+    if (id) {
20
+      getTaCheckById(id).then(setCheckInfo);
21
+    }
22
+  }, [id]);
23
+
24
+  return (
25
+    <Page>
26
+      <CheckForm checkInfo={checkInfo} onChange={setCheckInfo} />
27
+      <Row gutter={24} style={{marginTop: '24px'}}>
28
+        <Col span={12}>
29
+          <Card title="实例调查" extra={<Button icon={<PlusOutlined />} onClick={() => locRef.current.newQu()}>问题</Button>}>
30
+            <LocForm ref={locRef} checkId={id} />
31
+          </Card>
32
+        </Col>
33
+        <Col span={12}>
34
+          <Card title="问卷调查">
35
+          </Card>
36
+        </Col>
37
+      </Row>
38
+    </Page>
39
+  )
40
+}

+ 68
- 0
src/pages/check/components/CheckForm.jsx Vedi File

@@ -0,0 +1,68 @@
1
+import React from 'react';
2
+import dayjs from 'dayjs';
3
+import { Row, Col, Button, Form, Input, DatePicker } from 'antd';
4
+import { ModalForm } from '@ant-design/pro-components';
5
+import { postTaCheck, putTaCheck } from '@/service/tacheck';
6
+
7
+export default (props) => {
8
+  const { checkInfo, onChange } = props;
9
+
10
+  const [open, setOpen] = React.useState(false);
11
+  const [form] = Form.useForm();
12
+
13
+  const title = checkInfo ? checkInfo.title : '点击编辑创建';
14
+  const dateStr = checkInfo ? `${checkInfo.startDate} ~ ${checkInfo.endDate}` : '';
15
+
16
+  const onFinish = async (values) => {
17
+    const data = {
18
+      ...values,
19
+      startDate: dayjs(values.startDate).format('YYYY-MM-DD'),
20
+      endDate: dayjs(values.endDate).format('YYYY-MM-DD'),
21
+    }
22
+
23
+    if (!checkInfo) {
24
+      const res = await postTaCheck(data);
25
+      onChange(res);
26
+    } else {
27
+      const res = await putTaCheck(checkInfo.checkId, data);
28
+      onChange(res);
29
+    }
30
+
31
+    return true;
32
+  }
33
+
34
+  React.useEffect(() => {
35
+    if (checkInfo) {
36
+      form.setFieldsValue({
37
+        ...checkInfo,
38
+        startDate: dayjs(checkInfo.startDate),
39
+        endDate: dayjs(checkInfo.endDate),
40
+      });
41
+    }
42
+  }, [checkInfo]);
43
+
44
+  return (
45
+    <Row gutter={48}>
46
+      <Col span={18}>
47
+        <h2 style={{ textAlign: 'center' }} >{title}</h2>
48
+        <Row>
49
+          <Col span={8} offset={16}>{dateStr}</Col>
50
+        </Row>
51
+      </Col>
52
+      <Col span={4}>
53
+        <Button onClick={() => setOpen(true)}>编辑</Button>
54
+      </Col>
55
+      <ModalForm title="测评维护" open={open} width={480} form={form} onFinish={onFinish} onOpenChange={setOpen}>
56
+          <Form.Item name="title" label="测评名称" required>
57
+            <Input placeholder="请输入测评名称" />
58
+          </Form.Item>
59
+          <Form.Item name="startDate" label="开始时间" required>
60
+            <DatePicker placeholder="请选择" style={{ width: '100%' }} />
61
+          </Form.Item>
62
+          <Form.Item name="endDate" label="结束时间" required>
63
+            <DatePicker placeholder="请选择" style={{ width: '100%' }} />
64
+          </Form.Item>
65
+      </ModalForm>
66
+    </Row>
67
+  )
68
+}

+ 123
- 0
src/pages/check/components/LocForm.jsx Vedi File

@@ -0,0 +1,123 @@
1
+import React from 'react';
2
+import { Button, Tabs, Form, Row, Col, InputNumber, message } from 'antd';
3
+import useBool from '@/utils/hooks/useBool';
4
+import { getTdLocType } from '@/service/tdloctype';
5
+import { getByCheckId, postTaCheckItem } from '@/service/tacheckitem';
6
+import QuManage from './QuManage';
7
+
8
+const ItemForm = (props) => {
9
+  const {checkId, typeId, onChange} = props;
10
+
11
+  const [form] = Form.useForm();
12
+  const [loading, startLoading, stopLoading] = useBool();
13
+
14
+  const onFinish = (values) => {
15
+    const data = {...values, checkId, typeId, itemType: 'loc'}
16
+
17
+    startLoading();
18
+    postTaCheckItem(data).then(res => {
19
+      onChange(res);
20
+      form.setFieldsValue(res);
21
+      stopLoading();
22
+    }).catch(() => {
23
+      stopLoading();
24
+    });
25
+  }
26
+
27
+  const reset = () => {
28
+    form.resetFields();
29
+    form.setFieldsValue({ num: 1 });
30
+    onChange();
31
+  }
32
+
33
+  React.useEffect(() => {
34
+    if (checkId && typeId) {
35
+      startLoading();
36
+      getByCheckId(checkId, typeId).then(res => {
37
+        if (res) {
38
+          onChange(res);
39
+          form.setFieldsValue(res);
40
+        } else {
41
+          reset();
42
+        }
43
+        stopLoading();
44
+      }).catch(() => {
45
+        stopLoading();
46
+        reset();
47
+      });
48
+    } else {
49
+      reset();
50
+    }
51
+  }, [checkId, typeId]);
52
+
53
+  return (
54
+    <Form layout="inline" form={form} onFinish={onFinish}>
55
+      <Form.Item label="数量" name="num">
56
+        <InputNumber min={1} />
57
+      </Form.Item>
58
+      <Form.Item label="总分" name="fullScore">
59
+        <InputNumber min={0.00} precision={2} />
60
+      </Form.Item>
61
+      <Form.Item>
62
+        <Button disabled={!checkId || !typeId} loading={loading} type="primary" htmlType="submit">
63
+          确定
64
+        </Button>
65
+      </Form.Item>
66
+    </Form>
67
+  )
68
+}
69
+
70
+export default React.forwardRef((props, ref) => {
71
+  const {checkId} = props;
72
+  const [locList, setLocList] = React.useState([]);
73
+  const quRef = React.useRef();
74
+  const [checkItem, setCheckItem] = React.useState();
75
+  const [typeId, setTypeId] = React.useState();
76
+
77
+  const tabItems = React.useMemo(() => {
78
+    return locList.map(x => ({
79
+      label: x.name,
80
+      key: x.typeId,
81
+    }));
82
+  }, [locList]);
83
+
84
+  React.useEffect(() => {
85
+    getTdLocType({ pageSize: 500 }).then(res => {
86
+      const list = res.records;
87
+      setLocList(list);
88
+      // 默认第一个
89
+      setTypeId(list[0]?.typeId);
90
+    });
91
+  }, []);
92
+
93
+  
94
+  React.useImperativeHandle(ref, () => ({
95
+    newQu: () => {
96
+      if (!checkItem) {
97
+        message.warning('请先设置数量, 总分等');
98
+        return;
99
+      }
100
+      quRef.current.add();
101
+    },
102
+  }), [checkItem]);
103
+
104
+  return (
105
+    <div style={{display: 'flex'}}>
106
+      <div style={{flex: 'none'}}>
107
+        <Tabs
108
+          tabPosition="left"
109
+          activeKey={typeId}
110
+          items={tabItems}
111
+          onChange={(activeKey) => {
112
+            setTypeId(activeKey)
113
+            setCheckItem()
114
+          }}
115
+        />
116
+      </div>
117
+      <div style={{flex: 1}}>
118
+        <ItemForm checkId={checkId} typeId={typeId} onChange={setCheckItem} />
119
+        <QuManage ref={quRef} itemId={checkItem?.itemId} />
120
+      </div>
121
+    </div>
122
+  )
123
+})

+ 193
- 0
src/pages/check/components/QuManage.jsx Vedi File

@@ -0,0 +1,193 @@
1
+import React from 'react';
2
+import { Button, Form, Row, Col, Input, Modal, List } from 'antd';
3
+import {
4
+  DrawerForm,
5
+  ProFormGroup,
6
+  ProFormText,
7
+  ProFormSelect,
8
+  ProFormDigit,
9
+  ProFormList
10
+} from '@ant-design/pro-components';
11
+import WangEditor from '@/components/Wangeditor';
12
+import { postTaCheckItemQu, getTaCheckItemQu } from '@/service/tdlocquestion';
13
+
14
+export default React.forwardRef((props, ref) => {
15
+
16
+  const { itemId, onChange } = props;
17
+  
18
+  const [open, setOpen] = React.useState(false);
19
+  const [quInfo, setQuInfo] = React.useState(false);
20
+  const [list, setList] = React.useState([]);
21
+  const [form] = Form.useForm();
22
+
23
+  const onFinish = async (values) => {
24
+    const data = { ...(quInfo || {}), ...values, itemId }
25
+    const res = await postTaCheckItemQu(data);
26
+    onChange(res);
27
+
28
+    return true;
29
+  }
30
+
31
+  React.useEffect(() => {
32
+    if (quInfo) {
33
+      form.setFieldsValue(quInfo);
34
+    }
35
+  }, [quInfo]);
36
+
37
+  React.useEffect(() => {
38
+    if (itemId) {
39
+      getTaCheckItemQu({pageSize: 500, itemId}).then((res) => {
40
+        setList(res.records);
41
+      });
42
+    }
43
+  }, [itemId]);
44
+
45
+  React.useImperativeHandle(ref, () => ({
46
+    add: () => setOpen(true),
47
+  }), []);
48
+
49
+  return (
50
+    <div>
51
+      <DrawerForm title="问题维护" open={open} width={800} form={form} onFinish={onFinish} onOpenChange={setOpen}>
52
+        <ProFormText
53
+          name="title"
54
+          label="题干描述"
55
+          placeholder="请填写"
56
+          rules={[
57
+            {
58
+              required: true,
59
+              message: '请填写题干',
60
+            },
61
+          ]}
62
+        />
63
+        <Row gutter={24}>
64
+          <Col span={12}>
65
+            <ProFormSelect
66
+              name="quType"
67
+              label="问题类型"
68
+              fieldProps={{
69
+                style: { width: '100%' }
70
+              }}
71
+              valueEnum={{
72
+                radio: '单选',
73
+                fill: '填空'
74
+              }}
75
+              rules={[
76
+                {
77
+                  required: true,
78
+                  message: '请选择问题类型',
79
+                },
80
+              ]}
81
+            />
82
+          </Col>
83
+          <Col span={12}>
84
+            <ProFormSelect
85
+              name="computeType"
86
+              label="计分方式"
87
+              fieldProps={{
88
+                style: { width: '100%' }
89
+              }}
90
+              valueEnum={{
91
+                '+': '得分',
92
+                '-': '扣分'
93
+              }}
94
+              rules={[
95
+                {
96
+                  required: true,
97
+                  message: '请选择计分方式',
98
+                },
99
+              ]}
100
+            />
101
+          </Col>
102
+        </Row>
103
+        <Row gutter={24}>
104
+          <Col span={12}>
105
+            <ProFormDigit
106
+              name="maxScore"
107
+              label="最 高 分"
108
+              min={0}
109
+              fieldProps={{ precision: 2 }}
110
+              rules={[
111
+                {
112
+                  required: true,
113
+                  message: '请设置最高分',
114
+                },
115
+              ]}
116
+            />
117
+          </Col>
118
+          <Col span={12}>
119
+            <ProFormDigit
120
+              name="anScore"
121
+              label="单项计分"
122
+              min={0}
123
+              fieldProps={{ precision: 2 }}
124
+              rules={[
125
+                {
126
+                  required: true,
127
+                  message: '请设置单项计分',
128
+                },
129
+              ]}
130
+            />
131
+          </Col>
132
+        </Row>
133
+        <Form.Item name="stand" label="评分标准">
134
+          <WangEditor
135
+            height="200px"
136
+            toolbarConfig={{
137
+              toolbarKeys: [
138
+                'headerSelect',
139
+                'blockquote',
140
+                '|',
141
+                'bold',
142
+                'underline',
143
+                'italic',
144
+                'color',
145
+                'fontSize',
146
+                '|',
147
+                'bulletedList',
148
+                'numberedList',
149
+              ]
150
+            }}
151
+          />
152
+        </Form.Item>
153
+        <ProFormList
154
+          name="answerList"
155
+          label="选项列表"
156
+          copyIconProps={false}
157
+        >
158
+          <Row gutter={24} style={{width: '730px'}}>
159
+            <Col span={6}>
160
+              <ProFormText
161
+                name="answerCode"
162
+                label="选项"
163
+                help="类似 A, B, C, D"
164
+              />
165
+            </Col>
166
+            <Col span={6}>
167
+              <ProFormDigit
168
+                name="score"
169
+                label="计分"
170
+                min={0}
171
+                fieldProps={{ precision: 2 }}
172
+              />
173
+            </Col>
174
+            <Col span={12}>
175
+              <ProFormText
176
+                name="answer"
177
+                label="答案"
178
+                placeholder="具体选项内容"
179
+              />
180
+            </Col>
181
+          </Row>
182
+        </ProFormList>
183
+      </DrawerForm>
184
+      <List
185
+        itemLayout="horizontal"
186
+        dataSource={list}
187
+        renderItem={(item) => (
188
+          item.title
189
+        )}
190
+      />
191
+    </div>
192
+  )
193
+});

+ 107
- 0
src/pages/check/index.jsx Vedi File

@@ -0,0 +1,107 @@
1
+import React from 'react';
2
+import Page from '@/components/Page';
3
+import { useNavigate } from 'react-router-dom';
4
+import { queryTable } from "@/utils/request";
5
+import { ProTable } from "@ant-design/pro-components";
6
+import { Button, message, Popconfirm } from "antd";
7
+import { getTaCheck } from '@/service/tacheck';
8
+
9
+const queryList = queryTable(getTaCheck);
10
+
11
+export default (props) => {
12
+
13
+  const navigate = useNavigate();
14
+  const actionRef = React.useRef();
15
+
16
+  const columns = [
17
+    {
18
+      title: "测评名称",
19
+      dataIndex: "title",
20
+    },
21
+    {
22
+      title: "开始日期",
23
+      dataIndex: "startDate",
24
+    },
25
+    {
26
+      title: "结束日期",
27
+      dataIndex: "endDate",
28
+    },
29
+    {
30
+      title: "状态",
31
+      dataIndex: "status",
32
+      search: false,
33
+      valueEnum: {
34
+        1: {
35
+          text: "正常",
36
+          status: "Processing",
37
+        },
38
+        0: {
39
+          text: "禁用",
40
+          status: "Error",
41
+        },
42
+      },
43
+    },
44
+    {
45
+      title: "操作",
46
+      valueType: "option",
47
+      width: 200,
48
+      render: (_, record) => [
49
+        <Button
50
+          key={1}
51
+          style={{ padding: 0 }}
52
+          type="link"
53
+          onClick={() => {
54
+            updateStatus(record);
55
+          }}
56
+        >
57
+          {record.status === 1 ? "禁用" : "启用"}
58
+        </Button>,
59
+        <Button
60
+          key={2}
61
+          style={{ padding: 0 }}
62
+          type="link"
63
+          onClick={() => {
64
+            console.log(record, "]]");
65
+            navigate(`/check/edit?id=${record.checkId}`);
66
+          }}
67
+        >
68
+          编辑
69
+        </Button>,
70
+        <Popconfirm
71
+          key={3}
72
+          title="您是否确认删除 ?"
73
+          onConfirm={() => handleDelete(record.checkId)}
74
+          okText="确定"
75
+          cancelText="取消"
76
+        >
77
+          {/* manualPush */}
78
+          <Button style={{ padding: 0 }} type="link">
79
+            删除
80
+          </Button>
81
+        </Popconfirm>,
82
+      ],
83
+    },
84
+  ]
85
+
86
+  return (
87
+    <Page>
88
+      <ProTable
89
+        actionRef={actionRef}
90
+        rowKey="checkId"
91
+        toolBarRender={() => [
92
+          <Button
93
+            key="1"
94
+            type="primary"
95
+            onClick={() => {
96
+              navigate("/check/edit");
97
+            }}
98
+          >
99
+            新增
100
+          </Button>,
101
+        ]}
102
+        request={queryList}
103
+        columns={columns}
104
+      />
105
+    </Page>
106
+  )
107
+}

+ 32
- 2
src/routes/routes.jsx Vedi File

@@ -5,7 +5,7 @@ import {
5 5
   MailOutlined,
6 6
   MenuFoldOutlined,
7 7
   MenuUnfoldOutlined,
8
-  PieChartOutlined,
8
+  ProjectOutlined,
9 9
   SettingOutlined,
10 10
 } from '@ant-design/icons';
11 11
 import { Outlet } from 'react-router-dom';
@@ -15,7 +15,8 @@ import Page404 from '@/pages/404';
15 15
 import Role from '@/pages/role/index';
16 16
 import User from '@/pages/user/index';
17 17
 import UserEdit from '@/pages/user/Edit';
18
-
18
+import CheckList from '@/pages/check';
19
+import CheckEdit from '@/pages/check/Edit';
19 20
 
20 21
 import Index from '@/pages/index';
21 22
 import Home from "@/pages/sample/home";
@@ -145,6 +146,35 @@ export const authRoutes = [
145 146
       },
146 147
     ]
147 148
   },
149
+  {
150
+    path: "check",
151
+    element: <Outlet />,
152
+    meta: {
153
+      title: '模拟测评',
154
+      icon: <ProjectOutlined />,
155
+      // permission: 'form',
156
+    },
157
+    children: [
158
+      {
159
+        index: true,
160
+        element: <CheckList />,
161
+      },
162
+      {
163
+        path: "list",
164
+        element: <CheckList />,
165
+        meta: {
166
+          title: '测评列表',
167
+        }
168
+      },
169
+      {
170
+        path: "edit",
171
+        element: <CheckEdit />,
172
+        meta: {
173
+          title: '测评维护',
174
+        }
175
+      }
176
+    ]
177
+  }
148 178
 
149 179
   // {
150 180
   //   path: "form",

+ 5
- 5
src/service/tacheck.js Vedi File

@@ -3,24 +3,24 @@ import request from '@/utils/request';
3 3
 /*
4 4
  * 分页查询
5 5
  */
6
-export const getTaMockCheck = (params) => request('/api/taMockCheck', { params });
6
+export const getTaCheck = (params) => request('/api/taCheck', { params });
7 7
 
8 8
 /*
9 9
  * 新增数据
10 10
  */
11
-export const postTaMockCheck = (data) => request('/api/taMockCheck', { data, method: 'post' });
11
+export const postTaCheck = (data) => request('/api/taCheck', { data, method: 'post' });
12 12
 
13 13
 /*
14 14
  * 通过ID查询单条数据
15 15
  */
16
-export const getTaMockCheckById = (id) => request(`/api/taMockCheck/${id}`);
16
+export const getTaCheckById = (id) => request(`/api/taCheck/${id}`);
17 17
 
18 18
 /*
19 19
  * 更新数据
20 20
  */
21
-export const putTaMockCheck = (id, data) => request(`/api/taMockCheck/${id}`, { data, method: 'put' });
21
+export const putTaCheck = (id, data) => request(`/api/taCheck/${id}`, { data, method: 'put' });
22 22
 
23 23
 /*
24 24
  * 通过主键删除数据
25 25
  */
26
-export const deleteTaMockCheck = (id) => request(`/api/taMockCheck/${id}`, { method: 'delete' });
26
+export const deleteTaCheck = (id) => request(`/api/taCheck/${id}`, { method: 'delete' });

+ 9
- 0
src/service/tacheckitem.js Vedi File

@@ -24,3 +24,12 @@ export const putTaCheckItem = (id, data) => request(`/api/taCheckItem/${id}`, {
24 24
  * 通过主键删除数据
25 25
  */
26 26
 export const deleteTaCheckItem = (id) => request(`/api/taCheckItem/${id}`, { method: 'delete' });
27
+
28
+
29
+/**
30
+ * 通过测评ID,点位ID查询详情
31
+ * @param {*} checkId 
32
+ * @param {*} typeId 
33
+ * @returns 
34
+ */
35
+export const getByCheckId = (checkId, typeId) => request(`/api/taCheck/${checkId}/item/${typeId}`)

+ 23
- 0
src/utils/form.js Vedi File

@@ -0,0 +1,23 @@
1
+
2
+export const formItemLayout = {
3
+  labelCol: {
4
+    xs: { span: 24 },
5
+    sm: { span: 8 },
6
+  },
7
+  wrapperCol: {
8
+    xs: { span: 24 },
9
+    sm: { span: 16 },
10
+  },
11
+};
12
+export const tailFormItemLayout = {
13
+  wrapperCol: {
14
+    xs: {
15
+      span: 24,
16
+      offset: 0,
17
+    },
18
+    sm: {
19
+      span: 16,
20
+      offset: 8,
21
+    },
22
+  },
23
+};