index.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { useState, useEffect } from "react";
  2. import ItemCard from "@/components/ItemCard";
  3. import { APPLICATION_SCENARIOS_OPTIONS } from "@/constants";
  4. import { useRequest } from "umi";
  5. import { GetTemplatePublicList } from "@/api/templateStore";
  6. import { Input, Spin, Empty, Pagination } from "antd";
  7. import { MODULE_TEMPLATE_TYPE } from "@/constants";
  8. import noDataImg from "@/assets/no-data.svg";
  9. import '@/style/index.less';
  10. type OptionItem = {
  11. label: string;
  12. value: string;
  13. icon?: JSX.Element;
  14. };
  15. const scenes: OptionItem[] = [
  16. {
  17. label: "推荐",
  18. icon: <i className="iconfont icon-tuijian mr-1" />,
  19. value: "recommend",
  20. },
  21. ...APPLICATION_SCENARIOS_OPTIONS,
  22. ];
  23. const categorys: OptionItem[] = [
  24. { label: "全部类型", value: "all" },
  25. ...MODULE_TEMPLATE_TYPE,
  26. ];
  27. export default function Template() {
  28. const [search, setSearch] = useState("");
  29. const [industryFilter, setIndustryFilter] = useState("all");
  30. const [sceneFilter, setSceneFilter] = useState("recommend");
  31. const [currentPage, setCurrentPage] = useState(1);
  32. const { data, run, loading } = useRequest(GetTemplatePublicList, {
  33. defaultParams: [
  34. {
  35. currentPage: 1,
  36. pageSize: 20,
  37. filters: [
  38. { name: "isDel", value: 0 },
  39. { name: "isOnMarket", value: 1 },
  40. ],
  41. },
  42. ],
  43. });
  44. useEffect(() => {
  45. setCurrentPage(1);
  46. run({
  47. currentPage: 1,
  48. pageSize: 20,
  49. filters: [
  50. { name: "isDel", value: 0 },
  51. { name: "isOnMarket", value: 1 },
  52. { name: "name", value: search },
  53. {
  54. name: "industries",
  55. value: industryFilter === "all" ? "" : industryFilter,
  56. },
  57. {
  58. name: "applicationScenarios",
  59. value: sceneFilter === "recommend" ? "" : sceneFilter,
  60. },
  61. ],
  62. });
  63. }, [industryFilter, sceneFilter, search]);
  64. const handleChangePage = (page: number) => {
  65. setCurrentPage(page);
  66. run({
  67. currentPage: page,
  68. pageSize: 20,
  69. filters: [
  70. { name: "isDel", value: 0 },
  71. { name: "isOnMarket", value: 1 },
  72. { name: "name", value: search },
  73. {
  74. name: "industries",
  75. value: industryFilter === "all" ? "" : industryFilter,
  76. },
  77. {
  78. name: "applicationScenarios",
  79. value: sceneFilter === "recommend" ? "" : sceneFilter,
  80. },
  81. ],
  82. });
  83. };
  84. const handleToAppDetail = (id: string) => {
  85. window.open(`#/detail/template/${id}`, "_blank");
  86. };
  87. return (
  88. <div className="flex h-full">
  89. <div className="left w-fit sm:w-[216px] shrink-0 pt-6 px-4 border-gray-200 border-0 border-r border-solid border-gray-200">
  90. <ul className="flex flex-col gap-y-2">
  91. {categorys.map((item) => (
  92. <li
  93. key={item.value}
  94. className={`cursor-pointer text-14px text-secondary gap-2 flex items-center pc:justify-start pc:w-full mobile:justify-center mobile:w-fit h-9 px-3 mobile:px-2 rounded-lg ${industryFilter === item.value ? "bg-white font-semibold !text-primary shadow-xs" : ""}`}
  95. onClick={() => setIndustryFilter(item.value)}
  96. >
  97. <span>{item.label}</span>
  98. </li>
  99. ))}
  100. </ul>
  101. </div>
  102. <div className="right flex-1 pt-6 px-4 h-full flex flex-col">
  103. <div className="shrink-0 pt-6 px-12">
  104. <div className="mb-1 text-primary text-xl font-semibold">
  105. 探索模块模版
  106. </div>
  107. <div className="text-gray-500 text-sm">
  108. 使用这些内容模块,可以快速完善你的系统功能模块。
  109. </div>
  110. </div>
  111. <div className="flex items-center justify-between mt-6 px-12">
  112. <div className="flex space-x-1 text-[13px] flex-wrap">
  113. {scenes.map((scene) => (
  114. <div
  115. key={scene.value}
  116. className={`cursor-pointer px-3 py-[7px] h-[32px] rounded-lg font-medium leading-[18px] cursor-pointer ${scene.value === sceneFilter ? "bg-white shadow-xs text-primary-600 text-primary" : "border-transparent text-gray-700 hover:bg-gray-200"}`}
  117. onClick={() => setSceneFilter(scene.value)}
  118. >
  119. {scene.icon}
  120. {scene.label}
  121. </div>
  122. ))}
  123. </div>
  124. <div>
  125. <Input
  126. value={search}
  127. onChange={(e) => setSearch(e.target.value)}
  128. placeholder="搜索"
  129. prefix={<i className="iconfont icon-sousuo" />}
  130. allowClear
  131. ></Input>
  132. </div>
  133. </div>
  134. <div className="relative flex flex-1 pb-6 flex-col overflow-auto bg-gray-100 shrink-0 grow mt-4">
  135. <nav
  136. className="style_appList grid content-start shrink-0 gap-4 px-6 sm:px-12"
  137. >
  138. {(data?.result?.model || []).map((item: any, index: number) => (
  139. <ItemCard data={item} key={index} onClick={handleToAppDetail} />
  140. ))}
  141. </nav>
  142. <Pagination
  143. className="mt-6"
  144. align="center"
  145. hideOnSinglePage
  146. current={currentPage}
  147. total={data?.result?.totalCount || 0}
  148. onChange={handleChangePage}
  149. />
  150. {!data?.result.model.length && !loading && (
  151. <Empty description="暂无数据" image={noDataImg} />
  152. )}
  153. <div className="h-200px w-full absolute left-0 top0 flex items-center justify-center pointer-events-none">
  154. <Spin spinning={loading} />
  155. </div>
  156. </div>
  157. </div>
  158. </div>
  159. );
  160. }