Browse Source

:sparkles: wbw 存盘

visuddhinanda 3 years ago
parent
commit
bbda481bd8

+ 36 - 28
dashboard/src/components/template/Wbw/WbwCase.tsx

@@ -1,6 +1,6 @@
 import { useEffect, useState } from "react";
 import { useIntl } from "react-intl";
-import { Typography, Button, Space } from "antd";
+import { Typography, Button, Space, Tag } from "antd";
 import { SwapOutlined } from "@ant-design/icons";
 import type { MenuProps } from "antd";
 import { Dropdown } from "antd";
@@ -11,6 +11,7 @@ import { PaliReal } from "../../../utils";
 import "./wbw.css";
 import { useAppSelector } from "../../../hooks";
 import { inlineDict as _inlineDict } from "../../../reducers/inline-dict";
+import WbwParent2 from "./WbwParent2";
 
 const { Text } = Typography;
 
@@ -20,7 +21,7 @@ interface IWidget {
   onSplit?: Function;
   onChange?: Function;
 }
-const Widget = ({ data, display, onSplit, onChange }: IWidget) => {
+const WbwCaseWidget = ({ data, display, onSplit, onChange }: IWidget) => {
   const intl = useIntl();
   const defaultMenu: MenuProps["items"] = [
     {
@@ -46,22 +47,24 @@ const Widget = ({ data, display, onSplit, onChange }: IWidget) => {
       let myMap = new Map<string, number>();
       let factors: string[] = [];
       for (const iterator of result) {
-        myMap.set(iterator.type + "$" + iterator.grammar, 1);
+        myMap.set(iterator.type + "#" + iterator.grammar, 1);
       }
       myMap.forEach((value, key, map) => {
         factors.push(key);
       });
 
       const menu = factors.map((item) => {
-        const arrItem: string[] = item.replaceAll(".", "").split("$");
+        const arrItem: string[] = item
+          .replaceAll(".", "")
+          .replaceAll("#", "$")
+          .split("$");
         let noNull = arrItem.filter((item) => item !== "");
-        const key = noNull.join("$");
         noNull.forEach((item, index, arr) => {
           arr[index] = intl.formatMessage({
             id: `dict.fields.type.${item}.short.label`,
           });
         });
-        return { key: key, label: noNull.join(" ") };
+        return { key: item, label: noNull.join(" ") };
       });
       setItems(menu);
     }
@@ -77,28 +80,30 @@ const Widget = ({ data, display, onSplit, onChange }: IWidget) => {
   let caseElement: JSX.Element | JSX.Element[] | undefined;
   if (
     display === "block" &&
-    (typeof data.case === "undefined" ||
-      data.case.value.length === 0 ||
-      data.case.value[0] === "")
+    (typeof data.case === "undefined" || data.case.value.trim() === "")
   ) {
     //空白的语法信息在逐词解析模式显示占位字符串
     caseElement = (
       <span>{intl.formatMessage({ id: "dict.fields.case.label" })}</span>
     );
   } else {
-    caseElement = data.case?.value.map((item, id) => {
-      if (item !== "") {
-        return (
-          <span key={id} className="case">
-            {intl.formatMessage({
-              id: `dict.fields.type.${item}.short.label`,
-            })}
-          </span>
-        );
-      } else {
-        return <></>;
-      }
-    });
+    caseElement = data.case?.value
+      .replace("#", "$")
+      .split("$")
+      .map((item, id) => {
+        if (item !== "") {
+          const strCase = item.replaceAll(".", "");
+          return (
+            <span key={id} className="case">
+              {intl.formatMessage({
+                id: `dict.fields.type.${strCase}.short.label`,
+              })}
+            </span>
+          );
+        } else {
+          return <span key={id}></span>;
+        }
+      });
   }
 
   if (typeof data.real !== "undefined" && PaliReal(data.real.value) !== "") {
@@ -106,12 +111,17 @@ const Widget = ({ data, display, onSplit, onChange }: IWidget) => {
       <div className="wbw_word_item" style={{ display: "flex" }}>
         <Text type="secondary">
           <div>
-            <Dropdown menu={{ items, onClick }} placement="bottomLeft">
+            <Dropdown
+              key="dropdown"
+              menu={{ items, onClick }}
+              placement="bottomLeft"
+            >
               <span>{caseElement}</span>
             </Dropdown>
-
+            <WbwParent2 data={data} />
             {showSplit ? (
               <Button
+                key="button"
                 className="wbw_split"
                 size="small"
                 shape="circle"
@@ -122,9 +132,7 @@ const Widget = ({ data, display, onSplit, onChange }: IWidget) => {
                   }
                 }}
               />
-            ) : (
-              <></>
-            )}
+            ) : undefined}
           </div>
         </Text>
       </div>
@@ -135,4 +143,4 @@ const Widget = ({ data, display, onSplit, onChange }: IWidget) => {
   }
 };
 
-export default Widget;
+export default WbwCaseWidget;

+ 17 - 10
dashboard/src/components/template/Wbw/WbwDetail.tsx

@@ -23,37 +23,44 @@ const Widget = ({ data, onClose, onSave }: IWidget) => {
   const intl = useIntl();
   const [currWbwData, setCurrWbwData] = useState(data);
   function fieldChanged(field: TFieldName, value: string) {
+    console.log("field", field, "value", value);
     let mData = currWbwData;
     switch (field) {
       case "note":
-        mData.note = { value: value, status: 5 };
+        mData.note = { value: value, status: 7 };
         break;
       case "bookMarkColor":
-        mData.bookMarkColor = { value: parseInt(value), status: 5 };
+        mData.bookMarkColor = { value: parseInt(value), status: 7 };
         break;
       case "bookMarkText":
-        mData.bookMarkText = { value: value, status: 5 };
+        mData.bookMarkText = { value: value, status: 7 };
         break;
       case "word":
-        mData.word = { value: value, status: 5 };
+        mData.word = { value: value, status: 7 };
         break;
       case "real":
-        mData.real = { value: value, status: 5 };
+        mData.real = { value: value, status: 7 };
         break;
       case "meaning":
-        mData.meaning = { value: value.split("$"), status: 5 };
+        mData.meaning = { value: value.split("$"), status: 7 };
         break;
       case "factors":
-        mData.factors = { value: value, status: 5 };
+        mData.factors = { value: value, status: 7 };
         break;
       case "factorMeaning":
-        mData.factorMeaning = { value: value, status: 5 };
+        mData.factorMeaning = { value: value, status: 7 };
         break;
       case "parent":
-        mData.parent = { value: value, status: 5 };
+        mData.parent = { value: value, status: 7 };
+        break;
+      case "parent2":
+        mData.parent2 = { value: value, status: 7 };
+        break;
+      case "grammar2":
+        mData.grammar2 = { value: value, status: 7 };
         break;
       case "case":
-        mData.case = { value: value.split("$"), status: 5 };
+        mData.case = { value: value, status: 7 };
         break;
       case "confidence":
         mData.confidence = parseFloat(value);

+ 74 - 47
dashboard/src/components/template/Wbw/WbwDetailBasic.tsx

@@ -1,17 +1,20 @@
 import { useEffect, useState } from "react";
 import { useIntl } from "react-intl";
-import { Divider, Form, Select, Input, AutoComplete } from "antd";
+import { Form, Input, AutoComplete, Button, Popover, Space, Badge } from "antd";
 import { Collapse } from "antd";
+import { MoreOutlined } from "@ant-design/icons";
 
 import SelectCase from "../../dict/SelectCase";
-import { IWbw } from "./WbwWord";
+import { IWbw, IWbwField } from "./WbwWord";
 import WbwMeaningSelect from "./WbwMeaningSelect";
 import { useAppSelector } from "../../../hooks";
 import { inlineDict as _inlineDict } from "../../../reducers/inline-dict";
 import { getFactorsInDict } from "./WbwFactors";
 import { IApiResponseDictData } from "../../api/Dict";
+import WbwDetailFm from "./WbwDetailFm";
+import WbwDetailParent2 from "./WbwDetailParent2";
+import WbwDetailRelation from "./WbwDetailRelation";
 
-const { Option } = Select;
 const { Panel } = Collapse;
 
 interface ValueType {
@@ -49,6 +52,7 @@ export const getParentInDict = (
     return [];
   }
 };
+
 interface IWidget {
   data: IWbw;
   onChange?: Function;
@@ -61,6 +65,12 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
   const inlineDict = useAppSelector(_inlineDict);
   const [factorOptions, setFactorOptions] = useState<ValueType[]>([]);
   const [parentOptions, setParentOptions] = useState<ValueType[]>([]);
+  const [factors, setFactors] = useState<string[]>([]);
+  const [openCreate, setOpenCreate] = useState(false);
+  const [_meaning, setMeaning] = useState<string[] | undefined>(
+    data.meaning?.value
+  );
+
   const onMeaningChange = (value: string | string[]) => {
     console.log(`Selected: ${value}`);
     if (typeof onChange !== "undefined") {
@@ -100,6 +110,10 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
     setParentOptions(parentOptions);
   }, [inlineDict, data]);
 
+  const relationCount = data.relation
+    ? JSON.parse(data.relation.value).length
+    : 0;
+
   return (
     <>
       <Form
@@ -114,6 +128,8 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
           factorMeaning: data.factorMeaning?.value,
           parent: data.parent?.value,
           case: data.case?.value,
+          parent2: data.parent2?.value,
+          grammar2: data.grammar2?.value,
         }}
       >
         <Form.Item
@@ -122,20 +138,21 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
           label={intl.formatMessage({ id: "forms.fields.meaning.label" })}
           tooltip={intl.formatMessage({ id: "forms.fields.meaning.tooltip" })}
         >
-          <Select
-            allowClear
-            mode="tags"
-            onChange={onMeaningChange}
-            style={{ width: "100%" }}
-            options={items.map((item) => ({ label: item, value: item }))}
-            dropdownRender={(menu) => (
-              <>
-                {menu}
-                <Divider style={{ margin: "8px 0" }}>更多</Divider>
+          <div style={{ display: "flex" }}>
+            <Input
+              value={_meaning?.join(";")}
+              allowClear
+              onChange={(e) => {
+                console.log(e.target.value);
+                setMeaning(e.target.value.split(";"));
+              }}
+            />
+            <Popover
+              content={
                 <WbwMeaningSelect
                   data={data}
                   onSelect={(meaning: string) => {
-                    const currMeanings = form.getFieldValue("meaning") || [];
+                    const currMeanings = _meaning ? _meaning : [];
                     console.log(meaning);
                     if (!items.includes(meaning)) {
                       setItems([...items, meaning]);
@@ -144,15 +161,25 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
                       currMeanings.push(meaning);
                       console.log("it push", meaning);
                     }
+                    setMeaning(currMeanings);
                     form.setFieldsValue({
                       meaning: currMeanings,
                     });
                     onMeaningChange(currMeanings);
                   }}
                 />
-              </>
-            )}
-          />
+              }
+              overlayStyle={{ width: 500 }}
+              placement="bottom"
+              trigger="click"
+              open={openCreate}
+              onOpenChange={(open: boolean) => {
+                setOpenCreate(open);
+              }}
+            >
+              <Button type="text" icon={<MoreOutlined />} onClick={() => {}} />
+            </Popover>
+          </div>
         </Form.Item>
         <Form.Item
           style={{ marginBottom: 6 }}
@@ -162,7 +189,8 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
         >
           <AutoComplete
             options={factorOptions}
-            onChange={(value: any, option: ValueType | ValueType[]) => {
+            onChange={(value: string, option: ValueType | ValueType[]) => {
+              setFactors(value.split("+"));
               if (typeof onChange !== "undefined") {
                 onChange({ field: "factors", value: value });
               }
@@ -181,7 +209,16 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
             id: "forms.fields.factor.meaning.tooltip",
           })}
         >
-          <Input allowClear />
+          <WbwDetailFm
+            factors={factors}
+            initValue={data.factorMeaning?.value.split("+")}
+            onChange={(value: string[]) => {
+              console.log("fm change", value);
+              if (typeof onChange !== "undefined") {
+                onChange({ field: "factorMeaning", value: value.join("+") });
+              }
+            }}
+          />
         </Form.Item>
         <Form.Item
           style={{ marginBottom: 6 }}
@@ -190,9 +227,9 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
           name="case"
         >
           <SelectCase
-            onCaseChange={(value: (string | number)[]) => {
+            onCaseChange={(value: string) => {
               if (typeof onChange !== "undefined") {
-                onChange({ field: "case", value: value.join("$") });
+                onChange({ field: "case", value: value });
               }
             }}
           />
@@ -219,37 +256,27 @@ const Widget = ({ data, showRelation = true, onChange }: IWidget) => {
           </AutoComplete>
         </Form.Item>
         <Collapse bordered={false}>
-          <Panel header="词源" key="1">
-            <Form.Item
-              name="parent1"
-              label={intl.formatMessage({ id: "forms.fields.parent.label" })}
-              tooltip={intl.formatMessage({
-                id: "forms.fields.parent.tooltip",
-              })}
-            >
-              <Input
-                allowClear
-                placeholder={intl.formatMessage({
-                  id: "forms.fields.parent.label",
-                })}
-                addonAfter={
-                  <Form.Item name="suffix" noStyle>
-                    <Select style={{ width: 100 }} allowClear>
-                      <Option value="prp">现在分词</Option>
-                      <Option value="pp">过去分词</Option>
-                      <Option value="fpp">未来分词</Option>
-                    </Select>
-                  </Form.Item>
+          <Panel header="词源" key="parent2">
+            <WbwDetailParent2
+              data={data}
+              onChange={(e: IWbwField) => {
+                if (typeof onChange !== "undefined") {
+                  onChange(e);
                 }
-              />
-            </Form.Item>
+              }}
+            />
           </Panel>
           <Panel
-            header="关系"
-            key="2"
+            header={
+              <Space>
+                {"关联"}
+                <Badge color="geekblue" count={relationCount} />
+              </Space>
+            }
+            key="relation"
             style={{ display: showRelation ? "block" : "none" }}
           >
-            关系语法
+            <WbwDetailRelation data={data} />
           </Panel>
         </Collapse>
       </Form>

+ 8 - 2
dashboard/src/components/template/Wbw/WbwFactorMeaning.tsx

@@ -17,7 +17,12 @@ interface IWidget {
   display?: TWbwDisplayMode;
   onChange?: Function;
 }
-const Widget = ({ data, display, onChange, factors }: IWidget) => {
+const WbwFactorMeaningWidget = ({
+  data,
+  display,
+  onChange,
+  factors,
+}: IWidget) => {
   const intl = useIntl();
   const defaultMenu: MenuProps["items"] = [
     {
@@ -60,6 +65,7 @@ const Widget = ({ data, display, onChange, factors }: IWidget) => {
     if (typeof factors !== "undefined") {
     }
   }, [factors]);
+
   const onClick: MenuProps["onClick"] = (e) => {
     console.log("click ", e);
     if (typeof onChange !== "undefined") {
@@ -99,4 +105,4 @@ const Widget = ({ data, display, onChange, factors }: IWidget) => {
   }
 };
 
-export default Widget;
+export default WbwFactorMeaningWidget;

+ 9 - 3
dashboard/src/components/template/Wbw/WbwPali.tsx

@@ -4,6 +4,7 @@ import {
   TagTwoTone,
   InfoCircleOutlined,
   CommentOutlined,
+  ApartmentOutlined,
 } from "@ant-design/icons";
 
 import "./wbw.css";
@@ -23,7 +24,7 @@ interface IWidget {
   display?: TWbwDisplayMode;
   onSave?: Function;
 }
-const Widget = ({ data, display, onSave }: IWidget) => {
+const WbwPaliWidget = ({ data, display, onSave }: IWidget) => {
   const [click, setClicked] = useState(false);
   const [paliColor, setPaliColor] = useState("unset");
   const [isHover, setIsHover] = useState(false);
@@ -82,6 +83,10 @@ const Widget = ({ data, display, onSave }: IWidget) => {
     />
   ) : undefined;
 
+  const relationIcon = data.relation ? (
+    <ApartmentOutlined style={{ color: "blue" }} />
+  ) : undefined;
+
   const bookMarkIcon = data.bookMarkText ? (
     <Popover
       content={<Paragraph copyable>{data.bookMarkText.value}</Paragraph>}
@@ -146,7 +151,7 @@ const Widget = ({ data, display, onSave }: IWidget) => {
         marginLeft: "-2em",
       };
       commentIconStyle = {
-        visibility: isHover ? "visible" : "hidden",
+        visibility: "hidden",
         cursor: "pointer",
       };
     }
@@ -193,6 +198,7 @@ const Widget = ({ data, display, onSave }: IWidget) => {
         {videoIcon}
         {noteIcon}
         {bookMarkIcon}
+        {relationIcon}
         {discussionIcon}
       </div>
     );
@@ -206,4 +212,4 @@ const Widget = ({ data, display, onSave }: IWidget) => {
   }
 };
 
-export default Widget;
+export default WbwPaliWidget;

+ 2 - 2
dashboard/src/components/template/Wbw/WbwPara.tsx

@@ -6,7 +6,7 @@ import { IWbw } from "./WbwWord";
 interface IWidget {
   data: IWbw;
 }
-const Widget = ({ data }: IWidget) => {
+const WbwParaWidget = ({ data }: IWidget) => {
   return (
     <span>
       <Button size="small" type="link" icon={<PicCenterOutlined />} />
@@ -14,4 +14,4 @@ const Widget = ({ data }: IWidget) => {
   );
 };
 
-export default Widget;
+export default WbwParaWidget;

+ 26 - 5
dashboard/src/components/template/Wbw/WbwWord.tsx

@@ -23,8 +23,10 @@ export type TFieldName =
   | "meaning"
   | "type"
   | "grammar"
+  | "grammar2"
   | "case"
   | "parent"
+  | "parent2"
   | "factors"
   | "factorMeaning"
   | "relation"
@@ -44,21 +46,26 @@ enum WbwStatus {
   auto = 3,
   manual = 5,
 }
-interface WbwElement<R> {
+export interface WbwElement<R> {
   value: R;
   status: WbwStatus;
 }
 
 export interface IWbw {
   uid?: string;
+  book: number;
+  para: number;
+  sn: number[];
   word: WbwElement<string>;
   real?: WbwElement<string>;
   meaning?: WbwElement<string[]>;
   type?: WbwElement<string>;
   grammar?: WbwElement<string>;
   style?: WbwElement<string>;
-  case?: WbwElement<string[]>;
+  case?: WbwElement<string>;
   parent?: WbwElement<string>;
+  parent2?: WbwElement<string>;
+  grammar2?: WbwElement<string>;
   factors?: WbwElement<string>;
   factorMeaning?: WbwElement<string>;
   relation?: WbwElement<string>;
@@ -84,7 +91,7 @@ interface IWidget {
   onChange?: Function;
   onSplit?: Function;
 }
-const Widget = ({
+const WbwWordWidget = ({
   data,
   display = "block",
   fields = { meaning: true, factors: true, factorMeaning: true, case: true },
@@ -170,6 +177,7 @@ const Widget = ({
         }}
       >
         <WbwPali
+          key="pali"
           data={wordData}
           display={display}
           onSave={(e: IWbw) => {
@@ -189,6 +197,7 @@ const Widget = ({
         >
           {fieldDisplay?.meaning ? (
             <WbwMeaning
+              key="meaning"
               data={wordData}
               display={display}
               onChange={(e: string) => {
@@ -204,6 +213,7 @@ const Widget = ({
           ) : undefined}
           {fieldDisplay?.factors ? (
             <WbwFactors
+              key="factors"
               data={wordData}
               display={display}
               onChange={(e: string) => {
@@ -212,11 +222,15 @@ const Widget = ({
                 newData.factors = { value: e, status: 5 };
                 setNewFactors(e);
                 setWordData(newData);
+                if (typeof onChange !== "undefined") {
+                  onChange(newData);
+                }
               }}
             />
           ) : undefined}
           {fieldDisplay?.factorMeaning ? (
             <WbwFactorMeaning
+              key="fm"
               data={wordData}
               display={display}
               factors={newFactors}
@@ -224,11 +238,15 @@ const Widget = ({
                 const newData: IWbw = JSON.parse(JSON.stringify(wordData));
                 newData.factorMeaning = { value: e, status: 5 };
                 setWordData(newData);
+                if (typeof onChange !== "undefined") {
+                  onChange(newData);
+                }
               }}
             />
           ) : undefined}
           {fieldDisplay?.case ? (
             <WbwCase
+              key="case"
               data={wordData}
               display={display}
               onSplit={(e: boolean) => {
@@ -239,8 +257,11 @@ const Widget = ({
               }}
               onChange={(e: string) => {
                 const newData: IWbw = JSON.parse(JSON.stringify(wordData));
-                newData.case = { value: e.split("$"), status: 5 };
+                newData.case = { value: e, status: 7 };
                 setWordData(newData);
+                if (typeof onChange !== "undefined") {
+                  onChange(newData);
+                }
               }}
             />
           ) : undefined}
@@ -250,4 +271,4 @@ const Widget = ({
   }
 };
 
-export default Widget;
+export default WbwWordWidget;

+ 105 - 6
dashboard/src/components/template/WbwSent.tsx

@@ -1,16 +1,58 @@
+import { message } from "antd";
 import { useEffect, useState } from "react";
 
 import { useAppSelector } from "../../hooks";
 import { mode } from "../../reducers/article-mode";
-import WbwWord, { IWbw, IWbwFields } from "./Wbw/WbwWord";
+import { post } from "../../request";
+import WbwWord, { IWbw, IWbwFields, WbwElement } from "./Wbw/WbwWord";
 
+interface IWbwXml {
+  id: string;
+  pali: WbwElement<string>;
+  real?: WbwElement<string>;
+  type?: WbwElement<string>;
+  gramma?: WbwElement<string>;
+  mean?: WbwElement<string>;
+  org?: WbwElement<string>;
+  om?: WbwElement<string>;
+  case?: WbwElement<string>;
+  parent?: WbwElement<string>;
+  pg?: WbwElement<string>;
+  parent2?: WbwElement<string>;
+  lock?: boolean;
+  bmt?: WbwElement<string>;
+  bmc?: WbwElement<number>;
+  cf: number;
+}
+interface IWbwUpdateResponse {
+  ok: boolean;
+  message: string;
+  data: { rows?: IWbwXml[]; count: number };
+}
+interface IWbwRequest {
+  book: number;
+  para: number;
+  sn: number;
+  channel_id: string;
+  data: IWbwXml[];
+}
 interface IWidget {
   data: IWbw[];
+  book: number;
+  para: number;
+  channelId: string;
   display?: "block" | "inline";
   fields?: IWbwFields;
 }
-export const WbwSentCtl = ({ data, display = "inline", fields }: IWidget) => {
-  const [wordData, setWordData] = useState(data);
+export const WbwSentCtl = ({
+  data,
+  channelId,
+  book,
+  para,
+  display = "inline",
+  fields,
+}: IWidget) => {
+  const [wordData, setWordData] = useState<IWbw[]>(data);
   const [wbwMode, setWbwMode] = useState(display);
   const [fieldDisplay, setFieldDisplay] = useState(fields);
   const newMode = useAppSelector(mode);
@@ -47,8 +89,62 @@ export const WbwSentCtl = ({ data, display = "inline", fields }: IWidget) => {
             fields={fieldDisplay}
             onChange={(e: IWbw) => {
               console.log("word changed", e);
-              console.log("word id", id);
-              //TODO update
+              let newData = [...wordData];
+              newData.forEach((value, index, array) => {
+                if (value.sn.join() === e.sn.join()) {
+                  console.log("found", e.sn);
+                  array[index] = e;
+                }
+              });
+              console.log("new data", newData);
+              setWordData(newData);
+              const data = newData.filter((value) => value.sn[0] === e.sn[0]);
+              const postParam: IWbwRequest = {
+                book: book,
+                para: para,
+                sn: e.sn[0],
+                channel_id: channelId,
+                data: data.map((item) => {
+                  return {
+                    pali: item.word,
+                    real: item.real,
+                    id: `${book}-${para}-${e.sn[0]}`,
+                    type: item.type,
+                    gramma: item.type,
+                    mean: item.meaning
+                      ? {
+                          value: item.meaning?.value.join("$"),
+                          status: item.meaning?.status,
+                        }
+                      : undefined,
+                    org: item.factors,
+                    om: item.factorMeaning,
+                    case: item.case
+                      ? {
+                          value: item.case?.value,
+                          status: item.case?.status,
+                        }
+                      : undefined,
+                    parent: item.parent,
+                    pg: item.grammar2,
+                    parent2: item.parent2,
+                    lock: item.locked,
+                    bmt: item.bookMarkText,
+                    bmc: item.bookMarkColor,
+                    cf: item.confidence,
+                  };
+                }),
+              };
+              console.log("wbw post", postParam);
+              post<IWbwRequest, IWbwUpdateResponse>(`/v2/wbw`, postParam).then(
+                (json) => {
+                  if (json.ok) {
+                    message.info(e.word.value + " updated");
+                  } else {
+                    message.error(json.message);
+                  }
+                }
+              );
             }}
             onSplit={(isSplit: boolean) => {
               if (isSplit) {
@@ -56,10 +152,13 @@ export const WbwSentCtl = ({ data, display = "inline", fields }: IWidget) => {
                 const newData: IWbw[] = JSON.parse(JSON.stringify(wordData));
                 const children: IWbw[] | undefined = wordData[id].factors?.value
                   .split("+")
-                  .map((item) => {
+                  .map((item, index) => {
                     return {
                       word: { value: item, status: 5 },
                       real: { value: item, status: 5 },
+                      book: wordData[id].book,
+                      para: wordData[id].para,
+                      sn: [...wordData[id].sn, index],
                       confidence: 1,
                     };
                   });