|
@@ -0,0 +1,420 @@
|
|
|
+import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
+import styles from "./index.module.scss";
|
|
|
+import { Button, Checkbox, Input, Modal, Select } from "antd";
|
|
|
+import MyPopconfirm from "@/components/MyPopconfirm";
|
|
|
+import { A6QListType, options1, options2 } from "../data";
|
|
|
+import { MessageFu } from "@/utils/message";
|
|
|
+import TextArea from "antd/es/input/TextArea";
|
|
|
+import { CloseCircleOutlined } from "@ant-design/icons";
|
|
|
+import classNames from "classnames";
|
|
|
+
|
|
|
+const oneObj: A6QListType = {
|
|
|
+ id: 1,
|
|
|
+ name: "",
|
|
|
+ type: "单选",
|
|
|
+ skip: "不需要",
|
|
|
+ custom: false,
|
|
|
+ num: 1,
|
|
|
+ sList: [
|
|
|
+ { id: 1.1, txt: "", skip2: false, num2: 1 },
|
|
|
+ { id: 1.2, txt: "", skip2: false, num2: 1 },
|
|
|
+ ],
|
|
|
+};
|
|
|
+
|
|
|
+type Props = {
|
|
|
+ moId: number;
|
|
|
+ closeFu: () => void;
|
|
|
+ tableLen: number;
|
|
|
+};
|
|
|
+
|
|
|
+function QTadd({ moId, closeFu, tableLen }: Props) {
|
|
|
+ const getInfoFu = useCallback(async (id: number) => {}, []);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (moId > 0) getInfoFu(moId);
|
|
|
+ else {
|
|
|
+ // 新增
|
|
|
+ setList([oneObj]);
|
|
|
+ }
|
|
|
+ }, [getInfoFu, moId]);
|
|
|
+
|
|
|
+ // 是否 已经点击过确定
|
|
|
+ const [fileCheck, setFileCheck] = useState(false);
|
|
|
+
|
|
|
+ // 题目的数组
|
|
|
+ const [list, setList] = useState<A6QListType[]>([]);
|
|
|
+
|
|
|
+ // 点击新增题目
|
|
|
+ const addListFu = useCallback(
|
|
|
+ (rank: 1 | 2, length?: number) => {
|
|
|
+ if (rank === 1 && list.length + tableLen >= 50)
|
|
|
+ return MessageFu.warning("最多支持50题!");
|
|
|
+ if (length && length >= 6) return MessageFu.warning("最多6个选项!");
|
|
|
+ if (rank === 1) {
|
|
|
+ setList([
|
|
|
+ ...list,
|
|
|
+ {
|
|
|
+ id: Date.now(),
|
|
|
+ name: "",
|
|
|
+ type: "单选",
|
|
|
+ skip: "不需要",
|
|
|
+ custom: false,
|
|
|
+ num: 1,
|
|
|
+ sList: [
|
|
|
+ { id: Date.now(), txt: "", skip2: false, num2: 1 },
|
|
|
+ { id: Date.now() + 1, txt: "", skip2: false, num2: 1 },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ setList(
|
|
|
+ list.map((v) => ({
|
|
|
+ ...v,
|
|
|
+ sList: [
|
|
|
+ ...v.sList,
|
|
|
+ { id: Date.now(), txt: "", skip2: false, num2: 1 },
|
|
|
+ ],
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [list, tableLen]
|
|
|
+ );
|
|
|
+
|
|
|
+ // 点击删除
|
|
|
+ const delListFu = useCallback(
|
|
|
+ (rank: 1 | 2, id: number) => {
|
|
|
+ if (rank === 1) {
|
|
|
+ setList(list.filter((v) => v.id !== id));
|
|
|
+ } else {
|
|
|
+ setList(
|
|
|
+ list.map((v) => ({
|
|
|
+ ...v,
|
|
|
+ sList: v.sList.filter((v2) => v2.id !== id),
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [list]
|
|
|
+ );
|
|
|
+
|
|
|
+ // 信息的改变(去掉跳题)
|
|
|
+ const dataChangeFu = useCallback(
|
|
|
+ (
|
|
|
+ e: string | boolean,
|
|
|
+ id: number,
|
|
|
+ key: "name" | "type" | "skip" | "custom" | "txt" | "skip2",
|
|
|
+ index: number
|
|
|
+ ) => {
|
|
|
+ let value: string | boolean;
|
|
|
+ if (typeof e === "string") value = e.replace(/\s+/g, "");
|
|
|
+ else value = e;
|
|
|
+
|
|
|
+ let num = index;
|
|
|
+ if (index === 0) num = 2;
|
|
|
+ else num = 1;
|
|
|
+
|
|
|
+ // 第二级信息的改变
|
|
|
+ if (key === "txt" || key === "skip2") {
|
|
|
+ setList(
|
|
|
+ list.map((v) => ({
|
|
|
+ ...v,
|
|
|
+ sList: v.sList.map((v2) => ({
|
|
|
+ ...v2,
|
|
|
+ num2: id === v2.id ? num : v2.num2,
|
|
|
+ [key]: id === v2.id ? value : v2[key],
|
|
|
+ })),
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // 第一级信息的改变
|
|
|
+
|
|
|
+ setList(
|
|
|
+ list.map((v) => ({
|
|
|
+ ...v,
|
|
|
+ num: id === v.id ? num : v.num,
|
|
|
+ [key]: id === v.id ? value : v[key],
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [list]
|
|
|
+ );
|
|
|
+
|
|
|
+ // 跳题的改变
|
|
|
+ const skipChangeFu = useCallback(
|
|
|
+ (e: number, id: number, len: 1 | 2) => {
|
|
|
+ if (len === 1) {
|
|
|
+ setList(
|
|
|
+ list.map((v) => ({
|
|
|
+ ...v,
|
|
|
+ num: id === v.id ? e : v.num,
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ setList(
|
|
|
+ list.map((v) => ({
|
|
|
+ ...v,
|
|
|
+ sList: v.sList.map((v2) => ({
|
|
|
+ ...v2,
|
|
|
+ num2: v2.id === id ? e : v2.num2,
|
|
|
+ })),
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [list]
|
|
|
+ );
|
|
|
+
|
|
|
+ // 跳题的数组
|
|
|
+ const numList = useMemo(() => {
|
|
|
+ let arr: number[] = [];
|
|
|
+ for (let ii = 0; ii < list.length; ii++) {
|
|
|
+ arr.push(ii + 1);
|
|
|
+ }
|
|
|
+ return arr;
|
|
|
+ }, [list.length]);
|
|
|
+
|
|
|
+ // 单个题目是否全部填写标准
|
|
|
+ const oneFlag = useCallback((info: A6QListType) => {
|
|
|
+ let flag = false;
|
|
|
+
|
|
|
+ if (!info.name) flag = true;
|
|
|
+ else if (info.type !== "填空") {
|
|
|
+ flag = info.sList.some((v) => !v.txt);
|
|
|
+ }
|
|
|
+
|
|
|
+ return flag;
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ // 点击提交
|
|
|
+ const btnOkFu = useCallback(() => {
|
|
|
+ setFileCheck(true);
|
|
|
+
|
|
|
+ // 待完善
|
|
|
+ if (!fileCheck) return MessageFu.warning("请规范填写题目信息!");
|
|
|
+
|
|
|
+ const dom = document.querySelector(".A6Qlist2SonErr");
|
|
|
+ if (dom) return MessageFu.warning("请规范填写题目信息!");
|
|
|
+ }, [fileCheck]);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Modal
|
|
|
+ wrapClassName={styles.QTadd}
|
|
|
+ open={true}
|
|
|
+ title={
|
|
|
+ <div className="QTatitle">
|
|
|
+ <div>{moId > 0 ? "编辑" : "新增"}题目</div>
|
|
|
+ <div>
|
|
|
+ <span className="QTatitleS">
|
|
|
+ 最多支持50题,还能新增{50 - tableLen - list.length}题
|
|
|
+ </span>
|
|
|
+  
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
+ onClick={() => addListFu(1)}
|
|
|
+ disabled={tableLen + list.length >= 50}
|
|
|
+ >
|
|
|
+ 新增
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ footer={
|
|
|
+ [] // 设置footer为空,去掉 取消 确定默认按钮
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <div className="QTmain">
|
|
|
+ <div className="A6Qlist">
|
|
|
+ <div className="A6Qlist2">
|
|
|
+ {list.map((v, i) => (
|
|
|
+ <div
|
|
|
+ className={classNames(
|
|
|
+ "A6Qlist2Son",
|
|
|
+ oneFlag(v) && fileCheck ? "A6Qlist2SonErr" : ""
|
|
|
+ )}
|
|
|
+ key={v.id}
|
|
|
+ >
|
|
|
+ {/* 1级 删除 */}
|
|
|
+ {i === 0 ? null : (
|
|
|
+ <MyPopconfirm
|
|
|
+ txtK="删除"
|
|
|
+ onConfirm={() => delListFu(1, v.id)}
|
|
|
+ Dom={
|
|
|
+ <div className="A6Q2del">
|
|
|
+ <CloseCircleOutlined rev={undefined} />
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 题目 */}
|
|
|
+ <div className="A6Q2_1">
|
|
|
+ <div>
|
|
|
+ <span>*</span> 题目 {i + 1}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <TextArea
|
|
|
+ value={v.name}
|
|
|
+ onChange={(e) =>
|
|
|
+ dataChangeFu(e.target.value, v.id, "name", i)
|
|
|
+ }
|
|
|
+ className="A6text"
|
|
|
+ placeholder="请输入内容"
|
|
|
+ showCount
|
|
|
+ maxLength={200}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="A6Q2_2">
|
|
|
+ {/* 类型 跳题 自定义 */}
|
|
|
+ <div>
|
|
|
+ 类型 
|
|
|
+ <Select
|
|
|
+ disabled={v.skip === "选项跳题"}
|
|
|
+ value={v.type}
|
|
|
+ onChange={(e) => dataChangeFu(e, v.id, "type", i)}
|
|
|
+ placeholder="请选择"
|
|
|
+ style={{ width: 100 }}
|
|
|
+ options={options1}
|
|
|
+ />
|
|
|
+   跳题 
|
|
|
+ <Select
|
|
|
+ value={v.skip}
|
|
|
+ onChange={(e) => dataChangeFu(e, v.id, "skip", i)}
|
|
|
+ placeholder="请选择"
|
|
|
+ style={{ width: 100 }}
|
|
|
+ options={
|
|
|
+ v.type === "单选"
|
|
|
+ ? options2
|
|
|
+ : options2.filter((c) => c.label !== "选项跳题")
|
|
|
+ }
|
|
|
+ />
|
|
|
+ <span hidden={v.skip !== "答完跳题"}>
|
|
|
+   跳至第 
|
|
|
+ <Select
|
|
|
+ value={v.num}
|
|
|
+ onChange={(e) => skipChangeFu(e, v.id, 1)}
|
|
|
+ placeholder="请选择"
|
|
|
+ style={{ width: 100 }}
|
|
|
+ options={numList
|
|
|
+ .filter((b) => b !== i + 1)
|
|
|
+ .map((c) => ({
|
|
|
+ value: c,
|
|
|
+ label: c,
|
|
|
+ }))}
|
|
|
+ />
|
|
|
+  题
|
|
|
+ </span>
|
|
|
+   
|
|
|
+ {v.type === "填空" ? null : (
|
|
|
+ <Checkbox
|
|
|
+ checked={v.custom}
|
|
|
+ onChange={(e) =>
|
|
|
+ dataChangeFu(e.target.checked, v.id, "custom", i)
|
|
|
+ }
|
|
|
+ >
|
|
|
+ 支持填写自定义回答
|
|
|
+ </Checkbox>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 子选项 */}
|
|
|
+ <div className="A6Q2_21main" hidden={v.type === "填空"}>
|
|
|
+ {v.sList.map((v2, i2) => (
|
|
|
+ <div className="A6Q2_21Son" key={v2.id}>
|
|
|
+ <div>
|
|
|
+ <span>*</span> 选项 {i2 + 1}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <Input
|
|
|
+ value={v2.txt}
|
|
|
+ onChange={(e) =>
|
|
|
+ dataChangeFu(e.target.value, v2.id, "txt", i2)
|
|
|
+ }
|
|
|
+ maxLength={50}
|
|
|
+ showCount
|
|
|
+ placeholder="请输入内容"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 2级 跳题 */}
|
|
|
+ <span
|
|
|
+ className="A6Q2skip2"
|
|
|
+ hidden={v.skip !== "选项跳题"}
|
|
|
+ >
|
|
|
+ <Checkbox
|
|
|
+ checked={v2.skip2}
|
|
|
+ onChange={(e) =>
|
|
|
+ dataChangeFu(e.target.checked, v2.id, "skip2", i)
|
|
|
+ }
|
|
|
+ >
|
|
|
+ 跳题
|
|
|
+ </Checkbox>
|
|
|
+ <span hidden={!v2.skip2}>
|
|
|
+ 跳至第
|
|
|
+ <Select
|
|
|
+ value={v2.num2}
|
|
|
+ onChange={(e) => skipChangeFu(e, v2.id, 2)}
|
|
|
+ placeholder="请选择"
|
|
|
+ style={{ width: 80 }}
|
|
|
+ options={numList
|
|
|
+ .filter((b) => b !== i + 1)
|
|
|
+ .map((c) => ({
|
|
|
+ value: c,
|
|
|
+ label: c,
|
|
|
+ }))}
|
|
|
+ />
|
|
|
+ 题
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ {/* 2级 删除 */}
|
|
|
+ {i2 <= 1 ? null : (
|
|
|
+ <MyPopconfirm
|
|
|
+ txtK="删除"
|
|
|
+ onConfirm={() => delListFu(2, v2.id)}
|
|
|
+ Dom={
|
|
|
+ <div className="A6Q2del2">
|
|
|
+ <CloseCircleOutlined rev={undefined} />
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ {/* 子选项的新增 */}
|
|
|
+ <div className="A6Q2_22" hidden={v.type === "填空"}>
|
|
|
+ <Button
|
|
|
+ onClick={() => addListFu(2, v.sList.length)}
|
|
|
+ disabled={v.sList.length >= 6}
|
|
|
+ >
|
|
|
+ 新增选项
|
|
|
+ </Button>
|
|
|
+  
|
|
|
+ <span>最多支持6个选项</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="QTbtn">
|
|
|
+ <Button type="primary" onClick={btnOkFu}>
|
|
|
+ 提交
|
|
|
+ </Button>
|
|
|
+  
|
|
|
+ <MyPopconfirm txtK="取消" onConfirm={closeFu} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Modal>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+const MemoQTadd = React.memo(QTadd);
|
|
|
+
|
|
|
+export default MemoQTadd;
|