Răsfoiți Sursa

Merge pull request #1801 from visuddhinanda/agile

channel列表增加统计信息
visuddhinanda 2 ani în urmă
părinte
comite
f2fc08f35d

+ 2 - 0
dashboard/src/components/api/Channel.ts

@@ -36,6 +36,8 @@ export interface IApiResponseChannelData {
   updated_at: string;
   updated_at: string;
   role?: TRole;
   role?: TRole;
   final?: IFinal[];
   final?: IFinal[];
+  content_created_at: string;
+  content_updated_at: string;
 }
 }
 export interface IApiResponseChannel {
 export interface IApiResponseChannel {
   ok: boolean;
   ok: boolean;

+ 104 - 0
dashboard/src/components/channel/ChannelInfo.tsx

@@ -0,0 +1,104 @@
+import { Statistic, StatisticCard } from "@ant-design/pro-components";
+import { Modal } from "antd";
+import { useEffect, useState } from "react";
+import { IItem } from "./ChannelPickerTable";
+
+interface IChannelInfoModal {
+  open?: boolean;
+  channel?: IItem;
+  onClose?: Function;
+}
+
+export const ChannelInfoModal = ({
+  open,
+  channel,
+  onClose,
+}: IChannelInfoModal) => {
+  const [isModalOpen, setIsModalOpen] = useState(open);
+  useEffect(() => setIsModalOpen(open), [open]);
+  return (
+    <Modal
+      destroyOnClose={true}
+      width={300}
+      title="统计"
+      open={isModalOpen}
+      onCancel={(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
+        setIsModalOpen(false);
+        if (typeof onClose !== "undefined") {
+          onClose();
+        }
+      }}
+      footer={<></>}
+    >
+      <ChannelInfoWidget channel={channel} />
+    </Modal>
+  );
+};
+interface IWidget {
+  channel?: IItem;
+}
+const ChannelInfoWidget = ({ channel }: IWidget) => {
+  const [count, setCount] = useState<number>();
+  useEffect(() => {
+    const sentElement = document.querySelectorAll(".pcd_sent");
+    let sentList: string[] = [];
+    for (let index = 0; index < sentElement.length; index++) {
+      const element = sentElement[index];
+      const id = element.id.split("_")[1];
+      sentList.push(id);
+    }
+    setCount(sentList.length);
+  }, []);
+  let totalStrLen = 0;
+  let finalStrLen = 0;
+  let finalSent = 0;
+  channel?.final?.forEach((value) => {
+    totalStrLen += value[0];
+    if (value[1]) {
+      finalStrLen += value[0];
+      finalSent++;
+    }
+  });
+  const final = channel?.final ? (finalSent * 100) / channel?.final?.length : 0;
+  return (
+    <>
+      <StatisticCard
+        title={"版本:" + channel?.title}
+        statistic={{
+          value: count,
+          suffix: "句",
+          description: (
+            <Statistic title="完成度" value={Math.round(final) + "%"} />
+          ),
+        }}
+        chart={<></>}
+        footer={
+          <>
+            <Statistic
+              value={totalStrLen}
+              title="巴利字符"
+              layout="horizontal"
+            />
+            <Statistic
+              value={finalStrLen}
+              title="译文字符"
+              layout="horizontal"
+            />
+            <Statistic
+              value={channel?.content_created_at}
+              title="创建于"
+              layout="horizontal"
+            />
+            <Statistic
+              value={channel?.content_updated_at}
+              title="最近更新"
+              layout="horizontal"
+            />
+          </>
+        }
+      />
+    </>
+  );
+};
+
+export default ChannelInfoWidget;

+ 22 - 2
dashboard/src/components/channel/ChannelMy.tsx

@@ -17,6 +17,7 @@ import {
   ReloadOutlined,
   ReloadOutlined,
   MoreOutlined,
   MoreOutlined,
   CopyOutlined,
   CopyOutlined,
+  InfoCircleOutlined,
 } from "@ant-design/icons";
 } from "@ant-design/icons";
 
 
 import { post } from "../../request";
 import { post } from "../../request";
@@ -29,6 +30,7 @@ import ProgressSvg from "./ProgressSvg";
 import { IChannel } from "./Channel";
 import { IChannel } from "./Channel";
 import CopyToModal from "./CopyToModal";
 import CopyToModal from "./CopyToModal";
 import { ArticleType } from "../article/Article";
 import { ArticleType } from "../article/Article";
+import { ChannelInfoModal } from "./ChannelInfo";
 
 
 interface ChannelTreeNode {
 interface ChannelTreeNode {
   key: string;
   key: string;
@@ -62,7 +64,8 @@ const ChannelMy = ({
   const [loading, setLoading] = useState(true);
   const [loading, setLoading] = useState(true);
   const [copyChannel, setCopyChannel] = useState<IChannel>();
   const [copyChannel, setCopyChannel] = useState<IChannel>();
   const [copyOpen, setCopyOpen] = useState<boolean>(false);
   const [copyOpen, setCopyOpen] = useState<boolean>(false);
-
+  const [infoOpen, setInfoOpen] = useState<boolean>(false);
+  const [statistic, setStatistic] = useState<IItem>();
   useEffect(() => load(), []);
   useEffect(() => load(), []);
 
 
   useEffect(() => {
   useEffect(() => {
@@ -155,6 +158,8 @@ const ChannelMy = ({
               createdAt: date.getTime(),
               createdAt: date.getTime(),
               final: item.final,
               final: item.final,
               progress: progress,
               progress: progress,
+              content_created_at: item.content_created_at,
+              content_updated_at: item.content_updated_at,
             };
             };
           });
           });
 
 
@@ -350,6 +355,13 @@ const ChannelMy = ({
                               }),
                               }),
                               icon: <CopyOutlined />,
                               icon: <CopyOutlined />,
                             },
                             },
+                            {
+                              key: "statistic",
+                              label: intl.formatMessage({
+                                id: "buttons.statistic",
+                              }),
+                              icon: <InfoCircleOutlined />,
+                            },
                           ],
                           ],
                           onClick: (e) => {
                           onClick: (e) => {
                             switch (e.key) {
                             switch (e.key) {
@@ -361,7 +373,10 @@ const ChannelMy = ({
                                 });
                                 });
                                 setCopyOpen(true);
                                 setCopyOpen(true);
                                 break;
                                 break;
-
+                              case "statistic":
+                                setInfoOpen(true);
+                                setStatistic(node.channel);
+                                break;
                               default:
                               default:
                                 break;
                                 break;
                             }
                             }
@@ -388,6 +403,11 @@ const ChannelMy = ({
         open={copyOpen}
         open={copyOpen}
         onClose={() => setCopyOpen(false)}
         onClose={() => setCopyOpen(false)}
       />
       />
+      <ChannelInfoModal
+        channel={statistic}
+        open={infoOpen}
+        onClose={() => setInfoOpen(false)}
+      />
     </div>
     </div>
   );
   );
 };
 };

+ 2 - 0
dashboard/src/components/channel/ChannelPickerTable.tsx

@@ -43,6 +43,8 @@ export interface IItem {
   final?: IFinal[];
   final?: IFinal[];
   progress: number;
   progress: number;
   createdAt: number;
   createdAt: number;
+  content_created_at?: string;
+  content_updated_at?: string;
 }
 }
 interface IWidget {
 interface IWidget {
   type?: ArticleType | "editable";
   type?: ArticleType | "editable";

+ 1 - 0
dashboard/src/locales/zh-Hans/buttons.ts

@@ -75,6 +75,7 @@ const items = {
   "buttons.refuse": "拒绝",
   "buttons.refuse": "拒绝",
   "buttons.use.as.guest": "以访客身份继续使用",
   "buttons.use.as.guest": "以访客身份继续使用",
   "buttons.got.it": "知道了",
   "buttons.got.it": "知道了",
+  "buttons.statistic": "统计",
 };
 };
 
 
 export default items;
 export default items;