From 3ab59fe79c3bb43658c21c3486101cec9a83a14b Mon Sep 17 00:00:00 2001 From: Doghole Date: Thu, 22 May 2025 00:27:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E7=9A=84=EF=BC=8C?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/extra/indexJs.js | 1 + .../rich/emoney/client/WebviewClient.java | 177 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 conf/extra/indexJs.js create mode 100644 src/main/java/quant/rich/emoney/client/WebviewClient.java diff --git a/conf/extra/indexJs.js b/conf/extra/indexJs.js new file mode 100644 index 0000000..9764f3e --- /dev/null +++ b/conf/extra/indexJs.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[167],{1296:function(n,e,t){var content=t(2170);"string"==typeof content&&(content=[[n.i,content,""]]),content.locals&&(n.exports=content.locals);(0,t(23).default)("52fd4ff2",content,!0,{sourceMap:!1})},2169:function(n,e,t){"use strict";var r=t(1296);t.n(r).a},2170:function(n,e,t){(n.exports=t(22)(!1)).push([n.i,".swiper-slide{min-height:21.84533rem}.swiper-pagination{position:fixed;bottom:0;width:100%}.swiper-pagination .swiper-pagination-bullet{margin:0 0.10667rem}.swiper-pagination .swiper-pagination-bullet-active{background-color:red}.text-detail{padding-bottom:0.42667rem}.swiper-item{padding:0 0.64rem 0.64rem 0.64rem}.swiper-item .title{min-height:1.96267rem;line-height:1.96267rem}.swiper-item .border1{height:1px}.swiper-item .text{padding-left:0.64rem}.swiper-item .text li{padding-left:0;color:red}.swiper-item .images{width:95%;margin:0.64rem auto;display:block}.theme-landscape .swiper-slide{min-height:auto}",""])},2466:function(n,e,t){"use strict";t.r(e);t(26),t(52),t(578);var r=[{id:1,data:[{title:"操盘线周期选择原则",items:["中短线趋势:看日线,买卖操作看60或30分钟线B、S买卖点","中长线趋势:看周线,买卖操作看日线B、S买卖点。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/操盘线_周期选择原则说明.png"},{title:"BS点解说",items:["个股发出B(买)点,表示个股走势有望向好,可能出现投资机会;个股发出S点(卖)点,表示个股走势有向坏迹象,需要注意风险防范。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/操盘线_BS点说明.png?v=1"},{title:"大盘BS点",items:["大盘出B(买)点,表示大盘走势向好,此时要结合板块B(买)点和个股B(买)点找出热点板块中的热点个股。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/操盘线_大盘BS点说明.png"},{title:"板块BS点",items:["在大盘出买点后,在板块中寻找比大盘更早出买点的板块,再结合该板块中的个股出B点的股票,找出热点股。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/操盘线_板块BS点说明.png"}],name:"CPX",nameCode:"10002800"},{id:2,data:[{title:"OBV指标说明",items:["OBV指标简介OBV指标又叫能量潮指标,由OBV值和OBV线构成的,通过统计成交量变动的趋势来推测股价趋势。","当OBV线下降而股价却上升,预示股票上升能量不足,股价可能随时下跌,是卖出股票的信号。当OBV线上升而股价却小幅下跌,说明市场上人气旺盛,下档承接力较强,股价的下跌只是暂时的技术性回调,股价可能即将止跌回升。","当OBV线呈缓慢上升而股价也同步上涨时,表示行情稳步向上,股市中长期投资形势尚好,股价仍有上升空间。","当OBV线呈缓慢下降而股价也同步下跌时,表示行情逐步盘跌,股市中长期投资形势不佳,股价仍有下跌空间。","当OBV线出现急速上升的现象时,表明市场上大部分买盘已全力涌进,而买方的能量的爆发不可能持续太久,行情可能将会出现回档,应考虑逢高卖出。","当OBV线出现急速下跌的现象时,表明市场上大量卖盘汹涌而出,股市行情已经转为跌势,行价将进入一段较长时期的下跌过程中。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/OBV指标.png"}],name:"OBV",nameCode:"10009000"},{id:3,data:[{title:"ASI指标说明",items:["ASI简介ASI(振动升降指标),ASI指标以开盘、最高、最低、收盘价与前一交易日的各种价格相比较作为计算因子,研判市场的方向性。","ASI走势几乎和股价是同步发展,当股价由下往上,欲穿过前一波的高点套牢区时,于接近高点处,尚未确定能否顺利穿越之际。如果ASI领先股价,提早一步,通过相对股价的前一波ASI高点,则次一日之后,可以确定股价必然能顺利突破高点套牢区。","股价由上往下,欲穿越前一波低点的密集支撑区时,于接近低点处,尚未确定是否将因失去信心,而跌破支撑之际。如果ASI领先股价,提早一步,跌破相对股价的前一波ASI低点,则次一日之后,可以确定股价将随后跌破低点支撑区。","向上爬升的ASI,一旦向下跌破其前一次显著的N型转折点,一律可视为停损卖出的讯号。","股价走势一波比一波高,而ASI却未相对创新高点形成“牛背离”时,应卖出。","股价走势一波比一波低,而ASI却未相对创新低点形成“熊背离”时,应买进。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/ASI指标.png"}],name:"ASI",nameCode:"10009100"},{id:4,data:[{title:"FSL指标说明",items:["FSL指标简介FSL(分水岭)指标是一个强弱势的分界线。","股价在分水岭之上为强势,反之为弱势。","当股价从上方向下,在分水岭上方获得支撑,同时分水岭向上运行,说明股价受到支撑,可考虑建仓;当股价从下方向上,在分水岭遇阻回落,同时分水岭向下运行,说明股价受压,此时应卖出股票,防范风险。这种方法同样可以应用于对大盘的分析。","分水岭向下且股价由下向上突破分水岭时,说明此股票在由弱变强,可以考虑建仓。","分水岭向上且股价由上向下跌破分水岭时,说明此股票在由强变弱,要及时止损。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/FSL指标.png"}],name:"FSL",nameCode:"10009700"},{id:5,data:[{title:"SLOWKD指标说明",items:["
算法: 先求未成熟随机值RSV
RSV =(收盘价-N日来最低价)/(N日来最高价-最低价)×100
FASTK线:RSV的M1日均线。
K线:FASTK的M2日均线。
D线:K线的M3日均线。
参数:N、M1、M2、M3天数,一般为9、3、3、5。
"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/SLOWKD指标.png"}]},{id:6,data:[{title:"资金博弈指标说明",items:["资金博弈简介资金博弈指标统计各类资金累计的成交量并与流通盘做比较,近似估算各类资金总体的控盘力度。","根据逐单成交数据将资金划分为散户、中户、大户、超级大户四类,由于买入量等于卖出量,故四条指标线的数值相加为0。","散户、中户、大户、超级大户四类资金的情况与绿/蓝/黄/紫4条指标线一一对应。散户资金:当前的散户资金控盘力度。","中户资金:当前的中户资金控盘力度。大户资金:当前的大户资金控盘力度。超级资金:当前的超级大户资金控盘力度。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/资金博弈指标.png"}],name:"资金博弈",nameCode:"10006200"},{id:7,data:[{title:"筹码聚散指标说明",items:["筹码聚散简介筹码聚散是依据每日卖出单数和买入单数差的累计值(估计值)估算个股筹码的聚散情况,聚散方向是单数差的10日平滑累加均值。","红色,单数差为正值,大单买入较多;绿色,单数差为负值,大单卖出较多。","反映筹码的收集和发散过程,持续向上表示筹码在向少数人转移,是收集过程;股价向上聚散方向向下,表明散户或游资在追涨,股价持续性不强。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/筹码聚散指标.png"}],name:"筹码聚散",nameCode:"10006500"},{id:8,data:[{title:"超级资金指标说明",items:["超级资金简介超级资金里的超户值也是占流通盘的百分比,它表示的是当天的情况,以柱状表示红柱为正,绿柱为负;

“累计”上穿“均值”超级资金在建仓

“累计”下破“均值”超级资金在出货

“累计”在“零轴”之上,市场为强势,可重仓参与

“累计”在“零轴”之下,市场为弱势,规避风险练习"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/超级资金指标.png"}],name:"超级资金",nameCode:"10006600"},{id:9,data:[{title:"大户资金指标说明",items:["大户资金含义:体现了大户当日的净买卖方向,红柱为净买入,绿柱为净卖出,数值为当日净量占流通盘的百分比。","用法:黄线上穿黑线表示大户资金有介入,反之则是出逃。大户资金进出往往反映了市场游资的动向。","打开方式:
1. K线/操盘线界面“选指标”—选择指标
2. 在滑动区选择相应指标"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/大户资金指标.png"}],name:"大户资金",nameCode:"10006700"},{id:10,data:[{title:"散户资金指标说明",items:["散户:资金少,小量买卖股票的普通投资者。","散户线上升,筹码分散,散户线上升幅度加快,资金离场,容易演变为散户主导性行情。","散户线下降,筹码集中,主力持股数上升幅度加快,主力引导性大行情往往产生。","如散户线由升开始转降,通常说明主力开始进场收集廉价筹码,大盘可能转好。","散户线持续下降,股价也不涨,表明主力在压低建仓。","散户线持续下降后突然再次加速下坠,股价却小幅走高后横盘不涨,说明主力洗盘将结束,可能步入拉升阶段。","散户线持续下降,股价反而走低,表明主力在悄然接盘。","散户线上升幅度开始加快,股价也上涨,说明主力在拉高派发手中的筹码。","散户线持续上升,如股价下跌,通常说明主力正在快速派发手中的筹码,出货坚决。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/散户资金指标.png"}],name:"散户资金",nameCode:"10006800"},{id:11,data:[{title:"趋势顶底指标说明",items:["趋势顶底简介长、中、短期趋势显示,便于用户明确股价当前走势的状况。","顶部的红色区域和底部的蓝绿色区域用于用户识别股价走势的高低和超买超卖情况。","最底部的绿色方块显示阶段性底部,出现的红点意味短线抄底信号;而顶部的红色方框表示阶段性头部区域提示用户要谨慎。","使用时以黄色的中期趋势线为主要的判断依据,结合灰色短期线和红色长期线把握买卖点,当长期趋势线向上时尽量选择短期线回调时进场,反之要注意高抛止盈止损。"],image:"https://appstatic.emoney.cn/html/imgs/stock/note/趋势顶底指标.png"}],name:"趋势顶底",nameCode:"10003200"},{id:12,data:[{title:"融资融券",items:["“融资融券”又称“证券信用交易”,包括券商对投资者的融资、融券和金融机构对券商的融资、融券。","融资是借钱买证券,证券公司借款给客户购买证券,客户到期偿还本息,客户向证券公司融资买进证券称为“买空”;","融券是借证券来卖,然后以证券归还,证券公司出借证券给客户出售,客户到期返还相同种类和数量的证券并支付利息,客户向证券公司融券卖出称为“卖空”。","融资余额:每天融资买进股票额与偿还融资额间的差额","融券余额:每天融券卖出股票额与偿还融券间的差额","融资余额增加时,表示投资者心态偏向买方,市场人气旺盛,属强势市场;反之则属于弱势市场。","融券余额增加,表示市场趋向卖方市场;反之则趋向买方。"]}],name:"融资融券",nameCode:"10010100"},{id:13,data:[{title:"主力进出:",items:["1. 若多方主力向上穿越空方主力,则为买入信号。","2. 若多方主力向下击破空方主力,则为卖出信号。"]}],name:"ZLJC",nameCode:"10007700"},{id:14,data:[{title:"龙腾活跃:",items:["1. 海面线:股价走势趋向上趋于平淡和活跃变化的分水岭;","2. 龙腾活跃处于海面线以下,走势表现处于相对平淡和疲弱,为不活跃状态;","3. 龙腾活跃处于海面线上方,形态上趋向活跃,股价相对有望出现上涨走势,位置越高也就相对越活跃;","4. 龙腾活跃线上穿海面线,走势形态上开始呈现活跃变化,可以顺势把握个股的潜在上涨机会;"]}],name:"龙腾活跃",nameCode:"10003001"},{id:15,data:[{title:"深跌:",items:["深跌指标,主要体现股价形态上是否具备阶段性的超跌和处于相对的低位。指标主要由阶段下跌指标线,以及浅色、蓝色、深蓝色背景区域组成。","阶段下跌指标线:体现阶段性下跌空间,和形态上相对回弹的对比,方向向下表明整体处于下跌趋向,反之表明整体处于回升或上涨趋向。","当指标线向下进入到浅色背景区域,意味着走势形态上具备阶段性深跌,存在技术性反弹预期和可能。","当指标线向下进入到蓝色背景区域,意味着阶段性超跌,反弹预期可能性明显。","当指标线向下进入到深蓝色背景区域,意味着形态上具备阶段性严重超跌,底部反弹预期更强。"]}],name:"深跌",nameCode:"10003300"},{id:16,data:[{title:"强势区间:",items:["强势区间指标,是龙腾四海指标的另一种指标呈现方式。","强势区间指标,以黄颜色背景区域和红色背景区域,突出体现技术上形态上的强度。","当龙腾四海线由下往上,进入到黄色背景区域,为技术上进入相对活跃和形态转强,股价相对更易出现上涨。","当龙腾四海线由下往上,进入到红色背景区域,为技术上进入强势格局,股价容易出现短期强势上涨或加速。"]}],name:"强势区间",nameCode:"10003400"},{id:17,data:[{title:"买卖频谱:",items:["白线为买线,黄线为卖线。","当白线向上穿越黄线为买入信号,此时柱差显示为红色系频谱。","当白线向下击穿黄线为卖出信号,此时柱差显示威绿色系频谱。","红色系频谱展开越充分,上升力度越强。","绿色系频谱展开越充分,下跌力度越强。"]}],name:"买卖频谱",nameCode:"10003500"},{id:18,data:[{title:"北上资金买卖净额:",items:["根据港交所数据深度计算的每日净流入、净流出。数据单位为万元。"]}],name:"北上资金买卖净额",nameCode:"10006900"},{id:19,data:[{title:"北上资金持股占比:",items:["港资所持股票数量占流通A股的比例。"]}],name:"北上资金持股占比",nameCode:"10007000"},{id:21,data:[{title:"量王叠现:",items:["量王叠现指标是基于量能变化统计编制而成,一般适用于日线周期。","该指标将量能情况标识为三种状态:","1.普通量能","2.条纹红柱代表阶段性量能较强劲","3.紫色柱状代表当日放量至少为昨日一倍以上","该指标可搭配其他指标使用以作为量能方面的考量依据,例如红柱状态下发出B点等等"]}],name:"量王叠现",nameCode:"10003600"},{id:22,data:[{title:"黄金回踩:",items:["顺势而为,伏击个股主升浪","当黄金眼信号触发后,以股价作为主线,股价回调并触碰MA30均线,并之后股价重新站回MA30均线,并且整个过程MA5和MA10任意一条都不能死叉MA30,即触发黄金眼回踩,不然就是黄金眼破坏。","二买点:黄金眼回踩触发后,之后黄金眼未被破坏,股价由S点转为B点,B点即为第二买点。(股价回调出S点,暂时先出场,等黄金眼回踩并转为B点)","加仓:黄金回踩触发后,股价一直处于红色持股状态,后续再出回踩信号,即为加仓点。","卖出:操盘线S点出发必须先行卖出,且是最后的卖点,随后等待再次买入信号。","无效回踩:股价出发黄金眼后出现回调,股价未能触碰到30日均线,即为黄金眼无效回踩。","有效回踩后被破坏:股价回调后并触碰MA30均线之后,股价又会到MA30均线之上,即形成黄金眼有效回踩,但之后MA5或MA10任意一条死叉MA30,即黄金眼破坏。即使之后股价再回到MA30之上,也定义为黄金眼破坏。(盘后确认)","优先交易环境: ","30日均线上行个股优先:黄金眼出发回踩后30日均线上行股票优先。","绩优股优先:业绩有保证、前景看好的股票出现黄金眼后优先考虑。","次新股优先:上市后爆炒回落首次出现符合条件的黄金眼回踩的个股优先考虑。","多重信号优先:近期频繁出现黄金眼回踩,且后一个黄金眼回踩高于前一个黄金眼回踩的股票可优先考虑。","避免交易环境:","1. 避免年度已出现大幅上涨且已在高位的股票,出现翻倍行情的个股更高谨慎对待,避免高位站岗。","2. 避免长期走势横盘整理的个股,该类个股因为区间窄幅波动,信号同样频繁,特点是信号发出后都没有收益,且在高点。","3. 仙股、超级低价股、退市警示股以及基本面不佳的个股要规避。"]}],name:"黄金回踩",nameCode:"10003700"},{id:23,data:[{title:"伏击活跃股:",items:["强势活跃表现,伏击短期回落,顺势短期价差。","1. 成交量集中放量(大资金青睐)","2. 换手率高(股性活跃)","3. 对比大盘指数来看,股价的波动性大(股性活跃)","4. 大单比率高,资金流向呈上升趋势(主力正在介入)"]}],name:"伏击活跃股",nameCode:"10003900"},{id:24,data:[{title:"冰火两重天:",items:["1. 暖色系图谱为多头控制区域,冷色系为空头控制区域。","2. 若股价创新高而该指标不同步创新高,则产生顶背离,表明股价上涨乏力,随时准备卖出,此时最好结合60分钟操盘线卖出,以获得最大利润。","3. 若股价创新低而该指标不同步创新低,则产生底背离,表明股价下跌开始缺乏动力,随时准备介入,此时若日线操盘线发出买入信号,则介入的安全系数会比较大。"]}]},{id:25,data:[{title:"成本均线:",items:["成本均线在计算中考虑了成交量的作用,可以近似真实的反映市场的平均持股成本。该指标分5日、13日、34日及∞(无穷)四条线,前三条线为市场交易中最近该日内买入股票者的平均建仓成本,∞线则是所有持筹者的平均建仓成本。短期成本均线在上,长期成本均线在下称多头排列,反之为空头排列;成本均线的多头及空头排列都相当稳定。","成本均线中最重要的一条是∞成本均线,它是市场牛熊的重要分水岭,股价在此之上往往是牛市;在此之下市场可能步入熊市,∞成本均线的支撑和压力作用很显著。"]}]},{id:26,data:[{title:"波段无敌:",items:["1. 取值范围:-50~+50。","2. 0轴以下为空方优势区域,0轴以上为多头优势区。","3. 若BD值等于-50且横盘,坚决持币观望。","4. 若BD值等于+50且横盘,坚决持股待涨,且往往会涨势加速。","5. 股价回调不破+30,继续持股待涨,属于正常调整。"]}],name:"BDWD",nameCode:"10009900"},{id:27,data:[{title:"锅底右侧:",items:["技术上下跌充分,经历阶段性筑底后,股价回升上涨,股价有望进入右侧反弹上涨趋向"]}],name:"锅底右侧",nameCode:"10004000"},{id:28,data:[{title:"大阳起势:",items:["经历过阶段性上涨,技术上已脱离底部,股价经过短期震荡休整后,中大阳线强势上涨,逾越休整形态或重要均线位置"]}],name:"大阳起势",nameCode:"10004100"},{id:29,data:[{title:"主题博弈-锅底精选:",items:["《主题博弈-锅底精选》指标是一套发现底部信号的操作指标。分为偏左侧的“拐点”信号与右侧的“锅底”信号。具体用法参考主题博弈相关教程。"]}],name:"锅底精选",nameCode:"10005301"},{id:30,data:[{title:"蓄势盘龙-盘龙活跃区2.0:",items:["【盘龙活跃区2.0】是一套捕捉个股右侧主升浪操作指标,具体用法参考蓄势盘龙高级课教程。"]}],name:"盘龙活跃区2.0",nameCode:"10005400"},{id:31,data:[{title:"量王精选:",items:["红色实心柱子是量王,黄色实心柱子是天量;量王出现说明近阶段的量能达到了一定的程度,呈现交易相对活跃状态。具体用法参考量王精选相关教程。"]}],name:"量王精选",nameCode:"10005500"},{id:32,data:[{title:"龙腾长波指标说明:",items:["趋势性上涨形态,股价出现阶段性震荡休整或调整,而后再次起涨走强"]}],name:"龙腾长波",nameCode:"10004200"},{id:33,data:[{title:"CMFX指标说明:",items:["筹码分析:分析市场筹码流动情况,掌握多空对战实力。","1.白线代表市场锁定筹码,多为主力控盘筹码,数值越大说明主力控盘锁定筹码越多,上涨概率越大。","2.黄线代表市场浮动筹码,多为散户流动筹码,数值越大说明散户持有浮动筹码越多,下跌概率越大。","3.柱差反映市场筹码控盘能力,反映主力控盘力度,预示后市上扬概率及幅度,红柱越大,说明主力控盘度越高,上涨概率越高,反之则下跌概率越高。"]}],name:"CMFX",nameCode:"10010200"},{id:34,data:[{title:"冰谷火焰指标说明:",items:["股价经历中长期的充分下跌,K线形态上止跌回升或尖冲下影,有阶段性左侧止跌迹象,有望逐步进入筑底或底部回升。"]}],name:"冰谷火焰",nameCode:"10004300"},{id:35,data:[{title:"资金潜龙指标说明:",items:["前期历经阶段性的下跌,技术上相对低位,阶段内大单流入偏多或资金做多回流行为迹象。"]}],name:"资金潜龙",nameCode:"10004400"},{id:36,data:[{title:"【均线三部曲--中期四线】指标:",items:["水平虚线-对应上方白色数字:为均线粘合度的参考值,主要用来衡量粘合程度是否达4线参考数值1.05;
\n绿色柱状-对应上方绿色数字4线粘合:表示4条均线粘合程度,当4线粘合值<1.05时,会显示绿色柱状,上方绿色数值越小,说明4条均线越粘合;
\n黄色柱状-对应上方黄色数字:表示4条均线方向一致向上,上方黄色数值,表示第几天出现共振;
\n红色柱状-对应上方红色数字:表示4条均线从小到大依次排列,上方红色数值,表示第几天出现多头;
\nPS:4线-MA 参数为5、10、20、60,柱子在水平虚线上下可以不用过多关注,主要关注颜色。"]}],name:"均线三部曲-中期四线",nameCode:"10005700"},{id:37,data:[{title:"黄金通道:",items:["该指标仅适用于60分钟周期,适用于强势个股的交易辅助,具体详见高级课内容。"]}],name:"黄金通道",nameCode:"10005800"},{id:38,data:[{title:"黄金通道强弱区:",items:["该指标仅适用于60分钟周期,辅助判断短周期股价运行区间的强弱度,具体详见高级课内容。"]}],name:"黄金通道强弱区",nameCode:"10000800"},{id:39,data:[{title:"蹦极新生:",items:["阶段性上涨趋势,股价出现短期快速回调,趋势顶底短期线异动下探,而后股价回升上涨。","股价有短期洗盘休整后再度上涨的迹象"]}],name:"蹦极新生",nameCode:"10003800"},{id:40,data:[{title:"夏普率:",items:["夏普率是指基金近一年的风险收益比。夏普率越大越好。","同类均值是指该基金所属的益盟基金一级分类中所有基金的近一年夏普率均值"]}],name:"夏普率",nameCode:"10001200"},{id:41,data:[{title:"PE:",items:["PE估值是指市盈率,指持仓股票价格除以每股收益(每股收益,EPS)的比率。","PE百分位是指该估值所处的历史分位数。","注:当估值不在合理范围时,在图形中我们会将值调整到合理范围内。如,当PE为负时,其百分位我们定义为100%,即处于高估。"]}],name:"PE",nameCode:"10001600"},{id:42,data:[{title:"PB:",items:["PB估值是指市净率,指持仓股票价格除以每股净资产的比率。","PB分位是指该估值所处的历史分位数。","注:当估值不在合理范围时,在图形中我们会将值调整到合理范围内。如,当PB为负时,其百分位我们定义为100%,即处于高估。"]}],name:"PB",nameCode:"10001500"},{id:43,data:[{title:"基金份额:",items:["是指向投入者公开发行的,表示持有人按其所持份额对基金财产享有收益分配权、清算后剩余财产取得权和其他相关权利,并承担相应义务的凭证。"]}],name:"基金份额",nameCode:"10001300"},{id:44,data:[{title:"龙行趋势线:",items:["《龙行趋势线》指标用图形和数值体现长期和短期两个级别的趋势变化,红绿柱状描述长期趋势变化,红绿带状描述短期趋势变化","多空:正值代表当前为多头环境,负值代表当前为空头环境;","空间:当前价格对比历史最高价格的比值;","长多:长期多头趋势维持的天数;","长空:长期空头趋势维持的天数;","短多:短期多头趋势维持的天数;","短空:短期空头趋势维持的天数;"]}],name:"龙行趋势线",nameCode:"10006000"},{id:45,data:[{title:"基金操盘线:",items:["基金操盘线是一款可以识别趋势的指标。","操作原则:B点买入,S点卖出;红色持有标的,蓝色抛出标的。","趋势分为上涨趋势和下跌趋势,由于是趋势指标所以只在趋势明朗后才会出现B点买入信号或者S点卖出信号,一般不会在拐点位置出现信号,因此B点不是最早的买入点,S点是最后的卖出点。"]}],name:"FUNDCPX",nameCode:"10002700"},{id:46,data:[{title:"DKBY指标说明:",items:["多空博弈","1.当“多方”线向上与“空方”线“金叉”时为买点。","2.当“多方”线向下与“空方”线“死叉”时为卖点。"]}],name:"DKBY",nameCode:"10008500"},{id:47,data:[{title:"龙抬头指标说明:",items:["符合蓄势盘龙形态,并且当前资金活跃,处于右侧拐头、安全入口的个股,具体用法详见蓄势盘龙高级课,建议结合指数及风口节奏进行使用。"]}],name:"龙抬头",nameCode:"10006100"},{id:48,data:[{title:"动态估值指标用法:",items:["基于对未来业绩预测的动态估值,与公司实际市值对比,计算出估值状态。","用法:","1、公司实际市值/动态估值<0.8,为机会区间;","2、公司实际市值/动态估值>1.25,为预警区间;","3、0.8<=公司实际市值/动态估值<=1.25,为观察区间。"]}],name:"动态估值",nameCode:"10001700"},{id:49,data:[{title:"解套空间:",items:["体现了机构持股成本与当前股价的差距。解套空间为绿色时,表示机构持股成本高于当前股价,值越大表示机构被套程度越深;解套空间为红色时,表示机构持股成本低于当前股价,值越大表示机构获利比例越高;解套空间为黄色时,表示机构没有被套也没有获利;如果解套空间为黄色且在零轴持续一段时间,说明在此时间段内没有机构的持股数据。","注:机构包括公募基金、国家队、QFII和知名私募四类机构。","机构持股成本由算法模型估算得出,仅供参考。"]}],name:"解套空间",nameCode:"10001800"},{id:50,data:[{title:"机构认可度(个股):",items:["指基金公司,国家队,QFII和知名私募四类机构持有该股的流通市值占总市值的比例。该指标指按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露延续上一报告期指标值或数据未披露完整采用已披露数据计算指标值。"]}],name:"机构认可度(个股)",nameCode:"10001900"},{id:51,data:[{title:"机构参与度 (个股):",items:["指持有该股占总股本比例超过0.01%的基金、国家队、QFII和知名私募四类机构的机构家数。该指标按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露,延续上一报告期指标数据或数据未披露完整,采用已披露数据计算指标值。"]}],name:"机构参与度(个股)",nameCode:"10002000"},{id:52,data:[{title:"机构认可度(板块):",items:["指基金公司,国家队,QFII和知名私募四类机构持有该板块的流通市值占板块总市值的比例。该指标值按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露完整,延续上一报告期指标值。"]}],name:"机构认可度(板块)",nameCode:"10002200"},{id:53,data:[{title:"机构持股覆盖率:",items:["指基金公司,国家队,QFII和知名私募四类机构所持有该板块成分股家数除以该板块成分股总家数。该指标值按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露完整,延续上一报告期指标值。"]}],name:"机构持股覆盖率",nameCode:"10002300"},{id:54,data:[{title:"机构参与度 (板块):",items:["指基金公司,国家队,QFII和知名私募四类机构持有该板块成分股的机构家数。该指标值按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露完整,延续上一报告期指标值。"]}],name:"机构参与度(板块)",nameCode:"10002400"},{id:55,data:[{title:"机构持股市值:",items:["指报告期期末基金公司,国家队,QFII和知名私募这四类机构所持有的该板块流通市值。该指标值按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露完整,延续上一报告期指标值。"]}],name:"机构持股市值",nameCode:"10002500"},{id:56,data:[{title:"机构配置度:",items:["指基金公司,国家队,QFII和知名私募这些四类机构合计持有某个板块流通股市值占该板块总份额市值的比例。该指标值按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露完整,延续上一报告期指标值。"]}],name:"机构配置度",nameCode:"10002600"},{id:57,data:[{title:"活跃机构增减仓:",items:["指基金公司,国家队,QFII和知名私募四类机构累计增减仓的情况。指标柱为红色时,数字为正,代表该报告期内机构增仓,红柱越高代表增仓幅度越大;指标柱为绿色时,数字为负,代表该报告期内机构减仓,绿柱越高代表减仓幅度越大。","该指标指按报告期更新,实线表示该报告期数据已披露完整,虚线表示该报告期数据尚未披露延续上一报告期指标值或数据未披露完整采用已披露数据计算指标值。"]}],name:"活跃机构增减仓",nameCode:"10002100"},{data:[{title:"DDI:",items:["分析DDI柱状线,由红变绿(正变负),卖出信号;由绿变红,买入信号。"]}],name:"DDI",nameCode:"10008600"},{data:[{title:"强势风口指标说明:",items:["强势风口由三线强势,强风口、火线题材三大条件组成,旨在帮助用户发现超强风口,叠加强势周期和强势股要素共同使用,可提升操作胜率。","1、三线强势,利用不同周期的共振,挖掘强势板块,入选后显示空心黄色方格","2、强风口,近15个交易日内入选风口全景/风口主线的题材,入选后显示蓝色风口图标","3、火线题材,近15个交易日内入选火线题材的概念,入选后显示红色火苗","4、三线强势+强风口+火线题材三个指标信号共同出现的时候,显示红色背景,代表入选三个风口,属于强势风口。"]}],name:"强势风口",nameCode:"10004900"},{data:[{title:"黄金坑指标说明:",items:["深度,图中金黄色区域,表明股票跌幅深度,深度越大,反弹力度会越大。","估值,即估值星级,黄色上方的橙色部分,越大表示估值相对越低。","弹性,橘红色部分,弹性越大,随市场反弹速度越快。","纯度,大红色部分,纯度越高,表明市场黄金坑股票越多,市场整体反弹可能越大。","用法:","先找黄金坑,再看纯度,然后关注估值和弹性,整体是这些值越大越好。"]}],name:"黄金坑",nameCode:"10011400"},{data:[{title:"顺势强度指标说明:",items:["表示上涨趋势强度。"]}],name:"顺势强度",nameCode:"10011500"},{name:"强龙起势",nameCode:"10004702",data:[{title:"强龙起势指标:",items:["股价的强势上涨,背后往往离不开多种因素的综合影响,首先,强势的外在最直接表现就是量价的配合反应。","其次,股价预期上涨途中,要尽可能少压力,股价背后的多空筹码最好要经历足够的消化和收集,上方没有明显的抛压,才利于股价的走强。","再者,股价持续上涨和走强的潜力,往往需要有形态上的向好和偏强为基础。另外,股价背后有主力资金的做多支持,往往更具走强和持续走强的潜质。","强龙起势,就是基于上述因素,分别从量价、筹码、形态、资金等不同维度,以不同颜色色块的方式体现股价涨跌背后是否具备相应的走强因素。并辅助以强风口、火线的入选来加强对个股的判断","方便综合研判股价涨跌背后是否具备强势的潜质。","量价:有色块则以为这个股短期趋势趋于向好,量能相对活跃。若量价不满足,则色块为空。","筹码:股价背后筹码有过较充分的消化和收集,短期上方抛压不明显。若筹码不满足,则色块为空。","形态:股价形态上有短期突破的表现,或者指标形态上短期走强,整体处于相对偏强。若形态不满足,则色块为空。","资金:当天主力有一定力度的做多支持,短期或阶段性有资金做多行为支持。若资金不满足,则色块为空。","强风口,近15个交易日内入选风口全景/风口主线的题材,入选后显示蓝色风口图。","火线:近15日入选火线题材,入选后显示火焰标志","指标上方,针对同时满足量价、筹码、形态、资金四个要素的数量,进行相应的数字呈现,1为满足一种强势因子,2为满足其中两种强势因子,以此类推。对于上方的数字,符合操盘线红色,对应上方的数字显示为红色,对于不符合操盘线红色,上方均显示为简单的纯数字。","对于股价背后的强势潜在,同时满足上述因素的数量越多,往往意味着个股短期更具强势潜质,因此,对于同时满足3和4种因素的色块,代表股价有起势信号。","多个连续黄色信号,仅显示第一个,首3和首4。若4的黄色信号在前,代表起势信号更明确,随后跟随的3不在显示黄色信号。","强龙起势增加了三步擒龙触发条件的显示,若满足三步擒龙紫色信号,代表股价有转折趋势,可提前关注。"]}]},{name:"偏离度",nameCode:"10012200",data:[{title:"偏离度:",items:["表示标的价格偏离中期线的程度:","当价格处于中期线上方时,偏离越远,风险越大;","当价格处于中期线下方时,偏离越远,机会越大。"]}]},{name:"中期线",nameCode:"10012100",data:[{title:"中期线:",items:["代表标的的中期趋势:","曲线向上走时,代表中期趋势上涨;","曲线向下走时,代表中期趋势下跌。"]}]},{name:"步步高指标",nameCode:"10012400",data:[{title:"步步高指标:",items:["价格的涨跌,是股价表现强弱的最直接体现,量能的放大和支持,往往是股价上涨的助推,体现的是股价背后交投的活跃性,因此,通过观察股价短期或阶段性的活跃性表现和变化,往往有助于分析判断股价是否具备上涨潜力和延续性。","步步高,就是基于阶段性量价的起伏表现,相对中长期量价形态的变化,重心和相对背离等综合因素分析运算,指标化的揭示量价活跃性表现和变动趋向。实战中可以单独或结合其他指标,来辅助操盘线进行相应的分析判断。","指标值范围:从极值0到极值100。海面线作为活跃性变化的低位分水岭。海面线以下,意味着活跃性偏弱,相对不利于股价的上涨。活跃值线体向上,意味着量价活跃性相对提升,反之亦然。活跃值越高意味着量价活跃度越热,反之越冷。","当股价经历中长期的充分下跌后企稳回升,若活跃值由海面线以下转折向上,乃至逾越海面线,意味着里价活跃性的复苏,指标显示紫色柱线,辅助操盘线可低位稳操作。","当活跃复苏后,量价热度进一步提升,活跃值线随之向上,逾越30,指标在紫色柱线上显示黄色,意味着量价活跃性进入到中位缓升区,辅助操盘线可中继顺势。","进入缓升区后,当量价热度继续升高,活跃值线随之向上,逾越50,指标柱线上方显示橙色,意味着量价活跃性进入到快升区,量价热度相对较高,辅助操盘线可把握潜在活跃性机会(活跃快升区忌恋战,活跃热度越高,越需要注意可能的量价起伏变化)。"]}]},{name:"控盘资金(原短线主力)",nameCode:"10012500",data:[{title:"控盘资金(原短线主力)指标说明:",items:["控盘资金指标反应的是具有雄厚资金的参与者(即控盘资金)的买入、卖出情况。这类资金的流入流出,对股票走势影响较大。","红色代表买方占优,表示买入资金大于卖出资金。","绿色代表卖出占优,表示卖出资金大于买入资金。","数值大小反映了控盘资金流入流出的量的多少,越大越强烈。"]}]},{name:"市盈率(PE-TTM)",nameCode:"10012700",data:[{title:"市盈率(PE-TTM)指标说明:",items:["PETTM是个股最新总市值与近一年TTM归母净利润的比值,反映的是股票估值的大小;机会值和危险值分别表示近五年PETTM的30%分位值和70%分位值;","PETTM越大, 说明股票估值越贵, 高于危险值时,股票进入高估区间;","PETTM越小, 说明股票估值越便宜, 低于机会值时,股票进入低估区间;","PETTM等于0, 说明公司近一年TTM归母净利润亏损"]}]},{name:"三步擒龙(新)",nameCode:"10012600",data:[{title:"三步擒龙(新)指标说明:",items:["研判股价上涨和持续性上涨的潜力,往往离不开量价、趋势、形态等方面的考量。股价短期是否具备上涨的潜力,首先其短期趋势要处于预期向好的节奏内。其次股价走势形态上要趋于活跃和偏强,背后多空资金维度,多方需要占据相对的优势。再者股价上涨背后需要量能维度的交投活跃性配合。这也就是三步擒龙的基本考量,分别从趋势、资金和活跃等三个维度,以不同颜色的色块进行呈现(实心色块为该因素符合,反之空心为不符合)。","趋势,即短期趋势趋于向好,日线操盘线B点或处于红色阶段。","资金,即前期有过异动上涨,且控盘资金净流入占优。"," 以上三者均具备,则为三步擒龙的基本要求符合,意味个股短期走势上偏强,量价相对活跃。",'当然,对于个股股价的涨跌,背后若有市场热点或板块共性的支持,其短期往往更具上涨或活跃的潜力。因此指标下方融入了"风口"是否具备的辅助因素参考。若个股所属板块,当日符合火线题材或风口、强风口的,则指标下方显示"火",反之则为空。',"与此同时,为了方便对比和查看,指标上方显示了符合下方不同维度(趋势、活跃、资金)的数量,1为符合其中一个要素,2为符合其中两个维度,3为符合三个。","另外,对于趋势、活跃、资金等三个不同维度中,若当天符合趋势(操盘线)要求,则数字为红色背景;","紫色信号:意味着短期有转折变强的迹象","紫2:前一天符合条件数0,当天符合条件数2(且操盘线红色),前一天符合条件1或2,但不符合操盘线红色,当天符合条件数2。","紫3:前一天符合条件数0或1,当天符合条件数3(且操盘线红色),前一天符合条件1或2,但不符合操盘线红色,当天符合条件数3。","结合股价形态位置和特征,比如底部转折、中继性上涨或走强、形态上的突破走强等,相对更具参考性。"]}]},{name:"估值分位",nameCode:"10013000",data:[{title:"估值分位指标说明:",items:["估值分位是基于个股PETTM的分位数得到的价格区间,反映的是当前股票价格所处的估值位置;机会值和危险值分别表示近七年PETTM的30%分位值和70%分位值;","当前股价进入高估区域, 说明股票当前处于相对高估的位置;","当前股价进入低估区域,说明股票当前处于相对低估的位置;","当前股价处于低估与高估之间,说明股票当前处于相对合理的位置;"]}]},{name:"量能识别",nameCode:"10013300",data:[{title:"量能识别指标说明:",items:["量能识别指标用于帮助用户快速识别成交量的关键变化,结合股价走势和操盘线,可更精准地做出投资决策。指标包括三倍、倍量、放量、半量和地量,适用于不同市场行情。","黄色量柱(三倍):当前成交量是前一日的三倍及以上。在上涨行情中,是主力大举买入的信号,股价有望加速上涨;在下跌行情中,可能是主力恐慌性抛售,股价面临大幅下跌风险。需高度重视并结合操盘线分析。","橙色量柱(倍量):当前成交量是前一日的两倍。在上涨行情中,预示股价有望继续上扬;在下跌行情中,可能是恐慌性抛售或主力出逃的信号。需结合操盘线判断。","紫色量柱(放量):股价上涨时成交量同步放大。表明上涨动力充足,是股价上涨的有力支撑信号。但若出现在高位,也可能是主力拉高出货,需结合操盘线判断。","绿色量柱(半量):成交量较前一阶段减少一倍或以上。在上升趋势中,可能暗示资金跟进不足,趋势难持续;在下降趋势中,可能预示市场底部即将形成。","灰色量柱(地量):成交量处于一段时间的历史低位。表明当前交易并不活跃,买卖双方观望情绪浓厚。可等更明确的市场信号出现后再判断。","不同个股的量能表现有差异,大盘蓝筹股量能相对稳定,小盘股或题材股量能波动大。投资者需结合个股特性使用该指标。"]}]}],o={name:"note",head:{title:"指标说明"},data:function(){var n=this.$route.query.id,e=this.$route.query.name;return e&&(e=e.replace(/\s/g,"")),{id:n,indicatorName:e,list:[{title:"",items:[],image:""}],hidePagenation:!1,swiperOption:{pagination:{el:".swiper-pagination",type:"bullets"}}}},mounted:function(){this.init()},methods:{getConfig:function(n,e){for(var t,o=r,l=/^\d{8}$/.test(e),m=0;m .swiper-wrapper {\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n -webkit-flex-direction: column;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.swiper-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n z-index: 1;\n display: -webkit-box;\n display: -webkit-flex;\n display: -ms-flexbox;\n display: flex;\n -webkit-transition-property: -webkit-transform;\n transition-property: -webkit-transform;\n -o-transition-property: transform;\n transition-property: transform;\n transition-property: transform, -webkit-transform;\n -webkit-box-sizing: content-box;\n box-sizing: content-box;\n}\n.swiper-container-android .swiper-slide,\n.swiper-wrapper {\n -webkit-transform: translate3d(0px, 0, 0);\n transform: translate3d(0px, 0, 0);\n}\n.swiper-container-multirow > .swiper-wrapper {\n -webkit-flex-wrap: wrap;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n}\n.swiper-container-free-mode > .swiper-wrapper {\n -webkit-transition-timing-function: ease-out;\n -o-transition-timing-function: ease-out;\n transition-timing-function: ease-out;\n margin: 0 auto;\n}\n.swiper-slide {\n -webkit-flex-shrink: 0;\n -ms-flex-negative: 0;\n flex-shrink: 0;\n width: 100%;\n height: 100%;\n position: relative;\n -webkit-transition-property: -webkit-transform;\n transition-property: -webkit-transform;\n -o-transition-property: transform;\n transition-property: transform;\n transition-property: transform, -webkit-transform;\n}\n.swiper-slide-invisible-blank {\n visibility: hidden;\n}\n/* Auto Height */\n.swiper-container-autoheight,\n.swiper-container-autoheight .swiper-slide {\n height: auto;\n}\n.swiper-container-autoheight .swiper-wrapper {\n -webkit-box-align: start;\n -webkit-align-items: flex-start;\n -ms-flex-align: start;\n align-items: flex-start;\n -webkit-transition-property: height, -webkit-transform;\n transition-property: height, -webkit-transform;\n -o-transition-property: transform, height;\n transition-property: transform, height;\n transition-property: transform, height, -webkit-transform;\n}\n/* 3D Effects */\n.swiper-container-3d {\n -webkit-perspective: 25.6rem;\n perspective: 25.6rem;\n}\n.swiper-container-3d .swiper-wrapper,\n.swiper-container-3d .swiper-slide,\n.swiper-container-3d .swiper-slide-shadow-left,\n.swiper-container-3d .swiper-slide-shadow-right,\n.swiper-container-3d .swiper-slide-shadow-top,\n.swiper-container-3d .swiper-slide-shadow-bottom,\n.swiper-container-3d .swiper-cube-shadow {\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n}\n.swiper-container-3d .swiper-slide-shadow-left,\n.swiper-container-3d .swiper-slide-shadow-right,\n.swiper-container-3d .swiper-slide-shadow-top,\n.swiper-container-3d .swiper-slide-shadow-bottom {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 10;\n}\n.swiper-container-3d .swiper-slide-shadow-left {\n background-image: -webkit-gradient(linear, right top, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));\n background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: -o-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n}\n.swiper-container-3d .swiper-slide-shadow-right {\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n}\n.swiper-container-3d .swiper-slide-shadow-top {\n background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));\n background-image: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n}\n.swiper-container-3d .swiper-slide-shadow-bottom {\n background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));\n background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));\n}\n/* IE10 Windows Phone 8 Fixes */\n.swiper-container-wp8-horizontal,\n.swiper-container-wp8-horizontal > .swiper-wrapper {\n -ms-touch-action: pan-y;\n touch-action: pan-y;\n}\n.swiper-container-wp8-vertical,\n.swiper-container-wp8-vertical > .swiper-wrapper {\n -ms-touch-action: pan-x;\n touch-action: pan-x;\n}\n.swiper-button-prev,\n.swiper-button-next {\n position: absolute;\n top: 50%;\n width: 0.576rem;\n height: 0.93867rem;\n margin-top: -0.46933rem;\n z-index: 10;\n cursor: pointer;\n background-size: 0.576rem 0.93867rem;\n background-position: center;\n background-repeat: no-repeat;\n}\n.swiper-button-prev.swiper-button-disabled,\n.swiper-button-next.swiper-button-disabled {\n opacity: 0.35;\n cursor: auto;\n pointer-events: none;\n}\n.swiper-button-prev,\n.swiper-container-rtl .swiper-button-next {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E\");\n left: 0.21333rem;\n right: auto;\n}\n.swiper-button-next,\n.swiper-container-rtl .swiper-button-prev {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E\");\n right: 0.21333rem;\n left: auto;\n}\n.swiper-button-prev.swiper-button-white,\n.swiper-container-rtl .swiper-button-next.swiper-button-white {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E\");\n}\n.swiper-button-next.swiper-button-white,\n.swiper-container-rtl .swiper-button-prev.swiper-button-white {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E\");\n}\n.swiper-button-prev.swiper-button-black,\n.swiper-container-rtl .swiper-button-next.swiper-button-black {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E\");\n}\n.swiper-button-next.swiper-button-black,\n.swiper-container-rtl .swiper-button-prev.swiper-button-black {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E\");\n}\n.swiper-button-lock {\n display: none;\n}\n.swiper-pagination {\n position: absolute;\n text-align: center;\n -webkit-transition: 300ms opacity;\n -o-transition: 300ms opacity;\n transition: 300ms opacity;\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n z-index: 10;\n}\n.swiper-pagination.swiper-pagination-hidden {\n opacity: 0;\n}\n/* Common Styles */\n.swiper-pagination-fraction,\n.swiper-pagination-custom,\n.swiper-container-horizontal > .swiper-pagination-bullets {\n bottom: 0.21333rem;\n left: 0;\n width: 100%;\n}\n/* Bullets */\n.swiper-pagination-bullets-dynamic {\n overflow: hidden;\n font-size: 0;\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet {\n -webkit-transform: scale(0.33);\n -ms-transform: scale(0.33);\n transform: scale(0.33);\n position: relative;\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active {\n -webkit-transform: scale(1);\n -ms-transform: scale(1);\n transform: scale(1);\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-main {\n -webkit-transform: scale(1);\n -ms-transform: scale(1);\n transform: scale(1);\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev {\n -webkit-transform: scale(0.66);\n -ms-transform: scale(0.66);\n transform: scale(0.66);\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev-prev {\n -webkit-transform: scale(0.33);\n -ms-transform: scale(0.33);\n transform: scale(0.33);\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next {\n -webkit-transform: scale(0.66);\n -ms-transform: scale(0.66);\n transform: scale(0.66);\n}\n.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next-next {\n -webkit-transform: scale(0.33);\n -ms-transform: scale(0.33);\n transform: scale(0.33);\n}\n.swiper-pagination-bullet {\n width: 0.17067rem;\n height: 0.17067rem;\n display: inline-block;\n border-radius: 100%;\n background: #000;\n opacity: 0.2;\n}\nbutton.swiper-pagination-bullet {\n border: none;\n margin: 0;\n padding: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.swiper-pagination-clickable .swiper-pagination-bullet {\n cursor: pointer;\n}\n.swiper-pagination-bullet-active {\n opacity: 1;\n background: #007aff;\n}\n.swiper-container-vertical > .swiper-pagination-bullets {\n right: 0.21333rem;\n top: 50%;\n -webkit-transform: translate3d(0px, -50%, 0);\n transform: translate3d(0px, -50%, 0);\n}\n.swiper-container-vertical > .swiper-pagination-bullets .swiper-pagination-bullet {\n margin: 0.128rem 0;\n display: block;\n}\n.swiper-container-vertical > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic {\n top: 50%;\n -webkit-transform: translateY(-50%);\n -ms-transform: translateY(-50%);\n transform: translateY(-50%);\n width: 0.17067rem;\n}\n.swiper-container-vertical > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet {\n display: inline-block;\n -webkit-transition: 200ms top, 200ms -webkit-transform;\n transition: 200ms top, 200ms -webkit-transform;\n -o-transition: 200ms transform, 200ms top;\n transition: 200ms transform, 200ms top;\n transition: 200ms transform, 200ms top, 200ms -webkit-transform;\n}\n.swiper-container-horizontal > .swiper-pagination-bullets .swiper-pagination-bullet {\n margin: 0 4px;\n}\n.swiper-container-horizontal > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic {\n left: 50%;\n -webkit-transform: translateX(-50%);\n -ms-transform: translateX(-50%);\n transform: translateX(-50%);\n white-space: nowrap;\n}\n.swiper-container-horizontal > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet {\n -webkit-transition: 200ms left, 200ms -webkit-transform;\n transition: 200ms left, 200ms -webkit-transform;\n -o-transition: 200ms transform, 200ms left;\n transition: 200ms transform, 200ms left;\n transition: 200ms transform, 200ms left, 200ms -webkit-transform;\n}\n.swiper-container-horizontal.swiper-container-rtl > .swiper-pagination-bullets-dynamic .swiper-pagination-bullet {\n -webkit-transition: 200ms right, 200ms -webkit-transform;\n transition: 200ms right, 200ms -webkit-transform;\n -o-transition: 200ms transform, 200ms right;\n transition: 200ms transform, 200ms right;\n transition: 200ms transform, 200ms right, 200ms -webkit-transform;\n}\n/* Progress */\n.swiper-pagination-progressbar {\n background: rgba(0, 0, 0, 0.25);\n position: absolute;\n}\n.swiper-pagination-progressbar .swiper-pagination-progressbar-fill {\n background: #007aff;\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n -webkit-transform: scale(0);\n -ms-transform: scale(0);\n transform: scale(0);\n -webkit-transform-origin: left top;\n -ms-transform-origin: left top;\n transform-origin: left top;\n}\n.swiper-container-rtl .swiper-pagination-progressbar .swiper-pagination-progressbar-fill {\n -webkit-transform-origin: right top;\n -ms-transform-origin: right top;\n transform-origin: right top;\n}\n.swiper-container-horizontal > .swiper-pagination-progressbar,\n.swiper-container-vertical > .swiper-pagination-progressbar.swiper-pagination-progressbar-opposite {\n width: 100%;\n height: 4px;\n left: 0;\n top: 0;\n}\n.swiper-container-vertical > .swiper-pagination-progressbar,\n.swiper-container-horizontal > .swiper-pagination-progressbar.swiper-pagination-progressbar-opposite {\n width: 4px;\n height: 100%;\n left: 0;\n top: 0;\n}\n.swiper-pagination-white .swiper-pagination-bullet-active {\n background: #ffffff;\n}\n.swiper-pagination-progressbar.swiper-pagination-white {\n background: rgba(255, 255, 255, 0.25);\n}\n.swiper-pagination-progressbar.swiper-pagination-white .swiper-pagination-progressbar-fill {\n background: #ffffff;\n}\n.swiper-pagination-black .swiper-pagination-bullet-active {\n background: #000000;\n}\n.swiper-pagination-progressbar.swiper-pagination-black {\n background: rgba(0, 0, 0, 0.25);\n}\n.swiper-pagination-progressbar.swiper-pagination-black .swiper-pagination-progressbar-fill {\n background: #000000;\n}\n.swiper-pagination-lock {\n display: none;\n}\n/* Scrollbar */\n.swiper-scrollbar {\n border-radius: 0.21333rem;\n position: relative;\n -ms-touch-action: none;\n background: rgba(0, 0, 0, 0.1);\n}\n.swiper-container-horizontal > .swiper-scrollbar {\n position: absolute;\n left: 1%;\n bottom: 3px;\n z-index: 50;\n height: 0.10667rem;\n width: 98%;\n}\n.swiper-container-vertical > .swiper-scrollbar {\n position: absolute;\n right: 3px;\n top: 1%;\n z-index: 50;\n width: 0.10667rem;\n height: 98%;\n}\n.swiper-scrollbar-drag {\n height: 100%;\n width: 100%;\n position: relative;\n background: rgba(0, 0, 0, 0.5);\n border-radius: 0.21333rem;\n left: 0;\n top: 0;\n}\n.swiper-scrollbar-cursor-drag {\n cursor: move;\n}\n.swiper-scrollbar-lock {\n display: none;\n}\n.swiper-zoom-container {\n width: 100%;\n height: 100%;\n display: -webkit-box;\n display: -webkit-flex;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-pack: center;\n -webkit-justify-content: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-align: center;\n -webkit-align-items: center;\n -ms-flex-align: center;\n align-items: center;\n text-align: center;\n}\n.swiper-zoom-container > img,\n.swiper-zoom-container > svg,\n.swiper-zoom-container > canvas {\n max-width: 100%;\n max-height: 100%;\n -o-object-fit: contain;\n object-fit: contain;\n}\n.swiper-slide-zoomed {\n cursor: move;\n}\n/* Preloader */\n.swiper-lazy-preloader {\n width: 0.896rem;\n height: 0.896rem;\n position: absolute;\n left: 50%;\n top: 50%;\n margin-left: -0.448rem;\n margin-top: -0.448rem;\n z-index: 10;\n -webkit-transform-origin: 50%;\n -ms-transform-origin: 50%;\n transform-origin: 50%;\n -webkit-animation: swiper-preloader-spin 1s steps(12, end) infinite;\n animation: swiper-preloader-spin 1s steps(12, end) infinite;\n}\n.swiper-lazy-preloader:after {\n display: block;\n content: '';\n width: 100%;\n height: 100%;\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E\");\n background-position: 50%;\n background-size: 100%;\n background-repeat: no-repeat;\n}\n.swiper-lazy-preloader-white:after {\n background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E\");\n}\n@-webkit-keyframes swiper-preloader-spin {\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@keyframes swiper-preloader-spin {\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n/* a11y */\n.swiper-container .swiper-notification {\n position: absolute;\n left: 0;\n top: 0;\n pointer-events: none;\n opacity: 0;\n z-index: -1000;\n}\n.swiper-container-fade.swiper-container-free-mode .swiper-slide {\n -webkit-transition-timing-function: ease-out;\n -o-transition-timing-function: ease-out;\n transition-timing-function: ease-out;\n}\n.swiper-container-fade .swiper-slide {\n pointer-events: none;\n -webkit-transition-property: opacity;\n -o-transition-property: opacity;\n transition-property: opacity;\n}\n.swiper-container-fade .swiper-slide .swiper-slide {\n pointer-events: none;\n}\n.swiper-container-fade .swiper-slide-active,\n.swiper-container-fade .swiper-slide-active .swiper-slide-active {\n pointer-events: auto;\n}\n.swiper-container-cube {\n overflow: visible;\n}\n.swiper-container-cube .swiper-slide {\n pointer-events: none;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n z-index: 1;\n visibility: hidden;\n -webkit-transform-origin: 0 0;\n -ms-transform-origin: 0 0;\n transform-origin: 0 0;\n width: 100%;\n height: 100%;\n}\n.swiper-container-cube .swiper-slide .swiper-slide {\n pointer-events: none;\n}\n.swiper-container-cube.swiper-container-rtl .swiper-slide {\n -webkit-transform-origin: 100% 0;\n -ms-transform-origin: 100% 0;\n transform-origin: 100% 0;\n}\n.swiper-container-cube .swiper-slide-active,\n.swiper-container-cube .swiper-slide-active .swiper-slide-active {\n pointer-events: auto;\n}\n.swiper-container-cube .swiper-slide-active,\n.swiper-container-cube .swiper-slide-next,\n.swiper-container-cube .swiper-slide-prev,\n.swiper-container-cube .swiper-slide-next + .swiper-slide {\n pointer-events: auto;\n visibility: visible;\n}\n.swiper-container-cube .swiper-slide-shadow-top,\n.swiper-container-cube .swiper-slide-shadow-bottom,\n.swiper-container-cube .swiper-slide-shadow-left,\n.swiper-container-cube .swiper-slide-shadow-right {\n z-index: 0;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n}\n.swiper-container-cube .swiper-cube-shadow {\n position: absolute;\n left: 0;\n bottom: 0px;\n width: 100%;\n height: 100%;\n background: #000;\n opacity: 0.6;\n -webkit-filter: blur(1.06667rem);\n filter: blur(1.06667rem);\n z-index: 0;\n}\n.swiper-container-flip {\n overflow: visible;\n}\n.swiper-container-flip .swiper-slide {\n pointer-events: none;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n z-index: 1;\n}\n.swiper-container-flip .swiper-slide .swiper-slide {\n pointer-events: none;\n}\n.swiper-container-flip .swiper-slide-active,\n.swiper-container-flip .swiper-slide-active .swiper-slide-active {\n pointer-events: auto;\n}\n.swiper-container-flip .swiper-slide-shadow-top,\n.swiper-container-flip .swiper-slide-shadow-bottom,\n.swiper-container-flip .swiper-slide-shadow-left,\n.swiper-container-flip .swiper-slide-shadow-right {\n z-index: 0;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n}\n.swiper-container-coverflow .swiper-wrapper {\n /* Windows 8 IE 10 fix */\n -ms-perspective: 25.6rem;\n}\n",""])}}]); \ No newline at end of file diff --git a/src/main/java/quant/rich/emoney/client/WebviewClient.java b/src/main/java/quant/rich/emoney/client/WebviewClient.java new file mode 100644 index 0000000..5dfa83b --- /dev/null +++ b/src/main/java/quant/rich/emoney/client/WebviewClient.java @@ -0,0 +1,177 @@ +package quant.rich.emoney.client; + +import java.net.Proxy; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.microsoft.playwright.Browser; +import com.microsoft.playwright.BrowserContext; +import com.microsoft.playwright.BrowserType; +import com.microsoft.playwright.Page; +import com.microsoft.playwright.Playwright; +import com.microsoft.playwright.Request; +import com.microsoft.playwright.BrowserType.LaunchOptions; +import com.microsoft.playwright.Route.ResumeOptions; +import com.microsoft.playwright.options.HttpHeader; +import com.microsoft.playwright.options.WaitUntilState; + +import lombok.Data; +import lombok.experimental.Accessors; +import quant.rich.emoney.component.LockByCaller; +import quant.rich.emoney.entity.config.EmoneyRequestConfig; +import quant.rich.emoney.entity.config.ProxyConfig; +import quant.rich.emoney.util.SpringContextHolder; + +public class WebviewClient { + + private static Playwright playwright; + private static boolean isReady = false; + private static volatile ProxyConfig proxyConfig; + private static volatile EmoneyRequestConfig emoneyRequestConfig; + + static { + try { + playwright = Playwright.create(); + isReady = true; + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public static boolean isReady() { + return isReady; + } + + private static ProxyConfig getProxyConfig() { + if (proxyConfig == null) { + synchronized (WebviewClient.class) { + if (proxyConfig == null) { + proxyConfig = SpringContextHolder.getBean(ProxyConfig.class); + } + } + } + return proxyConfig; + } + + private static EmoneyRequestConfig getEmoneyRequestConfig() { + if (emoneyRequestConfig == null) { + synchronized (WebviewClient.class) { + if (emoneyRequestConfig == null) { + emoneyRequestConfig = SpringContextHolder.getBean(EmoneyRequestConfig.class); + } + } + } + return emoneyRequestConfig; + } + + @LockByCaller + public static WebviewResponseWrapper getIndexDetailWrapper(String indexCode) { + + String proxyUrl = getProxyConfig().getProxyUrl(); + LaunchOptions launchOptions = new BrowserType.LaunchOptions() + .setHeadless(true); + + // 设置代理 + if (StringUtils.isNotBlank(proxyUrl)) { + launchOptions.setProxy(proxyUrl); + } + + Browser browser = playwright.chromium().launch(launchOptions); + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + // 设置 Webview User-Agent + .setUserAgent(getEmoneyRequestConfig().getWebviewUserAgent()) + // 设置是否忽略 HTTPS 证书 + .setIgnoreHTTPSErrors(getProxyConfig().getIgnoreHttpsVerification()) + ); + + // 设置全局请求头 + // 根据抓包获得,当前目标版本 5.8.1 + Map headers = new HashMap<>(); + headers.put("Upgrade-Insecure-Requests", "1"); + headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"); + headers.put("X-Requested-With", "cn.emoney.emstock"); + headers.put("Sec-Fetch-Site", "none"); + headers.put("Sec-Fetch-Mode", "navigate"); + headers.put("Sec-Fetch-User", "?1"); + headers.put("Sec-Fetch-Dest", "document"); + headers.put("Accept-Encoding", "gzip, deflate"); + headers.put("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"); + + context.setExtraHTTPHeaders(headers); + context.route("**/*", route -> { + // 清除 Playwright 添加的额外请求头 + Request request = route.request(); + List requestHeaderList = request.headersArray(); + Map requestHeaders = new HashMap<>(); + for (HttpHeader header : requestHeaderList) { + requestHeaders.put(header.name, header.value); + } + requestHeaders.remove("sec-ch-ua"); + requestHeaders.remove("sec-ch-ua-mobile"); + requestHeaders.remove("sec-ch-ua-platform"); + requestHeaders.remove("Cache-Control"); + requestHeaders.remove("Pragma"); + requestHeaders.remove("cache-control"); + requestHeaders.remove("pragma"); + + // 判断页面附属请求并进行个性化,以尽可能模仿原生 APP + System.out.format("url: %s, requestType: %s\r\n", request.url(), request.resourceType()); + + String resourceType = request.resourceType(); + + if (!"document".equals(resourceType)) { + // 非 document(html) 请求的 + requestHeaders.put("Sec-Fetch-Mode", "no-cors"); + requestHeaders.remove("Upgrade-Insecure-Requests"); + } + if ("image".equals(request.resourceType())) { + // 图片请求 + requestHeaders.put("Accept", "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"); + } + else if ("script".equals(request.resourceType())) { + // 图片请求 + requestHeaders.put("Accept", "*/*"); + } + route.resume(new ResumeOptions().setHeaders(requestHeaders)); + }); + + Page page = context.newPage(); + WebviewResponseWrapper wrapper = new WebviewResponseWrapper(); + + page.onResponse(handler -> { + String requestUrl = handler.request().url(); + if (requestUrl.endsWith(".js")) { + String jsContent = handler.request().response().text(); + wrapper.jsMap.put(requestUrl, jsContent); + } + }); + + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.append("https://appstatic.emoney.cn/html/emapp/stock/note/?name="); + urlBuilder.append(indexCode); + urlBuilder.append("&emoneyScaleType=0&emoneyLandMode=0&token="); + urlBuilder.append(getEmoneyRequestConfig().getAuthorization()); + String url = urlBuilder.toString(); + + page.navigate(url, new Page.NavigateOptions().setWaitUntil(WaitUntilState.NETWORKIDLE)); + + wrapper.setRenderedHtml(page.content()); + wrapper.setPage(page); + browser.close(); + + return wrapper; + } + + @Data + @Accessors(chain=true) + public static class WebviewResponseWrapper { + private Map jsMap = new HashMap<>(); + private String renderedHtml; + private Page page; + } + +}