Browse Source

refactor: 问卷管理

chenlei 1 year ago
parent
commit
ed8a519a3a

+ 70 - 36
src/pages/Questionnaire/components/topicDrawer.tsx

@@ -9,13 +9,22 @@ import {
   Switch,
   message,
 } from "antd";
+import { FC, useEffect, useRef, useState } from "react";
 // @ts-ignore
 import { v4 as uuidv4 } from "uuid";
-import { FC, useEffect, useRef, useState } from "react";
+
+export type AnswerType = {
+  answer: {
+    key: string;
+    val: number;
+    name?: string;
+    _save?: boolean;
+  }[];
+};
 
 export type QuestionType = {
   id: number;
-  answer: string;
+  answer: AnswerType | string;
   hasDiy: boolean;
   question: string;
   type: number;
@@ -31,6 +40,8 @@ export interface TopicDrawerProps {
   edit: (params: QuestionType) => void;
 }
 
+let id = 1;
+
 export const TopicDrawer: FC<TopicDrawerProps> = ({
   item,
   open,
@@ -42,43 +53,57 @@ export const TopicDrawer: FC<TopicDrawerProps> = ({
   const optionsFormRef = useRef<FormInstance>(null);
   const basicFormRef = useRef<FormInstance>(null);
 
-  const [options, setOptions] = useState<
-    {
-      val: string;
-      name?: string;
-    }[]
-  >([]);
+  const [options, setOptions] = useState<AnswerType["answer"]>([]);
 
   useEffect(() => {
-    if (item) {
+    if (item && open) {
       const { answer, ...rest } = item;
+      const a = (
+        typeof answer !== "string" ? answer : JSON.parse(answer as string)
+      ).answer.map((i: (typeof options)[0]) => ({
+        ...i,
+        val: Number(i.val),
+      }));
       basicFormRef.current?.setFieldsValue(rest);
 
-      setOptions(JSON.parse(answer).answer);
-    } else {
-      handleReset();
+      setOptions(a);
+      id = a[a.length - 1].val + 1;
     }
-  }, [item]);
+  }, [item, open]);
 
   const handleAddOption = () => {
     setOptions((prev) => [
       ...prev,
       {
-        val: uuidv4(),
+        val: id++,
+        key: uuidv4(),
       },
     ]);
   };
 
   const handleRemoveOption = (idx: number) => {
+    id -= 1;
     setOptions((prev) => {
-      prev.splice(idx, 1);
-      return [...prev];
+      const newList = [...prev];
+      newList.splice(idx, 1);
+      // 如果是新增的选项,被删除目标后面的选项id需要减一
+      // 保持与 `选项${idx + 1}` 一致
+      return newList.map((i, index) => ({
+        ...i,
+        val: !i._save && index >= idx ? i.val - 1 : i.val,
+      }));
     });
   };
 
+  useEffect(() => {
+    console.log(options);
+  }, [options]);
+
   const handleReset = () => {
-    setOptions([]);
+    id = 1;
+    optionsFormRef.current?.resetFields();
     basicFormRef.current?.resetFields();
+    setOptions([]);
   };
 
   const handleSubmit = async () => {
@@ -91,12 +116,14 @@ export const TopicDrawer: FC<TopicDrawerProps> = ({
     const vals = optionsFormRef.current?.getFieldsValue();
     const params: QuestionType = {
       ...basicFormRef.current?.getFieldsValue(),
-      answer: JSON.stringify({
-        answer: Object.keys(vals).map((val) => ({
-          val,
-          name: vals[val],
+      answer: {
+        answer: Object.keys(vals).map((key, index) => ({
+          val: options[index].val,
+          name: vals[key],
+          key: key,
+          _save: options[index]._save,
         })),
-      }),
+      },
     };
 
     if (!item) {
@@ -114,21 +141,26 @@ export const TopicDrawer: FC<TopicDrawerProps> = ({
       }
     }
 
-    close();
+    handleClose();
+  };
 
+  const handleClose = () => {
     handleReset();
+    close();
   };
 
   return (
     <Drawer
+      destroyOnClose
       title={item ? "编辑题目" : "新增题目"}
       placement="right"
       width={500}
       open={open}
-      onClose={close}
+      maskClosable={false}
+      onClose={handleClose}
       extra={
         <Space>
-          <Button onClick={close}>取消</Button>
+          <Button onClick={handleClose}>取消</Button>
           <Button loading={loading} type="primary" onClick={handleSubmit}>
             保存
           </Button>
@@ -177,7 +209,7 @@ export const TopicDrawer: FC<TopicDrawerProps> = ({
 
         {options.map((i, idx) => (
           <div
-            key={i.val}
+            key={i.key}
             style={{
               display: "flex",
               alignItems: "center",
@@ -185,7 +217,7 @@ export const TopicDrawer: FC<TopicDrawerProps> = ({
           >
             <Form.Item
               label={`选项${idx + 1}`}
-              name={i.val}
+              name={i.key}
               initialValue={i.name}
               rules={[{ required: true, message: "请输入" }]}
               style={{ flex: 1 }}
@@ -197,15 +229,17 @@ export const TopicDrawer: FC<TopicDrawerProps> = ({
               />
             </Form.Item>
 
-            <Button
-              type="text"
-              danger
-              size="small"
-              style={{ marginBottom: 24 }}
-              onClick={handleRemoveOption.bind(undefined, idx)}
-            >
-              删除
-            </Button>
+            {!i?._save && (
+              <Button
+                type="text"
+                danger
+                size="small"
+                style={{ marginBottom: 24 }}
+                onClick={handleRemoveOption.bind(undefined, idx)}
+              >
+                删除
+              </Button>
+            )}
           </div>
         ))}
       </Form>

+ 26 - 19
src/pages/Questionnaire/create-or-edit/index.tsx

@@ -11,7 +11,11 @@ import {
 } from "antd";
 import { useCallback, useEffect, useMemo, useRef, useState } from "react";
 import { useNavigate, useParams } from "react-router-dom";
-import { QuestionType, TopicDrawer } from "../components/topicDrawer";
+import {
+  AnswerType,
+  QuestionType,
+  TopicDrawer,
+} from "../components/topicDrawer";
 import { dayjs, formatDate } from "@dage/utils";
 import { questionaireApi } from "@/api";
 import { DageTableActions } from "@dage/pc-components";
@@ -84,26 +88,22 @@ export default function QuestionnaireCreateOrEditPage() {
     });
 
     const newList = list
-      .filter((i) => i._isNew)
-      .map((i) => ({
-        ...i,
-        id: undefined,
-        _isNew: undefined,
-        _isEdit: undefined,
-        questionnaireId: data.id,
-      }));
-
-    const editList = list
-      .filter((i) => i._isEdit)
-      .map((i) => ({
-        ...i,
-        _isNew: undefined,
-        _isEdit: undefined,
+      .filter((i) => i._isNew || i._isEdit)
+      .map(({ answer, id, _isNew, _isEdit, ...rest }) => ({
+        ...rest,
+        id: _isEdit ? id : undefined,
+        questionnaireId: _isNew ? data.id : undefined,
+        answer: JSON.stringify({
+          answer: (answer as AnswerType).answer.map((i) => ({
+            ...i,
+            _save: true,
+          })),
+        }),
       }));
 
-    if (editList.length || newList.length) {
+    if (newList.length) {
       // @ts-ignore
-      await questionaireApi.saveQuestions(editList.concat(newList));
+      await questionaireApi.saveQuestions(newList);
     }
 
     handleCancel();
@@ -148,31 +148,38 @@ export default function QuestionnaireCreateOrEditPage() {
     return [
       {
         title: "题目序号",
+        width: 100,
         render: (text: any, record: any, index: number) => {
           return <span>{index + 1}</span>;
         },
       },
       {
+        width: 140,
         title: "题目描述",
         dataIndex: "question",
       },
       {
         title: "选项",
-        dataIndex: "answer",
+        render: (item: QuestionType) => {
+          return JSON.stringify(item.answer);
+        },
       },
       {
         title: "类型",
+        width: 80,
         render: (item: QuestionType) => {
           return <span>{item.type === 1 ? "单选" : "多选"}</span>;
         },
       },
       {
         title: "允许自定义答案",
+        width: 140,
         render: (item: QuestionType) => {
           return <span>{item.hasDiy ? "是" : "否"}</span>;
         },
       },
       {
+        width: 120,
         title: "操作",
         render: (idx: number, item: QuestionType) => {
           return (