bianjiang 1 ano atrás
pai
commit
fb9aa2b4d7

+ 1 - 1
package.json

@@ -2,7 +2,7 @@
   "name": "demo",
   "private": true,
   "version": "0.0.0",
-  "type": "module",
+  "type": "commonjs",
   "scripts": {
     "dev": "vite",
     "build": "vue-tsc && vite build",

+ 2 - 2
src/components/Provider/index.tsx

@@ -2,10 +2,10 @@ import { ConfigProvider } from "ant-design-vue";
 import { defineComponent } from "vue";
 import { LoadingProvider } from "./Loading";
 import { ModalProvider } from "./Modal";
-
+import zhCN from "ant-design-vue/es/locale/zh_CN";
 export const Provider = defineComponent((props, { slots }) => {
   return () => (
-    <ConfigProvider>
+    <ConfigProvider locale={zhCN}>
       {slots.default?.()}
       <ModalProvider />
       <LoadingProvider />

+ 11 - 8
src/modules/components/CategoryModal.tsx

@@ -2,7 +2,7 @@ import Modal from "@/components/Provider/Modal";
 import { css } from "@linaria/core";
 import { Button, Checkbox, Form, Input, Select } from "ant-design-vue";
 import { defineComponent, onMounted, reactive, ref } from "vue";
-import { any } from "vue-types";
+import { any, number } from "vue-types";
 import UploadImage from "./UploadImage";
 import { uploader } from "../objects";
 const layout = {
@@ -13,6 +13,7 @@ const layout = {
 export default defineComponent({
   props: {
     data: any(),
+    level: number(),
   },
   setup(props) {
     const modal = Modal.use();
@@ -54,13 +55,15 @@ export default defineComponent({
       return (
         <div class={EditStyle}>
           <Form {...layout} onSubmit={submit}>
-            <Form.Item {...validateInfos.cover} wrapperCol={{ span: 24 }}>
-              <UploadImage
-                data={formState.formData.cover}
-                text={"上传菜单banner图"}
-                onChange={changeBanner}
-              ></UploadImage>
-            </Form.Item>
+            {props.level != 2 && (
+              <Form.Item {...validateInfos.cover} wrapperCol={{ span: 24 }}>
+                <UploadImage
+                  data={formState.formData.cover}
+                  text={"上传菜单banner图"}
+                  onChange={changeBanner}
+                ></UploadImage>
+              </Form.Item>
+            )}
             <Form.Item {...validateInfos.name} label={"菜单名称"}>
               <Input
                 placeholder={"请输入菜单名称"}

+ 7 - 4
src/modules/module/category/actions.tsx

@@ -2,10 +2,13 @@ import Modal from "@/components/Provider/Modal";
 import CategoryModal from "../../components/CategoryModal";
 
 export const categoryActions = {
-  async EditCategoryItem(item?: any) {
-    const base: any = await Modal.show(<CategoryModal data={item} />, {
-      title: item ? "编辑分类" : "添加分类",
-    });
+  async EditCategoryItem(item = {} as any, key = 0) {
+    const base: any = await Modal.show(
+      <CategoryModal data={item} level={key} />,
+      {
+        title: item._id ? "编辑菜单" : "添加菜单",
+      }
+    );
     return base;
   },
 };

+ 4 - 4
src/modules/module/category/index.ts

@@ -61,21 +61,21 @@ export const useCategory = defineStore("category", {
       this.listController.setCrudPrefix("/category");
       await this.listController.loadPage(1, 200);
     },
-    async addCategoryItem(pid = "top") {
-      const base = await categoryActions.EditCategoryItem();
+    async addCategoryItem(pid = "top", key = 0) {
+      const base = await categoryActions.EditCategoryItem({}, key + 1);
       const item = { pid, ...base };
       loading.show("保存中");
       await this.listController.addItem(item);
       loading.hidden();
       message.success("添加成功");
     },
-    async updateCategoryItem(item: any) {
+    async updateCategoryItem(item: any, key = 0) {
       const res = await this.listController.itemDetail(item._id);
       if (res.errorNo != 200) {
         message.warn("未查询到数据!");
         return;
       }
-      const base = await categoryActions.EditCategoryItem(res.result);
+      const base = await categoryActions.EditCategoryItem(res.result, key);
       loading.show("保存中");
       await this.listController.saveItem(base);
       loading.hidden();

+ 10 - 0
src/styles/main.css

@@ -11,11 +11,21 @@
   width: 100%;
   margin: 0 auto;
 }
+@media screen and (max-width: 1644px) {
+  .global_w {
+    padding: 0 20px;
+  }
+}
 .detail_page_w {
   max-width: 1200px;
   width: 100%;
   margin: 0 auto;
 }
+@media screen and (max-width: 1200px) {
+  .detail_page_w {
+    padding: 0 20px;
+  }
+}
 .image_error {
   background: #f2f2f2 url("../assets/image_error.png") no-repeat center;
 }

+ 1 - 0
src/typings/asset.d.ts

@@ -19,6 +19,7 @@ declare type ArticleItem = {
   summary?: string;
   content?: string; //内容
   sort: number;
+  createTime: string;
 };
 declare type BannerItem = {
   _id: string;

+ 4 - 4
src/views/admin/category/CategoryTree.tsx

@@ -32,7 +32,7 @@ export default defineComponent({
                   icon={<PlusSquareOutlined />}
                   onClick={(e) => {
                     e.stopPropagation();
-                    emit("add", item._id);
+                    emit("add", item._id, key);
                   }}
                 ></Button>
               )}
@@ -43,10 +43,10 @@ export default defineComponent({
                 icon={<FormOutlined />}
                 onClick={(e) => {
                   e.stopPropagation();
-                  emit("update", item);
+                  emit("update", item, key);
                 }}
               ></Button>
-              <Button
+              {/* <Button
                 class="tree_btn"
                 title="删除"
                 icon={<DeleteOutlined />}
@@ -54,7 +54,7 @@ export default defineComponent({
                   e.stopPropagation();
                   emit("delete", item);
                 }}
-              ></Button>
+              ></Button> */}
             </div>
           </div>
         );

+ 2 - 2
src/views/website/components/layout/Menu.tsx

@@ -59,8 +59,8 @@ const MenuLayout = css`
   a {
     flex: 1;
     position: relative;
-    margin-top: 14px;
-    padding-bottom: 24px;
+    margin-top: 16px;
+    padding-bottom: 22px;
     font-size: 16px;
     text-align: center;
     color: rgba(255, 255, 255, 0.8);

+ 16 - 3
src/views/website/detail/DetailPage.tsx

@@ -1,8 +1,9 @@
 import { useArticle } from "@/modules";
 import { css } from "@linaria/core";
 import loading from "@/components/Provider/Loading";
-import { defineComponent, onMounted, reactive } from "vue";
+import { defineComponent, onMounted, reactive, watch } from "vue";
 import { object } from "vue-types";
+import { Empty } from "ant-design-vue";
 
 export default defineComponent({
   props: {
@@ -13,8 +14,14 @@ export default defineComponent({
     const artStore = useArticle();
     const state = reactive({
       data: {} as any,
+      loading: true,
     });
-
+    watch(
+      () => props.data?._id,
+      () => {
+        initDetail();
+      }
+    );
     onMounted(() => {
       initDetail();
     });
@@ -32,12 +39,18 @@ export default defineComponent({
           state.data = detRes;
         }
       }
+      state.loading = false;
       loading.hidden();
     };
     return () => {
       return (
         <div class={page}>
-          <div class={"detail_page_w"} innerHTML={state.data.content}></div>
+          <div innerHTML={state.data.content}></div>
+          {!state.loading && !state.data.content && (
+            <div class={"ant-list-empty-text"}>
+              <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
+            </div>
+          )}
         </div>
       );
     };

+ 59 - 0
src/views/website/detail/List.tsx

@@ -0,0 +1,59 @@
+import { defineComponent, reactive } from "vue";
+import { array, bool, object, string } from "vue-types";
+
+import { List } from "ant-design-vue";
+import { css } from "@linaria/core";
+import { useRoute, useRouter } from "vue-router";
+
+export default defineComponent({
+  props: {
+    dataSource: array<any>().isRequired,
+    loading: bool(),
+    actions: object() as any,
+  },
+  setup(props, { slots }) {
+    const state = reactive({
+      loading: false,
+    });
+    const route = useRoute();
+    const router = useRouter();
+    return () => {
+      const { dataSource, actions } = props;
+      return (
+        <div class={ListContent}>
+          <List
+            loading={state.loading}
+            grid={{ gutter: 18, xs: 2, sm: 2, md: 2, lg: 3, xl: 4, xxl: 4 }}
+            dataSource={dataSource}
+            rowKey={(item) => item._id}
+            renderItem={({ item, index }) => {
+              return <List.Item>{slots.item?.(item, index)}</List.Item>;
+            }}
+            pagination={{
+              hideOnSinglePage: true,
+              current: actions.state.page * 1,
+              pageSize: actions.state.size,
+              total: actions.state.total,
+              onChange: (v) => {
+                const query = { ...route.query, page: v };
+                router.push({ path: route.path, query });
+              },
+            }}
+          ></List>
+        </div>
+      );
+    };
+  },
+});
+const ListContent = css`
+  .ant-list-pagination {
+    text-align: center;
+    .ant-pagination-item-active {
+      background: var(--vt-c-primary);
+      border-color: var(--vt-c-primary);
+      a {
+        color: #fff;
+      }
+    }
+  }
+`;

+ 267 - 0
src/views/website/detail/ListPage.tsx

@@ -0,0 +1,267 @@
+import { useArticle } from "@/modules";
+import { css } from "@linaria/core";
+import loading from "@/components/Provider/Loading";
+import { defineComponent, onMounted, reactive, watch } from "vue";
+import Image from "@/components/Image";
+import { any, object } from "vue-types";
+import List from "./List";
+import { useRoute, useRouter } from "vue-router";
+import dayjs from "dayjs";
+const teacherList = [
+  "6464ae7a8dcb7ddb98b57a28",
+  "6464b7ca8dcb7ddb98b57a63",
+  "6464b7d18dcb7ddb98b57a64",
+  "6464b7d78dcb7ddb98b57a65",
+  "6464b7dd8dcb7ddb98b57a66",
+  "6464b7e38dcb7ddb98b57a67",
+  "6464b7e98dcb7ddb98b57a68",
+  "6464b7f08dcb7ddb98b57a69",
+  "6464b7f68dcb7ddb98b57a6a",
+];
+export default defineComponent({
+  props: {
+    data: object<CategoryItem>(),
+  },
+  setup(props, { emit }) {
+    const data: any = props.data || {};
+    const artStore = useArticle();
+    artStore.listController.state.list = [];
+    const route = useRoute();
+    onMounted(() => {
+      initDetail();
+    });
+    watch(
+      () => route.query.page,
+      () => {
+        initDetail();
+      }
+    );
+
+    const initDetail = async () => {
+      loading.show("");
+      let page: any = 1;
+      if (route.query.page) {
+        page = route.query.page as string;
+      }
+      artStore.listController.state.query = JSON.stringify({
+        cid: data._id,
+      });
+      await artStore.listController.loadPage(page * 1);
+      loading.hidden();
+    };
+    const itemRender = (item: any, index: number) => {
+      if (teacherList.includes(data._id)) {
+        return <TeacherItem item={item} key={item._id} />;
+      }
+      return <ArticleItem item={item} key={item._id} />;
+    };
+    return () => {
+      return (
+        <div class={page}>
+          <div class={"list_content"}>
+            <List
+              dataSource={artStore.listController.state.list}
+              actions={artStore.listController}
+            >
+              {{
+                item: (item: any, index: number) => {
+                  return itemRender(item, index);
+                },
+              }}
+            </List>
+          </div>
+        </div>
+      );
+    };
+  },
+});
+const TeacherItem = defineComponent({
+  props: {
+    item: any(),
+  },
+  setup(props, ctx) {
+    const { item } = props;
+    const router = useRouter();
+    const route = useRoute();
+    return () => (
+      <div class={TeacherItemStyle}>
+        <div
+          class={"item"}
+          onClick={() => {
+            const id = route.params.id;
+            const aid = item._id;
+            router.push({ name: "article", params: { id }, query: { aid } });
+          }}
+        >
+          <Image src={item.cover} />
+          <div class={"item_footer"}>
+            <div class={"name"}>{item.title}</div>
+          </div>
+        </div>
+      </div>
+    );
+  },
+});
+const ArticleItem = defineComponent({
+  props: {
+    item: object<ArticleItem>(),
+  },
+  setup(props) {
+    const { item } = props;
+    const router = useRouter();
+    const route = useRoute();
+    const renderTitle = (title?: string) => {
+      if (title && title.length > 30) {
+        return title.substring(0, 30) + "...";
+      }
+      return title;
+    };
+    const renderSummary = (summary?: string) => {
+      if (summary && summary.length > 60) {
+        return summary.substring(0, 60) + "...";
+      }
+      return summary;
+    };
+    return () => (
+      <div class={ListItemStyle}>
+        <div
+          class={"item"}
+          onClick={() => {
+            const id = route.params.id;
+            const aid = item?._id;
+            router.push({ name: "article", params: { id }, query: { aid } });
+          }}
+        >
+          <div class={"list_img"}>
+            <Image src={item?.cover} />
+          </div>
+          <div class={"info_box"}>
+            <div class={"item_tit"}>{renderTitle(item?.title)}</div>
+            <div class={"item_desc"}>{renderSummary(item?.summary)}</div>
+            <div class={"item_date"}>
+              {dayjs(item?.createTime).format("YYYY.MM.DD")}
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  },
+});
+const page = css``;
+const TeacherItemStyle = css`
+  width: 100%;
+  height: 380px;
+  overflow: hidden;
+  .item {
+    display: block;
+    width: 100%;
+    height: 100%;
+    position: relative;
+    overflow: hidden;
+    cursor: pointer;
+    img {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+    }
+    &:hover {
+      .item_footer {
+        transform: translateY(0);
+      }
+    }
+    .item_footer {
+      position: absolute;
+      display: inline-flex;
+      flex-direction: column;
+      justify-content: flex-end;
+      bottom: 0;
+      left: 0;
+      width: 100%;
+      height: 140px;
+      padding: 0 24px 20px;
+      transform: translateY(100%);
+      background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%);
+      transition: all 0.3s ease-in-out;
+    }
+    .name {
+      color: #fff;
+      font-size: 18px;
+      font-weight: 600;
+    }
+  }
+`;
+const ListItemStyle = css`
+  width: 100%;
+  background-color: #fff;
+  overflow: hidden;
+  position: relative;
+  .item {
+    position: relative;
+    display: block;
+    border-bottom: 2px solid rgba(159, 159, 159, 0.5);
+    cursor: pointer;
+    &::before {
+      content: "";
+      position: absolute;
+      bottom: 0;
+      right: 0;
+      border-width: 6px;
+      border-color: transparent rgba(159, 159, 159, 0.5)
+        rgba(159, 159, 159, 0.5) transparent;
+    }
+    &::after {
+      content: "";
+      position: absolute;
+      bottom: -2px;
+      right: 0;
+      width: 0;
+      height: 2px;
+      background-color: var(--vt-c-primary);
+      transition: width 0.3s ease-in-out;
+    }
+    &:hover {
+      &::before {
+        border-color: transparent var(--vt-c-primary) var(--vt-c-primary)
+          transparent;
+      }
+      &::after {
+        width: 100%;
+      }
+      img {
+        transform: scale(1.2);
+      }
+    }
+  }
+  .list_img {
+    width: 100%;
+    height: 280px;
+    overflow: hidden;
+  }
+  img {
+    width: 100%;
+    height: 280px;
+    object-fit: cover;
+    transition: all 0.3s ease-in-out;
+  }
+  .info_box {
+    padding: 16px 12px;
+  }
+  .item_tit {
+    font-size: 16px;
+    line-height: 24px;
+    color: #333333;
+  }
+  .item_desc {
+    margin-top: 16px;
+    font-size: 12px;
+    line-height: 20px;
+    font-weight: 400;
+    color: #666666;
+  }
+  .item_date {
+    font-size: 12px;
+    margin-top: 18px;
+    font-weight: 300;
+    color: #999999;
+  }
+`;

+ 4 - 4
src/views/website/detail/PageTabs.tsx

@@ -1,6 +1,7 @@
 import { css } from "@linaria/core";
 
 import { defineComponent } from "vue";
+import { useRouter } from "vue-router";
 import { any, string } from "vue-types";
 
 export default defineComponent({
@@ -8,9 +9,8 @@ export default defineComponent({
     data: any(),
     activeKey: string(),
   },
-  emits: ["change"],
-  setup(props, { emit }) {
-    console.log(props.data);
+  setup(props) {
+    const router = useRouter();
     return () => {
       return (
         <div class={page}>
@@ -21,7 +21,7 @@ export default defineComponent({
                   class={["tabs_item", e._id == props.activeKey ? "cur" : ""]}
                   key={e._id}
                   onClick={() => {
-                    emit("change", e);
+                    router.push(`/detail/${e._id}`);
                   }}
                 >
                   {e.name}

+ 58 - 0
src/views/website/detail/PageTabsLow.tsx

@@ -0,0 +1,58 @@
+import { css } from "@linaria/core";
+
+import { defineComponent } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { any, string } from "vue-types";
+
+export default defineComponent({
+  props: {
+    data: any(),
+    activeKey: string(),
+  },
+  setup(props, { emit }) {
+    const router = useRouter();
+    const route = useRoute();
+    return () => {
+      return (
+        <div class={page}>
+          {props.data &&
+            props.data.map((e: CategoryItem) => {
+              return (
+                <div
+                  class={["tabs_item", e._id == props.activeKey ? "cur" : ""]}
+                  key={e._id}
+                  onClick={() => {
+                    router.push({ path: route.path, query: { cid: e._id } });
+                  }}
+                >
+                  {e.name}
+                </div>
+              );
+            })}
+        </div>
+      );
+    };
+  },
+});
+const page = css`
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background-color: #fff;
+  margin-bottom: 50px;
+  .tabs_item {
+    position: relative;
+    margin: 0 30px;
+    height: 46px;
+    line-height: 46px;
+    font-size: 14px;
+    font-weight: 400;
+    color: #666666;
+    cursor: pointer;
+    transition: all 0.2s ease-in-out;
+    &.cur {
+      font-weight: 600;
+      color: #333;
+    }
+  }
+`;

+ 0 - 0
src/views/website/detail/PageTabsTh.tsx


+ 192 - 0
src/views/website/detail/article.tsx

@@ -0,0 +1,192 @@
+import { useArticle, useCategory } from "@/modules";
+import { css } from "@linaria/core";
+
+import { defineComponent, onMounted, reactive, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import PageTabs from "./PageTabs";
+import { Empty, message } from "ant-design-vue";
+
+export default defineComponent({
+  setup() {
+    const route = useRoute();
+    const router = useRouter();
+    const categoryStore = useCategory();
+    const articleStore = useArticle();
+    const state = reactive({
+      currFloor: {} as any,
+      currMid: {} as any,
+      currTree: {} as any,
+      currBg: "",
+      content: "",
+      loading: true,
+    });
+    watch(
+      () => categoryStore.listController.state.list,
+      () => {
+        initCategory();
+      }
+    );
+    onMounted(() => {
+      initCategory();
+      initArticle();
+    });
+    const initCategory = () => {
+      const id = route.params.id;
+      const currCategory = categoryStore.listController.state.list.find(
+        (e: CategoryItem) => {
+          return e._id == id;
+        }
+      );
+
+      if (!currCategory) {
+        if (categoryStore.listController.state.list.length > 0) {
+          router.replace("/404");
+        }
+        return;
+      }
+
+      if (currCategory?.pid == "top") {
+        state.currTree = categoryStore.categoryTree.find((e) => {
+          return e._id == id;
+        });
+        state.currMid = state.currTree.children[0];
+        if (state.currMid.children && state.currMid.children.length) {
+          const cid = route.query.cid;
+          if (cid) {
+            state.currFloor = state.currMid.children.find((e: any) => {
+              return e._id == cid;
+            });
+          } else {
+            state.currFloor = state.currMid.children[0];
+          }
+        } else {
+          state.currFloor = state.currMid;
+        }
+        return;
+      }
+      state.currMid = currCategory;
+      if (currCategory.children && currCategory.children.length) {
+        const cid = route.query.cid;
+        if (cid) {
+          state.currFloor = currCategory.children.find((e: any) => {
+            return e._id == cid;
+          });
+        } else {
+          state.currFloor = currCategory.children[0];
+        }
+      } else {
+        state.currFloor = state.currMid;
+      }
+      state.currTree = categoryStore.categoryTree.find((e) => {
+        return e._id == currCategory.pid;
+      });
+    };
+    const initArticle = async () => {
+      const aid = route.query.aid;
+      if (!aid) {
+        state.loading = false;
+        return;
+      }
+      const res = await articleStore.listController.itemDetail(aid as string);
+      if (res.errorNo != 200) {
+        message.warn("未查询到数据!");
+        state.loading = false;
+        return;
+      }
+      state.loading = false;
+      state.content = res.result.content;
+    };
+
+    return () => {
+      return (
+        <div class={page}>
+          <div
+            class={"page_title_box"}
+            style={{
+              backgroundImage: `url(${
+                state.currMid.cover ? state.currMid.cover : state.currTree.cover
+              })`,
+            }}
+          >
+            <div class={"title detail_page_w"}>
+              <h1>{state.currTree.name}</h1>
+              <h2>{state.currTree.subName}</h2>
+            </div>
+          </div>
+          <div class={"page_tabs_box"}>
+            <div class="detail_page_w">
+              <PageTabs
+                data={state.currTree.children}
+                activeKey={state.currMid._id}
+              />
+            </div>
+          </div>
+          <div class={"page_content"}>
+            <div class={"detail_page_w"}>
+              <div innerHTML={state.content}></div>
+              {!state.loading && !state.content && (
+                <div class={"ant-list-empty-text"}>
+                  <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
+                </div>
+              )}
+            </div>
+          </div>
+        </div>
+      );
+    };
+  },
+});
+const page = css`
+  .page_title_box {
+    position: relative;
+    height: 500px;
+    background-position: center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    transition: all 0.2s ease-in-out;
+    &::after {
+      content: "";
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      width: 100%;
+      height: 220px;
+      background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%);
+      opacity: 0.7;
+      z-index: 1;
+    }
+    .title {
+      position: relative;
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-end;
+      padding-bottom: 28px;
+      z-index: 2;
+      h1 {
+        font-size: 36px;
+        font-weight: 400;
+        margin-bottom: 16px;
+        color: #fff;
+      }
+      h2 {
+        margin-bottom: 0;
+        height: 1em;
+        font-size: 14px;
+        font-weight: 300;
+        color: #fff;
+      }
+    }
+  }
+  .page_tabs_box {
+    background-color: #fff;
+    border-bottom: 1px solid #e5e5e5;
+  }
+  .page_content {
+    padding: 50px 0;
+    line-height: 1.5;
+    img {
+      display: inline;
+    }
+  }
+`;

+ 60 - 19
src/views/website/detail/index.tsx

@@ -2,17 +2,21 @@ import { useCategory } from "@/modules";
 import { css } from "@linaria/core";
 
 import { defineComponent, onMounted, reactive, watch } from "vue";
-import { useRoute } from "vue-router";
+import { useRoute, useRouter } from "vue-router";
 import PageTabs from "./PageTabs";
-import detail from "@/views/admin/detail";
+
 import DetailPage from "./DetailPage";
+import PageTabsLow from "./PageTabsLow";
+import ListPage from "./ListPage";
 
 export default defineComponent({
   setup() {
     const route = useRoute();
+    const router = useRouter();
     const categoryStore = useCategory();
     const state = reactive({
-      currChild: {} as any,
+      currFloor: {} as any,
+      currMid: {} as any,
       currTree: {} as any,
       currBg: "",
     });
@@ -28,6 +32,12 @@ export default defineComponent({
         initCategory();
       }
     );
+    watch(
+      () => route.query.cid,
+      () => {
+        initCategory();
+      }
+    );
     onMounted(() => {
       initCategory();
     });
@@ -38,26 +48,50 @@ export default defineComponent({
           return e._id == id;
         }
       );
-      console.log(currCategory);
+
       if (!currCategory) {
+        if (categoryStore.listController.state.list.length > 0) {
+          router.replace("/404");
+        }
         return;
       }
+
       if (currCategory.pid == "top") {
         state.currTree = categoryStore.categoryTree.find((e) => {
           return e._id == id;
         });
-        state.currChild = state.currTree.children[0];
+        state.currMid = state.currTree.children[0];
+        if (state.currMid.children && state.currMid.children.length) {
+          const cid = route.query.cid;
+          if (cid) {
+            state.currFloor = state.currMid.children.find((e: any) => {
+              return e._id == cid;
+            });
+          } else {
+            state.currFloor = state.currMid.children[0];
+          }
+        } else {
+          state.currFloor = state.currMid;
+        }
         return;
       }
-      state.currChild = currCategory;
+      state.currMid = currCategory;
+      if (currCategory.children && currCategory.children.length) {
+        const cid = route.query.cid;
+        if (cid) {
+          state.currFloor = currCategory.children.find((e: any) => {
+            return e._id == cid;
+          });
+        } else {
+          state.currFloor = currCategory.children[0];
+        }
+      } else {
+        state.currFloor = state.currMid;
+      }
       state.currTree = categoryStore.categoryTree.find((e) => {
         return e._id == currCategory.pid;
       });
     };
-    const changeCurrChild = (e: any) => {
-      state.currChild = e;
-      console.log(e);
-    };
 
     return () => {
       return (
@@ -66,9 +100,7 @@ export default defineComponent({
             class={"page_title_box"}
             style={{
               backgroundImage: `url(${
-                state.currChild.cover
-                  ? state.currChild.cover
-                  : state.currTree.cover
+                state.currMid.cover ? state.currMid.cover : state.currTree.cover
               })`,
             }}
           >
@@ -81,16 +113,25 @@ export default defineComponent({
             <div class="detail_page_w">
               <PageTabs
                 data={state.currTree.children}
-                activeKey={state.currChild._id}
-                onChange={changeCurrChild}
+                activeKey={state.currMid._id}
               />
             </div>
           </div>
           <div class={"page_content"}>
-            {/* {state.currChild.children&&<} */}
-            {state.currChild.type == "detail" && (
-              <DetailPage key={state.currChild._id} data={state.currChild} />
-            )}
+            <div class={"detail_page_w"}>
+              {state.currMid.children && state.currMid.children.length > 0 && (
+                <PageTabsLow
+                  data={state.currMid.children}
+                  activeKey={state.currFloor._id}
+                />
+              )}
+              {state.currFloor.type == "detail" && (
+                <DetailPage key={state.currFloor._id} data={state.currFloor} />
+              )}
+              {state.currFloor.type == "list" && (
+                <ListPage key={state.currFloor._id} data={state.currFloor} />
+              )}
+            </div>
           </div>
         </div>
       );

+ 5 - 0
src/views/website/router/index.ts

@@ -13,6 +13,11 @@ const router = createRouter({
       name: "detail",
       component: () => import("../detail"),
     },
+    {
+      path: "/article/:id",
+      name: "article",
+      component: () => import("../detail/article"),
+    },
     {
       path: "/404",
       name: "404",

+ 1 - 0
tsconfig.json

@@ -9,6 +9,7 @@
     /* Bundler mode */
     "moduleResolution": "node",
     "allowImportingTsExtensions": true,
+    "allowSyntheticDefaultImports": true,
     "resolveJsonModule": true,
     "isolatedModules": true,
     "noEmit": true,