From 9adafb135498f8a56d2b49c714e06381402313c0 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 09:38:19 +0800 Subject: [PATCH 01/58] =?UTF-8?q?feat(auth):=20access=20token=20=E7=BC=A9?= =?UTF-8?q?=E5=88=B0=202=20=E5=B0=8F=E6=97=B6=20+=20refresh=20token=20?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后台登录框原来预填了 sundynix/sundynix,等于把凭证写在页面上,去掉。 令牌改为 access(2h) + refresh 两段式: - 新表 sundynix_refresh_tokens,只存 sha256,明文只在签发时返回一次 - 有效期:小程序 30 天、后台 7 天 - 新接口 /api/auth/refresh|logout、/api/admin/refresh|logout 安全约定: - 每次续期都轮换刷新令牌,旧的立即作废 - 作废后 60 秒内再到达算并发重试放行,超过则判定泄露、吊销该账号全部会话 - 主动退出与被连坐吊销的令牌不吃宽限期,否则「吊销全部」形同虚设 - 禁用用户时一并吊销刷新令牌,最多 2 小时彻底失去访问 两端请求层都做了单飞续期:并发请求同时 401 只发一次 refresh, 否则刷新令牌会被并发轮换掉互相打架。小程序续期失败回退 wx.login, 登录/续期请求标 noAuthRetry,避免登录失败(同样返回 40100)触发自我套娃。 顺带修掉 vite 代理仍指向 8080 的遗留(端口早已改 9090)。 Co-Authored-By: Claude Opus 5 --- deploy/.env.example | 6 +- deploy/docker-compose.yml | 5 +- pets-be/README.md | 15 ++ .../admin/dist/assets/index-1jDx3IlD.js | 59 +++++++ .../admin/dist/assets/index-BmWfHKYa.js | 59 ------- pets-be/internal/admin/dist/index.html | 2 +- pets-be/internal/config/config.go | 12 +- pets-be/internal/handler/admin.go | 58 ++++++- pets-be/internal/handler/auth.go | 69 ++++++++- pets-be/internal/model/base.go | 1 + pets-be/internal/model/refresh_token.go | 19 +++ pets-be/internal/router/router.go | 5 + pets-be/internal/service/admin.go | 9 +- pets-be/internal/service/token.go | 145 ++++++++++++++++++ pets-be/pkg/jwt/jwt.go | 7 +- pets-be/web/admin/src/components/Layout.tsx | 4 +- pets-be/web/admin/src/lib/api.ts | 62 +++++++- pets-be/web/admin/src/pages/Login.tsx | 28 +++- pets-be/web/admin/vite.config.ts | 2 +- pets-fe/utils/api.js | 25 ++- pets-fe/utils/request.js | 81 ++++++++-- 21 files changed, 569 insertions(+), 104 deletions(-) create mode 100644 pets-be/internal/admin/dist/assets/index-1jDx3IlD.js delete mode 100644 pets-be/internal/admin/dist/assets/index-BmWfHKYa.js create mode 100644 pets-be/internal/model/refresh_token.go create mode 100644 pets-be/internal/service/token.go diff --git a/deploy/.env.example b/deploy/.env.example index 4dc99ef..9f75c14 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -32,7 +32,11 @@ MINIO_PUBLIC_BASE_URL=https://res.sundynix.cn # ── 登录鉴权 ── JWT_SECRET=改成随机长字符串 -JWT_EXPIRE_HOURS=168 +# access token 有效期(小时)。短一点更安全,过期由前端拿 refresh token 静默续期 +JWT_EXPIRE_HOURS=2 +# 刷新令牌有效期:小程序 30 天、后台 7 天。到期才需要重新登录 +JWT_REFRESH_EXPIRE_HOURS=720 +JWT_ADMIN_REFRESH_EXPIRE_HOURS=168 # 生产必须 false,否则任何人都能用昵称直接登录 AUTH_DEV_LOGIN=false diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 60ccca8..f0908ed 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -38,7 +38,10 @@ services: PETS_MINIO_PUBLIC_BASE_URL: ${MINIO_PUBLIC_BASE_URL:?} PETS_JWT_SECRET: ${JWT_SECRET:?} - PETS_JWT_EXPIRE_HOURS: ${JWT_EXPIRE_HOURS:-168} + # access token 2 小时;过期由前端拿 refresh token 静默续期 + PETS_JWT_EXPIRE_HOURS: ${JWT_EXPIRE_HOURS:-2} + PETS_JWT_REFRESH_EXPIRE_HOURS: ${JWT_REFRESH_EXPIRE_HOURS:-720} + PETS_JWT_ADMIN_REFRESH_EXPIRE_HOURS: ${JWT_ADMIN_REFRESH_EXPIRE_HOURS:-168} PETS_WECHAT_APP_ID: ${WECHAT_APP_ID:?} PETS_WECHAT_APP_SECRET: ${WECHAT_APP_SECRET:?} diff --git a/pets-be/README.md b/pets-be/README.md index 725fd80..0cd3e4b 100644 --- a/pets-be/README.md +++ b/pets-be/README.md @@ -47,3 +47,18 @@ make admin-dev # vite dev server :5173,已代理 /api → :8080 ## 登录鉴权 默认 `auth.dev_login: true`,`POST /api/auth/login {"nickname":"xxx"}` 即发用户 JWT。 接真微信:在 `configs/config.yaml` 填 `wechat.app_secret` 并把 `dev_login` 置 false,实现 `/api/auth/wechat`(code2session)。 + +### access token + refresh token +登录接口返回 `token`(access) 与 `refresh_token` 两个令牌: + +- **access token**:JWT,默认 **2 小时**(`jwt.expire_hours`),放 `Authorization: Bearer`,服务端无状态校验。 +- **refresh token**:随机串,落库 `sundynix_refresh_tokens`(**只存 sha256**)。小程序 30 天、后台 7 天。 +- 续期:`POST /api/auth/refresh` / `POST /api/admin/refresh`,入参 `{"refresh_token":"..."}`,返回新的一对令牌。 +- 退出:`POST /api/auth/logout` / `POST /api/admin/logout` 作废该刷新令牌。 + +安全约定: +- **每次续期都轮换**刷新令牌,旧的立即作废;作废后 60 秒内再到达算并发重试(放行),超过则判定泄露,**吊销该账号全部会话**。 +- 主动退出、被连坐吊销的令牌不享受宽限期。 +- 禁用用户时一并吊销其刷新令牌,最多 2 小时后彻底失去访问。 + +前端两端都做了单飞续期:并发请求同时 401 只会发一次 refresh(否则刷新令牌会被并发轮换掉)。小程序续期失败会回退到 `wx.login` 重新登录。 diff --git a/pets-be/internal/admin/dist/assets/index-1jDx3IlD.js b/pets-be/internal/admin/dist/assets/index-1jDx3IlD.js new file mode 100644 index 0000000..94625bd --- /dev/null +++ b/pets-be/internal/admin/dist/assets/index-1jDx3IlD.js @@ -0,0 +1,59 @@ +var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,a)=>(a=n==null?{}:e(i(n)),c(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var u=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function ee(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function te(e,t){return ee(e.type,t,e.props)}function ne(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function E(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var D=/\/+/g;function O(e,t){return typeof e==`object`&&e&&e.key!=null?E(``+e.key):t.toString(36)}function re(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ie(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ie(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+O(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(D,`$&/`)+`/`),ie(o,r,i,``,function(e){return e})):o!=null&&(ne(o)&&(o=te(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(D,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=u()})),f=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,ne());else{var t=n(l);t!==null&&O(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function ee(){return g?!0:!(e.unstable_now()-Tt&&ee());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&O(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?ne():S=!1}}}var ne;if(typeof y==`function`)ne=function(){y(te)};else if(typeof MessageChannel<`u`){var E=new MessageChannel,D=E.port2;E.port1.onmessage=te,ne=function(){D.postMessage(null)}}else ne=function(){_(te,0)};function O(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,O(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,ne()))),r},e.unstable_shouldYield=ee,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),p=o(((e,t)=>{t.exports=f()})),m=o((e=>{var t=d();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=m()})),g=o((e=>{var t=p(),n=d(),r=h();function i(e){var t=`https://react.dev/errors/`+e;if(1le||(e.current=ce[le],ce[le]=null,le--)}function N(e,t){le++,ce[le]=e.current,e.current=t}var ue=j(null),de=j(null),fe=j(null),pe=j(null);function me(e,t){switch(N(fe,t),N(de,e),N(ue,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}M(ue),N(ue,e)}function he(){M(ue),M(de),M(fe)}function ge(e){e.memoizedState!==null&&N(pe,e);var t=ue.current,n=Hd(t,e.type);t!==n&&(N(de,e),N(ue,n))}function _e(e){de.current===e&&(M(ue),M(de)),pe.current===e&&(M(pe),Qf._currentValue=se)}var ve,ye;function be(e){if(ve===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);ve=t&&t[1]||``,ye=-1)`:-1i||c[r]!==l[i]){var u=` +`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{xe=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?be(n):``}function Ce(e,t){switch(e.tag){case 26:case 27:case 5:return be(e.type);case 16:return be(`Lazy`);case 13:return e.child!==t&&t!==null?be(`Suspense Fallback`):be(`Suspense`);case 19:return be(`SuspenseList`);case 0:case 15:return Se(e.type,!1);case 11:return Se(e.type.render,!1);case 1:return Se(e.type,!0);case 31:return be(`Activity`);default:return``}}function we(e){try{var t=``,n=null;do t+=Ce(e,n),n=e,e=e.return;while(e);return t}catch(e){return` +Error generating stack: `+e.message+` +`+e.stack}}var Te=Object.prototype.hasOwnProperty,Ee=t.unstable_scheduleCallback,De=t.unstable_cancelCallback,Oe=t.unstable_shouldYield,ke=t.unstable_requestPaint,Ae=t.unstable_now,je=t.unstable_getCurrentPriorityLevel,Me=t.unstable_ImmediatePriority,Ne=t.unstable_UserBlockingPriority,Pe=t.unstable_NormalPriority,Fe=t.unstable_LowPriority,Ie=t.unstable_IdlePriority,Le=t.log,Re=t.unstable_setDisableYieldValue,ze=null,Be=null;function Ve(e){if(typeof Le==`function`&&Re(e),Be&&typeof Be.setStrictMode==`function`)try{Be.setStrictMode(ze,e)}catch{}}var He=Math.clz32?Math.clz32:Ge,Ue=Math.log,We=Math.LN2;function Ge(e){return e>>>=0,e===0?32:31-(Ue(e)/We|0)|0}var Ke=256,qe=262144,Je=4194304;function Ye(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Xe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ye(n))):i=Ye(o):i=Ye(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ye(n))):i=Ye(o)):i=Ye(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ze(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function $e(){var e=Je;return Je<<=1,!(Je&62914560)&&(Je=4194304),e}function et(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function tt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nt(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),mn=!1;if(pn)try{var hn={};Object.defineProperty(hn,"passive",{get:function(){mn=!0}}),window.addEventListener(`test`,hn,hn),window.removeEventListener(`test`,hn,hn)}catch{mn=!1}var gn=null,_n=null,vn=null;function yn(){if(vn)return vn;var e,t=_n,n=t.length,r,i=`value`in gn?gn.value:gn.textContent,a=i.length;for(e=0;e=Zn),er=` `,tr=!1;function nr(e,t){switch(e){case`keyup`:return Yn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function rr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ir=!1;function ar(e,t){switch(e){case`compositionend`:return rr(t);case`keypress`:return t.which===32?(tr=!0,er):null;case`textInput`:return e=t.data,e===er&&tr?null:e;default:return null}}function or(e,t){if(ir)return e===`compositionend`||!Xn&&nr(e,t)?(e=yn(),vn=_n=gn=null,ir=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Or(n)}}function Ar(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ar(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Bt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Bt(e.document)}return t}function Mr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Nr=pn&&`documentMode`in document&&11>=document.documentMode,Pr=null,Fr=null,Ir=null,Lr=!1;function Rr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Lr||Pr==null||Pr!==Bt(r)||(r=Pr,`selectionStart`in r&&Mr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ir&&Dr(Ir,r)||(Ir=r,r=Ed(Fr,`onSelect`),0>=o,i-=o,ki=1<<32-He(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),L&&ji(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),L&&ji(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return L&&ji(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),L&&ji(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===ne&&Aa(l)===r.type){n(e,r.sibling),c=a(r,o.props),La(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=gi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=hi(o.type,o.key,o.props,null,e.mode,c),La(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=yi(o,e.mode,c),c.return=e,e=c}return s(e);case ne:return o=Aa(o),b(e,r,o,c)}if(oe(o))return h(e,r,o,c);if(re(o)){if(l=re(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Ia(o),c);if(o.$$typeof===C)return b(e,r,ia(e,o),c);Ra(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=_i(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Fa=0;var i=b(e,t,n,r);return Pa=null,i}catch(t){if(t===wa||t===Ea)throw t;var a=fi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ba=za(!0),Va=za(!1),Ha=!1;function Ua(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Wa(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ga(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ka(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,q&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=li(e),ci(e,null,n),t}return ai(e,r,t,n),li(e)}function qa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}function Ja(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ya=!1;function Xa(){if(Ya){var e=ha;if(e!==null)throw e}}function Za(e,t,n,r){Ya=!1;var i=e.updateQueue;Ha=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(Y&f)===f:(r&f)===f){f!==0&&f===ma&&(Ya=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=m({},d,f);break a;case 2:Ha=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Gl|=o,e.lanes=o,e.memoizedState=d}}function Qa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function $a(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,Ls(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Is(e,t,va(c,r),pu(e)):Is(e,t,r,pu(e))}catch(n){Is(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function Es(){}function Ds(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Os(e).queue;Ts(e,a,t,se,n===null?Es:function(){return ks(e),n(r)})}function Os(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:se,baseState:se,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:se},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function ks(e){var t=Os(e);t.next===null&&(t=e.alternate.memoizedState),Is(e,t.next.queue,{},pu())}function As(){return ra(Qf)}function js(){return No().memoizedState}function Ms(){return No().memoizedState}function Ns(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Ga(n);var r=Ka(t,e,n);r!==null&&(hu(r,t,n),qa(r,t,n)),t={cache:ua()},e.payload=t;return}t=t.return}}function Ps(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Rs(e)?zs(t,n):(n=oi(e,t,n,r),n!==null&&(hu(n,e,r),Bs(n,t,r)))}function Fs(e,t,n){Is(e,t,n,pu())}function Is(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Rs(e))zs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Er(s,o))return ai(e,t,i,0),Rl===null&&ii(),!1}catch{}if(n=oi(e,t,i,r),n!==null)return hu(n,e,r),Bs(n,t,r),!0}return!1}function Ls(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Rs(e)){if(t)throw Error(i(479))}else t=oi(e,n,r,2),t!==null&&hu(t,e,2)}function Rs(e){var t=e.alternate;return e===R||t!==null&&t===R}function zs(e,t){vo=_o=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Bs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}var Vs={readContext:ra,use:Io,useCallback:wo,useContext:wo,useEffect:wo,useImperativeHandle:wo,useLayoutEffect:wo,useInsertionEffect:wo,useMemo:wo,useReducer:wo,useRef:wo,useState:wo,useDebugValue:wo,useDeferredValue:wo,useTransition:wo,useSyncExternalStore:wo,useId:wo,useHostTransitionStatus:wo,useFormState:wo,useActionState:wo,useOptimistic:wo,useMemoCache:wo,useCacheRefresh:wo};Vs.useEffectEvent=wo;var Hs={readContext:ra,use:Io,useCallback:function(e,t){return Mo().memoizedState=[e,t===void 0?null:t],e},useContext:ra,useEffect:fs,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),us(4194308,4,vs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return us(4194308,4,e,t)},useInsertionEffect:function(e,t){us(4,2,e,t)},useMemo:function(e,t){var n=Mo();t=t===void 0?null:t;var r=e();if(yo){Ve(!0);try{e()}finally{Ve(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Mo();if(n!==void 0){var i=n(t);if(yo){Ve(!0);try{n(t)}finally{Ve(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ps.bind(null,R,e),[r.memoizedState,e]},useRef:function(e){var t=Mo();return e={current:e},t.memoizedState=e},useState:function(e){e=Jo(e);var t=e.queue,n=Fs.bind(null,R,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:bs,useDeferredValue:function(e,t){return Cs(Mo(),e,t)},useTransition:function(){var e=Jo(!1);return e=Ts.bind(null,R,e.queue,!0,!1),Mo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=R,a=Mo();if(L){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Rl===null)throw Error(i(349));Y&127||Uo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,fs(Go.bind(null,r,o,e),[e]),r.flags|=2048,cs(9,{destroy:void 0},Wo.bind(null,r,o,n,t),null),n},useId:function(){var e=Mo(),t=Rl.identifierPrefix;if(L){var n=Ai,r=ki;n=(r&~(1<<32-He(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=bo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[P]=t,o[dt]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Nc(t)}}return Rc(t),Pc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Nc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=fe.current,Ui(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=I,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[P]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||Bi(t,!0)}else e=Bd(e).createTextNode(r),e[P]=t,t.stateNode=e}return Rc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Ui(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[P]=t}else Wi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),e=!1}else n=Gi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(fo(t),t):(fo(t),null);if(t.flags&128)throw Error(i(558))}return Rc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Ui(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[P]=t}else Wi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),a=!1}else a=Gi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(fo(t),t):(fo(t),null)}return fo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Ic(t,t.updateQueue),Rc(t),null);case 4:return he(),e===null&&Sd(t.stateNode.containerInfo),Rc(t),null;case 10:return Zi(t.type),Rc(t),null;case 19:if(M(po),r=t.memoizedState,r===null)return Rc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Lc(r,!1);else{if(Wl!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=mo(e),o!==null){for(t.flags|=128,Lc(r,!1),e=o.updateQueue,t.updateQueue=e,Ic(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)F(n,e),n=n.sibling;return N(po,po.current&1|2),L&&ji(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ae()>tu&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304)}else{if(!a)if(e=mo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Ic(t,e),Lc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!L)return Rc(t),null}else 2*Ae()-r.renderingStartTime>tu&&n!==536870912&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Rc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ae(),e.sibling=null,n=po.current,N(po,a?n&1|2:n&1),L&&ji(t,r.treeForkCount),e);case 22:case 23:return fo(t),io(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Rc(t),t.subtreeFlags&6&&(t.flags|=8192)):Rc(t),n=t.updateQueue,n!==null&&Ic(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&M(ba),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Zi(la),Rc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Pi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Zi(la),he(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return _e(t),null;case 31:if(t.memoizedState!==null){if(fo(t),t.alternate===null)throw Error(i(340));Wi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(fo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Wi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return M(po),null;case 4:return he(),null;case 10:return Zi(t.type),null;case 22:case 23:return fo(t),io(),e!==null&&M(ba),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Zi(la),null;case 25:return null;default:return null}}function Vc(e,t){switch(Pi(t),t.tag){case 3:Zi(la),he();break;case 26:case 27:case 5:_e(t);break;case 4:he();break;case 31:t.memoizedState!==null&&fo(t);break;case 13:fo(t);break;case 19:M(po);break;case 10:Zi(t.type);break;case 22:case 23:fo(t),io(),e!==null&&M(ba);break;case 24:Zi(la)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{$a(t,n)}catch(t){Z(e,e.return,t)}}}function Gc(e,t,n){n.props=Ys(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[dt]=t}catch(t){Z(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=rn));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[P]=e,t[dt]=n}catch(t){Z(e,e.return,t)}}var W=!1,tl=!1,nl=!1,rl=typeof WeakSet==`function`?WeakSet:Set,il=null;function al(e,t){if(e=e.containerInfo,Rd=sp,e=jr(e),Mr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,il=t;il!==null;)if(t=il,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,il=e;else for(;il!==null;){switch(t=il,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[P]=e,Ct(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=kr(s,h),v=kr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=lu,lu=null;var o=au,s=su;if(iu=0,ou=au=null,su=0,q&6)throw Error(i(331));var c=q;if(q|=4,Nl(o.current),Tl(o,o.current,s,n),q=c,id(0,!1),Be&&typeof Be.onPostCommitFiberRoot==`function`)try{Be.onPostCommitFiberRoot(ze,o)}catch{}return!0}finally{A.p=a,k.T=r,Vu(e,t)}}function Wu(e,t,n){t=xi(n,t),t=ec(e.stateNode,t,2),e=Ka(e,t,2),e!==null&&(tt(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(ru===null||!ru.has(r))){e=xi(n,e),n=tc(2),r=Ka(t,n,2),r!==null&&(nc(n,r,t,e),tt(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Ll;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Hl=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Rl===e&&(Y&n)===n&&(Wl===4||Wl===3&&(Y&62914560)===Y&&300>Ae()-$l?!(q&2)&&Su(e,0):ql|=n,Yl===Y&&(Yl=0)),rd(e)}function qu(e,t){t===0&&(t=$e()),e=si(e,t),e!==null&&(tt(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return Ee(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-He(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=Y,a=Xe(r,r===Rl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ze(r,a)||(n=!0,ld(r,a));r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=Ae(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}iu!==0&&iu!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ht(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),Ct(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ht(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ht(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ht(n.imageSizes)+`"]`)):i+=`[href="`+Ht(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=m({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),Ct(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ht(r)+`"][href="`+Ht(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=m({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),Ct(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=St(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=m({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);Ct(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=St(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Ct(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=St(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Ct(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=fe.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=St(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=St(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=St(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ht(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return m({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),Ct(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ht(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ht(n.href)+`"]`);if(r)return t.instance=r,Ct(r),r;var a=m({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),Ct(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,Ct(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),Ct(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,Ct(a),a):(r=n,(a=mf.get(o))&&(r=m({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),Ct(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,Ct(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),Ct(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=g()})),v=`modulepreload`,y=function(e){return`/admin/`+e},b={},x=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,new URL(`../../../src/node/plugins/importAnalysisBuild.ts`,import.meta.url)).href}r=o(t.map(t=>{if(t=y(t,n),t=s(t),t in b)return;b[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:v,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},S=l(d(),1),C=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,w=/^[\\/]{2}/;function T(e,t){return t+e.replace(/\\/g,`/`)}var ee=`popstate`;function te(e){return typeof e==`object`&&!!e&&`pathname`in e&&`search`in e&&`hash`in e&&`state`in e&&`key`in e}function ne(e={}){function t(e,t){let n=t.state?.masked,{pathname:r,search:i,hash:a}=n||e.location;return ie(``,{pathname:r,search:i,hash:a},t.state&&t.state.usr||null,t.state&&t.state.key||`default`,n?{pathname:e.location.pathname,search:e.location.search,hash:e.location.hash}:void 0)}function n(e,t){return typeof t==`string`?t:ae(t)}return k(t,n,null,e)}function E(e,t){if(e===!1||e==null)throw Error(t)}function D(e,t){if(!e){typeof console<`u`&&console.warn(t);try{throw Error(t)}catch{}}}function O(){return Math.random().toString(36).substring(2,10)}function re(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function ie(e,t,n=null,r,i){return{pathname:typeof e==`string`?e:e.pathname,search:``,hash:``,...typeof t==`string`?oe(t):t,state:n,key:t&&t.key||r||O(),mask:i}}function ae({pathname:e=`/`,search:t=``,hash:n=``}){return t&&t!==`?`&&(e+=t.charAt(0)===`?`?t:`?`+t),n&&n!==`#`&&(e+=n.charAt(0)===`#`?n:`#`+n),e}function oe(e){let t={};if(e){let n=e.indexOf(`#`);n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf(`?`);r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function k(e,t,n,r={}){let{window:i=document.defaultView,v5Compat:a=!1}=r,o=i.history,s=`POP`,c=null,l=u();l??(l=0,o.replaceState({...o.state,idx:l},``));function u(){return(o.state||{idx:null}).idx}function d(){s=`POP`;let e=u(),t=e==null?null:e-l;l=e,c&&c({action:s,location:h.location,delta:t})}function f(e,t){s=`PUSH`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u()+1;let d=re(r,l),f=h.createHref(r.mask||r);try{o.pushState(d,``,f)}catch(e){if(e instanceof DOMException&&e.name===`DataCloneError`)throw e;i.location.assign(f)}a&&c&&c({action:s,location:h.location,delta:1})}function p(e,t){s=`REPLACE`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u();let i=re(r,l),d=h.createHref(r.mask||r);o.replaceState(i,``,d),a&&c&&c({action:s,location:h.location,delta:0})}function m(e){return A(i,e)}let h={get action(){return s},get location(){return e(i,o)},listen(e){if(c)throw Error(`A history only accepts one active listener`);return i.addEventListener(ee,d),c=e,()=>{i.removeEventListener(ee,d),c=null}},createHref(e){return t(i,e)},createURL:m,encodeLocation(e){let t=m(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:f,replace:p,go(e){return o.go(e)}};return h}function A(e,t,n=!1){let r=`http://localhost`;e&&(r=e.location.origin===`null`?e.location.href:e.location.origin),E(r,`No window.location.(origin|href) available to create URL`);let i=typeof t==`string`?t:ae(t);return i=i.replace(/ $/,`%20`),!n&&w.test(i)&&(i=r+i),new URL(i,r)}function se(e,t,n=`/`){return ce(e,t,n,!1)}function ce(e,t,n,r,i){let a=Te((typeof t==`string`?oe(t):t).pathname||`/`,n);if(a==null)return null;let o=i??j(e),s=null,c=we(a);for(let e=0;s==null&&e{let c={relativePath:s===void 0?e.path||``:s,caseSensitive:e.caseSensitive===!0,childrenIndex:a,route:e};if(c.relativePath.startsWith(`/`)){if(!c.relativePath.startsWith(r)&&o)return;E(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length)}let l=Ne([r,c.relativePath]),u=n.concat(c);e.children&&e.children.length>0&&(E(e.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${l}".`),M(e.children,t,u,l,o)),!(e.path==null&&!e.index)&&t.push({path:l,score:ve(l,e.index),routesMeta:u.map((e,t)=>{let[n,r]=Ce(e.relativePath,e.caseSensitive,t===u.length-1);return{...e,matcher:n,compiledParams:r}})})};return e.forEach((e,t)=>{if(e.path===``||!e.path?.includes(`?`))a(e,t);else for(let n of N(e.path))a(e,t,!0,n)}),t}function N(e){let t=e.split(`/`);if(t.length===0)return[];let[n,...r]=t,i=n.endsWith(`?`),a=n.replace(/\?$/,``);if(r.length===0)return i?[a,``]:[a];let o=N(r.join(`/`)),s=[];return s.push(...o.map(e=>e===``?a:[a,e].join(`/`))),i&&s.push(...o),s.map(t=>e.startsWith(`/`)&&t===``?`/`:t)}function ue(e){e.sort((e,t)=>e.score===t.score?ye(e.routesMeta.map(e=>e.childrenIndex),t.routesMeta.map(e=>e.childrenIndex)):t.score-e.score)}var de=/^:[\w-]+$/,fe=3,pe=2,me=1,he=10,ge=-2,_e=e=>e===`*`;function ve(e,t){let n=e.split(`/`),r=n.length;return n.some(_e)&&(r+=ge),t&&(r+=pe),n.filter(e=>!_e(e)).reduce((e,t)=>e+(de.test(t)?fe:t===``?me:he),r)}function ye(e,t){return e.length===t.length&&e.slice(0,-1).every((e,n)=>e===t[n])?e[e.length-1]-t[t.length-1]:0}function be(e,t,n=!1){let{routesMeta:r}=e,i={},a=`/`,o=[];for(let e=0;e{if(t===`*`){let e=s[r]||``;o=a.slice(0,a.length-e.length).replace(/(.)\/+$/,`$1`)}let i=s[r];return n&&!i?e[t]=void 0:e[t]=(i||``).replace(/%2F/g,`/`),e},{}),pathname:a,pathnameBase:o,pattern:e}}function Ce(e,t=!1,n=!0){D(e===`*`||!e.endsWith(`*`)||e.endsWith(`/*`),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,`/*`)}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,`/*`)}".`);let r=[],i=`^`+e.replace(/\/*\*?$/,``).replace(/^\/*/,`/`).replace(/[\\.*+^${}|()[\]]/g,`\\$&`).replace(/\/:([\w-]+)(\?)?/g,(e,t,n,i,a)=>{if(r.push({paramName:t,isOptional:n!=null}),n){let t=a.charAt(i+e.length);return t&&t!==`/`?`/([^\\/]*)`:`(?:/([^\\/]*))?`}return`/([^\\/]+)`}).replace(/\/([\w-]+)\?(\/|$)/g,`(/$1)?$2`);return e.endsWith(`*`)?(r.push({paramName:`*`}),i+=e===`*`||e===`/*`?`(.*)$`:`(?:\\/(.+)|\\/*)$`):n?i+=`\\/*$`:e!==``&&e!==`/`&&(i+=`(?:(?=\\/|$))`),[new RegExp(i,t?void 0:`i`),r]}function we(e){try{return e.split(`/`).map(e=>decodeURIComponent(e).replace(/\//g,`%2F`)).join(`/`)}catch(t){return D(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Te(e,t){if(t===`/`)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith(`/`)?t.length-1:t.length,r=e.charAt(n);return r&&r!==`/`?null:e.slice(n)||`/`}function Ee(e,t=`/`){let{pathname:n,search:r=``,hash:i=``}=typeof e==`string`?oe(e):e,a;return n?(n=Me(n),a=n.startsWith(`/`)?De(n.substring(1),`/`):De(n,t)):a=t,{pathname:a,search:Ie(r),hash:Le(i)}}function De(e,t){let n=Pe(t).split(`/`);return e.split(`/`).forEach(e=>{e===`..`?n.length>1&&n.pop():e!==`.`&&n.push(e)}),n.length>1?n.join(`/`):`/`}function Oe(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ke(e){return e.filter((e,t)=>t===0||e.route.path&&e.route.path.length>0)}function Ae(e){let t=ke(e);return t.map((e,n)=>n===t.length-1?e.pathname:e.pathnameBase)}function je(e,t,n,r=!1){let i;typeof e==`string`?i=oe(e):(i={...e},E(!i.pathname||!i.pathname.includes(`?`),Oe(`?`,`pathname`,`search`,i)),E(!i.pathname||!i.pathname.includes(`#`),Oe(`#`,`pathname`,`hash`,i)),E(!i.search||!i.search.includes(`#`),Oe(`#`,`search`,`hash`,i)));let a=e===``||i.pathname===``,o=a?`/`:i.pathname,s;if(o==null)s=n;else{let e=t.length-1;if(!r&&o.startsWith(`..`)){let t=o.split(`/`);for(;t[0]===`..`;)t.shift(),--e;i.pathname=t.join(`/`)}s=e>=0?t[e]:`/`}let c=Ee(i,s),l=o&&o!==`/`&&o.endsWith(`/`),u=(a||o===`.`)&&n.endsWith(`/`);return!c.pathname.endsWith(`/`)&&(l||u)&&(c.pathname+=`/`),c}var Me=e=>e.replace(/[\\/]{2,}/g,`/`),Ne=e=>Me(e.join(`/`)),Pe=e=>e.replace(/\/+$/,``),Fe=e=>Pe(e).replace(/^\/*/,`/`),Ie=e=>!e||e===`?`?``:e.startsWith(`?`)?e:`?`+e,Le=e=>!e||e===`#`?``:e.startsWith(`#`)?e:`#`+e,Re=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||``,this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function ze(e){return e!=null&&typeof e.status==`number`&&typeof e.statusText==`string`&&typeof e.internal==`boolean`&&`data`in e}function Be(e){return Ne(e.map(e=>e.route.path).filter(Boolean))||`/`}var Ve=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function He(e,t){let n=e;if(typeof n!=`string`||!C.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(Ve)try{let e=new URL(window.location.href),r=w.test(n)?new URL(T(n,e.protocol)):new URL(n),a=Te(r.pathname,t);r.origin===e.origin&&a!=null?n=a+r.search+r.hash:i=!0}catch{D(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join(`\0`);var Ue=[`POST`,`PUT`,`PATCH`,`DELETE`];new Set(Ue);var We=[`GET`,...Ue];new Set(We);var Ge=[`about:`,`blob:`,`chrome:`,`chrome-untrusted:`,`content:`,`data:`,`devtools:`,`file:`,`filesystem:`,`javascript:`];function Ke(e){try{return Ge.includes(new URL(e).protocol)}catch{return!1}}var qe=S.createContext(null);qe.displayName=`DataRouter`;var Je=S.createContext(null);Je.displayName=`DataRouterState`;var Ye=S.createContext(!1);function Xe(){return S.useContext(Ye)}var Ze=S.createContext({isTransitioning:!1});Ze.displayName=`ViewTransition`;var Qe=S.createContext(new Map);Qe.displayName=`Fetchers`;var $e=S.createContext(null);$e.displayName=`Await`;var et=S.createContext(null);et.displayName=`Navigation`;var tt=S.createContext(null);tt.displayName=`Location`;var nt=S.createContext({outlet:null,matches:[],isDataRoute:!1});nt.displayName=`Route`;var rt=S.createContext(null);rt.displayName=`RouteError`;var it=`REACT_ROUTER_ERROR`,at=`REDIRECT`,ot=`ROUTE_ERROR_RESPONSE`;function st(e){if(e.startsWith(`${it}:${at}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`&&typeof t.location==`string`&&typeof t.reloadDocument==`boolean`&&typeof t.replace==`boolean`)return t}catch{}}function ct(e){if(e.startsWith(`${it}:${ot}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`)return new Re(t.status,t.statusText,t.data)}catch{}}function lt(e,{relative:t}={}){E(ut(),`useHref() may be used only in the context of a component.`);let{basename:n,navigator:r}=S.useContext(et),{hash:i,pathname:a,search:o}=_t(e,{relative:t}),s=a;return n!==`/`&&(s=a===`/`?n:Ne([n,a])),r.createHref({pathname:s,search:o,hash:i})}function ut(){return S.useContext(tt)!=null}function P(){return E(ut(),`useLocation() may be used only in the context of a component.`),S.useContext(tt).location}var dt=`You should call navigate() in a React.useEffect(), not when your component is first rendered.`;function ft(e){S.useContext(et).static||S.useLayoutEffect(e)}function pt(){let{isDataRoute:e}=S.useContext(nt);return e?It():mt()}function mt(){E(ut(),`useNavigate() may be used only in the context of a component.`);let e=S.useContext(qe),{basename:t,navigator:n}=S.useContext(et),{matches:r}=S.useContext(nt),{pathname:i}=P(),a=JSON.stringify(Ae(r)),o=S.useRef(!1);return ft(()=>{o.current=!0}),S.useCallback((r,s={})=>{if(D(o.current,dt),!o.current)return;if(typeof r==`number`){n.go(r);return}let c=je(r,JSON.parse(a),i,s.relative===`path`);e==null&&t!==`/`&&(c.pathname=c.pathname===`/`?t:Ne([t,c.pathname])),(s.replace?n.replace:n.push)(c,s.state,s)},[t,n,a,i,e])}var ht=S.createContext(null);function gt(e){let t=S.useContext(nt).outlet;return S.useMemo(()=>t&&S.createElement(ht.Provider,{value:e},t),[t,e])}function _t(e,{relative:t}={}){let{matches:n}=S.useContext(nt),{pathname:r}=P(),i=JSON.stringify(Ae(n));return S.useMemo(()=>je(e,JSON.parse(i),r,t===`path`),[e,i,r,t])}function vt(e,t){return yt(e,t)}function yt(e,t,n){E(ut(),`useRoutes() may be used only in the context of a component.`);let{navigator:r}=S.useContext(et),{matches:i}=S.useContext(nt),a=i[i.length-1],o=a?a.params:{},s=a?a.pathname:`/`,c=a?a.pathnameBase:`/`,l=a&&a.route;{let e=l&&l.path||``;Rt(s,!l||e.endsWith(`*`)||e.endsWith(`*?`),`You rendered descendant (or called \`useRoutes()\`) at "${s}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. + +Please change the parent to .`)}let u=P(),d;if(t){let e=typeof t==`string`?oe(t):t;E(c===`/`||e.pathname?.startsWith(c),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${c}" but pathname "${e.pathname}" was given in the \`location\` prop.`),d=e}else d=u;let f=d.pathname||`/`,p=f;if(c!==`/`){let e=c.replace(/^\//,``).split(`/`);p=`/`+f.replace(/^\//,``).split(`/`).slice(e.length).join(`/`)}let m=n&&n.state.matches.length?n.state.matches.map(e=>Object.assign(e,{route:n.manifest[e.route.id]||e.route})):se(e,{pathname:p});D(l||m!=null,`No routes matched location "${d.pathname}${d.search}${d.hash}" `),D(m==null||m[m.length-1].route.element!==void 0||m[m.length-1].route.Component!==void 0||m[m.length-1].route.lazy!==void 0,`Matched leaf route at location "${d.pathname}${d.search}${d.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let h=Et(m&&m.map(e=>Object.assign({},e,{params:Object.assign({},o,e.params),pathname:Ne([c,r.encodeLocation?r.encodeLocation(e.pathname.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathname]),pathnameBase:e.pathnameBase===`/`?c:Ne([c,r.encodeLocation?r.encodeLocation(e.pathnameBase.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathnameBase])})),i,n);return t&&h?S.createElement(tt.Provider,{value:{location:{pathname:`/`,search:``,hash:``,state:null,key:`default`,mask:void 0,...d},navigationType:`POP`}},h):h}function bt(){let e=Ft(),t=ze(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r=`rgba(200,200,200, 0.5)`,i={padding:`0.5rem`,backgroundColor:r},a={padding:`2px 4px`,backgroundColor:r},o=null;return console.error(`Error handled by React Router default ErrorBoundary:`,e),o=S.createElement(S.Fragment,null,S.createElement(`p`,null,`💿 Hey developer 👋`),S.createElement(`p`,null,`You can provide a way better UX than this when your app throws errors by providing your own `,S.createElement(`code`,{style:a},`ErrorBoundary`),` or`,` `,S.createElement(`code`,{style:a},`errorElement`),` prop on your route.`)),S.createElement(S.Fragment,null,S.createElement(`h2`,null,`Unexpected Application Error!`),S.createElement(`h3`,{style:{fontStyle:`italic`}},t),n?S.createElement(`pre`,{style:i},n):null,o)}var xt=S.createElement(bt,null),St=class extends S.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!==`idle`&&e.revalidation===`idle`?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error===void 0?t.error:e.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error(`React Router caught the following error during render`,e)}render(){let e=this.state.error;if(this.context&&typeof e==`object`&&e&&`digest`in e&&typeof e.digest==`string`){let t=ct(e.digest);t&&(e=t)}let t=e===void 0?this.props.children:S.createElement(nt.Provider,{value:this.props.routeContext},S.createElement(rt.Provider,{value:e,children:this.props.component}));return this.context?S.createElement(wt,{error:e},t):t}};St.contextType=Ye;var Ct=new WeakMap;function wt({children:e,error:t}){let{basename:n}=S.useContext(et);if(typeof t==`object`&&t&&`digest`in t&&typeof t.digest==`string`){let e=st(t.digest);if(e){let r=Ct.get(t);if(r)throw r;let i=He(e.location,n),a=i.absoluteURL||i.to;if(Ke(a))throw Error(`Invalid redirect location`);if(Ve&&!Ct.get(t))if(i.isExternal||e.reloadDocument)window.location.href=a;else{let n=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(i.to,{replace:e.replace}));throw Ct.set(t,n),n}return S.createElement(`meta`,{httpEquiv:`refresh`,content:`0;url=${a}`})}}return e}function Tt({routeContext:e,match:t,children:n}){let r=S.useContext(qe);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),S.createElement(nt.Provider,{value:e},n)}function Et(e,t=[],n){let r=n?.state;if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let i=e,a=r?.errors;if(a!=null){let e=i.findIndex(e=>e.route.id&&a?.[e.route.id]!==void 0);E(e>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(a).join(`,`)}`),i=i.slice(0,Math.min(i.length,e+1))}let o=!1,s=-1;if(n&&r){o=r.renderFallback;for(let e=0;e=0?i.slice(0,s+1):[i[0]];break}}}}let c=n?.onError,l=r&&c?(e,t)=>{c(e,{location:r.location,params:r.matches?.[0]?.params??{},pattern:Be(r.matches),errorInfo:t})}:void 0;return i.reduceRight((e,n,c)=>{let u,d=!1,f=null,p=null;r&&(u=a&&n.route.id?a[n.route.id]:void 0,f=n.route.errorElement||xt,o&&(s<0&&c===0?(Rt(`route-fallback`,!1,"No `HydrateFallback` element provided to render during initial hydration"),d=!0,p=null):s===c&&(d=!0,p=n.route.hydrateFallbackElement||null)));let m=t.concat(i.slice(0,c+1)),h=()=>{let t;return t=u?f:d?p:n.route.Component?S.createElement(n.route.Component,null):n.route.element?n.route.element:e,S.createElement(Tt,{match:n,routeContext:{outlet:e,matches:m,isDataRoute:r!=null},children:t})};return r&&(n.route.ErrorBoundary||n.route.errorElement||c===0)?S.createElement(St,{location:r.location,revalidation:r.revalidation,component:f,error:u,children:h(),routeContext:{outlet:null,matches:m,isDataRoute:!0},onError:l}):h()},null)}function Dt(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Ot(e){let t=S.useContext(qe);return E(t,Dt(e)),t}function kt(e){let t=S.useContext(Je);return E(t,Dt(e)),t}function At(e){let t=S.useContext(nt);return E(t,Dt(e)),t}function jt(e){let t=At(e),n=t.matches[t.matches.length-1];return E(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function Mt(){return jt(`useRouteId`)}function Nt(){let e=kt(`useNavigation`);return S.useMemo(()=>{let{matches:t,historyAction:n,...r}=e.navigation;return r},[e.navigation])}function Pt(){let{matches:e,loaderData:t}=kt(`useMatches`);return S.useMemo(()=>e.map(e=>le(e,t)),[e,t])}function Ft(){let e=S.useContext(rt),t=kt(`useRouteError`),n=jt(`useRouteError`);return e===void 0?t.errors?.[n]:e}function It(){let{router:e}=Ot(`useNavigate`),t=jt(`useNavigate`),n=S.useRef(!1);return ft(()=>{n.current=!0}),S.useCallback(async(r,i={})=>{D(n.current,dt),n.current&&(typeof r==`number`?await e.navigate(r):await e.navigate(r,{fromRouteId:t,...i}))},[e,t])}var Lt={};function Rt(e,t,n){!t&&!Lt[e]&&(Lt[e]=!0,D(!1,n))}S.memo(zt);function zt({routes:e,manifest:t,future:n,state:r,isStatic:i,onError:a}){return yt(e,void 0,{manifest:t,state:r,isStatic:i,onError:a,future:n})}function Bt({to:e,replace:t,state:n,relative:r}){E(ut(),` may be used only in the context of a component.`);let{static:i}=S.useContext(et);D(!i,` must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.`);let{matches:a}=S.useContext(nt),{pathname:o}=P(),s=pt(),c=je(e,Ae(a),o,r===`path`),l=JSON.stringify(c);return S.useEffect(()=>{s(JSON.parse(l),{replace:t,state:n,relative:r})},[s,l,r,t,n]),null}function Vt(e){return gt(e.context)}function Ht(e){E(!1,`A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .`)}function Ut({basename:e=`/`,children:t=null,location:n,navigationType:r=`POP`,navigator:i,static:a=!1,useTransitions:o}){E(!ut(),`You cannot render a inside another . You should never have more than one in your app.`);let s=e.replace(/^\/*/,`/`),c=S.useMemo(()=>({basename:s,navigator:i,static:a,useTransitions:o,future:{}}),[s,i,a,o]);typeof n==`string`&&(n=oe(n));let{pathname:l=`/`,search:u=``,hash:d=``,state:f=null,key:p=`default`,mask:m}=n,h=S.useMemo(()=>{let e=Te(l,s);return e==null?null:{location:{pathname:e,search:u,hash:d,state:f,key:p,mask:m},navigationType:r}},[s,l,u,d,f,p,r,m]);return D(h!=null,` is not able to match the URL "${l}${u}${d}" because it does not start with the basename, so the won't render anything.`),h==null?null:S.createElement(et.Provider,{value:c},S.createElement(tt.Provider,{children:t,value:h}))}function Wt({children:e,location:t}){return vt(Gt(e),t)}S.Component;function Gt(e,t=[]){let n=[];return S.Children.forEach(e,(e,r)=>{if(!S.isValidElement(e))return;let i=[...t,r];if(e.type===S.Fragment){n.push.apply(n,Gt(e.props.children,i));return}E(e.type===Ht,`[${typeof e.type==`string`?e.type:e.type.name}] is not a component. All component children of must be a or `),E(!e.props.index||!e.props.children,`An index route cannot have child routes.`);let a={id:e.props.id||i.join(`-`),caseSensitive:e.props.caseSensitive,element:e.props.element,Component:e.props.Component,index:e.props.index,path:e.props.path,middleware:e.props.middleware,loader:e.props.loader,action:e.props.action,hydrateFallbackElement:e.props.hydrateFallbackElement,HydrateFallback:e.props.HydrateFallback,errorElement:e.props.errorElement,ErrorBoundary:e.props.ErrorBoundary,hasErrorBoundary:e.props.hasErrorBoundary===!0||e.props.ErrorBoundary!=null||e.props.errorElement!=null,shouldRevalidate:e.props.shouldRevalidate,handle:e.props.handle,lazy:e.props.lazy};e.props.children&&(a.children=Gt(e.props.children,i)),n.push(a)}),n}var Kt=`get`,qt=`application/x-www-form-urlencoded`;function Jt(e){return typeof HTMLElement<`u`&&e instanceof HTMLElement}function Yt(e){return Jt(e)&&e.tagName.toLowerCase()===`button`}function Xt(e){return Jt(e)&&e.tagName.toLowerCase()===`form`}function Zt(e){return Jt(e)&&e.tagName.toLowerCase()===`input`}function Qt(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function $t(e,t){return e.button===0&&(!t||t===`_self`)&&!Qt(e)}var en=null;function tn(){if(en===null)try{new FormData(document.createElement(`form`),0),en=!1}catch{en=!0}return en}var nn=new Set([`application/x-www-form-urlencoded`,`multipart/form-data`,`text/plain`]);function rn(e){return e!=null&&!nn.has(e)?(D(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${qt}"`),null):e}function an(e,t){let n,r,i,a,o;if(Xt(e)){let o=e.getAttribute(`action`);r=o?Te(o,t):null,n=e.getAttribute(`method`)||Kt,i=rn(e.getAttribute(`enctype`))||qt,a=new FormData(e)}else if(Yt(e)||Zt(e)&&(e.type===`submit`||e.type===`image`)){let o=e.form;if(o==null)throw Error(`Cannot submit a diff --git a/pets-fe/pages/article/article.wxss b/pets-fe/pages/article/article.wxss index 8453d68..ff5f6af 100644 --- a/pets-fe/pages/article/article.wxss +++ b/pets-fe/pages/article/article.wxss @@ -1,13 +1,15 @@ -.hint{padding:60rpx 0;text-align:center;color:var(--muted);font-size:28rpx} - -.art-head{padding:12rpx 0 28rpx} -.art-icon{font-size:72rpx;line-height:1;margin-bottom:16rpx} -.art-title{font-size:44rpx;font-weight:800;line-height:1.35;letter-spacing:-.5rpx} -.art-desc{margin-top:14rpx;color:var(--muted);font-size:27rpx;line-height:1.6} +.art-head{padding:var(--sp-2) 0 var(--sp-4)} +.art-icon{ + width:96rpx;height:96rpx;border-radius:var(--r-md);margin-bottom:var(--sp-3); + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink); +} +.art-title{font-size:var(--fs-2xl);font-weight:var(--fw-b);line-height:1.35;letter-spacing:-.5rpx} +.art-desc{margin-top:var(--sp-2);color:var(--muted);font-size:var(--fs-md);line-height:1.6} .art-content{ - font-size:29rpx;line-height:1.85;color:#3D352E; + font-size:var(--fs-md);line-height:1.85;color:var(--text-2); white-space:pre-line; /* 正文用真实换行排版 */ } -.art-foot{margin-top:28rpx;text-align:center;color:var(--muted);font-size:23rpx} +.art-foot{margin-top:var(--sp-4);text-align:center;color:var(--muted);font-size:var(--fs-cap)} diff --git a/pets-fe/pages/community/community.js b/pets-fe/pages/community/community.js index 537345f..65bc7b9 100644 --- a/pets-fe/pages/community/community.js +++ b/pets-fe/pages/community/community.js @@ -67,8 +67,9 @@ Page({ toastErr(e); }); }, + // 来自 seg-tabs 的 change 事件 switchFeedTab(e) { - this.setData({ feedIdx: e.currentTarget.dataset.index }); + this.setData({ feedIdx: Number(e.detail.index) }); this.loadPosts(); }, likePost(e) { diff --git a/pets-fe/pages/community/community.json b/pets-fe/pages/community/community.json index 24ea6ea..7f17b0c 100644 --- a/pets-fe/pages/community/community.json +++ b/pets-fe/pages/community/community.json @@ -2,6 +2,8 @@ "usingComponents": { "nav-bar": "/components/nav-bar/nav-bar", "bottom-sheet": "/components/bottom-sheet/bottom-sheet", - "fab": "/components/fab/fab" + "fab": "/components/fab/fab", + "pt-icon": "/components/pt-icon/index", + "seg-tabs": "/components/seg-tabs/index" } } diff --git a/pets-fe/pages/community/community.wxml b/pets-fe/pages/community/community.wxml index 06c4830..33d219a 100644 --- a/pets-fe/pages/community/community.wxml +++ b/pets-fe/pages/community/community.wxml @@ -5,18 +5,10 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } - - 宠友圈 - 和宠友交流、晒宠、求助与经验分享。 - - - - {{item}} - + - + @@ -35,17 +27,17 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } - {{item.liked ? '♥' : '♡'}} {{item.like_count}} - 💬 {{item.comment_count}} - + {{item.like_count}} + {{item.comment_count}} + - + {{loadErr}} 点击重试 - + {{feedTabs[feedIdx] === '关注' ? '还没有关注的人,去「推荐」里关注几个宠友吧 🐾' : '还没有帖子,来发第一条吧 🐾'}} diff --git a/pets-fe/pages/community/community.wxss b/pets-fe/pages/community/community.wxss index 936feb7..69d0834 100644 --- a/pets-fe/pages/community/community.wxss +++ b/pets-fe/pages/community/community.wxss @@ -1,50 +1,44 @@ -.feed-tabs{white-space:nowrap;padding:0 0 24rpx} -.feed-tab{ - display:inline-block;border:1rpx solid var(--line);background:#fff;border-radius:999rpx; - height:68rpx;line-height:68rpx;padding:0 26rpx;color:var(--muted);font-size:26rpx;font-weight:900; - box-shadow:0 12rpx 32rpx rgba(70,48,25,.05);margin-right:16rpx; -} -.feed-tab.active{color:var(--primary-dark);background:#FFF4E4;border-color:#FFD39A} +.compose-card{margin-bottom:var(--sp-4)} -.compose-card{margin-bottom:28rpx} - -.post-card{background:#fff;border-radius:48rpx;box-shadow:var(--shadow);padding:30rpx;margin-bottom:28rpx} -.post-head{display:flex;align-items:center;gap:20rpx;margin-bottom:22rpx} +.post-card{background:#fff;border-radius:var(--r-lg);box-shadow:var(--sd-1);padding:var(--sp-4);margin-bottom:var(--sp-4)} +.post-head{display:flex;align-items:center;gap:var(--sp-3);margin-bottom:var(--sp-3)} .post-avatar{ - width:84rpx;height:84rpx;border-radius:32rpx;background:#FFF0D8; - display:flex;align-items:center;justify-content:center;font-size:44rpx;flex:none; + width:80rpx;height:80rpx;border-radius:var(--r-sm);background:var(--primary-soft); + display:flex;align-items:center;justify-content:center;font-size:40rpx;flex:none; } -.post-user{flex:1} -.pu-b{font-size:28rpx;display:block;font-weight:700} -.ai-tag{display:inline-block;margin-left:10rpx;padding:0 10rpx;border-radius:8rpx;background:#EAF0FF;color:#3B6BE5;font-size:20rpx;font-weight:700;vertical-align:1rpx} -.pu-s{font-size:24rpx;color:var(--muted)} -.post-content{font-size:28rpx;line-height:1.62;color:#443D37;margin-bottom:24rpx} +.post-user{flex:1;min-width:0} +.pu-b{font-size:var(--fs-md);display:block;font-weight:var(--fw-b)} +.ai-tag{ + display:inline-block;margin-left:var(--sp-1);padding:0 var(--sp-1);border-radius:var(--r-xs); + background:var(--blue-soft);color:var(--blue-ink);font-size:var(--fs-cap);font-weight:var(--fw-b);vertical-align:1rpx; +} +.pu-s{font-size:var(--fs-sm);color:var(--muted)} +.post-content{font-size:var(--fs-md);line-height:1.62;color:var(--text-2);margin-bottom:var(--sp-3)} -.photo-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12rpx;margin-bottom:24rpx} +.photo-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-1);margin-bottom:var(--sp-3)} .photo-tile{ - aspect-ratio:1;border-radius:32rpx;background:linear-gradient(135deg,#FFE6BA,#FFF8ED); - display:flex;align-items:center;justify-content:center;font-size:60rpx; + aspect-ratio:1;border-radius:var(--r-sm);background:var(--primary-soft); + display:flex;align-items:center;justify-content:center;font-size:56rpx; } -.post-actions{display:flex;justify-content:space-around;border-top:1rpx solid var(--line);padding-top:20rpx} -.pa-btn{color:var(--muted);font-weight:900;font-size:26rpx} -.pa-btn.liked{color:var(--red)} - -.empty-hint{text-align:center;color:var(--muted);font-size:26rpx;padding:80rpx 0} - -/* 页面不自身滚动,改由 page-scroll 承载滚动(隐藏滚动条)*/ - -/* 帖子分享按钮:用微信原生 open-type=share,需抹掉 button 默认外观 */ -.pa-share{ - background:transparent;border:none;padding:0;margin:0;line-height:inherit; - font-size:26rpx;font-weight:900;color:var(--muted); +.post-actions{display:flex;justify-content:space-around;border-top:1rpx solid var(--line);padding-top:var(--sp-3)} +.pa-btn{ + display:flex;align-items:center;gap:var(--sp-1); + color:var(--muted);font-weight:var(--fw-b);font-size:var(--fs-sm); } +.pa-btn.liked{color:var(--red-ink)} +/* 分享用微信原生 open-type=share,得抹掉 button 默认外观 */ +.pa-share{background:transparent;border:none;padding:0;margin:0;line-height:inherit;height:auto} .pa-share::after{border:none} /* 关注按钮 */ .follow-btn{ - flex:none;font-size:22rpx;font-weight:700;padding:6rpx 18rpx;border-radius:999rpx; - color:var(--primary-dark);background:#FFF2DC;border:1rpx solid #FFD39A; + flex:none;font-size:var(--fs-cap);font-weight:var(--fw-b);padding:6rpx var(--sp-3);border-radius:var(--r-full); + color:var(--primary-dark);background:var(--primary-soft);border:1rpx solid var(--primary-line); } .follow-btn.on{color:var(--muted);background:#F4F1EC;border-color:var(--line)} -.retry-btn{margin-top:20rpx;display:inline-block;padding:12rpx 36rpx;border-radius:999rpx;background:#FFF2DC;color:var(--primary-dark);font-weight:700;font-size:26rpx} + +.retry-btn{ + margin-top:var(--sp-3);display:inline-block;padding:var(--sp-2) var(--sp-6);border-radius:var(--r-full); + background:var(--primary-soft);color:var(--primary-dark);font-weight:var(--fw-b);font-size:var(--fs-sm); +} diff --git a/pets-fe/pages/home/home.wxss b/pets-fe/pages/home/home.wxss index e925d76..5b5102b 100644 --- a/pets-fe/pages/home/home.wxss +++ b/pets-fe/pages/home/home.wxss @@ -37,13 +37,5 @@ .day.sel{border-color:var(--primary);background:var(--primary-soft);color:var(--primary-dark);box-shadow:0 0 0 2rpx rgba(245,169,71,.35)} .day.has-dot::after{content:"";display:block;width:8rpx;height:8rpx;border-radius:50%;background:var(--green);margin:6rpx auto 0} -/* 快速记录:靠颜色分类,不靠 emoji */ -.quick-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-2)} -.quick{ - border-radius:var(--r-md);min-height:128rpx; - display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-1); - font-weight:var(--fw-b);font-size:var(--fs-sm); -} - .ai-text{color:var(--text-2);font-size:var(--fs-md);line-height:1.6} .ai-cta{margin-top:var(--sp-4)} diff --git a/pets-fe/pages/learn/learn.json b/pets-fe/pages/learn/learn.json index 24ea6ea..fa34741 100644 --- a/pets-fe/pages/learn/learn.json +++ b/pets-fe/pages/learn/learn.json @@ -2,6 +2,7 @@ "usingComponents": { "nav-bar": "/components/nav-bar/nav-bar", "bottom-sheet": "/components/bottom-sheet/bottom-sheet", - "fab": "/components/fab/fab" + "fab": "/components/fab/fab", + "pt-icon": "/components/pt-icon/index" } } diff --git a/pets-fe/pages/learn/learn.wxml b/pets-fe/pages/learn/learn.wxml index bd4c476..a4e3dff 100644 --- a/pets-fe/pages/learn/learn.wxml +++ b/pets-fe/pages/learn/learn.wxml @@ -3,12 +3,12 @@ - 新手养宠知识 - 新手养宠知识,看完顺手生成你的计划。 + 看完顺手生成你的计划。 + 还没有文章 - {{item.icon}} + {{item.title}}{{item.desc}} diff --git a/pets-fe/pages/onboarding/onboarding.json b/pets-fe/pages/onboarding/onboarding.json index c55f727..c58f7d1 100644 --- a/pets-fe/pages/onboarding/onboarding.json +++ b/pets-fe/pages/onboarding/onboarding.json @@ -1,6 +1,7 @@ { "usingComponents": { - "nav-bar": "/components/nav-bar/nav-bar" + "nav-bar": "/components/nav-bar/nav-bar", + "pt-icon": "/components/pt-icon/index" }, "navigationBarTitleText": "肉垫计划" } diff --git a/pets-fe/pages/onboarding/onboarding.wxml b/pets-fe/pages/onboarding/onboarding.wxml index 35777f8..a95f79f 100644 --- a/pets-fe/pages/onboarding/onboarding.wxml +++ b/pets-fe/pages/onboarding/onboarding.wxml @@ -5,7 +5,7 @@ - + 肉垫计划 新手养宠的 AI 日历、健康记录和成长报告。先生成计划,再每天照着做。 @@ -24,10 +24,10 @@ 目前支持猫和狗,选一个开始。 - 🐱猫猫幼猫、成年猫、老年猫 + 猫猫幼猫、成年猫、老年猫 - 🐶狗狗幼犬、成年犬、老年犬 + 狗狗幼犬、成年犬、老年犬 @@ -78,7 +78,7 @@ 多选,我们会据此为你定制计划。 - {{item.on ? '✓' : ''}}{{item.label}} + {{item.label}} @@ -89,11 +89,11 @@ 正在生成专属养宠计划 正在根据它的信息生成专属计划… - 已识别:{{stage}} - 已生成:30 天新手计划 - 已安排:疫苗 / 驱虫提醒 - 已开启:体重、便便、饮食记录 - 已准备:首张成长报告卡片 + 已识别:{{stage}} + 已生成:30 天新手计划 + 已安排:疫苗 / 驱虫提醒 + 已开启:体重、便便、饮食记录 + 已准备:首张成长报告卡片 diff --git a/pets-fe/pages/onboarding/onboarding.wxss b/pets-fe/pages/onboarding/onboarding.wxss index 3655ad6..69f5419 100644 --- a/pets-fe/pages/onboarding/onboarding.wxss +++ b/pets-fe/pages/onboarding/onboarding.wxss @@ -1,53 +1,59 @@ .onboard-page{ - padding:0 40rpx 56rpx; + padding:0 var(--pad-x) 56rpx; min-height:100%; background: radial-gradient(circle at top right, rgba(245,169,71,.22), transparent 45%), var(--bg); } .step{animation:fade .24s ease} -.skip-link{text-align:center;margin-top:28rpx;color:var(--muted);font-size:28rpx;padding:12rpx} +.skip-link{text-align:center;margin-top:var(--sp-4);color:var(--muted);font-size:var(--fs-md);padding:var(--sp-2)} @keyframes fade{from{opacity:0;transform:translateY(16rpx)}to{opacity:1;transform:none}} -.hero{text-align:center;padding:60rpx 0 32rpx} +.hero{text-align:center;padding:60rpx 0 var(--sp-5)} .pet-logo{ - width:192rpx;height:192rpx;margin:0 auto 36rpx;border-radius:60rpx; + width:176rpx;height:176rpx;margin:0 auto var(--sp-5);border-radius:var(--r-lg); background:linear-gradient(135deg,#FFE0AB,#FDB35C); - display:flex;align-items:center;justify-content:center;font-size:96rpx; - box-shadow:0 32rpx 72rpx rgba(245,169,71,.26); + display:flex;align-items:center;justify-content:center;font-size:88rpx; + box-shadow:var(--sd-2); } -.hero-h1{font-size:64rpx;letter-spacing:-1.2rpx;font-weight:800} -.hero-sub{margin-top:20rpx;line-height:1.65;color:var(--muted);font-size:30rpx} +.hero-h1{font-size:var(--fs-2xl);letter-spacing:-1.2rpx;font-weight:var(--fw-b)} +.hero-sub{margin-top:var(--sp-3);line-height:1.65;color:var(--muted);font-size:var(--fs-md)} -.proof-row{display:grid;grid-template-columns:repeat(3,1fr);gap:16rpx;margin:40rpx 0} -.proof{background:#fff;border-radius:36rpx;padding:24rpx 16rpx;text-align:center;box-shadow:var(--shadow)} -.proof-b{display:block;font-size:32rpx;font-weight:800} -.proof-s{color:var(--muted);font-size:22rpx} +.proof-row{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-3);margin:var(--sp-6) 0} +.proof{background:#fff;border-radius:var(--r-md);padding:var(--sp-4) var(--sp-3);text-align:center;box-shadow:var(--sd-1)} +.proof-b{display:block;font-size:var(--fs-lg);font-weight:var(--fw-b)} +.proof-s{color:var(--muted);font-size:var(--fs-cap)} -.step-title{font-size:48rpx;letter-spacing:-.8rpx;line-height:1.24;margin:16rpx 0;font-weight:800} -.step-sub{color:var(--muted);line-height:1.6;font-size:28rpx;margin-bottom:32rpx} +.step-title{font-size:var(--fs-2xl);letter-spacing:-.8rpx;line-height:1.24;margin:var(--sp-3) 0;font-weight:var(--fw-b)} +.step-sub{color:var(--muted);line-height:1.6;font-size:var(--fs-md);margin-bottom:var(--sp-5)} -.choice-grid{display:grid;grid-template-columns:1fr 1fr;gap:24rpx;margin-bottom:36rpx} +.choice-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-4);margin-bottom:var(--sp-5)} .choice-card{ - background:#fff;border:4rpx solid transparent;border-radius:48rpx;min-height:264rpx; - padding:36rpx 28rpx;box-shadow:var(--shadow);transition:.18s ease; + background:#fff;border:4rpx solid transparent;border-radius:var(--r-lg);min-height:248rpx; + padding:var(--sp-5) var(--sp-4);box-shadow:var(--sd-1);transition:.18s ease; + display:flex;flex-direction:column;align-items:flex-start; } -.choice-card.selected{border-color:var(--primary);background:#FFF8EC} -.choice-card .animal{font-size:88rpx;margin-bottom:20rpx} -.choice-b{font-size:34rpx;font-weight:900} -.choice-s{display:block;color:var(--muted);font-size:24rpx;margin-top:12rpx} +.choice-card.selected{border-color:var(--primary);background:var(--primary-soft)} +.choice-card .animal{ + width:96rpx;height:96rpx;border-radius:var(--r-md);margin-bottom:var(--sp-3); + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink); +} +.choice-card.selected .animal{background:#fff} +.choice-b{font-size:var(--fs-lg);font-weight:var(--fw-b)} +.choice-s{display:block;color:var(--muted);font-size:var(--fs-sm);margin-top:var(--sp-2)} -.form-card{background:#fff;border-radius:48rpx;padding:32rpx;box-shadow:var(--shadow);margin-bottom:36rpx} +.form-card{background:#fff;border-radius:var(--r-lg);padding:var(--sp-5);box-shadow:var(--sd-1);margin-bottom:var(--sp-5)} -.stage-list{display:flex;flex-direction:column;gap:22rpx;margin-bottom:36rpx} -.stage-card{background:#fff;border-radius:40rpx;border:4rpx solid transparent;padding:30rpx;box-shadow:var(--shadow)} +.stage-list{display:flex;flex-direction:column;gap:var(--sp-3);margin-bottom:var(--sp-5)} +.stage-card{background:#fff;border-radius:var(--r-md);border:4rpx solid transparent;padding:var(--sp-4);box-shadow:var(--sd-1)} .stage-card.selected{border-color:var(--green);background:var(--green-soft)} -.stage-b{font-size:32rpx;font-weight:900} -.stage-p{color:var(--muted);font-size:24rpx;margin-top:10rpx} +.stage-b{font-size:var(--fs-lg);font-weight:var(--fw-b)} +.stage-p{color:var(--muted);font-size:var(--fs-sm);margin-top:var(--sp-1)} -.gen-card{margin-top:32rpx;background:#fff;border-radius:56rpx;padding:48rpx;box-shadow:var(--shadow2)} -.gen-line{display:flex;align-items:center;gap:20rpx;padding:20rpx 0;color:#5F554D;font-size:28rpx} +.gen-card{margin-top:var(--sp-5);background:#fff;border-radius:var(--r-lg);padding:var(--sp-6);box-shadow:var(--sd-2)} +.gen-line{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) 0;color:var(--text-2);font-size:var(--fs-md)} .tick{ - width:48rpx;height:48rpx;border-radius:50%;background:var(--green);color:#fff; - display:flex;align-items:center;justify-content:center;font-size:28rpx;font-weight:900;flex:none; + width:44rpx;height:44rpx;border-radius:50%;background:var(--green);color:#fff; + display:flex;align-items:center;justify-content:center;flex:none; } diff --git a/pets-fe/pages/plan/plan.js b/pets-fe/pages/plan/plan.js index f92a611..111159b 100644 --- a/pets-fe/pages/plan/plan.js +++ b/pets-fe/pages/plan/plan.js @@ -31,6 +31,11 @@ Page({ data: { pet: {}, planView: 'timeline', + planTabs: [ + { key: 'timeline', label: '路线图' }, + { key: 'calendar', label: '日历' }, + { key: 'aiPlan', label: 'AI 计划' }, + ], plan: null, calCells: [], calLabel: '', @@ -117,8 +122,9 @@ Page({ }) .catch(() => {}); }, + // 来自 seg-tabs 的 change 事件,key 即 planView switchPlanView(e) { - const view = e.currentTarget.dataset.view; + const view = e.detail.key; this.setData({ planView: view }); if (view === 'calendar' && !this.data.calLoaded) this.loadCalendar(); }, diff --git a/pets-fe/pages/plan/plan.json b/pets-fe/pages/plan/plan.json index 075a8b2..58b7029 100644 --- a/pets-fe/pages/plan/plan.json +++ b/pets-fe/pages/plan/plan.json @@ -3,6 +3,8 @@ "nav-bar": "/components/nav-bar/nav-bar", "pet-switch": "/components/pet-switch/pet-switch", "bottom-sheet": "/components/bottom-sheet/bottom-sheet", - "fab": "/components/fab/fab" + "fab": "/components/fab/fab", + "pt-icon": "/components/pt-icon/index", + "seg-tabs": "/components/seg-tabs/index" } } diff --git a/pets-fe/pages/plan/plan.wxml b/pets-fe/pages/plan/plan.wxml index 001a365..edcc95f 100644 --- a/pets-fe/pages/plan/plan.wxml +++ b/pets-fe/pages/plan/plan.wxml @@ -2,18 +2,9 @@ - - 养宠计划 - 按宠物查看路线图、日历与 AI 计划。 - - - - 路线图 - 日历 - AI 计划 - + @@ -29,13 +20,13 @@ {{item.day_label}}{{item.dateLabel}} - {{item.done ? '✓' : ''}} + {{item.title}}{{item.description}} - 暂无计划 + 暂无计划 @@ -64,7 +55,7 @@ 提醒{{item.title}} - 这天没有安排 + 这天没有安排 diff --git a/pets-fe/pages/plan/plan.wxss b/pets-fe/pages/plan/plan.wxss index a865891..179cd70 100644 --- a/pets-fe/pages/plan/plan.wxss +++ b/pets-fe/pages/plan/plan.wxss @@ -1,58 +1,55 @@ -.inline-tabs{display:flex;padding:8rpx;gap:8rpx;border-radius:32rpx;background:#EFE8DE;margin-bottom:28rpx} -.it-btn{ - flex:1;height:68rpx;line-height:68rpx;text-align:center;border-radius:24rpx; - color:var(--muted);font-weight:900;font-size:26rpx; -} -.it-btn.active{background:#fff;color:var(--primary-dark);box-shadow:0 12rpx 28rpx rgba(0,0,0,.06)} - -.timeline{padding-left:36rpx;position:relative} +/* 竖线时间轴 */ +.timeline{padding-left:var(--sp-6);position:relative} .timeline::before{content:"";position:absolute;left:12rpx;top:12rpx;bottom:16rpx;width:4rpx;background:#E8DED0} -.time-block{position:relative;margin-bottom:28rpx} -.time-label{font-weight:900;color:var(--primary-dark);font-size:26rpx;margin-bottom:16rpx;position:relative} -.time-date{margin-left:12rpx;font-weight:600;color:var(--muted);font-size:22rpx} +.time-block{position:relative;margin-bottom:var(--sp-4)} +.time-label{font-weight:var(--fw-b);color:var(--primary-dark);font-size:var(--fs-sm);margin-bottom:var(--sp-3);position:relative} +.time-date{margin-left:var(--sp-2);font-weight:var(--fw);color:var(--muted);font-size:var(--fs-cap)} .time-label::before{ content:"";position:absolute;left:-34rpx;top:8rpx;width:24rpx;height:24rpx;border-radius:50%; - background:var(--primary);border:6rpx solid #fff;box-shadow:0 0 0 4rpx #F5D5A8; + background:var(--primary);border:6rpx solid #fff;box-shadow:0 0 0 4rpx var(--primary-line); +} +.plan-task{ + background:#fff;border-radius:var(--r-md);padding:var(--sp-4);box-shadow:var(--sd-1); + border:1rpx solid transparent;display:flex;gap:var(--sp-3);align-items:flex-start; } -.plan-task{background:#fff;border-radius:36rpx;padding:26rpx;box-shadow:var(--shadow);border:1rpx solid transparent;display:flex;gap:18rpx;align-items:flex-start} .plan-task.done{opacity:.55} .pk-check{ width:44rpx;height:44rpx;border-radius:50%;border:4rpx solid #DED1C4;flex:none;margin-top:2rpx; - display:flex;align-items:center;justify-content:center;color:#fff;font-size:24rpx;font-weight:900; + display:flex;align-items:center;justify-content:center;color:#fff; } .plan-task.done .pk-check{background:var(--green);border-color:var(--green)} .pk-body{flex:1} -.pk-b{font-size:28rpx;font-weight:700} -.pk-p{color:var(--muted);font-size:24rpx;line-height:1.45;margin-top:10rpx} -.ai-plan-tip{color:var(--muted);font-size:26rpx;line-height:1.6;margin-bottom:16rpx} +.pk-b{font-size:var(--fs-md);font-weight:var(--fw-b)} +.pk-p{color:var(--muted);font-size:var(--fs-sm);line-height:1.45;margin-top:var(--sp-1)} +.ai-plan-tip{color:var(--muted);font-size:var(--fs-sm);line-height:1.6;margin-bottom:var(--sp-3)} -.calendar{background:#fff;border-radius:44rpx;padding:28rpx;box-shadow:var(--shadow)} -.cal-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:20rpx;font-weight:900;font-size:30rpx} -.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:12rpx;text-align:center} -.cal-w{font-size:22rpx;color:var(--muted);padding:8rpx 0} +/* 日历 */ +.calendar{background:#fff;border-radius:var(--r-lg);padding:var(--sp-4);box-shadow:var(--sd-1)} +.cal-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--sp-3);font-weight:var(--fw-b);font-size:var(--fs-lg)} +.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--sp-2);text-align:center} +.cal-w{font-size:var(--fs-cap);color:var(--muted);padding:var(--sp-1) 0} .cal-cell{ - height:76rpx;border-radius:24rpx;display:flex;align-items:center;justify-content:center; - font-weight:800;font-size:26rpx;background:#FBFAF8;position:relative; + height:76rpx;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center; + font-weight:var(--fw-b);font-size:var(--fs-sm);background:var(--surface-2);position:relative; } .cal-cell.blank{background:transparent} -.cal-cell.today{background:#FFF3DF;color:var(--primary-dark)} -.cal-cell.tasked::after{content:"";position:absolute;bottom:10rpx;width:10rpx;height:10rpx;border-radius:50%;background:var(--green)} +.cal-cell.today{background:var(--primary-soft);color:var(--primary-dark)} +.cal-cell.tasked::after{content:"";position:absolute;bottom:8rpx;width:8rpx;height:8rpx;border-radius:50%;background:var(--green)} .cal-cell.sel{background:var(--primary);color:#fff} .cal-cell.sel.tasked::after{background:#fff} -.day-detail{margin-top:24rpx;border-top:1rpx solid var(--line);padding-top:24rpx} -.dd-title{font-weight:900;font-size:28rpx;margin-bottom:16rpx} -.dd-item{display:flex;align-items:center;gap:16rpx;padding:14rpx 0} -.dd-tag{flex:none;font-size:20rpx;font-weight:700;padding:2rpx 12rpx;border-radius:999rpx} -.dd-tag.plan{background:#FFF2DC;color:var(--primary-dark)} -.dd-tag.task{background:#E6F4EA;color:#2E7D5B} -.dd-tag.rem{background:#EAF0FF;color:#3B6BE5} -.dd-b{font-size:27rpx;color:var(--text)} +/* 某天的安排 */ +.day-detail{margin-top:var(--sp-4);border-top:1rpx solid var(--line);padding-top:var(--sp-4)} +.dd-title{font-weight:var(--fw-b);font-size:var(--fs-md);margin-bottom:var(--sp-3)} +.dd-item{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-2) 0} +.dd-tag{flex:none;font-size:var(--fs-cap);font-weight:var(--fw-b);padding:2rpx var(--sp-2);border-radius:var(--r-full)} +.dd-tag.plan{background:var(--primary-soft);color:var(--primary-ink)} +.dd-tag.task{background:var(--green-soft);color:var(--green-ink)} +.dd-tag.rem{background:var(--blue-soft);color:var(--blue-ink)} +.dd-b{font-size:var(--fs-md);color:var(--text)} .dd-b.done{text-decoration:line-through;color:var(--muted)} -.dd-empty{padding:20rpx 0;color:var(--muted);font-size:26rpx;text-align:center} -.extracted{display:grid;grid-template-columns:1fr 1fr;gap:16rpx;margin:24rpx 0} -.extract{background:#FBFAF8;border-radius:30rpx;padding:20rpx;font-size:24rpx} -.ex-b{display:block;font-size:26rpx;margin-bottom:6rpx;font-weight:700} - -/* 页面不自身滚动,改由 page-scroll 承载滚动(隐藏滚动条)*/ +/* AI 提取信息 */ +.extracted{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3);margin:var(--sp-4) 0} +.extract{background:var(--surface-2);border-radius:var(--r-sm);padding:var(--sp-3);font-size:var(--fs-sm)} +.ex-b{display:block;font-size:var(--fs-sm);margin-bottom:6rpx;font-weight:var(--fw-b);color:var(--muted)} diff --git a/pets-fe/pages/profile/profile.json b/pets-fe/pages/profile/profile.json index 24ea6ea..fa34741 100644 --- a/pets-fe/pages/profile/profile.json +++ b/pets-fe/pages/profile/profile.json @@ -2,6 +2,7 @@ "usingComponents": { "nav-bar": "/components/nav-bar/nav-bar", "bottom-sheet": "/components/bottom-sheet/bottom-sheet", - "fab": "/components/fab/fab" + "fab": "/components/fab/fab", + "pt-icon": "/components/pt-icon/index" } } diff --git a/pets-fe/pages/profile/profile.wxml b/pets-fe/pages/profile/profile.wxml index cbdde59..881e725 100644 --- a/pets-fe/pages/profile/profile.wxml +++ b/pets-fe/pages/profile/profile.wxml @@ -6,27 +6,27 @@ {{pet.emoji}} - 📷 + {{pet.name}} {{pet.age}}|{{pet.weight}}|{{pet.stage}} {{pet.breed}}{{pet.breed && pet.color ? ' · ' : ''}}{{pet.color}} - + - 宠物档案(编辑)已完善 {{profilePct}}% › - 提醒设置 {{summary.reminders}} 条 › - 健康记录 {{summary.records}} 条 › - 多宠物管理 {{summary.pets}} 只 › + 宠物档案(编辑)已完善 {{profilePct}}% + 提醒设置{{summary.reminders}} 条 + 健康记录{{summary.records}} 条 + 多宠物管理{{summary.pets}} 只 - 会员权益 {{summary.pro_status === 'active' ? '已开通' : '未开通'}} › - 数据导出 文本 › - 意见反馈 去填写 › - 关于我们 v0.2 › + 会员权益{{summary.pro_status === 'active' ? '已开通' : '未开通'}} + 数据导出文本 + 意见反馈去填写 + 关于我们v0.2 diff --git a/pets-fe/pages/profile/profile.wxss b/pets-fe/pages/profile/profile.wxss index 4cf2b0a..8684038 100644 --- a/pets-fe/pages/profile/profile.wxss +++ b/pets-fe/pages/profile/profile.wxss @@ -1,16 +1,25 @@ -.profile-header{text-align:center;padding:24rpx 0 32rpx} -.ph-avatar{margin:0 auto 20rpx;width:152rpx;height:152rpx;font-size:76rpx;border-radius:56rpx;position:relative;overflow:visible} -.ph-avatar-img{width:100%;height:100%;border-radius:56rpx} -.ph-avatar-cam{position:absolute;right:-6rpx;bottom:-6rpx;width:52rpx;height:52rpx;line-height:52rpx;text-align:center;font-size:26rpx;background:#fff;border-radius:50%;box-shadow:var(--shadow)} -.ph-name{font-size:44rpx;font-weight:800} -.ph-meta{font-size:26rpx;margin-top:10rpx} +.profile-header{text-align:center;padding:var(--sp-4) 0 var(--sp-5)} +.ph-avatar{margin:0 auto var(--sp-3);width:152rpx;height:152rpx;font-size:76rpx;border-radius:var(--r-lg);position:relative;overflow:visible} +.ph-avatar-img{width:100%;height:100%;border-radius:var(--r-lg)} +.ph-avatar-cam{ + position:absolute;right:-6rpx;bottom:-6rpx;width:52rpx;height:52rpx; + display:flex;align-items:center;justify-content:center;color:var(--text-2); + background:#fff;border-radius:50%;box-shadow:var(--sd-1); +} +.ph-name{font-size:var(--fs-2xl);font-weight:var(--fw-b)} +.ph-meta{font-size:var(--fs-sm);margin-top:var(--sp-1)} -.profile-list{background:#fff;border-radius:48rpx;box-shadow:var(--shadow);overflow:hidden;margin-bottom:28rpx} +.profile-list{background:#fff;border-radius:var(--r-lg);box-shadow:var(--sd-1);overflow:hidden;margin-bottom:var(--sp-4)} .profile-row{ - display:flex;align-items:center;justify-content:space-between;min-height:104rpx;padding:0 32rpx; - border-bottom:1rpx solid var(--line);font-size:28rpx;font-weight:800; + display:flex;align-items:center;gap:var(--sp-3);min-height:104rpx;padding:0 var(--sp-4); + border-bottom:1rpx solid var(--line);font-size:var(--fs-md);font-weight:var(--fw-b); } .profile-row:last-child{border-bottom:0} -.pr-val{color:var(--muted);font-weight:700;font-size:26rpx} - -/* 页面不自身滚动,改由 page-scroll 承载滚动(隐藏滚动条)*/ +.pr-ic{ + width:56rpx;height:56rpx;border-radius:var(--r-xs);flex:none; + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink); +} +.pr-label{flex:1;min-width:0} +.pr-val{color:var(--muted);font-weight:var(--fw);font-size:var(--fs-sm)} +.pr-arrow{color:var(--muted2);display:flex;align-items:center;flex:none} diff --git a/pets-fe/pages/record/record.js b/pets-fe/pages/record/record.js index 45bae8b..6adc7a2 100644 --- a/pets-fe/pages/record/record.js +++ b/pets-fe/pages/record/record.js @@ -15,10 +15,34 @@ function fmtTime(iso) { if (d.toDateString() === y.toDateString()) return '昨天 ' + hm; return d.getMonth() + 1 + '月' + d.getDate() + '日'; } +// 记录类型 → 配色。和首页快速记录入口用同一套分组: +// 体重/疫苗=橙、便便/饮食=绿、异常/用药=蓝、消费/照片=紫 +const TYPE_TONE = { + weight: 'tone-1', vaccine: 'tone-1', deworm: 'tone-1', + poop: 'tone-2', food: 'tone-2', + symptom: 'tone-3', medicine: 'tone-3', + cost: 'tone-4', photo: 'tone-4', +}; + +// 记一笔的九个入口 +const RECORD_ITEMS = [ + { type: 'weight', icon: 'weight', label: '体重', tone: 'tone-1' }, + { type: 'food', icon: 'food', label: '饮食', tone: 'tone-2' }, + { type: 'poop', icon: 'poop', label: '便便', tone: 'tone-2' }, + { type: 'symptom', icon: 'symptom', label: '异常', tone: 'tone-3' }, + { type: 'medicine', icon: 'medicine', label: '用药', tone: 'tone-3' }, + { type: 'cost', icon: 'cost', label: '消费', tone: 'tone-4' }, + { type: 'vaccine', icon: 'vaccine', label: '疫苗', tone: 'tone-1' }, + { type: 'deworm', icon: 'deworm', label: '驱虫', tone: 'tone-1' }, + { type: 'photo', icon: 'photo', label: '照片', tone: 'tone-4' }, +]; + function mapRecord(r) { return { id: r.id, - icon: r.icon || '✍️', + // 图标按 type 取(9 值枚举,可靠);老数据 icon 字段里的 emoji 只作兜底 + type: r.type || r.icon || '', + tone: TYPE_TONE[r.type] || 'tone-1', title: r.title, desc: fmtTime(r.occurred_at) + (r.description ? '|' + r.description : ''), image: r.image_url || '', @@ -80,6 +104,7 @@ Page({ recHasMore: false, recFilters: REC_FILTERS, recFilterIdx: 0, + recordItems: RECORD_ITEMS, trendSvg: '', trendStats: null, trendDots: [], @@ -114,8 +139,9 @@ Page({ curFilter() { return this.data.recFilters[this.data.recFilterIdx].key; }, + // 来自 seg-tabs 的 change 事件 onFilterTap(e) { - const i = Number(e.currentTarget.dataset.index); + const i = Number(e.detail.index); if (i === this.data.recFilterIdx) return; this.setData({ recFilterIdx: i }, () => this.loadRecords()); }, diff --git a/pets-fe/pages/record/record.json b/pets-fe/pages/record/record.json index 075a8b2..58b7029 100644 --- a/pets-fe/pages/record/record.json +++ b/pets-fe/pages/record/record.json @@ -3,6 +3,8 @@ "nav-bar": "/components/nav-bar/nav-bar", "pet-switch": "/components/pet-switch/pet-switch", "bottom-sheet": "/components/bottom-sheet/bottom-sheet", - "fab": "/components/fab/fab" + "fab": "/components/fab/fab", + "pt-icon": "/components/pt-icon/index", + "seg-tabs": "/components/seg-tabs/index" } } diff --git a/pets-fe/pages/record/record.wxml b/pets-fe/pages/record/record.wxml index 554392c..68a12ec 100644 --- a/pets-fe/pages/record/record.wxml +++ b/pets-fe/pages/record/record.wxml @@ -2,23 +2,15 @@ - - 快速记录 - 先选择宠物,再记录体重、饮食、异常和消费。 - - - - ⚖️体重 - 🍽️饮食 - 💩便便 - 🤒异常 - 💊用药 - 💰消费 - 💉疫苗 - 🛡️驱虫 - 📷照片 + + 记一笔 + + + {{item.label}} + + @@ -40,32 +32,28 @@ {{selDot.value}}kg {{selDot.delta > 0 ? '+' : ''}}{{selDot.delta}}kg - 📝 {{selDot.note}} + {{selDot.note}} 这次没有填备注 点击圆点查看每次记录 - 先记录几次体重,这里会自动画出趋势曲线 + 先记录几次体重,这里会自动画出趋势曲线 健康时间轴摘要 - - {{item.label}} - + - {{item.icon}} + {{item.title}}{{item.desc}} - 这个分类下还没有记录 + 这个分类下还没有记录 长按任意一条可删除 查看更多(共 {{recTotal}} 条) diff --git a/pets-fe/pages/record/record.wxss b/pets-fe/pages/record/record.wxss index 6d2c273..33a0db1 100644 --- a/pets-fe/pages/record/record.wxss +++ b/pets-fe/pages/record/record.wxss @@ -1,13 +1,5 @@ -.record-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24rpx;margin-bottom:28rpx} -.record-item{ - height:184rpx;background:#fff;border-radius:44rpx;box-shadow:var(--shadow); - display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16rpx; - font-weight:900;color:var(--text);font-size:28rpx; -} -.ri-ic{font-size:56rpx} - .mini-chart{ - height:256rpx;border-radius:36rpx;margin-top:24rpx;position:relative;overflow:hidden; + height:256rpx;border-radius:var(--r-md);margin-top:var(--sp-4);position:relative;overflow:hidden; background: linear-gradient(180deg,rgba(115,190,157,.16),rgba(115,190,157,0)), repeating-linear-gradient(0deg,#fff,#fff 60rpx,#EFE8DE 62rpx); @@ -15,41 +7,38 @@ .chart-line{position:absolute;left:36rpx;right:36rpx;top:44rpx;bottom:44rpx;width:auto;height:auto} .dot-layer{position:absolute;left:36rpx;right:36rpx;top:44rpx;bottom:44rpx} .dot{position:absolute;width:40rpx;height:40rpx;margin:-20rpx 0 0 -20rpx;border-radius:50%;} -.dot::after{content:'';position:absolute;left:50%;top:50%;width:18rpx;height:18rpx;margin:-9rpx 0 0 -9rpx;border-radius:50%;background:#fff;border:4rpx solid #73BE9D;box-sizing:border-box} -.dot.on::after{width:26rpx;height:26rpx;margin:-13rpx 0 0 -13rpx;background:#73BE9D;box-shadow:0 0 0 6rpx rgba(115,190,157,.25)} -.trend-stats{margin-top:16rpx;font-size:26rpx;color:var(--muted)} -.point-detail{margin-top:20rpx;padding:24rpx 28rpx;border-radius:32rpx;background:#F3FAF6;border:1rpx solid #DCEFE4} -.pd-main{display:flex;align-items:baseline;gap:20rpx} -.pd-date{font-size:26rpx;color:var(--muted)} -.pd-weight{font-size:40rpx;font-weight:800;color:#2E7D5B} -.pd-delta{font-size:26rpx;font-weight:700} -.pd-delta.up{color:var(--red)} -.pd-delta.down{color:#2E7D5B} -.pd-note{margin-top:12rpx;font-size:28rpx;color:#4A4A46;line-height:1.5} +.dot::after{content:'';position:absolute;left:50%;top:50%;width:18rpx;height:18rpx;margin:-9rpx 0 0 -9rpx;border-radius:50%;background:#fff;border:4rpx solid var(--green);box-sizing:border-box} +.dot.on::after{width:26rpx;height:26rpx;margin:-13rpx 0 0 -13rpx;background:var(--green);box-shadow:0 0 0 6rpx rgba(115,190,157,.25)} +.trend-stats{margin-top:var(--sp-3);font-size:var(--fs-sm);color:var(--muted)} + +.point-detail{ + margin-top:var(--sp-3);padding:var(--sp-4);border-radius:var(--r-md); + background:var(--green-soft);border:1rpx solid #DCEFE4; +} +.pd-main{display:flex;align-items:baseline;gap:var(--sp-3)} +.pd-date{font-size:var(--fs-sm);color:var(--muted)} +.pd-weight{font-size:var(--fs-xl);font-weight:var(--fw-b);color:var(--green-ink)} +.pd-delta{font-size:var(--fs-sm);font-weight:var(--fw-b)} +.pd-delta.up{color:var(--red-ink)} +.pd-delta.down{color:var(--green-ink)} +.pd-note{margin-top:var(--sp-2);font-size:var(--fs-md);color:var(--text-2);line-height:1.5} .pd-note.muted{color:var(--muted)} -.chart-hint{margin-top:12rpx;font-size:22rpx;color:var(--muted);text-align:center} -.chart-empty{margin-top:24rpx;padding:48rpx 24rpx;border-radius:36rpx;background:#FBFAF8;color:var(--muted);font-size:26rpx;text-align:center} +.chart-hint{margin-top:var(--sp-2);font-size:var(--fs-cap);color:var(--muted);text-align:center} -.health-timeline{display:flex;flex-direction:column;gap:20rpx} -.tl-empty{padding:36rpx 8rpx;text-align:center;color:var(--muted);font-size:26rpx} -.tl-more{margin-top:20rpx;padding:20rpx;text-align:center;color:var(--primary-dark);background:#FBFAF8;border-radius:28rpx;font-size:26rpx;font-weight:700} -.health-event{display:flex;gap:20rpx;background:#FBFAF8;border-radius:32rpx;padding:24rpx} +.health-timeline{display:flex;flex-direction:column;gap:var(--sp-2)} +.health-event{display:flex;gap:var(--sp-3);background:var(--surface-2);border-radius:var(--r-md);padding:var(--sp-4)} +/* 底色和文字色由 .tone-N 提供(记录类型决定),这里只管形状 */ .event-dot{ - width:68rpx;height:68rpx;border-radius:26rpx;flex:none; - display:flex;align-items:center;justify-content:center;background:#FFF0D7;font-size:34rpx; + width:64rpx;height:64rpx;border-radius:var(--r-sm);flex:none; + display:flex;align-items:center;justify-content:center; } -.he-b{font-size:28rpx;font-weight:700} -.he-p{color:var(--muted);font-size:24rpx;line-height:1.45;margin-top:6rpx} +.he-b{font-size:var(--fs-md);font-weight:var(--fw-b)} +.he-p{color:var(--muted);font-size:var(--fs-sm);line-height:1.45;margin-top:6rpx} .he-body{flex:1;min-width:0} -.he-img{margin-top:14rpx;width:220rpx;height:220rpx;border-radius:20rpx} +.he-img{margin-top:var(--sp-2);width:220rpx;height:220rpx;border-radius:var(--r-sm)} -/* 页面不自身滚动,改由 page-scroll 承载滚动(隐藏滚动条)*/ - -/* 时间轴类型筛选 */ -.rec-filter{white-space:nowrap;margin-bottom:20rpx} -.rf-chip{ - display:inline-block;padding:10rpx 26rpx;margin-right:14rpx;border-radius:999rpx; - background:#fff;border:1rpx solid var(--line);color:var(--muted);font-size:24rpx;font-weight:700; +.tl-tip{margin-top:var(--sp-3);text-align:center;color:var(--muted);font-size:var(--fs-cap)} +.tl-more{ + margin-top:var(--sp-3);padding:var(--sp-3);text-align:center;color:var(--primary-dark); + background:var(--surface-2);border-radius:var(--r-md);font-size:var(--fs-sm);font-weight:var(--fw-b); } -.rf-chip.on{background:#FFF2DC;color:var(--primary-dark);border-color:#FFD39A} -.tl-tip{margin-top:16rpx;text-align:center;color:var(--muted);font-size:22rpx} diff --git a/pets-fe/pages/report/report.json b/pets-fe/pages/report/report.json index 075a8b2..cfab932 100644 --- a/pets-fe/pages/report/report.json +++ b/pets-fe/pages/report/report.json @@ -3,6 +3,7 @@ "nav-bar": "/components/nav-bar/nav-bar", "pet-switch": "/components/pet-switch/pet-switch", "bottom-sheet": "/components/bottom-sheet/bottom-sheet", - "fab": "/components/fab/fab" + "fab": "/components/fab/fab", + "pt-icon": "/components/pt-icon/index" } } diff --git a/pets-fe/pages/report/report.wxml b/pets-fe/pages/report/report.wxml index 5e175f6..be7b06a 100644 --- a/pets-fe/pages/report/report.wxml +++ b/pets-fe/pages/report/report.wxml @@ -2,11 +2,6 @@ - - 成长报告 - 每只宠物的成长报告、账单与健康摘要。 - - @@ -50,7 +45,7 @@ Pro 会员 解锁 365 天计划、PDF 健康档案、月度报告、多宠物管理与年度账单。 - + diff --git a/pets-fe/pages/report/report.wxss b/pets-fe/pages/report/report.wxss index b99f71a..2106ca1 100644 --- a/pets-fe/pages/report/report.wxss +++ b/pets-fe/pages/report/report.wxss @@ -1,13 +1,10 @@ .report-card{background:linear-gradient(135deg,#FFFFFF,#F2FAF6)} -.rc-text{color:var(--muted);font-size:28rpx;line-height:1.6} -.stat-b{display:block;font-size:36rpx;margin-bottom:8rpx;font-weight:800} -.stat-s{font-size:22rpx;color:var(--muted)} +.rc-text{color:var(--text-2);font-size:var(--fs-md);line-height:1.6} -.bill-bars{display:flex;flex-direction:column;gap:20rpx;margin-top:24rpx} -.bill-row{display:grid;grid-template-columns:88rpx 1fr 108rpx;gap:16rpx;align-items:center;font-size:24rpx} +.bill-bars{display:flex;flex-direction:column;gap:var(--sp-3);margin-top:var(--sp-4)} +.bill-row{display:grid;grid-template-columns:88rpx 1fr 108rpx;gap:var(--sp-3);align-items:center;font-size:var(--fs-sm)} .bill-cat{color:var(--text)} -.bill-amt{font-weight:900;text-align:right} -.mini-bar{height:18rpx;border-radius:999rpx;background:#F0E7DD;overflow:hidden} -.mini-bar-fill{display:block;height:100%;border-radius:999rpx;background:linear-gradient(90deg,var(--blue),#A9C8F6)} - -/* 页面不自身滚动,改由 page-scroll 承载滚动(隐藏滚动条)*/ +.bill-amt{font-weight:var(--fw-b);text-align:right} +/* 账单条比全局 .bar 细一档,蓝色是「花费」的语义色 */ +.mini-bar{height:var(--sp-2);border-radius:var(--r-full);background:#F0E7DD;overflow:hidden} +.mini-bar-fill{display:block;height:100%;border-radius:var(--r-full);background:var(--blue)} -- 2.52.0 From cab8b9ee285012c6ae7670eaef08d38eb42ee190 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 10:55:43 +0800 Subject: [PATCH 08/58] =?UTF-8?q?feat(fe):=20=E5=BC=B9=E5=B1=82=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E5=AF=B9=E9=BD=90=20token=EF=BC=88=E4=B8=8D=E5=8A=A8?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E4=B8=8D=E5=8A=A8=E5=86=99=E5=BA=93?= =?UTF-8?q?=E5=80=BC=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bottom-sheet 是 1245 行 / 28 种 type 的上帝组件,任何结构改动都会把 UI 重构变成功能重构,两类风险叠加后无法定位。所以这次严格限定: 改了:组件私有样式的值(圆角/字号/间距/配色走 token) 改了:wxml 里 5 处纯展示的 emoji → pt-icon(风险等级 ⚠️、勾选 ✓、 删图 ×、加图 +、已开通 Pro ✓) 没动:innerType 分发链、wx:if/elif 顺序、任何 data-*、onSave 的 payload 没动:8 处 data-icon="💩" 和 bottom-sheet.js 里 36 处 icon 字面量 —— 这些是写进数据库的值,改了会让历史数据和新数据分裂成两套且 回滚不回来。清理它需要给 HealthRecord 加 icon 枚举 + migration, 是独立任务。 sheet-scroll 上限从 78vh 提到 80vh:圆角和间距变化后,exportData / manageTasks / comments 这三型最容易从「内滚」变成被截断。 Co-Authored-By: Claude Opus 5 --- .../components/bottom-sheet/bottom-sheet.json | 4 +- .../components/bottom-sheet/bottom-sheet.wxml | 10 +-- .../components/bottom-sheet/bottom-sheet.wxss | 77 +++++++++++-------- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.json b/pets-fe/components/bottom-sheet/bottom-sheet.json index a89ef4d..a88211e 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.json +++ b/pets-fe/components/bottom-sheet/bottom-sheet.json @@ -1,4 +1,6 @@ { "component": true, - "usingComponents": {} + "usingComponents": { + "pt-icon": "/components/pt-icon/index" + } } diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index d57b615..c1f5ee7 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -75,7 +75,7 @@ module.exports.sel = function (map, key, index, def) { AI 观察建议 - ⚠️ 风险等级:{{riskData ? riskData.risk_level : '中'}} + 风险等级:{{riskData ? riskData.risk_level : '中'}} 可能原因:{{riskData ? riskData.causes : '可能与换粮、应激或消化不适有关。不要把这里写成诊断结论。'}} 建议:{{riskData ? riskData.suggestion : '继续观察精神、食欲和排便;暂停新食物;记录呕吐或腹泻次数。'}} 建议就医:{{riskData ? riskData.seek_care : '如果持续超过 24 小时,或伴随便血、精神明显变差、频繁呕吐,建议尽快就医。'}} @@ -232,9 +232,9 @@ module.exports.sel = function (map, key, index, def) { 肉垫计划 Pro 解锁 365 天计划、PDF 健康档案、月度报告、多宠物管理与年度账单。 - {{item}} + {{item}} - + 会员功能还在准备中,暂未开放购买。 @@ -292,9 +292,9 @@ module.exports.sel = function (map, key, index, def) { - × + - + diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index 2501820..ec6d21d 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -7,58 +7,75 @@ .overlay.show{opacity:1;pointer-events:auto} .sheet{ position:absolute;left:0;right:0;bottom:0; - background:#fff;border-radius:60rpx 60rpx 0 0; - padding:32rpx 0 0; + background:#fff;border-radius:48rpx 48rpx 0 0; + padding:var(--sp-5) 0 0; transform:translateY(106%);transition:.24s ease; - box-shadow:0 -40rpx 100rpx rgba(0,0,0,.16); + box-shadow:var(--sd-3); } .overlay.show .sheet{transform:translateY(0)} .sheet-scroll{ box-sizing:border-box; - max-height:78vh; - padding:0 36rpx calc(120rpx + env(safe-area-inset-bottom)); + /* exportData / manageTasks / comments 是最长的三型,圆角间距变化后靠这个上限内滚 */ + max-height:80vh; + padding:0 var(--sp-5) calc(120rpx + env(safe-area-inset-bottom)); } .sheet-scroll::-webkit-scrollbar,.plan-chat::-webkit-scrollbar{width:0;height:0;display:none} -.sheetbar{width:88rpx;height:10rpx;border-radius:999rpx;background:#E1D8CF;margin:0 auto 24rpx} +.sheetbar{width:80rpx;height:8rpx;border-radius:var(--r-full);background:#E1D8CF;margin:0 auto var(--sp-4)} -.sheet-h3{font-size:40rpx;font-weight:800;margin-bottom:20rpx} -.sheet-p{font-size:28rpx;color:#62584F;line-height:1.65;margin-bottom:24rpx} +.sheet-h3{font-size:var(--fs-xl);font-weight:var(--fw-b);margin-bottom:var(--sp-3)} +.sheet-p{font-size:var(--fs-md);color:var(--text-2);line-height:1.65;margin-bottom:var(--sp-4)} .sheet-p.pre,.poster-list.pre{white-space:pre-line} -.poster-h3{font-size:40rpx;font-weight:800;margin-bottom:20rpx} -.bold{font-weight:900} +.poster-h3{font-size:var(--fs-xl);font-weight:var(--fw-b);margin-bottom:var(--sp-3)} -.ai-input-row{display:flex;gap:16rpx;align-items:center} +.ai-input-row{display:flex;gap:var(--sp-3);align-items:center} .ai-input-row .input{flex:1} -.ai-send{height:88rpx;line-height:88rpx;padding:0 28rpx} +.ai-send{height:88rpx;line-height:88rpx;padding:0 var(--sp-4)} /* 弹层内的日期选择器展示 */ .picker-box{color:var(--text)} -.del-btn{background:var(--red-soft);color:var(--red)} +.del-btn{background:var(--red-soft);color:var(--red-ink)} -/* 管理任务 */ -.mtask-row{display:flex;align-items:center;gap:16rpx;padding:20rpx 0;border-bottom:1rpx solid var(--line)} +/* 管理任务 / 管理宠物 */ +.mtask-row{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) 0;border-bottom:1rpx solid var(--line)} .mtask-body{flex:1;min-width:0} -.mtask-b{font-size:28rpx;font-weight:700} -.mtask-pri{margin-left:12rpx;font-size:20rpx;font-weight:700;color:var(--primary-dark);background:#FFF2DC;padding:2rpx 12rpx;border-radius:999rpx} -.mtask-p{margin-top:6rpx;font-size:24rpx;color:var(--muted)} -.mtask-op{flex:none;font-size:26rpx;font-weight:700;color:var(--primary-dark);padding:8rpx 18rpx;background:#FBFAF8;border-radius:16rpx} -.mtask-op.del{color:var(--red)} -.mtask-form-row{display:flex;align-items:center;gap:16rpx} -.mtask-form-row .seg-btn{flex:none;padding:0 28rpx;height:72rpx;line-height:72rpx} +.mtask-b{font-size:var(--fs-md);font-weight:var(--fw-b)} +.mtask-pri{ + margin-left:var(--sp-2);font-size:var(--fs-cap);font-weight:var(--fw-b); + color:var(--primary-ink);background:var(--primary-soft);padding:2rpx var(--sp-2);border-radius:var(--r-full); +} +.mtask-p{margin-top:6rpx;font-size:var(--fs-sm);color:var(--muted)} +.mtask-op{ + flex:none;font-size:var(--fs-sm);font-weight:var(--fw-b);color:var(--primary-dark); + padding:var(--sp-1) var(--sp-3);background:var(--surface-2);border-radius:var(--r-xs); +} +.mtask-op.del{color:var(--red-ink)} +.mtask-form-row{display:flex;align-items:center;gap:var(--sp-3)} +/* 这条覆写了全局 .seg-btn 的高度,全局值变化时要一起看 */ +.mtask-form-row .seg-btn{flex:none;padding:0 var(--sp-4);height:var(--h-sm);line-height:var(--h-sm)} .mtask-form-row .picker-box{flex:1} /* 图片选择器 */ -.img-picker{display:flex;flex-wrap:wrap;gap:16rpx} -.img-thumb{position:relative;width:160rpx;height:160rpx;border-radius:20rpx;overflow:hidden} +.img-picker{display:flex;flex-wrap:wrap;gap:var(--sp-3)} +.img-thumb{position:relative;width:160rpx;height:160rpx;border-radius:var(--r-sm);overflow:hidden} .img-thumb image{width:100%;height:100%} -.img-del{position:absolute;top:0;right:0;width:40rpx;height:40rpx;line-height:38rpx;text-align:center;background:rgba(0,0,0,.55);color:#fff;font-size:30rpx;border-radius:0 20rpx 0 20rpx} -.img-add{width:160rpx;height:160rpx;border-radius:20rpx;border:2rpx dashed #D8CFC4;display:flex;align-items:center;justify-content:center;font-size:56rpx;color:#B9AE9F;background:#FBFAF8} +.img-del{ + position:absolute;top:0;right:0;width:44rpx;height:44rpx; + display:flex;align-items:center;justify-content:center; + background:rgba(0,0,0,.55);color:#fff;border-radius:0 var(--r-sm) 0 var(--r-sm); +} +.img-add{ + width:160rpx;height:160rpx;border-radius:var(--r-sm);border:2rpx dashed #D8CFC4; + display:flex;align-items:center;justify-content:center;color:var(--muted2);background:var(--surface-2); +} /* 导出健康档案 */ .export-box{ - max-height:560rpx;overflow-y:auto;background:#FBFAF8;border-radius:28rpx; - padding:24rpx;font-size:25rpx;line-height:1.7;color:#4A4A46;white-space:pre-line; - border:1rpx solid var(--line);margin-bottom:24rpx; + max-height:560rpx;overflow-y:auto;background:var(--surface-2);border-radius:var(--r-md); + padding:var(--sp-4);font-size:var(--fs-sm);line-height:1.7;color:var(--text-2);white-space:pre-line; + border:1rpx solid var(--line);margin-bottom:var(--sp-4); } .export-box::-webkit-scrollbar{width:0;height:0;display:none} -.mine-tag{margin-left:10rpx;font-size:20rpx;font-weight:700;color:var(--primary-dark);background:#FFF2DC;padding:2rpx 10rpx;border-radius:999rpx} +.mine-tag{ + margin-left:var(--sp-1);font-size:var(--fs-cap);font-weight:var(--fw-b); + color:var(--primary-ink);background:var(--primary-soft);padding:2rpx var(--sp-1);border-radius:var(--r-full); +} -- 2.52.0 From 35fc57e8de71bcc42ab770ed29cc0eee3bee93d0 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 11:10:41 +0800 Subject: [PATCH 09/58] =?UTF-8?q?feat(fe):=20AI=20=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E6=88=90=E9=A1=B5=EF=BC=88=E6=89=93=E5=AD=97=E6=9C=BA=EF=BC=89?= =?UTF-8?q?+=20=E4=BF=AE=E5=BF=AB=E9=80=9F=E8=AE=B0=E5=BD=95=206=20?= =?UTF-8?q?=E5=A4=84=E9=97=AE=E9=A2=98=20+=20=E5=AF=BC=E8=88=AA=E6=A0=8F?= =?UTF-8?q?=E5=8E=BB=E6=8E=A5=E7=BC=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AI 从底部弹层改成独立页面 pages/ai/ai: - 整屏聊天,输入框固定在底部,不再是「问题都打不完」的小格子 - 回复逐字吐出(30ms/2 字),点一下可跳过 - 会话 session 从 sheet 改为 chat,历史拉 50 条 - 组件里对应的 ai 分支和 aiMessages/aiInput/sendAI 一并删掉, 避免两套实现并存 快速记录九个入口逐个排查,修掉 6 处: 1. 疫苗/驱虫的默认日期写死成 2026-07-21 / 2026-07-15,早已是过去的 日期 —— 改成打开时按今天 +30 / +90 天算 2. 异常观察没选症状时,optIdx 返回 0 会被当成选了「呕吐」,等于替 用户瞎填 —— 加 optPicked 判断,没选就提示 3. 体重为空时会静默存成「上次的体重」,凭空造一条假数据 —— 改为必填校验 4. 消费金额为空会存成 ¥0 —— 必填校验 5. 用药药品名为空 —— 必填校验 6. 照片弹层里「模拟上传预览」是没删掉的假文案 顺带清理:保存按钮上的 data-text / data-icon 从来没被读过(onSave 只用 buildRecord 的返回值),是纯误导的死属性,删掉。我上一条 commit 把它们 说成「写库值」是说错了 —— 真正写库的是 buildRecord 里的 icon 字段,那部分 仍然没动。 导航栏原来是一整条半透明色块,底边和页面渐变硬碰硬,屏幕上横着一道接缝。 改成上实下虚的渐变,并用同一条 mask 把毛玻璃一起淡出(只淡背景不淡 blur 的话,接缝会从色差变成糊边)。返回键做成圆形,和右上角胶囊视觉对称。 Co-Authored-By: Claude Opus 5 --- pets-fe/app.json | 28 ++++- .../components/bottom-sheet/bottom-sheet.js | 84 ++++++-------- .../components/bottom-sheet/bottom-sheet.wxml | 36 ++---- pets-fe/components/nav-bar/nav-bar.wxss | 30 +++-- pets-fe/pages/ai/ai.js | 107 ++++++++++++++++++ pets-fe/pages/ai/ai.json | 6 + pets-fe/pages/ai/ai.wxml | 28 +++++ pets-fe/pages/ai/ai.wxss | 43 +++++++ pets-fe/pages/community/community.js | 2 +- pets-fe/pages/home/home.js | 2 +- pets-fe/pages/home/home.wxml | 2 +- pets-fe/pages/learn/learn.js | 2 +- pets-fe/pages/plan/plan.js | 2 +- pets-fe/pages/profile/profile.js | 2 +- pets-fe/pages/record/record.js | 2 +- pets-fe/pages/report/report.js | 2 +- 16 files changed, 281 insertions(+), 97 deletions(-) create mode 100644 pets-fe/pages/ai/ai.js create mode 100644 pets-fe/pages/ai/ai.json create mode 100644 pets-fe/pages/ai/ai.wxml create mode 100644 pets-fe/pages/ai/ai.wxss diff --git a/pets-fe/app.json b/pets-fe/app.json index 7f5a8cc..15629f2 100644 --- a/pets-fe/app.json +++ b/pets-fe/app.json @@ -8,7 +8,8 @@ "pages/community/community", "pages/learn/learn", "pages/article/article", - "pages/profile/profile" + "pages/profile/profile", + "pages/ai/ai" ], "window": { "navigationStyle": "custom", @@ -21,11 +22,26 @@ "selectedColor": "#DD8420", "backgroundColor": "#FFFFFF", "list": [ - { "pagePath": "pages/home/home", "text": "首页" }, - { "pagePath": "pages/plan/plan", "text": "计划" }, - { "pagePath": "pages/record/record", "text": "记录" }, - { "pagePath": "pages/report/report", "text": "报告" }, - { "pagePath": "pages/community/community", "text": "社区" } + { + "pagePath": "pages/home/home", + "text": "首页" + }, + { + "pagePath": "pages/plan/plan", + "text": "计划" + }, + { + "pagePath": "pages/record/record", + "text": "记录" + }, + { + "pagePath": "pages/report/report", + "text": "报告" + }, + { + "pagePath": "pages/community/community", + "text": "社区" + } ] }, "sitemapLocation": "sitemap.json", diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index 6484aa3..1be5ea5 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -8,6 +8,13 @@ function fmtDate(iso) { return d.getMonth() + 1 + '月' + d.getDate() + '日'; } +// n 天后的 YYYY-MM-DD,给提醒类弹层做默认日期 +function daysLater(n) { + const d = new Date(Date.now() + n * 86400000); + const p = (x) => (x < 10 ? '0' + x : '' + x); + return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate()); +} + function ageFromBirthday(bday) { if (!bday) return ''; const b = new Date(bday); @@ -60,7 +67,7 @@ Component({ pet: {}, segSel: {}, optSel: {}, - dateVals: { vaccine: '2026-07-21', deworm: '2026-07-15' }, + dateVals: { vaccine: '', deworm: '' }, wInput: '', wNote: '', poopNote: '', @@ -87,8 +94,6 @@ Component({ addColor: '', addBreed: '', commentText: '', - aiInput: '', - aiMessages: [], riskData: null, comments: [], reminders: [], @@ -147,6 +152,9 @@ Component({ patch.wInput = (pet.weight || '').replace('kg', ''); patch.wNote = ''; } + // 提醒日期给个合理的默认值。原本写死成固定日期,时间一过就成了「提醒昨天」 + if (type === 'vaccine') patch.dateVals = { ...this.data.dateVals, vaccine: daysLater(30) }; + if (type === 'deworm') patch.dateVals = { ...this.data.dateVals, deworm: daysLater(90) }; if (type === 'editPet') { // 预填当前宠物档案 patch.addName = pet.name || ''; @@ -160,15 +168,6 @@ Component({ }; patch.optSel = { addStage: Math.max(0, STAGES.indexOf(pet.stage)) }; } - if (type === 'ai') { - patch.aiMessages = [ - { - role: 'ai', - text: `我是 ${pet.name || '毛孩子'} 的养宠助手。我会优先基于档案、计划和历史记录回答,而不是泛泛聊天。`, - }, - ]; - patch.aiInput = ''; - } this.setData(patch); this.loadSheetData(type); }, @@ -190,8 +189,6 @@ Component({ api.getPoster(id).then((p) => this.setData({ poster: p })).catch(() => {}); } else if (type === 'reportDetail' && id) { api.weeklyReport(id).then((r) => this.setData({ reportDetail: r })).catch(() => {}); - } else if (type === 'ai') { - this.loadAIHistory(); } else if (type === 'pro') { api.getPro().then((p) => this.setData({ proInfo: p })).catch(() => {}); } @@ -492,10 +489,18 @@ Component({ const v = this.data.optSel[group]; return v === undefined ? 0 : v; }, + // 与 optIdx 的区别:没选就是没选,不当成选了第 0 项 + optPicked(group) { + return this.data.optSel[group] !== undefined; + }, // 异常观察 → 生成风险评估(真调后端 AI,失败回退) onGenRisk() { const id = store.currentPetId(); + if (!this.optPicked('symp')) { + wx.showToast({ title: '先选一下发生了什么', icon: 'none' }); + return; + } const symptoms = ['呕吐', '拉稀', '精神差', '皮肤红']; const durations = ['刚刚', '半天', '1天以上']; const spirits = ['正常', '一般', '明显变差']; @@ -597,13 +602,26 @@ Component({ }, onSave() { + const t = this.data.innerType; + if (t === 'cost' && !(parseFloat(this.data.costAmount) > 0)) { + wx.showToast({ title: '先填个金额', icon: 'none' }); + return; + } + if (t === 'medicine' && !(this.data.medName || '').trim()) { + wx.showToast({ title: '先填药品名称', icon: 'none' }); + return; + } this.createAndClose(this.buildRecord()); }, onSaveWeight() { - let w = (this.data.wInput || '').toString().replace(/\s+/g, ''); - if (!w) w = (this.data.pet.weight || '').replace('kg', ''); - const num = parseFloat(w) || 0; - const weight = w.includes('kg') ? w : w + 'kg'; + const w = (this.data.wInput || '').toString().replace(/\s+/g, '').replace('kg', ''); + const num = parseFloat(w); + // 原来空值会静默存成「上次的体重」,等于凭空造一条假数据 + if (!w || !(num > 0)) { + wx.showToast({ title: '填一个有效体重', icon: 'none' }); + return; + } + const weight = w + 'kg'; this.createAndClose({ type: 'weight', icon: '⚖️', title: '体重 ' + weight, num_value: num, description: (this.data.wNote || '').trim() }); }, onSavePhoto() { @@ -745,35 +763,5 @@ Component({ this.close(); }, - // AI 聊天 - onAiInput(e) { this.setData({ aiInput: e.detail.value }); }, - // 拉取历史对话,接在开场白之后;没有历史就保持开场白 - loadAIHistory() { - api - .aiMessages('sheet', 30) - .then((list) => { - if (!list || !list.length) return; - const history = list.map((m) => ({ role: m.role === 'user' ? 'user' : 'ai', text: m.text })); - this.setData({ aiMessages: this.data.aiMessages.concat(history) }); - }) - .catch(() => {}); - }, - sendAI(e) { - const preset = e.currentTarget.dataset.text; - const text = (preset || this.data.aiInput || '').trim(); - if (!text) return; - const msgs = this.data.aiMessages.concat([{ role: 'user', text }]); - this.setData({ aiMessages: msgs, aiInput: '' }); - api - .aiChat({ pet_id: store.currentPetId() || null, session: 'sheet', text }) - .then((res) => { - this.setData({ aiMessages: this.data.aiMessages.concat([{ role: 'ai', text: res.reply }]) }); - }) - .catch(() => { - this.setData({ - aiMessages: this.data.aiMessages.concat([{ role: 'ai', text: '网络异常,请稍后再试。' }]), - }); - }); - }, }, }); diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index c1f5ee7..49d23cb 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -33,7 +33,7 @@ module.exports.sel = function (map, key, index, def) { - + @@ -46,7 +46,7 @@ module.exports.sel = function (map, key, index, def) { 偏少 不吃 - + @@ -80,7 +80,7 @@ module.exports.sel = function (map, key, index, def) { 建议:{{riskData ? riskData.suggestion : '继续观察精神、食欲和排便;暂停新食物;记录呕吐或腹泻次数。'}} 建议就医:{{riskData ? riskData.seek_care : '如果持续超过 24 小时,或伴随便血、精神明显变差、频繁呕吐,建议尽快就医。'}} - + @@ -93,7 +93,7 @@ module.exports.sel = function (map, key, index, def) { 当前体重:{{pet.weight}} 近期重点:疫苗期、换粮观察、排便记录 建议携带:排便/呕吐照片、饮食变化、疫苗驱虫记录。 - + @@ -101,7 +101,7 @@ module.exports.sel = function (map, key, index, def) { 记录用药 - + @@ -114,7 +114,7 @@ module.exports.sel = function (map, key, index, def) { 用品 - + @@ -125,7 +125,7 @@ module.exports.sel = function (map, key, index, def) { {{dateVals.vaccine}} - + @@ -136,7 +136,7 @@ module.exports.sel = function (map, key, index, def) { {{dateVals.deworm}} - + @@ -146,7 +146,7 @@ module.exports.sel = function (map, key, index, def) { {{pet.emoji}} {{pet.name}} 的成长照片 - 模拟上传预览 + 支持 jpg / png,单张不超过 10MB @@ -184,24 +184,6 @@ module.exports.sel = function (map, key, index, def) { - - - 问问 AI - - {{item.text}} - - - - 猫咪吐了一次 - 多久驱虫 - 换粮软便 - - - - - - diff --git a/pets-fe/components/nav-bar/nav-bar.wxss b/pets-fe/components/nav-bar/nav-bar.wxss index 7ca13bc..b6fc5ec 100644 --- a/pets-fe/components/nav-bar/nav-bar.wxss +++ b/pets-fe/components/nav-bar/nav-bar.wxss @@ -1,19 +1,33 @@ :host{display:block} + +/* 原来是一整条半透明色块,底边和页面渐变硬碰硬,屏幕上横着一道接缝。 + 改成上实下虚的渐变,并且用同一条 mask 把毛玻璃也一起淡出—— + 只淡化背景色而不淡化 blur 的话,接缝会从「色差」变成「糊边」,一样难看。 */ .nav-wrap{ position:fixed;top:0;left:0;right:0;z-index:100; - background:rgba(248,246,242,.82); - backdrop-filter:blur(28rpx); - -webkit-backdrop-filter:blur(28rpx); + background:linear-gradient(180deg, + rgba(250,247,242,.94) 0%, + rgba(250,247,242,.88) 58%, + rgba(250,247,242,0) 100%); + backdrop-filter:blur(20rpx); + -webkit-backdrop-filter:blur(20rpx); + -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 62%,transparent 100%); + mask-image:linear-gradient(180deg,#000 0%,#000 62%,transparent 100%); } .nav-inner{ position:relative;display:flex;align-items:center;justify-content:center; } .nav-title{ - font-size:var(--fs-lg);font-weight:var(--fw-b);color:var(--text); - max-width:60%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; + font-size:var(--fs-md);font-weight:var(--fw-b);color:var(--text); + letter-spacing:.5rpx; + max-width:56%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; } +/* 返回键做成有边界的圆形,和右上角胶囊在视觉上对称 */ .nav-back{ - position:absolute;left:20rpx;top:50%;transform:translateY(-50%); - width:64rpx;height:64rpx;display:flex;align-items:center;justify-content:center; - color:var(--text); + position:absolute;left:var(--sp-3);top:50%;transform:translateY(-50%); + width:60rpx;height:60rpx;border-radius:50%; + display:flex;align-items:center;justify-content:center; + color:var(--text);background:rgba(255,255,255,.72); + box-shadow:0 4rpx 12rpx rgba(70,48,25,.06); } +.nav-back:active{background:rgba(255,255,255,.95)} diff --git a/pets-fe/pages/ai/ai.js b/pets-fe/pages/ai/ai.js new file mode 100644 index 0000000..b2a28bd --- /dev/null +++ b/pets-fe/pages/ai/ai.js @@ -0,0 +1,107 @@ +const store = require('../../utils/store.js'); +const api = require('../../utils/api.js'); +const { toastErr } = require('../../utils/ui.js'); + +const SESSION = 'chat'; +const PRESETS = ['猫咪今天吐了一次怎么办?', '幼猫多久驱虫一次?', '换粮后软便怎么办?', '疫苗打完要注意什么?']; + +// 打字机:每帧吐几个字。太快没效果,太慢让人等,30ms/2 字接近正常朗读速度。 +const TYPE_STEP = 2; +const TYPE_INTERVAL = 30; + +Page({ + data: { + pet: {}, + messages: [], + input: '', + presets: PRESETS, + sending: false, + loaded: false, + }, + onLoad() { + this._unsub = store.subscribe((pet) => this.setData({ pet })); + store + .ready() + .then(() => { + this.setData({ pet: store.getPet() }); + this.loadHistory(); + }) + .catch((e) => toastErr(e)); + }, + onUnload() { + if (this._unsub) this._unsub(); + this.stopTyping(); + }, + + loadHistory() { + const opening = { + role: 'ai', + text: '我是' + (store.getPet().name || '毛孩子') + '的养宠助手。我会优先根据档案、计划和历史记录回答,而不是泛泛聊天。', + }; + api + .aiMessages(SESSION, 50) + .then((list) => { + const history = (list || []).map((m) => ({ role: m.role === 'user' ? 'user' : 'ai', text: m.text })); + this.setData({ messages: [opening].concat(history), loaded: true }, () => this.scrollToBottom()); + }) + .catch(() => this.setData({ messages: [opening], loaded: true })); + }, + + onInput(e) { + this.setData({ input: e.detail.value }); + }, + + onSend(e) { + const preset = e.currentTarget && e.currentTarget.dataset.text; + const text = (preset || this.data.input || '').trim(); + if (!text || this.data.sending) return; + + // 先把用户消息和一个空的 AI 气泡放上去,AI 气泡随后逐字填充 + const messages = this.data.messages.concat([ + { role: 'user', text }, + { role: 'ai', text: '', pending: true }, + ]); + this.setData({ messages, input: '', sending: true }, () => this.scrollToBottom()); + + api + .aiChat({ pet_id: store.currentPetId() || null, session: SESSION, text }) + .then((res) => this.typewrite(res.reply || '(没有返回内容)')) + .catch((e) => this.typewrite(e.message || '网络异常,请稍后再试。')); + }, + + // 逐字把回复填进最后一个气泡 + typewrite(full) { + this.stopTyping(); + const idx = this.data.messages.length - 1; + let n = 0; + this._timer = setInterval(() => { + n = Math.min(full.length, n + TYPE_STEP); + this.setData({ [`messages[${idx}].text`]: full.slice(0, n) }); + if (n % 20 === 0) this.scrollToBottom(); + if (n >= full.length) { + this.stopTyping(); + this.setData({ [`messages[${idx}].pending`]: false, sending: false }, () => this.scrollToBottom()); + } + }, TYPE_INTERVAL); + }, + stopTyping() { + if (this._timer) { + clearInterval(this._timer); + this._timer = null; + } + }, + // 打字过程中点一下可以跳过,不用干等 + onSkip() { + if (!this.data.sending) return; + this.stopTyping(); + this.setData({ sending: false }); + }, + + scrollToBottom() { + this.setData({ scrollInto: 'chat-bottom' }); + }, + + onShareAppMessage() { + return { title: '肉垫计划 · AI 养宠助手', path: '/pages/ai/ai' }; + }, +}); diff --git a/pets-fe/pages/ai/ai.json b/pets-fe/pages/ai/ai.json new file mode 100644 index 0000000..6594cd8 --- /dev/null +++ b/pets-fe/pages/ai/ai.json @@ -0,0 +1,6 @@ +{ + "usingComponents": { + "nav-bar": "/components/nav-bar/nav-bar", + "pt-icon": "/components/pt-icon/index" + } +} diff --git a/pets-fe/pages/ai/ai.wxml b/pets-fe/pages/ai/ai.wxml new file mode 100644 index 0000000..e444230 --- /dev/null +++ b/pets-fe/pages/ai/ai.wxml @@ -0,0 +1,28 @@ + + + + + + + + {{item.text}} + + + + + + + + + {{item}} + + + + + + + + diff --git a/pets-fe/pages/ai/ai.wxss b/pets-fe/pages/ai/ai.wxss new file mode 100644 index 0000000..c06e288 --- /dev/null +++ b/pets-fe/pages/ai/ai.wxss @@ -0,0 +1,43 @@ +/* 整页聊天:上面滚动区自适应,下面输入区固定,中间不留空 */ +.chat-scroll{flex:1;min-height:0} +.chat-body{padding:var(--sp-3) var(--pad-x) var(--sp-5)} +.chat-bottom{height:1rpx} + +.row{display:flex;align-items:flex-start;gap:var(--sp-2);margin-bottom:var(--sp-4)} +.row-user{justify-content:flex-end} +.ai-avatar{ + width:60rpx;height:60rpx;border-radius:var(--r-sm);flex:none;margin-top:4rpx; + display:flex;align-items:center;justify-content:center; + background:var(--cta);color:#fff; +} +.bubble{ + max-width:76%;border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4); + font-size:var(--fs-md);line-height:1.62;word-break:break-word; +} +.bubble-ai{background:#fff;box-shadow:var(--sd-1);border-top-left-radius:var(--r-xs)} +.bubble-user{background:var(--primary-soft);color:var(--primary-ink);border-top-right-radius:var(--r-xs)} +/* 打字光标 */ +.caret{color:var(--primary);animation:blink .9s steps(1) infinite} +@keyframes blink{50%{opacity:0}} + +/* 底部输入区 */ +.dock{ + flex:none;background:rgba(255,255,255,.94); + backdrop-filter:blur(28rpx);-webkit-backdrop-filter:blur(28rpx); + border-top:1rpx solid var(--line); + padding:var(--sp-3) var(--pad-x) calc(var(--sp-3) + env(safe-area-inset-bottom)); +} +.presets{white-space:nowrap;margin-bottom:var(--sp-3)} +.preset{ + display:inline-block;height:var(--h-sm);line-height:var(--h-sm);padding:0 var(--sp-4); + margin-right:var(--sp-2);border-radius:var(--r-full);border:1rpx solid var(--line); + background:#fff;color:var(--text-2);font-size:var(--fs-sm); +} +.input-row{display:flex;align-items:center;gap:var(--sp-3)} +.input-row .input{flex:1;background:var(--surface-2)} +.send{ + width:88rpx;height:88rpx;border-radius:var(--r-md);flex:none; + display:flex;align-items:center;justify-content:center; + background:var(--line);color:#fff;transition:.16s ease; +} +.send.on{background:var(--cta)} diff --git a/pets-fe/pages/community/community.js b/pets-fe/pages/community/community.js index 65bc7b9..b2c994d 100644 --- a/pets-fe/pages/community/community.js +++ b/pets-fe/pages/community/community.js @@ -102,7 +102,7 @@ Page({ wx.navigateTo({ url: '/pages/learn/learn' }); }, onFab() { - this.setData({ sheetType: 'ai', sheetPostId: '', sheetShow: true }); + wx.navigateTo({ url: '/pages/ai/ai' }); }, // 长按自己的帖子可删除 onLongPressPost(e) { diff --git a/pets-fe/pages/home/home.js b/pets-fe/pages/home/home.js index 22f96a7..488a97d 100644 --- a/pets-fe/pages/home/home.js +++ b/pets-fe/pages/home/home.js @@ -189,7 +189,7 @@ Page({ this.openSheetType('editPet'); }, onFab() { - this.openSheetType('ai'); + wx.navigateTo({ url: '/pages/ai/ai' }); }, goProfile() { wx.navigateTo({ url: '/pages/profile/profile' }); diff --git a/pets-fe/pages/home/home.wxml b/pets-fe/pages/home/home.wxml index 4f2ff22..6aa8c07 100644 --- a/pets-fe/pages/home/home.wxml +++ b/pets-fe/pages/home/home.wxml @@ -79,7 +79,7 @@ AI 今日建议 {{summary.advice || '正在生成今日建议…'}} - + 问问 AI 养宠助手 diff --git a/pets-fe/pages/learn/learn.js b/pets-fe/pages/learn/learn.js index fc92938..ddec272 100644 --- a/pets-fe/pages/learn/learn.js +++ b/pets-fe/pages/learn/learn.js @@ -35,7 +35,7 @@ Page({ this.setData({ sheetShow: false }); }, onFab() { - this.setData({ sheetType: 'ai', sheetShow: true }); + wx.navigateTo({ url: '/pages/ai/ai' }); }, onShareAppMessage() { return { title: '新手养宠知识合集', path: '/pages/learn/learn' }; diff --git a/pets-fe/pages/plan/plan.js b/pets-fe/pages/plan/plan.js index 111159b..528b853 100644 --- a/pets-fe/pages/plan/plan.js +++ b/pets-fe/pages/plan/plan.js @@ -178,7 +178,7 @@ Page({ this.setData({ sheetType: 'addPet', sheetShow: true }); }, onFab() { - this.setData({ sheetType: 'ai', sheetShow: true }); + wx.navigateTo({ url: '/pages/ai/ai' }); }, onShareAppMessage() { return { title: '我给毛孩子做了份养护计划', path: '/pages/plan/plan' }; diff --git a/pets-fe/pages/profile/profile.js b/pets-fe/pages/profile/profile.js index 167b9e0..7f6d451 100644 --- a/pets-fe/pages/profile/profile.js +++ b/pets-fe/pages/profile/profile.js @@ -68,7 +68,7 @@ Page({ this.loadSummary(); }, onFab() { - this.setData({ sheetType: 'ai', sheetShow: true }); + wx.navigateTo({ url: '/pages/ai/ai' }); }, onShareAppMessage() { return { title: '肉垫计划 · 新手养宠助手', path: '/pages/home/home' }; diff --git a/pets-fe/pages/record/record.js b/pets-fe/pages/record/record.js index 6adc7a2..7a7beef 100644 --- a/pets-fe/pages/record/record.js +++ b/pets-fe/pages/record/record.js @@ -245,7 +245,7 @@ Page({ this.openSheetType('addPet'); }, onFab() { - this.openSheetType('ai'); + wx.navigateTo({ url: '/pages/ai/ai' }); }, onShareAppMessage() { return { title: '用肉垫计划记录毛孩子的成长', path: '/pages/record/record' }; diff --git a/pets-fe/pages/report/report.js b/pets-fe/pages/report/report.js index c064f85..f8eeb97 100644 --- a/pets-fe/pages/report/report.js +++ b/pets-fe/pages/report/report.js @@ -59,7 +59,7 @@ Page({ this.setData({ sheetType: 'addPet', sheetShow: true }); }, onFab() { - this.setData({ sheetType: 'ai', sheetShow: true }); + wx.navigateTo({ url: '/pages/ai/ai' }); }, onShareAppMessage() { return { title: '看看我家毛孩子的成长报告', path: '/pages/report/report' }; -- 2.52.0 From d9d7e128ffb83068e12c565e16f820930d64744d Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 11:58:00 +0800 Subject: [PATCH 10/58] =?UTF-8?q?feat:=20=E5=BC=95=E5=AF=BC=E9=A1=B5?= =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=8C=89=E7=94=9F=E6=97=A5=E6=8E=A8=E6=96=AD?= =?UTF-8?q?=20+=208=20=E5=A5=97=E5=85=BB=E6=8A=A4=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=8C=89=E4=B8=B4=E5=BA=8A=E5=85=B1=E8=AF=86=E9=87=8D=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 引导页三个逻辑漏洞 1. **阶段和生日脱节**:用户填了 3 个月的生日,却能手选「成年期」, 而阶段决定疫苗针次、驱虫周期和每天要做的事,选错整套计划都是偏的。 现在按生日自动推断(猫狗同:12 月龄成年、7 岁进老年),仍可手改, 但改成矛盾值时会弹框说明代价;服务端 NormalizeStage 兜底。 2. **`goals` 是假选择**:6 个勾选框收上来只存进 pets.goals,一处没用过。 现在真正生效:体重提醒、月度报告按勾选生成,勾了「想控制养宠开销」 会多一条记账任务。疫苗和驱虫不给关——狂犬是法定要求,漏驱虫真会出事。 3. **「刚到家 0-30 天」和年龄阶段互斥**:挤在一个四选一里,刚接回家的 成年猫只能二选一。现在拆开:stage 只存年龄阶段,新增 pets.arrived_at, 到家不满 30 天时把安置期那套任务和计划叠加上去(同标题去重)。 顺带:生日/到家日期不能选未来(前后端各拦一道)、体重范围校验。 ## 疫苗提醒改为按月龄算 原来不管多大都排「14 天后首针」,一只 8 月龄才接回家的猫会被安排去打首免。 现在 dueDaysFor 按真实月龄推:<2 月龄等到 8 周龄、2-5 月龄间隔 21 天、 5-12 月龄两周内补齐、成年走年度加强。标题也跟着改写,否则用户照着 「年度疫苗加强」去打错针。 年度疫苗不再编一个假的到期日(原来写 30 天后),改用频率描述。 ## 8 套模板按临床共识重配 依据 WSAVA 疫苗指南、ESCCAP/CAPC 驱虫建议、AAHA 生命阶段指南整理: 猫三联 3 针间隔 3-4 周末针不早于 16 周龄、犬联苗 2-3 针 + 3 月龄狂犬、 体内驱虫 6 月龄前每月一次之后每 3 个月、幼崽 3-6 月龄每天 3-4 餐、 成年犬每天 2 次共 30-60 分钟遛狗、老年建议半年一次体检。 每套从 11 条扩到 10-14 条,描述写成能直接照做的具体动作。 后台新增「恢复默认」:启动 seed 改为只补缺失、不覆盖已有(管理员可能 改过),内置模板更新后必须从后台显式推一次。 Co-Authored-By: Claude Opus 5 --- .../admin/dist/assets/index-1jDx3IlD.js | 59 ---- .../admin/dist/assets/index-D8GFrwWw.js | 59 ++++ pets-be/internal/admin/dist/index.html | 2 +- pets-be/internal/handler/admin.go | 25 +- pets-be/internal/handler/pet.go | 30 +- pets-be/internal/model/pet.go | 3 +- pets-be/internal/router/router.go | 1 + pets-be/internal/service/care_template.go | 285 ++++++++++++------ pets-be/internal/service/pet.go | 168 ++++++++++- pets-be/web/admin/src/lib/api.ts | 5 + pets-be/web/admin/src/pages/CareTemplates.tsx | 23 +- pets-fe/pages/onboarding/onboarding.js | 81 ++++- pets-fe/pages/onboarding/onboarding.wxml | 31 +- pets-fe/pages/onboarding/onboarding.wxss | 11 + 14 files changed, 583 insertions(+), 200 deletions(-) delete mode 100644 pets-be/internal/admin/dist/assets/index-1jDx3IlD.js create mode 100644 pets-be/internal/admin/dist/assets/index-D8GFrwWw.js diff --git a/pets-be/internal/admin/dist/assets/index-1jDx3IlD.js b/pets-be/internal/admin/dist/assets/index-1jDx3IlD.js deleted file mode 100644 index 94625bd..0000000 --- a/pets-be/internal/admin/dist/assets/index-1jDx3IlD.js +++ /dev/null @@ -1,59 +0,0 @@ -var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,a)=>(a=n==null?{}:e(i(n)),c(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var u=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function ee(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function te(e,t){return ee(e.type,t,e.props)}function ne(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function E(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var D=/\/+/g;function O(e,t){return typeof e==`object`&&e&&e.key!=null?E(``+e.key):t.toString(36)}function re(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ie(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ie(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+O(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(D,`$&/`)+`/`),ie(o,r,i,``,function(e){return e})):o!=null&&(ne(o)&&(o=te(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(D,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=u()})),f=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,ne());else{var t=n(l);t!==null&&O(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function ee(){return g?!0:!(e.unstable_now()-Tt&&ee());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&O(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?ne():S=!1}}}var ne;if(typeof y==`function`)ne=function(){y(te)};else if(typeof MessageChannel<`u`){var E=new MessageChannel,D=E.port2;E.port1.onmessage=te,ne=function(){D.postMessage(null)}}else ne=function(){_(te,0)};function O(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,O(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,ne()))),r},e.unstable_shouldYield=ee,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),p=o(((e,t)=>{t.exports=f()})),m=o((e=>{var t=d();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=m()})),g=o((e=>{var t=p(),n=d(),r=h();function i(e){var t=`https://react.dev/errors/`+e;if(1le||(e.current=ce[le],ce[le]=null,le--)}function N(e,t){le++,ce[le]=e.current,e.current=t}var ue=j(null),de=j(null),fe=j(null),pe=j(null);function me(e,t){switch(N(fe,t),N(de,e),N(ue,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}M(ue),N(ue,e)}function he(){M(ue),M(de),M(fe)}function ge(e){e.memoizedState!==null&&N(pe,e);var t=ue.current,n=Hd(t,e.type);t!==n&&(N(de,e),N(ue,n))}function _e(e){de.current===e&&(M(ue),M(de)),pe.current===e&&(M(pe),Qf._currentValue=se)}var ve,ye;function be(e){if(ve===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);ve=t&&t[1]||``,ye=-1)`:-1i||c[r]!==l[i]){var u=` -`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{xe=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?be(n):``}function Ce(e,t){switch(e.tag){case 26:case 27:case 5:return be(e.type);case 16:return be(`Lazy`);case 13:return e.child!==t&&t!==null?be(`Suspense Fallback`):be(`Suspense`);case 19:return be(`SuspenseList`);case 0:case 15:return Se(e.type,!1);case 11:return Se(e.type.render,!1);case 1:return Se(e.type,!0);case 31:return be(`Activity`);default:return``}}function we(e){try{var t=``,n=null;do t+=Ce(e,n),n=e,e=e.return;while(e);return t}catch(e){return` -Error generating stack: `+e.message+` -`+e.stack}}var Te=Object.prototype.hasOwnProperty,Ee=t.unstable_scheduleCallback,De=t.unstable_cancelCallback,Oe=t.unstable_shouldYield,ke=t.unstable_requestPaint,Ae=t.unstable_now,je=t.unstable_getCurrentPriorityLevel,Me=t.unstable_ImmediatePriority,Ne=t.unstable_UserBlockingPriority,Pe=t.unstable_NormalPriority,Fe=t.unstable_LowPriority,Ie=t.unstable_IdlePriority,Le=t.log,Re=t.unstable_setDisableYieldValue,ze=null,Be=null;function Ve(e){if(typeof Le==`function`&&Re(e),Be&&typeof Be.setStrictMode==`function`)try{Be.setStrictMode(ze,e)}catch{}}var He=Math.clz32?Math.clz32:Ge,Ue=Math.log,We=Math.LN2;function Ge(e){return e>>>=0,e===0?32:31-(Ue(e)/We|0)|0}var Ke=256,qe=262144,Je=4194304;function Ye(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Xe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ye(n))):i=Ye(o):i=Ye(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ye(n))):i=Ye(o)):i=Ye(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ze(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function $e(){var e=Je;return Je<<=1,!(Je&62914560)&&(Je=4194304),e}function et(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function tt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nt(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),mn=!1;if(pn)try{var hn={};Object.defineProperty(hn,"passive",{get:function(){mn=!0}}),window.addEventListener(`test`,hn,hn),window.removeEventListener(`test`,hn,hn)}catch{mn=!1}var gn=null,_n=null,vn=null;function yn(){if(vn)return vn;var e,t=_n,n=t.length,r,i=`value`in gn?gn.value:gn.textContent,a=i.length;for(e=0;e=Zn),er=` `,tr=!1;function nr(e,t){switch(e){case`keyup`:return Yn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function rr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ir=!1;function ar(e,t){switch(e){case`compositionend`:return rr(t);case`keypress`:return t.which===32?(tr=!0,er):null;case`textInput`:return e=t.data,e===er&&tr?null:e;default:return null}}function or(e,t){if(ir)return e===`compositionend`||!Xn&&nr(e,t)?(e=yn(),vn=_n=gn=null,ir=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Or(n)}}function Ar(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ar(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Bt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Bt(e.document)}return t}function Mr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Nr=pn&&`documentMode`in document&&11>=document.documentMode,Pr=null,Fr=null,Ir=null,Lr=!1;function Rr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Lr||Pr==null||Pr!==Bt(r)||(r=Pr,`selectionStart`in r&&Mr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ir&&Dr(Ir,r)||(Ir=r,r=Ed(Fr,`onSelect`),0>=o,i-=o,ki=1<<32-He(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),L&&ji(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),L&&ji(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return L&&ji(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),L&&ji(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===ne&&Aa(l)===r.type){n(e,r.sibling),c=a(r,o.props),La(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=gi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=hi(o.type,o.key,o.props,null,e.mode,c),La(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=yi(o,e.mode,c),c.return=e,e=c}return s(e);case ne:return o=Aa(o),b(e,r,o,c)}if(oe(o))return h(e,r,o,c);if(re(o)){if(l=re(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Ia(o),c);if(o.$$typeof===C)return b(e,r,ia(e,o),c);Ra(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=_i(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Fa=0;var i=b(e,t,n,r);return Pa=null,i}catch(t){if(t===wa||t===Ea)throw t;var a=fi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ba=za(!0),Va=za(!1),Ha=!1;function Ua(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Wa(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ga(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ka(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,q&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=li(e),ci(e,null,n),t}return ai(e,r,t,n),li(e)}function qa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}function Ja(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ya=!1;function Xa(){if(Ya){var e=ha;if(e!==null)throw e}}function Za(e,t,n,r){Ya=!1;var i=e.updateQueue;Ha=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(Y&f)===f:(r&f)===f){f!==0&&f===ma&&(Ya=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=m({},d,f);break a;case 2:Ha=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Gl|=o,e.lanes=o,e.memoizedState=d}}function Qa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function $a(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,Ls(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Is(e,t,va(c,r),pu(e)):Is(e,t,r,pu(e))}catch(n){Is(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function Es(){}function Ds(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Os(e).queue;Ts(e,a,t,se,n===null?Es:function(){return ks(e),n(r)})}function Os(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:se,baseState:se,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:se},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function ks(e){var t=Os(e);t.next===null&&(t=e.alternate.memoizedState),Is(e,t.next.queue,{},pu())}function As(){return ra(Qf)}function js(){return No().memoizedState}function Ms(){return No().memoizedState}function Ns(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Ga(n);var r=Ka(t,e,n);r!==null&&(hu(r,t,n),qa(r,t,n)),t={cache:ua()},e.payload=t;return}t=t.return}}function Ps(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Rs(e)?zs(t,n):(n=oi(e,t,n,r),n!==null&&(hu(n,e,r),Bs(n,t,r)))}function Fs(e,t,n){Is(e,t,n,pu())}function Is(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Rs(e))zs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Er(s,o))return ai(e,t,i,0),Rl===null&&ii(),!1}catch{}if(n=oi(e,t,i,r),n!==null)return hu(n,e,r),Bs(n,t,r),!0}return!1}function Ls(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Rs(e)){if(t)throw Error(i(479))}else t=oi(e,n,r,2),t!==null&&hu(t,e,2)}function Rs(e){var t=e.alternate;return e===R||t!==null&&t===R}function zs(e,t){vo=_o=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Bs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}var Vs={readContext:ra,use:Io,useCallback:wo,useContext:wo,useEffect:wo,useImperativeHandle:wo,useLayoutEffect:wo,useInsertionEffect:wo,useMemo:wo,useReducer:wo,useRef:wo,useState:wo,useDebugValue:wo,useDeferredValue:wo,useTransition:wo,useSyncExternalStore:wo,useId:wo,useHostTransitionStatus:wo,useFormState:wo,useActionState:wo,useOptimistic:wo,useMemoCache:wo,useCacheRefresh:wo};Vs.useEffectEvent=wo;var Hs={readContext:ra,use:Io,useCallback:function(e,t){return Mo().memoizedState=[e,t===void 0?null:t],e},useContext:ra,useEffect:fs,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),us(4194308,4,vs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return us(4194308,4,e,t)},useInsertionEffect:function(e,t){us(4,2,e,t)},useMemo:function(e,t){var n=Mo();t=t===void 0?null:t;var r=e();if(yo){Ve(!0);try{e()}finally{Ve(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Mo();if(n!==void 0){var i=n(t);if(yo){Ve(!0);try{n(t)}finally{Ve(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ps.bind(null,R,e),[r.memoizedState,e]},useRef:function(e){var t=Mo();return e={current:e},t.memoizedState=e},useState:function(e){e=Jo(e);var t=e.queue,n=Fs.bind(null,R,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:bs,useDeferredValue:function(e,t){return Cs(Mo(),e,t)},useTransition:function(){var e=Jo(!1);return e=Ts.bind(null,R,e.queue,!0,!1),Mo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=R,a=Mo();if(L){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Rl===null)throw Error(i(349));Y&127||Uo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,fs(Go.bind(null,r,o,e),[e]),r.flags|=2048,cs(9,{destroy:void 0},Wo.bind(null,r,o,n,t),null),n},useId:function(){var e=Mo(),t=Rl.identifierPrefix;if(L){var n=Ai,r=ki;n=(r&~(1<<32-He(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=bo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[P]=t,o[dt]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Nc(t)}}return Rc(t),Pc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Nc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=fe.current,Ui(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=I,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[P]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||Bi(t,!0)}else e=Bd(e).createTextNode(r),e[P]=t,t.stateNode=e}return Rc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Ui(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[P]=t}else Wi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),e=!1}else n=Gi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(fo(t),t):(fo(t),null);if(t.flags&128)throw Error(i(558))}return Rc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Ui(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[P]=t}else Wi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),a=!1}else a=Gi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(fo(t),t):(fo(t),null)}return fo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Ic(t,t.updateQueue),Rc(t),null);case 4:return he(),e===null&&Sd(t.stateNode.containerInfo),Rc(t),null;case 10:return Zi(t.type),Rc(t),null;case 19:if(M(po),r=t.memoizedState,r===null)return Rc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Lc(r,!1);else{if(Wl!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=mo(e),o!==null){for(t.flags|=128,Lc(r,!1),e=o.updateQueue,t.updateQueue=e,Ic(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)F(n,e),n=n.sibling;return N(po,po.current&1|2),L&&ji(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ae()>tu&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304)}else{if(!a)if(e=mo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Ic(t,e),Lc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!L)return Rc(t),null}else 2*Ae()-r.renderingStartTime>tu&&n!==536870912&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Rc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ae(),e.sibling=null,n=po.current,N(po,a?n&1|2:n&1),L&&ji(t,r.treeForkCount),e);case 22:case 23:return fo(t),io(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Rc(t),t.subtreeFlags&6&&(t.flags|=8192)):Rc(t),n=t.updateQueue,n!==null&&Ic(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&M(ba),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Zi(la),Rc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Pi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Zi(la),he(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return _e(t),null;case 31:if(t.memoizedState!==null){if(fo(t),t.alternate===null)throw Error(i(340));Wi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(fo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Wi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return M(po),null;case 4:return he(),null;case 10:return Zi(t.type),null;case 22:case 23:return fo(t),io(),e!==null&&M(ba),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Zi(la),null;case 25:return null;default:return null}}function Vc(e,t){switch(Pi(t),t.tag){case 3:Zi(la),he();break;case 26:case 27:case 5:_e(t);break;case 4:he();break;case 31:t.memoizedState!==null&&fo(t);break;case 13:fo(t);break;case 19:M(po);break;case 10:Zi(t.type);break;case 22:case 23:fo(t),io(),e!==null&&M(ba);break;case 24:Zi(la)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{$a(t,n)}catch(t){Z(e,e.return,t)}}}function Gc(e,t,n){n.props=Ys(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[dt]=t}catch(t){Z(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=rn));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[P]=e,t[dt]=n}catch(t){Z(e,e.return,t)}}var W=!1,tl=!1,nl=!1,rl=typeof WeakSet==`function`?WeakSet:Set,il=null;function al(e,t){if(e=e.containerInfo,Rd=sp,e=jr(e),Mr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,il=t;il!==null;)if(t=il,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,il=e;else for(;il!==null;){switch(t=il,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[P]=e,Ct(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=kr(s,h),v=kr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=lu,lu=null;var o=au,s=su;if(iu=0,ou=au=null,su=0,q&6)throw Error(i(331));var c=q;if(q|=4,Nl(o.current),Tl(o,o.current,s,n),q=c,id(0,!1),Be&&typeof Be.onPostCommitFiberRoot==`function`)try{Be.onPostCommitFiberRoot(ze,o)}catch{}return!0}finally{A.p=a,k.T=r,Vu(e,t)}}function Wu(e,t,n){t=xi(n,t),t=ec(e.stateNode,t,2),e=Ka(e,t,2),e!==null&&(tt(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(ru===null||!ru.has(r))){e=xi(n,e),n=tc(2),r=Ka(t,n,2),r!==null&&(nc(n,r,t,e),tt(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Ll;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Hl=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Rl===e&&(Y&n)===n&&(Wl===4||Wl===3&&(Y&62914560)===Y&&300>Ae()-$l?!(q&2)&&Su(e,0):ql|=n,Yl===Y&&(Yl=0)),rd(e)}function qu(e,t){t===0&&(t=$e()),e=si(e,t),e!==null&&(tt(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return Ee(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-He(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=Y,a=Xe(r,r===Rl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ze(r,a)||(n=!0,ld(r,a));r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=Ae(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}iu!==0&&iu!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ht(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),Ct(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ht(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ht(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ht(n.imageSizes)+`"]`)):i+=`[href="`+Ht(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=m({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),Ct(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ht(r)+`"][href="`+Ht(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=m({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),Ct(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=St(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=m({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);Ct(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=St(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Ct(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=St(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Ct(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=fe.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=St(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=St(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=St(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ht(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return m({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),Ct(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ht(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ht(n.href)+`"]`);if(r)return t.instance=r,Ct(r),r;var a=m({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),Ct(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,Ct(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),Ct(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,Ct(a),a):(r=n,(a=mf.get(o))&&(r=m({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),Ct(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,Ct(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),Ct(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=g()})),v=`modulepreload`,y=function(e){return`/admin/`+e},b={},x=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,new URL(`../../../src/node/plugins/importAnalysisBuild.ts`,import.meta.url)).href}r=o(t.map(t=>{if(t=y(t,n),t=s(t),t in b)return;b[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:v,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},S=l(d(),1),C=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,w=/^[\\/]{2}/;function T(e,t){return t+e.replace(/\\/g,`/`)}var ee=`popstate`;function te(e){return typeof e==`object`&&!!e&&`pathname`in e&&`search`in e&&`hash`in e&&`state`in e&&`key`in e}function ne(e={}){function t(e,t){let n=t.state?.masked,{pathname:r,search:i,hash:a}=n||e.location;return ie(``,{pathname:r,search:i,hash:a},t.state&&t.state.usr||null,t.state&&t.state.key||`default`,n?{pathname:e.location.pathname,search:e.location.search,hash:e.location.hash}:void 0)}function n(e,t){return typeof t==`string`?t:ae(t)}return k(t,n,null,e)}function E(e,t){if(e===!1||e==null)throw Error(t)}function D(e,t){if(!e){typeof console<`u`&&console.warn(t);try{throw Error(t)}catch{}}}function O(){return Math.random().toString(36).substring(2,10)}function re(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function ie(e,t,n=null,r,i){return{pathname:typeof e==`string`?e:e.pathname,search:``,hash:``,...typeof t==`string`?oe(t):t,state:n,key:t&&t.key||r||O(),mask:i}}function ae({pathname:e=`/`,search:t=``,hash:n=``}){return t&&t!==`?`&&(e+=t.charAt(0)===`?`?t:`?`+t),n&&n!==`#`&&(e+=n.charAt(0)===`#`?n:`#`+n),e}function oe(e){let t={};if(e){let n=e.indexOf(`#`);n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf(`?`);r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function k(e,t,n,r={}){let{window:i=document.defaultView,v5Compat:a=!1}=r,o=i.history,s=`POP`,c=null,l=u();l??(l=0,o.replaceState({...o.state,idx:l},``));function u(){return(o.state||{idx:null}).idx}function d(){s=`POP`;let e=u(),t=e==null?null:e-l;l=e,c&&c({action:s,location:h.location,delta:t})}function f(e,t){s=`PUSH`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u()+1;let d=re(r,l),f=h.createHref(r.mask||r);try{o.pushState(d,``,f)}catch(e){if(e instanceof DOMException&&e.name===`DataCloneError`)throw e;i.location.assign(f)}a&&c&&c({action:s,location:h.location,delta:1})}function p(e,t){s=`REPLACE`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u();let i=re(r,l),d=h.createHref(r.mask||r);o.replaceState(i,``,d),a&&c&&c({action:s,location:h.location,delta:0})}function m(e){return A(i,e)}let h={get action(){return s},get location(){return e(i,o)},listen(e){if(c)throw Error(`A history only accepts one active listener`);return i.addEventListener(ee,d),c=e,()=>{i.removeEventListener(ee,d),c=null}},createHref(e){return t(i,e)},createURL:m,encodeLocation(e){let t=m(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:f,replace:p,go(e){return o.go(e)}};return h}function A(e,t,n=!1){let r=`http://localhost`;e&&(r=e.location.origin===`null`?e.location.href:e.location.origin),E(r,`No window.location.(origin|href) available to create URL`);let i=typeof t==`string`?t:ae(t);return i=i.replace(/ $/,`%20`),!n&&w.test(i)&&(i=r+i),new URL(i,r)}function se(e,t,n=`/`){return ce(e,t,n,!1)}function ce(e,t,n,r,i){let a=Te((typeof t==`string`?oe(t):t).pathname||`/`,n);if(a==null)return null;let o=i??j(e),s=null,c=we(a);for(let e=0;s==null&&e{let c={relativePath:s===void 0?e.path||``:s,caseSensitive:e.caseSensitive===!0,childrenIndex:a,route:e};if(c.relativePath.startsWith(`/`)){if(!c.relativePath.startsWith(r)&&o)return;E(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length)}let l=Ne([r,c.relativePath]),u=n.concat(c);e.children&&e.children.length>0&&(E(e.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${l}".`),M(e.children,t,u,l,o)),!(e.path==null&&!e.index)&&t.push({path:l,score:ve(l,e.index),routesMeta:u.map((e,t)=>{let[n,r]=Ce(e.relativePath,e.caseSensitive,t===u.length-1);return{...e,matcher:n,compiledParams:r}})})};return e.forEach((e,t)=>{if(e.path===``||!e.path?.includes(`?`))a(e,t);else for(let n of N(e.path))a(e,t,!0,n)}),t}function N(e){let t=e.split(`/`);if(t.length===0)return[];let[n,...r]=t,i=n.endsWith(`?`),a=n.replace(/\?$/,``);if(r.length===0)return i?[a,``]:[a];let o=N(r.join(`/`)),s=[];return s.push(...o.map(e=>e===``?a:[a,e].join(`/`))),i&&s.push(...o),s.map(t=>e.startsWith(`/`)&&t===``?`/`:t)}function ue(e){e.sort((e,t)=>e.score===t.score?ye(e.routesMeta.map(e=>e.childrenIndex),t.routesMeta.map(e=>e.childrenIndex)):t.score-e.score)}var de=/^:[\w-]+$/,fe=3,pe=2,me=1,he=10,ge=-2,_e=e=>e===`*`;function ve(e,t){let n=e.split(`/`),r=n.length;return n.some(_e)&&(r+=ge),t&&(r+=pe),n.filter(e=>!_e(e)).reduce((e,t)=>e+(de.test(t)?fe:t===``?me:he),r)}function ye(e,t){return e.length===t.length&&e.slice(0,-1).every((e,n)=>e===t[n])?e[e.length-1]-t[t.length-1]:0}function be(e,t,n=!1){let{routesMeta:r}=e,i={},a=`/`,o=[];for(let e=0;e{if(t===`*`){let e=s[r]||``;o=a.slice(0,a.length-e.length).replace(/(.)\/+$/,`$1`)}let i=s[r];return n&&!i?e[t]=void 0:e[t]=(i||``).replace(/%2F/g,`/`),e},{}),pathname:a,pathnameBase:o,pattern:e}}function Ce(e,t=!1,n=!0){D(e===`*`||!e.endsWith(`*`)||e.endsWith(`/*`),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,`/*`)}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,`/*`)}".`);let r=[],i=`^`+e.replace(/\/*\*?$/,``).replace(/^\/*/,`/`).replace(/[\\.*+^${}|()[\]]/g,`\\$&`).replace(/\/:([\w-]+)(\?)?/g,(e,t,n,i,a)=>{if(r.push({paramName:t,isOptional:n!=null}),n){let t=a.charAt(i+e.length);return t&&t!==`/`?`/([^\\/]*)`:`(?:/([^\\/]*))?`}return`/([^\\/]+)`}).replace(/\/([\w-]+)\?(\/|$)/g,`(/$1)?$2`);return e.endsWith(`*`)?(r.push({paramName:`*`}),i+=e===`*`||e===`/*`?`(.*)$`:`(?:\\/(.+)|\\/*)$`):n?i+=`\\/*$`:e!==``&&e!==`/`&&(i+=`(?:(?=\\/|$))`),[new RegExp(i,t?void 0:`i`),r]}function we(e){try{return e.split(`/`).map(e=>decodeURIComponent(e).replace(/\//g,`%2F`)).join(`/`)}catch(t){return D(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Te(e,t){if(t===`/`)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith(`/`)?t.length-1:t.length,r=e.charAt(n);return r&&r!==`/`?null:e.slice(n)||`/`}function Ee(e,t=`/`){let{pathname:n,search:r=``,hash:i=``}=typeof e==`string`?oe(e):e,a;return n?(n=Me(n),a=n.startsWith(`/`)?De(n.substring(1),`/`):De(n,t)):a=t,{pathname:a,search:Ie(r),hash:Le(i)}}function De(e,t){let n=Pe(t).split(`/`);return e.split(`/`).forEach(e=>{e===`..`?n.length>1&&n.pop():e!==`.`&&n.push(e)}),n.length>1?n.join(`/`):`/`}function Oe(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ke(e){return e.filter((e,t)=>t===0||e.route.path&&e.route.path.length>0)}function Ae(e){let t=ke(e);return t.map((e,n)=>n===t.length-1?e.pathname:e.pathnameBase)}function je(e,t,n,r=!1){let i;typeof e==`string`?i=oe(e):(i={...e},E(!i.pathname||!i.pathname.includes(`?`),Oe(`?`,`pathname`,`search`,i)),E(!i.pathname||!i.pathname.includes(`#`),Oe(`#`,`pathname`,`hash`,i)),E(!i.search||!i.search.includes(`#`),Oe(`#`,`search`,`hash`,i)));let a=e===``||i.pathname===``,o=a?`/`:i.pathname,s;if(o==null)s=n;else{let e=t.length-1;if(!r&&o.startsWith(`..`)){let t=o.split(`/`);for(;t[0]===`..`;)t.shift(),--e;i.pathname=t.join(`/`)}s=e>=0?t[e]:`/`}let c=Ee(i,s),l=o&&o!==`/`&&o.endsWith(`/`),u=(a||o===`.`)&&n.endsWith(`/`);return!c.pathname.endsWith(`/`)&&(l||u)&&(c.pathname+=`/`),c}var Me=e=>e.replace(/[\\/]{2,}/g,`/`),Ne=e=>Me(e.join(`/`)),Pe=e=>e.replace(/\/+$/,``),Fe=e=>Pe(e).replace(/^\/*/,`/`),Ie=e=>!e||e===`?`?``:e.startsWith(`?`)?e:`?`+e,Le=e=>!e||e===`#`?``:e.startsWith(`#`)?e:`#`+e,Re=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||``,this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function ze(e){return e!=null&&typeof e.status==`number`&&typeof e.statusText==`string`&&typeof e.internal==`boolean`&&`data`in e}function Be(e){return Ne(e.map(e=>e.route.path).filter(Boolean))||`/`}var Ve=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function He(e,t){let n=e;if(typeof n!=`string`||!C.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(Ve)try{let e=new URL(window.location.href),r=w.test(n)?new URL(T(n,e.protocol)):new URL(n),a=Te(r.pathname,t);r.origin===e.origin&&a!=null?n=a+r.search+r.hash:i=!0}catch{D(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join(`\0`);var Ue=[`POST`,`PUT`,`PATCH`,`DELETE`];new Set(Ue);var We=[`GET`,...Ue];new Set(We);var Ge=[`about:`,`blob:`,`chrome:`,`chrome-untrusted:`,`content:`,`data:`,`devtools:`,`file:`,`filesystem:`,`javascript:`];function Ke(e){try{return Ge.includes(new URL(e).protocol)}catch{return!1}}var qe=S.createContext(null);qe.displayName=`DataRouter`;var Je=S.createContext(null);Je.displayName=`DataRouterState`;var Ye=S.createContext(!1);function Xe(){return S.useContext(Ye)}var Ze=S.createContext({isTransitioning:!1});Ze.displayName=`ViewTransition`;var Qe=S.createContext(new Map);Qe.displayName=`Fetchers`;var $e=S.createContext(null);$e.displayName=`Await`;var et=S.createContext(null);et.displayName=`Navigation`;var tt=S.createContext(null);tt.displayName=`Location`;var nt=S.createContext({outlet:null,matches:[],isDataRoute:!1});nt.displayName=`Route`;var rt=S.createContext(null);rt.displayName=`RouteError`;var it=`REACT_ROUTER_ERROR`,at=`REDIRECT`,ot=`ROUTE_ERROR_RESPONSE`;function st(e){if(e.startsWith(`${it}:${at}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`&&typeof t.location==`string`&&typeof t.reloadDocument==`boolean`&&typeof t.replace==`boolean`)return t}catch{}}function ct(e){if(e.startsWith(`${it}:${ot}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`)return new Re(t.status,t.statusText,t.data)}catch{}}function lt(e,{relative:t}={}){E(ut(),`useHref() may be used only in the context of a component.`);let{basename:n,navigator:r}=S.useContext(et),{hash:i,pathname:a,search:o}=_t(e,{relative:t}),s=a;return n!==`/`&&(s=a===`/`?n:Ne([n,a])),r.createHref({pathname:s,search:o,hash:i})}function ut(){return S.useContext(tt)!=null}function P(){return E(ut(),`useLocation() may be used only in the context of a component.`),S.useContext(tt).location}var dt=`You should call navigate() in a React.useEffect(), not when your component is first rendered.`;function ft(e){S.useContext(et).static||S.useLayoutEffect(e)}function pt(){let{isDataRoute:e}=S.useContext(nt);return e?It():mt()}function mt(){E(ut(),`useNavigate() may be used only in the context of a component.`);let e=S.useContext(qe),{basename:t,navigator:n}=S.useContext(et),{matches:r}=S.useContext(nt),{pathname:i}=P(),a=JSON.stringify(Ae(r)),o=S.useRef(!1);return ft(()=>{o.current=!0}),S.useCallback((r,s={})=>{if(D(o.current,dt),!o.current)return;if(typeof r==`number`){n.go(r);return}let c=je(r,JSON.parse(a),i,s.relative===`path`);e==null&&t!==`/`&&(c.pathname=c.pathname===`/`?t:Ne([t,c.pathname])),(s.replace?n.replace:n.push)(c,s.state,s)},[t,n,a,i,e])}var ht=S.createContext(null);function gt(e){let t=S.useContext(nt).outlet;return S.useMemo(()=>t&&S.createElement(ht.Provider,{value:e},t),[t,e])}function _t(e,{relative:t}={}){let{matches:n}=S.useContext(nt),{pathname:r}=P(),i=JSON.stringify(Ae(n));return S.useMemo(()=>je(e,JSON.parse(i),r,t===`path`),[e,i,r,t])}function vt(e,t){return yt(e,t)}function yt(e,t,n){E(ut(),`useRoutes() may be used only in the context of a component.`);let{navigator:r}=S.useContext(et),{matches:i}=S.useContext(nt),a=i[i.length-1],o=a?a.params:{},s=a?a.pathname:`/`,c=a?a.pathnameBase:`/`,l=a&&a.route;{let e=l&&l.path||``;Rt(s,!l||e.endsWith(`*`)||e.endsWith(`*?`),`You rendered descendant (or called \`useRoutes()\`) at "${s}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. - -Please change the parent to .`)}let u=P(),d;if(t){let e=typeof t==`string`?oe(t):t;E(c===`/`||e.pathname?.startsWith(c),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${c}" but pathname "${e.pathname}" was given in the \`location\` prop.`),d=e}else d=u;let f=d.pathname||`/`,p=f;if(c!==`/`){let e=c.replace(/^\//,``).split(`/`);p=`/`+f.replace(/^\//,``).split(`/`).slice(e.length).join(`/`)}let m=n&&n.state.matches.length?n.state.matches.map(e=>Object.assign(e,{route:n.manifest[e.route.id]||e.route})):se(e,{pathname:p});D(l||m!=null,`No routes matched location "${d.pathname}${d.search}${d.hash}" `),D(m==null||m[m.length-1].route.element!==void 0||m[m.length-1].route.Component!==void 0||m[m.length-1].route.lazy!==void 0,`Matched leaf route at location "${d.pathname}${d.search}${d.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let h=Et(m&&m.map(e=>Object.assign({},e,{params:Object.assign({},o,e.params),pathname:Ne([c,r.encodeLocation?r.encodeLocation(e.pathname.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathname]),pathnameBase:e.pathnameBase===`/`?c:Ne([c,r.encodeLocation?r.encodeLocation(e.pathnameBase.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathnameBase])})),i,n);return t&&h?S.createElement(tt.Provider,{value:{location:{pathname:`/`,search:``,hash:``,state:null,key:`default`,mask:void 0,...d},navigationType:`POP`}},h):h}function bt(){let e=Ft(),t=ze(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r=`rgba(200,200,200, 0.5)`,i={padding:`0.5rem`,backgroundColor:r},a={padding:`2px 4px`,backgroundColor:r},o=null;return console.error(`Error handled by React Router default ErrorBoundary:`,e),o=S.createElement(S.Fragment,null,S.createElement(`p`,null,`💿 Hey developer 👋`),S.createElement(`p`,null,`You can provide a way better UX than this when your app throws errors by providing your own `,S.createElement(`code`,{style:a},`ErrorBoundary`),` or`,` `,S.createElement(`code`,{style:a},`errorElement`),` prop on your route.`)),S.createElement(S.Fragment,null,S.createElement(`h2`,null,`Unexpected Application Error!`),S.createElement(`h3`,{style:{fontStyle:`italic`}},t),n?S.createElement(`pre`,{style:i},n):null,o)}var xt=S.createElement(bt,null),St=class extends S.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!==`idle`&&e.revalidation===`idle`?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error===void 0?t.error:e.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error(`React Router caught the following error during render`,e)}render(){let e=this.state.error;if(this.context&&typeof e==`object`&&e&&`digest`in e&&typeof e.digest==`string`){let t=ct(e.digest);t&&(e=t)}let t=e===void 0?this.props.children:S.createElement(nt.Provider,{value:this.props.routeContext},S.createElement(rt.Provider,{value:e,children:this.props.component}));return this.context?S.createElement(wt,{error:e},t):t}};St.contextType=Ye;var Ct=new WeakMap;function wt({children:e,error:t}){let{basename:n}=S.useContext(et);if(typeof t==`object`&&t&&`digest`in t&&typeof t.digest==`string`){let e=st(t.digest);if(e){let r=Ct.get(t);if(r)throw r;let i=He(e.location,n),a=i.absoluteURL||i.to;if(Ke(a))throw Error(`Invalid redirect location`);if(Ve&&!Ct.get(t))if(i.isExternal||e.reloadDocument)window.location.href=a;else{let n=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(i.to,{replace:e.replace}));throw Ct.set(t,n),n}return S.createElement(`meta`,{httpEquiv:`refresh`,content:`0;url=${a}`})}}return e}function Tt({routeContext:e,match:t,children:n}){let r=S.useContext(qe);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),S.createElement(nt.Provider,{value:e},n)}function Et(e,t=[],n){let r=n?.state;if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let i=e,a=r?.errors;if(a!=null){let e=i.findIndex(e=>e.route.id&&a?.[e.route.id]!==void 0);E(e>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(a).join(`,`)}`),i=i.slice(0,Math.min(i.length,e+1))}let o=!1,s=-1;if(n&&r){o=r.renderFallback;for(let e=0;e=0?i.slice(0,s+1):[i[0]];break}}}}let c=n?.onError,l=r&&c?(e,t)=>{c(e,{location:r.location,params:r.matches?.[0]?.params??{},pattern:Be(r.matches),errorInfo:t})}:void 0;return i.reduceRight((e,n,c)=>{let u,d=!1,f=null,p=null;r&&(u=a&&n.route.id?a[n.route.id]:void 0,f=n.route.errorElement||xt,o&&(s<0&&c===0?(Rt(`route-fallback`,!1,"No `HydrateFallback` element provided to render during initial hydration"),d=!0,p=null):s===c&&(d=!0,p=n.route.hydrateFallbackElement||null)));let m=t.concat(i.slice(0,c+1)),h=()=>{let t;return t=u?f:d?p:n.route.Component?S.createElement(n.route.Component,null):n.route.element?n.route.element:e,S.createElement(Tt,{match:n,routeContext:{outlet:e,matches:m,isDataRoute:r!=null},children:t})};return r&&(n.route.ErrorBoundary||n.route.errorElement||c===0)?S.createElement(St,{location:r.location,revalidation:r.revalidation,component:f,error:u,children:h(),routeContext:{outlet:null,matches:m,isDataRoute:!0},onError:l}):h()},null)}function Dt(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Ot(e){let t=S.useContext(qe);return E(t,Dt(e)),t}function kt(e){let t=S.useContext(Je);return E(t,Dt(e)),t}function At(e){let t=S.useContext(nt);return E(t,Dt(e)),t}function jt(e){let t=At(e),n=t.matches[t.matches.length-1];return E(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function Mt(){return jt(`useRouteId`)}function Nt(){let e=kt(`useNavigation`);return S.useMemo(()=>{let{matches:t,historyAction:n,...r}=e.navigation;return r},[e.navigation])}function Pt(){let{matches:e,loaderData:t}=kt(`useMatches`);return S.useMemo(()=>e.map(e=>le(e,t)),[e,t])}function Ft(){let e=S.useContext(rt),t=kt(`useRouteError`),n=jt(`useRouteError`);return e===void 0?t.errors?.[n]:e}function It(){let{router:e}=Ot(`useNavigate`),t=jt(`useNavigate`),n=S.useRef(!1);return ft(()=>{n.current=!0}),S.useCallback(async(r,i={})=>{D(n.current,dt),n.current&&(typeof r==`number`?await e.navigate(r):await e.navigate(r,{fromRouteId:t,...i}))},[e,t])}var Lt={};function Rt(e,t,n){!t&&!Lt[e]&&(Lt[e]=!0,D(!1,n))}S.memo(zt);function zt({routes:e,manifest:t,future:n,state:r,isStatic:i,onError:a}){return yt(e,void 0,{manifest:t,state:r,isStatic:i,onError:a,future:n})}function Bt({to:e,replace:t,state:n,relative:r}){E(ut(),` may be used only in the context of a component.`);let{static:i}=S.useContext(et);D(!i,` must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.`);let{matches:a}=S.useContext(nt),{pathname:o}=P(),s=pt(),c=je(e,Ae(a),o,r===`path`),l=JSON.stringify(c);return S.useEffect(()=>{s(JSON.parse(l),{replace:t,state:n,relative:r})},[s,l,r,t,n]),null}function Vt(e){return gt(e.context)}function Ht(e){E(!1,`A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .`)}function Ut({basename:e=`/`,children:t=null,location:n,navigationType:r=`POP`,navigator:i,static:a=!1,useTransitions:o}){E(!ut(),`You cannot render a inside another . You should never have more than one in your app.`);let s=e.replace(/^\/*/,`/`),c=S.useMemo(()=>({basename:s,navigator:i,static:a,useTransitions:o,future:{}}),[s,i,a,o]);typeof n==`string`&&(n=oe(n));let{pathname:l=`/`,search:u=``,hash:d=``,state:f=null,key:p=`default`,mask:m}=n,h=S.useMemo(()=>{let e=Te(l,s);return e==null?null:{location:{pathname:e,search:u,hash:d,state:f,key:p,mask:m},navigationType:r}},[s,l,u,d,f,p,r,m]);return D(h!=null,` is not able to match the URL "${l}${u}${d}" because it does not start with the basename, so the won't render anything.`),h==null?null:S.createElement(et.Provider,{value:c},S.createElement(tt.Provider,{children:t,value:h}))}function Wt({children:e,location:t}){return vt(Gt(e),t)}S.Component;function Gt(e,t=[]){let n=[];return S.Children.forEach(e,(e,r)=>{if(!S.isValidElement(e))return;let i=[...t,r];if(e.type===S.Fragment){n.push.apply(n,Gt(e.props.children,i));return}E(e.type===Ht,`[${typeof e.type==`string`?e.type:e.type.name}] is not a component. All component children of must be a or `),E(!e.props.index||!e.props.children,`An index route cannot have child routes.`);let a={id:e.props.id||i.join(`-`),caseSensitive:e.props.caseSensitive,element:e.props.element,Component:e.props.Component,index:e.props.index,path:e.props.path,middleware:e.props.middleware,loader:e.props.loader,action:e.props.action,hydrateFallbackElement:e.props.hydrateFallbackElement,HydrateFallback:e.props.HydrateFallback,errorElement:e.props.errorElement,ErrorBoundary:e.props.ErrorBoundary,hasErrorBoundary:e.props.hasErrorBoundary===!0||e.props.ErrorBoundary!=null||e.props.errorElement!=null,shouldRevalidate:e.props.shouldRevalidate,handle:e.props.handle,lazy:e.props.lazy};e.props.children&&(a.children=Gt(e.props.children,i)),n.push(a)}),n}var Kt=`get`,qt=`application/x-www-form-urlencoded`;function Jt(e){return typeof HTMLElement<`u`&&e instanceof HTMLElement}function Yt(e){return Jt(e)&&e.tagName.toLowerCase()===`button`}function Xt(e){return Jt(e)&&e.tagName.toLowerCase()===`form`}function Zt(e){return Jt(e)&&e.tagName.toLowerCase()===`input`}function Qt(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function $t(e,t){return e.button===0&&(!t||t===`_self`)&&!Qt(e)}var en=null;function tn(){if(en===null)try{new FormData(document.createElement(`form`),0),en=!1}catch{en=!0}return en}var nn=new Set([`application/x-www-form-urlencoded`,`multipart/form-data`,`text/plain`]);function rn(e){return e!=null&&!nn.has(e)?(D(!1,`"${e}" is not a valid \`encType\` for \`\`/\`\` and will default to "${qt}"`),null):e}function an(e,t){let n,r,i,a,o;if(Xt(e)){let o=e.getAttribute(`action`);r=o?Te(o,t):null,n=e.getAttribute(`method`)||Kt,i=rn(e.getAttribute(`enctype`))||qt,a=new FormData(e)}else if(Yt(e)||Zt(e)&&(e.type===`submit`||e.type===`image`)){let o=e.form;if(o==null)throw Error(`Cannot submit a diff --git a/pets-fe/pages/onboarding/onboarding.js b/pets-fe/pages/onboarding/onboarding.js index 705b11a..6959763 100644 --- a/pets-fe/pages/onboarding/onboarding.js +++ b/pets-fe/pages/onboarding/onboarding.js @@ -3,6 +3,36 @@ const api = require('../../utils/api.js'); const GENDERS = ['男孩', '女孩', '不确定']; +// 与后端 service.AgeStages 一致:「刚到家」不是年龄阶段,它由到家日期单独决定 +const STAGE_OPTIONS = [ + { key: '幼年期', desc: '疫苗针次、驱虫、体重增长、社会化训练' }, + { key: '成年期', desc: '体重控制、口腔、日常健康管理' }, + { key: '老年期', desc: '慢病监测、半年体检、用药与护理' }, +]; + +function today() { + const d = new Date(); + const p = (n) => (n < 10 ? '0' + n : '' + n); + return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate()); +} + +function monthsSince(dateStr) { + const b = new Date(dateStr); + const now = new Date(); + let m = (now.getFullYear() - b.getFullYear()) * 12 + (now.getMonth() - b.getMonth()); + if (now.getDate() < b.getDate()) m--; + return m < 0 ? 0 : m; +} + +// 与后端 StageFromBirthday 同一套规则:12 月龄成年、7 岁进入老年 +function stageFromBirthday(birthday) { + if (!birthday) return ''; + const m = monthsSince(birthday); + if (m < 12) return '幼年期'; + if (m >= 84) return '老年期'; + return '成年期'; +} + function ageFromBirthday(bdayStr) { if (!bdayStr) return ''; const b = new Date(bdayStr); @@ -21,7 +51,11 @@ Page({ birthday: '', genderIdx: 0, weight: '', - stage: '幼年期', + arrivedAt: '', + today: '', + stage: '', + stageAuto: '', + stageOptions: STAGE_OPTIONS, goals: [ { label: '不知道每天该做什么', on: true }, { label: '疫苗驱虫怕忘记', on: true }, @@ -33,6 +67,7 @@ Page({ submitting: false, }, onLoad() { + this.setData({ today: today(), arrivedAt: today() }); // 已有宠物则直接进首页 store .ready() @@ -52,7 +87,15 @@ Page({ }, onName(e) { this.setData({ petName: e.detail.value }); }, onWeight(e) { this.setData({ weight: e.detail.value }); }, - onBirthday(e) { this.setData({ birthday: e.detail.value }); }, + onBirthday(e) { + const birthday = e.detail.value; + const auto = stageFromBirthday(birthday); + const patch = { birthday, stageAuto: auto }; + // 用户手动选过就尊重他的选择,否则跟着生日走 + if (!this._stageTouched) patch.stage = auto; + this.setData(patch); + }, + onArrived(e) { this.setData({ arrivedAt: e.detail.value }); }, selectGender(e) { this.setData({ genderIdx: Number(e.currentTarget.dataset.index) }); }, // 先随便看看:不建数据,直接进首页浏览(无宠物时首页显示空态) skipBrowse() { wx.switchTab({ url: '/pages/home/home' }); }, @@ -61,10 +104,39 @@ Page({ wx.showToast({ title: '给它起个名字吧', icon: 'none' }); return; } + const w = parseFloat(this.data.weight); + // 体重会进趋势图和用药剂量参考,乱填不如不填 + if (this.data.weight && !(w > 0 && w < 120)) { + wx.showToast({ title: '体重看起来不太对', icon: 'none' }); + return; + } + if (!this.data.birthday) { + wx.showToast({ title: '生日决定疫苗和驱虫节奏,估个大概也行', icon: 'none' }); + return; + } this.nextStep(); }, chooseStage(e) { - this.setData({ stage: e.currentTarget.dataset.stage }); + const stage = e.currentTarget.dataset.stage; + const auto = this.data.stageAuto; + // 改成和生日矛盾的阶段是允许的(领养估的生日可能不准,大型犬发育也慢), + // 但要先说清楚代价:阶段决定疫苗针次怎么排,选错会漏针 + if (auto && stage !== auto) { + wx.showModal({ + title: '和生日对不上', + content: `按生日算它应该在「${auto}」。改成「${stage}」的话,疫苗针次和驱虫周期会按${stage}安排。确定要改吗?`, + confirmText: '确定改', + success: (res) => { + if (res.confirm) { + this._stageTouched = true; + this.setData({ stage }); + } + }, + }); + return; + } + this._stageTouched = true; + this.setData({ stage }); }, toggleGoal(e) { const i = e.currentTarget.dataset.index; @@ -80,8 +152,9 @@ Page({ type: this.data.petType, gender: GENDERS[this.data.genderIdx], birthday: this.data.birthday, + arrived_at: this.data.arrivedAt, weight: this.data.weight, - stage: this.data.stage, + stage: this.data.stage || this.data.stageAuto, age: ageFromBirthday(this.data.birthday), goals: this.data.goals.filter((g) => g.on).map((g) => g.label), }; diff --git a/pets-fe/pages/onboarding/onboarding.wxml b/pets-fe/pages/onboarding/onboarding.wxml index a95f79f..ebbc0ba 100644 --- a/pets-fe/pages/onboarding/onboarding.wxml +++ b/pets-fe/pages/onboarding/onboarding.wxml @@ -40,10 +40,15 @@ - - - {{birthday || '选择日期'}} + + + {{birthday || '选择日期(不确定可以估个大概)'}} + + + {{arrivedAt || '选择日期'}} + + 刚到家不满 30 天的话,会额外安排一组安置期任务 男孩 女孩 @@ -58,16 +63,16 @@ 它现在处于哪个阶段? - 阶段会决定今日任务、提醒和 AI 建议。 + 阶段决定疫苗节奏、驱虫周期和每天要做的事,选错整套计划都会偏。 + + 已按生日自动判断为「{{stageAuto}}」,不对可以改 + - - 幼年期疫苗、驱虫、体重增长、行为训练 - - 刚到家 0-30 天适应环境、饮食稳定、基础照护 - - 成年期体重、饮食、日常健康管理 - - 老年期慢病、体检、用药和护理 + + {{item.key}}按生日推荐 + {{item.desc}} + @@ -75,7 +80,7 @@ 你最想解决什么? - 多选,我们会据此为你定制计划。 + 勾上的会变成真的提醒和任务,没勾的不会打扰你。 {{item.label}} diff --git a/pets-fe/pages/onboarding/onboarding.wxss b/pets-fe/pages/onboarding/onboarding.wxss index 69f5419..34ed5ad 100644 --- a/pets-fe/pages/onboarding/onboarding.wxss +++ b/pets-fe/pages/onboarding/onboarding.wxss @@ -57,3 +57,14 @@ width:44rpx;height:44rpx;border-radius:50%;background:var(--green);color:#fff; display:flex;align-items:center;justify-content:center;flex:none; } + +.field-tip{margin-top:var(--sp-2);color:var(--muted);font-size:var(--fs-cap);line-height:1.5} +.stage-auto{ + display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-3); + padding:var(--sp-3) var(--sp-4);border-radius:var(--r-md); + background:var(--green-soft);color:var(--green-ink);font-size:var(--fs-sm); +} +.stage-hint{ + margin-left:var(--sp-2);padding:2rpx var(--sp-2);border-radius:var(--r-full); + background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap);font-weight:var(--fw); +} -- 2.52.0 From 7159930d9c714af9cb7e8e335812ff092466721a Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 12:55:22 +0800 Subject: [PATCH 11/58] =?UTF-8?q?feat(admin):=20=E9=9A=8F=E6=9C=BA?= =?UTF-8?q?=E6=98=B5=E7=A7=B0=20+=20=E5=BB=BA=E6=A1=A3=E6=95=B0=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=20+=20=E5=B8=96=E5=AD=90=E5=8F=91=E5=B8=83=E6=97=B6?= =?UTF-8?q?=E9=97=B4=20+=2016=20=E7=AF=87=E6=96=B0=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 新用户昵称 微信登录拿不到昵称(要用户主动授权),原来一律叫「微信用户」, 社区里一屏全是同名,后台也没法区分。改成随机生成「铲屎官12138」 这种形式:10 个前缀 × 5 位数字,落库前查重,撞了重试。 新增 users.nickname_auto 标记这个昵称是系统生成的。原来判断该不该 用微信授权昵称覆盖,靠的是「昵称是不是等于『微信用户』」这个字符串 比较,改成随机昵称后这招就失效了。有标记位才能安全覆盖,同时保证 用户自己改过的昵称不会被冲掉(改昵称时会把标记置 false)。 ## 用户管理 加「宠物档案」列,显示每个用户建了几个档。用一次 GROUP BY 查完 当页所有人,不是每行一次 count——那会是 N+1。 ## 帖子审核 加发布时间列。今天的显示「今天 14:48」,昨天的显示「昨天」, 更早的显示日期——审核时关心的是「多久以前发的」而不是完整时间戳。 ## 文章 新增 16 篇,连同原有 4 篇共 20 篇,每篇 400-570 字: 猫 5 篇(新猫到家第一周 / 猫砂盆 / 公猫尿闭 / 掉毛毛球 / 老年猫信号) 狗 5 篇(社会化关键期 / 定点排便 / 遛狗时长 / 刷牙 / 中暑防护) 通用 6 篇(体重趋势 / 驱虫周期 / 绝育 / 急诊清单 / 就医准备 / 养宠预算) 沿用和 AI 助手一样的安全护栏:不做诊断、不给药物剂量,凡是可能 延误病情的都写清「什么时候必须去医院」。犬用驱虫药对猫的致死风险 这类真实事故也写进去了。 seedArticles 从「库空才插」改成「按标题补缺失」,以后往内置清单加 文章,老库启动也能拿到。 Co-Authored-By: Claude Opus 5 --- .../{index-D8GFrwWw.js => index-nel7hMHL.js} | 26 +- pets-be/internal/admin/dist/index.html | 2 +- pets-be/internal/database/articles_more.go | 501 ++++++++++++++++++ pets-be/internal/database/seed.go | 22 +- pets-be/internal/handler/auth.go | 5 +- pets-be/internal/model/user.go | 16 +- pets-be/internal/service/admin.go | 32 ++ pets-be/internal/service/auth.go | 9 +- pets-be/internal/service/nickname.go | 45 ++ pets-be/web/admin/src/pages/Posts.tsx | 19 + pets-be/web/admin/src/pages/Users.tsx | 4 + 11 files changed, 652 insertions(+), 29 deletions(-) rename pets-be/internal/admin/dist/assets/{index-D8GFrwWw.js => index-nel7hMHL.js} (50%) create mode 100644 pets-be/internal/database/articles_more.go create mode 100644 pets-be/internal/service/nickname.go diff --git a/pets-be/internal/admin/dist/assets/index-D8GFrwWw.js b/pets-be/internal/admin/dist/assets/index-nel7hMHL.js similarity index 50% rename from pets-be/internal/admin/dist/assets/index-D8GFrwWw.js rename to pets-be/internal/admin/dist/assets/index-nel7hMHL.js index f6d922d..088b80c 100644 --- a/pets-be/internal/admin/dist/assets/index-D8GFrwWw.js +++ b/pets-be/internal/admin/dist/assets/index-nel7hMHL.js @@ -5,8 +5,8 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r= `);for(i=r=0;ri||c[r]!==l[i]){var u=` `+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{xe=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?be(n):``}function Ce(e,t){switch(e.tag){case 26:case 27:case 5:return be(e.type);case 16:return be(`Lazy`);case 13:return e.child!==t&&t!==null?be(`Suspense Fallback`):be(`Suspense`);case 19:return be(`SuspenseList`);case 0:case 15:return Se(e.type,!1);case 11:return Se(e.type.render,!1);case 1:return Se(e.type,!0);case 31:return be(`Activity`);default:return``}}function we(e){try{var t=``,n=null;do t+=Ce(e,n),n=e,e=e.return;while(e);return t}catch(e){return` Error generating stack: `+e.message+` -`+e.stack}}var Te=Object.prototype.hasOwnProperty,Ee=t.unstable_scheduleCallback,De=t.unstable_cancelCallback,Oe=t.unstable_shouldYield,ke=t.unstable_requestPaint,Ae=t.unstable_now,je=t.unstable_getCurrentPriorityLevel,Me=t.unstable_ImmediatePriority,Ne=t.unstable_UserBlockingPriority,Pe=t.unstable_NormalPriority,Fe=t.unstable_LowPriority,Ie=t.unstable_IdlePriority,Le=t.log,Re=t.unstable_setDisableYieldValue,ze=null,Be=null;function Ve(e){if(typeof Le==`function`&&Re(e),Be&&typeof Be.setStrictMode==`function`)try{Be.setStrictMode(ze,e)}catch{}}var He=Math.clz32?Math.clz32:Ge,Ue=Math.log,We=Math.LN2;function Ge(e){return e>>>=0,e===0?32:31-(Ue(e)/We|0)|0}var Ke=256,qe=262144,Je=4194304;function Ye(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Xe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ye(n))):i=Ye(o):i=Ye(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ye(n))):i=Ye(o)):i=Ye(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ze(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function $e(){var e=Je;return Je<<=1,!(Je&62914560)&&(Je=4194304),e}function et(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function tt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nt(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),hn=!1;if(mn)try{var gn={};Object.defineProperty(gn,"passive",{get:function(){hn=!0}}),window.addEventListener(`test`,gn,gn),window.removeEventListener(`test`,gn,gn)}catch{hn=!1}var _n=null,vn=null,yn=null;function bn(){if(yn)return yn;var e,t=vn,n=t.length,r,i=`value`in _n?_n.value:_n.textContent,a=i.length;for(e=0;e=Qn),tr=` `,nr=!1;function rr(e,t){switch(e){case`keyup`:return Xn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function ir(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ar=!1;function or(e,t){switch(e){case`compositionend`:return ir(t);case`keypress`:return t.which===32?(nr=!0,tr):null;case`textInput`:return e=t.data,e===tr&&nr?null:e;default:return null}}function sr(e,t){if(ar)return e===`compositionend`||!Zn&&rr(e,t)?(e=bn(),yn=vn=_n=null,ar=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=kr(n)}}function jr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?jr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Mr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Vt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Vt(e.document)}return t}function Nr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Pr=mn&&`documentMode`in document&&11>=document.documentMode,Fr=null,Ir=null,Lr=null,Rr=!1;function zr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Rr||Fr==null||Fr!==Vt(r)||(r=Fr,`selectionStart`in r&&Nr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Lr&&Or(Lr,r)||(Lr=r,r=Td(Ir,`onSelect`),0>=o,i-=o,Ai=1<<32-He(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),I&&Mi(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),I&&Mi(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return I&&Mi(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),I&&Mi(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===ne&&ja(l)===r.type){n(e,r.sibling),c=a(r,o.props),Ra(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=_i(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=gi(o.type,o.key,o.props,null,e.mode,c),Ra(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=bi(o,e.mode,c),c.return=e,e=c}return s(e);case ne:return o=ja(o),b(e,r,o,c)}if(oe(o))return h(e,r,o,c);if(re(o)){if(l=re(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,La(o),c);if(o.$$typeof===C)return b(e,r,aa(e,o),c);za(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=vi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Ia=0;var i=b(e,t,n,r);return Fa=null,i}catch(t){if(t===Ta||t===Da)throw t;var a=pi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Va=Ba(!0),Ha=Ba(!1),Ua=!1;function Wa(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ga(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ka(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function qa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,q&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=ui(e),li(e,null,n),t}return oi(e,r,t,n),ui(e)}function Ja(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}function Ya(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Xa=!1;function Za(){if(Xa){var e=ga;if(e!==null)throw e}}function Qa(e,t,n,r){Xa=!1;var i=e.updateQueue;Ua=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(X&f)===f:(r&f)===f){f!==0&&f===ha&&(Xa=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=m({},d,f);break a;case 2:Ua=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Wl|=o,e.lanes=o,e.memoizedState=d}}function $a(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function eo(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,zs(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Rs(e,t,ya(c,r),fu(e)):Rs(e,t,r,fu(e))}catch(n){Rs(e,t,{then:function(){},status:`rejected`,reason:n},fu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function Os(){}function ks(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=As(e).queue;Ds(e,a,t,se,n===null?Os:function(){return js(e),n(r)})}function As(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:se,baseState:se,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Bo,lastRenderedState:se},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Bo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function js(e){var t=As(e);t.next===null&&(t=e.alternate.memoizedState),Rs(e,t.next.queue,{},fu())}function Ms(){return ia(Qf)}function Ns(){return Fo().memoizedState}function Ps(){return Fo().memoizedState}function Fs(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=fu();e=Ka(n);var r=qa(t,e,n);r!==null&&(mu(r,t,n),Ja(r,t,n)),t={cache:da()},e.payload=t;return}t=t.return}}function Is(e,t,n){var r=fu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Bs(e)?Vs(t,n):(n=si(e,t,n,r),n!==null&&(mu(n,e,r),Hs(n,t,r)))}function Ls(e,t,n){Rs(e,t,n,fu())}function Rs(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Bs(e))Vs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Dr(s,o))return oi(e,t,i,0),J===null&&ai(),!1}catch{}if(n=si(e,t,i,r),n!==null)return mu(n,e,r),Hs(n,t,r),!0}return!1}function zs(e,t,n,r){if(r={lane:2,revertLane:ud(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Bs(e)){if(t)throw Error(i(479))}else t=si(e,n,r,2),t!==null&&mu(t,e,2)}function Bs(e){var t=e.alternate;return e===L||t!==null&&t===L}function Vs(e,t){bo=yo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Hs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}var Us={readContext:ia,use:Ro,useCallback:Eo,useContext:Eo,useEffect:Eo,useImperativeHandle:Eo,useLayoutEffect:Eo,useInsertionEffect:Eo,useMemo:Eo,useReducer:Eo,useRef:Eo,useState:Eo,useDebugValue:Eo,useDeferredValue:Eo,useTransition:Eo,useSyncExternalStore:Eo,useId:Eo,useHostTransitionStatus:Eo,useFormState:Eo,useActionState:Eo,useOptimistic:Eo,useMemoCache:Eo,useCacheRefresh:Eo};Us.useEffectEvent=Eo;var Ws={readContext:ia,use:Ro,useCallback:function(e,t){return Po().memoizedState=[e,t===void 0?null:t],e},useContext:ia,useEffect:ms,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),fs(4194308,4,bs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return fs(4194308,4,e,t)},useInsertionEffect:function(e,t){fs(4,2,e,t)},useMemo:function(e,t){var n=Po();t=t===void 0?null:t;var r=e();if(xo){Ve(!0);try{e()}finally{Ve(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Po();if(n!==void 0){var i=n(t);if(xo){Ve(!0);try{n(t)}finally{Ve(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Is.bind(null,L,e),[r.memoizedState,e]},useRef:function(e){var t=Po();return e={current:e},t.memoizedState=e},useState:function(e){e=Xo(e);var t=e.queue,n=Ls.bind(null,L,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:Ss,useDeferredValue:function(e,t){return Ts(Po(),e,t)},useTransition:function(){var e=Xo(!1);return e=Ds.bind(null,L,e.queue,!0,!1),Po().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=L,a=Po();if(I){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),J===null)throw Error(i(349));X&127||Go(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,ms(qo.bind(null,r,o,e),[e]),r.flags|=2048,us(9,{destroy:void 0},Ko.bind(null,r,o,n,t),null),n},useId:function(){var e=Po(),t=J.identifierPrefix;if(I){var n=ji,r=Ai;n=(r&~(1<<32-He(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=So++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[dt]=t,o[ft]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Fc(t)}}return H(t),Ic(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Fc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=fe.current,Wi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=F,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[dt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||jd(e.nodeValue,n)),e||Vi(t,!0)}else e=Bd(e).createTextNode(r),e[dt]=t,t.stateNode=e}return H(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Wi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[dt]=t}else Gi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;H(t),e=!1}else n=Ki(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(po(t),t):(po(t),null);if(t.flags&128)throw Error(i(558))}return H(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Wi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[dt]=t}else Gi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;H(t),a=!1}else a=Ki(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(po(t),t):(po(t),null)}return po(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Rc(t,t.updateQueue),H(t),null);case 4:return he(),e===null&&xd(t.stateNode.containerInfo),H(t),null;case 10:return Qi(t.type),H(t),null;case 19:if(M(mo),r=t.memoizedState,r===null)return H(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)zc(r,!1);else{if(Ul!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=ho(e),o!==null){for(t.flags|=128,zc(r,!1),e=o.updateQueue,t.updateQueue=e,Rc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)P(n,e),n=n.sibling;return N(mo,mo.current&1|2),I&&Mi(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ae()>eu&&(t.flags|=128,a=!0,zc(r,!1),t.lanes=4194304)}else{if(!a)if(e=ho(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Rc(t,e),zc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!I)return H(t),null}else 2*Ae()-r.renderingStartTime>eu&&n!==536870912&&(t.flags|=128,a=!0,zc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(H(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ae(),e.sibling=null,n=mo.current,N(mo,a?n&1|2:n&1),I&&Mi(t,r.treeForkCount),e);case 22:case 23:return po(t),ao(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(H(t),t.subtreeFlags&6&&(t.flags|=8192)):H(t),n=t.updateQueue,n!==null&&Rc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&M(xa),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Qi(ua),H(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Vc(e,t){switch(Fi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Qi(ua),he(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return _e(t),null;case 31:if(t.memoizedState!==null){if(po(t),t.alternate===null)throw Error(i(340));Gi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(po(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Gi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return M(mo),null;case 4:return he(),null;case 10:return Qi(t.type),null;case 22:case 23:return po(t),ao(),e!==null&&M(xa),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Qi(ua),null;case 25:return null;default:return null}}function Hc(e,t){switch(Fi(t),t.tag){case 3:Qi(ua),he();break;case 26:case 27:case 5:_e(t);break;case 4:he();break;case 31:t.memoizedState!==null&&po(t);break;case 13:po(t);break;case 19:M(mo);break;case 10:Qi(t.type);break;case 22:case 23:po(t),ao(),e!==null&&M(xa);break;case 24:Qi(ua)}}function Uc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Q(t,t.return,e)}}function Wc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Q(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Q(t,t.return,e)}}function Gc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{eo(t,n)}catch(t){Q(e,e.return,t)}}}function Kc(e,t,n){n.props=Zs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Q(e,t,n)}}function qc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Q(e,t,n)}}function Jc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Q(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Q(e,t,n)}else n.current=null}function Yc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Q(e,e.return,t)}}function Xc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[ft]=t}catch(t){Q(e,e.return,t)}}function Zc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Qc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Zc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=an));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(el(e,t,n),e=e.sibling;e!==null;)el(e,t,n),e=e.sibling}function tl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[dt]=e,t[ft]=n}catch(t){Q(e,e.return,t)}}var nl=!1,U=!1,rl=!1,il=typeof WeakSet==`function`?WeakSet:Set,al=null;function ol(e,t){if(e=e.containerInfo,Rd=sp,e=Mr(e),Nr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,al=t;al!==null;)if(t=al,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,al=e;else for(;al!==null;){switch(t=al,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[dt]=e,wt(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Ar(s,h),v=Ar(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=cu,cu=null;var o=iu,s=ou;if(ru=0,au=iu=null,ou=0,q&6)throw Error(i(331));var c=q;if(q|=4,Nl(o.current),Tl(o,o.current,s,n),q=c,rd(0,!1),Be&&typeof Be.onPostCommitFiberRoot==`function`)try{Be.onPostCommitFiberRoot(ze,o)}catch{}return!0}finally{A.p=a,k.T=r,Bu(e,t)}}function Uu(e,t,n){t=Si(n,t),t=nc(e.stateNode,t,2),e=qa(e,t,2),e!==null&&(tt(e,2),nd(e))}function Q(e,t,n){if(e.tag===3)Uu(e,e,n);else for(;t!==null;){if(t.tag===3){Uu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(nu===null||!nu.has(r))){e=Si(n,e),n=rc(2),r=qa(t,n,2),r!==null&&(ic(n,r,t,e),tt(r,2),nd(r));break}}t=t.return}}function Wu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Ll;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Vl=!0,i.add(n),e=Gu.bind(null,e,t,n),t.then(e,e))}function Gu(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,J===e&&(X&n)===n&&(Ul===4||Ul===3&&(X&62914560)===X&&300>Ae()-Ql?!(q&2)&&xu(e,0):Kl|=n,Jl===X&&(Jl=0)),nd(e)}function Ku(e,t){t===0&&(t=$e()),e=ci(e,t),e!==null&&(tt(e,t),nd(e))}function qu(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Ku(e,n)}function Ju(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),Ku(e,n)}function Yu(e,t){return Ee(e,t)}var Xu=null,Zu=null,Qu=!1,$u=!1,ed=!1,td=0;function nd(e){e!==Zu&&e.next===null&&(Zu===null?Xu=Zu=e:Zu=Zu.next=e),$u=!0,Qu||(Qu=!0,ld())}function rd(e,t){if(!ed&&$u){ed=!0;do for(var n=!1,r=Xu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-He(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,cd(r,a))}else a=X,a=Xe(r,r===J?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ze(r,a)||(n=!0,cd(r,a));r=r.next}while(n);ed=!1}}function id(){ad()}function ad(){$u=Qu=!1;var e=0;td!==0&&Gd()&&(e=td);for(var t=Ae(),n=null,r=Xu;r!==null;){var i=r.next,a=od(r,t);a===0?(r.next=null,n===null?Xu=i:n.next=i,i===null&&(Zu=n)):(n=r,(e!==0||a&3)&&($u=!0)),r=i}ru!==0&&ru!==5||rd(e,!1),td!==0&&(td=0)}function od(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ut(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),wt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ut(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ut(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ut(n.imageSizes)+`"]`)):i+=`[href="`+Ut(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=m({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),wt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ut(r)+`"][href="`+Ut(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=m({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),wt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=Ct(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=m({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);wt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=Ct(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),wt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=Ct(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),wt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=fe.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=Ct(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=Ct(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=Ct(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ut(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return m({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),wt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ut(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ut(n.href)+`"]`);if(r)return t.instance=r,wt(r),r;var a=m({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),wt(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,wt(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),wt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,wt(a),a):(r=n,(a=mf.get(o))&&(r=m({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),wt(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,wt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),wt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=g()})),v=`modulepreload`,y=function(e){return`/admin/`+e},b={},x=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,new URL(`../../../src/node/plugins/importAnalysisBuild.ts`,import.meta.url)).href}r=o(t.map(t=>{if(t=y(t,n),t=s(t),t in b)return;b[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:v,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},S=l(d(),1),C=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,w=/^[\\/]{2}/;function T(e,t){return t+e.replace(/\\/g,`/`)}var ee=`popstate`;function te(e){return typeof e==`object`&&!!e&&`pathname`in e&&`search`in e&&`hash`in e&&`state`in e&&`key`in e}function ne(e={}){function t(e,t){let n=t.state?.masked,{pathname:r,search:i,hash:a}=n||e.location;return ie(``,{pathname:r,search:i,hash:a},t.state&&t.state.usr||null,t.state&&t.state.key||`default`,n?{pathname:e.location.pathname,search:e.location.search,hash:e.location.hash}:void 0)}function n(e,t){return typeof t==`string`?t:ae(t)}return k(t,n,null,e)}function E(e,t){if(e===!1||e==null)throw Error(t)}function D(e,t){if(!e){typeof console<`u`&&console.warn(t);try{throw Error(t)}catch{}}}function O(){return Math.random().toString(36).substring(2,10)}function re(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function ie(e,t,n=null,r,i){return{pathname:typeof e==`string`?e:e.pathname,search:``,hash:``,...typeof t==`string`?oe(t):t,state:n,key:t&&t.key||r||O(),mask:i}}function ae({pathname:e=`/`,search:t=``,hash:n=``}){return t&&t!==`?`&&(e+=t.charAt(0)===`?`?t:`?`+t),n&&n!==`#`&&(e+=n.charAt(0)===`#`?n:`#`+n),e}function oe(e){let t={};if(e){let n=e.indexOf(`#`);n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf(`?`);r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function k(e,t,n,r={}){let{window:i=document.defaultView,v5Compat:a=!1}=r,o=i.history,s=`POP`,c=null,l=u();l??(l=0,o.replaceState({...o.state,idx:l},``));function u(){return(o.state||{idx:null}).idx}function d(){s=`POP`;let e=u(),t=e==null?null:e-l;l=e,c&&c({action:s,location:h.location,delta:t})}function f(e,t){s=`PUSH`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u()+1;let d=re(r,l),f=h.createHref(r.mask||r);try{o.pushState(d,``,f)}catch(e){if(e instanceof DOMException&&e.name===`DataCloneError`)throw e;i.location.assign(f)}a&&c&&c({action:s,location:h.location,delta:1})}function p(e,t){s=`REPLACE`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u();let i=re(r,l),d=h.createHref(r.mask||r);o.replaceState(i,``,d),a&&c&&c({action:s,location:h.location,delta:0})}function m(e){return A(i,e)}let h={get action(){return s},get location(){return e(i,o)},listen(e){if(c)throw Error(`A history only accepts one active listener`);return i.addEventListener(ee,d),c=e,()=>{i.removeEventListener(ee,d),c=null}},createHref(e){return t(i,e)},createURL:m,encodeLocation(e){let t=m(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:f,replace:p,go(e){return o.go(e)}};return h}function A(e,t,n=!1){let r=`http://localhost`;e&&(r=e.location.origin===`null`?e.location.href:e.location.origin),E(r,`No window.location.(origin|href) available to create URL`);let i=typeof t==`string`?t:ae(t);return i=i.replace(/ $/,`%20`),!n&&w.test(i)&&(i=r+i),new URL(i,r)}function se(e,t,n=`/`){return ce(e,t,n,!1)}function ce(e,t,n,r,i){let a=Te((typeof t==`string`?oe(t):t).pathname||`/`,n);if(a==null)return null;let o=i??j(e),s=null,c=we(a);for(let e=0;s==null&&e{let c={relativePath:s===void 0?e.path||``:s,caseSensitive:e.caseSensitive===!0,childrenIndex:a,route:e};if(c.relativePath.startsWith(`/`)){if(!c.relativePath.startsWith(r)&&o)return;E(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length)}let l=Ne([r,c.relativePath]),u=n.concat(c);e.children&&e.children.length>0&&(E(e.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${l}".`),M(e.children,t,u,l,o)),!(e.path==null&&!e.index)&&t.push({path:l,score:ve(l,e.index),routesMeta:u.map((e,t)=>{let[n,r]=Ce(e.relativePath,e.caseSensitive,t===u.length-1);return{...e,matcher:n,compiledParams:r}})})};return e.forEach((e,t)=>{if(e.path===``||!e.path?.includes(`?`))a(e,t);else for(let n of N(e.path))a(e,t,!0,n)}),t}function N(e){let t=e.split(`/`);if(t.length===0)return[];let[n,...r]=t,i=n.endsWith(`?`),a=n.replace(/\?$/,``);if(r.length===0)return i?[a,``]:[a];let o=N(r.join(`/`)),s=[];return s.push(...o.map(e=>e===``?a:[a,e].join(`/`))),i&&s.push(...o),s.map(t=>e.startsWith(`/`)&&t===``?`/`:t)}function ue(e){e.sort((e,t)=>e.score===t.score?ye(e.routesMeta.map(e=>e.childrenIndex),t.routesMeta.map(e=>e.childrenIndex)):t.score-e.score)}var de=/^:[\w-]+$/,fe=3,pe=2,me=1,he=10,ge=-2,_e=e=>e===`*`;function ve(e,t){let n=e.split(`/`),r=n.length;return n.some(_e)&&(r+=ge),t&&(r+=pe),n.filter(e=>!_e(e)).reduce((e,t)=>e+(de.test(t)?fe:t===``?me:he),r)}function ye(e,t){return e.length===t.length&&e.slice(0,-1).every((e,n)=>e===t[n])?e[e.length-1]-t[t.length-1]:0}function be(e,t,n=!1){let{routesMeta:r}=e,i={},a=`/`,o=[];for(let e=0;e{if(t===`*`){let e=s[r]||``;o=a.slice(0,a.length-e.length).replace(/(.)\/+$/,`$1`)}let i=s[r];return n&&!i?e[t]=void 0:e[t]=(i||``).replace(/%2F/g,`/`),e},{}),pathname:a,pathnameBase:o,pattern:e}}function Ce(e,t=!1,n=!0){D(e===`*`||!e.endsWith(`*`)||e.endsWith(`/*`),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,`/*`)}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,`/*`)}".`);let r=[],i=`^`+e.replace(/\/*\*?$/,``).replace(/^\/*/,`/`).replace(/[\\.*+^${}|()[\]]/g,`\\$&`).replace(/\/:([\w-]+)(\?)?/g,(e,t,n,i,a)=>{if(r.push({paramName:t,isOptional:n!=null}),n){let t=a.charAt(i+e.length);return t&&t!==`/`?`/([^\\/]*)`:`(?:/([^\\/]*))?`}return`/([^\\/]+)`}).replace(/\/([\w-]+)\?(\/|$)/g,`(/$1)?$2`);return e.endsWith(`*`)?(r.push({paramName:`*`}),i+=e===`*`||e===`/*`?`(.*)$`:`(?:\\/(.+)|\\/*)$`):n?i+=`\\/*$`:e!==``&&e!==`/`&&(i+=`(?:(?=\\/|$))`),[new RegExp(i,t?void 0:`i`),r]}function we(e){try{return e.split(`/`).map(e=>decodeURIComponent(e).replace(/\//g,`%2F`)).join(`/`)}catch(t){return D(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Te(e,t){if(t===`/`)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith(`/`)?t.length-1:t.length,r=e.charAt(n);return r&&r!==`/`?null:e.slice(n)||`/`}function Ee(e,t=`/`){let{pathname:n,search:r=``,hash:i=``}=typeof e==`string`?oe(e):e,a;return n?(n=Me(n),a=n.startsWith(`/`)?De(n.substring(1),`/`):De(n,t)):a=t,{pathname:a,search:Ie(r),hash:Le(i)}}function De(e,t){let n=Pe(t).split(`/`);return e.split(`/`).forEach(e=>{e===`..`?n.length>1&&n.pop():e!==`.`&&n.push(e)}),n.length>1?n.join(`/`):`/`}function Oe(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ke(e){return e.filter((e,t)=>t===0||e.route.path&&e.route.path.length>0)}function Ae(e){let t=ke(e);return t.map((e,n)=>n===t.length-1?e.pathname:e.pathnameBase)}function je(e,t,n,r=!1){let i;typeof e==`string`?i=oe(e):(i={...e},E(!i.pathname||!i.pathname.includes(`?`),Oe(`?`,`pathname`,`search`,i)),E(!i.pathname||!i.pathname.includes(`#`),Oe(`#`,`pathname`,`hash`,i)),E(!i.search||!i.search.includes(`#`),Oe(`#`,`search`,`hash`,i)));let a=e===``||i.pathname===``,o=a?`/`:i.pathname,s;if(o==null)s=n;else{let e=t.length-1;if(!r&&o.startsWith(`..`)){let t=o.split(`/`);for(;t[0]===`..`;)t.shift(),--e;i.pathname=t.join(`/`)}s=e>=0?t[e]:`/`}let c=Ee(i,s),l=o&&o!==`/`&&o.endsWith(`/`),u=(a||o===`.`)&&n.endsWith(`/`);return!c.pathname.endsWith(`/`)&&(l||u)&&(c.pathname+=`/`),c}var Me=e=>e.replace(/[\\/]{2,}/g,`/`),Ne=e=>Me(e.join(`/`)),Pe=e=>e.replace(/\/+$/,``),Fe=e=>Pe(e).replace(/^\/*/,`/`),Ie=e=>!e||e===`?`?``:e.startsWith(`?`)?e:`?`+e,Le=e=>!e||e===`#`?``:e.startsWith(`#`)?e:`#`+e,Re=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||``,this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function ze(e){return e!=null&&typeof e.status==`number`&&typeof e.statusText==`string`&&typeof e.internal==`boolean`&&`data`in e}function Be(e){return Ne(e.map(e=>e.route.path).filter(Boolean))||`/`}var Ve=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function He(e,t){let n=e;if(typeof n!=`string`||!C.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(Ve)try{let e=new URL(window.location.href),r=w.test(n)?new URL(T(n,e.protocol)):new URL(n),a=Te(r.pathname,t);r.origin===e.origin&&a!=null?n=a+r.search+r.hash:i=!0}catch{D(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join(`\0`);var Ue=[`POST`,`PUT`,`PATCH`,`DELETE`];new Set(Ue);var We=[`GET`,...Ue];new Set(We);var Ge=[`about:`,`blob:`,`chrome:`,`chrome-untrusted:`,`content:`,`data:`,`devtools:`,`file:`,`filesystem:`,`javascript:`];function Ke(e){try{return Ge.includes(new URL(e).protocol)}catch{return!1}}var qe=S.createContext(null);qe.displayName=`DataRouter`;var Je=S.createContext(null);Je.displayName=`DataRouterState`;var Ye=S.createContext(!1);function Xe(){return S.useContext(Ye)}var Ze=S.createContext({isTransitioning:!1});Ze.displayName=`ViewTransition`;var Qe=S.createContext(new Map);Qe.displayName=`Fetchers`;var $e=S.createContext(null);$e.displayName=`Await`;var et=S.createContext(null);et.displayName=`Navigation`;var tt=S.createContext(null);tt.displayName=`Location`;var nt=S.createContext({outlet:null,matches:[],isDataRoute:!1});nt.displayName=`Route`;var rt=S.createContext(null);rt.displayName=`RouteError`;var it=`REACT_ROUTER_ERROR`,at=`REDIRECT`,ot=`ROUTE_ERROR_RESPONSE`;function st(e){if(e.startsWith(`${it}:${at}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`&&typeof t.location==`string`&&typeof t.reloadDocument==`boolean`&&typeof t.replace==`boolean`)return t}catch{}}function ct(e){if(e.startsWith(`${it}:${ot}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`)return new Re(t.status,t.statusText,t.data)}catch{}}function lt(e,{relative:t}={}){E(ut(),`useHref() may be used only in the context of a component.`);let{basename:n,navigator:r}=S.useContext(et),{hash:i,pathname:a,search:o}=vt(e,{relative:t}),s=a;return n!==`/`&&(s=a===`/`?n:Ne([n,a])),r.createHref({pathname:s,search:o,hash:i})}function ut(){return S.useContext(tt)!=null}function dt(){return E(ut(),`useLocation() may be used only in the context of a component.`),S.useContext(tt).location}var ft=`You should call navigate() in a React.useEffect(), not when your component is first rendered.`;function pt(e){S.useContext(et).static||S.useLayoutEffect(e)}function mt(){let{isDataRoute:e}=S.useContext(nt);return e?Lt():ht()}function ht(){E(ut(),`useNavigate() may be used only in the context of a component.`);let e=S.useContext(qe),{basename:t,navigator:n}=S.useContext(et),{matches:r}=S.useContext(nt),{pathname:i}=dt(),a=JSON.stringify(Ae(r)),o=S.useRef(!1);return pt(()=>{o.current=!0}),S.useCallback((r,s={})=>{if(D(o.current,ft),!o.current)return;if(typeof r==`number`){n.go(r);return}let c=je(r,JSON.parse(a),i,s.relative===`path`);e==null&&t!==`/`&&(c.pathname=c.pathname===`/`?t:Ne([t,c.pathname])),(s.replace?n.replace:n.push)(c,s.state,s)},[t,n,a,i,e])}var gt=S.createContext(null);function _t(e){let t=S.useContext(nt).outlet;return S.useMemo(()=>t&&S.createElement(gt.Provider,{value:e},t),[t,e])}function vt(e,{relative:t}={}){let{matches:n}=S.useContext(nt),{pathname:r}=dt(),i=JSON.stringify(Ae(n));return S.useMemo(()=>je(e,JSON.parse(i),r,t===`path`),[e,i,r,t])}function yt(e,t){return bt(e,t)}function bt(e,t,n){E(ut(),`useRoutes() may be used only in the context of a component.`);let{navigator:r}=S.useContext(et),{matches:i}=S.useContext(nt),a=i[i.length-1],o=a?a.params:{},s=a?a.pathname:`/`,c=a?a.pathnameBase:`/`,l=a&&a.route;{let e=l&&l.path||``;zt(s,!l||e.endsWith(`*`)||e.endsWith(`*?`),`You rendered descendant (or called \`useRoutes()\`) at "${s}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. +`+e.stack}}var Te=Object.prototype.hasOwnProperty,Ee=t.unstable_scheduleCallback,De=t.unstable_cancelCallback,Oe=t.unstable_shouldYield,ke=t.unstable_requestPaint,Ae=t.unstable_now,je=t.unstable_getCurrentPriorityLevel,Me=t.unstable_ImmediatePriority,Ne=t.unstable_UserBlockingPriority,Pe=t.unstable_NormalPriority,Fe=t.unstable_LowPriority,Ie=t.unstable_IdlePriority,Le=t.log,Re=t.unstable_setDisableYieldValue,ze=null,Be=null;function Ve(e){if(typeof Le==`function`&&Re(e),Be&&typeof Be.setStrictMode==`function`)try{Be.setStrictMode(ze,e)}catch{}}var He=Math.clz32?Math.clz32:Ge,Ue=Math.log,We=Math.LN2;function Ge(e){return e>>>=0,e===0?32:31-(Ue(e)/We|0)|0}var Ke=256,qe=262144,Je=4194304;function Ye(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Xe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ye(n))):i=Ye(o):i=Ye(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ye(n))):i=Ye(o)):i=Ye(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ze(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function $e(){var e=Je;return Je<<=1,!(Je&62914560)&&(Je=4194304),e}function et(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function tt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nt(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),hn=!1;if(mn)try{var gn={};Object.defineProperty(gn,"passive",{get:function(){hn=!0}}),window.addEventListener(`test`,gn,gn),window.removeEventListener(`test`,gn,gn)}catch{hn=!1}var _n=null,vn=null,yn=null;function bn(){if(yn)return yn;var e,t=vn,n=t.length,r,i=`value`in _n?_n.value:_n.textContent,a=i.length;for(e=0;e=Qn),tr=` `,nr=!1;function rr(e,t){switch(e){case`keyup`:return Xn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function ir(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ar=!1;function or(e,t){switch(e){case`compositionend`:return ir(t);case`keypress`:return t.which===32?(nr=!0,tr):null;case`textInput`:return e=t.data,e===tr&&nr?null:e;default:return null}}function sr(e,t){if(ar)return e===`compositionend`||!Zn&&rr(e,t)?(e=bn(),yn=vn=_n=null,ar=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=kr(n)}}function jr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?jr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Mr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Vt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Vt(e.document)}return t}function Nr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Pr=mn&&`documentMode`in document&&11>=document.documentMode,Fr=null,Ir=null,Lr=null,Rr=!1;function zr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Rr||Fr==null||Fr!==Vt(r)||(r=Fr,`selectionStart`in r&&Nr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Lr&&Or(Lr,r)||(Lr=r,r=Td(Ir,`onSelect`),0>=o,i-=o,Ai=1<<32-He(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),I&&Mi(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),I&&Mi(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return I&&Mi(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),I&&Mi(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===ne&&ja(l)===r.type){n(e,r.sibling),c=a(r,o.props),Ra(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=_i(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=gi(o.type,o.key,o.props,null,e.mode,c),Ra(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=bi(o,e.mode,c),c.return=e,e=c}return s(e);case ne:return o=ja(o),b(e,r,o,c)}if(oe(o))return h(e,r,o,c);if(re(o)){if(l=re(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,La(o),c);if(o.$$typeof===C)return b(e,r,aa(e,o),c);za(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=vi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Ia=0;var i=b(e,t,n,r);return Fa=null,i}catch(t){if(t===Ta||t===Da)throw t;var a=pi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Va=Ba(!0),Ha=Ba(!1),Ua=!1;function Wa(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ga(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ka(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function qa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,J&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=ui(e),li(e,null,n),t}return oi(e,r,t,n),ui(e)}function Ja(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}function Ya(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Xa=!1;function Za(){if(Xa){var e=ga;if(e!==null)throw e}}function Qa(e,t,n,r){Xa=!1;var i=e.updateQueue;Ua=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(X&f)===f:(r&f)===f){f!==0&&f===ha&&(Xa=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=m({},d,f);break a;case 2:Ua=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Wl|=o,e.lanes=o,e.memoizedState=d}}function $a(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function eo(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,Rs(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Ls(e,t,ya(c,r),fu(e)):Ls(e,t,r,fu(e))}catch(n){Ls(e,t,{then:function(){},status:`rejected`,reason:n},fu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function Ds(){}function Os(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=ks(e).queue;Es(e,a,t,se,n===null?Ds:function(){return As(e),n(r)})}function ks(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:se,baseState:se,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:zo,lastRenderedState:se},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:zo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function As(e){var t=ks(e);t.next===null&&(t=e.alternate.memoizedState),Ls(e,t.next.queue,{},fu())}function js(){return ia(Qf)}function Ms(){return Po().memoizedState}function Ns(){return Po().memoizedState}function Ps(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=fu();e=Ka(n);var r=qa(t,e,n);r!==null&&(mu(r,t,n),Ja(r,t,n)),t={cache:da()},e.payload=t;return}t=t.return}}function Fs(e,t,n){var r=fu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},zs(e)?Bs(t,n):(n=si(e,t,n,r),n!==null&&(mu(n,e,r),Vs(n,t,r)))}function Is(e,t,n){Ls(e,t,n,fu())}function Ls(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(zs(e))Bs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Dr(s,o))return oi(e,t,i,0),Ll===null&&ai(),!1}catch{}if(n=si(e,t,i,r),n!==null)return mu(n,e,r),Vs(n,t,r),!0}return!1}function Rs(e,t,n,r){if(r={lane:2,revertLane:ud(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},zs(e)){if(t)throw Error(i(479))}else t=si(e,n,r,2),t!==null&&mu(t,e,2)}function zs(e){var t=e.alternate;return e===L||t!==null&&t===L}function Bs(e,t){yo=vo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Vs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}var Hs={readContext:ia,use:Lo,useCallback:To,useContext:To,useEffect:To,useImperativeHandle:To,useLayoutEffect:To,useInsertionEffect:To,useMemo:To,useReducer:To,useRef:To,useState:To,useDebugValue:To,useDeferredValue:To,useTransition:To,useSyncExternalStore:To,useId:To,useHostTransitionStatus:To,useFormState:To,useActionState:To,useOptimistic:To,useMemoCache:To,useCacheRefresh:To};Hs.useEffectEvent=To;var Us={readContext:ia,use:Lo,useCallback:function(e,t){return No().memoizedState=[e,t===void 0?null:t],e},useContext:ia,useEffect:ps,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),ds(4194308,4,ys.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ds(4194308,4,e,t)},useInsertionEffect:function(e,t){ds(4,2,e,t)},useMemo:function(e,t){var n=No();t=t===void 0?null:t;var r=e();if(bo){Ve(!0);try{e()}finally{Ve(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=No();if(n!==void 0){var i=n(t);if(bo){Ve(!0);try{n(t)}finally{Ve(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Fs.bind(null,L,e),[r.memoizedState,e]},useRef:function(e){var t=No();return e={current:e},t.memoizedState=e},useState:function(e){e=Yo(e);var t=e.queue,n=Is.bind(null,L,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:xs,useDeferredValue:function(e,t){return ws(No(),e,t)},useTransition:function(){var e=Yo(!1);return e=Es.bind(null,L,e.queue,!0,!1),No().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=L,a=No();if(I){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Ll===null)throw Error(i(349));X&127||Wo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,ps(Ko.bind(null,r,o,e),[e]),r.flags|=2048,ls(9,{destroy:void 0},Go.bind(null,r,o,n,t),null),n},useId:function(){var e=No(),t=Ll.identifierPrefix;if(I){var n=ji,r=Ai;n=(r&~(1<<32-He(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=xo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[dt]=t,o[ft]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Pc(t)}}return U(t),Fc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Pc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=fe.current,Wi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=F,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[dt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||jd(e.nodeValue,n)),e||Vi(t,!0)}else e=Bd(e).createTextNode(r),e[dt]=t,t.stateNode=e}return U(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Wi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[dt]=t}else Gi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),e=!1}else n=Ki(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(po(t),t):(po(t),null);if(t.flags&128)throw Error(i(558))}return U(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Wi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[dt]=t}else Gi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),a=!1}else a=Ki(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(po(t),t):(po(t),null)}return po(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Lc(t,t.updateQueue),U(t),null);case 4:return he(),e===null&&xd(t.stateNode.containerInfo),U(t),null;case 10:return Qi(t.type),U(t),null;case 19:if(M(mo),r=t.memoizedState,r===null)return U(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Rc(r,!1);else{if(Ul!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=ho(e),o!==null){for(t.flags|=128,Rc(r,!1),e=o.updateQueue,t.updateQueue=e,Lc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)P(n,e),n=n.sibling;return N(mo,mo.current&1|2),I&&Mi(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ae()>eu&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304)}else{if(!a)if(e=ho(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Lc(t,e),Rc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!I)return U(t),null}else 2*Ae()-r.renderingStartTime>eu&&n!==536870912&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(U(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ae(),e.sibling=null,n=mo.current,N(mo,a?n&1|2:n&1),I&&Mi(t,r.treeForkCount),e);case 22:case 23:return po(t),ao(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(U(t),t.subtreeFlags&6&&(t.flags|=8192)):U(t),n=t.updateQueue,n!==null&&Lc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&M(xa),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Qi(ua),U(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Fi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Qi(ua),he(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return _e(t),null;case 31:if(t.memoizedState!==null){if(po(t),t.alternate===null)throw Error(i(340));Gi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(po(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Gi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return M(mo),null;case 4:return he(),null;case 10:return Qi(t.type),null;case 22:case 23:return po(t),ao(),e!==null&&M(xa),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Qi(ua),null;case 25:return null;default:return null}}function Vc(e,t){switch(Fi(t),t.tag){case 3:Qi(ua),he();break;case 26:case 27:case 5:_e(t);break;case 4:he();break;case 31:t.memoizedState!==null&&po(t);break;case 13:po(t);break;case 19:M(mo);break;case 10:Qi(t.type);break;case 22:case 23:po(t),ao(),e!==null&&M(xa);break;case 24:Qi(ua)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Q(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Q(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Q(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{eo(t,n)}catch(t){Q(e,e.return,t)}}}function Gc(e,t,n){n.props=Xs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Q(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Q(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Q(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Q(e,t,n)}else n.current=null}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Q(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[ft]=t}catch(t){Q(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=an));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[dt]=e,t[ft]=n}catch(t){Q(e,e.return,t)}}var tl=!1,W=!1,nl=!1,rl=typeof WeakSet==`function`?WeakSet:Set,il=null;function al(e,t){if(e=e.containerInfo,Rd=sp,e=Mr(e),Nr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,il=t;il!==null;)if(t=il,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,il=e;else for(;il!==null;){switch(t=il,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[dt]=e,wt(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Ar(s,h),v=Ar(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=cu,cu=null;var o=iu,s=ou;if(ru=0,au=iu=null,ou=0,J&6)throw Error(i(331));var c=J;if(J|=4,Ml(o.current),wl(o,o.current,s,n),J=c,rd(0,!1),Be&&typeof Be.onPostCommitFiberRoot==`function`)try{Be.onPostCommitFiberRoot(ze,o)}catch{}return!0}finally{A.p=a,k.T=r,Bu(e,t)}}function Uu(e,t,n){t=Si(n,t),t=tc(e.stateNode,t,2),e=qa(e,t,2),e!==null&&(tt(e,2),nd(e))}function Q(e,t,n){if(e.tag===3)Uu(e,e,n);else for(;t!==null;){if(t.tag===3){Uu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(nu===null||!nu.has(r))){e=Si(n,e),n=nc(2),r=qa(t,n,2),r!==null&&(rc(n,r,t,e),tt(r,2),nd(r));break}}t=t.return}}function Wu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Il;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Vl=!0,i.add(n),e=Gu.bind(null,e,t,n),t.then(e,e))}function Gu(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Ll===e&&(X&n)===n&&(Ul===4||Ul===3&&(X&62914560)===X&&300>Ae()-Ql?!(J&2)&&xu(e,0):Kl|=n,Jl===X&&(Jl=0)),nd(e)}function Ku(e,t){t===0&&(t=$e()),e=ci(e,t),e!==null&&(tt(e,t),nd(e))}function qu(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Ku(e,n)}function Ju(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),Ku(e,n)}function Yu(e,t){return Ee(e,t)}var Xu=null,Zu=null,Qu=!1,$u=!1,ed=!1,td=0;function nd(e){e!==Zu&&e.next===null&&(Zu===null?Xu=Zu=e:Zu=Zu.next=e),$u=!0,Qu||(Qu=!0,ld())}function rd(e,t){if(!ed&&$u){ed=!0;do for(var n=!1,r=Xu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-He(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,cd(r,a))}else a=X,a=Xe(r,r===Ll?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ze(r,a)||(n=!0,cd(r,a));r=r.next}while(n);ed=!1}}function id(){ad()}function ad(){$u=Qu=!1;var e=0;td!==0&&Gd()&&(e=td);for(var t=Ae(),n=null,r=Xu;r!==null;){var i=r.next,a=od(r,t);a===0?(r.next=null,n===null?Xu=i:n.next=i,i===null&&(Zu=n)):(n=r,(e!==0||a&3)&&($u=!0)),r=i}ru!==0&&ru!==5||rd(e,!1),td!==0&&(td=0)}function od(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ut(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),wt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ut(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ut(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ut(n.imageSizes)+`"]`)):i+=`[href="`+Ut(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=m({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),wt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ut(r)+`"][href="`+Ut(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=m({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),wt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=Ct(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=m({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);wt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=Ct(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),wt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=Ct(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),wt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=fe.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=Ct(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=Ct(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=Ct(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ut(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return m({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),wt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ut(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ut(n.href)+`"]`);if(r)return t.instance=r,wt(r),r;var a=m({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),wt(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,wt(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),wt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,wt(a),a):(r=n,(a=mf.get(o))&&(r=m({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),wt(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,wt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),wt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=g()})),v=`modulepreload`,y=function(e){return`/admin/`+e},b={},x=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,new URL(`../../../src/node/plugins/importAnalysisBuild.ts`,import.meta.url)).href}r=o(t.map(t=>{if(t=y(t,n),t=s(t),t in b)return;b[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:v,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},S=l(d(),1),C=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,w=/^[\\/]{2}/;function T(e,t){return t+e.replace(/\\/g,`/`)}var ee=`popstate`;function te(e){return typeof e==`object`&&!!e&&`pathname`in e&&`search`in e&&`hash`in e&&`state`in e&&`key`in e}function ne(e={}){function t(e,t){let n=t.state?.masked,{pathname:r,search:i,hash:a}=n||e.location;return ie(``,{pathname:r,search:i,hash:a},t.state&&t.state.usr||null,t.state&&t.state.key||`default`,n?{pathname:e.location.pathname,search:e.location.search,hash:e.location.hash}:void 0)}function n(e,t){return typeof t==`string`?t:ae(t)}return k(t,n,null,e)}function E(e,t){if(e===!1||e==null)throw Error(t)}function D(e,t){if(!e){typeof console<`u`&&console.warn(t);try{throw Error(t)}catch{}}}function O(){return Math.random().toString(36).substring(2,10)}function re(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function ie(e,t,n=null,r,i){return{pathname:typeof e==`string`?e:e.pathname,search:``,hash:``,...typeof t==`string`?oe(t):t,state:n,key:t&&t.key||r||O(),mask:i}}function ae({pathname:e=`/`,search:t=``,hash:n=``}){return t&&t!==`?`&&(e+=t.charAt(0)===`?`?t:`?`+t),n&&n!==`#`&&(e+=n.charAt(0)===`#`?n:`#`+n),e}function oe(e){let t={};if(e){let n=e.indexOf(`#`);n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf(`?`);r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function k(e,t,n,r={}){let{window:i=document.defaultView,v5Compat:a=!1}=r,o=i.history,s=`POP`,c=null,l=u();l??(l=0,o.replaceState({...o.state,idx:l},``));function u(){return(o.state||{idx:null}).idx}function d(){s=`POP`;let e=u(),t=e==null?null:e-l;l=e,c&&c({action:s,location:h.location,delta:t})}function f(e,t){s=`PUSH`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u()+1;let d=re(r,l),f=h.createHref(r.mask||r);try{o.pushState(d,``,f)}catch(e){if(e instanceof DOMException&&e.name===`DataCloneError`)throw e;i.location.assign(f)}a&&c&&c({action:s,location:h.location,delta:1})}function p(e,t){s=`REPLACE`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u();let i=re(r,l),d=h.createHref(r.mask||r);o.replaceState(i,``,d),a&&c&&c({action:s,location:h.location,delta:0})}function m(e){return A(i,e)}let h={get action(){return s},get location(){return e(i,o)},listen(e){if(c)throw Error(`A history only accepts one active listener`);return i.addEventListener(ee,d),c=e,()=>{i.removeEventListener(ee,d),c=null}},createHref(e){return t(i,e)},createURL:m,encodeLocation(e){let t=m(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:f,replace:p,go(e){return o.go(e)}};return h}function A(e,t,n=!1){let r=`http://localhost`;e&&(r=e.location.origin===`null`?e.location.href:e.location.origin),E(r,`No window.location.(origin|href) available to create URL`);let i=typeof t==`string`?t:ae(t);return i=i.replace(/ $/,`%20`),!n&&w.test(i)&&(i=r+i),new URL(i,r)}function se(e,t,n=`/`){return ce(e,t,n,!1)}function ce(e,t,n,r,i){let a=Te((typeof t==`string`?oe(t):t).pathname||`/`,n);if(a==null)return null;let o=i??j(e),s=null,c=we(a);for(let e=0;s==null&&e{let c={relativePath:s===void 0?e.path||``:s,caseSensitive:e.caseSensitive===!0,childrenIndex:a,route:e};if(c.relativePath.startsWith(`/`)){if(!c.relativePath.startsWith(r)&&o)return;E(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length)}let l=Ne([r,c.relativePath]),u=n.concat(c);e.children&&e.children.length>0&&(E(e.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${l}".`),M(e.children,t,u,l,o)),!(e.path==null&&!e.index)&&t.push({path:l,score:ve(l,e.index),routesMeta:u.map((e,t)=>{let[n,r]=Ce(e.relativePath,e.caseSensitive,t===u.length-1);return{...e,matcher:n,compiledParams:r}})})};return e.forEach((e,t)=>{if(e.path===``||!e.path?.includes(`?`))a(e,t);else for(let n of N(e.path))a(e,t,!0,n)}),t}function N(e){let t=e.split(`/`);if(t.length===0)return[];let[n,...r]=t,i=n.endsWith(`?`),a=n.replace(/\?$/,``);if(r.length===0)return i?[a,``]:[a];let o=N(r.join(`/`)),s=[];return s.push(...o.map(e=>e===``?a:[a,e].join(`/`))),i&&s.push(...o),s.map(t=>e.startsWith(`/`)&&t===``?`/`:t)}function ue(e){e.sort((e,t)=>e.score===t.score?ye(e.routesMeta.map(e=>e.childrenIndex),t.routesMeta.map(e=>e.childrenIndex)):t.score-e.score)}var de=/^:[\w-]+$/,fe=3,pe=2,me=1,he=10,ge=-2,_e=e=>e===`*`;function ve(e,t){let n=e.split(`/`),r=n.length;return n.some(_e)&&(r+=ge),t&&(r+=pe),n.filter(e=>!_e(e)).reduce((e,t)=>e+(de.test(t)?fe:t===``?me:he),r)}function ye(e,t){return e.length===t.length&&e.slice(0,-1).every((e,n)=>e===t[n])?e[e.length-1]-t[t.length-1]:0}function be(e,t,n=!1){let{routesMeta:r}=e,i={},a=`/`,o=[];for(let e=0;e{if(t===`*`){let e=s[r]||``;o=a.slice(0,a.length-e.length).replace(/(.)\/+$/,`$1`)}let i=s[r];return n&&!i?e[t]=void 0:e[t]=(i||``).replace(/%2F/g,`/`),e},{}),pathname:a,pathnameBase:o,pattern:e}}function Ce(e,t=!1,n=!0){D(e===`*`||!e.endsWith(`*`)||e.endsWith(`/*`),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,`/*`)}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,`/*`)}".`);let r=[],i=`^`+e.replace(/\/*\*?$/,``).replace(/^\/*/,`/`).replace(/[\\.*+^${}|()[\]]/g,`\\$&`).replace(/\/:([\w-]+)(\?)?/g,(e,t,n,i,a)=>{if(r.push({paramName:t,isOptional:n!=null}),n){let t=a.charAt(i+e.length);return t&&t!==`/`?`/([^\\/]*)`:`(?:/([^\\/]*))?`}return`/([^\\/]+)`}).replace(/\/([\w-]+)\?(\/|$)/g,`(/$1)?$2`);return e.endsWith(`*`)?(r.push({paramName:`*`}),i+=e===`*`||e===`/*`?`(.*)$`:`(?:\\/(.+)|\\/*)$`):n?i+=`\\/*$`:e!==``&&e!==`/`&&(i+=`(?:(?=\\/|$))`),[new RegExp(i,t?void 0:`i`),r]}function we(e){try{return e.split(`/`).map(e=>decodeURIComponent(e).replace(/\//g,`%2F`)).join(`/`)}catch(t){return D(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Te(e,t){if(t===`/`)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith(`/`)?t.length-1:t.length,r=e.charAt(n);return r&&r!==`/`?null:e.slice(n)||`/`}function Ee(e,t=`/`){let{pathname:n,search:r=``,hash:i=``}=typeof e==`string`?oe(e):e,a;return n?(n=Me(n),a=n.startsWith(`/`)?De(n.substring(1),`/`):De(n,t)):a=t,{pathname:a,search:Ie(r),hash:Le(i)}}function De(e,t){let n=Pe(t).split(`/`);return e.split(`/`).forEach(e=>{e===`..`?n.length>1&&n.pop():e!==`.`&&n.push(e)}),n.length>1?n.join(`/`):`/`}function Oe(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ke(e){return e.filter((e,t)=>t===0||e.route.path&&e.route.path.length>0)}function Ae(e){let t=ke(e);return t.map((e,n)=>n===t.length-1?e.pathname:e.pathnameBase)}function je(e,t,n,r=!1){let i;typeof e==`string`?i=oe(e):(i={...e},E(!i.pathname||!i.pathname.includes(`?`),Oe(`?`,`pathname`,`search`,i)),E(!i.pathname||!i.pathname.includes(`#`),Oe(`#`,`pathname`,`hash`,i)),E(!i.search||!i.search.includes(`#`),Oe(`#`,`search`,`hash`,i)));let a=e===``||i.pathname===``,o=a?`/`:i.pathname,s;if(o==null)s=n;else{let e=t.length-1;if(!r&&o.startsWith(`..`)){let t=o.split(`/`);for(;t[0]===`..`;)t.shift(),--e;i.pathname=t.join(`/`)}s=e>=0?t[e]:`/`}let c=Ee(i,s),l=o&&o!==`/`&&o.endsWith(`/`),u=(a||o===`.`)&&n.endsWith(`/`);return!c.pathname.endsWith(`/`)&&(l||u)&&(c.pathname+=`/`),c}var Me=e=>e.replace(/[\\/]{2,}/g,`/`),Ne=e=>Me(e.join(`/`)),Pe=e=>e.replace(/\/+$/,``),Fe=e=>Pe(e).replace(/^\/*/,`/`),Ie=e=>!e||e===`?`?``:e.startsWith(`?`)?e:`?`+e,Le=e=>!e||e===`#`?``:e.startsWith(`#`)?e:`#`+e,Re=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||``,this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function ze(e){return e!=null&&typeof e.status==`number`&&typeof e.statusText==`string`&&typeof e.internal==`boolean`&&`data`in e}function Be(e){return Ne(e.map(e=>e.route.path).filter(Boolean))||`/`}var Ve=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function He(e,t){let n=e;if(typeof n!=`string`||!C.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(Ve)try{let e=new URL(window.location.href),r=w.test(n)?new URL(T(n,e.protocol)):new URL(n),a=Te(r.pathname,t);r.origin===e.origin&&a!=null?n=a+r.search+r.hash:i=!0}catch{D(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join(`\0`);var Ue=[`POST`,`PUT`,`PATCH`,`DELETE`];new Set(Ue);var We=[`GET`,...Ue];new Set(We);var Ge=[`about:`,`blob:`,`chrome:`,`chrome-untrusted:`,`content:`,`data:`,`devtools:`,`file:`,`filesystem:`,`javascript:`];function Ke(e){try{return Ge.includes(new URL(e).protocol)}catch{return!1}}var qe=S.createContext(null);qe.displayName=`DataRouter`;var Je=S.createContext(null);Je.displayName=`DataRouterState`;var Ye=S.createContext(!1);function Xe(){return S.useContext(Ye)}var Ze=S.createContext({isTransitioning:!1});Ze.displayName=`ViewTransition`;var Qe=S.createContext(new Map);Qe.displayName=`Fetchers`;var $e=S.createContext(null);$e.displayName=`Await`;var et=S.createContext(null);et.displayName=`Navigation`;var tt=S.createContext(null);tt.displayName=`Location`;var nt=S.createContext({outlet:null,matches:[],isDataRoute:!1});nt.displayName=`Route`;var rt=S.createContext(null);rt.displayName=`RouteError`;var it=`REACT_ROUTER_ERROR`,at=`REDIRECT`,ot=`ROUTE_ERROR_RESPONSE`;function st(e){if(e.startsWith(`${it}:${at}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`&&typeof t.location==`string`&&typeof t.reloadDocument==`boolean`&&typeof t.replace==`boolean`)return t}catch{}}function ct(e){if(e.startsWith(`${it}:${ot}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`)return new Re(t.status,t.statusText,t.data)}catch{}}function lt(e,{relative:t}={}){E(ut(),`useHref() may be used only in the context of a component.`);let{basename:n,navigator:r}=S.useContext(et),{hash:i,pathname:a,search:o}=vt(e,{relative:t}),s=a;return n!==`/`&&(s=a===`/`?n:Ne([n,a])),r.createHref({pathname:s,search:o,hash:i})}function ut(){return S.useContext(tt)!=null}function dt(){return E(ut(),`useLocation() may be used only in the context of a component.`),S.useContext(tt).location}var ft=`You should call navigate() in a React.useEffect(), not when your component is first rendered.`;function pt(e){S.useContext(et).static||S.useLayoutEffect(e)}function mt(){let{isDataRoute:e}=S.useContext(nt);return e?Lt():ht()}function ht(){E(ut(),`useNavigate() may be used only in the context of a component.`);let e=S.useContext(qe),{basename:t,navigator:n}=S.useContext(et),{matches:r}=S.useContext(nt),{pathname:i}=dt(),a=JSON.stringify(Ae(r)),o=S.useRef(!1);return pt(()=>{o.current=!0}),S.useCallback((r,s={})=>{if(D(o.current,ft),!o.current)return;if(typeof r==`number`){n.go(r);return}let c=je(r,JSON.parse(a),i,s.relative===`path`);e==null&&t!==`/`&&(c.pathname=c.pathname===`/`?t:Ne([t,c.pathname])),(s.replace?n.replace:n.push)(c,s.state,s)},[t,n,a,i,e])}var gt=S.createContext(null);function _t(e){let t=S.useContext(nt).outlet;return S.useMemo(()=>t&&S.createElement(gt.Provider,{value:e},t),[t,e])}function vt(e,{relative:t}={}){let{matches:n}=S.useContext(nt),{pathname:r}=dt(),i=JSON.stringify(Ae(n));return S.useMemo(()=>je(e,JSON.parse(i),r,t===`path`),[e,i,r,t])}function yt(e,t){return bt(e,t)}function bt(e,t,n){E(ut(),`useRoutes() may be used only in the context of a component.`);let{navigator:r}=S.useContext(et),{matches:i}=S.useContext(nt),a=i[i.length-1],o=a?a.params:{},s=a?a.pathname:`/`,c=a?a.pathnameBase:`/`,l=a&&a.route;{let e=l&&l.path||``;zt(s,!l||e.endsWith(`*`)||e.endsWith(`*?`),`You rendered descendant (or called \`useRoutes()\`) at "${s}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. Please change the parent to .`)}let u=dt(),d;if(t){let e=typeof t==`string`?oe(t):t;E(c===`/`||e.pathname?.startsWith(c),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${c}" but pathname "${e.pathname}" was given in the \`location\` prop.`),d=e}else d=u;let f=d.pathname||`/`,p=f;if(c!==`/`){let e=c.replace(/^\//,``).split(`/`);p=`/`+f.replace(/^\//,``).split(`/`).slice(e.length).join(`/`)}let m=n&&n.state.matches.length?n.state.matches.map(e=>Object.assign(e,{route:n.manifest[e.route.id]||e.route})):se(e,{pathname:p});D(l||m!=null,`No routes matched location "${d.pathname}${d.search}${d.hash}" `),D(m==null||m[m.length-1].route.element!==void 0||m[m.length-1].route.Component!==void 0||m[m.length-1].route.lazy!==void 0,`Matched leaf route at location "${d.pathname}${d.search}${d.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let h=Dt(m&&m.map(e=>Object.assign({},e,{params:Object.assign({},o,e.params),pathname:Ne([c,r.encodeLocation?r.encodeLocation(e.pathname.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathname]),pathnameBase:e.pathnameBase===`/`?c:Ne([c,r.encodeLocation?r.encodeLocation(e.pathnameBase.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathnameBase])})),i,n);return t&&h?S.createElement(tt.Provider,{value:{location:{pathname:`/`,search:``,hash:``,state:null,key:`default`,mask:void 0,...d},navigationType:`POP`}},h):h}function xt(){let e=It(),t=ze(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r=`rgba(200,200,200, 0.5)`,i={padding:`0.5rem`,backgroundColor:r},a={padding:`2px 4px`,backgroundColor:r},o=null;return console.error(`Error handled by React Router default ErrorBoundary:`,e),o=S.createElement(S.Fragment,null,S.createElement(`p`,null,`💿 Hey developer 👋`),S.createElement(`p`,null,`You can provide a way better UX than this when your app throws errors by providing your own `,S.createElement(`code`,{style:a},`ErrorBoundary`),` or`,` `,S.createElement(`code`,{style:a},`errorElement`),` prop on your route.`)),S.createElement(S.Fragment,null,S.createElement(`h2`,null,`Unexpected Application Error!`),S.createElement(`h3`,{style:{fontStyle:`italic`}},t),n?S.createElement(`pre`,{style:i},n):null,o)}var St=S.createElement(xt,null),Ct=class extends S.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!==`idle`&&e.revalidation===`idle`?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error===void 0?t.error:e.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error(`React Router caught the following error during render`,e)}render(){let e=this.state.error;if(this.context&&typeof e==`object`&&e&&`digest`in e&&typeof e.digest==`string`){let t=ct(e.digest);t&&(e=t)}let t=e===void 0?this.props.children:S.createElement(nt.Provider,{value:this.props.routeContext},S.createElement(rt.Provider,{value:e,children:this.props.component}));return this.context?S.createElement(Tt,{error:e},t):t}};Ct.contextType=Ye;var wt=new WeakMap;function Tt({children:e,error:t}){let{basename:n}=S.useContext(et);if(typeof t==`object`&&t&&`digest`in t&&typeof t.digest==`string`){let e=st(t.digest);if(e){let r=wt.get(t);if(r)throw r;let i=He(e.location,n),a=i.absoluteURL||i.to;if(Ke(a))throw Error(`Invalid redirect location`);if(Ve&&!wt.get(t))if(i.isExternal||e.reloadDocument)window.location.href=a;else{let n=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(i.to,{replace:e.replace}));throw wt.set(t,n),n}return S.createElement(`meta`,{httpEquiv:`refresh`,content:`0;url=${a}`})}}return e}function Et({routeContext:e,match:t,children:n}){let r=S.useContext(qe);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),S.createElement(nt.Provider,{value:e},n)}function Dt(e,t=[],n){let r=n?.state;if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let i=e,a=r?.errors;if(a!=null){let e=i.findIndex(e=>e.route.id&&a?.[e.route.id]!==void 0);E(e>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(a).join(`,`)}`),i=i.slice(0,Math.min(i.length,e+1))}let o=!1,s=-1;if(n&&r){o=r.renderFallback;for(let e=0;e=0?i.slice(0,s+1):[i[0]];break}}}}let c=n?.onError,l=r&&c?(e,t)=>{c(e,{location:r.location,params:r.matches?.[0]?.params??{},pattern:Be(r.matches),errorInfo:t})}:void 0;return i.reduceRight((e,n,c)=>{let u,d=!1,f=null,p=null;r&&(u=a&&n.route.id?a[n.route.id]:void 0,f=n.route.errorElement||St,o&&(s<0&&c===0?(zt(`route-fallback`,!1,"No `HydrateFallback` element provided to render during initial hydration"),d=!0,p=null):s===c&&(d=!0,p=n.route.hydrateFallbackElement||null)));let m=t.concat(i.slice(0,c+1)),h=()=>{let t;return t=u?f:d?p:n.route.Component?S.createElement(n.route.Component,null):n.route.element?n.route.element:e,S.createElement(Et,{match:n,routeContext:{outlet:e,matches:m,isDataRoute:r!=null},children:t})};return r&&(n.route.ErrorBoundary||n.route.errorElement||c===0)?S.createElement(Ct,{location:r.location,revalidation:r.revalidation,component:f,error:u,children:h(),routeContext:{outlet:null,matches:m,isDataRoute:!0},onError:l}):h()},null)}function Ot(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function kt(e){let t=S.useContext(qe);return E(t,Ot(e)),t}function At(e){let t=S.useContext(Je);return E(t,Ot(e)),t}function jt(e){let t=S.useContext(nt);return E(t,Ot(e)),t}function Mt(e){let t=jt(e),n=t.matches[t.matches.length-1];return E(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function Nt(){return Mt(`useRouteId`)}function Pt(){let e=At(`useNavigation`);return S.useMemo(()=>{let{matches:t,historyAction:n,...r}=e.navigation;return r},[e.navigation])}function Ft(){let{matches:e,loaderData:t}=At(`useMatches`);return S.useMemo(()=>e.map(e=>le(e,t)),[e,t])}function It(){let e=S.useContext(rt),t=At(`useRouteError`),n=Mt(`useRouteError`);return e===void 0?t.errors?.[n]:e}function Lt(){let{router:e}=kt(`useNavigate`),t=Mt(`useNavigate`),n=S.useRef(!1);return pt(()=>{n.current=!0}),S.useCallback(async(r,i={})=>{D(n.current,ft),n.current&&(typeof r==`number`?await e.navigate(r):await e.navigate(r,{fromRouteId:t,...i}))},[e,t])}var Rt={};function zt(e,t,n){!t&&!Rt[e]&&(Rt[e]=!0,D(!1,n))}S.memo(Bt);function Bt({routes:e,manifest:t,future:n,state:r,isStatic:i,onError:a}){return bt(e,void 0,{manifest:t,state:r,isStatic:i,onError:a,future:n})}function Vt({to:e,replace:t,state:n,relative:r}){E(ut(),` may be used only in the context of a component.`);let{static:i}=S.useContext(et);D(!i,` must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.`);let{matches:a}=S.useContext(nt),{pathname:o}=dt(),s=mt(),c=je(e,Ae(a),o,r===`path`),l=JSON.stringify(c);return S.useEffect(()=>{s(JSON.parse(l),{replace:t,state:n,relative:r})},[s,l,r,t,n]),null}function Ht(e){return _t(e.context)}function Ut(e){E(!1,`A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .`)}function Wt({basename:e=`/`,children:t=null,location:n,navigationType:r=`POP`,navigator:i,static:a=!1,useTransitions:o}){E(!ut(),`You cannot render a inside another . You should never have more than one in your app.`);let s=e.replace(/^\/*/,`/`),c=S.useMemo(()=>({basename:s,navigator:i,static:a,useTransitions:o,future:{}}),[s,i,a,o]);typeof n==`string`&&(n=oe(n));let{pathname:l=`/`,search:u=``,hash:d=``,state:f=null,key:p=`default`,mask:m}=n,h=S.useMemo(()=>{let e=Te(l,s);return e==null?null:{location:{pathname:e,search:u,hash:d,state:f,key:p,mask:m},navigationType:r}},[s,l,u,d,f,p,r,m]);return D(h!=null,` is not able to match the URL "${l}${u}${d}" because it does not start with the basename, so the won't render anything.`),h==null?null:S.createElement(et.Provider,{value:c},S.createElement(tt.Provider,{children:t,value:h}))}function Gt({children:e,location:t}){return yt(Kt(e),t)}S.Component;function Kt(e,t=[]){let n=[];return S.Children.forEach(e,(e,r)=>{if(!S.isValidElement(e))return;let i=[...t,r];if(e.type===S.Fragment){n.push.apply(n,Kt(e.props.children,i));return}E(e.type===Ut,`[${typeof e.type==`string`?e.type:e.type.name}] is not a component. All component children of must be a or `),E(!e.props.index||!e.props.children,`An index route cannot have child routes.`);let a={id:e.props.id||i.join(`-`),caseSensitive:e.props.caseSensitive,element:e.props.element,Component:e.props.Component,index:e.props.index,path:e.props.path,middleware:e.props.middleware,loader:e.props.loader,action:e.props.action,hydrateFallbackElement:e.props.hydrateFallbackElement,HydrateFallback:e.props.HydrateFallback,errorElement:e.props.errorElement,ErrorBoundary:e.props.ErrorBoundary,hasErrorBoundary:e.props.hasErrorBoundary===!0||e.props.ErrorBoundary!=null||e.props.errorElement!=null,shouldRevalidate:e.props.shouldRevalidate,handle:e.props.handle,lazy:e.props.lazy};e.props.children&&(a.children=Kt(e.props.children,i)),n.push(a)}),n}var qt=`get`,Jt=`application/x-www-form-urlencoded`;function Yt(e){return typeof HTMLElement<`u`&&e instanceof HTMLElement}function Xt(e){return Yt(e)&&e.tagName.toLowerCase()===`button`}function Zt(e){return Yt(e)&&e.tagName.toLowerCase()===`form`}function Qt(e){return Yt(e)&&e.tagName.toLowerCase()===`input`}function $t(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function en(e,t){return e.button===0&&(!t||t===`_self`)&&!$t(e)}var tn=null;function nn(){if(tn===null)try{new FormData(document.createElement(`form`),0),tn=!1}catch{tn=!0}return tn}var rn=new Set([`application/x-www-form-urlencoded`,`multipart/form-data`,`text/plain`]);function an(e){return e!=null&&!rn.has(e)?(D(!1,`"${e}" is not a valid \`encType\` for \`\`/\`\` and will default to "${Jt}"`),null):e}function on(e,t){let n,r,i,a,o;if(Zt(e)){let o=e.getAttribute(`action`);r=o?Te(o,t):null,n=e.getAttribute(`method`)||qt,i=an(e.getAttribute(`enctype`))||Jt,a=new FormData(e)}else if(Xt(e)||Qt(e)&&(e.type===`submit`||e.type===`image`)){let o=e.form;if(o==null)throw Error(`Cannot submit a -- 2.52.0 From e4460195463ac572a23fafac01ca0c70d7fec932 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 14:23:58 +0800 Subject: [PATCH 14/58] =?UTF-8?q?fix(fe):=20=E8=A1=A5=E9=BD=90=E6=97=A0?= =?UTF-8?q?=E5=AE=A0=E7=89=A9=E7=8A=B6=E6=80=81=20+=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E5=A4=B1=E8=B4=A5=E4=B8=8D=E5=86=8D=E9=9D=99?= =?UTF-8?q?=E9=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自查发现的四处,都属于「不报错但用户懵」: 1. record/plan/report 三页在 currentPetId 为空时直接 return,留下一堆 空卡片却不解释——用户以为坏了。加统一的 .no-pet 引导块,说清建档后 会有什么,并给一个建档按钮。 2. 首页门面卡在没建档时点击会打开「编辑宠物」的空表单。改成没档案就走 「添加」,文案也跟着变成「点这里建一份档案」。 3. 没建档时在快速记录弹层点「保存」,createAndClose 因为拿不到 petID 直接 close 掉——用户以为存上了,其实什么都没发生。改成明确提示。 4. 用户主动触发的操作失败不再静默:勾任务、全部完成、勾计划节点、点赞 四处的 .catch(() => {}) 换成 toast。后台加载类的静默保持不变—— 那些失败了重进页面会自愈,弹 toast 反而是噪音。 事件绑定做了一次全量扫描:18 个 wxml 里所有 bind/catch 绑的方法在对应 js 里都有实现,没有「点了没反应」的死按钮。 Co-Authored-By: Claude Opus 5 --- pets-fe/app.wxss | 14 ++++++++++++++ pets-fe/components/bottom-sheet/bottom-sheet.js | 7 ++++++- pets-fe/pages/community/community.js | 2 +- pets-fe/pages/home/home.js | 9 +++++++-- pets-fe/pages/home/home.wxml | 4 ++-- pets-fe/pages/plan/plan.js | 3 ++- pets-fe/pages/plan/plan.wxml | 7 +++++++ pets-fe/pages/record/record.wxml | 7 +++++++ pets-fe/pages/report/report.wxml | 7 +++++++ 9 files changed, 53 insertions(+), 7 deletions(-) diff --git a/pets-fe/app.wxss b/pets-fe/app.wxss index 519d25d..abbe876 100644 --- a/pets-fe/app.wxss +++ b/pets-fe/app.wxss @@ -343,3 +343,17 @@ page{scrollbar-width:none;-ms-overflow-style:none} .msg{max-width:88%;border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-md);line-height:1.55} .msg.ai{background:var(--green-soft);align-self:flex-start} .msg.user{background:var(--primary-soft);align-self:flex-end} + +/* 没有宠物时的引导块。四个主页面都会 currentPetId 为空直接 return, + 留下一堆空卡片却不解释为什么——用户以为是坏了。 */ +.no-pet{ + background:#fff;border-radius:var(--r-lg);box-shadow:var(--sd-1); + padding:var(--sp-6) var(--sp-5);text-align:center;margin-bottom:var(--sp-4); +} +.no-pet-ic{ + width:104rpx;height:104rpx;border-radius:var(--r-md);margin:0 auto var(--sp-3); + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink); +} +.no-pet-b{font-size:var(--fs-lg);font-weight:var(--fw-b)} +.no-pet-p{color:var(--muted);font-size:var(--fs-sm);margin:var(--sp-2) 0 var(--sp-4);line-height:1.6} diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index 1be5ea5..4984391 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -584,10 +584,15 @@ Component({ async createAndClose(rec) { const id = store.currentPetId(); - if (!rec || !id) { + if (!rec) { this.close(); return; } + // 没建档时点「保存」原来是静默关掉弹层,用户以为存上了,其实什么都没发生 + if (!id) { + wx.showToast({ title: '先建一份宠物档案再记录', icon: 'none' }); + return; + } if (this.data.saving) return; this.setData({ saving: true }); try { diff --git a/pets-fe/pages/community/community.js b/pets-fe/pages/community/community.js index b2c994d..9de9097 100644 --- a/pets-fe/pages/community/community.js +++ b/pets-fe/pages/community/community.js @@ -80,7 +80,7 @@ Page({ .then((res) => { this.setData({ [`posts[${i}].like_count`]: res.like_count, [`posts[${i}].liked`]: true }); }) - .catch(() => {}); + .catch((e) => toastErr(e, '点赞失败')); }, openComments(e) { this.setData({ sheetPostId: e.currentTarget.dataset.id, sheetType: 'comments', sheetShow: true }); diff --git a/pets-fe/pages/home/home.js b/pets-fe/pages/home/home.js index 488a97d..f4e559a 100644 --- a/pets-fe/pages/home/home.js +++ b/pets-fe/pages/home/home.js @@ -154,7 +154,7 @@ Page({ this.setTasks(tasks); this.loadSummary(); }) - .catch(() => {}); + .catch((e) => toastErr(e, '操作失败')); }, completeTasks() { const id = store.currentPetId(); @@ -165,7 +165,7 @@ Page({ this.setTasks((tasks || []).map(mapTask)); this.loadSummary(); }) - .catch(() => {}); + .catch((e) => toastErr(e, '操作失败')); }, openSheet(e) { this.openSheetType(e.currentTarget.dataset.type); @@ -185,6 +185,11 @@ Page({ onAddPet() { this.openSheetType('addPet'); }, + // 没建档时点门面卡应该去「添加」,而不是打开一个空的编辑表单 + onHeroTap() { + if (this.data.pet && this.data.pet.id) this.openSheetType('editPet'); + else this.openSheetType('addPet'); + }, onEditPet() { this.openSheetType('editPet'); }, diff --git a/pets-fe/pages/home/home.wxml b/pets-fe/pages/home/home.wxml index 6aa8c07..aa928af 100644 --- a/pets-fe/pages/home/home.wxml +++ b/pets-fe/pages/home/home.wxml @@ -16,7 +16,7 @@ - + {{summary.health_pct}}% @@ -24,7 +24,7 @@ {{pet.name || '还没有毛孩子'}} - {{undoneText}} + {{pet.id ? undoneText : '点这里建一份档案,任务和提醒会自动排好'}} {{item.text}} diff --git a/pets-fe/pages/plan/plan.js b/pets-fe/pages/plan/plan.js index 528b853..304e7d8 100644 --- a/pets-fe/pages/plan/plan.js +++ b/pets-fe/pages/plan/plan.js @@ -1,5 +1,6 @@ const store = require('../../utils/store.js'); const api = require('../../utils/api.js'); +const { toastErr } = require('../../utils/ui.js'); // "2026-07-04" → "7月4日" function fmtMD(date) { @@ -131,7 +132,7 @@ Page({ // 计划明细勾选 toggleTimelineTask(e) { const id = e.currentTarget.dataset.id; - api.togglePlanTask(id).then(() => this.loadTimeline()).catch(() => {}); + api.togglePlanTask(id).then(() => this.loadTimeline()).catch((e) => toastErr(e, '操作失败')); }, // AI 计划 onAiInput(e) { diff --git a/pets-fe/pages/plan/plan.wxml b/pets-fe/pages/plan/plan.wxml index edcc95f..b1b3270 100644 --- a/pets-fe/pages/plan/plan.wxml +++ b/pets-fe/pages/plan/plan.wxml @@ -4,6 +4,13 @@ + + + 还没有毛孩子的档案 + 建好档会按它的年龄阶段自动排好 30 天计划和疫苗驱虫提醒。 + 建一份档案 + + diff --git a/pets-fe/pages/record/record.wxml b/pets-fe/pages/record/record.wxml index 68a12ec..64203d9 100644 --- a/pets-fe/pages/record/record.wxml +++ b/pets-fe/pages/record/record.wxml @@ -4,6 +4,13 @@ + + + 还没有毛孩子的档案 + 建好档才能记体重、便便、饮食这些,趋势图也是从这些记录里长出来的。 + 建一份档案 + + 记一笔 diff --git a/pets-fe/pages/report/report.wxml b/pets-fe/pages/report/report.wxml index be7b06a..9d14b12 100644 --- a/pets-fe/pages/report/report.wxml +++ b/pets-fe/pages/report/report.wxml @@ -4,6 +4,13 @@ + + + 还没有毛孩子的档案 + 成长报告和账单都基于记录生成,先建个档开始记吧。 + 建一份档案 + + 本周成长报告{{report.health_status || '稳定成长'}} {{report.summary || '暂无本周数据'}} -- 2.52.0 From 75765b3ee8721dc866685b5eb2f6dd90f131f56c Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 15:03:36 +0800 Subject: [PATCH 15/58] =?UTF-8?q?feat:=20=E5=81=A5=E5=BA=B7=E6=B4=9E?= =?UTF-8?q?=E5=AF=9F=E2=80=94=E2=80=94=E6=8A=8A=E6=95=A3=E8=90=BD=E7=9A=84?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=8F=98=E6=88=90=E8=83=BD=E7=9C=8B=E6=87=82?= =?UTF-8?q?=E7=9A=84=E7=BB=93=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前用户记几十条数据只换回一条折线,数据没有回到他身上,所以不记也不亏。 新增 GET /api/pets/:id/insights,只看最近 90 天(更早的对「现在怎么样」 没参考价值,还会让关联分析找出一堆巧合),产出最多 6 条按严重度排序的结论: 1. 体重趋势 —— 单次数字没意义,跨度 ≥14 天的连续同向变化才算。 跌 10% 报警建议血检,涨 15% 提醒控制,跌 5% 持续观察 2. 换粮 → 软便的时间关联 —— 找异常排便前 72 小时内的饮食记录。 这是用户最看不出来的一类:两条记录隔两三天、分属不同类型,翻时间轴翻不出来 3. 异常扎堆 —— 两周内 ≥2 次异常。偶发一次和反复出现完全不是一回事 4. 逾期提醒 —— 设了不看等于没设 5. 同龄体重对比 —— 同物种、月龄差 2 个月内其它宠物的中位数。 样本 <8 只直接不显示:拿 3 只算出来的「中位数」比不给还糟 6. 记录习惯 —— 数据不足时negative空手而归,给一句「再记几条就能看出规律」 每条都带 evidence(支撑它的具体数据)和 action(点击直接跳到对应记录入口), 结论不能只是断言。文案沿用 AI 助手同一套护栏:不做诊断,异常一律写清 什么时候必须就医。 前端落在记录页体重趋势卡上方,三档配色区分严重度。 实测(造 4 条体重下滑 + 换粮 + 软便 + 两次异常): 🔴 体重掉了 13%,建议就医检查(39 天内 4.50→3.90kg) 🔴 两周内记了 2 次异常 🟠 这次「软便」之前 2 天有过饮食变化(7月20日换粮 → 7月22日软便) Co-Authored-By: Claude Opus 5 --- pets-be/internal/handler/record.go | 11 ++ pets-be/internal/router/router.go | 1 + pets-be/internal/service/insight.go | 287 ++++++++++++++++++++++++++++ pets-fe/pages/record/record.js | 21 ++ pets-fe/pages/record/record.wxml | 12 ++ pets-fe/pages/record/record.wxss | 15 ++ pets-fe/utils/api.js | 1 + 7 files changed, 348 insertions(+) create mode 100644 pets-be/internal/service/insight.go diff --git a/pets-be/internal/handler/record.go b/pets-be/internal/handler/record.go index deab119..d1b9703 100644 --- a/pets-be/internal/handler/record.go +++ b/pets-be/internal/handler/record.go @@ -79,3 +79,14 @@ func (h *Handler) WeightTrend(c *gin.Context) { } response.OK(c, points) } + +// PetInsights GET /api/pets/:id/insights +// 把散落的记录变成结论:体重趋势、换粮与软便的关联、异常扎堆、逾期提醒、同龄对比。 +func (h *Handler) PetInsights(c *gin.Context) { + list, err := h.svc.PetInsights(middleware.UserID(c), idParam(c, "id")) + if err != nil { + respondErr(c, err) + return + } + response.OK(c, list) +} diff --git a/pets-be/internal/router/router.go b/pets-be/internal/router/router.go index 8418d06..b110ac5 100644 --- a/pets-be/internal/router/router.go +++ b/pets-be/internal/router/router.go @@ -59,6 +59,7 @@ func registerUserAPI(api *gin.RouterGroup, h *handler.Handler, jm *appjwt.Manage g.GET("/pets/:id/records", h.ListRecords) g.POST("/pets/:id/records", h.CreateRecord) g.GET("/pets/:id/records/weight-trend", h.WeightTrend) + g.GET("/pets/:id/insights", h.PetInsights) g.DELETE("/records/:id", h.DeleteRecord) g.GET("/pets/:id/tasks", h.ListTasks) diff --git a/pets-be/internal/service/insight.go b/pets-be/internal/service/insight.go new file mode 100644 index 0000000..4f3426d --- /dev/null +++ b/pets-be/internal/service/insight.go @@ -0,0 +1,287 @@ +package service + +import ( + "fmt" + "sort" + "time" + + "github.com/sundynix/pets-be/internal/model" +) + +// Insight 一条健康洞察。 +// 这是「记录」这件事的兑现方式:用户记了几十条数据,之前只换回一条折线, +// 数据没有回到他身上。洞察要说出他自己看不出来的东西。 +type Insight struct { + Kind string `json:"kind"` // trend | correlation | overdue | benchmark | habit + Level string `json:"level"` // info | warn | alert + Title string `json:"title"` // 一句话结论 + Detail string `json:"detail"` // 依据 + 建议 + Action string `json:"action"` // 关联的记录弹层类型,前端据此给按钮 + Evidence string `json:"evidence"` // 支撑这条结论的具体数据 +} + +const ( + insightInfo = "info" + insightWarn = "warn" + insightAlert = "alert" +) + +// PetInsights 汇总一只宠物当前值得说的事。按严重度排序,最多 6 条。 +func (s *Service) PetInsights(userID, petID string) ([]Insight, error) { + pet, err := s.ownedPet(userID, petID) + if err != nil { + return nil, err + } + + // 只看最近 90 天。更早的数据对「现在怎么样」没有参考价值, + // 还会让关联分析找出一堆巧合。 + since := time.Now().AddDate(0, 0, -90) + var records []model.HealthRecord + if err := s.db.Where("pet_id = ? AND occurred_at >= ?", petID, since). + Order("occurred_at asc").Find(&records).Error; err != nil { + return nil, err + } + + var out []Insight + out = appendIf(out, s.weightTrendInsight(records)) + out = appendIf(out, s.foodPoopCorrelation(records)) + out = appendIf(out, s.symptomClusterInsight(records)) + out = appendIf(out, s.overdueReminderInsight(petID)) + out = appendIf(out, s.weightBenchmark(pet, records)) + out = appendIf(out, s.recordHabitInsight(records)) + + // alert > warn > info,同级保持原顺序 + rank := map[string]int{insightAlert: 0, insightWarn: 1, insightInfo: 2} + sort.SliceStable(out, func(i, j int) bool { return rank[out[i].Level] < rank[out[j].Level] }) + if len(out) > 6 { + out = out[:6] + } + return out, nil +} + +func appendIf(list []Insight, in *Insight) []Insight { + if in != nil { + list = append(list, *in) + } + return list +} + +func byType(records []model.HealthRecord, t string) []model.HealthRecord { + var out []model.HealthRecord + for _, r := range records { + if r.Type == t { + out = append(out, r) + } + } + return out +} + +// weightTrendInsight 体重趋势。单次数字没意义,连续同向变化才有。 +func (s *Service) weightTrendInsight(records []model.HealthRecord) *Insight { + w := byType(records, model.RecordWeight) + if len(w) < 3 { + return nil + } + first, last := w[0], w[len(w)-1] + if first.NumValue <= 0 || last.NumValue <= 0 { + return nil + } + days := int(last.OccurredAt.Sub(first.OccurredAt).Hours() / 24) + if days < 14 { + return nil // 时间跨度太短,波动多半是称重误差 + } + pct := (last.NumValue - first.NumValue) / first.NumValue * 100 + ev := fmt.Sprintf("%d 天内 %.2fkg → %.2fkg(%d 次记录)", days, first.NumValue, last.NumValue, len(w)) + + switch { + case pct <= -10: + return &Insight{ + Kind: "trend", Level: insightAlert, Action: "symptom", + Title: fmt.Sprintf("体重掉了 %.0f%%,建议就医检查", -pct), + Detail: "短期内明显掉秤,常见于甲亢、慢性肾病、糖尿病、寄生虫和口腔问题。即使精神食欲看起来正常,也建议做一次血检。", + Evidence: ev, + } + case pct >= 15: + return &Insight{ + Kind: "trend", Level: insightWarn, Action: "food", + Title: fmt.Sprintf("体重涨了 %.0f%%,注意控制", pct), + Detail: "超重是绝大多数慢性病的起点。摸得到肋骨但看不见明显轮廓才是标准体型,先从减少 10-20% 的喂食量开始。", + Evidence: ev, + } + case pct <= -5: + return &Insight{ + Kind: "trend", Level: insightWarn, Action: "weight", + Title: fmt.Sprintf("体重在缓慢下降(%.0f%%)", -pct), + Detail: "还不到紧急程度,但值得继续盯。保持每周称重,如果一个月内继续下降就去做次体检。", + Evidence: ev, + } + } + return &Insight{ + Kind: "trend", Level: insightInfo, Action: "weight", + Title: "体重保持稳定", + Detail: "这段时间的波动在正常范围内,继续保持现在的喂食量和运动量。", + Evidence: ev, + } +} + +// foodPoopCorrelation 换粮/饮食变化 → 排便异常的时间关联。 +// 这是用户自己最看不出来的一类:两条记录隔了两三天,翻时间轴翻不出规律。 +func (s *Service) foodPoopCorrelation(records []model.HealthRecord) *Insight { + foods := byType(records, model.RecordFood) + poops := byType(records, model.RecordPoop) + if len(foods) == 0 || len(poops) == 0 { + return nil + } + for _, p := range poops { + if p.Category == "" || p.Category == "正常" { + continue + } + // 往前找 3 天内的饮食记录 + for i := len(foods) - 1; i >= 0; i-- { + f := foods[i] + gap := p.OccurredAt.Sub(f.OccurredAt) + if gap < 0 || gap > 72*time.Hour { + continue + } + return &Insight{ + Kind: "correlation", Level: insightWarn, Action: "food", + Title: fmt.Sprintf("这次「%s」之前 %d 天有过饮食变化", p.Category, int(gap.Hours()/24)), + Detail: "换粮或加新食物引起的软便很常见。回到原来的粮,之后按 7 天过渡:每天替换约 1/7,软便就放慢速度。持续超过 3 天或带血要就医。", + Evidence: fmt.Sprintf("%s 记录「%s」→ %s 出现「%s」", + f.OccurredAt.Format("1月2日"), f.Title, p.OccurredAt.Format("1月2日"), p.Category), + } + } + } + return nil +} + +// symptomClusterInsight 异常记录扎堆。单次异常不说明什么,短期内反复才是信号。 +func (s *Service) symptomClusterInsight(records []model.HealthRecord) *Insight { + sym := byType(records, model.RecordSymptom) + if len(sym) < 2 { + return nil + } + recent := 0 + cut := time.Now().AddDate(0, 0, -14) + var last time.Time + for _, r := range sym { + if r.OccurredAt.After(cut) { + recent++ + last = r.OccurredAt + } + } + if recent < 2 { + return nil + } + return &Insight{ + Kind: "habit", Level: insightAlert, Action: "symptom", + Title: fmt.Sprintf("两周内记了 %d 次异常", recent), + Detail: "反复出现的异常和偶发一次完全不是一回事。把这些记录导出成就医摘要带去医院,比口头描述有用得多。", + Evidence: fmt.Sprintf("最近一次:%s", last.Format("1月2日")), + } +} + +// overdueReminderInsight 已经过期的提醒。设了不看等于没设。 +func (s *Service) overdueReminderInsight(petID string) *Insight { + var rems []model.Reminder + if err := s.db.Where("pet_id = ? AND next_due_date IS NOT NULL AND next_due_date < ?", + petID, time.Now()).Order("next_due_date asc").Find(&rems).Error; err != nil { + return nil + } + if len(rems) == 0 { + return nil + } + r := rems[0] + days := int(time.Since(*r.NextDueDate).Hours() / 24) + action := "vaccine" + if r.Type == model.ReminderDeworm { + action = "medicine" + } + return &Insight{ + Kind: "overdue", Level: insightAlert, Action: action, + Title: fmt.Sprintf("「%s」已经过期 %d 天", r.Title, days), + Detail: "疫苗和驱虫拖久了保护力会断档,尤其驱虫,遛弯和接触其它动物的风险是持续的。补上之后记得把下次日期也设好。", + Evidence: fmt.Sprintf("原定 %s", r.NextDueDate.Format("2006年1月2日")), + } +} + +// weightBenchmark 同龄同物种对比。 +// 这是单机数据做不到、只有平台侧能给的价值。样本不足就不给结论—— +// 拿 3 只猫算出来的「中位数」比不给还糟。 +func (s *Service) weightBenchmark(pet *model.Pet, records []model.HealthRecord) *Insight { + w := byType(records, model.RecordWeight) + if len(w) == 0 || pet.Birthday == nil || pet.Birthday.IsZero() { + return nil + } + mine := w[len(w)-1].NumValue + if mine <= 0 { + return nil + } + months := monthsSince(*pet.Birthday) + + // 同物种、月龄相差 2 个月以内的其它宠物,取各自最近一次体重 + lo := time.Now().AddDate(0, -(months + 2), 0) + hi := time.Now().AddDate(0, -maxInt(months-2, 0), 0) + var peers []float64 + rows, err := s.db.Raw(` + SELECT r.num_value FROM sundynix_health_records r + JOIN ( + SELECT pet_id, MAX(occurred_at) AS t FROM sundynix_health_records + WHERE type = ? GROUP BY pet_id + ) latest ON latest.pet_id = r.pet_id AND latest.occurred_at = latest.t + JOIN sundynix_pets p ON p.id = r.pet_id + WHERE r.type = ? AND r.num_value > 0 AND p.id <> ? + AND p.type = ? AND p.birthday BETWEEN ? AND ?`, + model.RecordWeight, model.RecordWeight, pet.ID, pet.Type, lo, hi).Rows() + if err != nil { + return nil + } + defer rows.Close() + for rows.Next() { + var v float64 + if rows.Scan(&v) == nil && v > 0 { + peers = append(peers, v) + } + } + // 样本太少给不出可信的参考值,宁可不显示 + if len(peers) < 8 { + return nil + } + sort.Float64s(peers) + med := peers[len(peers)/2] + diff := (mine - med) / med * 100 + + level, title := insightInfo, "体重和同龄伙伴差不多" + if diff >= 20 { + level, title = insightWarn, fmt.Sprintf("比同龄伙伴重 %.0f%%", diff) + } else if diff <= -20 { + level, title = insightWarn, fmt.Sprintf("比同龄伙伴轻 %.0f%%", -diff) + } + return &Insight{ + Kind: "benchmark", Level: level, Action: "weight", + Title: title, + Detail: "这只是同月龄的横向参考,品种和体型差异很大,不能当成标准。真正要看的还是它自己的体重曲线是否平稳。", + Evidence: fmt.Sprintf("%d 月龄 · 它 %.2fkg,%d 只同龄%s的中位数 %.2fkg", + months, mine, len(peers), pet.Type, med), + } +} + +// recordHabitInsight 记录习惯。没数据就没洞察,这条负责把用户拉回来记。 +func (s *Service) recordHabitInsight(records []model.HealthRecord) *Insight { + if len(records) >= 5 { + return nil + } + return &Insight{ + Kind: "habit", Level: insightInfo, Action: "weight", + Title: "再记几条,这里就能看出规律了", + Detail: "体重、便便、饮食三类各记几次之后,能自动帮你发现「换粮第几天开始软便」这种自己翻记录看不出来的关联。", + Evidence: fmt.Sprintf("目前共 %d 条记录", len(records)), + } +} + +func maxInt(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/pets-fe/pages/record/record.js b/pets-fe/pages/record/record.js index 7a7beef..f1472fa 100644 --- a/pets-fe/pages/record/record.js +++ b/pets-fe/pages/record/record.js @@ -93,6 +93,12 @@ function buildChart(points) { return { svg: 'data:image/svg+xml,' + encodeURIComponent(svg), dots }; } +// 洞察等级 → 图标。alert 用警告号,其余按类别给 +const INS_ICON = { alert: 'warn', warn: 'warn', info: 'trend' }; +function mapInsight(i) { + return { ...i, icon: i.level === 'info' ? (INS_ICON.info) : INS_ICON.alert }; +} + const REC_PAGE = 6; Page({ @@ -105,6 +111,7 @@ Page({ recFilters: REC_FILTERS, recFilterIdx: 0, recordItems: RECORD_ITEMS, + insights: [], trendSvg: '', trendStats: null, trendDots: [], @@ -165,6 +172,19 @@ Page({ }, }); }, + // 健康洞察:把散落的记录变成结论。点一条直接跳到对应的记录入口 + loadInsights() { + const id = store.currentPetId(); + if (!id) return this.setData({ insights: [] }); + api + .petInsights(id) + .then((list) => this.setData({ insights: (list || []).map(mapInsight) })) + .catch(() => this.setData({ insights: [] })); + }, + onTapInsight(e) { + const it = this.data.insights[e.currentTarget.dataset.index]; + if (it && it.action) this.openSheetType(it.action); + }, loadRecords() { const id = store.currentPetId(); if (!id) return; @@ -176,6 +196,7 @@ Page({ }) .catch((e) => toastErr(e)); this.loadTrend(); + this.loadInsights(); }, loadMoreRecords() { const id = store.currentPetId(); diff --git a/pets-fe/pages/record/record.wxml b/pets-fe/pages/record/record.wxml index 64203d9..87d6d5f 100644 --- a/pets-fe/pages/record/record.wxml +++ b/pets-fe/pages/record/record.wxml @@ -20,6 +20,18 @@ + + 健康洞察来自你的记录 + + + + {{item.title}} + + {{item.detail}} + {{item.evidence}} + + + 体重趋势记录 最新 {{trendStats.latest}}kg · 较首次 {{trendStats.delta >= 0 ? '+' : ''}}{{trendStats.delta}}kg · 共 {{trendStats.count}} 次 diff --git a/pets-fe/pages/record/record.wxss b/pets-fe/pages/record/record.wxss index 33a0db1..25c7996 100644 --- a/pets-fe/pages/record/record.wxss +++ b/pets-fe/pages/record/record.wxss @@ -42,3 +42,18 @@ margin-top:var(--sp-3);padding:var(--sp-3);text-align:center;color:var(--primary-dark); background:var(--surface-2);border-radius:var(--r-md);font-size:var(--fs-sm);font-weight:var(--fw-b); } + +/* 健康洞察 */ +.ins{border-radius:var(--r-md);padding:var(--sp-4);margin-bottom:var(--sp-2)} +.ins:last-child{margin-bottom:0} +.ins-info{background:var(--surface-2)} +.ins-warn{background:var(--primary-soft)} +.ins-alert{background:var(--red-soft)} +.ins-head{display:flex;align-items:flex-start;gap:var(--sp-2)} +.ins-ic{flex:none;margin-top:2rpx} +.ins-info .ins-ic{color:var(--green-ink)} +.ins-warn .ins-ic{color:var(--primary-ink)} +.ins-alert .ins-ic{color:var(--red-ink)} +.ins-title{flex:1;font-size:var(--fs-md);font-weight:var(--fw-b);line-height:1.4} +.ins-detail{color:var(--text-2);font-size:var(--fs-sm);line-height:1.6;margin-top:var(--sp-2)} +.ins-ev{color:var(--muted);font-size:var(--fs-cap);margin-top:var(--sp-2)} diff --git a/pets-fe/utils/api.js b/pets-fe/utils/api.js index c4aa5ab..ba0f016 100644 --- a/pets-fe/utils/api.js +++ b/pets-fe/utils/api.js @@ -66,6 +66,7 @@ const api = { }, createRecord: (id, body) => request({ url: `/api/pets/${id}/records`, method: 'POST', data: body }), deleteRecord: (recordId) => request({ url: `/api/records/${recordId}`, method: 'DELETE' }), + petInsights: (id) => request({ url: `/api/pets/${id}/insights` }), weightTrend: (id) => request({ url: `/api/pets/${id}/records/weight-trend` }), // 任务 -- 2.52.0 From 0dee6e27d2c52b57c821a5639042874653a89e86 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 15:08:56 +0800 Subject: [PATCH 16/58] =?UTF-8?q?fix(fe):=20=E6=88=90=E9=95=BF=E6=B5=B7?= =?UTF-8?q?=E6=8A=A5=E7=9A=84=E3=80=8C=E4=BF=9D=E5=AD=98/=E5=88=86?= =?UTF-8?q?=E4=BA=AB=E3=80=8D=E5=8E=9F=E6=9D=A5=E6=98=AF=E4=B8=AA=E8=A3=85?= =?UTF-8?q?=E9=A5=B0=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 报告页 → 分享卡片,弹层底部那个「保存 / 分享卡片」按钮绑的是 bindtap="close" —— 点了只是把弹层关掉,既不保存也不分享。按钮文案 承诺了两件事,一件也没做。 拆成两个真按钮: - 分享给朋友:走微信原生 open-type="share",转发标题带上宠物名 - 保存到相册:把海报画进离屏 canvas 再存相册 canvas 部分的几个坑: - 画布用 position:fixed 挪到屏幕外,不能 display:none —— 那样 selectorQuery 取不到节点 - 按 pixelRatio 放大再 scale,否则高分屏上导出的图是糊的 - 相册权限被拒过一次后 wx.authorize 不会再弹,必须 wx.openSetting 引导,否则这里会永远静默失败——正是这次要修的那类问题 Co-Authored-By: Claude Opus 5 --- pets-fe/components/bottom-sheet/bottom-sheet.js | 1 + pets-fe/components/bottom-sheet/bottom-sheet.wxml | 9 ++++++++- pets-fe/components/bottom-sheet/bottom-sheet.wxss | 3 +++ pets-fe/pages/report/report.js | 7 +++++-- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index 4984391..d88579d 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -101,6 +101,7 @@ Component({ reportDetail: null, proInfo: null, saving: false, + posterSaving: false, }, observers: { show: function (show) { diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index 49d23cb..b8f9567 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -198,7 +198,14 @@ module.exports.sel = function (map, key, index, def) { 健康状态:{{poster ? poster.headline : '稳定成长'}} 生成自:肉垫计划 - + + + + + + diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index ec6d21d..4857492 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -79,3 +79,6 @@ margin-left:var(--sp-1);font-size:var(--fs-cap);font-weight:var(--fw-b); color:var(--primary-ink);background:var(--primary-soft);padding:2rpx var(--sp-1);border-radius:var(--r-full); } + +/* 离屏画布:挪到可视区外而不是 display:none,否则 selectorQuery 取不到节点 */ +.poster-canvas{position:fixed;left:-9999rpx;top:0;width:600rpx;height:840rpx} diff --git a/pets-fe/pages/report/report.js b/pets-fe/pages/report/report.js index f8eeb97..c37d532 100644 --- a/pets-fe/pages/report/report.js +++ b/pets-fe/pages/report/report.js @@ -62,9 +62,12 @@ Page({ wx.navigateTo({ url: '/pages/ai/ai' }); }, onShareAppMessage() { - return { title: '看看我家毛孩子的成长报告', path: '/pages/report/report' }; + // 带上宠物名,转发出去别人一眼知道是谁家的 + const n = (this.data.pet && this.data.pet.name) || '我家毛孩子'; + return { title: `${n} 的成长报告`, path: '/pages/report/report' }; }, onShareTimeline() { - return { title: '看看我家毛孩子的成长报告' }; + const n = (this.data.pet && this.data.pet.name) || '我家毛孩子'; + return { title: `${n} 的成长报告` }; }, }); -- 2.52.0 From c7135424e5971fa1c203de64ddc52b9995e34950 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 15:25:18 +0800 Subject: [PATCH 17/58] =?UTF-8?q?fix(fe):=20=E4=BF=9D=E5=AD=98=E5=88=B0?= =?UTF-8?q?=E7=9B=B8=E5=86=8C=E7=9A=84=E6=96=B9=E6=B3=95=E6=A0=B9=E6=9C=AC?= =?UTF-8?q?=E6=B2=A1=E5=86=99=E8=BF=9B=E5=8E=BB=20+=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=A4=BE=E5=8C=BA=E7=89=88=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 保存到相册点了没反应 上次改的时候,插入方法的锚点用的是「// AI 聊天」那段注释,而它在 AI 独立成页时已经被删掉了 —— 替换没匹配上,onSavePoster / drawPoster / saveToAlbum 三个方法一个都没进 js,按钮绑了个不存在的方法。 我的检查器没拦住,是因为「事件绑定是否有实现」那条写在临时的 audit.js 里,日常只跑 check.js。已经把这条并进 check.js —— 加完立刻抓出了本次 新写的 13 处缺样式 class,说明它管用。 ## 社区 帖子操作栏原来是 space-around 排三个宽度不一的项:点赞数从 9 变 10 整行就会跳。改成三等分,图标 32rpx 居中对齐,没有数字时显示「点赞/评论」 而不是一个孤零零的 0,加了按下态。 帖子头部原来副标题固定写死「宠友」两个字,等于没有信息。换成发布时间 (刚刚 / 12 分钟前 / 3 天前)。 评论弹层原来拿 .record-row 当评论用 —— 那是个「左右两端对齐」的行, 昵称在左内容在右,评论一长就被挤扁,完全不是评论该有的样子。重做成 头像 + 昵称/时间 + 内容的正常结构;没有头像字段就用昵称首字做色块, 比一律显示同一个 emoji 强。发送按钮有输入才点亮,支持键盘回车发送。 Co-Authored-By: Claude Opus 5 --- .../components/bottom-sheet/bottom-sheet.js | 168 +++++++++++++++++- .../components/bottom-sheet/bottom-sheet.wxml | 29 ++- .../components/bottom-sheet/bottom-sheet.wxss | 26 +++ pets-fe/pages/community/community.js | 16 ++ pets-fe/pages/community/community.wxml | 20 ++- pets-fe/pages/community/community.wxss | 12 +- 6 files changed, 253 insertions(+), 18 deletions(-) diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index d88579d..829d59d 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -15,6 +15,21 @@ function daysLater(n) { return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate()); } +// 相对时间。社区里关心的是「多久以前发的」,精确到秒没意义 +function fmtAgo(iso) { + if (!iso) return ''; + const d = new Date(iso); + if (isNaN(d.getTime())) return ''; + const min = Math.floor((Date.now() - d.getTime()) / 60000); + if (min < 1) return '刚刚'; + if (min < 60) return min + ' 分钟前'; + if (min < 60 * 24) return Math.floor(min / 60) + ' 小时前'; + if (min < 60 * 24 * 7) return Math.floor(min / 1440) + ' 天前'; + const p = (n) => (n < 10 ? '0' + n : '' + n); + const sameYear = d.getFullYear() === new Date().getFullYear(); + return (sameYear ? '' : d.getFullYear() + '-') + p(d.getMonth() + 1) + '-' + p(d.getDate()); +} + function ageFromBirthday(bday) { if (!bday) return ''; const b = new Date(bday); @@ -223,6 +238,148 @@ Component({ page.getTabBar().setData({ hidden }); } }, + // ---- 成长海报:画进 canvas 才能存进相册 ---- + + onSavePoster() { + if (this.data.posterSaving) return; + this.setData({ posterSaving: true }); + this.drawPoster() + .then((tempPath) => this.saveToAlbum(tempPath)) + .then(() => wx.showToast({ title: '已保存到相册', icon: 'success' })) + .catch((e) => { + if (e && e.canceled) return; + wx.showToast({ title: (e && e.message) || '保存失败', icon: 'none' }); + }) + .then(() => this.setData({ posterSaving: false })); + }, + + // 把海报画到离屏 canvas 上,返回临时图片路径 + drawPoster() { + const W = 600; + const H = 840; + return new Promise((resolve, reject) => { + wx.createSelectorQuery() + .in(this) + .select('#posterCanvas') + .fields({ node: true, size: true }) + .exec((res) => { + const node = res && res[0] && res[0].node; + if (!node) return reject(new Error('画布还没准备好,稍后再试')); + + // 按设备像素比放大,否则在高分屏上导出的图是糊的 + let dpr = 2; + try { + dpr = (wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync()).pixelRatio || 2; + } catch (err) { + dpr = 2; + } + node.width = W * dpr; + node.height = H * dpr; + const ctx = node.getContext('2d'); + ctx.scale(dpr, dpr); + + const pet = this.data.pet || {}; + const p = this.data.poster || {}; + + const bg = ctx.createLinearGradient(0, 0, W, H); + bg.addColorStop(0, '#FFF7E8'); + bg.addColorStop(1, '#FFFFFF'); + ctx.fillStyle = bg; + ctx.fillRect(0, 0, W, H); + ctx.fillStyle = '#F2DFC3'; + ctx.fillRect(0, 0, W, 8); + + ctx.textAlign = 'center'; + ctx.fillStyle = '#2D2925'; + ctx.font = '600 40px sans-serif'; + ctx.fillText((pet.name || '毛孩子') + ' 的成长报告', W / 2, 96); + + ctx.font = '96px sans-serif'; + ctx.fillText(pet.emoji || '🐾', W / 2, 216); + + ctx.fillStyle = '#8D8277'; + ctx.font = '24px sans-serif'; + ctx.fillText([pet.age, pet.weight, pet.stage].filter(Boolean).join(' | '), W / 2, 268); + + ctx.fillStyle = 'rgba(255,255,255,.8)'; + this.roundRect(ctx, 60, 310, W - 120, 232, 24); + ctx.fill(); + const lines = [ + '完成任务 ' + (p.tasks_completed || 0) + ' 项', + '体重记录 ' + (p.weight_records || 0) + ' 次', + '疫苗记录 ' + (p.vaccine_records || 0) + ' 次', + '高风险异常 ' + (p.high_risk_count || 0) + ' 次', + ]; + ctx.textAlign = 'left'; + ctx.font = '28px sans-serif'; + lines.forEach((t, i) => { + const y = 360 + i * 52; + ctx.fillStyle = '#73BE9D'; + ctx.fillText('✓', 92, y); + ctx.fillStyle = '#443D37'; + ctx.fillText(t, 132, y); + }); + + ctx.textAlign = 'center'; + ctx.fillStyle = '#2D2925'; + ctx.font = '600 30px sans-serif'; + ctx.fillText('健康状态:' + (p.headline || '稳定成长'), W / 2, 620); + + ctx.fillStyle = '#B5A99D'; + ctx.font = '22px sans-serif'; + ctx.fillText('生成自 · 肉垫计划', W / 2, 780); + + // canvas 2d 是同步绘制,画完直接导出 + wx.canvasToTempFilePath( + { + canvas: node, + fileType: 'png', + success: (r) => resolve(r.tempFilePath), + fail: () => reject(new Error('生成图片失败')), + }, + this, + ); + }); + }); + }, + + roundRect(ctx, x, y, w, h, r) { + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); + }, + + // 存相册要相册写权限。用户拒过一次之后 wx.authorize 不会再弹, + // 必须引导他去设置页打开,否则这里会永远静默失败。 + saveToAlbum(filePath) { + return new Promise((resolve, reject) => { + wx.saveImageToPhotosAlbum({ + filePath, + success: resolve, + fail: (err) => { + const msg = (err && err.errMsg) || ''; + if (msg.indexOf('cancel') >= 0) return reject({ canceled: true }); + if (msg.indexOf('auth deny') >= 0 || msg.indexOf('authorize') >= 0) { + wx.showModal({ + title: '需要相册权限', + content: '保存卡片需要允许访问相册,去设置里打开一下?', + confirmText: '去设置', + success: (r) => { + if (r.confirm) wx.openSetting({}); + }, + }); + return reject({ canceled: true }); + } + reject(new Error('保存失败')); + }, + }); + }); + }, + onSeg(e) { const { group, index } = e.currentTarget.dataset; const segSel = Object.assign({}, this.data.segSel, { [group]: Number(index) }); @@ -248,7 +405,16 @@ Component({ loadComments() { if (!this.data.postId) return; api.listComments(this.data.postId) - .then((page) => this.setData({ comments: page.list || [] })) + .then((page) => + this.setData({ + comments: (page.list || []).map((c) => ({ + ...c, + timeText: fmtAgo(c.created_at), + // 没有头像字段,用昵称首字做个色块,比一律显示同一个 emoji 强 + initial: (c.author_name || '?').slice(0, 1), + })), + }), + ) .catch(() => {}); }, // 长按删除自己的评论 diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index b8f9567..ec92a03 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -319,16 +319,27 @@ module.exports.sel = function (map, key, index, def) { - 评论 - - {{item.author_name}} - {{item.content}} + 评论 {{comments.length ? comments.length : ''}} + + + {{item.initial}} + + + {{item.author_name}} + + {{item.timeText}} + + {{item.content}} + - 还没有评论,来抢沙发~ - 长按自己的评论可删除 - - - + + 还没有评论,来抢个沙发 + 长按自己的评论可删除 + + + + 发送 diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index 4857492..550e8ef 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -82,3 +82,29 @@ /* 离屏画布:挪到可视区外而不是 display:none,否则 selectorQuery 取不到节点 */ .poster-canvas{position:fixed;left:-9999rpx;top:0;width:600rpx;height:840rpx} + +/* 评论。原来拿 .record-row(左右两端对齐)当评论用,昵称在左内容在右, + 内容一长就被挤扁。改成头像 + 昵称时间 + 内容的正常结构。 */ +.cm{display:flex;gap:var(--sp-3);padding:var(--sp-3) 0;border-bottom:1rpx solid var(--line)} +.cm:last-of-type{border-bottom:0} +.cm-av{ + width:64rpx;height:64rpx;border-radius:var(--r-sm);flex:none; + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink); + font-size:var(--fs-md);font-weight:var(--fw-b); +} +.cm-body{flex:1;min-width:0} +.cm-head{display:flex;align-items:center;gap:var(--sp-1)} +.cm-name{font-size:var(--fs-sm);font-weight:var(--fw-b);color:var(--text-2)} +.cm-time{margin-left:auto;font-size:var(--fs-cap);color:var(--muted2);flex:none} +.cm-text{margin-top:6rpx;font-size:var(--fs-md);line-height:1.55;word-break:break-word} +.cm-tip{margin-top:var(--sp-3);text-align:center;color:var(--muted2);font-size:var(--fs-cap)} + +.cm-input{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4)} +.cm-input .input{flex:1} +.cm-send{ + flex:none;height:88rpx;padding:0 var(--sp-5);border-radius:var(--r-md); + display:flex;align-items:center;justify-content:center; + background:var(--line);color:#fff;font-size:var(--fs-md);font-weight:var(--fw-b);transition:.16s ease; +} +.cm-send.on{background:var(--cta)} diff --git a/pets-fe/pages/community/community.js b/pets-fe/pages/community/community.js index 9de9097..b3fa87f 100644 --- a/pets-fe/pages/community/community.js +++ b/pets-fe/pages/community/community.js @@ -2,6 +2,21 @@ const store = require('../../utils/store.js'); const api = require('../../utils/api.js'); const { toastErr } = require('../../utils/ui.js'); +// 相对时间。社区里关心的是「多久以前发的」,精确到秒没意义 +function fmtAgo(iso) { + if (!iso) return ''; + const d = new Date(iso); + if (isNaN(d.getTime())) return ''; + const min = Math.floor((Date.now() - d.getTime()) / 60000); + if (min < 1) return '刚刚'; + if (min < 60) return min + ' 分钟前'; + if (min < 60 * 24) return Math.floor(min / 60) + ' 小时前'; + if (min < 60 * 24 * 7) return Math.floor(min / 1440) + ' 天前'; + const p = (n) => (n < 10 ? '0' + n : '' + n); + const sameYear = d.getFullYear() === new Date().getFullYear(); + return (sameYear ? '' : d.getFullYear() + '-') + p(d.getMonth() + 1) + '-' + p(d.getDate()); +} + const TAG_CLASS = { 求助: 'warn', 经验: 'blue', 精选: 'purple', 避坑: 'red', 晒宠: '' }; function mapPost(p) { @@ -22,6 +37,7 @@ function mapPost(p) { user_id: p.user_id, followed: !!p.followed, is_self: !!p.is_self, + timeText: fmtAgo(p.created_at), }; } diff --git a/pets-fe/pages/community/community.wxml b/pets-fe/pages/community/community.wxml index 33d219a..b0246af 100644 --- a/pets-fe/pages/community/community.wxml +++ b/pets-fe/pages/community/community.wxml @@ -14,7 +14,10 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } {{item.author_emoji}} - {{item.author_name}}AI宠友 + + {{item.author_name}}AI + {{item.timeText}} + {{item.tag}} @@ -27,9 +30,18 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } - {{item.like_count}} - {{item.comment_count}} - + + + {{item.like_count || '点赞'}} + + + + {{item.comment_count || '评论'}} + + diff --git a/pets-fe/pages/community/community.wxss b/pets-fe/pages/community/community.wxss index 69d0834..d4b5e37 100644 --- a/pets-fe/pages/community/community.wxss +++ b/pets-fe/pages/community/community.wxss @@ -21,14 +21,18 @@ display:flex;align-items:center;justify-content:center;font-size:56rpx; } -.post-actions{display:flex;justify-content:space-around;border-top:1rpx solid var(--line);padding-top:var(--sp-3)} +/* 三等分。原来是 space-around 排三个宽度不一的项,点赞数一变宽度就跳 */ +.post-actions{display:flex;border-top:1rpx solid var(--line);padding-top:var(--sp-2)} .pa-btn{ - display:flex;align-items:center;gap:var(--sp-1); - color:var(--muted);font-weight:var(--fw-b);font-size:var(--fs-sm); + flex:1;height:72rpx; + display:flex;align-items:center;justify-content:center;gap:var(--sp-1); + color:var(--muted);font-weight:var(--fw);font-size:var(--fs-sm); } +.pa-n{line-height:1} .pa-btn.liked{color:var(--red-ink)} +.pa-btn:active{background:var(--surface-2);border-radius:var(--r-sm)} /* 分享用微信原生 open-type=share,得抹掉 button 默认外观 */ -.pa-share{background:transparent;border:none;padding:0;margin:0;line-height:inherit;height:auto} +.pa-share{background:transparent;border:none;padding:0;margin:0;line-height:inherit} .pa-share::after{border:none} /* 关注按钮 */ -- 2.52.0 From 5b2f8e50bc4ae3081d3b7e86a4ab5955db0d5c5d Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 15:50:38 +0800 Subject: [PATCH 18/58] =?UTF-8?q?fix:=20=E5=B8=A6=20date=20=E6=9F=A5?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=97=B6=E5=8C=BA=E9=94=99=E4=BD=8D=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E9=87=8D=E5=A4=8D=E7=94=9F=E6=88=90=20+=20=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E5=BC=B9=E7=AA=97=E9=87=8D=E5=81=9A=20+=20AI=20?= =?UTF-8?q?=E6=AF=8F=E6=97=A5=E6=AC=A1=E6=95=B0=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 首页添加的任务不显示(根因比表象严重) time.Parse("2006-01-02", q) 返回的是 UTC 时间,dayStart 又保留了 t.Location(),于是带 ?date= 查询时: 查询区间 = 07-29 00:00 UTC ~ 次日 = CST 的 08:00 ~ 次日 08:00 已有任务的 task_date 是 07-29 00:00 CST,落在区间外 后果不只是「新任务不显示」——ensureDayTasks 因此认为今天没有任务, 每刷一次首页就重新生成一批。用户手动加的那条(00:00 CST)永远不在 那个错位窗口里,所以管理页看得到、首页看不到。 全项目 7 处 time.Parse 日期解析统一换成 ParseInLocation + time.Local (任务、日计划、生日、到家日期、提醒到期日都受影响)。 实测:加一条后带 date 查得到 4 条,连查 4 次仍是 4 条不再增长。 ## 评论弹窗 - 改成居中弹出。评论以输入为主,贴底弹层会被键盘顶掉大半屏 - 单行 input 换成自动撑高的 textarea,最多 500 字,带字数 - 支持配图,最多 3 张(评论表加 images 字段) - 空评论原来会直接把弹层关掉,看起来像发成功了,改成明确提示 - 发完就地刷新列表,不再关闭弹层——连着回复更顺 ## AI 每日次数上限 AI 调用是真金白银,不设上限等于把钱包交给用户。新增按「用户 + 自然日 + 功能」计的额度,后台「社区运营」页可配问问 AI / 异常评估 / AI 计划 三档,改完立即生效。 两个刻意的设计: - 扣额度在请求大模型之前,失败也算用掉一次。否则刷接口空转照样烧钱 - 配置读不到时回落到保守默认值,绝不「读不到就不限制」——那正是配置 出问题时最不该发生的事 超限返回业务码 42900,小程序端明确说明「明天 0 点恢复」,不当成网络 错误让用户反复重试。 Co-Authored-By: Claude Opus 5 --- .../admin/dist/assets/index-BjLxu16U.css | 1 - .../admin/dist/assets/index-D4fxTaca.css | 1 + .../admin/dist/assets/index-DMg3rix-.js | 59 ++++++++++ .../admin/dist/assets/index-GGI_ie1V.js | 59 ---------- pets-be/internal/admin/dist/index.html | 4 +- pets-be/internal/handler/admin.go | 20 ++++ pets-be/internal/handler/misc.go | 15 ++- pets-be/internal/handler/pet.go | 4 +- pets-be/internal/handler/plan.go | 4 +- pets-be/internal/handler/reminder.go | 4 +- pets-be/internal/model/ai_quota.go | 20 ++++ pets-be/internal/model/base.go | 2 + pets-be/internal/model/comment.go | 13 ++- pets-be/internal/router/router.go | 4 + pets-be/internal/service/ai.go | 4 + pets-be/internal/service/ai_llm.go | 3 + pets-be/internal/service/ai_quota.go | 110 ++++++++++++++++++ pets-be/internal/service/plan.go | 7 +- pets-be/web/admin/src/lib/api.ts | 6 + pets-be/web/admin/src/pages/CommunityBot.tsx | 72 +++++++++++- .../components/bottom-sheet/bottom-sheet.js | 33 +++++- .../components/bottom-sheet/bottom-sheet.wxml | 24 +++- .../components/bottom-sheet/bottom-sheet.wxss | 17 +++ pets-fe/pages/ai/ai.js | 6 +- pets-fe/utils/api.js | 4 +- 25 files changed, 405 insertions(+), 91 deletions(-) delete mode 100644 pets-be/internal/admin/dist/assets/index-BjLxu16U.css create mode 100644 pets-be/internal/admin/dist/assets/index-D4fxTaca.css create mode 100644 pets-be/internal/admin/dist/assets/index-DMg3rix-.js delete mode 100644 pets-be/internal/admin/dist/assets/index-GGI_ie1V.js create mode 100644 pets-be/internal/model/ai_quota.go create mode 100644 pets-be/internal/service/ai_quota.go diff --git a/pets-be/internal/admin/dist/assets/index-BjLxu16U.css b/pets-be/internal/admin/dist/assets/index-BjLxu16U.css deleted file mode 100644 index 25a9588..0000000 --- a/pets-be/internal/admin/dist/assets/index-BjLxu16U.css +++ /dev/null @@ -1 +0,0 @@ -*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background:40 33% 98%;--foreground:24 10% 15%;--card:0 0% 100%;--card-foreground:24 10% 15%;--primary:33 90% 62%;--primary-foreground:0 0% 100%;--secondary:40 30% 94%;--secondary-foreground:24 10% 25%;--muted:40 20% 94%;--muted-foreground:25 8% 45%;--accent:40 40% 92%;--accent-foreground:24 10% 20%;--destructive:5 78% 57%;--destructive-foreground:0 0% 100%;--border:33 25% 88%;--input:33 25% 88%;--ring:33 90% 62%;--radius:.6rem}*{border-color:hsl(var(--border))}body{background:hsl(var(--background));color:hsl(var(--foreground));margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Microsoft YaHei,sans-serif}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-1\/2{left:50%}.right-4{right:1rem}.top-1\/2{top:50%}.top-4{top:1rem}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-2{margin-left:.5rem}.mr-1{margin-right:.25rem}.mt-1{margin-top:.25rem}.mt-auto{margin-top:auto}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-24{min-height:6rem}.min-h-screen{min-height:100vh}.w-16{width:4rem}.w-24{width:6rem}.w-28{width:7rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-56{width:14rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-36{min-width:9rem}.min-w-40{min-width:10rem}.max-w-2xl{max-width:42rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.-translate-x-1\/2{--tw-translate-x:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded-full{border-radius:9999px}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-input{border-color:hsl(var(--input))}.border-primary\/40{border-color:hsl(var(--primary) / .4)}.border-transparent{border-color:#0000}.bg-black\/40{background-color:#0006}.bg-card{background-color:hsl(var(--card))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/15{background-color:hsl(var(--destructive) / .15)}.bg-emerald-100{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.bg-muted{background-color:hsl(var(--muted))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-secondary{background-color:hsl(var(--secondary))}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pb-5{padding-bottom:1.25rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-700{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.text-foreground{color:hsl(var(--foreground))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.underline-offset-4{text-underline-offset:4px}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.outline{outline-style:solid}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus-visible\:outline-none:focus-visible{outline-offset:2px;outline:2px solid #0000}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:hsl(var(--ring))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0}.\[\&_tr\]\:border-b tr{border-bottom-width:1px} diff --git a/pets-be/internal/admin/dist/assets/index-D4fxTaca.css b/pets-be/internal/admin/dist/assets/index-D4fxTaca.css new file mode 100644 index 0000000..7f1c111 --- /dev/null +++ b/pets-be/internal/admin/dist/assets/index-D4fxTaca.css @@ -0,0 +1 @@ +*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background:40 33% 98%;--foreground:24 10% 15%;--card:0 0% 100%;--card-foreground:24 10% 15%;--primary:33 90% 62%;--primary-foreground:0 0% 100%;--secondary:40 30% 94%;--secondary-foreground:24 10% 25%;--muted:40 20% 94%;--muted-foreground:25 8% 45%;--accent:40 40% 92%;--accent-foreground:24 10% 20%;--destructive:5 78% 57%;--destructive-foreground:0 0% 100%;--border:33 25% 88%;--input:33 25% 88%;--ring:33 90% 62%;--radius:.6rem}*{border-color:hsl(var(--border))}body{background:hsl(var(--background));color:hsl(var(--foreground));margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Microsoft YaHei,sans-serif}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-1\/2{left:50%}.right-4{right:1rem}.top-1\/2{top:50%}.top-4{top:1rem}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-2{margin-left:.5rem}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.mt-auto{margin-top:auto}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-24{min-height:6rem}.min-h-screen{min-height:100vh}.w-16{width:4rem}.w-24{width:6rem}.w-28{width:7rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-56{width:14rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-36{min-width:9rem}.min-w-40{min-width:10rem}.max-w-2xl{max-width:42rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.-translate-x-1\/2{--tw-translate-x:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded-full{border-radius:9999px}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-input{border-color:hsl(var(--input))}.border-primary\/40{border-color:hsl(var(--primary) / .4)}.border-transparent{border-color:#0000}.bg-black\/40{background-color:#0006}.bg-card{background-color:hsl(var(--card))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/15{background-color:hsl(var(--destructive) / .15)}.bg-emerald-100{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.bg-muted{background-color:hsl(var(--muted))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-secondary{background-color:hsl(var(--secondary))}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pb-5{padding-bottom:1.25rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-700{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.text-foreground{color:hsl(var(--foreground))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.underline-offset-4{text-underline-offset:4px}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.outline{outline-style:solid}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus-visible\:outline-none:focus-visible{outline-offset:2px;outline:2px solid #0000}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:hsl(var(--ring))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0}.\[\&_tr\]\:border-b tr{border-bottom-width:1px} diff --git a/pets-be/internal/admin/dist/assets/index-DMg3rix-.js b/pets-be/internal/admin/dist/assets/index-DMg3rix-.js new file mode 100644 index 0000000..93641a9 --- /dev/null +++ b/pets-be/internal/admin/dist/assets/index-DMg3rix-.js @@ -0,0 +1,59 @@ +var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,a)=>(a=n==null?{}:e(i(n)),c(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var u=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function ee(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function te(e,t){return ee(e.type,t,e.props)}function ne(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function E(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var D=/\/+/g;function O(e,t){return typeof e==`object`&&e&&e.key!=null?E(``+e.key):t.toString(36)}function re(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ie(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ie(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+O(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(D,`$&/`)+`/`),ie(o,r,i,``,function(e){return e})):o!=null&&(ne(o)&&(o=te(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(D,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=u()})),f=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,ne());else{var t=n(l);t!==null&&O(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function ee(){return g?!0:!(e.unstable_now()-Tt&&ee());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&O(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?ne():S=!1}}}var ne;if(typeof y==`function`)ne=function(){y(te)};else if(typeof MessageChannel<`u`){var E=new MessageChannel,D=E.port2;E.port1.onmessage=te,ne=function(){D.postMessage(null)}}else ne=function(){_(te,0)};function O(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,O(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,ne()))),r},e.unstable_shouldYield=ee,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),p=o(((e,t)=>{t.exports=f()})),m=o((e=>{var t=d();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=m()})),g=o((e=>{var t=p(),n=d(),r=h();function i(e){var t=`https://react.dev/errors/`+e;if(1le||(e.current=ce[le],ce[le]=null,le--)}function N(e,t){le++,ce[le]=e.current,e.current=t}var ue=j(null),de=j(null),fe=j(null),pe=j(null);function me(e,t){switch(N(fe,t),N(de,e),N(ue,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}M(ue),N(ue,e)}function he(){M(ue),M(de),M(fe)}function ge(e){e.memoizedState!==null&&N(pe,e);var t=ue.current,n=Hd(t,e.type);t!==n&&(N(de,e),N(ue,n))}function _e(e){de.current===e&&(M(ue),M(de)),pe.current===e&&(M(pe),Qf._currentValue=se)}var ve,ye;function be(e){if(ve===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);ve=t&&t[1]||``,ye=-1)`:-1i||c[r]!==l[i]){var u=` +`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{xe=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?be(n):``}function Ce(e,t){switch(e.tag){case 26:case 27:case 5:return be(e.type);case 16:return be(`Lazy`);case 13:return e.child!==t&&t!==null?be(`Suspense Fallback`):be(`Suspense`);case 19:return be(`SuspenseList`);case 0:case 15:return Se(e.type,!1);case 11:return Se(e.type.render,!1);case 1:return Se(e.type,!0);case 31:return be(`Activity`);default:return``}}function we(e){try{var t=``,n=null;do t+=Ce(e,n),n=e,e=e.return;while(e);return t}catch(e){return` +Error generating stack: `+e.message+` +`+e.stack}}var Te=Object.prototype.hasOwnProperty,Ee=t.unstable_scheduleCallback,De=t.unstable_cancelCallback,Oe=t.unstable_shouldYield,ke=t.unstable_requestPaint,Ae=t.unstable_now,je=t.unstable_getCurrentPriorityLevel,Me=t.unstable_ImmediatePriority,Ne=t.unstable_UserBlockingPriority,Pe=t.unstable_NormalPriority,Fe=t.unstable_LowPriority,Ie=t.unstable_IdlePriority,Le=t.log,Re=t.unstable_setDisableYieldValue,ze=null,Be=null;function Ve(e){if(typeof Le==`function`&&Re(e),Be&&typeof Be.setStrictMode==`function`)try{Be.setStrictMode(ze,e)}catch{}}var He=Math.clz32?Math.clz32:Ge,Ue=Math.log,We=Math.LN2;function Ge(e){return e>>>=0,e===0?32:31-(Ue(e)/We|0)|0}var Ke=256,qe=262144,Je=4194304;function Ye(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Xe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ye(n))):i=Ye(o):i=Ye(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ye(n))):i=Ye(o)):i=Ye(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ze(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function $e(){var e=Je;return Je<<=1,!(Je&62914560)&&(Je=4194304),e}function et(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function tt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nt(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),mn=!1;if(pn)try{var hn={};Object.defineProperty(hn,"passive",{get:function(){mn=!0}}),window.addEventListener(`test`,hn,hn),window.removeEventListener(`test`,hn,hn)}catch{mn=!1}var gn=null,_n=null,vn=null;function yn(){if(vn)return vn;var e,t=_n,n=t.length,r,i=`value`in gn?gn.value:gn.textContent,a=i.length;for(e=0;e=Zn),er=` `,tr=!1;function nr(e,t){switch(e){case`keyup`:return Yn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function rr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ir=!1;function ar(e,t){switch(e){case`compositionend`:return rr(t);case`keypress`:return t.which===32?(tr=!0,er):null;case`textInput`:return e=t.data,e===er&&tr?null:e;default:return null}}function or(e,t){if(ir)return e===`compositionend`||!Xn&&nr(e,t)?(e=yn(),vn=_n=gn=null,ir=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Or(n)}}function Ar(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ar(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Bt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Bt(e.document)}return t}function Mr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Nr=pn&&`documentMode`in document&&11>=document.documentMode,Pr=null,Fr=null,Ir=null,Lr=!1;function Rr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Lr||Pr==null||Pr!==Bt(r)||(r=Pr,`selectionStart`in r&&Mr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ir&&Dr(Ir,r)||(Ir=r,r=Td(Fr,`onSelect`),0>=o,i-=o,ki=1<<32-He(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),L&&ji(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),L&&ji(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return L&&ji(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),L&&ji(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===ne&&Aa(l)===r.type){n(e,r.sibling),c=a(r,o.props),La(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=gi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=hi(o.type,o.key,o.props,null,e.mode,c),La(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=yi(o,e.mode,c),c.return=e,e=c}return s(e);case ne:return o=Aa(o),b(e,r,o,c)}if(oe(o))return h(e,r,o,c);if(re(o)){if(l=re(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Ia(o),c);if(o.$$typeof===C)return b(e,r,ia(e,o),c);Ra(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=_i(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Fa=0;var i=b(e,t,n,r);return Pa=null,i}catch(t){if(t===wa||t===Ea)throw t;var a=fi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ba=za(!0),Va=za(!1),Ha=!1;function Ua(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Wa(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ga(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ka(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,q&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=li(e),ci(e,null,n),t}return ai(e,r,t,n),li(e)}function qa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}function Ja(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ya=!1;function Xa(){if(Ya){var e=ha;if(e!==null)throw e}}function Za(e,t,n,r){Ya=!1;var i=e.updateQueue;Ha=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(X&f)===f:(r&f)===f){f!==0&&f===ma&&(Ya=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=m({},d,f);break a;case 2:Ha=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Wl|=o,e.lanes=o,e.memoizedState=d}}function Qa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function $a(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,Ls(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Is(e,t,va(c,r),fu(e)):Is(e,t,r,fu(e))}catch(n){Is(e,t,{then:function(){},status:`rejected`,reason:n},fu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function Es(){}function Ds(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Os(e).queue;Ts(e,a,t,se,n===null?Es:function(){return ks(e),n(r)})}function Os(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:se,baseState:se,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:se},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function ks(e){var t=Os(e);t.next===null&&(t=e.alternate.memoizedState),Is(e,t.next.queue,{},fu())}function As(){return ra(Qf)}function js(){return No().memoizedState}function Ms(){return No().memoizedState}function Ns(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=fu();e=Ga(n);var r=Ka(t,e,n);r!==null&&(mu(r,t,n),qa(r,t,n)),t={cache:ua()},e.payload=t;return}t=t.return}}function Ps(e,t,n){var r=fu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Rs(e)?zs(t,n):(n=oi(e,t,n,r),n!==null&&(mu(n,e,r),Bs(n,t,r)))}function Fs(e,t,n){Is(e,t,n,fu())}function Is(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Rs(e))zs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Er(s,o))return ai(e,t,i,0),J===null&&ii(),!1}catch{}if(n=oi(e,t,i,r),n!==null)return mu(n,e,r),Bs(n,t,r),!0}return!1}function Ls(e,t,n,r){if(r={lane:2,revertLane:ud(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Rs(e)){if(t)throw Error(i(479))}else t=oi(e,n,r,2),t!==null&&mu(t,e,2)}function Rs(e){var t=e.alternate;return e===R||t!==null&&t===R}function zs(e,t){vo=_o=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Bs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}var Vs={readContext:ra,use:Io,useCallback:wo,useContext:wo,useEffect:wo,useImperativeHandle:wo,useLayoutEffect:wo,useInsertionEffect:wo,useMemo:wo,useReducer:wo,useRef:wo,useState:wo,useDebugValue:wo,useDeferredValue:wo,useTransition:wo,useSyncExternalStore:wo,useId:wo,useHostTransitionStatus:wo,useFormState:wo,useActionState:wo,useOptimistic:wo,useMemoCache:wo,useCacheRefresh:wo};Vs.useEffectEvent=wo;var Hs={readContext:ra,use:Io,useCallback:function(e,t){return Mo().memoizedState=[e,t===void 0?null:t],e},useContext:ra,useEffect:fs,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),us(4194308,4,vs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return us(4194308,4,e,t)},useInsertionEffect:function(e,t){us(4,2,e,t)},useMemo:function(e,t){var n=Mo();t=t===void 0?null:t;var r=e();if(yo){Ve(!0);try{e()}finally{Ve(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Mo();if(n!==void 0){var i=n(t);if(yo){Ve(!0);try{n(t)}finally{Ve(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ps.bind(null,R,e),[r.memoizedState,e]},useRef:function(e){var t=Mo();return e={current:e},t.memoizedState=e},useState:function(e){e=Jo(e);var t=e.queue,n=Fs.bind(null,R,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:bs,useDeferredValue:function(e,t){return Cs(Mo(),e,t)},useTransition:function(){var e=Jo(!1);return e=Ts.bind(null,R,e.queue,!0,!1),Mo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=R,a=Mo();if(L){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),J===null)throw Error(i(349));X&127||Uo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,fs(Go.bind(null,r,o,e),[e]),r.flags|=2048,cs(9,{destroy:void 0},Wo.bind(null,r,o,n,t),null),n},useId:function(){var e=Mo(),t=J.identifierPrefix;if(L){var n=Ai,r=ki;n=(r&~(1<<32-He(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=bo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[P]=t,o[dt]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Nc(t)}}return Rc(t),Pc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Nc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=fe.current,Ui(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=I,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[P]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||jd(e.nodeValue,n)),e||Bi(t,!0)}else e=Bd(e).createTextNode(r),e[P]=t,t.stateNode=e}return Rc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Ui(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[P]=t}else Wi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),e=!1}else n=Gi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(fo(t),t):(fo(t),null);if(t.flags&128)throw Error(i(558))}return Rc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Ui(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[P]=t}else Wi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),a=!1}else a=Gi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(fo(t),t):(fo(t),null)}return fo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Ic(t,t.updateQueue),Rc(t),null);case 4:return he(),e===null&&xd(t.stateNode.containerInfo),Rc(t),null;case 10:return Zi(t.type),Rc(t),null;case 19:if(M(po),r=t.memoizedState,r===null)return Rc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Lc(r,!1);else{if(Ul!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=mo(e),o!==null){for(t.flags|=128,Lc(r,!1),e=o.updateQueue,t.updateQueue=e,Ic(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)F(n,e),n=n.sibling;return N(po,po.current&1|2),L&&ji(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ae()>eu&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304)}else{if(!a)if(e=mo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Ic(t,e),Lc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!L)return Rc(t),null}else 2*Ae()-r.renderingStartTime>eu&&n!==536870912&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Rc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ae(),e.sibling=null,n=po.current,N(po,a?n&1|2:n&1),L&&ji(t,r.treeForkCount),e);case 22:case 23:return fo(t),io(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Rc(t),t.subtreeFlags&6&&(t.flags|=8192)):Rc(t),n=t.updateQueue,n!==null&&Ic(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&M(ba),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Zi(la),Rc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Pi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Zi(la),he(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return _e(t),null;case 31:if(t.memoizedState!==null){if(fo(t),t.alternate===null)throw Error(i(340));Wi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(fo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Wi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return M(po),null;case 4:return he(),null;case 10:return Zi(t.type),null;case 22:case 23:return fo(t),io(),e!==null&&M(ba),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Zi(la),null;case 25:return null;default:return null}}function Vc(e,t){switch(Pi(t),t.tag){case 3:Zi(la),he();break;case 26:case 27:case 5:_e(t);break;case 4:he();break;case 31:t.memoizedState!==null&&fo(t);break;case 13:fo(t);break;case 19:M(po);break;case 10:Zi(t.type);break;case 22:case 23:fo(t),io(),e!==null&&M(ba);break;case 24:Zi(la)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Q(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Q(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Q(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{$a(t,n)}catch(t){Q(e,e.return,t)}}}function Gc(e,t,n){n.props=Ys(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Q(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Q(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Q(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Q(e,t,n)}else n.current=null}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Q(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[dt]=t}catch(t){Q(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=rn));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[P]=e,t[dt]=n}catch(t){Q(e,e.return,t)}}var W=!1,tl=!1,nl=!1,rl=typeof WeakSet==`function`?WeakSet:Set,il=null;function al(e,t){if(e=e.containerInfo,Rd=sp,e=jr(e),Mr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,il=t;il!==null;)if(t=il,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,il=e;else for(;il!==null;){switch(t=il,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[P]=e,Ct(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=kr(s,h),v=kr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=cu,cu=null;var o=iu,s=ou;if(ru=0,au=iu=null,ou=0,q&6)throw Error(i(331));var c=q;if(q|=4,Nl(o.current),Tl(o,o.current,s,n),q=c,rd(0,!1),Be&&typeof Be.onPostCommitFiberRoot==`function`)try{Be.onPostCommitFiberRoot(ze,o)}catch{}return!0}finally{A.p=a,k.T=r,Bu(e,t)}}function Uu(e,t,n){t=xi(n,t),t=ec(e.stateNode,t,2),e=Ka(e,t,2),e!==null&&(tt(e,2),nd(e))}function Q(e,t,n){if(e.tag===3)Uu(e,e,n);else for(;t!==null;){if(t.tag===3){Uu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(nu===null||!nu.has(r))){e=xi(n,e),n=tc(2),r=Ka(t,n,2),r!==null&&(nc(n,r,t,e),tt(r,2),nd(r));break}}t=t.return}}function Wu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Ll;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Vl=!0,i.add(n),e=Gu.bind(null,e,t,n),t.then(e,e))}function Gu(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,J===e&&(X&n)===n&&(Ul===4||Ul===3&&(X&62914560)===X&&300>Ae()-Ql?!(q&2)&&xu(e,0):Kl|=n,Jl===X&&(Jl=0)),nd(e)}function Ku(e,t){t===0&&(t=$e()),e=si(e,t),e!==null&&(tt(e,t),nd(e))}function qu(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Ku(e,n)}function Ju(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),Ku(e,n)}function Yu(e,t){return Ee(e,t)}var Xu=null,Zu=null,Qu=!1,$u=!1,ed=!1,td=0;function nd(e){e!==Zu&&e.next===null&&(Zu===null?Xu=Zu=e:Zu=Zu.next=e),$u=!0,Qu||(Qu=!0,ld())}function rd(e,t){if(!ed&&$u){ed=!0;do for(var n=!1,r=Xu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-He(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,cd(r,a))}else a=X,a=Xe(r,r===J?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ze(r,a)||(n=!0,cd(r,a));r=r.next}while(n);ed=!1}}function id(){ad()}function ad(){$u=Qu=!1;var e=0;td!==0&&Gd()&&(e=td);for(var t=Ae(),n=null,r=Xu;r!==null;){var i=r.next,a=od(r,t);a===0?(r.next=null,n===null?Xu=i:n.next=i,i===null&&(Zu=n)):(n=r,(e!==0||a&3)&&($u=!0)),r=i}ru!==0&&ru!==5||rd(e,!1),td!==0&&(td=0)}function od(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Ht(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),Ct(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ht(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ht(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ht(n.imageSizes)+`"]`)):i+=`[href="`+Ht(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=m({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),Ct(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ht(r)+`"][href="`+Ht(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=m({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),Ct(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=St(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=m({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);Ct(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=St(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Ct(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=St(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=m({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Ct(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=fe.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=St(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=St(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=St(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Ht(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return m({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),Ct(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Ht(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ht(n.href)+`"]`);if(r)return t.instance=r,Ct(r),r;var a=m({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),Ct(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,Ct(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),Ct(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,Ct(a),a):(r=n,(a=mf.get(o))&&(r=m({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),Ct(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,Ct(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),Ct(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=g()})),v=`modulepreload`,y=function(e){return`/admin/`+e},b={},x=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,new URL(`../../../src/node/plugins/importAnalysisBuild.ts`,import.meta.url)).href}r=o(t.map(t=>{if(t=y(t,n),t=s(t),t in b)return;b[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:v,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},S=l(d(),1),C=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,w=/^[\\/]{2}/;function T(e,t){return t+e.replace(/\\/g,`/`)}var ee=`popstate`;function te(e){return typeof e==`object`&&!!e&&`pathname`in e&&`search`in e&&`hash`in e&&`state`in e&&`key`in e}function ne(e={}){function t(e,t){let n=t.state?.masked,{pathname:r,search:i,hash:a}=n||e.location;return ie(``,{pathname:r,search:i,hash:a},t.state&&t.state.usr||null,t.state&&t.state.key||`default`,n?{pathname:e.location.pathname,search:e.location.search,hash:e.location.hash}:void 0)}function n(e,t){return typeof t==`string`?t:ae(t)}return k(t,n,null,e)}function E(e,t){if(e===!1||e==null)throw Error(t)}function D(e,t){if(!e){typeof console<`u`&&console.warn(t);try{throw Error(t)}catch{}}}function O(){return Math.random().toString(36).substring(2,10)}function re(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function ie(e,t,n=null,r,i){return{pathname:typeof e==`string`?e:e.pathname,search:``,hash:``,...typeof t==`string`?oe(t):t,state:n,key:t&&t.key||r||O(),mask:i}}function ae({pathname:e=`/`,search:t=``,hash:n=``}){return t&&t!==`?`&&(e+=t.charAt(0)===`?`?t:`?`+t),n&&n!==`#`&&(e+=n.charAt(0)===`#`?n:`#`+n),e}function oe(e){let t={};if(e){let n=e.indexOf(`#`);n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf(`?`);r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function k(e,t,n,r={}){let{window:i=document.defaultView,v5Compat:a=!1}=r,o=i.history,s=`POP`,c=null,l=u();l??(l=0,o.replaceState({...o.state,idx:l},``));function u(){return(o.state||{idx:null}).idx}function d(){s=`POP`;let e=u(),t=e==null?null:e-l;l=e,c&&c({action:s,location:h.location,delta:t})}function f(e,t){s=`PUSH`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u()+1;let d=re(r,l),f=h.createHref(r.mask||r);try{o.pushState(d,``,f)}catch(e){if(e instanceof DOMException&&e.name===`DataCloneError`)throw e;i.location.assign(f)}a&&c&&c({action:s,location:h.location,delta:1})}function p(e,t){s=`REPLACE`;let r=te(e)?e:ie(h.location,e,t);n&&n(r,e),l=u();let i=re(r,l),d=h.createHref(r.mask||r);o.replaceState(i,``,d),a&&c&&c({action:s,location:h.location,delta:0})}function m(e){return A(i,e)}let h={get action(){return s},get location(){return e(i,o)},listen(e){if(c)throw Error(`A history only accepts one active listener`);return i.addEventListener(ee,d),c=e,()=>{i.removeEventListener(ee,d),c=null}},createHref(e){return t(i,e)},createURL:m,encodeLocation(e){let t=m(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:f,replace:p,go(e){return o.go(e)}};return h}function A(e,t,n=!1){let r=`http://localhost`;e&&(r=e.location.origin===`null`?e.location.href:e.location.origin),E(r,`No window.location.(origin|href) available to create URL`);let i=typeof t==`string`?t:ae(t);return i=i.replace(/ $/,`%20`),!n&&w.test(i)&&(i=r+i),new URL(i,r)}function se(e,t,n=`/`){return ce(e,t,n,!1)}function ce(e,t,n,r,i){let a=Te((typeof t==`string`?oe(t):t).pathname||`/`,n);if(a==null)return null;let o=i??j(e),s=null,c=we(a);for(let e=0;s==null&&e{let c={relativePath:s===void 0?e.path||``:s,caseSensitive:e.caseSensitive===!0,childrenIndex:a,route:e};if(c.relativePath.startsWith(`/`)){if(!c.relativePath.startsWith(r)&&o)return;E(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length)}let l=Ne([r,c.relativePath]),u=n.concat(c);e.children&&e.children.length>0&&(E(e.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${l}".`),M(e.children,t,u,l,o)),!(e.path==null&&!e.index)&&t.push({path:l,score:ve(l,e.index),routesMeta:u.map((e,t)=>{let[n,r]=Ce(e.relativePath,e.caseSensitive,t===u.length-1);return{...e,matcher:n,compiledParams:r}})})};return e.forEach((e,t)=>{if(e.path===``||!e.path?.includes(`?`))a(e,t);else for(let n of N(e.path))a(e,t,!0,n)}),t}function N(e){let t=e.split(`/`);if(t.length===0)return[];let[n,...r]=t,i=n.endsWith(`?`),a=n.replace(/\?$/,``);if(r.length===0)return i?[a,``]:[a];let o=N(r.join(`/`)),s=[];return s.push(...o.map(e=>e===``?a:[a,e].join(`/`))),i&&s.push(...o),s.map(t=>e.startsWith(`/`)&&t===``?`/`:t)}function ue(e){e.sort((e,t)=>e.score===t.score?ye(e.routesMeta.map(e=>e.childrenIndex),t.routesMeta.map(e=>e.childrenIndex)):t.score-e.score)}var de=/^:[\w-]+$/,fe=3,pe=2,me=1,he=10,ge=-2,_e=e=>e===`*`;function ve(e,t){let n=e.split(`/`),r=n.length;return n.some(_e)&&(r+=ge),t&&(r+=pe),n.filter(e=>!_e(e)).reduce((e,t)=>e+(de.test(t)?fe:t===``?me:he),r)}function ye(e,t){return e.length===t.length&&e.slice(0,-1).every((e,n)=>e===t[n])?e[e.length-1]-t[t.length-1]:0}function be(e,t,n=!1){let{routesMeta:r}=e,i={},a=`/`,o=[];for(let e=0;e{if(t===`*`){let e=s[r]||``;o=a.slice(0,a.length-e.length).replace(/(.)\/+$/,`$1`)}let i=s[r];return n&&!i?e[t]=void 0:e[t]=(i||``).replace(/%2F/g,`/`),e},{}),pathname:a,pathnameBase:o,pattern:e}}function Ce(e,t=!1,n=!0){D(e===`*`||!e.endsWith(`*`)||e.endsWith(`/*`),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,`/*`)}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,`/*`)}".`);let r=[],i=`^`+e.replace(/\/*\*?$/,``).replace(/^\/*/,`/`).replace(/[\\.*+^${}|()[\]]/g,`\\$&`).replace(/\/:([\w-]+)(\?)?/g,(e,t,n,i,a)=>{if(r.push({paramName:t,isOptional:n!=null}),n){let t=a.charAt(i+e.length);return t&&t!==`/`?`/([^\\/]*)`:`(?:/([^\\/]*))?`}return`/([^\\/]+)`}).replace(/\/([\w-]+)\?(\/|$)/g,`(/$1)?$2`);return e.endsWith(`*`)?(r.push({paramName:`*`}),i+=e===`*`||e===`/*`?`(.*)$`:`(?:\\/(.+)|\\/*)$`):n?i+=`\\/*$`:e!==``&&e!==`/`&&(i+=`(?:(?=\\/|$))`),[new RegExp(i,t?void 0:`i`),r]}function we(e){try{return e.split(`/`).map(e=>decodeURIComponent(e).replace(/\//g,`%2F`)).join(`/`)}catch(t){return D(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Te(e,t){if(t===`/`)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith(`/`)?t.length-1:t.length,r=e.charAt(n);return r&&r!==`/`?null:e.slice(n)||`/`}function Ee(e,t=`/`){let{pathname:n,search:r=``,hash:i=``}=typeof e==`string`?oe(e):e,a;return n?(n=Me(n),a=n.startsWith(`/`)?De(n.substring(1),`/`):De(n,t)):a=t,{pathname:a,search:Ie(r),hash:Le(i)}}function De(e,t){let n=Pe(t).split(`/`);return e.split(`/`).forEach(e=>{e===`..`?n.length>1&&n.pop():e!==`.`&&n.push(e)}),n.length>1?n.join(`/`):`/`}function Oe(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ke(e){return e.filter((e,t)=>t===0||e.route.path&&e.route.path.length>0)}function Ae(e){let t=ke(e);return t.map((e,n)=>n===t.length-1?e.pathname:e.pathnameBase)}function je(e,t,n,r=!1){let i;typeof e==`string`?i=oe(e):(i={...e},E(!i.pathname||!i.pathname.includes(`?`),Oe(`?`,`pathname`,`search`,i)),E(!i.pathname||!i.pathname.includes(`#`),Oe(`#`,`pathname`,`hash`,i)),E(!i.search||!i.search.includes(`#`),Oe(`#`,`search`,`hash`,i)));let a=e===``||i.pathname===``,o=a?`/`:i.pathname,s;if(o==null)s=n;else{let e=t.length-1;if(!r&&o.startsWith(`..`)){let t=o.split(`/`);for(;t[0]===`..`;)t.shift(),--e;i.pathname=t.join(`/`)}s=e>=0?t[e]:`/`}let c=Ee(i,s),l=o&&o!==`/`&&o.endsWith(`/`),u=(a||o===`.`)&&n.endsWith(`/`);return!c.pathname.endsWith(`/`)&&(l||u)&&(c.pathname+=`/`),c}var Me=e=>e.replace(/[\\/]{2,}/g,`/`),Ne=e=>Me(e.join(`/`)),Pe=e=>e.replace(/\/+$/,``),Fe=e=>Pe(e).replace(/^\/*/,`/`),Ie=e=>!e||e===`?`?``:e.startsWith(`?`)?e:`?`+e,Le=e=>!e||e===`#`?``:e.startsWith(`#`)?e:`#`+e,Re=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||``,this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function ze(e){return e!=null&&typeof e.status==`number`&&typeof e.statusText==`string`&&typeof e.internal==`boolean`&&`data`in e}function Be(e){return Ne(e.map(e=>e.route.path).filter(Boolean))||`/`}var Ve=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function He(e,t){let n=e;if(typeof n!=`string`||!C.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(Ve)try{let e=new URL(window.location.href),r=w.test(n)?new URL(T(n,e.protocol)):new URL(n),a=Te(r.pathname,t);r.origin===e.origin&&a!=null?n=a+r.search+r.hash:i=!0}catch{D(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join(`\0`);var Ue=[`POST`,`PUT`,`PATCH`,`DELETE`];new Set(Ue);var We=[`GET`,...Ue];new Set(We);var Ge=[`about:`,`blob:`,`chrome:`,`chrome-untrusted:`,`content:`,`data:`,`devtools:`,`file:`,`filesystem:`,`javascript:`];function Ke(e){try{return Ge.includes(new URL(e).protocol)}catch{return!1}}var qe=S.createContext(null);qe.displayName=`DataRouter`;var Je=S.createContext(null);Je.displayName=`DataRouterState`;var Ye=S.createContext(!1);function Xe(){return S.useContext(Ye)}var Ze=S.createContext({isTransitioning:!1});Ze.displayName=`ViewTransition`;var Qe=S.createContext(new Map);Qe.displayName=`Fetchers`;var $e=S.createContext(null);$e.displayName=`Await`;var et=S.createContext(null);et.displayName=`Navigation`;var tt=S.createContext(null);tt.displayName=`Location`;var nt=S.createContext({outlet:null,matches:[],isDataRoute:!1});nt.displayName=`Route`;var rt=S.createContext(null);rt.displayName=`RouteError`;var it=`REACT_ROUTER_ERROR`,at=`REDIRECT`,ot=`ROUTE_ERROR_RESPONSE`;function st(e){if(e.startsWith(`${it}:${at}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`&&typeof t.location==`string`&&typeof t.reloadDocument==`boolean`&&typeof t.replace==`boolean`)return t}catch{}}function ct(e){if(e.startsWith(`${it}:${ot}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t==`object`&&t&&typeof t.status==`number`&&typeof t.statusText==`string`)return new Re(t.status,t.statusText,t.data)}catch{}}function lt(e,{relative:t}={}){E(ut(),`useHref() may be used only in the context of a component.`);let{basename:n,navigator:r}=S.useContext(et),{hash:i,pathname:a,search:o}=_t(e,{relative:t}),s=a;return n!==`/`&&(s=a===`/`?n:Ne([n,a])),r.createHref({pathname:s,search:o,hash:i})}function ut(){return S.useContext(tt)!=null}function P(){return E(ut(),`useLocation() may be used only in the context of a component.`),S.useContext(tt).location}var dt=`You should call navigate() in a React.useEffect(), not when your component is first rendered.`;function ft(e){S.useContext(et).static||S.useLayoutEffect(e)}function pt(){let{isDataRoute:e}=S.useContext(nt);return e?It():mt()}function mt(){E(ut(),`useNavigate() may be used only in the context of a component.`);let e=S.useContext(qe),{basename:t,navigator:n}=S.useContext(et),{matches:r}=S.useContext(nt),{pathname:i}=P(),a=JSON.stringify(Ae(r)),o=S.useRef(!1);return ft(()=>{o.current=!0}),S.useCallback((r,s={})=>{if(D(o.current,dt),!o.current)return;if(typeof r==`number`){n.go(r);return}let c=je(r,JSON.parse(a),i,s.relative===`path`);e==null&&t!==`/`&&(c.pathname=c.pathname===`/`?t:Ne([t,c.pathname])),(s.replace?n.replace:n.push)(c,s.state,s)},[t,n,a,i,e])}var ht=S.createContext(null);function gt(e){let t=S.useContext(nt).outlet;return S.useMemo(()=>t&&S.createElement(ht.Provider,{value:e},t),[t,e])}function _t(e,{relative:t}={}){let{matches:n}=S.useContext(nt),{pathname:r}=P(),i=JSON.stringify(Ae(n));return S.useMemo(()=>je(e,JSON.parse(i),r,t===`path`),[e,i,r,t])}function vt(e,t){return yt(e,t)}function yt(e,t,n){E(ut(),`useRoutes() may be used only in the context of a component.`);let{navigator:r}=S.useContext(et),{matches:i}=S.useContext(nt),a=i[i.length-1],o=a?a.params:{},s=a?a.pathname:`/`,c=a?a.pathnameBase:`/`,l=a&&a.route;{let e=l&&l.path||``;Rt(s,!l||e.endsWith(`*`)||e.endsWith(`*?`),`You rendered descendant (or called \`useRoutes()\`) at "${s}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. + +Please change the parent to .`)}let u=P(),d;if(t){let e=typeof t==`string`?oe(t):t;E(c===`/`||e.pathname?.startsWith(c),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${c}" but pathname "${e.pathname}" was given in the \`location\` prop.`),d=e}else d=u;let f=d.pathname||`/`,p=f;if(c!==`/`){let e=c.replace(/^\//,``).split(`/`);p=`/`+f.replace(/^\//,``).split(`/`).slice(e.length).join(`/`)}let m=n&&n.state.matches.length?n.state.matches.map(e=>Object.assign(e,{route:n.manifest[e.route.id]||e.route})):se(e,{pathname:p});D(l||m!=null,`No routes matched location "${d.pathname}${d.search}${d.hash}" `),D(m==null||m[m.length-1].route.element!==void 0||m[m.length-1].route.Component!==void 0||m[m.length-1].route.lazy!==void 0,`Matched leaf route at location "${d.pathname}${d.search}${d.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let h=Et(m&&m.map(e=>Object.assign({},e,{params:Object.assign({},o,e.params),pathname:Ne([c,r.encodeLocation?r.encodeLocation(e.pathname.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathname]),pathnameBase:e.pathnameBase===`/`?c:Ne([c,r.encodeLocation?r.encodeLocation(e.pathnameBase.replace(/%/g,`%25`).replace(/\?/g,`%3F`).replace(/#/g,`%23`)).pathname:e.pathnameBase])})),i,n);return t&&h?S.createElement(tt.Provider,{value:{location:{pathname:`/`,search:``,hash:``,state:null,key:`default`,mask:void 0,...d},navigationType:`POP`}},h):h}function bt(){let e=Ft(),t=ze(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r=`rgba(200,200,200, 0.5)`,i={padding:`0.5rem`,backgroundColor:r},a={padding:`2px 4px`,backgroundColor:r},o=null;return console.error(`Error handled by React Router default ErrorBoundary:`,e),o=S.createElement(S.Fragment,null,S.createElement(`p`,null,`💿 Hey developer 👋`),S.createElement(`p`,null,`You can provide a way better UX than this when your app throws errors by providing your own `,S.createElement(`code`,{style:a},`ErrorBoundary`),` or`,` `,S.createElement(`code`,{style:a},`errorElement`),` prop on your route.`)),S.createElement(S.Fragment,null,S.createElement(`h2`,null,`Unexpected Application Error!`),S.createElement(`h3`,{style:{fontStyle:`italic`}},t),n?S.createElement(`pre`,{style:i},n):null,o)}var xt=S.createElement(bt,null),St=class extends S.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!==`idle`&&e.revalidation===`idle`?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error===void 0?t.error:e.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error(`React Router caught the following error during render`,e)}render(){let e=this.state.error;if(this.context&&typeof e==`object`&&e&&`digest`in e&&typeof e.digest==`string`){let t=ct(e.digest);t&&(e=t)}let t=e===void 0?this.props.children:S.createElement(nt.Provider,{value:this.props.routeContext},S.createElement(rt.Provider,{value:e,children:this.props.component}));return this.context?S.createElement(wt,{error:e},t):t}};St.contextType=Ye;var Ct=new WeakMap;function wt({children:e,error:t}){let{basename:n}=S.useContext(et);if(typeof t==`object`&&t&&`digest`in t&&typeof t.digest==`string`){let e=st(t.digest);if(e){let r=Ct.get(t);if(r)throw r;let i=He(e.location,n),a=i.absoluteURL||i.to;if(Ke(a))throw Error(`Invalid redirect location`);if(Ve&&!Ct.get(t))if(i.isExternal||e.reloadDocument)window.location.href=a;else{let n=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(i.to,{replace:e.replace}));throw Ct.set(t,n),n}return S.createElement(`meta`,{httpEquiv:`refresh`,content:`0;url=${a}`})}}return e}function Tt({routeContext:e,match:t,children:n}){let r=S.useContext(qe);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),S.createElement(nt.Provider,{value:e},n)}function Et(e,t=[],n){let r=n?.state;if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let i=e,a=r?.errors;if(a!=null){let e=i.findIndex(e=>e.route.id&&a?.[e.route.id]!==void 0);E(e>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(a).join(`,`)}`),i=i.slice(0,Math.min(i.length,e+1))}let o=!1,s=-1;if(n&&r){o=r.renderFallback;for(let e=0;e=0?i.slice(0,s+1):[i[0]];break}}}}let c=n?.onError,l=r&&c?(e,t)=>{c(e,{location:r.location,params:r.matches?.[0]?.params??{},pattern:Be(r.matches),errorInfo:t})}:void 0;return i.reduceRight((e,n,c)=>{let u,d=!1,f=null,p=null;r&&(u=a&&n.route.id?a[n.route.id]:void 0,f=n.route.errorElement||xt,o&&(s<0&&c===0?(Rt(`route-fallback`,!1,"No `HydrateFallback` element provided to render during initial hydration"),d=!0,p=null):s===c&&(d=!0,p=n.route.hydrateFallbackElement||null)));let m=t.concat(i.slice(0,c+1)),h=()=>{let t;return t=u?f:d?p:n.route.Component?S.createElement(n.route.Component,null):n.route.element?n.route.element:e,S.createElement(Tt,{match:n,routeContext:{outlet:e,matches:m,isDataRoute:r!=null},children:t})};return r&&(n.route.ErrorBoundary||n.route.errorElement||c===0)?S.createElement(St,{location:r.location,revalidation:r.revalidation,component:f,error:u,children:h(),routeContext:{outlet:null,matches:m,isDataRoute:!0},onError:l}):h()},null)}function Dt(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Ot(e){let t=S.useContext(qe);return E(t,Dt(e)),t}function kt(e){let t=S.useContext(Je);return E(t,Dt(e)),t}function At(e){let t=S.useContext(nt);return E(t,Dt(e)),t}function jt(e){let t=At(e),n=t.matches[t.matches.length-1];return E(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function Mt(){return jt(`useRouteId`)}function Nt(){let e=kt(`useNavigation`);return S.useMemo(()=>{let{matches:t,historyAction:n,...r}=e.navigation;return r},[e.navigation])}function Pt(){let{matches:e,loaderData:t}=kt(`useMatches`);return S.useMemo(()=>e.map(e=>le(e,t)),[e,t])}function Ft(){let e=S.useContext(rt),t=kt(`useRouteError`),n=jt(`useRouteError`);return e===void 0?t.errors?.[n]:e}function It(){let{router:e}=Ot(`useNavigate`),t=jt(`useNavigate`),n=S.useRef(!1);return ft(()=>{n.current=!0}),S.useCallback(async(r,i={})=>{D(n.current,dt),n.current&&(typeof r==`number`?await e.navigate(r):await e.navigate(r,{fromRouteId:t,...i}))},[e,t])}var Lt={};function Rt(e,t,n){!t&&!Lt[e]&&(Lt[e]=!0,D(!1,n))}S.memo(zt);function zt({routes:e,manifest:t,future:n,state:r,isStatic:i,onError:a}){return yt(e,void 0,{manifest:t,state:r,isStatic:i,onError:a,future:n})}function Bt({to:e,replace:t,state:n,relative:r}){E(ut(),` may be used only in the context of a component.`);let{static:i}=S.useContext(et);D(!i,` must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.`);let{matches:a}=S.useContext(nt),{pathname:o}=P(),s=pt(),c=je(e,Ae(a),o,r===`path`),l=JSON.stringify(c);return S.useEffect(()=>{s(JSON.parse(l),{replace:t,state:n,relative:r})},[s,l,r,t,n]),null}function Vt(e){return gt(e.context)}function Ht(e){E(!1,`A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .`)}function Ut({basename:e=`/`,children:t=null,location:n,navigationType:r=`POP`,navigator:i,static:a=!1,useTransitions:o}){E(!ut(),`You cannot render a inside another . You should never have more than one in your app.`);let s=e.replace(/^\/*/,`/`),c=S.useMemo(()=>({basename:s,navigator:i,static:a,useTransitions:o,future:{}}),[s,i,a,o]);typeof n==`string`&&(n=oe(n));let{pathname:l=`/`,search:u=``,hash:d=``,state:f=null,key:p=`default`,mask:m}=n,h=S.useMemo(()=>{let e=Te(l,s);return e==null?null:{location:{pathname:e,search:u,hash:d,state:f,key:p,mask:m},navigationType:r}},[s,l,u,d,f,p,r,m]);return D(h!=null,` is not able to match the URL "${l}${u}${d}" because it does not start with the basename, so the won't render anything.`),h==null?null:S.createElement(et.Provider,{value:c},S.createElement(tt.Provider,{children:t,value:h}))}function Wt({children:e,location:t}){return vt(Gt(e),t)}S.Component;function Gt(e,t=[]){let n=[];return S.Children.forEach(e,(e,r)=>{if(!S.isValidElement(e))return;let i=[...t,r];if(e.type===S.Fragment){n.push.apply(n,Gt(e.props.children,i));return}E(e.type===Ht,`[${typeof e.type==`string`?e.type:e.type.name}] is not a component. All component children of must be a or `),E(!e.props.index||!e.props.children,`An index route cannot have child routes.`);let a={id:e.props.id||i.join(`-`),caseSensitive:e.props.caseSensitive,element:e.props.element,Component:e.props.Component,index:e.props.index,path:e.props.path,middleware:e.props.middleware,loader:e.props.loader,action:e.props.action,hydrateFallbackElement:e.props.hydrateFallbackElement,HydrateFallback:e.props.HydrateFallback,errorElement:e.props.errorElement,ErrorBoundary:e.props.ErrorBoundary,hasErrorBoundary:e.props.hasErrorBoundary===!0||e.props.ErrorBoundary!=null||e.props.errorElement!=null,shouldRevalidate:e.props.shouldRevalidate,handle:e.props.handle,lazy:e.props.lazy};e.props.children&&(a.children=Gt(e.props.children,i)),n.push(a)}),n}var Kt=`get`,qt=`application/x-www-form-urlencoded`;function Jt(e){return typeof HTMLElement<`u`&&e instanceof HTMLElement}function Yt(e){return Jt(e)&&e.tagName.toLowerCase()===`button`}function Xt(e){return Jt(e)&&e.tagName.toLowerCase()===`form`}function Zt(e){return Jt(e)&&e.tagName.toLowerCase()===`input`}function Qt(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function $t(e,t){return e.button===0&&(!t||t===`_self`)&&!Qt(e)}var en=null;function tn(){if(en===null)try{new FormData(document.createElement(`form`),0),en=!1}catch{en=!0}return en}var nn=new Set([`application/x-www-form-urlencoded`,`multipart/form-data`,`text/plain`]);function rn(e){return e!=null&&!nn.has(e)?(D(!1,`"${e}" is not a valid \`encType\` for \`\`/\`\` and will default to "${qt}"`),null):e}function an(e,t){let n,r,i,a,o;if(Xt(e)){let o=e.getAttribute(`action`);r=o?Te(o,t):null,n=e.getAttribute(`method`)||Kt,i=rn(e.getAttribute(`enctype`))||qt,a=new FormData(e)}else if(Yt(e)||Zt(e)&&(e.type===`submit`||e.type===`image`)){let o=e.form;if(o==null)throw Error(`Cannot submit a + {qMsg && {qMsg}} + + + + ) } diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index 829d59d..e69529d 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -117,6 +117,8 @@ Component({ proInfo: null, saving: false, posterSaving: false, + centered: false, + commentImages: [], }, observers: { show: function (show) { @@ -136,7 +138,8 @@ Component({ methods: { setType(type, fresh) { const pet = store.getPet(); - const patch = { innerType: type, pet }; + // 评论以输入为主,贴底弹层会被键盘顶掉大半屏,改成居中 + const patch = { innerType: type, pet, centered: type === 'comments' }; if (fresh) { patch.segSel = {}; patch.optSel = {}; @@ -161,6 +164,7 @@ Component({ patch.addColor = ''; patch.addBreed = ''; patch.commentText = ''; + patch.commentImages = []; patch.riskData = null; patch.saving = false; } @@ -925,14 +929,35 @@ Component({ // 评论 async onSendComment() { const text = (this.data.commentText || '').trim(); - if (!text || !this.data.postId) return this.close(); + // 原来空评论会直接把弹层关掉,看起来像发成功了。改成明确提示 + if (!text) return wx.showToast({ title: '写点什么再发', icon: 'none' }); + if (!this.data.postId) return this.close(); try { - await api.createComment(this.data.postId, text); + await api.createComment(this.data.postId, text, this.data.commentImages.map((i) => i.url)); + this.setData({ commentText: '', commentImages: [] }); + this.loadComments(); this.triggerEvent('commented'); } catch (e) { wx.showToast({ title: e.message || '评论失败', icon: 'none' }); } - this.close(); + }, + + // 评论配图,最多 3 张 + onPickCommentImages() { + const left = 3 - this.data.commentImages.length; + if (left <= 0) return wx.showToast({ title: '最多 3 张', icon: 'none' }); + upload + .chooseAndUploadImages(left) + .then((files) => this.setData({ commentImages: this.data.commentImages.concat(files) })) + .catch((e) => { + if (e && e.canceled) return; + wx.showToast({ title: (e && e.message) || '上传失败', icon: 'none' }); + }); + }, + onRemoveCommentImage(e) { + const list = this.data.commentImages.slice(); + list.splice(e.currentTarget.dataset.index, 1); + this.setData({ commentImages: list }); }, }, diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index ec92a03..254e776 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -7,7 +7,7 @@ module.exports.sel = function (map, key, index, def) { - + @@ -336,10 +336,24 @@ module.exports.sel = function (map, key, index, def) { 还没有评论,来抢个沙发 长按自己的评论可删除 - - - 发送 + + + + + + + + + + + + 配图 {{commentImages.length}}/3 + + {{commentText.length}}/500 + 发送 + diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index 550e8ef..f5732a4 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -108,3 +108,20 @@ background:var(--line);color:#fff;font-size:var(--fs-md);font-weight:var(--fw-b);transition:.16s ease; } .cm-send.on{background:var(--cta)} + +/* 居中弹层:评论这类以输入为主的,贴底会被键盘顶掉大半屏 */ +.sheet.sheet-center{ + left:var(--sp-5);right:var(--sp-5);bottom:auto;top:50%; + border-radius:var(--r-lg); + transform:translateY(-50%) scale(.94);opacity:0; +} +.overlay.show .sheet.sheet-center{transform:translateY(-50%) scale(1);opacity:1} +.sheet-center .sheet-scroll{max-height:62vh;padding:0 var(--sp-5) var(--sp-5)} +.sheet-center .sheetbar{display:none} + +/* 评论编辑区 */ +.cm-editor{margin-top:var(--sp-4);border-top:1rpx solid var(--line);padding-top:var(--sp-4)} +.cm-ta{min-height:160rpx;height:auto} +.cm-bar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)} +.cm-pic{display:flex;align-items:center;gap:var(--sp-1);color:var(--muted);font-size:var(--fs-sm)} +.cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} diff --git a/pets-fe/pages/ai/ai.js b/pets-fe/pages/ai/ai.js index b2a28bd..f00083e 100644 --- a/pets-fe/pages/ai/ai.js +++ b/pets-fe/pages/ai/ai.js @@ -66,7 +66,11 @@ Page({ api .aiChat({ pet_id: store.currentPetId() || null, session: SESSION, text }) .then((res) => this.typewrite(res.reply || '(没有返回内容)')) - .catch((e) => this.typewrite(e.message || '网络异常,请稍后再试。')); + .catch((e) => { + const msg = (e && e.message) || '网络异常,请稍后再试。'; + // 额度用完不是故障,别让用户以为是网络问题反复重试 + this.typewrite(msg.indexOf('次数') >= 0 ? msg + '\n\n每天的次数是为了控制成本,明天 0 点恢复。' : msg); + }); }, // 逐字把回复填进最后一个气泡 diff --git a/pets-fe/utils/api.js b/pets-fe/utils/api.js index ba0f016..6bcc196 100644 --- a/pets-fe/utils/api.js +++ b/pets-fe/utils/api.js @@ -108,8 +108,8 @@ const api = { deletePost: (id) => request({ url: `/api/posts/${id}`, method: 'DELETE' }), deleteComment: (id) => request({ url: `/api/comments/${id}`, method: 'DELETE' }), listComments: (id) => request({ url: `/api/posts/${id}/comments` }), - createComment: (id, content) => - request({ url: `/api/posts/${id}/comments`, method: 'POST', data: { content } }), + createComment: (id, content, images) => + request({ url: `/api/posts/${id}/comments`, method: 'POST', data: { content, images: images || [] } }), // 文章 listArticles: () => request({ url: '/api/articles' }), -- 2.52.0 From 535ef08da761ed8cecc8e5d7b583c969d1583dae Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 16:19:32 +0800 Subject: [PATCH 19/58] =?UTF-8?q?fix:=20=E8=AF=84=E8=AE=BA=E9=85=8D?= =?UTF-8?q?=E5=9B=BE=E6=95=B4=E6=9D=A1=E9=93=BE=E8=B7=AF=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=20+=20=E5=AE=A0=E7=89=A9=E5=88=87=E6=8D=A2=E6=9D=A1=E5=90=B8?= =?UTF-8?q?=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 评论图片传了等于没传 上次只做了一半:model 加了 Images 字段、前端做了上传 UI,但 handler 的 commentReq 没有 images、service 的 CreateComment 连 参数都没有,图片上传完就丢了;评论列表也从没渲染过图片。 补齐:请求体 → service 落库(JSON 数组) → 列表回显 → 点击大图预览。 实测带两张图的评论和纯文字评论各存各的,互不影响。 ## 宠物切换条吸顶 首页/计划/记录/报告四页的 pet-switch 原本在 scroll-view 里,滚下去 就找不到了。而切宠物是随时要用的动作——多宠用户看着 A 的数据想切到 B,还得先滚回顶部。 移出滚动区,放在导航栏下方做成固定的一条,带毛玻璃和分隔线。首页的 问候语留在滚动区里,滚走就滚走,反正它只在刚进页面时有意义。 Co-Authored-By: Claude Opus 5 --- pets-be/internal/handler/community.go | 5 +++-- pets-be/internal/service/community.go | 6 +++++- pets-fe/app.wxss | 14 ++++++++++++++ pets-fe/components/bottom-sheet/bottom-sheet.js | 5 +++++ pets-fe/components/bottom-sheet/bottom-sheet.wxml | 5 +++++ pets-fe/components/bottom-sheet/bottom-sheet.wxss | 2 ++ pets-fe/pages/home/home.wxml | 4 ++-- pets-fe/pages/plan/plan.wxml | 4 ++-- pets-fe/pages/record/record.wxml | 4 ++-- pets-fe/pages/report/report.wxml | 4 ++-- 10 files changed, 42 insertions(+), 11 deletions(-) diff --git a/pets-be/internal/handler/community.go b/pets-be/internal/handler/community.go index 7d448cd..b5367e8 100644 --- a/pets-be/internal/handler/community.go +++ b/pets-be/internal/handler/community.go @@ -113,7 +113,8 @@ func (h *Handler) ListComments(c *gin.Context) { } type commentReq struct { - Content string `json:"content"` + Content string `json:"content"` + Images []string `json:"images"` } // CreateComment POST /api/posts/:id/comments @@ -127,7 +128,7 @@ func (h *Handler) CreateComment(c *gin.Context) { response.FailParams(c, "评论内容不能为空") return } - comment, err := h.svc.CreateComment(middleware.UserID(c), idParam(c, "id"), req.Content) + comment, err := h.svc.CreateComment(middleware.UserID(c), idParam(c, "id"), req.Content, req.Images) if err != nil { respondErr(c, err) return diff --git a/pets-be/internal/service/community.go b/pets-be/internal/service/community.go index 077b821..ebb0ec7 100644 --- a/pets-be/internal/service/community.go +++ b/pets-be/internal/service/community.go @@ -209,7 +209,7 @@ func (s *Service) ListComments(userID, postID string, offset, limit int) ([]mode } // CreateComment 评论 -func (s *Service) CreateComment(userID, postID string, content string) (*model.Comment, error) { +func (s *Service) CreateComment(userID, postID string, content string, images []string) (*model.Comment, error) { if _, err := s.GetPost(postID); err != nil { return nil, err } @@ -219,6 +219,10 @@ func (s *Service) CreateComment(userID, postID string, content string) (*model.C name = user.Nickname } comment := model.Comment{PostID: postID, UserID: userID, AuthorName: name, Content: content, Status: "published"} + // 配图存 JSON 数组。空数组也要显式写,否则前端拿到 null 还要额外判空 + if b, err := json.Marshal(images); err == nil && len(images) > 0 { + comment.Images = b + } if err := s.db.Transaction(func(tx *gorm.DB) error { if err := tx.Create(&comment).Error; err != nil { return err diff --git a/pets-fe/app.wxss b/pets-fe/app.wxss index abbe876..ca59719 100644 --- a/pets-fe/app.wxss +++ b/pets-fe/app.wxss @@ -357,3 +357,17 @@ page{scrollbar-width:none;-ms-overflow-style:none} } .no-pet-b{font-size:var(--fs-lg);font-weight:var(--fw-b)} .no-pet-p{color:var(--muted);font-size:var(--fs-sm);margin:var(--sp-2) 0 var(--sp-4);line-height:1.6} + +/* 宠物切换条固定在导航栏下方。它原本在 scroll-view 里,滚下去就找不到了, + 而切宠物是随时要用的动作——尤其多宠用户,看着 A 的数据想切到 B + 还得先滚回顶部。移出滚动区,四个主页面通用。 */ +.pet-bar{ + flex:none; + padding:var(--sp-2) var(--pad-x) 0; + background:rgba(250,247,242,.92); + backdrop-filter:blur(20rpx); + -webkit-backdrop-filter:blur(20rpx); + border-bottom:1rpx solid rgba(238,230,220,.7); +} +/* 条内的 pet-switch 自己带 padding-bottom,这里不再叠加 */ +.pet-bar .pet-switch{padding-bottom:var(--sp-2)} diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index e69529d..ac93f06 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -416,6 +416,7 @@ Component({ timeText: fmtAgo(c.created_at), // 没有头像字段,用昵称首字做个色块,比一律显示同一个 emoji 强 initial: (c.author_name || '?').slice(0, 1), + imgs: Array.isArray(c.images) ? c.images : [], })), }), ) @@ -954,6 +955,10 @@ Component({ wx.showToast({ title: (e && e.message) || '上传失败', icon: 'none' }); }); }, + onPreviewCommentImage(e) { + const { urls, cur } = e.currentTarget.dataset; + if (urls && urls.length) wx.previewImage({ urls, current: cur }); + }, onRemoveCommentImage(e) { const list = this.data.commentImages.slice(); list.splice(e.currentTarget.dataset.index, 1); diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index 254e776..8be9fb2 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -330,6 +330,11 @@ module.exports.sel = function (map, key, index, def) { {{item.timeText}} {{item.content}} + + + diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index f5732a4..360119a 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -125,3 +125,5 @@ .cm-bar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)} .cm-pic{display:flex;align-items:center;gap:var(--sp-1);color:var(--muted);font-size:var(--fs-sm)} .cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} +.cm-imgs{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-top:var(--sp-2)} +.cm-img{width:150rpx;height:150rpx;border-radius:var(--r-sm)} diff --git a/pets-fe/pages/home/home.wxml b/pets-fe/pages/home/home.wxml index aa928af..bd1a877 100644 --- a/pets-fe/pages/home/home.wxml +++ b/pets-fe/pages/home/home.wxml @@ -1,5 +1,7 @@ + + @@ -13,8 +15,6 @@ - - diff --git a/pets-fe/pages/plan/plan.wxml b/pets-fe/pages/plan/plan.wxml index b1b3270..eada325 100644 --- a/pets-fe/pages/plan/plan.wxml +++ b/pets-fe/pages/plan/plan.wxml @@ -1,9 +1,9 @@ + + - - 还没有毛孩子的档案 diff --git a/pets-fe/pages/record/record.wxml b/pets-fe/pages/record/record.wxml index 87d6d5f..2568598 100644 --- a/pets-fe/pages/record/record.wxml +++ b/pets-fe/pages/record/record.wxml @@ -1,9 +1,9 @@ + + - - 还没有毛孩子的档案 diff --git a/pets-fe/pages/report/report.wxml b/pets-fe/pages/report/report.wxml index 9d14b12..5561f90 100644 --- a/pets-fe/pages/report/report.wxml +++ b/pets-fe/pages/report/report.wxml @@ -1,9 +1,9 @@ + + - - 还没有毛孩子的档案 -- 2.52.0 From 9fc61e878e1ecd9b4a17abf224936392d354b53c Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 16:33:50 +0800 Subject: [PATCH 20/58] =?UTF-8?q?feat:=20=E8=AF=84=E8=AE=BA=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=9B=9E=E5=A4=8D=EF=BC=88=E4=B8=A4=E7=BA=A7=20+=20@?= =?UTF-8?q?=E6=9F=90=E4=BA=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 不做无限层级——手机屏幕撑不住层层缩进,读到第四层就没法看了。 微信、小红书、B站清一色是两级:一级评论 + 其下的回复列表,回复里 用「回复 @某人」表达指向谁。 数据结构:comments 加 parent_id + reply_to_name。回复的回复会被 压平到同一条一级评论下(parent_id 取爷爷的),同时把被回复人的名字 记进 reply_to_name —— 这样既保住两级,又不丢「在跟谁说话」的信息。 几个容易做错的地方: - 一次查完这一页所有一级评论的回复,不是每条一次查询(N+1) - 一级评论默认只带 3 条回复,其余点「展开全部 N 条」再拉,避免热门 评论一次返回几百条 - 删一级评论要连它下面的回复一起删,否则回复变成挂在空处的孤儿; 帖子的 comment_count 也要按实际删除条数减,不是减 1 - total 统计含回复,和帖子上显示的数字对得上 - replies 为空时返回 [],不是 null 实测四条评论(含一条回复的回复): ▸ 甲:一级评论 (2 条回复) └ 乙:多久了? └ 甲 回复 乙:三天了 ▸ 乙:另一条一级评论 (0 条回复) 删掉第一条一级评论后 total 4→1,comment_count 同步。 Co-Authored-By: Claude Opus 5 --- pets-be/internal/handler/community.go | 17 +++- pets-be/internal/model/comment.go | 11 ++- pets-be/internal/router/router.go | 1 + pets-be/internal/service/community.go | 93 ++++++++++++++++--- .../components/bottom-sheet/bottom-sheet.js | 37 +++++++- .../components/bottom-sheet/bottom-sheet.wxml | 26 +++++- .../components/bottom-sheet/bottom-sheet.wxss | 13 +++ pets-fe/utils/api.js | 9 +- 8 files changed, 182 insertions(+), 25 deletions(-) diff --git a/pets-be/internal/handler/community.go b/pets-be/internal/handler/community.go index b5367e8..c34e0de 100644 --- a/pets-be/internal/handler/community.go +++ b/pets-be/internal/handler/community.go @@ -113,8 +113,9 @@ func (h *Handler) ListComments(c *gin.Context) { } type commentReq struct { - Content string `json:"content"` - Images []string `json:"images"` + Content string `json:"content"` + Images []string `json:"images"` + ParentID string `json:"parent_id"` // 回复某条评论时传它的 id } // CreateComment POST /api/posts/:id/comments @@ -128,7 +129,7 @@ func (h *Handler) CreateComment(c *gin.Context) { response.FailParams(c, "评论内容不能为空") return } - comment, err := h.svc.CreateComment(middleware.UserID(c), idParam(c, "id"), req.Content, req.Images) + comment, err := h.svc.CreateComment(middleware.UserID(c), idParam(c, "id"), req.Content, req.Images, req.ParentID) if err != nil { respondErr(c, err) return @@ -171,3 +172,13 @@ func (h *Handler) DeleteOwnComment(c *gin.Context) { } response.OK(c, gin.H{"deleted": true}) } + +// ListReplies GET /api/comments/:id/replies 展开某条评论的全部回复 +func (h *Handler) ListReplies(c *gin.Context) { + list, err := h.svc.ListReplies(middleware.UserID(c), idParam(c, "id")) + if err != nil { + respondErr(c, err) + return + } + response.OK(c, list) +} diff --git a/pets-be/internal/model/comment.go b/pets-be/internal/model/comment.go index 1ca3cf6..4995bfb 100644 --- a/pets-be/internal/model/comment.go +++ b/pets-be/internal/model/comment.go @@ -10,7 +10,14 @@ type Comment struct { AuthorName string `gorm:"size:64" json:"author_name"` Content string `gorm:"size:512" json:"content"` Images datatypes.JSON `json:"images"` - Status string `gorm:"size:16;default:published" json:"status"` + // 两级评论:ParentID 为空是一级评论,否则是某条一级评论下的回复。 + // 不做无限层级——手机上层层缩进读到第四层就没法看了, + // 主流产品(微信、小红书、B站)都是两级 + @某人 表达指向。 + ParentID string `gorm:"size:24;index" json:"parent_id"` + ReplyToName string `gorm:"size:64" json:"reply_to_name"` + Status string `gorm:"size:16;default:published" json:"status"` - IsSelf bool `gorm:"-" json:"is_self"` // 计算字段:是不是我自己发的 + IsSelf bool `gorm:"-" json:"is_self"` // 计算字段:是不是我自己发的 + Replies []Comment `gorm:"-" json:"replies"` // 计算字段:一级评论下挂的回复 + ReplyN int `gorm:"-" json:"reply_n"` // 回复总数(可能多于返回的条数) } diff --git a/pets-be/internal/router/router.go b/pets-be/internal/router/router.go index 0e3dca7..c3b2b10 100644 --- a/pets-be/internal/router/router.go +++ b/pets-be/internal/router/router.go @@ -100,6 +100,7 @@ func registerUserAPI(api *gin.RouterGroup, h *handler.Handler, jm *appjwt.Manage g.POST("/posts/:id/comments", h.CreateComment) g.DELETE("/posts/:id", h.DeleteOwnPost) g.DELETE("/comments/:id", h.DeleteOwnComment) + g.GET("/comments/:id/replies", h.ListReplies) g.GET("/articles", h.ListArticles) g.POST("/feedback", h.CreateFeedback) diff --git a/pets-be/internal/service/community.go b/pets-be/internal/service/community.go index ebb0ec7..03971ad 100644 --- a/pets-be/internal/service/community.go +++ b/pets-be/internal/service/community.go @@ -193,23 +193,67 @@ func (s *Service) postLikeCount(postID string) (int, error) { // ListComments 评论分页 func (s *Service) ListComments(userID, postID string, offset, limit int) ([]model.Comment, int64, error) { - q := s.db.Model(&model.Comment{}).Where("post_id = ? AND status = ?", postID, "published") + base := func() *gorm.DB { + return s.db.Model(&model.Comment{}).Where("post_id = ? AND status = ?", postID, "published") + } + // total 是这条帖子的评论总数(含回复),和帖子上显示的数字对得上 var total int64 - if err := q.Count(&total).Error; err != nil { + if err := base().Count(&total).Error; err != nil { return nil, 0, err } - var comments []model.Comment - if err := q.Order("id desc").Offset(offset).Limit(limit).Find(&comments).Error; err != nil { + // 只分页一级评论,回复跟着它爹一起返回 + var roots []model.Comment + if err := base().Where("parent_id = ? OR parent_id IS NULL", ""). + Order("id desc").Offset(offset).Limit(limit).Find(&roots).Error; err != nil { return nil, 0, err } - for i := range comments { - comments[i].IsSelf = comments[i].UserID == userID + if len(roots) == 0 { + return []model.Comment{}, total, nil } - return comments, total, nil + + ids := make([]string, 0, len(roots)) + for i := range roots { + roots[i].IsSelf = roots[i].UserID == userID + ids = append(ids, roots[i].ID) + } + // 一次查完这一页所有一级评论的回复,不要每条一次查询 + var replies []model.Comment + s.db.Where("parent_id IN ? AND status = ?", ids, "published").Order("id asc").Find(&replies) + byParent := map[string][]model.Comment{} + for i := range replies { + replies[i].IsSelf = replies[i].UserID == userID + byParent[replies[i].ParentID] = append(byParent[replies[i].ParentID], replies[i]) + } + for i := range roots { + list := byParent[roots[i].ID] + if list == nil { + list = []model.Comment{} // 空切片而不是 nil,否则 JSON 出来是 null + } + roots[i].ReplyN = len(list) + // 默认只带前 3 条,其余等前端点「展开」再要,避免热门评论一次拉几百条 + if len(list) > 3 { + list = list[:3] + } + roots[i].Replies = list + } + return roots, total, nil +} + +// ListReplies 展开某条一级评论下的全部回复 +func (s *Service) ListReplies(userID, commentID string) ([]model.Comment, error) { + var list []model.Comment + if err := s.db.Where("parent_id = ? AND status = ?", commentID, "published"). + Order("id asc").Find(&list).Error; err != nil { + return nil, err + } + for i := range list { + list[i].IsSelf = list[i].UserID == userID + } + return list, nil } // CreateComment 评论 -func (s *Service) CreateComment(userID, postID string, content string, images []string) (*model.Comment, error) { +func (s *Service) CreateComment(userID, postID string, content string, images []string, parentID string) (*model.Comment, error) { if _, err := s.GetPost(postID); err != nil { return nil, err } @@ -218,7 +262,23 @@ func (s *Service) CreateComment(userID, postID string, content string, images [] if err := s.db.First(&user, userID).Error; err == nil && user.Nickname != "" { name = user.Nickname } - comment := model.Comment{PostID: postID, UserID: userID, AuthorName: name, Content: content, Status: "published"} + // 回复的回复仍然挂到同一条一级评论下,保持两级不塌成深树 + replyTo := "" + if parentID != "" { + var parent model.Comment + if err := s.db.Where("id = ? AND post_id = ?", parentID, postID).First(&parent).Error; err != nil { + return nil, ErrNotFound + } + if parent.ParentID != "" { + replyTo = parent.AuthorName + parentID = parent.ParentID + } + } + + comment := model.Comment{ + PostID: postID, UserID: userID, AuthorName: name, Content: content, + Status: "published", ParentID: parentID, ReplyToName: replyTo, + } // 配图存 JSON 数组。空数组也要显式写,否则前端拿到 null 还要额外判空 if b, err := json.Marshal(images); err == nil && len(images) > 0 { comment.Images = b @@ -265,7 +325,18 @@ func (s *Service) DeleteOwnComment(userID, commentID string) error { Update("status", "deleted").Error; err != nil { return err } - return tx.Model(&model.Post{}).Where("id = ? AND comment_count > 0", c.PostID). - UpdateColumn("comment_count", gorm.Expr("comment_count - 1")).Error + // 删一级评论要连它下面的回复一起删,否则回复会变成挂在空处的孤儿 + n := int64(1) + if c.ParentID == "" { + res := tx.Model(&model.Comment{}). + Where("parent_id = ? AND status = ?", commentID, "published"). + Update("status", "deleted") + if res.Error != nil { + return res.Error + } + n += res.RowsAffected + } + return tx.Model(&model.Post{}).Where("id = ? AND comment_count >= ?", c.PostID, n). + UpdateColumn("comment_count", gorm.Expr("comment_count - ?", n)).Error }) } diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index ac93f06..f9a8dbf 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -119,6 +119,7 @@ Component({ posterSaving: false, centered: false, commentImages: [], + replyTo: {}, }, observers: { show: function (show) { @@ -165,6 +166,7 @@ Component({ patch.addBreed = ''; patch.commentText = ''; patch.commentImages = []; + patch.replyTo = {}; patch.riskData = null; patch.saving = false; } @@ -417,6 +419,7 @@ Component({ // 没有头像字段,用昵称首字做个色块,比一律显示同一个 emoji 强 initial: (c.author_name || '?').slice(0, 1), imgs: Array.isArray(c.images) ? c.images : [], + replies: (c.replies || []).map((r) => ({ ...r, timeText: fmtAgo(r.created_at) })), })), }), ) @@ -424,8 +427,9 @@ Component({ }, // 长按删除自己的评论 onDeleteComment(e) { - const c = this.data.comments[e.currentTarget.dataset.index]; - if (!c || !c.is_self) return; + const { id, self } = e.currentTarget.dataset; + if (!id || !self) return; + const c = { id }; wx.showModal({ title: '删除评论', content: '确定删除这条评论?', @@ -934,8 +938,13 @@ Component({ if (!text) return wx.showToast({ title: '写点什么再发', icon: 'none' }); if (!this.data.postId) return this.close(); try { - await api.createComment(this.data.postId, text, this.data.commentImages.map((i) => i.url)); - this.setData({ commentText: '', commentImages: [] }); + await api.createComment( + this.data.postId, + text, + this.data.commentImages.map((i) => i.url), + this.data.replyTo.id || '', + ); + this.setData({ commentText: '', commentImages: [], replyTo: {} }); this.loadComments(); this.triggerEvent('commented'); } catch (e) { @@ -955,6 +964,26 @@ Component({ wx.showToast({ title: (e && e.message) || '上传失败', icon: 'none' }); }); }, + // 回复某条评论:输入区顶部显示「回复 xxx」,发送时带上 parent_id + onReplyTo(e) { + const { id, name } = e.currentTarget.dataset; + this.setData({ replyTo: { id, name } }); + }, + onCancelReply() { + this.setData({ replyTo: {} }); + }, + // 一级评论默认只带 3 条回复,点开拉全量 + onExpandReplies(e) { + const { id, index } = e.currentTarget.dataset; + api + .listReplies(id) + .then((list) => + this.setData({ + [`comments[${index}].replies`]: (list || []).map((r) => ({ ...r, timeText: fmtAgo(r.created_at) })), + }), + ) + .catch((err) => wx.showToast({ title: (err && err.message) || '加载失败', icon: 'none' })); + }, onPreviewCommentImage(e) { const { urls, cur } = e.currentTarget.dataset; if (urls && urls.length) wx.previewImage({ urls, current: cur }); diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index 8be9fb2..47a02d7 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -321,7 +321,7 @@ module.exports.sel = function (map, key, index, def) { 评论 {{comments.length ? comments.length : ''}} - + {{item.initial}} @@ -329,12 +329,28 @@ module.exports.sel = function (map, key, index, def) { {{item.timeText}} - {{item.content}} + {{item.content}} + + + + + {{r.author_name}} + 回复 {{r.reply_to_name}} + {{r.content}} + + + 展开全部 {{item.reply_n}} 条回复 + + + + 回复 @@ -342,7 +358,11 @@ module.exports.sel = function (map, key, index, def) { 长按自己的评论可删除 - diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index 360119a..8f05b32 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -127,3 +127,16 @@ .cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} .cm-imgs{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-top:var(--sp-2)} .cm-img{width:150rpx;height:150rpx;border-radius:var(--r-sm)} + +/* 回复:只缩进一层,再深手机上就没法读了 */ +.cm-replies{margin-top:var(--sp-2);padding:var(--sp-2) var(--sp-3);background:var(--surface-2);border-radius:var(--r-sm)} +.cm-reply{font-size:var(--fs-sm);line-height:1.6;color:var(--text);padding:4rpx 0} +.cm-at{color:var(--muted)} +.cm-more{margin-top:6rpx;font-size:var(--fs-cap);color:var(--primary-dark)} +.cm-act{margin-top:var(--sp-2);font-size:var(--fs-cap);color:var(--muted)} +.cm-replying{ + display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-2); + padding:var(--sp-1) var(--sp-3);border-radius:var(--r-full); + background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap);align-self:flex-start; +} +.cm-cancel{display:flex;align-items:center} diff --git a/pets-fe/utils/api.js b/pets-fe/utils/api.js index 6bcc196..2690012 100644 --- a/pets-fe/utils/api.js +++ b/pets-fe/utils/api.js @@ -108,8 +108,13 @@ const api = { deletePost: (id) => request({ url: `/api/posts/${id}`, method: 'DELETE' }), deleteComment: (id) => request({ url: `/api/comments/${id}`, method: 'DELETE' }), listComments: (id) => request({ url: `/api/posts/${id}/comments` }), - createComment: (id, content, images) => - request({ url: `/api/posts/${id}/comments`, method: 'POST', data: { content, images: images || [] } }), + createComment: (id, content, images, parentId) => + request({ + url: `/api/posts/${id}/comments`, + method: 'POST', + data: { content, images: images || [], parent_id: parentId || '' }, + }), + listReplies: (commentId) => request({ url: `/api/comments/${commentId}/replies` }), // 文章 listArticles: () => request({ url: '/api/articles' }), -- 2.52.0 From fe420ba47c3aed569375fb75c7f48576ce9b8b44 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 16:39:36 +0800 Subject: [PATCH 21/58] =?UTF-8?q?feat(fe):=20=E8=AF=84=E8=AE=BA=E6=94=B9?= =?UTF-8?q?=E6=88=90=E5=B0=8F=E7=BA=A2=E4=B9=A6=E9=82=A3=E5=A5=97=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E2=80=94=E2=80=94=E7=82=B9=E8=AF=84=E8=AE=BA=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=94=A4=E8=B5=B7=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一版做成了居中弹窗,参考图给的是另一种范式:输入栏常驻底部,点任意 一条评论就把它激活并填上「回复 @xxx」。按参考图重做,居中那套一并删掉, 不留死代码。 结构从「一个滚动容器装所有东西」改成三段式: 固定头(共 N 条评论)+ 滚动列表 + 常驻输入栏 输入栏必须在滚动区外——放进去的话列表一滚它就跟着走,点完评论还得再 把输入框找回来,正是这次要解决的问题。 交互: - 点评论或回复的任意位置 → 输入框获得焦点,placeholder 变「回复 @xxx」, 上方出现可取消的橙色提示条。不用再单独点一个「回复」按钮 - 删除从长按改成显式的「删除」文字,只在自己的评论上出现——长按是 隐藏交互,没人会发现 - 回复带首字头像并缩进一层,「甲 回复 乙」的指向关系显示在昵称行 键盘处理用 adjust-position=false + bindfocus 拿键盘高度自己顶:弹层是 fixed 定位,交给系统调整会把整块推出屏幕。 Co-Authored-By: Claude Opus 5 --- .../components/bottom-sheet/bottom-sheet.js | 35 ++++- .../components/bottom-sheet/bottom-sheet.wxml | 148 ++++++++++-------- .../components/bottom-sheet/bottom-sheet.wxss | 82 +++++----- 3 files changed, 150 insertions(+), 115 deletions(-) diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index f9a8dbf..bded3c9 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -117,9 +117,11 @@ Component({ proInfo: null, saving: false, posterSaving: false, - centered: false, commentImages: [], replyTo: {}, + cmFocus: false, + kbHeight: 0, + total: 0, }, observers: { show: function (show) { @@ -139,8 +141,7 @@ Component({ methods: { setType(type, fresh) { const pet = store.getPet(); - // 评论以输入为主,贴底弹层会被键盘顶掉大半屏,改成居中 - const patch = { innerType: type, pet, centered: type === 'comments' }; + const patch = { innerType: type, pet }; if (fresh) { patch.segSel = {}; patch.optSel = {}; @@ -167,6 +168,8 @@ Component({ patch.commentText = ''; patch.commentImages = []; patch.replyTo = {}; + patch.cmFocus = false; + patch.kbHeight = 0; patch.riskData = null; patch.saving = false; } @@ -413,13 +416,18 @@ Component({ api.listComments(this.data.postId) .then((page) => this.setData({ + total: page.total || 0, comments: (page.list || []).map((c) => ({ ...c, timeText: fmtAgo(c.created_at), // 没有头像字段,用昵称首字做个色块,比一律显示同一个 emoji 强 initial: (c.author_name || '?').slice(0, 1), imgs: Array.isArray(c.images) ? c.images : [], - replies: (c.replies || []).map((r) => ({ ...r, timeText: fmtAgo(r.created_at) })), + replies: (c.replies || []).map((r) => ({ + ...r, + timeText: fmtAgo(r.created_at), + initial: (r.author_name || '?').slice(0, 1), + })), })), }), ) @@ -965,9 +973,20 @@ Component({ }); }, // 回复某条评论:输入区顶部显示「回复 xxx」,发送时带上 parent_id + // 小红书那套:点任意一条评论/回复,直接把输入框激活并填上「回复 @xxx」, + // 不用再去底部找输入框、也不用单独点一个「回复」按钮 onReplyTo(e) { const { id, name } = e.currentTarget.dataset; - this.setData({ replyTo: { id, name } }); + if (!id) return; + this.setData({ replyTo: { id, name }, cmFocus: true }); + }, + onCommentFocus(e) { + // adjust-position=false,键盘高度自己接管:弹层是 fixed 定位, + // 交给系统顶会把整块推出屏幕 + this.setData({ kbHeight: (e.detail && e.detail.height) || 0 }); + }, + onCommentBlur() { + this.setData({ kbHeight: 0, cmFocus: false }); }, onCancelReply() { this.setData({ replyTo: {} }); @@ -979,7 +998,11 @@ Component({ .listReplies(id) .then((list) => this.setData({ - [`comments[${index}].replies`]: (list || []).map((r) => ({ ...r, timeText: fmtAgo(r.created_at) })), + [`comments[${index}].replies`]: (list || []).map((r) => ({ + ...r, + timeText: fmtAgo(r.created_at), + initial: (r.author_name || '?').slice(0, 1), + })), }), ) .catch((err) => wx.showToast({ title: (err && err.message) || '加载失败', icon: 'none' })); diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index 47a02d7..adb50f4 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -7,10 +7,91 @@ module.exports.sel = function (map, key, index, def) { - + - + + + 共 {{total}} 条评论 + + + + {{item.initial}} + + {{item.author_name}} + {{item.content}} + + + + + {{item.timeText}} + 回复 + 删除 + + + + + + {{r.initial}} + + + {{r.author_name}} + 回复 {{r.reply_to_name}} + + {{r.content}} + + {{r.timeText}} + 回复 + 删除 + + + + + — 展开全部 {{item.reply_n}} 条回复 + + + + + + 还没有评论,来抢个沙发 + + + + + 回复 {{replyTo.name}} + + + + + + + + + + + + + + {{commentText.length}}/500 + 发送 + + + + + + 记录体重 @@ -318,69 +399,6 @@ module.exports.sel = function (map, key, index, def) { - - 评论 {{comments.length ? comments.length : ''}} - - - {{item.initial}} - - - {{item.author_name}} - - {{item.timeText}} - - {{item.content}} - - - - - - - - {{r.author_name}} - 回复 {{r.reply_to_name}} - {{r.content}} - - - 展开全部 {{item.reply_n}} 条回复 - - - - 回复 - - - - 还没有评论,来抢个沙发 - 长按自己的评论可删除 - - - - 回复 {{replyTo.name}} - - - - - - - - - - - - - 配图 {{commentImages.length}}/3 - - {{commentText.length}}/500 - 发送 - - - diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index 8f05b32..d9aa008 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -83,60 +83,54 @@ /* 离屏画布:挪到可视区外而不是 display:none,否则 selectorQuery 取不到节点 */ .poster-canvas{position:fixed;left:-9999rpx;top:0;width:600rpx;height:840rpx} -/* 评论。原来拿 .record-row(左右两端对齐)当评论用,昵称在左内容在右, - 内容一长就被挤扁。改成头像 + 昵称时间 + 内容的正常结构。 */ -.cm{display:flex;gap:var(--sp-3);padding:var(--sp-3) 0;border-bottom:1rpx solid var(--line)} -.cm:last-of-type{border-bottom:0} +/* ── 评论:头 + 滚动列表 + 常驻输入栏 ── */ +.sheet.sheet-cmp{display:flex;flex-direction:column;height:82vh;padding-bottom:0} +.cmp-head{ + flex:none;text-align:center;padding:0 0 var(--sp-3); + font-size:var(--fs-sm);color:var(--muted);border-bottom:1rpx solid var(--line); +} +.cmp-list{flex:1;min-height:0;padding:var(--sp-3) var(--sp-5) 0} +.cmp-dock{ + flex:none;background:#fff;border-top:1rpx solid var(--line); + padding:var(--sp-3) var(--sp-5) calc(20rpx + env(safe-area-inset-bottom)); + transition:padding-bottom .2s ease; +} + +.cm{display:flex;gap:var(--sp-3);padding:var(--sp-3) 0} .cm-av{ - width:64rpx;height:64rpx;border-radius:var(--r-sm);flex:none; + width:64rpx;height:64rpx;border-radius:50%;flex:none; display:flex;align-items:center;justify-content:center; background:var(--primary-soft);color:var(--primary-ink); font-size:var(--fs-md);font-weight:var(--fw-b); } +.cm-av-sm{width:48rpx;height:48rpx;font-size:var(--fs-sm)} .cm-body{flex:1;min-width:0} -.cm-head{display:flex;align-items:center;gap:var(--sp-1)} -.cm-name{font-size:var(--fs-sm);font-weight:var(--fw-b);color:var(--text-2)} -.cm-time{margin-left:auto;font-size:var(--fs-cap);color:var(--muted2);flex:none} +.cm-name{font-size:var(--fs-sm);color:var(--muted)} +.cm-at{color:var(--muted2)} .cm-text{margin-top:6rpx;font-size:var(--fs-md);line-height:1.55;word-break:break-word} -.cm-tip{margin-top:var(--sp-3);text-align:center;color:var(--muted2);font-size:var(--fs-cap)} - -.cm-input{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4)} -.cm-input .input{flex:1} -.cm-send{ - flex:none;height:88rpx;padding:0 var(--sp-5);border-radius:var(--r-md); - display:flex;align-items:center;justify-content:center; - background:var(--line);color:#fff;font-size:var(--fs-md);font-weight:var(--fw-b);transition:.16s ease; -} -.cm-send.on{background:var(--cta)} - -/* 居中弹层:评论这类以输入为主的,贴底会被键盘顶掉大半屏 */ -.sheet.sheet-center{ - left:var(--sp-5);right:var(--sp-5);bottom:auto;top:50%; - border-radius:var(--r-lg); - transform:translateY(-50%) scale(.94);opacity:0; -} -.overlay.show .sheet.sheet-center{transform:translateY(-50%) scale(1);opacity:1} -.sheet-center .sheet-scroll{max-height:62vh;padding:0 var(--sp-5) var(--sp-5)} -.sheet-center .sheetbar{display:none} - -/* 评论编辑区 */ -.cm-editor{margin-top:var(--sp-4);border-top:1rpx solid var(--line);padding-top:var(--sp-4)} -.cm-ta{min-height:160rpx;height:auto} -.cm-bar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)} -.cm-pic{display:flex;align-items:center;gap:var(--sp-1);color:var(--muted);font-size:var(--fs-sm)} -.cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} .cm-imgs{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-top:var(--sp-2)} .cm-img{width:150rpx;height:150rpx;border-radius:var(--r-sm)} +.cm-meta{display:flex;align-items:center;gap:var(--sp-4);margin-top:var(--sp-2);font-size:var(--fs-cap);color:var(--muted2)} +.cm-reply-btn{color:var(--muted)} +.cm-del{color:var(--red-ink)} +.cm-replies{margin-top:var(--sp-2)} +.cm-reply{display:flex;gap:var(--sp-2);padding:var(--sp-2) 0} +.cm-more{margin-top:4rpx;font-size:var(--fs-cap);color:var(--muted)} -/* 回复:只缩进一层,再深手机上就没法读了 */ -.cm-replies{margin-top:var(--sp-2);padding:var(--sp-2) var(--sp-3);background:var(--surface-2);border-radius:var(--r-sm)} -.cm-reply{font-size:var(--fs-sm);line-height:1.6;color:var(--text);padding:4rpx 0} -.cm-at{color:var(--muted)} -.cm-more{margin-top:6rpx;font-size:var(--fs-cap);color:var(--primary-dark)} -.cm-act{margin-top:var(--sp-2);font-size:var(--fs-cap);color:var(--muted)} +/* 「回复 @xxx」的提示条 */ .cm-replying{ - display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-2); - padding:var(--sp-1) var(--sp-3);border-radius:var(--r-full); - background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap);align-self:flex-start; + display:inline-flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-2); + padding:4rpx var(--sp-3);border-radius:var(--r-full); + background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap); } .cm-cancel{display:flex;align-items:center} +.cm-ta{min-height:120rpx;height:auto;background:var(--surface-2)} +.cm-bar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-2)} +.cm-pic{display:flex;align-items:center;color:var(--muted)} +.cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} +.cm-send{ + flex:none;height:72rpx;padding:0 var(--sp-5);border-radius:var(--r-full); + display:flex;align-items:center;justify-content:center; + background:var(--line);color:#fff;font-size:var(--fs-sm);font-weight:var(--fw-b);transition:.16s ease; +} +.cm-send.on{background:var(--cta)} -- 2.52.0 From b8b3ba99b447c951e5776464772c3f17b9850577 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 17:05:17 +0800 Subject: [PATCH 22/58] =?UTF-8?q?fix(fe):=20=E9=A1=B6=E9=83=A8=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=E6=9D=A1=E5=8E=BB=E6=8E=89=E8=A1=A5=E4=B8=81=E6=84=9F?= =?UTF-8?q?=20+=20=E7=A4=BE=E5=8C=BA=E5=88=86=E7=B1=BB=E5=90=B8=E9=A1=B6?= =?UTF-8?q?=20+=20=E5=88=87=E5=88=86=E7=B1=BB=E5=9B=9E=E9=A1=B6=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 那条 banner 为什么丑 我给它加了不透明底色 + 分隔线,而页面本身是渐变背景——等于在渐变上 贴了块补丁,屏幕上出现三条颜色不搭的横带。 但它根本不需要背景:它在文档流里而不是浮层,内容永远不会滚到它下面。 去掉 background / backdrop-filter / border 之后自然融进页面渐变。 顺手把 .pet-bar 改名 .top-bar,因为社区也要用它。 ## 社区 - 分类标签移出滚动区吸顶。原来一滚就没了,想换分类还得先滚回顶部 - 「发布图文」那个大黑按钮独占 124rpx,而发帖是低频操作,不该在每屏 都占着首屏。压成右侧的小胶囊,收进同一条,始终可点 - 切分类回到顶部:不然从「推荐」滚到一半切到「关注」,看到的是新列表 的中间,会以为内容错乱了 回顶用 scroll-into-view + 锚点,并在 bindscroll 里清掉锚点值—— 不清的话下次再设同一个值不会触发,第二次切分类就不动了。 Co-Authored-By: Claude Opus 5 --- pets-fe/app.wxss | 20 +- pets-fe/pages/community/community.js | 9 +- pets-fe/pages/community/community.wxml | 12 +- pets-fe/pages/community/community.wxss | 10 + pets-fe/pages/home/home.wxml | 2 +- pets-fe/pages/plan/plan.wxml | 2 +- pets-fe/pages/record/record.wxml | 2 +- pets-fe/pages/report/report.wxml | 2 +- pets-fe/preview-v2.html | 338 +++++++++++-------------- 9 files changed, 178 insertions(+), 219 deletions(-) diff --git a/pets-fe/app.wxss b/pets-fe/app.wxss index ca59719..8f2ea40 100644 --- a/pets-fe/app.wxss +++ b/pets-fe/app.wxss @@ -358,16 +358,10 @@ page{scrollbar-width:none;-ms-overflow-style:none} .no-pet-b{font-size:var(--fs-lg);font-weight:var(--fw-b)} .no-pet-p{color:var(--muted);font-size:var(--fs-sm);margin:var(--sp-2) 0 var(--sp-4);line-height:1.6} -/* 宠物切换条固定在导航栏下方。它原本在 scroll-view 里,滚下去就找不到了, - 而切宠物是随时要用的动作——尤其多宠用户,看着 A 的数据想切到 B - 还得先滚回顶部。移出滚动区,四个主页面通用。 */ -.pet-bar{ - flex:none; - padding:var(--sp-2) var(--pad-x) 0; - background:rgba(250,247,242,.92); - backdrop-filter:blur(20rpx); - -webkit-backdrop-filter:blur(20rpx); - border-bottom:1rpx solid rgba(238,230,220,.7); -} -/* 条内的 pet-switch 自己带 padding-bottom,这里不再叠加 */ -.pet-bar .pet-switch{padding-bottom:var(--sp-2)} +/* 顶部固定条:宠物切换 / 社区分类。 + 它在文档流里而不是浮层——内容永远不会滚到它下面,所以不需要任何背景。 + 之前给了不透明底色 + 分隔线,等于在页面渐变上贴了块补丁, + 屏幕上就出现三条颜色不搭的横带。 */ +.top-bar{flex:none;padding:var(--sp-2) var(--pad-x) 0} +.top-bar .pet-switch{padding-bottom:var(--sp-2)} +.top-bar .st-pill{padding-bottom:var(--sp-2)} diff --git a/pets-fe/pages/community/community.js b/pets-fe/pages/community/community.js index b3fa87f..3b72d7f 100644 --- a/pets-fe/pages/community/community.js +++ b/pets-fe/pages/community/community.js @@ -52,6 +52,7 @@ Page({ sheetPostId: '', loaded: false, loadErr: '', + intoView: '', }, onLoad() { this._unsub = store.subscribe((pet) => this.setData({ pet })); @@ -85,9 +86,15 @@ Page({ }, // 来自 seg-tabs 的 change 事件 switchFeedTab(e) { - this.setData({ feedIdx: Number(e.detail.index) }); + // 切分类必须回到顶部:不然从「推荐」滚到一半切到「关注」, + // 看到的是新列表的中间,会以为内容错乱了 + this.setData({ feedIdx: Number(e.detail.index), intoView: 'feed-top' }); this.loadPosts(); }, + // 滚动时清掉锚点,否则下次再设同一个值不会触发 + onFeedScroll() { + if (this.data.intoView) this.setData({ intoView: '' }); + }, likePost(e) { const i = e.currentTarget.dataset.index; const post = this.data.posts[i]; diff --git a/pets-fe/pages/community/community.wxml b/pets-fe/pages/community/community.wxml index b0246af..a3f7d96 100644 --- a/pets-fe/pages/community/community.wxml +++ b/pets-fe/pages/community/community.wxml @@ -3,14 +3,16 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } - - + - - - + + 发布 + + + + {{item.author_emoji}} diff --git a/pets-fe/pages/community/community.wxss b/pets-fe/pages/community/community.wxss index d4b5e37..13d296c 100644 --- a/pets-fe/pages/community/community.wxss +++ b/pets-fe/pages/community/community.wxss @@ -46,3 +46,13 @@ margin-top:var(--sp-3);display:inline-block;padding:var(--sp-2) var(--sp-6);border-radius:var(--r-full); background:var(--primary-soft);color:var(--primary-dark);font-weight:var(--fw-b);font-size:var(--fs-sm); } + +/* 分类标签吸顶,发布按钮收进同一条:原来那个大黑按钮独占 124rpx, + 而它是低频操作,不该在每屏都占着首屏 */ +.feed-bar{display:flex;align-items:flex-start;gap:var(--sp-3)} +.feed-bar .st{flex:1;min-width:0} +.feed-post{ + flex:none;display:flex;align-items:center;gap:4rpx; + height:var(--h-sm);padding:0 var(--sp-3);border-radius:var(--r-full); + background:var(--cta);color:#fff;font-size:var(--fs-sm);font-weight:var(--fw-b); +} diff --git a/pets-fe/pages/home/home.wxml b/pets-fe/pages/home/home.wxml index bd1a877..2803b74 100644 --- a/pets-fe/pages/home/home.wxml +++ b/pets-fe/pages/home/home.wxml @@ -1,6 +1,6 @@ - + diff --git a/pets-fe/pages/plan/plan.wxml b/pets-fe/pages/plan/plan.wxml index eada325..14bda85 100644 --- a/pets-fe/pages/plan/plan.wxml +++ b/pets-fe/pages/plan/plan.wxml @@ -1,6 +1,6 @@ - + diff --git a/pets-fe/pages/record/record.wxml b/pets-fe/pages/record/record.wxml index 2568598..7165bdb 100644 --- a/pets-fe/pages/record/record.wxml +++ b/pets-fe/pages/record/record.wxml @@ -1,6 +1,6 @@ - + diff --git a/pets-fe/pages/report/report.wxml b/pets-fe/pages/report/report.wxml index 5561f90..3bf9647 100644 --- a/pets-fe/pages/report/report.wxml +++ b/pets-fe/pages/report/report.wxml @@ -1,6 +1,6 @@ - + diff --git a/pets-fe/preview-v2.html b/pets-fe/preview-v2.html index ccffaad..85221df 100644 --- a/pets-fe/preview-v2.html +++ b/pets-fe/preview-v2.html @@ -1,35 +1,12 @@ - - -肉垫计划 · 设计预览 v2 - - - +
+

首页顶部

+
+
🐶
钞票
+
添加
+
+
下午好,开发用户
+
今天也要照顾好 钞票
+
+
卡片内容…
-

1 · 图标全集(38 个)

-

来源 Tabler Icons (MIT)。mask-image + currentColor,不是字体——Tabler 是描边图标,转字体要先展开轮廓,漏了会生成空字形。

-
weight
poop
food
symptom
medicine
cost
vaccine
deworm
photo
home
plan
record
report
community
back
next
plus
check
close
trash
edit
share
comment
like
like-on
more
bell
settings
ai
warn
doc
note
book
trend
cat
dog
user
clock
- -

2 · 尺寸可读性

-

32rpx(16px) 是正文里最常用的尺寸,重点看这一档描边够不够清楚。

-
- 16px / 32rpx - 20px / 40rpx - 24px / 48rpx - 28px / 56rpx -
- -

3 · tabBar

-
-
首页
-
计划
-
记录
-
报告
-
社区
-
- -

4 · 圆角 5 档

-
- xs 12 - sm 20 - md 28 - lg 40 - full -
- -

5 · 字号 6 档 / 字重只留两档

-
-
2xl 48 · 页面大标题
-
xl 40 · 卡片主数值
-
lg 32 · 小标题与按钮
-
md 28 · 正文
-
sm 24 · 辅助说明
-
cap 22 · 角标
-
- - -

6 · 按钮

-
-
保存记录
-
问问 AI
-
取消
-
开通 Pro
-
管理
-
-

主按钮保持暖橙:它有 36 处使用、绝大多数是弹层里的「保存」,改成深色会让全站主色消失。深色只给页面级首要 CTA。

- -

7 · 标签 / 状态 chip / 4 色分类块

-
- 已完成待处理 - 异常经验精选 -
-
- 体重稳定 - 任务全清 - 驱虫将到期 -
-
-
体重
-
饮食
-
异常
-
照片
-
- -

8 · 卡片 / 任务 / 统计 / 进度

-
-
-
今日任务管理
-
-
早餐喂食
已完成
-
记录体重
上次 4.2kg,建议每周一次
重要
-
+

社区顶部

+
+
+ 推荐关注新手求助晒宠
-
-
本周完成度72%
-
-
-
9
记录
-
4.2
体重kg
-
12
距驱虫
-
-
疫苗进度3/4 已完成
-
驱虫状态12 天后到期
-
-
- -

9 · 表单族(弹层里 28 种 type 全靠这几个类)

-
-
-
4.2
-
-
正常
软便
拉稀
-
-
-
呕吐拉稀精神差皮肤红
-
-
写点什么…
-
-
健康档案与体重趋势
-
AI 深度分析
-
-
取消
保存
-
-
- -

10 · 其它公共块

-
-
-
风险中 · 建议观察 24 小时
-
幼猫疫苗怎么打
首免、二免、三免的时间点和注意事项
-
小橘最近体重稳定,继续保持现在的喂食量就好。
那驱虫呢?
-
还没有记录,来记第一笔吧
-
-
- -

11 · 首页门面(方案 C)

-

状态环 + 状态 chip 做门面,今日任务提到首屏,4 色分类块替掉 8 宫格 emoji,最后一块深色 CTA。

-
-
-
- -
-
72%
-
完成度
-
-
-
-
小橘今天状态不错
-
还有 3 件事没做完
-
- 体重稳定 - 驱虫将到期 -
-
-
- -
-
今日任务管理
-
-
早餐喂食
-
记录体重
上次 4.2kg
重要
-
梳毛 10 分钟
-
-
- -
-
快速记录
-
-
体重
-
饮食
-
异常
-
照片
-
-
- -
问问 AI 养宠助手
-
- +
发布
+
+
+
🐮
+
奶牛猫饲养员
28 分钟前
+
+
刚打完第二针疫苗…
\ No newline at end of file -- 2.52.0 From 25f655a6fc2271d55b98a6e21b4040b8e93dfdfd Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 17:13:04 +0800 Subject: [PATCH 23/58] =?UTF-8?q?feat:=20=E8=A1=A5=E9=BD=90=E5=85=B3?= =?UTF-8?q?=E6=B3=A8=E7=9A=84=E5=85=A5=E5=8F=A3=E2=80=94=E2=80=94=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=B8=BB=E9=A1=B5=20+=20=E5=85=B3=E6=B3=A8/=E7=B2=89?= =?UTF-8?q?=E4=B8=9D=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关注之前只做了一半:能从帖子上点「+关注」,也有「关注」信息流,但 关注完就石沉大海——没有用户主页、看不到自己关注了谁、也不知道谁关注 了自己。功能是通的,路是断的。 后端新增: - GET /api/users/:id/profile 公开资料 + 帖子/关注/粉丝三个计数 + 我是否已关注 - GET /api/users/:id/posts TA 发布的帖子 - GET /api/users/:id/relations?kind=following|followers - /api/user/summary 补 following / followers,否则「我的」页那两行永远是 0 关系列表里「我是否关注了这批人」用一次 IN 查询查完,不是每行一次。 小程序端新增两个页面: - pages/user/user 用户主页:头像/昵称/三项计数/关注按钮 + TA 的帖子 - pages/relations 关注列表与粉丝列表(同一页,kind 区分) 入口: - 社区点头像或昵称 → TA 的主页 - 主页点「关注/粉丝」数字 → 对应列表 - 「我的」页新增「我的关注」「我的粉丝」两行 关注按钮先本地翻转再发请求,失败回滚——等接口返回按钮才变会显得很迟钝。 Co-Authored-By: Claude Opus 5 --- pets-be/internal/handler/community.go | 37 +++++++ pets-be/internal/router/router.go | 3 + pets-be/internal/service/home.go | 4 + pets-be/internal/service/user_profile.go | 123 +++++++++++++++++++++++ pets-fe/app.json | 4 +- pets-fe/pages/community/community.js | 5 + pets-fe/pages/community/community.wxml | 4 +- pets-fe/pages/profile/profile.js | 6 ++ pets-fe/pages/profile/profile.wxml | 2 + pets-fe/pages/relations/relations.js | 41 ++++++++ pets-fe/pages/relations/relations.json | 6 ++ pets-fe/pages/relations/relations.wxml | 20 ++++ pets-fe/pages/relations/relations.wxss | 12 +++ pets-fe/pages/user/user.js | 74 ++++++++++++++ pets-fe/pages/user/user.json | 6 ++ pets-fe/pages/user/user.wxml | 55 ++++++++++ pets-fe/pages/user/user.wxss | 12 +++ pets-fe/utils/api.js | 4 + 18 files changed, 415 insertions(+), 3 deletions(-) create mode 100644 pets-be/internal/service/user_profile.go create mode 100644 pets-fe/pages/relations/relations.js create mode 100644 pets-fe/pages/relations/relations.json create mode 100644 pets-fe/pages/relations/relations.wxml create mode 100644 pets-fe/pages/relations/relations.wxss create mode 100644 pets-fe/pages/user/user.js create mode 100644 pets-fe/pages/user/user.json create mode 100644 pets-fe/pages/user/user.wxml create mode 100644 pets-fe/pages/user/user.wxss diff --git a/pets-be/internal/handler/community.go b/pets-be/internal/handler/community.go index c34e0de..9aa7168 100644 --- a/pets-be/internal/handler/community.go +++ b/pets-be/internal/handler/community.go @@ -182,3 +182,40 @@ func (h *Handler) ListReplies(c *gin.Context) { } response.OK(c, list) } + +// UserCard GET /api/users/:id/profile 某人的公开资料 +func (h *Handler) UserCard(c *gin.Context) { + card, err := h.svc.GetUserCard(middleware.UserID(c), idParam(c, "id")) + if err != nil { + respondErr(c, err) + return + } + response.OK(c, card) +} + +// UserPosts GET /api/users/:id/posts 某人发布的帖子 +func (h *Handler) UserPosts(c *gin.Context) { + var req adminListReq + _ = c.ShouldBindQuery(&req) + req.Normalize() + posts, total, err := h.svc.ListUserPosts(middleware.UserID(c), idParam(c, "id"), req.Offset(), req.Limit()) + if err != nil { + response.FailErr(c, err) + return + } + response.OK(c, response.NewPage(posts, total, req.PageQuery)) +} + +// Relations GET /api/users/:id/relations?kind=following|followers +func (h *Handler) Relations(c *gin.Context) { + var req adminListReq + _ = c.ShouldBindQuery(&req) + req.Normalize() + kind := c.Query("kind") + list, total, err := h.svc.ListRelations(middleware.UserID(c), idParam(c, "id"), kind, req.Offset(), req.Limit()) + if err != nil { + response.FailErr(c, err) + return + } + response.OK(c, response.NewPage(list, total, req.PageQuery)) +} diff --git a/pets-be/internal/router/router.go b/pets-be/internal/router/router.go index c3b2b10..d0915de 100644 --- a/pets-be/internal/router/router.go +++ b/pets-be/internal/router/router.go @@ -88,6 +88,9 @@ func registerUserAPI(api *gin.RouterGroup, h *handler.Handler, jm *appjwt.Manage g.GET("/pets/:id/health-summary", h.HealthSummary) g.GET("/pets/:id/poster", h.Poster) + g.GET("/users/:id/profile", h.UserCard) + g.GET("/users/:id/posts", h.UserPosts) + g.GET("/users/:id/relations", h.Relations) g.POST("/users/:id/follow", h.FollowUser) g.DELETE("/users/:id/follow", h.UnfollowUser) diff --git a/pets-be/internal/service/home.go b/pets-be/internal/service/home.go index 90985c4..e9d6a6f 100644 --- a/pets-be/internal/service/home.go +++ b/pets-be/internal/service/home.go @@ -216,6 +216,8 @@ type UserSummary struct { Pets int64 `json:"pets"` Records int64 `json:"records"` Reminders int64 `json:"reminders"` + Following int64 `json:"following"` // 我关注了多少人 + Followers int64 `json:"followers"` // 多少人关注我 ProStatus string `json:"pro_status"` } @@ -225,6 +227,8 @@ func (s *Service) GetUserSummary(userID string) (*UserSummary, error) { s.db.Model(&model.Pet{}).Where("user_id = ?", userID).Count(&sum.Pets) s.db.Model(&model.HealthRecord{}).Where("user_id = ?", userID).Count(&sum.Records) s.db.Model(&model.Reminder{}).Where("user_id = ?", userID).Count(&sum.Reminders) + s.db.Model(&model.Follow{}).Where("follower_id = ?", userID).Count(&sum.Following) + s.db.Model(&model.Follow{}).Where("followee_id = ?", userID).Count(&sum.Followers) sum.ProStatus = model.ProNone var m model.ProMembership diff --git a/pets-be/internal/service/user_profile.go b/pets-be/internal/service/user_profile.go new file mode 100644 index 0000000..8ab6723 --- /dev/null +++ b/pets-be/internal/service/user_profile.go @@ -0,0 +1,123 @@ +package service + +import ( + "github.com/sundynix/pets-be/internal/model" +) + +// UserCard 用户公开资料。关注这件事之前只做了「点一下关注」, +// 关注完既看不到对方主页、也看不到自己关注了谁——等于关注完就石沉大海。 +type UserCard struct { + ID string `json:"id"` + Nickname string `json:"nickname"` + AvatarURL string `json:"avatar_url"` + IsBot bool `json:"is_bot"` + IsSelf bool `json:"is_self"` + Followed bool `json:"followed"` // 我有没有关注 TA + Posts int64 `json:"post_count"` + Following int64 `json:"following_count"` + Followers int64 `json:"follower_count"` +} + +// GetUserCard 取某人的公开资料 + 三个计数 + 我是否已关注 +func (s *Service) GetUserCard(viewerID, userID string) (*UserCard, error) { + var u model.User + if err := s.db.First(&u, "id = ?", userID).Error; err != nil { + return nil, ErrNotFound + } + card := &UserCard{ + ID: u.ID, Nickname: u.Nickname, IsBot: u.IsBot, + IsSelf: u.ID == viewerID, + AvatarURL: s.fileURL(u.AvatarFileID), + } + if card.AvatarURL == "" { + card.AvatarURL = u.Avatar + } + s.db.Model(&model.Post{}).Where("user_id = ? AND status = ?", userID, "published").Count(&card.Posts) + s.db.Model(&model.Follow{}).Where("follower_id = ?", userID).Count(&card.Following) + s.db.Model(&model.Follow{}).Where("followee_id = ?", userID).Count(&card.Followers) + + if !card.IsSelf { + var n int64 + s.db.Model(&model.Follow{}). + Where("follower_id = ? AND followee_id = ?", viewerID, userID).Count(&n) + card.Followed = n > 0 + } + return card, nil +} + +// ListUserPosts 某人发布的帖子 +func (s *Service) ListUserPosts(viewerID, userID string, offset, limit int) ([]model.Post, int64, error) { + q := s.db.Model(&model.Post{}).Where("user_id = ? AND status = ?", userID, "published") + var total int64 + if err := q.Count(&total).Error; err != nil { + return nil, 0, err + } + var posts []model.Post + if err := q.Order("id desc").Offset(offset).Limit(limit).Find(&posts).Error; err != nil { + return nil, 0, err + } + s.attachPostImages(posts) + s.markFollowed(viewerID, posts) + return posts, total, nil +} + +// ListRelations 关注列表 / 粉丝列表。 +// kind = "following" 我关注的人;"followers" 关注我的人 +func (s *Service) ListRelations(viewerID, userID, kind string, offset, limit int) ([]UserCard, int64, error) { + q := s.db.Model(&model.Follow{}) + var idCol string + if kind == "followers" { + q = q.Where("followee_id = ?", userID) + idCol = "follower_id" + } else { + q = q.Where("follower_id = ?", userID) + idCol = "followee_id" + } + var total int64 + if err := q.Count(&total).Error; err != nil { + return nil, 0, err + } + var ids []string + if err := q.Order("id desc").Offset(offset).Limit(limit).Pluck(idCol, &ids).Error; err != nil { + return nil, 0, err + } + if len(ids) == 0 { + return []UserCard{}, total, nil + } + + var users []model.User + s.db.Where("id IN ?", ids).Find(&users) + byID := map[string]model.User{} + for _, u := range users { + byID[u.ID] = u + } + + // 一次查出我关注了这批人里的哪些,不要每行一次查询 + var mine []string + s.db.Model(&model.Follow{}).Where("follower_id = ? AND followee_id IN ?", viewerID, ids). + Pluck("followee_id", &mine) + followed := map[string]bool{} + for _, id := range mine { + followed[id] = true + } + + // 按 ids 的顺序输出,保持「最近关注的在前」 + out := make([]UserCard, 0, len(ids)) + for _, id := range ids { + u, ok := byID[id] + if !ok { + continue + } + avatar := s.fileURL(u.AvatarFileID) + if avatar == "" { + avatar = u.Avatar + } + out = append(out, UserCard{ + ID: u.ID, Nickname: u.Nickname, IsBot: u.IsBot, + AvatarURL: avatar, + IsSelf: u.ID == viewerID, + Followed: followed[u.ID], + }) + } + return out, total, nil +} diff --git a/pets-fe/app.json b/pets-fe/app.json index 15629f2..c117869 100644 --- a/pets-fe/app.json +++ b/pets-fe/app.json @@ -9,7 +9,9 @@ "pages/learn/learn", "pages/article/article", "pages/profile/profile", - "pages/ai/ai" + "pages/ai/ai", + "pages/user/user", + "pages/relations/relations" ], "window": { "navigationStyle": "custom", diff --git a/pets-fe/pages/community/community.js b/pets-fe/pages/community/community.js index 3b72d7f..1a23d51 100644 --- a/pets-fe/pages/community/community.js +++ b/pets-fe/pages/community/community.js @@ -121,6 +121,11 @@ Page({ onCommented() { this.loadPosts(); }, + // 点头像或昵称进 TA 的主页。关注做了却没有主页,关注完就石沉大海 + goUser(e) { + const id = e.currentTarget.dataset.id; + if (id) wx.navigateTo({ url: `/pages/user/user?id=${id}` }); + }, goLearn() { wx.navigateTo({ url: '/pages/learn/learn' }); }, diff --git a/pets-fe/pages/community/community.wxml b/pets-fe/pages/community/community.wxml index a3f7d96..780bfd5 100644 --- a/pets-fe/pages/community/community.wxml +++ b/pets-fe/pages/community/community.wxml @@ -15,8 +15,8 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } - {{item.author_emoji}} - + {{item.author_emoji}} + {{item.author_name}}AI {{item.timeText}} diff --git a/pets-fe/pages/profile/profile.js b/pets-fe/pages/profile/profile.js index 7f6d451..50c989b 100644 --- a/pets-fe/pages/profile/profile.js +++ b/pets-fe/pages/profile/profile.js @@ -40,6 +40,12 @@ Page({ openSheet(e) { this.setData({ sheetType: e.currentTarget.dataset.type, sheetShow: true }); }, + // 自己的关注/粉丝。之前只有帖子上的「+关注」按钮,关注完没有任何地方能看 + goRelations(e) { + const uid = (this.data.user && this.data.user.id) || ''; + if (!uid) return wx.showToast({ title: '登录信息还没就绪', icon: 'none' }); + wx.navigateTo({ url: `/pages/relations/relations?id=${uid}&kind=${e.currentTarget.dataset.kind}` }); + }, goRecord() { wx.switchTab({ url: '/pages/record/record' }); }, diff --git a/pets-fe/pages/profile/profile.wxml b/pets-fe/pages/profile/profile.wxml index 881e725..ae5ed9b 100644 --- a/pets-fe/pages/profile/profile.wxml +++ b/pets-fe/pages/profile/profile.wxml @@ -20,6 +20,8 @@ 提醒设置{{summary.reminders}} 条 健康记录{{summary.records}} 条 多宠物管理{{summary.pets}} 只 + 我的关注{{summary.following || 0}} 人 + 我的粉丝{{summary.followers || 0}} 人 diff --git a/pets-fe/pages/relations/relations.js b/pets-fe/pages/relations/relations.js new file mode 100644 index 0000000..da59e20 --- /dev/null +++ b/pets-fe/pages/relations/relations.js @@ -0,0 +1,41 @@ +const api = require('../../utils/api.js'); +const { toastErr } = require('../../utils/ui.js'); + +Page({ + data: { uid: '', kind: 'following', title: '关注', list: [], page: 1, hasMore: false, loaded: false }, + onLoad(q) { + const kind = q && q.kind === 'followers' ? 'followers' : 'following'; + this.setData({ uid: (q && q.id) || '', kind, title: kind === 'followers' ? '粉丝' : '关注' }); + this.load(1); + }, + load(page) { + api + .relations(this.data.uid, this.data.kind, page) + .then((res) => { + const merged = page === 1 ? res.list || [] : this.data.list.concat(res.list || []); + this.setData({ list: merged, page, loaded: true, hasMore: merged.length < (res.total || 0) }); + }) + .catch((e) => { + this.setData({ loaded: true }); + toastErr(e); + }); + }, + loadMore() { + if (this.data.hasMore) this.load(this.data.page + 1); + }, + goUser(e) { + wx.navigateTo({ url: `/pages/user/user?id=${e.currentTarget.dataset.id}` }); + }, + // 同样先本地翻转再发请求,失败回滚 + toggleFollow(e) { + const i = e.currentTarget.dataset.index; + const u = this.data.list[i]; + if (!u || u.is_self) return; + const next = !u.followed; + this.setData({ [`list[${i}].followed`]: next }); + (next ? api.followUser(u.id) : api.unfollowUser(u.id)).catch((err) => { + this.setData({ [`list[${i}].followed`]: !next }); + toastErr(err, '操作失败'); + }); + }, +}); diff --git a/pets-fe/pages/relations/relations.json b/pets-fe/pages/relations/relations.json new file mode 100644 index 0000000..6594cd8 --- /dev/null +++ b/pets-fe/pages/relations/relations.json @@ -0,0 +1,6 @@ +{ + "usingComponents": { + "nav-bar": "/components/nav-bar/nav-bar", + "pt-icon": "/components/pt-icon/index" + } +} diff --git a/pets-fe/pages/relations/relations.wxml b/pets-fe/pages/relations/relations.wxml new file mode 100644 index 0000000..7e77f44 --- /dev/null +++ b/pets-fe/pages/relations/relations.wxml @@ -0,0 +1,20 @@ + + + + + + + + {{item.nickname[0]}} + + {{item.nickname}}AI + + + + + {{kind === 'followers' ? '还没有人关注 TA' : '还没有关注任何人,去宠友圈逛逛'}} + + + diff --git a/pets-fe/pages/relations/relations.wxss b/pets-fe/pages/relations/relations.wxss new file mode 100644 index 0000000..1ac6fad --- /dev/null +++ b/pets-fe/pages/relations/relations.wxss @@ -0,0 +1,12 @@ +.rel{ + display:flex;align-items:center;gap:var(--sp-3); + background:#fff;border-radius:var(--r-md);box-shadow:var(--sd-1); + padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-2); +} +.rel-av{ + width:80rpx;height:80rpx;border-radius:50%;flex:none;overflow:hidden; + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-lg);font-weight:var(--fw-b); +} +.rel-av-img{width:100%;height:100%} +.rel-name{flex:1;min-width:0;font-size:var(--fs-md);font-weight:var(--fw-b)} diff --git a/pets-fe/pages/user/user.js b/pets-fe/pages/user/user.js new file mode 100644 index 0000000..461bfc8 --- /dev/null +++ b/pets-fe/pages/user/user.js @@ -0,0 +1,74 @@ +const api = require('../../utils/api.js'); +const { toastErr } = require('../../utils/ui.js'); + +function fmtAgo(iso) { + if (!iso) return ''; + const d = new Date(iso); + if (isNaN(d.getTime())) return ''; + const min = Math.floor((Date.now() - d.getTime()) / 60000); + if (min < 1) return '刚刚'; + if (min < 60) return min + ' 分钟前'; + if (min < 60 * 24) return Math.floor(min / 60) + ' 小时前'; + if (min < 60 * 24 * 7) return Math.floor(min / 1440) + ' 天前'; + const p = (n) => (n < 10 ? '0' + n : '' + n); + return p(d.getMonth() + 1) + '-' + p(d.getDate()); +} + +Page({ + data: { uid: '', card: null, posts: [], page: 1, hasMore: false, loading: true }, + onLoad(q) { + const uid = q && q.id; + if (!uid) return wx.showToast({ title: '缺少用户', icon: 'none' }); + this.setData({ uid }); + this.loadCard(); + this.loadPosts(1); + }, + loadCard() { + api + .userCard(this.data.uid) + .then((card) => this.setData({ card, loading: false })) + .catch((e) => { + this.setData({ loading: false }); + toastErr(e); + }); + }, + loadPosts(page) { + api + .userPosts(this.data.uid, page) + .then((res) => { + const list = (res.list || []).map((p) => ({ ...p, timeText: fmtAgo(p.created_at) })); + const merged = page === 1 ? list : this.data.posts.concat(list); + this.setData({ posts: merged, page, hasMore: merged.length < (res.total || 0) }); + }) + .catch(() => {}); + }, + loadMore() { + if (this.data.hasMore) this.loadPosts(this.data.page + 1); + }, + // 关注状态先本地翻转,请求失败再翻回去——等接口返回按钮才变会显得很迟钝 + toggleFollow() { + const c = this.data.card; + if (!c || c.is_self) return; + const next = !c.followed; + this.setData({ + 'card.followed': next, + 'card.follower_count': Math.max(0, c.follower_count + (next ? 1 : -1)), + }); + (next ? api.followUser(c.id) : api.unfollowUser(c.id)).catch((e) => { + this.setData({ 'card.followed': !next, 'card.follower_count': c.follower_count }); + toastErr(e, '操作失败'); + }); + }, + goRelations(e) { + const kind = e.currentTarget.dataset.kind; + wx.navigateTo({ url: `/pages/relations/relations?id=${this.data.uid}&kind=${kind}` }); + }, + previewImage(e) { + const { urls, cur } = e.currentTarget.dataset; + if (urls && urls.length) wx.previewImage({ urls, current: cur }); + }, + onShareAppMessage() { + const n = (this.data.card && this.data.card.nickname) || '宠友'; + return { title: `${n} 的主页`, path: `/pages/user/user?id=${this.data.uid}` }; + }, +}); diff --git a/pets-fe/pages/user/user.json b/pets-fe/pages/user/user.json new file mode 100644 index 0000000..6594cd8 --- /dev/null +++ b/pets-fe/pages/user/user.json @@ -0,0 +1,6 @@ +{ + "usingComponents": { + "nav-bar": "/components/nav-bar/nav-bar", + "pt-icon": "/components/pt-icon/index" + } +} diff --git a/pets-fe/pages/user/user.wxml b/pets-fe/pages/user/user.wxml new file mode 100644 index 0000000..d7a5403 --- /dev/null +++ b/pets-fe/pages/user/user.wxml @@ -0,0 +1,55 @@ + +module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } + + + + + + 加载中… + + + + + + {{card.nickname[0]}} + + {{card.nickname}}AI + + + {{card.post_count}}帖子 + + {{card.following_count}}关注 + + + {{card.follower_count}}粉丝 + + + + + {{card.followed ? '已关注' : '关注 TA'}} + + + + + + {{item.timeText}} + + {{item.content}} + + + + {{img}} + + + + {{item.like_count || 0}} + {{item.comment_count || 0}} + + + + TA 还没有发过帖子 + + + diff --git a/pets-fe/pages/user/user.wxss b/pets-fe/pages/user/user.wxss new file mode 100644 index 0000000..23bb3b5 --- /dev/null +++ b/pets-fe/pages/user/user.wxss @@ -0,0 +1,12 @@ +.u-head{text-align:center;padding:var(--sp-6) var(--sp-5)} +.u-av{ + width:140rpx;height:140rpx;border-radius:50%;margin:0 auto var(--sp-3);overflow:hidden; + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary-ink);font-size:56rpx;font-weight:var(--fw-b); +} +.u-av-img{width:100%;height:100%} +.u-name{font-size:var(--fs-lg);font-weight:var(--fw-b)} +.u-stats{display:flex;justify-content:center;gap:var(--sp-6);margin:var(--sp-4) 0} +.u-stat{display:flex;flex-direction:column;align-items:center;gap:4rpx} +.u-n{font-size:var(--fs-lg);font-weight:var(--fw-b)} +.u-l{font-size:var(--fs-cap);color:var(--muted)} diff --git a/pets-fe/utils/api.js b/pets-fe/utils/api.js index 2690012..3649017 100644 --- a/pets-fe/utils/api.js +++ b/pets-fe/utils/api.js @@ -103,6 +103,10 @@ const api = { request({ url: `/api/posts?tab=${encodeURIComponent(tab || '')}&page=${page || 1}&page_size=10` }), createPost: (body) => request({ url: '/api/posts', method: 'POST', data: body }), likePost: (id) => request({ url: `/api/posts/${id}/like`, method: 'POST' }), + userCard: (userId) => request({ url: `/api/users/${userId}/profile` }), + userPosts: (userId, page) => request({ url: `/api/users/${userId}/posts?page=${page || 1}&page_size=10` }), + relations: (userId, kind, page) => + request({ url: `/api/users/${userId}/relations?kind=${kind}&page=${page || 1}&page_size=20` }), followUser: (userId) => request({ url: `/api/users/${userId}/follow`, method: 'POST' }), unfollowUser: (userId) => request({ url: `/api/users/${userId}/follow`, method: 'DELETE' }), deletePost: (id) => request({ url: `/api/posts/${id}`, method: 'DELETE' }), -- 2.52.0 From 3ad1516aa43555f52c1b9aa3d6ef9d8daff2fe06 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 29 Jul 2026 17:19:18 +0800 Subject: [PATCH 24/58] =?UTF-8?q?fix(fe):=20=E6=8C=89=E9=92=AE=E9=95=BF?= =?UTF-8?q?=E6=96=87=E6=A1=88=E6=92=91=E7=88=86=20+=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=B8=BB=E9=A1=B5=E5=B8=96=E5=AD=90=E6=B2=A1=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=20+=20=E9=A6=96=E5=AD=97=E5=A4=B4=E5=83=8F=E7=A9=BA=E7=99=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 三个都是我上一轮引入或没顾上的。 ## 「Pro 会员(即将开放)」把按钮撑爆 .btn 同时用了 flex 垂直居中和 line-height:96rpx。flex 已经负责居中了, line-height 纯属多余,而且文案一换行就被这个固定行高顶到按钮外面—— 「我的」页底部那颗按钮正好触发。改成 min-height + line-height:1.3, 按钮能随文案长高,短文案的高度不变。 ## 用户主页的帖子没有任何样式 .post-card 那一整套只写在 pages/community/community.wxss 里,而页面级 wxss 不跨页生效,所以用户主页上的帖子退化成裸文本。整块提到 app.wxss。 顺带给主页的帖子补上作者行和标签,和社区保持一致。 ## 头像圈里空白 WXML 表达式不支持字符串下标,{{nickname[0]}} 求值为空。改成在 js 里 slice 好再传给模板。 另外确认一下:粉丝列表本来就能点进主页——关注和粉丝共用 pages/relations 一个页面,每行都绑了 goUser,和关注列表走同一个 pages/user 主页。 Co-Authored-By: Claude Opus 5 --- pets-fe/app.wxss | 41 +++++++- pets-fe/pages/community/community.wxss | 34 ------- pets-fe/pages/relations/relations.js | 4 +- pets-fe/pages/relations/relations.wxml | 2 +- pets-fe/pages/user/user.js | 20 +++- pets-fe/pages/user/user.wxml | 9 +- pets-fe/preview-v2.html | 125 +++++++++++-------------- 7 files changed, 123 insertions(+), 112 deletions(-) diff --git a/pets-fe/app.wxss b/pets-fe/app.wxss index 8f2ea40..fc9160a 100644 --- a/pets-fe/app.wxss +++ b/pets-fe/app.wxss @@ -133,7 +133,8 @@ page{scrollbar-width:none;-ms-overflow-style:none} .btn{ border:0;height:var(--h-lg);border-radius:var(--r-md);padding:0 var(--sp-5); display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-2); - font-weight:var(--fw-b);font-size:var(--fs-lg);line-height:var(--h-lg);transition:.16s ease; + font-weight:var(--fw-b);font-size:var(--fs-lg);line-height:1.3;transition:.16s ease; + min-height:var(--h-lg);height:auto;padding-top:var(--sp-2);padding-bottom:var(--sp-2); } .btn::after{border:none} .btn:active{transform:scale(.98)} @@ -145,7 +146,7 @@ page{scrollbar-width:none;-ms-overflow-style:none} .btn-soft{color:var(--primary-ink);background:var(--primary-soft)} .btn-green{color:#fff;background:var(--green)} .btn-block{width:100%;display:flex} -.btn-small{height:var(--h-sm);border-radius:var(--r-sm);padding:0 var(--sp-4);font-size:var(--fs-sm);line-height:var(--h-sm)} +.btn-small{min-height:var(--h-sm);border-radius:var(--r-sm);padding:0 var(--sp-4);font-size:var(--fs-sm)} /* 卡片 */ .card{ @@ -365,3 +366,39 @@ page{scrollbar-width:none;-ms-overflow-style:none} .top-bar{flex:none;padding:var(--sp-2) var(--pad-x) 0} .top-bar .pet-switch{padding-bottom:var(--sp-2)} .top-bar .st-pill{padding-bottom:var(--sp-2)} + +/* 帖子卡。社区和用户主页都要用,页面级 wxss 不跨页生效,所以放全局 */ +.post-card{background:#fff;border-radius:var(--r-lg);box-shadow:var(--sd-1);padding:var(--sp-4);margin-bottom:var(--sp-4)} +.post-head{display:flex;align-items:center;gap:var(--sp-3);margin-bottom:var(--sp-3)} +.post-avatar{ + width:80rpx;height:80rpx;border-radius:var(--r-sm);background:var(--primary-soft); + display:flex;align-items:center;justify-content:center;font-size:40rpx;flex:none; +} +.post-user{flex:1;min-width:0} +.pu-b{font-size:var(--fs-md);display:block;font-weight:var(--fw-b)} +.ai-tag{ + display:inline-block;margin-left:var(--sp-1);padding:0 var(--sp-1);border-radius:var(--r-xs); + background:var(--blue-soft);color:var(--blue-ink);font-size:var(--fs-cap);font-weight:var(--fw-b);vertical-align:1rpx; +} +.pu-s{font-size:var(--fs-sm);color:var(--muted)} +.post-content{font-size:var(--fs-md);line-height:1.62;color:var(--text-2);margin-bottom:var(--sp-3)} + +.photo-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-1);margin-bottom:var(--sp-3)} +.photo-tile{ + aspect-ratio:1;border-radius:var(--r-sm);background:var(--primary-soft); + display:flex;align-items:center;justify-content:center;font-size:56rpx; +} + +/* 三等分。原来是 space-around 排三个宽度不一的项,点赞数一变宽度就跳 */ +.post-actions{display:flex;border-top:1rpx solid var(--line);padding-top:var(--sp-2)} +.pa-btn{ + flex:1;height:72rpx; + display:flex;align-items:center;justify-content:center;gap:var(--sp-1); + color:var(--muted);font-weight:var(--fw);font-size:var(--fs-sm); +} +.pa-n{line-height:1} +.pa-btn.liked{color:var(--red-ink)} +.pa-btn:active{background:var(--surface-2);border-radius:var(--r-sm)} +/* 分享用微信原生 open-type=share,得抹掉 button 默认外观 */ +.pa-share{background:transparent;border:none;padding:0;margin:0;line-height:inherit} +.pa-share::after{border:none} diff --git a/pets-fe/pages/community/community.wxss b/pets-fe/pages/community/community.wxss index 13d296c..4d53082 100644 --- a/pets-fe/pages/community/community.wxss +++ b/pets-fe/pages/community/community.wxss @@ -1,39 +1,5 @@ .compose-card{margin-bottom:var(--sp-4)} -.post-card{background:#fff;border-radius:var(--r-lg);box-shadow:var(--sd-1);padding:var(--sp-4);margin-bottom:var(--sp-4)} -.post-head{display:flex;align-items:center;gap:var(--sp-3);margin-bottom:var(--sp-3)} -.post-avatar{ - width:80rpx;height:80rpx;border-radius:var(--r-sm);background:var(--primary-soft); - display:flex;align-items:center;justify-content:center;font-size:40rpx;flex:none; -} -.post-user{flex:1;min-width:0} -.pu-b{font-size:var(--fs-md);display:block;font-weight:var(--fw-b)} -.ai-tag{ - display:inline-block;margin-left:var(--sp-1);padding:0 var(--sp-1);border-radius:var(--r-xs); - background:var(--blue-soft);color:var(--blue-ink);font-size:var(--fs-cap);font-weight:var(--fw-b);vertical-align:1rpx; -} -.pu-s{font-size:var(--fs-sm);color:var(--muted)} -.post-content{font-size:var(--fs-md);line-height:1.62;color:var(--text-2);margin-bottom:var(--sp-3)} - -.photo-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-1);margin-bottom:var(--sp-3)} -.photo-tile{ - aspect-ratio:1;border-radius:var(--r-sm);background:var(--primary-soft); - display:flex;align-items:center;justify-content:center;font-size:56rpx; -} - -/* 三等分。原来是 space-around 排三个宽度不一的项,点赞数一变宽度就跳 */ -.post-actions{display:flex;border-top:1rpx solid var(--line);padding-top:var(--sp-2)} -.pa-btn{ - flex:1;height:72rpx; - display:flex;align-items:center;justify-content:center;gap:var(--sp-1); - color:var(--muted);font-weight:var(--fw);font-size:var(--fs-sm); -} -.pa-n{line-height:1} -.pa-btn.liked{color:var(--red-ink)} -.pa-btn:active{background:var(--surface-2);border-radius:var(--r-sm)} -/* 分享用微信原生 open-type=share,得抹掉 button 默认外观 */ -.pa-share{background:transparent;border:none;padding:0;margin:0;line-height:inherit} -.pa-share::after{border:none} /* 关注按钮 */ .follow-btn{ diff --git a/pets-fe/pages/relations/relations.js b/pets-fe/pages/relations/relations.js index da59e20..6cb5c7f 100644 --- a/pets-fe/pages/relations/relations.js +++ b/pets-fe/pages/relations/relations.js @@ -12,7 +12,9 @@ Page({ api .relations(this.data.uid, this.data.kind, page) .then((res) => { - const merged = page === 1 ? res.list || [] : this.data.list.concat(res.list || []); + // WXML 表达式不支持字符串下标,首字母得在这里算好 + const list = (res.list || []).map((u) => ({ ...u, initial: (u.nickname || '?').slice(0, 1) })); + const merged = page === 1 ? list : this.data.list.concat(list); this.setData({ list: merged, page, loaded: true, hasMore: merged.length < (res.total || 0) }); }) .catch((e) => { diff --git a/pets-fe/pages/relations/relations.wxml b/pets-fe/pages/relations/relations.wxml index 7e77f44..09f45b3 100644 --- a/pets-fe/pages/relations/relations.wxml +++ b/pets-fe/pages/relations/relations.wxml @@ -6,7 +6,7 @@ - {{item.nickname[0]}} + {{item.initial}} {{item.nickname}}AI
+ ) +} diff --git a/pets-be/web/admin/src/pages/RecordTypes.tsx b/pets-be/web/admin/src/pages/RecordTypes.tsx new file mode 100644 index 0000000..6d9de3d --- /dev/null +++ b/pets-be/web/admin/src/pages/RecordTypes.tsx @@ -0,0 +1,275 @@ +import { useEffect, useState } from 'react' +import { api } from '@/lib/api' +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Card, CardContent } from '@/components/ui/card' +import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' + +type Field = { kind: string; label: string; unit?: string; options?: string[]; to_category: boolean } +type RT = { + id: string + code: string + label: string + icon: string + group: string + sort: number + enabled: boolean + form: string + locked: boolean + fields_raw: string + fields: Field[] +} + +const empty: any = { + id: '', code: '', label: '', icon: 'note', group: 'daily', + sort: 0, enabled: true, form: 'simple', locked: false, fields_raw: '', +} +const GROUPS = [ + { key: 'daily', label: '日常' }, + { key: 'health', label: '健康' }, + { key: 'care', label: '洗护' }, + { key: 'clean', label: '清洁' }, +] +const gLabel = (k: string) => GROUPS.find((g) => g.key === k)?.label || k + +// 字段配置那段紧凑写法的说明。放在弹窗里而不是文档里—— +// 这东西一年用两次,去翻文档的成本比它本身还高 +const HINT = `number:体重:kg 数值,落 num_value +options:状态:正常|软便|拉稀 单选,落 category +options:症状:呕吐|拉稀:- 末尾 - 表示不落 category(只进标题) +text:吃了什么 文本,只进标题 +(留空) 只要「时间 + 描述 + 照片」` + +export default function RecordTypes() { + const [list, setList] = useState([]) + const [open, setOpen] = useState(false) + const [form, setForm] = useState(empty) + const [err, setErr] = useState('') + + function reload() { + api + .recordTypes() + .then((r) => setList(r || [])) + .catch(() => setList([])) + } + useEffect(reload, []) + + function create() { + setForm({ ...empty }) + setErr('') + setOpen(true) + } + function edit(t: RT) { + setForm({ ...t }) + setErr('') + setOpen(true) + } + async function save() { + setErr('') + try { + await api.saveRecordType(form) + setOpen(false) + reload() + } catch (e: any) { + // 字段配置写错了后端会说第几行错在哪,原样透出 + setErr(e?.message || '保存失败') + } + } + async function del(t: RT) { + if (!confirm(`删除「${t.label}」?`)) return + try { + await api.deleteRecordType(t.id) + reload() + } catch (e: any) { + alert(e?.message || '删除失败') + } + } + + const set = (k: string) => (e: any) => setForm({ ...form, [k]: e.target.value }) + + // 字段配置渲染成人话,省得盯着 DSL 猜 + function fieldsText(t: RT) { + if (!t.fields?.length) return 时间 + 描述 + 照片 + return ( + + {t.fields.map((f, i) => ( + + {f.label} + {f.kind === 'number' && `·数值${f.unit || ''}`} + {f.kind === 'text' && '·文本'} + {f.kind === 'options' && `·单选${f.to_category ? '★' : ''}`} + + ))} + + ) + } + + const byGroup: Record = {} + list.forEach((t) => ((byGroup[t.group] = byGroup[t.group] || []).push(t))) + + return ( +
+
+
+

记录事项

+

+ 小程序「记一笔」的事项和它们的表单字段。★ 标记的单选会落到 category —— + 周报的高风险数、账单的分类统计都读这一列。 +

+
+ +
+ + + + + + + 分组 + 名称 + code + 表单字段 + 排序 + 状态 + 操作 + + + + {GROUPS.map((g) => + (byGroup[g.key] || []).map((t, i) => ( + + {i === 0 ? g.label : ''} + {t.label} + {t.code} + {fieldsText(t)} + {t.sort} + + {t.enabled ? 启用 : 停用} + {t.locked && ( + + 内置 + + )} + + + + {!t.locked && ( + + )} + + + )), + )} + {!list.length && ( + + + 还没有事项 —— 小程序的记录页会是空的 + + + )} + +
+
+
+ + + + + {form.id ? `编辑「${form.label}」` : '新增事项'} + +
+
+
+ + +
+
+ + +
+
+
+
+ +
+ {GROUPS.map((g) => ( + + ))} +
+
+
+ + +
+
+
+ + - + - + - {{commentText.length}}/500 + 发送 + {{commentText.length}}/500 diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index d9aa008..1943738 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -87,8 +87,20 @@ .sheet.sheet-cmp{display:flex;flex-direction:column;height:82vh;padding-bottom:0} .cmp-head{ flex:none;text-align:center;padding:0 0 var(--sp-3); - font-size:var(--fs-sm);color:var(--muted);border-bottom:1rpx solid var(--line); + font-size:var(--fs-md);font-weight:var(--fw-b);color:var(--text);border-bottom:1rpx solid var(--line); } +/* 空态:图标 + 两行字,居中在列表区,不再是一行字飘在大片留白里 */ +.cmp-empty{ + display:flex;flex-direction:column;align-items:center;justify-content:center; + padding:120rpx 0;color:var(--muted); +} +.cmp-empty-ic{ + width:140rpx;height:140rpx;border-radius:50%;margin-bottom:var(--sp-4); + display:flex;align-items:center;justify-content:center; + background:var(--primary-soft);color:var(--primary); +} +.cmp-empty-t{font-size:var(--fs-lg);font-weight:var(--fw-b);color:var(--text-2)} +.cmp-empty-p{margin-top:var(--sp-1);font-size:var(--fs-sm);color:var(--muted2)} .cmp-list{flex:1;min-height:0;padding:var(--sp-3) var(--sp-5) 0} .cmp-dock{ flex:none;background:#fff;border-top:1rpx solid var(--line); @@ -124,13 +136,22 @@ background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap); } .cm-cancel{display:flex;align-items:center} -.cm-ta{min-height:120rpx;height:auto;background:var(--surface-2)} -.cm-bar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-2)} -.cm-pic{display:flex;align-items:center;color:var(--muted)} -.cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} +/* 相机 + 输入框 + 发送 合成一条圆角输入栏,像聊天输入条; + textarea 撑开时相机和发送贴着底部 */ +.cm-inputrow{ + display:flex;align-items:flex-end;gap:var(--sp-2); + background:var(--surface-2);border:1rpx solid var(--line); + border-radius:32rpx;padding:10rpx var(--sp-2) 10rpx var(--sp-3); +} +.cm-pic{flex:none;display:flex;align-items:center;height:64rpx;color:var(--muted)} +.cm-ta{ + flex:1;min-width:0;min-height:64rpx;max-height:280rpx;height:auto; + padding:16rpx 0;background:transparent;font-size:var(--fs-md);line-height:1.4; +} .cm-send{ - flex:none;height:72rpx;padding:0 var(--sp-5);border-radius:var(--r-full); + flex:none;height:64rpx;padding:0 var(--sp-4);border-radius:var(--r-full); display:flex;align-items:center;justify-content:center; background:var(--line);color:#fff;font-size:var(--fs-sm);font-weight:var(--fw-b);transition:.16s ease; } .cm-send.on{background:var(--cta)} +.cm-count{display:block;text-align:right;margin-top:6rpx;color:var(--muted2);font-size:var(--fs-cap)} -- 2.52.0 From c48e241fe11620e1a079abd9f064daf35c4635df Mon Sep 17 00:00:00 2001 From: Blizzard Date: Thu, 30 Jul 2026 18:13:41 +0800 Subject: [PATCH 58/58] =?UTF-8?q?feat(fe):=20=E8=AF=84=E8=AE=BA=E6=94=B9?= =?UTF-8?q?=E5=B0=8F=E7=BA=A2=E4=B9=A6=E5=BC=8F=E5=B1=95=E5=BC=80=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E9=9D=A2=E6=9D=BF=EF=BC=9BFAB=20=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E6=9A=96=E6=A9=98=EF=BC=9B=E9=A1=B6=E9=83=A8=E5=8E=BB=E5=86=97?= =?UTF-8?q?=E4=BD=99=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 评论:底部平时一条细「说点什么」,点开才展开大写评论面板 (大输入框+工具栏+发送,浮在键盘上方)。失焦时有草稿保持展开, 避免点发送因面板收起而丢点击 - FAB 主题色统一:社区发帖 FAB 从深色改成和首页肉垫一致的暖橘圆钮 - 报告页顶部筛选去掉「添加」(报告页不需要建档入口) - 社区去掉顶部「发布」按钮,发帖统一走右下角悬浮按钮 Co-Authored-By: Claude Opus 5 --- .../components/bottom-sheet/bottom-sheet.js | 20 ++++++++-- .../components/bottom-sheet/bottom-sheet.wxml | 35 ++++++++++-------- .../components/bottom-sheet/bottom-sheet.wxss | 37 +++++++++++++------ pets-fe/components/fab/fab.wxss | 19 ++++------ pets-fe/pages/community/community.wxml | 4 +- pets-fe/pages/report/report.wxml | 2 +- 6 files changed, 71 insertions(+), 46 deletions(-) diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.js b/pets-fe/components/bottom-sheet/bottom-sheet.js index cde30cf..e059234 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.js +++ b/pets-fe/components/bottom-sheet/bottom-sheet.js @@ -80,6 +80,7 @@ Component({ commentImages: [], replyTo: {}, cmFocus: false, + composing: false, // 评论输入面板是否展开(收起时只是一条细条) kbHeight: 0, total: 0, }, @@ -117,6 +118,7 @@ Component({ patch.commentImages = []; patch.replyTo = {}; patch.cmFocus = false; + patch.composing = false; patch.kbHeight = 0; patch.saving = false; } @@ -635,7 +637,7 @@ Component({ this.data.commentImages.map((i) => i.url), this.data.replyTo.id || '', ); - this.setData({ commentText: '', commentImages: [], replyTo: {} }); + this.setData({ commentText: '', commentImages: [], replyTo: {}, composing: false, cmFocus: false }); this.loadComments(); this.triggerEvent('commented'); } catch (e) { @@ -661,7 +663,16 @@ Component({ onReplyTo(e) { const { id, name } = e.currentTarget.dataset; if (!id) return; - this.setData({ replyTo: { id, name }, cmFocus: true }); + // 点任意评论直接展开面板并预填回复对象 + this.setData({ replyTo: { id, name }, composing: true, cmFocus: true }); + }, + // 点细条:展开大输入面板并聚焦(拉起键盘) + onStartCompose() { + this.setData({ composing: true, cmFocus: true }); + }, + // 收起面板,草稿(文字/图片)留着,下次点开接着写 + onCloseCompose() { + this.setData({ composing: false, cmFocus: false, kbHeight: 0 }); }, onCommentFocus(e) { // adjust-position=false,键盘高度自己接管:弹层是 fixed 定位, @@ -669,7 +680,10 @@ Component({ this.setData({ kbHeight: (e.detail && e.detail.height) || 0 }); }, onCommentBlur() { - this.setData({ kbHeight: 0, cmFocus: false }); + // 失焦先放下键盘。有草稿就保持展开(否则点「发送」会因面板收起而丢掉这一下点击); + // 空内容才收回细条 + const empty = !(this.data.commentText || '').trim() && !this.data.commentImages.length; + this.setData({ kbHeight: 0, cmFocus: false, composing: empty ? false : this.data.composing }); }, onCancelReply() { this.setData({ replyTo: {} }); diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxml b/pets-fe/components/bottom-sheet/bottom-sheet.wxml index 0559235..0d7c241 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxml +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxml @@ -68,29 +68,34 @@ module.exports.sel = function (map, key, index, def) { - - - 回复 {{replyTo.name}} - + + + {{commentText || '说点什么…'}} + + + + + + + {{replyTo.name ? '回复 ' + replyTo.name : '写评论'}} + - + + - - - - - + + + {{commentText.length}}/500 发送 - {{commentText.length}}/500 diff --git a/pets-fe/components/bottom-sheet/bottom-sheet.wxss b/pets-fe/components/bottom-sheet/bottom-sheet.wxss index 1943738..547e849 100644 --- a/pets-fe/components/bottom-sheet/bottom-sheet.wxss +++ b/pets-fe/components/bottom-sheet/bottom-sheet.wxss @@ -136,22 +136,35 @@ background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap); } .cm-cancel{display:flex;align-items:center} -/* 相机 + 输入框 + 发送 合成一条圆角输入栏,像聊天输入条; - textarea 撑开时相机和发送贴着底部 */ -.cm-inputrow{ - display:flex;align-items:flex-end;gap:var(--sp-2); - background:var(--surface-2);border:1rpx solid var(--line); - border-radius:32rpx;padding:10rpx var(--sp-2) 10rpx var(--sp-3); +/* 收起态:底部一条细条,点了才展开成大面板(小红书那套) */ +.cm-collapsed{ + flex:none;display:flex;align-items:center;gap:var(--sp-3); + background:#fff;border-top:1rpx solid var(--line); + padding:var(--sp-3) var(--sp-5) calc(20rpx + env(safe-area-inset-bottom)); } -.cm-pic{flex:none;display:flex;align-items:center;height:64rpx;color:var(--muted)} +.cm-collapsed-pill{ + flex:1;min-width:0;height:76rpx;line-height:76rpx;padding:0 var(--sp-5); + border-radius:var(--r-full);background:var(--surface-2);color:var(--muted2); + font-size:var(--fs-md);overflow:hidden;white-space:nowrap;text-overflow:ellipsis; +} +.cm-collapsed-pill.has{color:var(--text)} +.cm-collapsed-ic{flex:none;display:flex;align-items:center;color:var(--muted)} + +/* 展开态:大写评论面板 */ +.cm-dock-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--sp-2)} +.cm-dock-title{font-size:var(--fs-md);font-weight:var(--fw-b);color:var(--text)} +.cm-dock-close{display:flex;align-items:center;color:var(--muted);padding:var(--sp-1)} .cm-ta{ - flex:1;min-width:0;min-height:64rpx;max-height:280rpx;height:auto; - padding:16rpx 0;background:transparent;font-size:var(--fs-md);line-height:1.4; + width:100%;box-sizing:border-box;min-height:200rpx;max-height:520rpx;height:auto; + padding:var(--sp-4);background:var(--surface-2);border-radius:var(--r-md); + font-size:var(--fs-lg);line-height:1.5; } +.cm-toolbar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)} +.cm-pic{flex:none;display:flex;align-items:center;color:var(--muted)} +.cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)} .cm-send{ - flex:none;height:64rpx;padding:0 var(--sp-4);border-radius:var(--r-full); + flex:none;height:76rpx;padding:0 var(--sp-6);border-radius:var(--r-full); display:flex;align-items:center;justify-content:center; - background:var(--line);color:#fff;font-size:var(--fs-sm);font-weight:var(--fw-b);transition:.16s ease; + background:var(--line);color:#fff;font-size:var(--fs-md);font-weight:var(--fw-b);transition:.16s ease; } .cm-send.on{background:var(--cta)} -.cm-count{display:block;text-align:right;margin-top:6rpx;color:var(--muted2);font-size:var(--fs-cap)} diff --git a/pets-fe/components/fab/fab.wxss b/pets-fe/components/fab/fab.wxss index 5685576..c3bb974 100644 --- a/pets-fe/components/fab/fab.wxss +++ b/pets-fe/components/fab/fab.wxss @@ -1,22 +1,17 @@ +/* 统一暖橘圆钮:首页肉垫和社区发帖用同一套主题色 */ .fab{ position:fixed;right:36rpx;bottom:calc(190rpx + env(safe-area-inset-bottom)); - width:108rpx;height:108rpx;border-radius:var(--r-md); - background:var(--cta); + width:112rpx;height:112rpx;border-radius:50%; + background:linear-gradient(150deg,#FFB865,#F5943E); color:#fff; display:flex;align-items:center;justify-content:center; - box-shadow:var(--sd-2); + box-shadow:0 12rpx 28rpx rgba(214,138,52,.42),0 2rpx 6rpx rgba(214,138,52,.3); z-index:60; } -.fab:active{transform:scale(.96)} +.fab:active{transform:scale(.94)} -/* 肉垫造型:暖橘圆钮,中间一只奶白肉垫。圆形更像脚印落下的样子, - 阴影带橘调让它从奶白背景上浮起来 */ -.fab-paw{ - width:116rpx;height:116rpx;border-radius:50%; - background:linear-gradient(150deg,#FFB865,#F5943E); - box-shadow:0 12rpx 28rpx rgba(214,138,52,.42),0 2rpx 6rpx rgba(214,138,52,.3); -} -.fab-paw:active{transform:scale(.94)} +/* 肉垫造型:和基础一致的暖橘圆钮,中间一只奶白肉垫 */ +.fab-paw{width:116rpx;height:116rpx} .paw{position:relative;width:66rpx;height:60rpx} /* 掌垫:上窄下宽的圆角心形块,坐在下方 */ diff --git a/pets-fe/pages/community/community.wxml b/pets-fe/pages/community/community.wxml index a25c0ce..e68084c 100644 --- a/pets-fe/pages/community/community.wxml +++ b/pets-fe/pages/community/community.wxml @@ -3,11 +3,9 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; } + - - 发布 - diff --git a/pets-fe/pages/report/report.wxml b/pets-fe/pages/report/report.wxml index cc68e88..f897697 100644 --- a/pets-fe/pages/report/report.wxml +++ b/pets-fe/pages/report/report.wxml @@ -1,6 +1,6 @@ - + -- 2.52.0