Explorar o código

Merge pull request #1020 from visuddhinanda/agile

:construction: 创建目录结构
visuddhinanda %!s(int64=3) %!d(string=hai) anos
pai
achega
97dd3cae66
Modificáronse 51 ficheiros con 1594 adicións e 5 borrados
  1. 12 0
      dashboard/README.md
  2. 91 4
      dashboard/src/Router.tsx
  3. 12 0
      dashboard/src/components/README.md
  4. 26 0
      dashboard/src/components/library/Footer.tsx
  5. 51 0
      dashboard/src/components/library/HeadBar.tsx
  6. 0 0
      dashboard/src/components/library/article/.txt
  7. 33 0
      dashboard/src/components/library/blog/HeadBar.tsx
  8. 0 0
      dashboard/src/components/library/dict/.txt
  9. 0 0
      dashboard/src/components/library/palicanon/.txt
  10. 5 0
      dashboard/src/components/studio/Footer.tsx
  11. 15 0
      dashboard/src/components/studio/HeadBar.tsx
  12. 56 0
      dashboard/src/components/studio/LeftSider.tsx
  13. 3 0
      dashboard/src/locales/README.md
  14. 15 0
      dashboard/src/locales/zh-Hans/channel/index.ts
  15. 16 0
      dashboard/src/locales/zh-Hans/dict/index.ts
  16. 24 0
      dashboard/src/locales/zh-Hans/index.ts
  17. 3 0
      dashboard/src/pages/README.md
  18. 23 0
      dashboard/src/pages/library/anthology/article.tsx
  19. 24 0
      dashboard/src/pages/library/anthology/index.tsx
  20. 22 0
      dashboard/src/pages/library/anthology/show.tsx
  21. 23 0
      dashboard/src/pages/library/blog/anthology.tsx
  22. 22 0
      dashboard/src/pages/library/blog/course.tsx
  23. 23 0
      dashboard/src/pages/library/blog/index.tsx
  24. 22 0
      dashboard/src/pages/library/blog/term.tsx
  25. 23 0
      dashboard/src/pages/library/blog/translation.tsx
  26. 19 0
      dashboard/src/pages/library/community/index.tsx
  27. 26 0
      dashboard/src/pages/library/community/recent.tsx
  28. 23 0
      dashboard/src/pages/library/course/course.tsx
  29. 23 0
      dashboard/src/pages/library/course/index.tsx
  30. 22 0
      dashboard/src/pages/library/course/lesson.tsx
  31. 19 0
      dashboard/src/pages/library/dict/index.tsx
  32. 22 0
      dashboard/src/pages/library/dict/show.tsx
  33. 19 0
      dashboard/src/pages/library/palicanon/index.tsx
  34. 22 0
      dashboard/src/pages/library/term/show.tsx
  35. 11 1
      dashboard/src/pages/nut/index.tsx
  36. 26 0
      dashboard/src/pages/studio/analysis/index.tsx
  37. 23 0
      dashboard/src/pages/studio/anthology/edit.tsx
  38. 27 0
      dashboard/src/pages/studio/anthology/index.tsx
  39. 23 0
      dashboard/src/pages/studio/article/edit.tsx
  40. 27 0
      dashboard/src/pages/studio/article/index.tsx
  41. 60 0
      dashboard/src/pages/studio/channel/create.tsx
  42. 83 0
      dashboard/src/pages/studio/channel/edit.tsx
  43. 27 0
      dashboard/src/pages/studio/channel/index.tsx
  44. 166 0
      dashboard/src/pages/studio/dict/index.tsx
  45. 83 0
      dashboard/src/pages/studio/group/edit.tsx
  46. 29 0
      dashboard/src/pages/studio/group/index.tsx
  47. 25 0
      dashboard/src/pages/studio/group/show.tsx
  48. 26 0
      dashboard/src/pages/studio/index.tsx
  49. 26 0
      dashboard/src/pages/studio/palicanon/index.tsx
  50. 26 0
      dashboard/src/pages/studio/recent/index.tsx
  51. 167 0
      dashboard/src/pages/studio/term/index.tsx

+ 12 - 0
dashboard/README.md

@@ -0,0 +1,12 @@
+# 前端框架
+
+## 目录
+
+- `public` 
+- `src`
+  - `components` 所有网页用的组件
+  - `locales` 所有国际化语言包
+  - `pages` 前端页面
+
+nut目录为练习用途。里面的内容可能会被删除。**线上不要使用**。
+

+ 91 - 4
dashboard/src/Router.tsx

@@ -17,6 +17,49 @@ import NutNotFound from "./pages/nut/not-found";
 import NutSwitchLanguage from "./pages/nut/switch-languages";
 import NutHome from "./pages/nut";
 
+import LibraryCommunity from "./pages/library/community";
+import LibraryCommunityRecent from "./pages/library/community/recent";
+import LibraryPalicanon from "./pages/library/palicanon";
+import LibraryCourse from "./pages/library/course";
+import LibraryCourseShow from "./pages/library/course/course";
+import LibraryLessonShow from "./pages/library/course/lesson";
+import LibraryTerm from "./pages/library/term/show";
+import LibraryDict from "./pages/library/dict";
+import LibraryDictShow from "./pages/library/dict/show";
+import LibraryAnthology from "./pages/library/anthology";
+import LibraryAnthologyShow from "./pages/library/anthology/show";
+import LibraryArticle from "./pages/library/anthology/article";
+
+import LibraryBlog from "./pages/library/blog";
+import LibraryBlogTranslation from "./pages/library/blog/translation";
+import LibraryBlogCourse from "./pages/library/blog/course";
+import LibraryBlogAnthology from "./pages/library/blog/anthology";
+import LibraryBlogTerm from "./pages/library/blog/term";
+
+import StudioHome from "./pages/studio";
+
+import StudioPalicanon from "./pages/studio/palicanon";
+import StudioRecent from "./pages/studio/recent";
+
+import StudioChannel from "./pages/studio/channel";
+import StudioChannelCreate from "./pages/studio/channel/create";
+import StudioChannelEdit from "./pages/studio/channel/edit";
+
+import StudioGroup from "./pages/studio/group";
+import StudioGroupEdit from "./pages/studio/group/edit";
+import StudioGroupShow from "./pages/studio/group/show";
+
+import StudioDict from "./pages/studio/dict";
+import StudioTerm from "./pages/studio/term";
+
+import StudioArticle from "./pages/studio/article";
+import StudioArticleEdit from "./pages/studio/article/edit";
+
+import StudioAnthology from "./pages/studio/anthology";
+import StudioAnthologyEdit from "./pages/studio/anthology/edit";
+
+import StudioAnalysis from "./pages/studio/analysis";
+
 const Widget = () => {
   return (
     <Routes>
@@ -29,10 +72,7 @@ const Widget = () => {
             <Route path="new" element={<NutUsersUnlockNew />} />
             <Route path="verify/:token" element={<NutUsersUnlockVerify />} />
           </Route>
-          <Route
-            path="reset-password/:token"
-            element={<NutUsersResetPassword />}
-          />
+          <Route path="reset-password/:token" element={<NutUsersResetPassword />} />
           <Route path="forgot-password" element={<NutUsersForgotPassword />} />
         </Route>
       </Route>
@@ -48,6 +88,53 @@ const Widget = () => {
       <Route path="forbidden" element={<NutForbidden />} />
       <Route path="" element={<NutHome />} />
       <Route path="*" element={<NutNotFound />} />
+
+	  <Route path="community" element={<LibraryCommunity />}></Route>
+	  <Route path="recent" element={<LibraryCommunityRecent />} />
+	  <Route path="palicanon" element={<LibraryPalicanon />} />
+
+	  <Route path="course" element={<LibraryCourse />}></Route>
+      <Route path="course/show/:id" element={<LibraryCourseShow />}></Route>
+      <Route path="course/lesson/:id" element={<LibraryLessonShow />}></Route>
+
+	  <Route path="term/:word" element={<LibraryTerm />} />
+
+	  <Route path="dict" element={<LibraryDict />} />
+	  <Route path="dict/:word" element={<LibraryDictShow />} />
+
+	  <Route path="anthology" element={<LibraryAnthology />} />
+	  <Route path="anthology/show/:id" element={<LibraryAnthologyShow />} />
+	  <Route path="article/show/:id" element={<LibraryArticle />} />
+
+	  <Route path="blog/:studioname" element={<LibraryBlog />} />
+	  <Route path="blog/:studioname/translation" element={<LibraryBlogTranslation />} />
+	  <Route path="blog/:studioname/course" element={<LibraryBlogCourse />} />
+	  <Route path="blog/:studioname/anthology" element={<LibraryBlogAnthology />} />
+	  <Route path="blog/:studioname/term" element={<LibraryBlogTerm />} />
+
+	  <Route path="studio/:studioname" element={<StudioHome />}></Route>
+	  <Route path="studio/:studioname/palicanon" element={<StudioPalicanon />}></Route>
+	  <Route path="studio/:studioname/recent" element={<StudioRecent />}></Route>
+
+	  <Route path="studio/:studioname/channel" element={<StudioChannel />}></Route>
+	  <Route path="studio/:studioname/channel/create" element={<StudioChannelCreate />} />
+	  <Route path="studio/:studioname/channel/edit/:channelid" element={<StudioChannelEdit />} />
+
+	  <Route path="studio/:studioname/group" element={<StudioGroup />}></Route>
+	  <Route path="studio/:studioname/group/:groupid" element={<StudioGroupShow />} />
+	  <Route path="studio/:studioname/group/edit/:groupid" element={<StudioGroupEdit />} />
+
+	  <Route path="studio/:studioname/dict" element={<StudioDict />}> </Route>
+	  <Route path="studio/:studioname/term" element={<StudioTerm />}> </Route>
+
+	  <Route path="studio/:studioname/article" element={<StudioArticle />}></Route>
+	  <Route path="studio/:studioname/article/edit/:articleid" element={<StudioArticleEdit />} />
+	  
+	  <Route path="studio/:studioname/anthology" element={<StudioAnthology />}></Route>
+	  <Route path="studio/:studioname/anthology/edit/:anthology_id" element={<StudioAnthologyEdit />} />
+
+	  <Route path="studio/:studioname/analysis" element={<StudioAnalysis />}></Route>
+
     </Routes>
   );
 };

+ 12 - 0
dashboard/src/components/README.md

@@ -0,0 +1,12 @@
+# 组件
+
+## 目录
+
+某栏目的专用组件放在以该栏目命名的目录下
+
+- `libray` 前台(阅读)的栏目
+  - `栏目名称` 某栏目的专用组件
+  - `组件1.tsx` libray 下面的栏目的公共组件
+- `studio` 用户后台(课程发布等)
+
+nut目录为练习用途。里面的内容可能会被删除。**线上不要使用**。

+ 26 - 0
dashboard/src/components/library/Footer.tsx

@@ -0,0 +1,26 @@
+import { Link } from "react-router-dom";
+import { Space } from "antd";
+import { useIntl } from "react-intl";
+
+const Widget = () => {
+	//Library foot bar
+	const intl = useIntl();//i18n
+	// TODO
+  return (
+	<div>
+		<p>底部区域</p>
+		<Space>
+
+			<Link to="/">
+				联系方式
+			</Link>
+			<Link to="/">
+				{intl.formatMessage({ id: "columns.library.palicanon.title" })}
+			</Link>
+		</Space>		
+	</div>
+
+  );
+};
+
+export default Widget;

+ 51 - 0
dashboard/src/components/library/HeadBar.tsx

@@ -0,0 +1,51 @@
+import { Link } from "react-router-dom";
+import { Layout } from 'antd';
+import { useIntl } from "react-intl";
+import type { MenuProps } from 'antd';
+import { Menu } from 'antd';
+
+const onClick: MenuProps['onClick'] = e => {
+    console.log('click ', e);
+  };
+
+type IWidgetHeadBar ={
+	selectedKeys?: string
+}
+const Widget = ({selectedKeys = ''}: IWidgetHeadBar) => {
+	//Library head bar
+	const intl = useIntl();//i18n
+	// TODO
+	const items: MenuProps['items'] = [
+		{
+		  label: (<Link to = "/community">{intl.formatMessage({ id: "columns.library.community.title" })}</Link>),
+		  key: 'community',
+		},
+		{
+			label: (<Link to = "/palicanon">{intl.formatMessage({ id: "columns.library.palicanon.title" })}</Link>),
+			key: 'palicanon',
+		},
+		{
+			label: (<Link to = "/course">{intl.formatMessage({ id: "columns.library.course.title" })}</Link>),
+			key: 'course',
+		},
+		{
+			label: (<Link to = "/dict">{intl.formatMessage({ id: "columns.library.dict.title" })}</Link>),
+			key: 'dict',
+		},
+		{
+			label: (<Link to = "/anthology">{intl.formatMessage({ id: "columns.library.anthology.title" })}</Link>),
+			key: 'anthology',
+		},		
+		{
+			label: (<a href = "https://asset-hk.wikipali.org/help/zh-Hans" target="_blank" rel="noreferrer">{intl.formatMessage({ id: "columns.library.help.title" })}</a>),
+			key: 'help',
+		},
+	];
+  return (
+	<Layout>
+		<Menu onClick={onClick} selectedKeys={[selectedKeys]} mode="horizontal" theme="dark" items={items} />
+	</Layout>
+  );
+};
+
+export default Widget;

+ 0 - 0
dashboard/src/components/library/article/.txt


+ 33 - 0
dashboard/src/components/library/blog/HeadBar.tsx

@@ -0,0 +1,33 @@
+import { Link } from "react-router-dom";
+import { Space } from "antd";
+import { useIntl } from "react-intl";
+
+const Widget = () => {
+	//Library head bar
+	const intl = useIntl();//i18n
+	// TODO
+  return (
+	<Space>
+		<Link to="/community">
+			{intl.formatMessage({ id: "columns.library.community.title" })}
+		</Link>
+		<Link to="/palicanon">
+			{intl.formatMessage({ id: "columns.library.palicanon.title" })}
+		</Link>
+		<Link to="/course">
+			{intl.formatMessage({ id: "columns.library.course.title" })}
+		</Link>
+		<Link to="/term">
+			{intl.formatMessage({ id: "columns.library.term.title" })}
+		</Link>
+		<Link to="/dict">
+			{intl.formatMessage({ id: "columns.library.dict.title" })}
+		</Link>
+		<Link to="/anthology">
+			{intl.formatMessage({ id: "columns.library.anthology.title" })}
+		</Link>
+	</Space>
+  );
+};
+
+export default Widget;

+ 0 - 0
dashboard/src/components/library/dict/.txt


+ 0 - 0
dashboard/src/components/library/palicanon/.txt


+ 5 - 0
dashboard/src/components/studio/Footer.tsx

@@ -0,0 +1,5 @@
+const Widget = () => {
+  return <div>Studio Footer</div>;
+};
+
+export default Widget;

+ 15 - 0
dashboard/src/components/studio/HeadBar.tsx

@@ -0,0 +1,15 @@
+import { Link } from "react-router-dom";
+import { Space } from "antd";
+
+const Widget = () => {
+  return (
+  	<div>
+		studio head bar
+		<Space>
+			<Link to="/">首页</Link>
+		</Space>
+	</div>
+  );
+};
+
+export default Widget;

+ 56 - 0
dashboard/src/components/studio/LeftSider.tsx

@@ -0,0 +1,56 @@
+import { Link } from "react-router-dom";
+import { Space } from "antd";
+import { useIntl } from "react-intl";
+import { useParams } from "react-router-dom";
+
+const Widget = () => {
+	//Library head bar
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();
+	// TODO
+	const linkPalicanon = "/studio/"+studioname+"/palicanon";
+	const linkRecent = "/studio/"+studioname+"/recent";
+	const linkChannel = "/studio/"+studioname+"/channel";
+	const linkGroup = "/studio/"+studioname+"/group";
+	const linkUserdict = "/studio/"+studioname+"/dict";
+	const linkTerm = "/studio/"+studioname+"/term";
+	const linkArticle = "/studio/"+studioname+"/article";
+	const linkAnthology = "/studio/"+studioname+"/anthology";
+	const linkAnalysis = "/studio/"+studioname+"/analysis";
+  return (
+  <div>
+	<Space>
+		<Link to={linkPalicanon}>
+			{intl.formatMessage({ id: "columns.studio.palicanon.title" })}
+		</Link>
+		<Link to={linkRecent}>
+			{intl.formatMessage({ id: "columns.studio.recent.title" })}
+		</Link>
+		<Link to={linkChannel}>
+			{intl.formatMessage({ id: "columns.studio.channel.title" })}
+		</Link>
+		<Link to={linkGroup}>
+			{intl.formatMessage({ id: "columns.studio.group.title" })}
+		</Link>
+		<Link to={linkUserdict}>
+			{intl.formatMessage({ id: "columns.studio.userdict.title" })}
+		</Link>
+		<Link to={linkTerm}>
+			{intl.formatMessage({ id: "columns.studio.term.title" })}
+		</Link>
+		<Link to={linkArticle}>
+			{intl.formatMessage({ id: "columns.studio.article.title" })}
+		</Link>
+		<Link to={linkAnthology}>
+			{intl.formatMessage({ id: "columns.studio.anthology.title" })}
+		</Link>
+		<Link to={linkAnalysis}>
+			{intl.formatMessage({ id: "columns.studio.analysis.title" })}
+		</Link>
+	</Space>
+
+  </div>
+  );
+};
+
+export default Widget;

+ 3 - 0
dashboard/src/locales/README.md

@@ -0,0 +1,3 @@
+# i18n
+
+nut目录为练习用途。里面的内容可能会被删除。**线上不要使用**。

+ 15 - 0
dashboard/src/locales/zh-Hans/channel/index.ts

@@ -0,0 +1,15 @@
+const items = {
+  "channel.title": "版本风格",
+  "channel.type": "类型",
+  "channel.name": "名称",
+  "channel.create.message.noname": "请输入版本名称",
+  "channel.type.nissaya.title": "逐词解析",
+  "channel.type.translation.title": "译文",
+  "channel.lang": "语言",
+  "channel.fields.lang.label": "语言",
+  "channel.fields.type.label": "类型",
+  "channel.fields.name.label": "名称",
+
+};
+
+export default items;

+ 16 - 0
dashboard/src/locales/zh-Hans/dict/index.ts

@@ -0,0 +1,16 @@
+const items = {
+  "dict": "字典",
+  "dict.fields.sn.label": "序号",
+  "dict.fields.word.label": "词头",
+  "dict.fields.type.label": "类型",
+  "dict.fields.grammar.label": "语法信息",
+  "dict.fields.parent.label": "词干",
+  "dict.fields.meaning.label": "意思",
+  "dict.fields.factors.label": "组份",
+  "dict.fields.factormeaning.label": "组份意思",
+  "dict.fields.note.label": "注释",
+  "dict.fields.confidence.label": "信心指数",
+  "dict.fields.dictname.label": "字典名称",
+};
+
+export default items;

+ 24 - 0
dashboard/src/locales/zh-Hans/index.ts

@@ -2,13 +2,37 @@ import forms from "./forms";
 import buttons from "./buttons";
 import tables from "./tables";
 import nut from "./nut";
+import channel from "./channel";
+import dict from "./dict";
 
 const items = {
   "flashes.success": "操作成功",
+  "columns.library.title": "藏经阁",
+  "columns.library.community.title": "社区",
+  "columns.library.palicanon.title": "圣典",
+  "columns.library.course.title": "课程",
+  "columns.library.term.title": "术语百科",
+  "columns.library.dict.title": "字典",
+  "columns.library.anthology.title": "文集",
+  "columns.library.help.title": "帮助",
+  "columns.library.convertor.title": "巴利字符转换器",
+  "columns.library.palihandbook.title": "语法手册",
+  "columns.studio.title": "译经楼",
+  "columns.studio.palicanon.title": "圣典",
+  "columns.studio.recent.title": "最近编辑",
+  "columns.studio.channel.title": "版本风格",
+  "columns.studio.group.title": "群组",
+  "columns.studio.userdict.title": "用户字典",
+  "columns.studio.term.title": "术语",
+  "columns.studio.article.title": "文章",
+  "columns.studio.anthology.title": "文集",
+  "columns.studio.analysis.title": "分析",
   ...buttons,
   ...forms,
   ...tables,
   ...nut,
+  ...channel,
+  ...dict,
 };
 
 export default items;

+ 3 - 0
dashboard/src/pages/README.md

@@ -0,0 +1,3 @@
+# 前端页面
+
+nut目录为练习用途。里面的内容可能会被删除。**线上不要使用**。

+ 23 - 0
dashboard/src/pages/library/anthology/article.tsx

@@ -0,0 +1,23 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { article_id } = useParams();//url 参数
+
+  return (
+    <div>
+		<HeadBar />
+      <div>文章阅读器{article_id}</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 24 - 0
dashboard/src/pages/library/anthology/index.tsx

@@ -0,0 +1,24 @@
+import { Space } from "antd";
+import { Link } from "react-router-dom";
+
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+  return (
+    <div>
+		<HeadBar selectedKeys="anthology"/>
+      <div>文集首页</div>
+	  <div>
+	  	<Space>
+			<Link to="/anthology/show/12345">文集1</Link>
+			<Link to="/article/show/23456">文章1</Link>
+		</Space>
+	  </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/library/anthology/show.tsx

@@ -0,0 +1,22 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { anthology_id } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar selectedKeys="anthology"/>
+      <div>文集{anthology_id}详情</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/library/blog/anthology.tsx

@@ -0,0 +1,23 @@
+import { Space } from "antd";
+import { useParams, Link } from "react-router-dom";
+import HeadBar from "../../../components/library/blog/HeadBar";
+import Footer from "../../../components/library/Footer";
+const Widget = () => {
+	// TODO
+	const { courseid } = useParams();//url 参数
+  return (
+    <div>
+	<HeadBar />
+      <div>课程{courseid} 详情</div>
+	  <div>
+	  	<Space>
+			<Link to="/course/lesson/12345">lesson 1</Link>
+			<Link to="/course/lesson/23456">lesson 2</Link>
+		</Space>
+	  </div>
+	  <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/library/blog/course.tsx

@@ -0,0 +1,22 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+import HeadBar from "../../../components/library/blog/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { lessonid } = useParams();//url 参数
+
+  return (
+    <div>
+		<HeadBar />
+      <div>课 {lessonid} 详情</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+	  <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/library/blog/index.tsx

@@ -0,0 +1,23 @@
+import { Space } from "antd";
+import { Link } from "react-router-dom";
+import HeadBar from "../../../components/library/blog/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+  return (
+    <div>
+		<HeadBar />
+      <div>课程首页</div>
+	  <div>
+	  	<Space>
+			<Link to="/course/show/12345">课程1</Link>
+			<Link to="/course/show/23456">课程2</Link>
+		</Space>
+	  </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/library/blog/term.tsx

@@ -0,0 +1,22 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+import HeadBar from "../../../components/library/blog/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { lessonid } = useParams();//url 参数
+
+  return (
+    <div>
+		<HeadBar />
+      <div>课 {lessonid} 详情</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+	  <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/library/blog/translation.tsx

@@ -0,0 +1,23 @@
+import { Space } from "antd";
+import { useParams, Link } from "react-router-dom";
+import HeadBar from "../../../components/library/blog/HeadBar";
+import Footer from "../../../components/library/Footer";
+const Widget = () => {
+	// TODO
+	const { courseid } = useParams();//url 参数
+  return (
+    <div>
+	<HeadBar />
+      <div>课程{courseid} 详情</div>
+	  <div>
+	  	<Space>
+			<Link to="/course/lesson/12345">lesson 1</Link>
+			<Link to="/course/lesson/23456">lesson 2</Link>
+		</Space>
+	  </div>
+	  <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 19 - 0
dashboard/src/pages/library/community/index.tsx

@@ -0,0 +1,19 @@
+import { Space } from "antd";
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+  return (
+    <div>
+		<HeadBar selectedKeys="community" />
+      <div>最新译文</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 26 - 0
dashboard/src/pages/library/community/recent.tsx

@@ -0,0 +1,26 @@
+import {Outlet,Link} from "react-router-dom";
+import {Space} from "antd";
+
+const Widget = () =>{
+	return (
+		<div>
+			<div>
+				我的阅读
+			</div>
+			<div>
+				<Outlet />
+				<div>
+					<Space>
+						<Link to="/">Home</Link>
+						<Link to="/community">社区</Link>
+					</Space>
+				</div>
+			</div>
+			<div>
+				底部区域
+			</div>
+		</div>
+	)
+}
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/library/course/course.tsx

@@ -0,0 +1,23 @@
+import { Space } from "antd";
+import { useParams, Link } from "react-router-dom";
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+const Widget = () => {
+	// TODO
+	const { courseid } = useParams();//url 参数
+  return (
+    <div>
+	<HeadBar  selectedKeys="course"/>
+      <div>课程{courseid} 详情</div>
+	  <div>
+	  	<Space>
+			<Link to="/course/lesson/12345">lesson 1</Link>
+			<Link to="/course/lesson/23456">lesson 2</Link>
+		</Space>
+	  </div>
+	  <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/library/course/index.tsx

@@ -0,0 +1,23 @@
+import { Space } from "antd";
+import { Link } from "react-router-dom";
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+  return (
+    <div>
+		<HeadBar selectedKeys="course"/>
+      <div>课程首页</div>
+	  <div>
+	  	<Space>
+			<Link to="/course/show/12345">课程1</Link>
+			<Link to="/course/show/23456">课程2</Link>
+		</Space>
+	  </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/library/course/lesson.tsx

@@ -0,0 +1,22 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { lessonid } = useParams();//url 参数
+
+  return (
+    <div>
+		<HeadBar  selectedKeys="course"/>
+      <div>课 {lessonid} 详情</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+	  <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 19 - 0
dashboard/src/pages/library/dict/index.tsx

@@ -0,0 +1,19 @@
+import { Space } from "antd";
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+  return (
+    <div>
+		<HeadBar  selectedKeys="dict"/>
+      <div>字典首页</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/library/dict/show.tsx

@@ -0,0 +1,22 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { word } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar selectedKeys="dict"/>
+      <div>字典-单词-{word}</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 19 - 0
dashboard/src/pages/library/palicanon/index.tsx

@@ -0,0 +1,19 @@
+import { Space } from "antd";
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+  return (
+    <div>
+		<HeadBar selectedKeys="palicanon" />
+      <div>圣典分类</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/library/term/show.tsx

@@ -0,0 +1,22 @@
+import { Space } from "antd";
+import { useParams } from "react-router-dom";
+
+import HeadBar from "../../../components/library/HeadBar";
+import Footer from "../../../components/library/Footer";
+
+const Widget = () => {
+	// TODO
+	const { word } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar />
+      <div>术语百科 单词-{word}</div>
+      <div>
+		<Space>主显示区</Space>
+      </div>
+		<Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 11 - 1
dashboard/src/pages/nut/index.tsx

@@ -1,5 +1,15 @@
+import HeadBar from "../../components/library/HeadBar";
+import Footer from "../../components/library/Footer";
+
 const Widget = () => {
-  return <div>Home Page</div>;
+  return (
+	<div>
+		<HeadBar  />
+		<div>Home Page</div>
+		<Footer />
+	</div>
+  	
+  );
 };
 
 export default Widget;

+ 26 - 0
dashboard/src/pages/studio/analysis/index.tsx

@@ -0,0 +1,26 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.analysis.title" })}/行为分析首页</h2>
+      <div>
+		<Space>
+			<Link to=""> </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/studio/anthology/edit.tsx

@@ -0,0 +1,23 @@
+import { useParams } from "react-router-dom";
+import { useIntl } from "react-intl";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();
+	const { studioname,anthology_id } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.anthology.title" })}/anthology/{anthology_id}</h2>
+      <div>
+		
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 27 - 0
dashboard/src/pages/studio/anthology/index.tsx

@@ -0,0 +1,27 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+	const linkEdit = `/studio/${studioname}/anthology/edit/12345`;
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.article.title" })}/文集列表</h2>
+      <div>
+		<Space>
+			<Link to={linkEdit}> anthology edit </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 23 - 0
dashboard/src/pages/studio/article/edit.tsx

@@ -0,0 +1,23 @@
+import { useParams } from "react-router-dom";
+import { useIntl } from "react-intl";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();
+	const { studioname,articleid } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.article.title" })}/edit/{articleid}</h2>
+      <div>
+		
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 27 - 0
dashboard/src/pages/studio/article/index.tsx

@@ -0,0 +1,27 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+	const linkEdit = `/studio/${studioname}/article/edit/12345`;
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.article.title" })}/文章列表</h2>
+      <div>
+		<Space>
+			<Link to={linkEdit}> article edit </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 60 - 0
dashboard/src/pages/studio/channel/create.tsx

@@ -0,0 +1,60 @@
+import { useParams } from "react-router-dom";
+import { ProForm, ProFormText , ProFormSelect } from "@ant-design/pro-components";
+import { useIntl } from "react-intl";
+import { Link } from "react-router-dom";
+import { Space,message } from "antd";
+interface IFormData {
+	name: string;
+	type: string;
+  }
+const Widget = () => {
+	const intl = useIntl();
+	const { studioname } = useParams();
+  return (
+    <div>
+      <div>studio/{studioname}/{intl.formatMessage({ id: "title.channel" })}/create</div>
+      <div>
+        <div>
+          <Space>
+            <Link to="/">Home</Link>
+            <Link to="/community/myread">{studioname}</Link>
+          </Space>
+        </div>
+		
+		<div>
+		<ProForm<IFormData>
+		onFinish={async (values: IFormData) => {
+			// TODO
+			console.log(values);
+			message.success(intl.formatMessage({ id: "flashes.success" }));
+		}}
+		>
+		<ProForm.Group>
+			<ProFormText
+			width="md"
+			name="name"
+			required
+			label={intl.formatMessage({ id: "channel.name" })}
+			rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+		/>
+		</ProForm.Group>
+		<ProForm.Group>
+			<ProFormSelect
+				options={[
+					{value: 'translation', label: intl.formatMessage({ id: "channel.type.translation.title" }), },
+					{value: 'nissaya', label: intl.formatMessage({ id: "channel.type.nissaya.title" }), },
+				]}
+				width="md"
+				name="type"
+				label={intl.formatMessage({ id: "channel.type" })}
+				/>
+		</ProForm.Group>
+		</ProForm>
+		</div>
+      </div>
+      <div>底部区域</div>
+    </div>
+  );
+};
+
+export default Widget;

+ 83 - 0
dashboard/src/pages/studio/channel/edit.tsx

@@ -0,0 +1,83 @@
+import { useParams } from "react-router-dom";
+import { ProForm, ProFormText , ProFormSelect,ProFormTextArea } from "@ant-design/pro-components";
+import { useIntl } from "react-intl";
+import { message } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+interface IFormData {
+	name: string;
+	type: string;
+	lang: string;
+	summary: string;
+	studio: string;
+  }
+const Widget = () => {
+	const intl = useIntl();
+	const { studioname,channelid } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.channel.title" })}/edit/{channelid}</h2>
+      <div>
+		
+		<div>
+		<ProForm<IFormData>
+		onFinish={async (values: IFormData) => {
+			// TODO
+			values.studio = "aaaa";
+			console.log(values);
+			message.success(intl.formatMessage({ id: "flashes.success" }));
+		}}
+		>
+		<ProForm.Group>
+			<ProFormText
+			width="md"
+			name="name"
+			required
+			label={intl.formatMessage({ id: "channel.name" })}
+			rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+			/>
+		</ProForm.Group>
+		
+		<ProForm.Group>
+			<ProFormSelect
+				options={[
+					{value: 'translation', label: intl.formatMessage({ id: "channel.type.translation.title" }), },
+					{value: 'nissaya', label: intl.formatMessage({ id: "channel.type.nissaya.title" }), },
+				]}
+				width="md"
+				name="type"
+				rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+				label={intl.formatMessage({ id: "channel.type" })}
+				/>
+		</ProForm.Group>
+		<ProForm.Group>
+			<ProFormSelect
+				options={[
+					{value: 'zh-Hans', label: "简体中文", },
+					{value: 'zh-Hant', label: "繁体中文", },
+					{value: 'en-US', label: "English", },
+				]}
+				width="md"
+				name="lang"
+				rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+				label={intl.formatMessage({ id: "channel.lang" })}
+				/>
+		</ProForm.Group>
+
+		<ProForm.Group>
+			<ProFormTextArea  name="summary" label="简介" />
+		</ProForm.Group>
+
+		</ProForm>
+		</div>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 27 - 0
dashboard/src/pages/studio/channel/index.tsx

@@ -0,0 +1,27 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+	const linkEdit = `/studio/${studioname}/channel/edit/12345`;
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.channel.title" })}/版本列表</h2>
+      <div>
+		<Space>
+			<Link to={linkEdit}> channel1 edit </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 166 - 0
dashboard/src/pages/studio/dict/index.tsx

@@ -0,0 +1,166 @@
+import { useParams } from "react-router-dom";
+import { ProTable } from "@ant-design/pro-components";
+import { useIntl } from "react-intl";
+import { Link } from "react-router-dom";
+import { Button,Layout } from "antd";
+import {  PlusOutlined } from '@ant-design/icons';
+
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+interface IItem {
+  id: number;
+  word: string;
+  type: string;
+  grammar: string;
+  parent: string;
+  meaning: string;  
+  note: string;
+  factors: string;
+  createdAt: number;
+}
+
+const valueEnum = {
+	0: 'n',
+	1: 'ti',
+	2: 'v',
+	3: 'ind',
+  };
+
+const Widget = () => {
+  const intl = useIntl();
+  const { studioname } = useParams();
+  return (
+	<Layout>
+		<HeadBar/>
+		<LeftSider/>
+		<Layout>{studioname}</Layout>
+    <ProTable<IItem>
+      columns={[
+        {
+          title: intl.formatMessage({ id: "dict.fields.sn.label" }),
+          dataIndex: "id",
+          key: "id",
+          width: 80,
+          search: false,
+        },
+        {
+          title: intl.formatMessage({ id: "dict.fields.word.label" }),
+          dataIndex: "word",
+          key: "word",
+		  render: (_) => <Link to="">{_}</Link>,
+		  tip: '单词过长会自动收缩',
+		  ellipsis: true,
+		  formItemProps: {
+			rules: [
+			  {
+				required: true,
+				message: '此项为必填项',
+			  },
+			],
+		  },
+        },
+		{
+			title: intl.formatMessage({ id: "dict.fields.type.label" }),
+			dataIndex: "type",
+			key: "type",
+			search: false,
+			filters: true,
+			onFilter: true,
+			valueEnum: {
+			  all: { text: '全部', status: 'Default' },
+			  n: { text: '名词', status: 'Default' },
+			  ti: { text: '三性', status: 'Processing' },
+			  v: { text: '动词', status: 'Success' },
+			  ind: { text: '不变词', status: 'Success' },
+			},
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.grammar.label" }),
+			dataIndex: "grammar",
+			key: "grammar",
+			search: false,
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.parent.label" }),
+			dataIndex: "parent",
+			key: "parent",
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.meaning.label" }),
+			dataIndex: "meaning",
+			key: "meaning",
+			tip: '意思过长会自动收缩',
+			ellipsis: true,
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.note.label" }),
+			dataIndex: "note",
+			key: "note",
+			search: false,
+			tip: '注释过长会自动收缩',
+			ellipsis: true,
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.factors.label" }),
+			dataIndex: "factors",
+			key: "factors",
+			search: false,
+		},
+        {
+          title: intl.formatMessage({ id: "forms.fields.created-at.label" }),
+          key: "created-at",
+          width: 200,
+
+          search: false,
+		  dataIndex: 'createdAt',
+		  valueType: 'date',
+    	sorter: (a, b) => a.createdAt - b.createdAt,
+        },
+      ]}
+      request={async (params = {}, sorter, filter) => {
+        // TODO
+        console.log(params, sorter, filter);
+
+        const size = params.pageSize || 20;
+        return {
+          total: 1 << 12,
+          success: true,
+          data: Array.from(Array(size).keys()).map((x) => {
+            const id = ((params.current || 1) - 1) * size + x + 1;
+			
+            var it: IItem = {
+              id,
+              word: `word ${id}`,
+			  type: valueEnum[2],
+			  grammar: "阳-单-属",
+			  parent: `parent ${id}`,
+			  meaning: `meaning ${id}`,
+			  note: `note ${id}`,
+			  factors: `factors ${id}`,
+              createdAt: Date.now() - Math.floor(Math.random() * 200000),
+            };
+            return it;
+          }),
+        };
+      }}
+      rowKey="id"
+      bordered
+      pagination={{
+        showQuickJumper: true,
+        showSizeChanger: true,
+      }}
+      headerTitle={intl.formatMessage({ id: "dict" })}
+	  toolBarRender={() => [
+        <Button key="button" icon={<PlusOutlined />} type="primary">
+          新建
+        </Button>,
+      ]}
+    />
+	<Footer/>
+	</Layout>
+  );
+};
+
+export default Widget;

+ 83 - 0
dashboard/src/pages/studio/group/edit.tsx

@@ -0,0 +1,83 @@
+import { useParams } from "react-router-dom";
+import { ProForm, ProFormText , ProFormSelect,ProFormTextArea } from "@ant-design/pro-components";
+import { useIntl } from "react-intl";
+import { message } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+interface IFormData {
+	name: string;
+	type: string;
+	lang: string;
+	summary: string;
+	studio: string;
+  }
+const Widget = () => {
+	const intl = useIntl();
+	const { studioname,groupid } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.group.title" })}/edit/{groupid}</h2>
+      <div>
+		
+		<div>
+		<ProForm<IFormData>
+		onFinish={async (values: IFormData) => {
+			// TODO
+			values.studio = "aaaa";
+			console.log(values);
+			message.success(intl.formatMessage({ id: "flashes.success" }));
+		}}
+		>
+		<ProForm.Group>
+			<ProFormText
+			width="md"
+			name="name"
+			required
+			label={intl.formatMessage({ id: "channel.name" })}
+			rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+			/>
+		</ProForm.Group>
+		
+		<ProForm.Group>
+			<ProFormSelect
+				options={[
+					{value: 'translation', label: intl.formatMessage({ id: "channel.type.translation.title" }), },
+					{value: 'nissaya', label: intl.formatMessage({ id: "channel.type.nissaya.title" }), },
+				]}
+				width="md"
+				name="type"
+				rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+				label={intl.formatMessage({ id: "channel.type" })}
+				/>
+		</ProForm.Group>
+		<ProForm.Group>
+			<ProFormSelect
+				options={[
+					{value: 'zh-Hans', label: "简体中文", },
+					{value: 'zh-Hant', label: "繁体中文", },
+					{value: 'en-US', label: "English", },
+				]}
+				width="md"
+				name="lang"
+				rules={[{ required: true, message: intl.formatMessage({ id: "channel.create.message.noname" }) }]}
+				label={intl.formatMessage({ id: "channel.lang" })}
+				/>
+		</ProForm.Group>
+
+		<ProForm.Group>
+			<ProFormTextArea  name="summary" label="简介" />
+		</ProForm.Group>
+
+		</ProForm>
+		</div>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 29 - 0
dashboard/src/pages/studio/group/index.tsx

@@ -0,0 +1,29 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+	const linkEdit = `/studio/${studioname}/group/edit/12345`;
+	const linkShow = `/studio/${studioname}/group/12345`;
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.channel.title" })}/版本列表</h2>
+      <div>
+		<Space>
+			<Link to={linkEdit}> group1 edit </Link>
+			<Link to={linkShow}> group1 show </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 25 - 0
dashboard/src/pages/studio/group/show.tsx

@@ -0,0 +1,25 @@
+import { useParams } from "react-router-dom";
+import { useIntl } from "react-intl";
+
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+
+const Widget = () => {
+	const intl = useIntl();
+	const { studioname,groupid } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.channel.title" })}/show/{groupid}</h2>
+      <div>
+		群组详情
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 26 - 0
dashboard/src/pages/studio/index.tsx

@@ -0,0 +1,26 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../components/studio/HeadBar";
+import LeftSider from "../../components/studio/LeftSider";
+import Footer from "../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/首页</h2>
+      <div>
+		<Space>
+			<Link to=""> </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 26 - 0
dashboard/src/pages/studio/palicanon/index.tsx

@@ -0,0 +1,26 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.palicanon.title" })}</h2>
+      <div>
+		<Space>
+			<Link to=""> </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 26 - 0
dashboard/src/pages/studio/recent/index.tsx

@@ -0,0 +1,26 @@
+import { useParams ,Link} from "react-router-dom";
+import { useIntl } from "react-intl";
+import { Space } from "antd";
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+const Widget = () => {
+	const intl = useIntl();//i18n
+	const { studioname } = useParams();//url 参数
+  return (
+    <div>
+		<HeadBar/>
+		<LeftSider/>
+      <h2>studio/{studioname}/{intl.formatMessage({ id: "columns.studio.recent.title" })}</h2>
+      <div>
+		<Space>
+			<Link to=""> </Link>
+		</Space>
+      </div>
+      <Footer/>
+    </div>
+  );
+};
+
+export default Widget;

+ 167 - 0
dashboard/src/pages/studio/term/index.tsx

@@ -0,0 +1,167 @@
+import { useParams } from "react-router-dom";
+import { ProTable } from "@ant-design/pro-components";
+import { useIntl } from "react-intl";
+import { Link } from "react-router-dom";
+import { Button,Layout } from "antd";
+import {  PlusOutlined } from '@ant-design/icons';
+
+import HeadBar from "../../../components/studio/HeadBar";
+import LeftSider from "../../../components/studio/LeftSider";
+import Footer from "../../../components/studio/Footer";
+
+interface IItem {
+  id: number;
+  word: string;
+  type: string;
+  grammar: string;
+  parent: string;
+  meaning: string;  
+  note: string;
+  factors: string;
+  createdAt: number;
+}
+
+const valueEnum = {
+	0: 'n',
+	1: 'ti',
+	2: 'v',
+	3: 'ind',
+  };
+
+const Widget = () => {
+  const intl = useIntl();
+  const { studioname } = useParams();
+  return (
+	<Layout>
+		<HeadBar/>
+		<LeftSider/>
+		<Layout>{studioname}</Layout>
+    <ProTable<IItem>
+      columns={[
+        {
+          title: intl.formatMessage({ id: "dict.fields.sn.label" }),
+          dataIndex: "id",
+          key: "id",
+          width: 80,
+          search: false,
+        },
+        {
+          title: intl.formatMessage({ id: "dict.fields.word.label" }),
+          dataIndex: "word",
+          key: "word",
+		  render: (_) => <Link to="">{_}</Link>,
+		  tip: '单词过长会自动收缩',
+		  ellipsis: true,
+		  formItemProps: {
+			rules: [
+			  {
+				required: true,
+				message: '此项为必填项',
+			  },
+			],
+		  },
+        },
+		{
+			title: intl.formatMessage({ id: "dict.fields.type.label" }),
+			dataIndex: "type",
+			key: "type",
+			search: false,
+			filters: true,
+			onFilter: true,
+			valueEnum: {
+			  all: { text: '全部', status: 'Default' },
+			  n: { text: '名词', status: 'Default' },
+			  ti: { text: '三性', status: 'Processing' },
+			  v: { text: '动词', status: 'Success' },
+			  ind: { text: '不变词', status: 'Success' },
+			},
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.grammar.label" }),
+			dataIndex: "grammar",
+			key: "grammar",
+			search: false,
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.parent.label" }),
+			dataIndex: "parent",
+			key: "parent",
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.meaning.label" }),
+			dataIndex: "meaning",
+			key: "meaning",
+			tip: '意思过长会自动收缩',
+			ellipsis: true,
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.note.label" }),
+			dataIndex: "note",
+			key: "note",
+			search: false,
+			tip: '注释过长会自动收缩',
+			ellipsis: true,
+		},
+		{
+			title: intl.formatMessage({ id: "dict.fields.factors.label" }),
+			dataIndex: "factors",
+			key: "factors",
+			search: false,
+		},
+        {
+          title: intl.formatMessage({ id: "forms.fields.created-at.label" }),
+          key: "created-at",
+          width: 200,
+
+          search: false,
+		  dataIndex: 'createdAt',
+		  valueType: 'date',
+    	sorter: (a, b) => a.createdAt - b.createdAt,
+        },
+      ]}
+      request={async (params = {}, sorter, filter) => {
+        // TODO
+        console.log(params, sorter, filter);
+
+        const size = params.pageSize || 20;
+        return {
+          total: 1 << 12,
+          success: true,
+          data: Array.from(Array(size).keys()).map((x) => {
+            const id = ((params.current || 1) - 1) * size + x + 1;
+			
+            var it: IItem = {
+              id,
+              word: `word ${id}`,
+			  type: valueEnum[2],
+			  grammar: "阳-单-属",
+			  parent: `parent ${id}`,
+			  meaning: `meaning ${id}`,
+			  note: `note ${id}`,
+			  factors: `factors ${id}`,
+              createdAt: Date.now() - Math.floor(Math.random() * 200000),
+            };
+            return it;
+          }),
+        };
+      }}
+      rowKey="id"
+      bordered
+      pagination={{
+        showQuickJumper: true,
+        showSizeChanger: true,
+      }}
+      headerTitle={intl.formatMessage({ id: "dict" })}
+	  toolBarRender={() => [
+        <Button key="button" icon={<PlusOutlined />} type="primary">
+          新建
+        </Button>,
+      ]}
+    />
+	<Footer/>
+
+	</Layout>
+  );
+};
+
+export default Widget;