bug修复 #6

Merged
leiyuee merged 1 commits from dev into master 3 months ago
  1. 4
      dist/assets/index-8XucR_p2.js
  2. 2
      dist/assets/index-8XucR_p2.js.map
  3. 4
      dist/assets/index-B7qTBdbE.js
  4. 1
      dist/assets/index-B7qTBdbE.js.map
  5. 4
      dist/assets/index-BGvG87k5.js
  6. 2
      dist/assets/index-BGvG87k5.js.map
  7. 4
      dist/assets/index-BJTWh1Kx.js
  8. 1
      dist/assets/index-BJTWh1Kx.js.map
  9. 4
      dist/assets/index-BKEHpvYm.js
  10. 2
      dist/assets/index-BKEHpvYm.js.map
  11. 1
      dist/assets/index-BOdvuzA5.js.map
  12. 4
      dist/assets/index-BY9C46Hx.js
  13. 1
      dist/assets/index-BY9C46Hx.js.map
  14. 14
      dist/assets/index-BlWdPD5L.js
  15. 1
      dist/assets/index-BlWdPD5L.js.map
  16. 4
      dist/assets/index-BpEIsqGj.js
  17. 2
      dist/assets/index-BpEIsqGj.js.map
  18. 4
      dist/assets/index-C8p-BT1G.js
  19. 2
      dist/assets/index-C8p-BT1G.js.map
  20. 1
      dist/assets/index-CFE14uAE.js.map
  21. 1
      dist/assets/index-COrnfX8o.js.map
  22. 1
      dist/assets/index-DSZ4TxXA.js.map
  23. 4
      dist/assets/index-DWUOHYXx.js
  24. 2
      dist/assets/index-DWUOHYXx.js.map
  25. 4
      dist/assets/index-X1UpxebS.js
  26. 2
      dist/assets/index-X1UpxebS.js.map
  27. 4
      dist/assets/index-bqQ0a4cY.js
  28. 2
      dist/assets/index-bqQ0a4cY.js.map
  29. 1
      dist/assets/index-neZGhFpy.js.map
  30. 4
      dist/assets/index-ocHw71Eb.js
  31. 1
      dist/assets/index-ocHw71Eb.js.map
  32. 2
      dist/index.html
  33. BIN
      popiart-website-new.zip
  34. 15
      src/pages/Characters/index.scss
  35. 259
      src/pages/Characters/index.tsx
  36. 4
      vite.config.mts

4
dist/assets/index-IYrYe2z2.js → dist/assets/index-8XucR_p2.js

@ -1,2 +1,2 @@
import{j as e}from"./markdown-vendor-BZI_VWzW.js";import{b8 as m,b9 as d}from"./index-DSZ4TxXA.js";import{u as g,r as o}from"./data-vendor-BOGugMqL.js";import{b as _}from"./react-vendor-wlKWdfEb.js";import"./arco-vendor-CAnKnMnO.js";const h="#user-agreement",c="#privacy-policy";function j(){const{t:l}=g(),{hash:i}=_(),t=i===c,r=l(t?"app.privacy_policy":"app.user_terms"),n=t?c.replace("#",""):h.replace("#",""),[p,a]=o.useState(void 0);return o.useEffect(()=>{a(void 0),t?m().then(s=>a(s.data?.content)):d().then(s=>a(s.data?.content))},[t]),e.jsx("div",{className:"legal-page",children:e.jsxs("section",{className:"legal-page__section",id:n,"aria-labelledby":"legal-doc-title",children:[e.jsx("h1",{className:"legal-page__title",id:"legal-doc-title",children:r}),e.jsx("div",{className:"legal-page__content",children:e.jsx("div",{dangerouslySetInnerHTML:{__html:p??""}})})]})})}export{j as default};
//# sourceMappingURL=index-IYrYe2z2.js.map
import{j as e}from"./markdown-vendor-BZI_VWzW.js";import{b8 as m,b9 as d}from"./index-BlWdPD5L.js";import{u as g,r as o}from"./data-vendor-BOGugMqL.js";import{b as _}from"./react-vendor-wlKWdfEb.js";import"./arco-vendor-CAnKnMnO.js";const h="#user-agreement",c="#privacy-policy";function j(){const{t:l}=g(),{hash:i}=_(),t=i===c,r=l(t?"app.privacy_policy":"app.user_terms"),n=t?c.replace("#",""):h.replace("#",""),[p,a]=o.useState(void 0);return o.useEffect(()=>{a(void 0),t?m().then(s=>a(s.data?.content)):d().then(s=>a(s.data?.content))},[t]),e.jsx("div",{className:"legal-page",children:e.jsxs("section",{className:"legal-page__section",id:n,"aria-labelledby":"legal-doc-title",children:[e.jsx("h1",{className:"legal-page__title",id:"legal-doc-title",children:r}),e.jsx("div",{className:"legal-page__content",children:e.jsx("div",{dangerouslySetInnerHTML:{__html:p??""}})})]})})}export{j as default};
//# sourceMappingURL=index-8XucR_p2.js.map

2
dist/assets/index-IYrYe2z2.js.map → dist/assets/index-8XucR_p2.js.map

@ -1 +1 @@
{"version":3,"file":"index-IYrYe2z2.js","sources":["../../src/pages/legal/index.tsx"],"sourcesContent":["import { getPrivacyPolicy, getUserTerms } from \"@/api/api\";\nimport { useEffect, useState } from \"react\";\nimport { useLocation } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport \"./index.scss\";\n\nconst USER_AGREEMENT_HASH = \"#user-agreement\";\nconst PRIVACY_POLICY_HASH = \"#privacy-policy\";\n\nexport default function Legal() {\n const { t } = useTranslation();\n const { hash } = useLocation();\n const showPrivacy = hash === PRIVACY_POLICY_HASH;\n const title = showPrivacy ? t(\"app.privacy_policy\") : t(\"app.user_terms\");\n const sectionId = showPrivacy\n ? PRIVACY_POLICY_HASH.replace(\"#\", \"\")\n : USER_AGREEMENT_HASH.replace(\"#\", \"\");\n\n const [html, setHtml] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n setHtml(undefined);\n if (showPrivacy) {\n getPrivacyPolicy().then((res) => setHtml(res.data?.content));\n } else {\n getUserTerms().then((res) => setHtml(res.data?.content));\n }\n }, [showPrivacy]);\n\n return (\n <div className=\"legal-page\">\n <section\n className=\"legal-page__section\"\n id={sectionId}\n aria-labelledby=\"legal-doc-title\"\n >\n <h1 className=\"legal-page__title\" id=\"legal-doc-title\">\n {title}\n </h1>\n <div className=\"legal-page__content\">\n <div dangerouslySetInnerHTML={{ __html: html ?? \"\" }} />\n </div>\n </section>\n </div>\n );\n}\n"],"names":["USER_AGREEMENT_HASH","PRIVACY_POLICY_HASH","Legal","t","useTranslation","hash","useLocation","showPrivacy","title","sectionId","html","setHtml","useState","useEffect","getPrivacyPolicy","res","getUserTerms","jsx","jsxs"],"mappings":"yOAMA,MAAMA,EAAsB,kBACtBC,EAAsB,kBAE5B,SAAwBC,GAAQ,CAC9B,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAA,EACR,CAAE,KAAAC,CAAA,EAASC,EAAA,EACXC,EAAcF,IAASJ,EACvBO,EAAsBL,EAAdI,EAAgB,qBAA0B,gBAAN,EAC5CE,EAAYF,EACdN,EAAoB,QAAQ,IAAK,EAAE,EACnCD,EAAoB,QAAQ,IAAK,EAAE,EAEjC,CAACU,EAAMC,CAAO,EAAIC,EAAAA,SAA6B,MAAS,EAE9DC,OAAAA,EAAAA,UAAU,IAAM,CACdF,EAAQ,MAAS,EACbJ,EACFO,EAAA,EAAmB,KAAMC,GAAQJ,EAAQI,EAAI,MAAM,OAAO,CAAC,EAE3DC,EAAA,EAAe,KAAMD,GAAQJ,EAAQI,EAAI,MAAM,OAAO,CAAC,CAE3D,EAAG,CAACR,CAAW,CAAC,EAGdU,EAAAA,IAAC,MAAA,CAAI,UAAU,aACb,SAAAC,EAAAA,KAAC,UAAA,CACC,UAAU,sBACV,GAAIT,EACJ,kBAAgB,kBAEhB,SAAA,CAAAQ,MAAC,KAAA,CAAG,UAAU,oBAAoB,GAAG,kBAClC,SAAAT,EACH,EACAS,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACb,SAAAA,EAAAA,IAAC,MAAA,CAAI,wBAAyB,CAAE,OAAQP,GAAQ,EAAA,CAAG,CAAG,CAAA,CACxD,CAAA,CAAA,CAAA,EAEJ,CAEJ"}
{"version":3,"file":"index-8XucR_p2.js","sources":["../../src/pages/legal/index.tsx"],"sourcesContent":["import { getPrivacyPolicy, getUserTerms } from \"@/api/api\";\nimport { useEffect, useState } from \"react\";\nimport { useLocation } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport \"./index.scss\";\n\nconst USER_AGREEMENT_HASH = \"#user-agreement\";\nconst PRIVACY_POLICY_HASH = \"#privacy-policy\";\n\nexport default function Legal() {\n const { t } = useTranslation();\n const { hash } = useLocation();\n const showPrivacy = hash === PRIVACY_POLICY_HASH;\n const title = showPrivacy ? t(\"app.privacy_policy\") : t(\"app.user_terms\");\n const sectionId = showPrivacy\n ? PRIVACY_POLICY_HASH.replace(\"#\", \"\")\n : USER_AGREEMENT_HASH.replace(\"#\", \"\");\n\n const [html, setHtml] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n setHtml(undefined);\n if (showPrivacy) {\n getPrivacyPolicy().then((res) => setHtml(res.data?.content));\n } else {\n getUserTerms().then((res) => setHtml(res.data?.content));\n }\n }, [showPrivacy]);\n\n return (\n <div className=\"legal-page\">\n <section\n className=\"legal-page__section\"\n id={sectionId}\n aria-labelledby=\"legal-doc-title\"\n >\n <h1 className=\"legal-page__title\" id=\"legal-doc-title\">\n {title}\n </h1>\n <div className=\"legal-page__content\">\n <div dangerouslySetInnerHTML={{ __html: html ?? \"\" }} />\n </div>\n </section>\n </div>\n );\n}\n"],"names":["USER_AGREEMENT_HASH","PRIVACY_POLICY_HASH","Legal","t","useTranslation","hash","useLocation","showPrivacy","title","sectionId","html","setHtml","useState","useEffect","getPrivacyPolicy","res","getUserTerms","jsx","jsxs"],"mappings":"yOAMA,MAAMA,EAAsB,kBACtBC,EAAsB,kBAE5B,SAAwBC,GAAQ,CAC9B,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAA,EACR,CAAE,KAAAC,CAAA,EAASC,EAAA,EACXC,EAAcF,IAASJ,EACvBO,EAAsBL,EAAdI,EAAgB,qBAA0B,gBAAN,EAC5CE,EAAYF,EACdN,EAAoB,QAAQ,IAAK,EAAE,EACnCD,EAAoB,QAAQ,IAAK,EAAE,EAEjC,CAACU,EAAMC,CAAO,EAAIC,EAAAA,SAA6B,MAAS,EAE9DC,OAAAA,EAAAA,UAAU,IAAM,CACdF,EAAQ,MAAS,EACbJ,EACFO,EAAA,EAAmB,KAAMC,GAAQJ,EAAQI,EAAI,MAAM,OAAO,CAAC,EAE3DC,EAAA,EAAe,KAAMD,GAAQJ,EAAQI,EAAI,MAAM,OAAO,CAAC,CAE3D,EAAG,CAACR,CAAW,CAAC,EAGdU,EAAAA,IAAC,MAAA,CAAI,UAAU,aACb,SAAAC,EAAAA,KAAC,UAAA,CACC,UAAU,sBACV,GAAIT,EACJ,kBAAgB,kBAEhB,SAAA,CAAAQ,MAAC,KAAA,CAAG,UAAU,oBAAoB,GAAG,kBAClC,SAAAT,EACH,EACAS,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACb,SAAAA,EAAAA,IAAC,MAAA,CAAI,wBAAyB,CAAE,OAAQP,GAAQ,EAAA,CAAG,CAAG,CAAA,CACxD,CAAA,CAAA,CAAA,EAEJ,CAEJ"}

4
dist/assets/index-neZGhFpy.js → dist/assets/index-B7qTBdbE.js

File diff suppressed because one or more lines are too long

1
dist/assets/index-B7qTBdbE.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-Dy0mUgCw.js → dist/assets/index-BGvG87k5.js

@ -1,2 +1,2 @@
import{j as t}from"./markdown-vendor-BZI_VWzW.js";import{ba as d}from"./index-DSZ4TxXA.js";import{r as a}from"./data-vendor-BOGugMqL.js";import{f as m,g}from"./react-vendor-wlKWdfEb.js";import"./arco-vendor-CAnKnMnO.js";function _(){const[i,s]=a.useState(void 0),[o,r]=a.useState(void 0),{id:n}=m(),[c]=g(),e=n??c.get("id")??void 0;return a.useEffect(()=>{e&&(s(void 0),d({id:e}).then(l=>{s(l.data?.content),r(l.data?.title)}))},[e]),t.jsx("div",{className:"legal-page",children:t.jsxs("section",{className:"legal-page__section",id:e,"aria-labelledby":"legal-doc-title",children:[t.jsx("h1",{className:"legal-page__title",id:"legal-doc-title",children:o}),t.jsx("div",{className:"legal-page__content",children:t.jsx("div",{dangerouslySetInnerHTML:{__html:i??""}})})]})})}export{_ as default};
//# sourceMappingURL=index-Dy0mUgCw.js.map
import{j as t}from"./markdown-vendor-BZI_VWzW.js";import{ba as d}from"./index-BlWdPD5L.js";import{r as a}from"./data-vendor-BOGugMqL.js";import{f as m,g}from"./react-vendor-wlKWdfEb.js";import"./arco-vendor-CAnKnMnO.js";function _(){const[i,s]=a.useState(void 0),[o,r]=a.useState(void 0),{id:n}=m(),[c]=g(),e=n??c.get("id")??void 0;return a.useEffect(()=>{e&&(s(void 0),d({id:e}).then(l=>{s(l.data?.content),r(l.data?.title)}))},[e]),t.jsx("div",{className:"legal-page",children:t.jsxs("section",{className:"legal-page__section",id:e,"aria-labelledby":"legal-doc-title",children:[t.jsx("h1",{className:"legal-page__title",id:"legal-doc-title",children:o}),t.jsx("div",{className:"legal-page__content",children:t.jsx("div",{dangerouslySetInnerHTML:{__html:i??""}})})]})})}export{_ as default};
//# sourceMappingURL=index-BGvG87k5.js.map

2
dist/assets/index-Dy0mUgCw.js.map → dist/assets/index-BGvG87k5.js.map

@ -1 +1 @@
{"version":3,"file":"index-Dy0mUgCw.js","sources":["../../src/pages/content/page/index.tsx"],"sourcesContent":["import { getContent } from \"@/api/api\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { useParams, useSearchParams } from \"react-router-dom\";\r\nimport \"./index.scss\";\r\n\r\nexport default function Content() {\r\n\r\n const [html, setHtml] = useState<string | undefined>(undefined);\r\n const [title, setTitle] = useState<string | undefined>(undefined);\r\n const { id: idFromPath } = useParams();\r\n const [searchParams] = useSearchParams();\r\n const id = idFromPath ?? searchParams.get(\"id\") ?? undefined;\r\n\r\n useEffect(() => {\r\n if (!id) return;\r\n setHtml(undefined);\r\n getContent({ id }).then((res) => {\r\n setHtml(res.data?.content);\r\n setTitle(res.data?.title);\r\n });\r\n }, [id]);\r\n\r\n return (\r\n <div className=\"legal-page\">\r\n <section\r\n className=\"legal-page__section\"\r\n id={id}\r\n aria-labelledby=\"legal-doc-title\"\r\n >\r\n <h1 className=\"legal-page__title\" id=\"legal-doc-title\">\r\n {title}\r\n </h1>\r\n <div className=\"legal-page__content\">\r\n <div dangerouslySetInnerHTML={{ __html: html ?? \"\" }} />\r\n </div>\r\n </section>\r\n </div>\r\n );\r\n}\r\n"],"names":["Content","html","setHtml","useState","title","setTitle","idFromPath","useParams","searchParams","useSearchParams","id","useEffect","getContent","res","jsx","jsxs"],"mappings":"4NAKA,SAAwBA,GAAU,CAE9B,KAAM,CAACC,EAAMC,CAAO,EAAIC,EAAAA,SAA6B,MAAS,EACxD,CAACC,EAAOC,CAAQ,EAAIF,EAAAA,SAA6B,MAAS,EAC1D,CAAE,GAAIG,CAAA,EAAeC,EAAA,EACrB,CAACC,CAAY,EAAIC,EAAA,EACjBC,EAAKJ,GAAcE,EAAa,IAAI,IAAI,GAAK,OAEnDG,OAAAA,EAAAA,UAAU,IAAM,CACPD,IACLR,EAAQ,MAAS,EACjBU,EAAW,CAAE,GAAAF,CAAA,CAAI,EAAE,KAAMG,GAAQ,CAC7BX,EAAQW,EAAI,MAAM,OAAO,EACzBR,EAASQ,EAAI,MAAM,KAAK,CAC5B,CAAC,EACL,EAAG,CAACH,CAAE,CAAC,EAGHI,EAAAA,IAAC,MAAA,CAAI,UAAU,aACX,SAAAC,EAAAA,KAAC,UAAA,CACG,UAAU,sBACV,GAAAL,EACA,kBAAgB,kBAEhB,SAAA,CAAAI,MAAC,KAAA,CAAG,UAAU,oBAAoB,GAAG,kBAChC,SAAAV,EACL,EACAU,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACX,SAAAA,EAAAA,IAAC,MAAA,CAAI,wBAAyB,CAAE,OAAQb,GAAQ,EAAA,CAAG,CAAG,CAAA,CAC1D,CAAA,CAAA,CAAA,EAER,CAER"}
{"version":3,"file":"index-BGvG87k5.js","sources":["../../src/pages/content/page/index.tsx"],"sourcesContent":["import { getContent } from \"@/api/api\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { useParams, useSearchParams } from \"react-router-dom\";\r\nimport \"./index.scss\";\r\n\r\nexport default function Content() {\r\n\r\n const [html, setHtml] = useState<string | undefined>(undefined);\r\n const [title, setTitle] = useState<string | undefined>(undefined);\r\n const { id: idFromPath } = useParams();\r\n const [searchParams] = useSearchParams();\r\n const id = idFromPath ?? searchParams.get(\"id\") ?? undefined;\r\n\r\n useEffect(() => {\r\n if (!id) return;\r\n setHtml(undefined);\r\n getContent({ id }).then((res) => {\r\n setHtml(res.data?.content);\r\n setTitle(res.data?.title);\r\n });\r\n }, [id]);\r\n\r\n return (\r\n <div className=\"legal-page\">\r\n <section\r\n className=\"legal-page__section\"\r\n id={id}\r\n aria-labelledby=\"legal-doc-title\"\r\n >\r\n <h1 className=\"legal-page__title\" id=\"legal-doc-title\">\r\n {title}\r\n </h1>\r\n <div className=\"legal-page__content\">\r\n <div dangerouslySetInnerHTML={{ __html: html ?? \"\" }} />\r\n </div>\r\n </section>\r\n </div>\r\n );\r\n}\r\n"],"names":["Content","html","setHtml","useState","title","setTitle","idFromPath","useParams","searchParams","useSearchParams","id","useEffect","getContent","res","jsx","jsxs"],"mappings":"4NAKA,SAAwBA,GAAU,CAE9B,KAAM,CAACC,EAAMC,CAAO,EAAIC,EAAAA,SAA6B,MAAS,EACxD,CAACC,EAAOC,CAAQ,EAAIF,EAAAA,SAA6B,MAAS,EAC1D,CAAE,GAAIG,CAAA,EAAeC,EAAA,EACrB,CAACC,CAAY,EAAIC,EAAA,EACjBC,EAAKJ,GAAcE,EAAa,IAAI,IAAI,GAAK,OAEnDG,OAAAA,EAAAA,UAAU,IAAM,CACPD,IACLR,EAAQ,MAAS,EACjBU,EAAW,CAAE,GAAAF,CAAA,CAAI,EAAE,KAAMG,GAAQ,CAC7BX,EAAQW,EAAI,MAAM,OAAO,EACzBR,EAASQ,EAAI,MAAM,KAAK,CAC5B,CAAC,EACL,EAAG,CAACH,CAAE,CAAC,EAGHI,EAAAA,IAAC,MAAA,CAAI,UAAU,aACX,SAAAC,EAAAA,KAAC,UAAA,CACG,UAAU,sBACV,GAAAL,EACA,kBAAgB,kBAEhB,SAAA,CAAAI,MAAC,KAAA,CAAG,UAAU,oBAAoB,GAAG,kBAChC,SAAAV,EACL,EACAU,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACX,SAAAA,EAAAA,IAAC,MAAA,CAAI,wBAAyB,CAAE,OAAQb,GAAQ,EAAA,CAAG,CAAG,CAAA,CAC1D,CAAA,CAAA,CAAA,EAER,CAER"}

4
dist/assets/index-COrnfX8o.js → dist/assets/index-BJTWh1Kx.js

File diff suppressed because one or more lines are too long

1
dist/assets/index-BJTWh1Kx.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-4_vgfGRD.js → dist/assets/index-BKEHpvYm.js

File diff suppressed because one or more lines are too long

2
dist/assets/index-4_vgfGRD.js.map → dist/assets/index-BKEHpvYm.js.map

File diff suppressed because one or more lines are too long

1
dist/assets/index-BOdvuzA5.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-BOdvuzA5.js → dist/assets/index-BY9C46Hx.js

@ -1,2 +1,2 @@
import{j as s}from"./markdown-vendor-BZI_VWzW.js";import{u as G,r as t}from"./data-vendor-BOGugMqL.js";import{g as U}from"./react-vendor-wlKWdfEb.js";import{bm as V,bn as H,o as Y,f as Z}from"./index-DSZ4TxXA.js";import"./arco-vendor-CAnKnMnO.js";const _=20,T=[{title:"image",assetType:"1"},{title:"video",assetType:"2"},{title:"template",assetType:"4"},{title:"character",assetType:"5"}];function A(o){const r=o;return r?.data?.list??r?.list??[]}function B(o){const r=o?.id??o?.assetId;return r==null||r===""?null:String(r)}function ee({tabIdPrefix:o}){const{t:r}=G(),[x,S]=U(),[l,b]=t.useState("1"),[c,f]=t.useState([]),[N,j]=t.useState(1),[g,u]=t.useState(!0),[d,F]=t.useState(!1),[v,C]=t.useState(!1),[h,I]=t.useState(null),L=t.useRef(null),P=t.useRef(!1),i=t.useRef(0),k=t.useRef(async()=>{});t.useEffect(()=>{const e=x.get("type");e!=null&&T.some(a=>a.assetType===e)&&b(e)},[x]);const w=t.useCallback(e=>({assetType:l,page:e,pageSize:_}),[l]),p=t.useCallback(e=>l==="5"?V({page:e,pageSize:_}):H(w(e)),[w,l]);t.useEffect(()=>{let e=!1;i.current+=1;const a=i.current;return j(1),u(!0),f([]),F(!0),I(null),p(1).then(n=>{if(e||i.current!==a)return;const m=A(n);f(m),u(m.length>=_)}).catch(n=>{e||i.current!==a||(I(n instanceof Error?n:new Error(String(n))),f([]),u(!1))}).finally(()=>{!e&&i.current===a&&F(!1)}),()=>{e=!0}},[p,l]);const D=t.useCallback(async()=>{if(!g||P.current||d||v)return;P.current=!0,C(!0);const e=i.current,a=N+1;try{const n=await p(a);if(i.current!==e)return;const m=A(n);m.length===0?u(!1):(f(q=>[...q,...m]),j(a),u(m.length>=_))}catch{i.current===e&&u(!1)}finally{P.current=!1,C(!1)}},[p,g,d,v,N]);k.current=D,t.useEffect(()=>{const e=L.current;if(!e||!g||d)return;const a=new IntersectionObserver(n=>{n[0]?.isIntersecting&&k.current()},{root:null,rootMargin:"200px",threshold:0});return a.observe(e),()=>a.disconnect()},[g,d,c.length]);const z=t.useCallback(e=>{b(e),S(a=>{const n=new URLSearchParams(a);return n.set("type",String(e)),n},{replace:!0})},[S]),y=t.useCallback(async e=>{const a=e.assetId;a!=null&&await Y({assetId:a})},[]),E=t.useCallback(async e=>{Z({id:e.id})},[]),R=t.useCallback(e=>{e.currentTarget.querySelector("video")?.play()},[]),M=t.useCallback(e=>{e.currentTarget.querySelector("video")?.pause()},[]),O=t.useMemo(()=>T.map(({title:e,assetType:a})=>({assetType:a,label:r(`pages.create.filters.${e}`)})),[r]),$=t.useMemo(()=>c.map(e=>{const a=B(e)??`row-${l}`;return l=="2"?s.jsx("li",{className:"myFavoritePanel__item",onClick:()=>void y(e),onMouseEnter:R,onMouseLeave:M,children:s.jsx("video",{className:"myFavoritePanel__media",src:e.asset.video,muted:!0,playsInline:!0,loop:!0,preload:"metadata",poster:e.asset.cover,"aria-hidden":!0})},a):l=="1"||l=="4"?s.jsx("li",{className:"myFavoritePanel__item",onClick:()=>void y(e),children:s.jsx("img",{className:"myFavoritePanel__media",src:e?.asset?.images?.[0],alt:"",loading:"lazy"})},a):l=="5"?s.jsx("li",{className:"myFavoritePanel__item",onClick:()=>void E(e),children:s.jsx("img",{className:"myFavoritePanel__media",src:e.avatar,alt:"",loading:"lazy"})},a):s.jsx("li",{className:"myFavoritePanel__item myFavoritePanel__item_empty",children:s.jsx("span",{className:"myFavoritePanel__emptyLabel",children:r("pages.create.panels.favorite.noPreview")})},a)}),[y,E,c,R,M,l,r]);return s.jsxs("div",{className:"myFavoritePanel",children:[s.jsx("div",{className:"createPage__subRow myFavoritePanel__subRow",children:s.jsx("div",{className:"createPage__filters",role:"group","aria-label":r("pages.create.filtersAria"),"data-active-tab":l,children:O.map(({assetType:e,label:a})=>s.jsx("button",{type:"button","data-type":e,"data-selected":l===e,"aria-pressed":l===e,className:classNames("createPage__filterPill",l===e&&"createPage__filterPill_active"),onClick:()=>z(e),children:a},e))})}),s.jsxs("section",{className:"createPage__panel createPage__panel_below_filters",id:`${o}-panel-favorite`,role:"tabpanel","aria-labelledby":`${o}-tab-favorite`,children:[d&&c.length===0?s.jsx("p",{className:"createPage__panelStatus",children:r("common.loading")}):null,h?s.jsx("p",{className:"createPage__panelStatus createPage__panelStatus_error",children:h.message}):null,!d&&!h&&c.length===0?s.jsx("p",{className:"createPage__panelPlaceholder",children:r("pages.create.panels.favorite.placeholder")}):null,c.length>0?s.jsxs(s.Fragment,{children:[s.jsx("ul",{className:"myFavoritePanel__list",role:"list",children:$}),g?s.jsx("div",{ref:L,className:"myFavoritePanel__sentinel","aria-hidden":!0}):null,v?s.jsx("p",{className:"createPage__panelStatus myFavoritePanel__loadMore",children:r("common.loading")}):null]}):null]})]})}export{ee as default};
//# sourceMappingURL=index-BOdvuzA5.js.map
import{j as s}from"./markdown-vendor-BZI_VWzW.js";import{u as G,r as t}from"./data-vendor-BOGugMqL.js";import{g as U}from"./react-vendor-wlKWdfEb.js";import{bm as V,bn as H,o as Y,f as Z}from"./index-BlWdPD5L.js";import"./arco-vendor-CAnKnMnO.js";const _=20,T=[{title:"image",assetType:"1"},{title:"video",assetType:"2"},{title:"template",assetType:"4"},{title:"character",assetType:"5"}];function A(o){const r=o;return r?.data?.list??r?.list??[]}function B(o){const r=o?.id??o?.assetId;return r==null||r===""?null:String(r)}function ee({tabIdPrefix:o}){const{t:r}=G(),[x,S]=U(),[l,b]=t.useState("1"),[c,f]=t.useState([]),[N,j]=t.useState(1),[g,u]=t.useState(!0),[d,F]=t.useState(!1),[v,C]=t.useState(!1),[h,I]=t.useState(null),L=t.useRef(null),P=t.useRef(!1),i=t.useRef(0),k=t.useRef(async()=>{});t.useEffect(()=>{const e=x.get("type");e!=null&&T.some(a=>a.assetType===e)&&b(e)},[x]);const w=t.useCallback(e=>({assetType:l,page:e,pageSize:_}),[l]),p=t.useCallback(e=>l==="5"?V({page:e,pageSize:_}):H(w(e)),[w,l]);t.useEffect(()=>{let e=!1;i.current+=1;const a=i.current;return j(1),u(!0),f([]),F(!0),I(null),p(1).then(n=>{if(e||i.current!==a)return;const m=A(n);f(m),u(m.length>=_)}).catch(n=>{e||i.current!==a||(I(n instanceof Error?n:new Error(String(n))),f([]),u(!1))}).finally(()=>{!e&&i.current===a&&F(!1)}),()=>{e=!0}},[p,l]);const D=t.useCallback(async()=>{if(!g||P.current||d||v)return;P.current=!0,C(!0);const e=i.current,a=N+1;try{const n=await p(a);if(i.current!==e)return;const m=A(n);m.length===0?u(!1):(f(q=>[...q,...m]),j(a),u(m.length>=_))}catch{i.current===e&&u(!1)}finally{P.current=!1,C(!1)}},[p,g,d,v,N]);k.current=D,t.useEffect(()=>{const e=L.current;if(!e||!g||d)return;const a=new IntersectionObserver(n=>{n[0]?.isIntersecting&&k.current()},{root:null,rootMargin:"200px",threshold:0});return a.observe(e),()=>a.disconnect()},[g,d,c.length]);const z=t.useCallback(e=>{b(e),S(a=>{const n=new URLSearchParams(a);return n.set("type",String(e)),n},{replace:!0})},[S]),y=t.useCallback(async e=>{const a=e.assetId;a!=null&&await Y({assetId:a})},[]),E=t.useCallback(async e=>{Z({id:e.id})},[]),R=t.useCallback(e=>{e.currentTarget.querySelector("video")?.play()},[]),M=t.useCallback(e=>{e.currentTarget.querySelector("video")?.pause()},[]),O=t.useMemo(()=>T.map(({title:e,assetType:a})=>({assetType:a,label:r(`pages.create.filters.${e}`)})),[r]),$=t.useMemo(()=>c.map(e=>{const a=B(e)??`row-${l}`;return l=="2"?s.jsx("li",{className:"myFavoritePanel__item",onClick:()=>void y(e),onMouseEnter:R,onMouseLeave:M,children:s.jsx("video",{className:"myFavoritePanel__media",src:e.asset.video,muted:!0,playsInline:!0,loop:!0,preload:"metadata",poster:e.asset.cover,"aria-hidden":!0})},a):l=="1"||l=="4"?s.jsx("li",{className:"myFavoritePanel__item",onClick:()=>void y(e),children:s.jsx("img",{className:"myFavoritePanel__media",src:e?.asset?.images?.[0],alt:"",loading:"lazy"})},a):l=="5"?s.jsx("li",{className:"myFavoritePanel__item",onClick:()=>void E(e),children:s.jsx("img",{className:"myFavoritePanel__media",src:e.avatar,alt:"",loading:"lazy"})},a):s.jsx("li",{className:"myFavoritePanel__item myFavoritePanel__item_empty",children:s.jsx("span",{className:"myFavoritePanel__emptyLabel",children:r("pages.create.panels.favorite.noPreview")})},a)}),[y,E,c,R,M,l,r]);return s.jsxs("div",{className:"myFavoritePanel",children:[s.jsx("div",{className:"createPage__subRow myFavoritePanel__subRow",children:s.jsx("div",{className:"createPage__filters",role:"group","aria-label":r("pages.create.filtersAria"),"data-active-tab":l,children:O.map(({assetType:e,label:a})=>s.jsx("button",{type:"button","data-type":e,"data-selected":l===e,"aria-pressed":l===e,className:classNames("createPage__filterPill",l===e&&"createPage__filterPill_active"),onClick:()=>z(e),children:a},e))})}),s.jsxs("section",{className:"createPage__panel createPage__panel_below_filters",id:`${o}-panel-favorite`,role:"tabpanel","aria-labelledby":`${o}-tab-favorite`,children:[d&&c.length===0?s.jsx("p",{className:"createPage__panelStatus",children:r("common.loading")}):null,h?s.jsx("p",{className:"createPage__panelStatus createPage__panelStatus_error",children:h.message}):null,!d&&!h&&c.length===0?s.jsx("p",{className:"createPage__panelPlaceholder",children:r("pages.create.panels.favorite.placeholder")}):null,c.length>0?s.jsxs(s.Fragment,{children:[s.jsx("ul",{className:"myFavoritePanel__list",role:"list",children:$}),g?s.jsx("div",{ref:L,className:"myFavoritePanel__sentinel","aria-hidden":!0}):null,v?s.jsx("p",{className:"createPage__panelStatus myFavoritePanel__loadMore",children:r("common.loading")}):null]}):null]})]})}export{ee as default};
//# sourceMappingURL=index-BY9C46Hx.js.map

1
dist/assets/index-BY9C46Hx.js.map

File diff suppressed because one or more lines are too long

14
dist/assets/index-DSZ4TxXA.js → dist/assets/index-BlWdPD5L.js

File diff suppressed because one or more lines are too long

1
dist/assets/index-BlWdPD5L.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-WndMfowJ.js → dist/assets/index-BpEIsqGj.js

File diff suppressed because one or more lines are too long

2
dist/assets/index-WndMfowJ.js.map → dist/assets/index-BpEIsqGj.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-m-i9epVT.js → dist/assets/index-C8p-BT1G.js

File diff suppressed because one or more lines are too long

2
dist/assets/index-m-i9epVT.js.map → dist/assets/index-C8p-BT1G.js.map

File diff suppressed because one or more lines are too long

1
dist/assets/index-CFE14uAE.js.map

File diff suppressed because one or more lines are too long

1
dist/assets/index-COrnfX8o.js.map

File diff suppressed because one or more lines are too long

1
dist/assets/index-DSZ4TxXA.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-B31bvijX.js → dist/assets/index-DWUOHYXx.js

File diff suppressed because one or more lines are too long

2
dist/assets/index-B31bvijX.js.map → dist/assets/index-DWUOHYXx.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-Ccz8tTiD.js → dist/assets/index-X1UpxebS.js

File diff suppressed because one or more lines are too long

2
dist/assets/index-Ccz8tTiD.js.map → dist/assets/index-X1UpxebS.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-D6s7DLC0.js → dist/assets/index-bqQ0a4cY.js

@ -1,2 +1,2 @@
import{j as t}from"./markdown-vendor-BZI_VWzW.js";import{L as o}from"./react-vendor-wlKWdfEb.js";import{R as s}from"./index-DSZ4TxXA.js";import{u as r}from"./data-vendor-BOGugMqL.js";import"./arco-vendor-CAnKnMnO.js";function c(){const{t:e}=r();return t.jsxs("div",{className:"flex min-h-[60vh] flex-col items-center justify-center text-gray-600",children:[t.jsx("p",{className:"text-6xl font-bold text-gray-300",children:"404"}),t.jsx("p",{className:"mt-2",children:e("notFound.title")}),t.jsx(o,{to:s.EXPLORE,className:"mt-4 text-blue-600 hover:underline",children:e("notFound.backHome")})]})}export{c as default};
//# sourceMappingURL=index-D6s7DLC0.js.map
import{j as t}from"./markdown-vendor-BZI_VWzW.js";import{L as o}from"./react-vendor-wlKWdfEb.js";import{R as s}from"./index-BlWdPD5L.js";import{u as r}from"./data-vendor-BOGugMqL.js";import"./arco-vendor-CAnKnMnO.js";function c(){const{t:e}=r();return t.jsxs("div",{className:"flex min-h-[60vh] flex-col items-center justify-center text-gray-600",children:[t.jsx("p",{className:"text-6xl font-bold text-gray-300",children:"404"}),t.jsx("p",{className:"mt-2",children:e("notFound.title")}),t.jsx(o,{to:s.EXPLORE,className:"mt-4 text-blue-600 hover:underline",children:e("notFound.backHome")})]})}export{c as default};
//# sourceMappingURL=index-bqQ0a4cY.js.map

2
dist/assets/index-D6s7DLC0.js.map → dist/assets/index-bqQ0a4cY.js.map

@ -1 +1 @@
{"version":3,"file":"index-D6s7DLC0.js","sources":["../../src/pages/NotFound/index.tsx"],"sourcesContent":["import { Link } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport { ROUTES } from \"@/constants\";\n\nexport default function NotFound() {\n const { t } = useTranslation();\n return (\n <div className=\"flex min-h-[60vh] flex-col items-center justify-center text-gray-600\">\n <p className=\"text-6xl font-bold text-gray-300\">404</p>\n <p className=\"mt-2\">{t(\"notFound.title\")}</p>\n <Link to={ROUTES.EXPLORE} className=\"mt-4 text-blue-600 hover:underline\">\n {t(\"notFound.backHome\")}\n </Link>\n </div>\n );\n}\n"],"names":["NotFound","t","useTranslation","jsxs","jsx","Link","ROUTES"],"mappings":"yNAIA,SAAwBA,GAAW,CACjC,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAA,EACd,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,uEACb,SAAA,CAAAC,EAAAA,IAAC,IAAA,CAAE,UAAU,mCAAmC,SAAA,MAAG,QAClD,IAAA,CAAE,UAAU,OAAQ,SAAAH,EAAE,gBAAgB,EAAE,EACzCG,EAAAA,IAACC,GAAK,GAAIC,EAAO,QAAS,UAAU,qCACjC,SAAAL,EAAE,mBAAmB,CAAA,CACxB,CAAA,EACF,CAEJ"}
{"version":3,"file":"index-bqQ0a4cY.js","sources":["../../src/pages/NotFound/index.tsx"],"sourcesContent":["import { Link } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport { ROUTES } from \"@/constants\";\n\nexport default function NotFound() {\n const { t } = useTranslation();\n return (\n <div className=\"flex min-h-[60vh] flex-col items-center justify-center text-gray-600\">\n <p className=\"text-6xl font-bold text-gray-300\">404</p>\n <p className=\"mt-2\">{t(\"notFound.title\")}</p>\n <Link to={ROUTES.EXPLORE} className=\"mt-4 text-blue-600 hover:underline\">\n {t(\"notFound.backHome\")}\n </Link>\n </div>\n );\n}\n"],"names":["NotFound","t","useTranslation","jsxs","jsx","Link","ROUTES"],"mappings":"yNAIA,SAAwBA,GAAW,CACjC,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAA,EACd,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,uEACb,SAAA,CAAAC,EAAAA,IAAC,IAAA,CAAE,UAAU,mCAAmC,SAAA,MAAG,QAClD,IAAA,CAAE,UAAU,OAAQ,SAAAH,EAAE,gBAAgB,EAAE,EACzCG,EAAAA,IAACC,GAAK,GAAIC,EAAO,QAAS,UAAU,qCACjC,SAAAL,EAAE,mBAAmB,CAAA,CACxB,CAAA,EACF,CAEJ"}

1
dist/assets/index-neZGhFpy.js.map

File diff suppressed because one or more lines are too long

4
dist/assets/index-CFE14uAE.js → dist/assets/index-ocHw71Eb.js

File diff suppressed because one or more lines are too long

1
dist/assets/index-ocHw71Eb.js.map

File diff suppressed because one or more lines are too long

2
dist/index.html

@ -18,7 +18,7 @@
<!-- <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> -->
<!-- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> -->
<!-- <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet"> -->
<script type="module" crossorigin src="/assets/index-DSZ4TxXA.js"></script>
<script type="module" crossorigin src="/assets/index-BlWdPD5L.js"></script>
<link rel="modulepreload" crossorigin href="/assets/data-vendor-BOGugMqL.js">
<link rel="modulepreload" crossorigin href="/assets/markdown-vendor-BZI_VWzW.js">
<link rel="modulepreload" crossorigin href="/assets/react-vendor-wlKWdfEb.js">

BIN
popiart-website-new.zip

Binary file not shown.

15
src/pages/Characters/index.scss

@ -266,6 +266,21 @@
text-overflow: ellipsis;
}
&__sentinel {
width: 100%;
height: 1px;
}
&__loading_more {
margin: 10px 0 0;
font-family: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
font-size: 14px;
font-weight: 500;
line-height: 26px;
color: #999999;
text-align: center;
}
&__diy_card {
cursor: pointer;
border: none;

259
src/pages/Characters/index.tsx

@ -35,6 +35,9 @@ const CHARACTER_LIBRARY_TAB = {
} as const;
type CharacterLibraryTab = (typeof CHARACTER_LIBRARY_TAB)[keyof typeof CHARACTER_LIBRARY_TAB];
const CHARACTERS_PAGE_SIZE = 30;
const LOAD_MORE_ROOT_MARGIN = "160px";
/**
* URL warmup 线
*
@ -51,6 +54,34 @@ function collectUniqueImageUrls(...groups: Array<Array<string | undefined>>) {
return Array.from(set);
}
function mergeUniqueById<T extends { id?: unknown }>(prev: T[], next: T[]): { merged: T[]; appendedCount: number } {
const existing = new Set<string>();
for (const row of prev) {
const id = row?.id;
if (id == null || id === "") continue;
existing.add(String(id));
}
const appended: T[] = [];
let appendedCount = 0;
for (const row of next) {
const id = row?.id;
if (id == null || id === "") {
appended.push(row);
appendedCount += 1;
continue;
}
const sid = String(id);
if (existing.has(sid)) continue;
existing.add(sid);
appended.push(row);
appendedCount += 1;
}
if (appendedCount === 0) return { merged: prev, appendedCount: 0 };
return { merged: [...prev, ...appended], appendedCount };
}
interface CharacterCardProps {
item: any;
isButton?: boolean;
@ -129,8 +160,28 @@ export function CharacterLibrarySections({ showDiyEntry = true }: CharacterLibra
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null);
const [categoryMenuOpen, setCategoryMenuOpen] = useState(false);
const [officialPage, setOfficialPage] = useState(1);
const [officialHasMore, setOfficialHasMore] = useState(true);
const [officialIsLoading, setOfficialIsLoading] = useState(false);
const [officialIsLoadingMore, setOfficialIsLoadingMore] = useState(false);
const [communityPage, setCommunityPage] = useState(1);
const [communityHasMore, setCommunityHasMore] = useState(true);
const [communityIsLoading, setCommunityIsLoading] = useState(false);
const [communityIsLoadingMore, setCommunityIsLoadingMore] = useState(false);
const [myCharacters, setMyCharacters] = useState<any[]>([]);// 我的角色
const dragTransferManager = useMemo(() => createImageDragTransferManager(), []);
const sentinelRef = useRef<HTMLDivElement>(null);
const officialQueryKeyRef = useRef<string>("");
const communityQueryKeyRef = useRef<string>("");
const officialPageRef = useRef(1);
const communityPageRef = useRef(1);
const officialCharactersRef = useRef<Record<string, unknown>[]>(officialCharacters);
const communityCharactersRef = useRef<any[]>(communityCharacters);
const officialLoadMoreLockRef = useRef(false);
const communityLoadMoreLockRef = useRef(false);
const loadNextPageRef = useRef<() => void>(() => {});
useEffect(() => {
return () => {
@ -138,6 +189,14 @@ export function CharacterLibrarySections({ showDiyEntry = true }: CharacterLibra
};
}, [dragTransferManager]);
useEffect(() => {
officialCharactersRef.current = officialCharacters;
}, [officialCharacters]);
useEffect(() => {
communityCharactersRef.current = communityCharacters;
}, [communityCharacters]);
// 官方角色分类
useEffect(() => {
void getCategoryListAll()
@ -209,29 +268,47 @@ export function CharacterLibrarySections({ showDiyEntry = true }: CharacterLibra
if (activeLibraryTab !== CHARACTER_LIBRARY_TAB.OFFICIAL) {
return;
}
const queryKey = `${String(selectedCategoryId ?? "all")}|${keywordParam}`;
officialQueryKeyRef.current = queryKey;
setOfficialPage(1);
officialPageRef.current = 1;
setOfficialHasMore(true);
setOfficialIsLoading(true);
const params: Record<string, unknown> = {
type: 1,
page: 1,
pageSize: 30,
pageSize: CHARACTERS_PAGE_SIZE,
};
if (selectedCategoryId != null) {
params.categoryId = selectedCategoryId;
}
if (keywordParam) {
params.keyword = keywordParam;
}
if (selectedCategoryId != null) params.categoryId = selectedCategoryId;
if (keywordParam) params.keyword = keywordParam;
let cancelled = false;
void getCharacterList(params)
.then((res: any) => {
if (!cancelled) {
setOfficialCharacters(parseCharacterListPayload(res));
}
if (cancelled) return;
if (officialQueryKeyRef.current !== queryKey) return;
const list = parseCharacterListPayload(res);
setOfficialCharacters(list);
setOfficialHasMore(list.length >= CHARACTERS_PAGE_SIZE);
})
.catch(() => {
if (!cancelled) {
setOfficialCharacters([]);
}
if (cancelled) return;
if (officialQueryKeyRef.current !== queryKey) return;
setOfficialCharacters([]);
setOfficialHasMore(false);
})
.finally(() => {
if (cancelled) return;
if (officialQueryKeyRef.current !== queryKey) return;
setOfficialIsLoading(false);
setOfficialIsLoadingMore(false);
officialLoadMoreLockRef.current = false;
});
return () => {
cancelled = true;
};
@ -242,27 +319,154 @@ export function CharacterLibrarySections({ showDiyEntry = true }: CharacterLibra
if (activeLibraryTab !== CHARACTER_LIBRARY_TAB.COMMUNITY) {
return;
}
const params: Record<string, unknown> = {};
if (keywordParam) {
params.keyword = keywordParam;
}
const queryKey = `${String(keywordParam ?? "")}`;
communityQueryKeyRef.current = queryKey;
setCommunityPage(1);
communityPageRef.current = 1;
setCommunityHasMore(true);
setCommunityIsLoading(true);
const params: Record<string, unknown> = {
page: 1,
pageSize: CHARACTERS_PAGE_SIZE,
};
if (keywordParam) params.keyword = keywordParam;
let cancelled = false;
void getUserPublicCharacterList(params)
.then((res: any) => {
if (!cancelled) {
setCommunityCharacters(parseCharacterListPayload(res));
}
if (cancelled) return;
if (communityQueryKeyRef.current !== queryKey) return;
const list = parseCharacterListPayload(res);
setCommunityCharacters(list);
setCommunityHasMore(list.length >= CHARACTERS_PAGE_SIZE);
})
.catch(() => {
if (!cancelled) {
setCommunityCharacters([]);
}
if (cancelled) return;
if (communityQueryKeyRef.current !== queryKey) return;
setCommunityCharacters([]);
setCommunityHasMore(false);
})
.finally(() => {
if (cancelled) return;
if (communityQueryKeyRef.current !== queryKey) return;
setCommunityIsLoading(false);
setCommunityIsLoadingMore(false);
communityLoadMoreLockRef.current = false;
});
return () => {
cancelled = true;
};
}, [activeLibraryTab, keywordParam]);
const loadMoreOfficial = useCallback(async () => {
if (!officialHasMore || officialIsLoading || officialIsLoadingMore) return;
if (officialLoadMoreLockRef.current) return;
officialLoadMoreLockRef.current = true;
setOfficialIsLoadingMore(true);
const queryKey = officialQueryKeyRef.current;
const nextPage = officialPageRef.current + 1;
try {
const params: Record<string, unknown> = {
type: 1,
page: nextPage,
pageSize: CHARACTERS_PAGE_SIZE,
};
if (selectedCategoryId != null) params.categoryId = selectedCategoryId;
if (keywordParam) params.keyword = keywordParam;
const res: any = await getCharacterList(params);
if (officialQueryKeyRef.current !== queryKey) return;
const nextList = parseCharacterListPayload(res);
const { appendedCount, merged } = mergeUniqueById(officialCharactersRef.current, nextList);
setOfficialCharacters(merged);
setOfficialPage(nextPage);
officialPageRef.current = nextPage;
if (appendedCount === 0) setOfficialHasMore(false);
else setOfficialHasMore(nextList.length >= CHARACTERS_PAGE_SIZE);
} catch {
if (officialQueryKeyRef.current !== queryKey) return;
setOfficialHasMore(false);
} finally {
officialLoadMoreLockRef.current = false;
if (officialQueryKeyRef.current === queryKey) setOfficialIsLoadingMore(false);
}
}, [officialHasMore, officialIsLoading, officialIsLoadingMore, selectedCategoryId, keywordParam]);
const loadMoreCommunity = useCallback(async () => {
if (!communityHasMore || communityIsLoading || communityIsLoadingMore) return;
if (communityLoadMoreLockRef.current) return;
communityLoadMoreLockRef.current = true;
setCommunityIsLoadingMore(true);
const queryKey = communityQueryKeyRef.current;
const nextPage = communityPageRef.current + 1;
try {
const params: Record<string, unknown> = {
page: nextPage,
pageSize: CHARACTERS_PAGE_SIZE,
};
if (keywordParam) params.keyword = keywordParam;
const res: any = await getUserPublicCharacterList(params);
if (communityQueryKeyRef.current !== queryKey) return;
const nextList = parseCharacterListPayload(res);
const { appendedCount, merged } = mergeUniqueById(communityCharactersRef.current, nextList);
setCommunityCharacters(merged);
setCommunityPage(nextPage);
communityPageRef.current = nextPage;
if (appendedCount === 0) setCommunityHasMore(false);
else setCommunityHasMore(nextList.length >= CHARACTERS_PAGE_SIZE);
} catch {
if (communityQueryKeyRef.current !== queryKey) return;
setCommunityHasMore(false);
} finally {
communityLoadMoreLockRef.current = false;
if (communityQueryKeyRef.current === queryKey) setCommunityIsLoadingMore(false);
}
}, [communityHasMore, communityIsLoading, communityIsLoadingMore, keywordParam]);
useEffect(() => {
loadNextPageRef.current = () => {
if (activeLibraryTab === CHARACTER_LIBRARY_TAB.OFFICIAL) void loadMoreOfficial();
else void loadMoreCommunity();
};
}, [activeLibraryTab, loadMoreOfficial, loadMoreCommunity]);
const hasMoreForActive = activeLibraryTab === CHARACTER_LIBRARY_TAB.OFFICIAL ? officialHasMore : communityHasMore;
const isLoadingForActive = activeLibraryTab === CHARACTER_LIBRARY_TAB.OFFICIAL ? officialIsLoading || officialIsLoadingMore : communityIsLoading || communityIsLoadingMore;
useEffect(() => {
const node = sentinelRef.current;
if (!node) return;
if (!hasMoreForActive || isLoadingForActive) return;
const io = new IntersectionObserver(
(entries) => {
if (entries[0]?.isIntersecting) void loadNextPageRef.current();
},
{ root: null, rootMargin: LOAD_MORE_ROOT_MARGIN, threshold: 0 },
);
io.observe(node);
return () => io.disconnect();
}, [hasMoreForActive, isLoadingForActive, officialCharacters.length, communityCharacters.length]);
useEffect(() => {
// 把三组数据一次合并后统一预热,避免重复调用造成的多次调度。
const urls = collectUniqueImageUrls(
@ -527,6 +731,15 @@ export function CharacterLibrarySections({ showDiyEntry = true }: CharacterLibra
/>
))}
</div>
{activeLibraryTab === CHARACTER_LIBRARY_TAB.OFFICIAL && officialIsLoadingMore ? (
<p className="character_library_sections__loading_more">{t("common.loading")}</p>
) : null}
{activeLibraryTab === CHARACTER_LIBRARY_TAB.COMMUNITY && communityIsLoadingMore ? (
<p className="character_library_sections__loading_more">{t("common.loading")}</p>
) : null}
{hasMoreForActive && !isLoadingForActive ? <div ref={sentinelRef} className="character_library_sections__sentinel" aria-hidden /> : null}
</section>
</div>
);

4
vite.config.mts

@ -24,8 +24,8 @@ export default defineConfig(({ mode }) => {
proxy: isDev
? {
"/api_client": {
target: "http://192.168.77.111:8080/",
// target: "https://popi.yuanzoo.cn/",
// target: "http://192.168.77.111:8080/",
target: "https://popi.yuanzoo.cn/",
secure: false,
changeOrigin: true,
},

Loading…
Cancel
Save