astock-agent/frontend/.next/static/chunks/app/recommendations/page-ef6715bbb27168f0.js
2026-04-08 00:57:23 +08:00

1 line
11 KiB
JavaScript

(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[70],{4895:function(e,t,n){Promise.resolve().then(n.bind(n,7773))},7773:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return i}});var a=n(7437),r=n(2265),s=n(1837),o=n(5229),c=n(6140);function i(){var e;let[t,n]=(0,r.useState)(null),[i,l]=(0,r.useState)("all"),[d,u]=(0,r.useState)(!1),x=(0,r.useCallback)(async()=>{try{let[e,t]=await Promise.all([(0,s.Io)("/api/recommendations/latest"),(0,s.Io)("/api/health")]);n(e),u(t.llm_enabled)}catch(e){console.error("加载推荐失败:",e)}},[]);(0,r.useEffect)(()=>{x()},[x]),(0,c.s)((0,r.useCallback)(()=>{x()},[x]));let m=null!==(e=null==t?void 0:t.recommendations)&&void 0!==e?e:[],h="all"===i?m:"buy"===i?m.filter(e=>"BUY"===e.signal):m.filter(e=>e.level===i);return(0,a.jsxs)("div",{className:"max-w-7xl mx-auto px-4 md:px-8 pt-6 pb-20 md:pb-10",children:[(0,a.jsx)("div",{className:"flex items-center justify-between mb-5 animate-fade-in-up",children:(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{className:"text-lg font-bold tracking-tight",children:"推荐列表"}),(0,a.jsxs)("p",{className:"text-xs text-text-muted mt-0.5",children:["共 ",(0,a.jsx)("span",{className:"font-mono tabular-nums",children:h.length})," 只"]})]})}),(0,a.jsx)("div",{className:"flex gap-2 mb-5 overflow-x-auto pb-1 animate-fade-in-up delay-75",children:[{key:"all",label:"全部"},{key:"buy",label:"买入信号"},{key:"强烈推荐",label:"强烈推荐"},{key:"推荐",label:"推荐"},{key:"观望",label:"观望"}].map(e=>{let{key:t,label:n}=e;return(0,a.jsx)("button",{onClick:()=>l(t),className:"text-xs px-4 py-1.5 rounded-xl whitespace-nowrap transition-all duration-200 font-medium ".concat(i===t?"bg-gradient-to-r from-amber-500/25 to-amber-600/20 text-amber-400 border border-amber-500/15":"bg-white/[0.03] text-text-muted hover:text-text-secondary hover:bg-white/[0.06] border border-transparent"),children:n},t)})}),0===h.length?(0,a.jsxs)("div",{className:"glass-card-static p-12 text-center animate-fade-in-up",children:[(0,a.jsxs)("div",{className:"text-text-muted text-sm mb-1",children:["暂无","all"===i?"":"符合条件的","推荐"]}),(0,a.jsx)("div",{className:"text-text-muted/50 text-xs",children:"尝试切换筛选条件或触发新的扫描"})]}):(0,a.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:h.map((e,t)=>(0,a.jsx)("div",{className:"animate-fade-in-up",style:{animationDelay:"".concat(60*t,"ms")},children:(0,a.jsx)(o.Z,{rec:e,showLLMLoading:d})},e.ts_code))})]})}},5229:function(e,t,n){"use strict";n.d(t,{Z:function(){return s}});var a=n(7437),r=n(3448);function s(e){let{rec:t,showLLMLoading:n=!1}=e,s=(0,r.ny)(t.level);return(0,a.jsxs)("a",{href:"/stock/".concat(t.ts_code),className:"block glass-card p-5 group",children:[(0,a.jsxs)("div",{className:"flex items-start justify-between mb-3",children:[(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{className:"flex items-center gap-2",children:[(0,a.jsx)("span",{className:"font-semibold text-sm tracking-tight",children:t.name}),(0,a.jsx)("span",{className:"text-xs px-2 py-0.5 rounded-full font-medium ".concat(s.bg," ").concat(s.text),children:t.level})]}),(0,a.jsxs)("div",{className:"text-xs text-text-muted mt-1 font-mono tabular-nums",children:[t.ts_code," ",(0,a.jsx)("span",{className:"text-text-muted/40 mx-1",children:"\xb7"})," ",t.sector]})]}),(0,a.jsxs)("div",{className:"text-right",children:[(0,a.jsx)("div",{className:"text-xl font-bold font-mono tabular-nums tracking-tight ".concat((0,r.Uz)(t.score)),children:t.score}),(0,a.jsx)("div",{className:"text-xs font-semibold tracking-wider ".concat((0,r.R8)(t.signal)),children:"BUY"===t.signal?"买入":"SELL"===t.signal?"卖出":"持有"})]})]}),(0,a.jsxs)("div",{className:"grid grid-cols-4 gap-2 mb-4",children:[(0,a.jsx)(o,{label:"市场",value:t.market_temp_score}),(0,a.jsx)(o,{label:"板块",value:t.sector_score}),(0,a.jsx)(o,{label:"资金",value:t.capital_score}),(0,a.jsx)(o,{label:"技术",value:t.technical_score})]}),t.entry_price&&(0,a.jsxs)("div",{className:"flex justify-between text-xs mb-3 bg-white/[0.03] rounded-xl px-4 py-2.5 border border-white/[0.04]",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("span",{className:"text-text-muted",children:"买入 "}),(0,a.jsx)("span",{className:"text-red-400 font-mono tabular-nums",children:t.entry_price})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("span",{className:"text-text-muted",children:"目标 "}),(0,a.jsx)("span",{className:"text-amber-400 font-mono tabular-nums",children:t.target_price})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("span",{className:"text-text-muted",children:"止损 "}),(0,a.jsx)("span",{className:"text-emerald-400 font-mono tabular-nums",children:t.stop_loss})]})]}),(0,a.jsx)("div",{className:"space-y-1.5",children:t.reasons.map((e,t)=>(0,a.jsxs)("div",{className:"text-xs text-text-secondary flex items-start gap-2",children:[(0,a.jsx)("span",{className:"w-1 h-1 rounded-full bg-amber-500/60 mt-[7px] shrink-0"}),(0,a.jsx)("span",{className:"leading-relaxed",children:e})]},t))}),t.llm_analysis?(0,a.jsxs)("div",{className:"mt-3 bg-accent-cyan/[0.06] border border-accent-cyan/[0.12] rounded-xl px-4 py-3",children:[(0,a.jsx)("div",{className:"text-xs text-accent-cyan/80 font-semibold tracking-wider mb-1.5",children:"AI 分析"}),(0,a.jsx)("div",{className:"text-xs text-text-secondary leading-relaxed",children:t.llm_analysis})]}):n?(0,a.jsxs)("div",{className:"mt-3 text-xs text-text-muted flex items-center gap-2",children:[(0,a.jsx)("span",{className:"inline-block w-3 h-3 border border-accent-cyan/30 border-t-accent-cyan/80 rounded-full animate-spin"}),"AI 分析中..."]}):null,t.risk_note&&(0,a.jsx)("div",{className:"mt-3 text-xs text-amber-500/60 bg-amber-500/[0.04] border border-amber-500/[0.08] rounded-lg px-3 py-1.5",children:t.risk_note}),(0,a.jsxs)("div",{className:"mt-3 flex items-center gap-1 text-xs text-text-muted opacity-0 group-hover:opacity-100 transition-opacity duration-300",children:[(0,a.jsx)("span",{children:"查看详情"}),(0,a.jsx)("svg",{width:"10",height:"10",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:(0,a.jsx)("path",{d:"M5 12h14M12 5l7 7-7 7"})})]})]})}function o(e){let{label:t,value:n}=e;return(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{className:"flex justify-between text-xs text-text-muted mb-1",children:[(0,a.jsx)("span",{className:"font-medium",children:t}),(0,a.jsx)("span",{className:"font-mono tabular-nums",children:n.toFixed(0)})]}),(0,a.jsx)("div",{className:"h-1.5 bg-white/[0.04] rounded-full overflow-hidden",children:(0,a.jsx)("div",{className:"h-full rounded-full transition-all duration-700 ease-out ".concat(n>=70?"score-bar-gradient-high":n>=50?"score-bar-gradient-mid":"score-bar-gradient-low"),style:{width:"".concat(Math.min(n,100),"%")}})})]})}},6140:function(e,t,n){"use strict";n.d(t,{s:function(){return r}});var a=n(2265);function r(e){let[t,n]=(0,a.useState)(!1),r=(0,a.useRef)(null),s=(0,a.useRef)(),o=(0,a.useCallback)(()=>{let t="https:"===window.location.protocol?"wss:":"ws:",a=new WebSocket("".concat(t,"//").concat(window.location.host,"/ws"));a.onopen=()=>{n(!0);let e=setInterval(()=>{a.readyState===WebSocket.OPEN&&a.send("ping")},3e4);a.addEventListener("close",()=>clearInterval(e))},a.onmessage=t=>{if("pong"!==t.data)try{let n=JSON.parse(t.data);null==e||e(n)}catch(e){}},a.onclose=()=>{n(!1),s.current=setTimeout(o,5e3)},a.onerror=()=>a.close(),r.current=a},[e]);return(0,a.useEffect)(()=>(o(),()=>{var e;clearTimeout(s.current),null===(e=r.current)||void 0===e||e.close()}),[o]),{connected:t}}},1837:function(e,t,n){"use strict";function a(){return localStorage.getItem("auth_token")}function r(){localStorage.removeItem("auth_token"),localStorage.removeItem("auth_user"),window.location.href="/login"}async function s(e){let t=a(),n={};t&&(n.Authorization="Bearer ".concat(t));let s=await fetch("".concat("").concat(e),{headers:n});if(401===s.status)throw r(),Error("Unauthorized");if(!s.ok)throw Error("API error: ".concat(s.status));return s.json()}async function o(e,t){let n=a(),s={"Content-Type":"application/json"};n&&(s.Authorization="Bearer ".concat(n));let o=await fetch("".concat("").concat(e),{method:"POST",headers:s,body:t?JSON.stringify(t):void 0});if(401===o.status)throw r(),Error("Unauthorized");if(!o.ok)throw Error("API error: ".concat(o.status));return o.json()}async function c(e){let t=a(),n={};t&&(n.Authorization="Bearer ".concat(t));let s=await fetch("".concat("").concat(e),{method:"DELETE",headers:n});if(401===s.status)throw r(),Error("Unauthorized");if(!s.ok)throw Error((await s.json().catch(()=>({}))).detail||"API error: ".concat(s.status));return s.json()}async function*i(e){let t=a(),n={"Content-Type":"application/json"};t&&(n.Authorization="Bearer ".concat(t));let s=await fetch("".concat("","/api/chat/stream"),{method:"POST",headers:n,body:JSON.stringify({messages:e})});if(401===s.status)throw r(),Error("Unauthorized");if(!s.ok)throw Error("Chat API error: ".concat(s.status));if(!s.body)throw Error("No response body");let o=s.body.getReader(),c=new TextDecoder,i="";for(;;){let{done:e,value:t}=await o.read();if(e)break;let n=(i+=c.decode(t,{stream:!0})).split("\n");for(let e of(i=n.pop()||"",n))if(e.startsWith("data: ")){let t=e.slice(6).trim();if("[DONE]"===t)return;try{let e=JSON.parse(t);yield e}catch(e){}}}}async function l(e,t){let n=await fetch("".concat("","/api/auth/login"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:e,password:t})});if(!n.ok)throw Error((await n.json().catch(()=>({}))).detail||"Login failed: ".concat(n.status));return n.json()}async function d(){return s("/api/auth/users")}async function u(e,t){return o("/api/auth/users",{username:e,role:t})}async function x(e){return c("/api/auth/users/".concat(e))}async function m(e){return o("/api/auth/users/".concat(e,"/reset-password"))}async function h(e,t){return o("/api/auth/change-password",{old_password:e,new_password:t})}n.d(t,{Io:function(){return s},Pj:function(){return u},UO:function(){return l},Ul:function(){return h},fK:function(){return x},jK:function(){return d},l8:function(){return o},oQ:function(){return m},ov:function(){return i}})},3448:function(e,t,n){"use strict";function a(e){return Math.abs(e)>=1e4?(e/1e4).toFixed(2)+"亿":Math.abs(e)>=1?e.toFixed(2)+"万":e.toFixed(2)}function r(e){return e>=80?"text-red-400":e>=60?"text-orange-400":e>=40?"text-yellow-400":"text-gray-400"}function s(e){switch(e){case"强烈推荐":return{bg:"bg-red-500/20",text:"text-red-400"};case"推荐":return{bg:"bg-orange-500/20",text:"text-orange-400"};case"观望":return{bg:"bg-yellow-500/20",text:"text-yellow-400"};default:return{bg:"bg-gray-500/20",text:"text-gray-400"}}}function o(e){return"BUY"===e?"text-red-400":"SELL"===e?"text-green-400":"text-gray-400"}function c(e){return e>=70?"#ff6b6b":e>=50?"#f59e0b":e>=30?"#fbbf24":"#34d399"}function i(e){return e>=70?"火热":e>=50?"温和":e>=30?"偏冷":"冰点"}n.d(t,{R8:function(){return o},Uz:function(){return r},Zd:function(){return i},jD:function(){return c},ny:function(){return s},uf:function(){return a}})}},function(e){e.O(0,[971,117,744],function(){return e(e.s=4895)}),_N_E=e.O()}]);