qwJxs.html 130 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport"
  7. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
  8. <title></title>
  9. <!-- 引入样式文件 -->
  10. <link rel="stylesheet"
  11. href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
  12. <!-- 必须先引入vue, 后使用vant-ui -->
  13. <script
  14. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
  15. <!-- 引入vant的组件库-->
  16. <!-- 引入 Vant 的 JS 文件 -->
  17. <script
  18. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
  19. <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
  20. <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
  21. <script src="../js/select-date.js"></script>
  22. <script
  23. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758187289797/echarts.js"></script>
  24. <script src="../js/echarts-wordcloud.js"></script>
  25. <!-- <script src="js/vconsole.min.js"></script>
  26. <script>
  27. var vConsole = new window.VConsole();
  28. </script> -->
  29. </head>
  30. <style>
  31. body {
  32. margin: 0;
  33. padding: 0;
  34. }
  35. .box {
  36. width: 100vw;
  37. /* height: 100vh; */
  38. box-sizing: border-box;
  39. background: #FAFAFA;
  40. }
  41. .page4 {
  42. width: 100vw;
  43. /* height: 100vh; */
  44. box-sizing: border-box;
  45. display: flex;
  46. flex-direction: column;
  47. }
  48. .popup_list {
  49. width: 100%;
  50. height: 100%;
  51. box-sizing: border-box;
  52. display: flex;
  53. flex-direction: column;
  54. padding: 44px 30px 10px;
  55. }
  56. .popup_item {
  57. padding: 15px 0;
  58. font-weight: bold;
  59. font-size: 16px;
  60. color: #222222;
  61. line-height: 24px;
  62. }
  63. .popup_line {
  64. height: 1px;
  65. background: linear-gradient(90deg, #000000 0%, rgba(0, 0, 0, 0) 100%);
  66. opacity: 0.1;
  67. }
  68. .mer_item {
  69. padding: 15px 0;
  70. font-weight: bold;
  71. font-size: 16px;
  72. color: #222222;
  73. line-height: 24px;
  74. border-bottom: 1px solid transparent;
  75. /* 占位 */
  76. border-image: linear-gradient(90deg, rgba(0, 0, 0, 0.1) 0%, transparent 100%) 1;
  77. }
  78. .mer_item_active {
  79. color: #1677FF;
  80. }
  81. .van-nav-bar__content {
  82. height: 44px;
  83. }
  84. .van-nav-bar__title {
  85. font-weight: bold;
  86. font-size: 14px;
  87. color: #222222;
  88. }
  89. .explain_list {
  90. display: flex;
  91. flex-direction: column;
  92. padding: 10px;
  93. font-weight: 400;
  94. font-size: 12px;
  95. color: #FFFFFF;
  96. line-height: 18px;
  97. }
  98. .explain_list div {
  99. padding-bottom: 10px;
  100. }
  101. .explain_list div:last-child {
  102. padding-bottom: 0;
  103. }
  104. .explain_icon {
  105. width: 20px;
  106. height: 20px;
  107. margin-left: 5px;
  108. }
  109. .navbar_icon {
  110. width: 24px;
  111. height: 24px;
  112. }
  113. .van-nav-bar__left {
  114. padding: 0 10px;
  115. }
  116. .van-nav-bar__right {
  117. padding: 0 10px;
  118. }
  119. .van-hairline--bottom::after {
  120. border-bottom: none;
  121. }
  122. .top_data {
  123. display: flex;
  124. align-items: center;
  125. justify-content: flex-end;
  126. padding: 10px;
  127. height: 54px;
  128. background: #FFFFFF;
  129. box-sizing: border-box;
  130. position: fixed;
  131. top: 44px;
  132. left: 0;
  133. width: 100%;
  134. z-index: 2;
  135. }
  136. .top_data_bottom {
  137. display: flex;
  138. align-items: center;
  139. justify-content: flex-end;
  140. position: fixed;
  141. top: 98px;
  142. right: 0;
  143. width: 100%;
  144. z-index: 1;
  145. padding-right: 10px;
  146. background: #FAFAFA;
  147. }
  148. .outlet_data {
  149. display: flex;
  150. align-items: center;
  151. justify-content: flex-end;
  152. height: 34px;
  153. background: #FAFAFA;
  154. box-sizing: border-box;
  155. }
  156. .close_icon {
  157. width: 24px;
  158. height: 24px;
  159. }
  160. .memberReply_title {
  161. font-weight: 500;
  162. font-size: 14px;
  163. color: #222222;
  164. line-height: 20px;
  165. background: #FFFFFF;
  166. display: flex;
  167. align-items: center;
  168. justify-content: space-between;
  169. height: 44px;
  170. padding: 0 10px;
  171. width: 100%;
  172. box-sizing: border-box;
  173. }
  174. .pop_content {
  175. padding: 10px 10px 10px;
  176. background: #FAFAFA;
  177. height: calc(100vh - 44px);
  178. overflow: auto;
  179. box-sizing: border-box;
  180. }
  181. .select_box {
  182. display: flex;
  183. margin-bottom: 10px;
  184. }
  185. .select_day {
  186. display: flex;
  187. align-items: center;
  188. background: #FFFFFF;
  189. box-sizing: border-box;
  190. padding: 10px 15px;
  191. font-weight: 400;
  192. font-size: 12px;
  193. color: #222222;
  194. margin-right: 10px;
  195. border-radius: 10px;
  196. }
  197. .search_input {
  198. width: 160px;
  199. height: 38px;
  200. border-radius: 10px;
  201. }
  202. .van-search__content {
  203. background: #FFFFFF;
  204. padding-left: 0;
  205. }
  206. .van-search__label {
  207. font-weight: 400;
  208. font-size: 12px;
  209. color: #222222;
  210. width: unset;
  211. }
  212. .van-popover__wrapper {
  213. height: unset;
  214. }
  215. .top_data_title {
  216. display: flex;
  217. align-items: center;
  218. }
  219. .top_data_right {
  220. display: flex;
  221. align-items: center;
  222. }
  223. .item_gap {
  224. margin-right: 10px;
  225. }
  226. .top_data_title_text {
  227. font-weight: 500;
  228. font-size: 14px;
  229. color: #222222;
  230. padding-left: 5px;
  231. }
  232. .top_data_title_branch {
  233. font-weight: 400;
  234. font-size: 12px;
  235. color: #222222;
  236. max-width: 90px;
  237. white-space: nowrap;
  238. /* 禁止换行 */
  239. overflow: hidden;
  240. /* 隐藏溢出内容 */
  241. text-overflow: ellipsis;
  242. /* 显示省略号 */
  243. }
  244. .triangle {
  245. width: 0;
  246. height: 0;
  247. border: 6px solid transparent;
  248. border-top-color: #222222;
  249. margin-top: 6px;
  250. border-radius: 5px;
  251. margin-left: 5px;
  252. }
  253. .page4_content {
  254. padding: 113px 10px 10px;
  255. }
  256. .page4_content2 {
  257. padding: 131px 10px 10px;
  258. }
  259. .box_connect {
  260. width: 100%;
  261. background: #FFFFFF;
  262. padding: 10px 10px 15px;
  263. box-sizing: border-box;
  264. border-radius: 10px;
  265. margin-bottom: 15px;
  266. }
  267. .clientCharts_title_box {
  268. display: flex;
  269. align-items: center;
  270. justify-content: space-between;
  271. }
  272. .clientCharts_title {
  273. font-weight: 500;
  274. font-size: 12px;
  275. color: #222222;
  276. display: flex;
  277. align-items: center;
  278. margin-bottom: 15px;
  279. }
  280. .clientCharts_title::before {
  281. content: '';
  282. width: 2px;
  283. height: 13px;
  284. background: #1677FF;
  285. border-radius: 1px;
  286. margin-right: 5px;
  287. display: inline-block;
  288. }
  289. .clientCharts_title_right {
  290. font-weight: 400;
  291. font-size: 12px;
  292. color: #1677FF;
  293. text-decoration-line: underline;
  294. margin-bottom: 15px;
  295. }
  296. .all_data {
  297. display: flex;
  298. align-items: center;
  299. flex-wrap: wrap;
  300. margin-top: 15px;
  301. }
  302. .add_data_p {
  303. font-weight: 400;
  304. font-size: 12px;
  305. color: #999999;
  306. padding: 4px 10px;
  307. background: #FFFFFF;
  308. border-radius: 5px;
  309. border: 1px solid #CCCCCC;
  310. margin-top: 0;
  311. margin-right: 15px;
  312. margin-bottom: 10px;
  313. }
  314. .allData_bg {
  315. background: #1677FF;
  316. border-radius: 5px;
  317. border: 1px solid #1677FF;
  318. color: #FFFFFF;
  319. }
  320. /* 选择日期组件开始 */
  321. .select_date {
  322. display: flex;
  323. align-items: center;
  324. }
  325. .date_list {
  326. width: 212px;
  327. box-sizing: border-box;
  328. display: flex;
  329. align-items: center;
  330. justify-content: space-between;
  331. background: #EDF3F8;
  332. border-radius: 20px;
  333. padding: 2px;
  334. }
  335. .filter_time_item {
  336. padding: 4px 0 3px;
  337. font-weight: 400;
  338. font-size: 12px;
  339. color: #222222;
  340. line-height: 17px;
  341. white-space: nowrap;
  342. }
  343. .filter_time1 {
  344. padding-left: 14px;
  345. padding-right: 14px;
  346. }
  347. .filter_time2 {
  348. padding-left: 11px;
  349. padding-right: 11px;
  350. }
  351. .filter_time3 {
  352. padding-left: 7px;
  353. padding-right: 7px;
  354. }
  355. .filter_time4 {
  356. padding-left: 8px;
  357. padding-right: 8px;
  358. }
  359. .current_date {
  360. font-weight: 400;
  361. font-size: 12px;
  362. color: #1677FF;
  363. line-height: 17px;
  364. background: #FFFFFF;
  365. border-radius: 12px;
  366. }
  367. /* 选择日期组件结束 */
  368. .num_item_title {
  369. font-weight: 400;
  370. font-size: 12px;
  371. line-height: 17px;
  372. padding-bottom: 5px;
  373. color: #666666;
  374. }
  375. .num_item_count {
  376. font-weight: bold;
  377. font-size: 16px;
  378. line-height: 24px;
  379. padding-bottom: 5px;
  380. color: #222222;
  381. }
  382. .num_item_data {
  383. display: flex;
  384. align-items: center;
  385. font-weight: 400;
  386. font-size: 10px;
  387. color: #999999;
  388. }
  389. .selected_color {
  390. color: #1677FF;
  391. }
  392. .client_item_icon {
  393. width: 12px;
  394. height: 12px;
  395. }
  396. .branch_table {
  397. overflow-x: auto;
  398. width: 100%;
  399. }
  400. .branch_header {
  401. padding: 10px;
  402. display: flex;
  403. align-items: center;
  404. justify-content: space-between;
  405. background: #F7F9FC;
  406. border-radius: 10px;
  407. font-weight: 500;
  408. font-size: 12px;
  409. color: #222222;
  410. min-width: max-content;
  411. text-align: center;
  412. }
  413. .branch_header div {
  414. min-width: 30px;
  415. }
  416. .branch_item {
  417. padding: 10px;
  418. display: flex;
  419. align-items: center;
  420. justify-content: space-between;
  421. font-weight: 400;
  422. font-size: 12px;
  423. color: #222222;
  424. border-bottom: 1px solid #E5E8ED;
  425. text-align: center;
  426. word-wrap: break-word;
  427. min-width: max-content;
  428. }
  429. .branch_item div {
  430. min-width: 30px;
  431. }
  432. .interact_box_bottom {
  433. display: flex;
  434. align-items: center;
  435. justify-content: space-between;
  436. }
  437. .interact_box_bottom {
  438. display: flex;
  439. align-items: center;
  440. justify-content: space-between;
  441. }
  442. .interact_line {
  443. width: 1px;
  444. /* margin: 0 8px; */
  445. height: 66px;
  446. background: linear-gradient(180deg, rgba(229, 232, 237, 0) 0%, #E5E8ED 51%, rgba(229, 232, 237, 0) 100%);
  447. }
  448. .interact_item {
  449. display: flex;
  450. flex-direction: column;
  451. align-items: center;
  452. text-align: center;
  453. }
  454. .leadGen_box {
  455. padding: 10px;
  456. background: #FAFAFA;
  457. border-radius: 10px;
  458. }
  459. .leadGen_box {
  460. padding: 10px;
  461. background: #FAFAFA;
  462. border-radius: 10px;
  463. }
  464. .table_carList {
  465. width: 100%;
  466. display: flex;
  467. align-items: center;
  468. overflow-x: auto;
  469. margin-bottom: 20px;
  470. }
  471. .table_carBox {
  472. display: flex;
  473. flex-direction: column;
  474. align-items: center;
  475. font-weight: 400;
  476. font-size: 12px;
  477. color: #222222;
  478. border-radius: 34px;
  479. margin-right: 10px;
  480. padding: 0 15px;
  481. }
  482. .table_carBox_bg {
  483. background: linear-gradient(#FFFFFF 0%, #E6F0FF 100%);
  484. }
  485. .table_car {
  486. width: 90px;
  487. height: 45px;
  488. }
  489. .table_carline {
  490. width: 16px;
  491. height: 3px;
  492. border-radius: 34px;
  493. margin-top: 2px;
  494. }
  495. .table_carline_bg {
  496. background: #1677FF;
  497. }
  498. .data_tips {
  499. font-weight: 400;
  500. font-size: 12px;
  501. line-height: 17px;
  502. color: #C4CFDA;
  503. text-align: center;
  504. margin: 5px 0 24px;
  505. }
  506. .step_list {
  507. width: 100%;
  508. display: flex;
  509. align-items: center;
  510. overflow-x: auto;
  511. }
  512. .step_box {
  513. min-width: 125px;
  514. padding: 10px;
  515. font-weight: 400;
  516. font-size: 12px;
  517. color: #666666;
  518. background: #F7F9FC;
  519. border-radius: 10px;
  520. margin-right: 10px;
  521. }
  522. .step_box_bg {
  523. background: #1677FF;
  524. color: #FFFFFF;
  525. }
  526. .step_num {
  527. font-weight: bold;
  528. font-size: 16px;
  529. color: #1677FF;
  530. padding-top: 10px;
  531. line-height: 24px;
  532. }
  533. .step_num_bg {
  534. color: #FFFFFF;
  535. }
  536. .van_loading {
  537. height: 400px;
  538. display: flex;
  539. align-items: center;
  540. justify-content: center;
  541. }
  542. .qwjxs_tabs {
  543. position: fixed;
  544. top: 0;
  545. left: 0;
  546. width: 100%;
  547. z-index: 2;
  548. }
  549. .qwjxs_tabs .van-tabs--line .van-tabs__wrap {
  550. height: 40px;
  551. }
  552. .qwjxs_tabs .van-tab--active {
  553. color: #136DFB !important;
  554. }
  555. .qwjxs_tabs .van-tab {
  556. color: #999999;
  557. }
  558. </style>
  559. <body>
  560. <div id="qwJxs" class="box">
  561. <!-- 数据查看 -->
  562. <div class="page4">
  563. <van-tabs class="qwjxs_tabs" v-model="pageTitle" ref="tabs" color="#136DFB" line-width="18px" line-height="2px" @click="onClickTabs">
  564. <van-tab title="客户资产" name="客户资产"></van-tab>
  565. <van-tab title="聊天分析" name="聊天分析"></van-tab>
  566. <van-tab title="员工监测" name="员工监测"></van-tab>
  567. <van-tab title="运营任务" name="运营任务"></van-tab>
  568. </van-tabs>
  569. <div class="top_data">
  570. <div class="top_data_right" v-if="pageTitle === '客户资产'">
  571. <div class="top_data_title item_gap" @click="showPicker = true">
  572. <div class="top_data_title_branch">网点:{{outletName}}</div>
  573. <div class="triangle"></div>
  574. </div>
  575. <div class="top_data_title" @click="showDeptPicker = true">
  576. <div class="top_data_title_branch">部门:{{deptName}}</div>
  577. <div class="triangle"></div>
  578. </div>
  579. </div>
  580. <select-date v-else :page-date="pageDate" @change-date="handleChangeDate"></select-date>
  581. </div>
  582. <div class="top_data_bottom" v-show="pageTitle !== '客户资产'">
  583. <div class="outlet_data item_gap" @click="showPicker = true">
  584. <div class="top_data_title_branch">网点:{{outletName}}</div>
  585. <div class="triangle"></div>
  586. </div>
  587. <div class="outlet_data" @click="showDeptPicker = true">
  588. <div class="top_data_title_branch">部门:{{deptName}}</div>
  589. <div class="triangle"></div>
  590. </div>
  591. </div>
  592. <!-- <van-popup v-model="showPopup" duration="0.2" closeable position="top" :lock-scroll="false"
  593. :style="{ height: '100vh' }" @close="handleClosePopup">
  594. <div class="popup_list" v-show="!showMer">
  595. <div class="popup_item" @click="handlePage(1)">客户资产</div>
  596. <div class="popup_line"></div>
  597. <div class="popup_item" @click="handlePage(2)">聊天分析</div>
  598. <div class="popup_line"></div>
  599. <div class="popup_item" @click="handlePage(3)">员工监测</div>
  600. <div class="popup_line"></div>
  601. <div class="popup_item" @click="handlePage(4)">运营任务</div>
  602. <div class="popup_line"></div>
  603. <div class="popup_item" @click="showMer = true">切换商户</div>
  604. <div class="popup_line"></div>
  605. <div class="popup_item" @click="handleLoginOut">退出登录</div>
  606. </div>
  607. <div class="popup_list" v-show="showMer">
  608. <div class="mer_item" :class="{'mer_item_active': tenancyId == item.id}" v-for="(item, index) in merList"
  609. :key="index" @click="handleSelectMer(item)">{{item.name}}</div>
  610. </div>
  611. </van-popup> -->
  612. <van-popup v-model="showPicker" duration="0.2" round position="bottom">
  613. <van-picker title="网点" show-toolbar :columns="outletsData" @confirm="onConfirm" @cancel="showPicker = false" />
  614. </van-popup>
  615. <van-popup v-model="showDeptPicker" duration="0.2" round position="bottom">
  616. <van-picker title="部门" show-toolbar :columns="deptData" @confirm="onDeptConfirm"
  617. @cancel="showDeptPicker = false" />
  618. </van-popup>
  619. <!-- 顾问响应统计 -->
  620. <van-popup v-model="showMemberReply" duration="0.2" position="right" :overlay="false" :lock-scroll="false"
  621. :style="{ width: '100%', height: '100vh' }">
  622. <div class="memberReply_title">
  623. <image class="close_icon" src="../img/close.png" @click="closeReply"></image>
  624. <div>顾问响应统计</div>
  625. <div class="close_icon"></div>
  626. </div>
  627. <div class="pop_content">
  628. <div class="select_box">
  629. <van-popover v-model="showDatePicker" trigger="click" close-on-click-action close-on-click-outside
  630. :actions="actions" @select="onSelect">
  631. <template #reference>
  632. <div class="select_day">
  633. <div class="top_data_title_branch">时间:{{timeData}}</div>
  634. <div class="triangle"></div>
  635. </div>
  636. </template>
  637. </van-popover>
  638. <van-search class="search_input" v-model="keyword" search :clearable="false" label="顾问:" left-icon=""
  639. right-icon="search" @search="handleSearch" @click-right-icon="handleSearch"></van-search>
  640. <van-calendar type="range" v-model="showSelfDate" @confirm="onSelfConfirm" color="#1677FF"
  641. :min-date="minDate" :max-date="maxDate" :allow-same-day="true"></van-calendar>
  642. </div>
  643. <div class="box_connect">
  644. <van-loading type="spinner" color="#1989fa" class="van_loading" v-if="loading"></van-loading>
  645. <div class="branch_table" style="margin-bottom: 20px;" v-if="!loading">
  646. <div class="branch_header" style="box-sizing: border-box;">
  647. <div style="width: 80px;">顾问</div>
  648. <div style="width: 50px;">今日处理<br />消息数</div>
  649. <div style="width: 40px;">超时<br />消息数</div>
  650. <div style="width: 50px;">平均响应<br />时间</div>
  651. <div style="width: 30px;">管理</div>
  652. </div>
  653. <div class="branch_item" style="box-sizing: border-box;" v-for="(item, index) in memberReplyData"
  654. :key="index">
  655. <div style="width: 80px;max-width: 80px;">{{item.memberName}}</div>
  656. <div style="width: 50px;">{{item.replyMsg}}</div>
  657. <div style="width: 40px;">{{item.timeoutMsg}}</div>
  658. <div style="width: 50px;">{{formatTime(item.avgReplyDuration)}}</div>
  659. <div style="width: 30px;color: #1677FF;" @click="handleItemMemberReply(item)">详情</div>
  660. </div>
  661. </div>
  662. <van-pagination v-model="currentPage" :total-items="totalItems" :show-page-size="3" force-ellipses
  663. @change="handleChangePage" />
  664. </div>
  665. </div>
  666. </van-popup>
  667. <!-- 顾问响应统计详情 -->
  668. <van-popup v-model="showItemMemberReply" position="right" duration="0.2" :lock-scroll="false" :overlay="false"
  669. :style="{ width: '100%', height: '100vh' }">
  670. <div class="memberReply_title">
  671. <image class="close_icon" src="../img/close.png" @click="closeItemMemberReply"></image>
  672. <div>顾问:{{currentMemberName}}</div>
  673. <div class="close_icon"></div>
  674. </div>
  675. <div class="pop_content">
  676. <div class="select_box">
  677. <van-popover v-model="showDatePicker2" trigger="click" close-on-click-action close-on-click-outside
  678. :actions="actions" @select="onSelect">
  679. <template #reference>
  680. <div class="select_day">
  681. <div class="top_data_title_branch">时间:{{timeData}}</div>
  682. <div class="triangle"></div>
  683. </div>
  684. </template>
  685. </van-popover>
  686. <van-calendar type="range" v-model="showSelfDate" @confirm="onSelfConfirm" color="#1677FF"
  687. :min-date="minDate" :max-date="maxDate" :allow-same-day="true"></van-calendar>
  688. </div>
  689. <div class="box_connect">
  690. <van-loading type="spinner" color="#1989fa" class="van_loading" v-if="loading"></van-loading>
  691. <div class="branch_table" style="margin-bottom: 20px;" v-if="!loading">
  692. <div class="branch_header">
  693. <div style="width: 60px;">客户昵称</div>
  694. <div style="width: 100px;">手机号</div>
  695. <div style="width: 80px;">最新消息<br />时间</div>
  696. <div style="width: 60px;">等待时间</div>
  697. <div style="width: 100px;">最新消息<br />内容</div>
  698. </div>
  699. <div class="branch_item" v-for="(item, index) in memberDetailReplyData" :key="index">
  700. <div style="width: 60px;">{{item.clientName}}</div>
  701. <div style="width: 100px;">{{item.clientPhone}}</div>
  702. <div style="width: 80px;">{{timeFormat(item.msgTime)}}</div>
  703. <div style="width: 60px;">{{formatTime(item.waitSeconds)}}</div>
  704. <div style="width: 100px;">{{item.content}}</div>
  705. </div>
  706. </div>
  707. <van-pagination v-model="currentItemPage" :total-items="itemTotalItems" :show-page-size="3" force-ellipses
  708. @change="handleChangeItemPage" />
  709. </div>
  710. </div>
  711. </van-popup>
  712. <!-- 顾问完成情况统计 -->
  713. <van-popup v-model="showDoneReply" position="right" duration="0.2" :overlay="false" :lock-scroll="false"
  714. :style="{ width: '100%', height: '100vh' }">
  715. <div class="memberReply_title">
  716. <image class="close_icon" src="../img/close.png" @click="closeReply"></image>
  717. <div>顾问完成情况统计</div>
  718. <div class="close_icon"></div>
  719. </div>
  720. <div class="pop_content">
  721. <div class="select_box">
  722. <van-popover v-model="showDatePicker3" trigger="click" close-on-click-action close-on-click-outside
  723. :actions="actions" @select="onSelect">
  724. <template #reference>
  725. <div class="select_day">
  726. <div class="top_data_title_branch">时间:{{timeData}}</div>
  727. <div class="triangle"></div>
  728. </div>
  729. </template>
  730. </van-popover>
  731. <van-calendar type="range" v-model="showSelfDate" @confirm="onSelfConfirm" color="#1677FF"
  732. :min-date="minDate" :max-date="maxDate" :allow-same-day="true"></van-calendar>
  733. </div>
  734. <div class="box_connect">
  735. <div class="branch_table" style="margin-bottom: 20px;">
  736. <div class="branch_header" style="box-sizing: border-box;">
  737. <div style="width: 60px;">顾问</div>
  738. <div style="width: 60px;">网点</div>
  739. <div style="width: 60px;">下发任务数</div>
  740. <div style="width: 60px;">完成任务数</div>
  741. </div>
  742. <div class="branch_item" style="box-sizing: border-box;" v-for="(item, index) in doneReplyData"
  743. :key="index">
  744. <div style="width: 60px;">{{item.memberName}}</div>
  745. <div style="width: 60px;">{{item.outletName}}</div>
  746. <div style="width: 60px;">{{item.taskNum}}</div>
  747. <div style="width: 60px;">{{item.completeNum}}</div>
  748. </div>
  749. </div>
  750. <van-pagination v-model="currentPage" :total-items="totalItems" :show-page-size="3" force-ellipses
  751. @change="handleChangePage" />
  752. </div>
  753. </div>
  754. </van-popup>
  755. <div class="page4_content" v-show="pageTitle === '客户资产'">
  756. <!-- 客户资产 -->
  757. <div class="box_connect">
  758. <div class="clientCharts_title" style="margin-bottom: 0;">总数据
  759. <van-popover style="height: 20px;" v-model="showPopover" trigger="click" theme="dark" placement="right">
  760. <div class="explain_list">
  761. <div>总客户数:添加企微的客户总数</div>
  762. <div>互动客户数:有产生过客户动态(包括不限于内容浏览、活动浏览、聊天等)的客户数</div>
  763. <div>留资报名客户数:填写过表单(含留资/活动报名等)的客户数</div>
  764. <div>到店客户:展厅进店及售后回站客户数</div>
  765. <div>成交客户:已购车的客户数(不含下订客戶)</div>
  766. </div>
  767. <template #reference>
  768. <image class="explain_icon" src="../img/jxs7.png"></image>
  769. </template>
  770. </van-popover>
  771. </div>
  772. <div id="funnelChart" :style="{ width: '100%', height: '200px', marginBottom: '20px' }"></div>
  773. <select-date :page-date="pageDate" @change-date="handleChangeDate"></select-date>
  774. <div class="all_data">
  775. <p class="add_data_p" :class="{'allData_bg': index === 1}" @click="handleClickItem(1)">总客户数</p>
  776. <p class="add_data_p" :class="{'allData_bg': index === 2}" @click="handleClickItem(2)">互动客户数</p>
  777. <p class="add_data_p" :class="{'allData_bg': index === 3}" @click="handleClickItem(3)">留资/报名客户数</p>
  778. <p class="add_data_p" :class="{'allData_bg': index === 4}" @click="handleClickItem(4)">邀约到店客户数</p>
  779. <p class="add_data_p" :class="{'allData_bg': index === 5}" @click="handleClickItem(5)">成交客户数</p>
  780. </div>
  781. <div id="adviserChart" v-if="index === 1" style="width: 100%;height: 200px;"></div>
  782. <div id="labelChart" v-else style="width: 100%;height: 200px;"></div>
  783. </div>
  784. <div class="box_connect">
  785. <div class="clientCharts_title">客群包分布</div>
  786. <div class="table_carList">
  787. <div class="table_carBox" :class="{'table_carBox_bg': carIndex === index}"
  788. v-for="(item, index) in tableList" :key="index" @click="handleClickCar(item, index)">
  789. <image class="table_car" :src="item.carModelImg"></image>
  790. <div>{{item.carModel}}</div>
  791. <div class="table_carline" :class="{'table_carline_bg': carIndex === index}"></div>
  792. </div>
  793. </div>
  794. <div class="branch_table" v-if="carStepData.length > 0">
  795. <div class="branch_header">
  796. <div style="width: 40px;">阶段</div>
  797. <div style="width: 60px;" v-for="(item, index) in carStepData[0].packageList[0].cols" :key="index">
  798. {{item.name}}
  799. </div>
  800. </div>
  801. <div class="branch_item" v-for="(item, index) in carStepData[0].packageList" :key="index">
  802. <div style="width: 40px;">{{item.stepName}}</div>
  803. <!-- 此处先循环carStepData[0].packageList[0].cols,是表格头以第一条数据为准 -->
  804. <div style="min-width: 60px;" v-for="(val, valIndex) in carStepData[0].packageList[0].cols"
  805. :key="valIndex">
  806. <span style="min-width: 60px;" v-for="(col, colIndex) in item.cols" :key="colIndex">
  807. {{val.name === col.name ? col.value[0] : ''}}
  808. </span>
  809. </div>
  810. </div>
  811. </div>
  812. </div>
  813. <div class="box_connect">
  814. <div class="clientCharts_title">意向车型标签排名</div>
  815. <div id="intentRankChart" style="width: 100%;height: 100%;"></div>
  816. </div>
  817. <div class="box_connect">
  818. <div class="clientCharts_title">已购车型标签排名</div>
  819. <div id="buyRankChart" style="width: 100%;height: 100%;"></div>
  820. </div>
  821. <div class="data_tips">—— 每日5:00更新数据 ——</div>
  822. </div>
  823. <div class="page4_content2" v-show="pageTitle === '聊天分析'">
  824. <!-- 聊天分析 -->
  825. <div class="box_connect">
  826. <div class="clientCharts_title">总数据</div>
  827. <div class="leadGen_box">
  828. <div class="interact_box_bottom">
  829. <div class="interact_item">
  830. <div class="num_item_title">私聊客户数</div>
  831. <div class="num_item_count">{{chatIndicators.total.privateChat}}</div>
  832. <div class="num_item_data">
  833. <div>昨日新增:
  834. <span class="selected_color">{{chatIndicators.yda.privateChat}}</span>
  835. </div>
  836. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  837. </div>
  838. </div>
  839. <div class="interact_line"></div>
  840. <div class="interact_item">
  841. <div class="num_item_title">私聊消息数</div>
  842. <div class="num_item_count">{{chatIndicators.total.privateMsgNum}}</div>
  843. <div class="num_item_data">
  844. <div>昨日新增:
  845. <span class="selected_color">{{chatIndicators.yda.privateMsgNum}}</span>
  846. </div>
  847. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  848. </div>
  849. </div>
  850. <div class="interact_line"></div>
  851. <div class="interact_item">
  852. <div class="num_item_title">群消息数</div>
  853. <div class="num_item_count">{{chatIndicators.total.groupMsgNum}}</div>
  854. <div class="num_item_data">
  855. <div>昨日新增:
  856. <span class="selected_color">{{chatIndicators.yda.groupMsgNum}}</span>
  857. </div>
  858. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  859. </div>
  860. </div>
  861. </div>
  862. </div>
  863. <div id="interactChart" style="width: 100%;height: 200px"></div>
  864. </div>
  865. <div class="box_connect">
  866. <div class="clientCharts_title">员工服务</div>
  867. <div class="leadGen_box">
  868. <div class="interact_box_bottom">
  869. <div class="interact_item">
  870. <div class="num_item_title">主动服务会话数</div>
  871. <div class="num_item_count">{{chatIndicators.total.proactiveServe}}</div>
  872. <div class="num_item_data">
  873. <div>昨日新增:
  874. <span class="selected_color">{{chatIndicators.yda.proactiveServe}}</span>
  875. </div>
  876. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  877. </div>
  878. </div>
  879. <div class="interact_line"></div>
  880. <div class="interact_item">
  881. <div class="num_item_title">客户回复会话数</div>
  882. <div class="num_item_count">{{chatIndicators.total.clientReply}}</div>
  883. <div class="num_item_data">
  884. <div>昨日新增:
  885. <span class="selected_color">{{chatIndicators.yda.clientReply}}</span>
  886. </div>
  887. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  888. </div>
  889. </div>
  890. <div class="interact_line"></div>
  891. <div class="interact_item">
  892. <div class="num_item_title">客户回复率</div>
  893. <div class="num_item_count">{{chatIndicators.total.clientReplyPercent ?
  894. chatIndicators.total.clientReplyPercent + '%' : ''}}</div>
  895. <div class="num_item_data">
  896. <div>较昨日:
  897. <span v-if="chatIndicators.yda.clientReplyPercent" class="selected_color"
  898. :style="{color: chatIndicators.yda.clientReplyPercent > 0 ? '#1677FF' : '#FF4E4E'}">
  899. {{chatIndicators.yda.clientReplyPercent > 0 ? '+' :
  900. ''}}{{chatIndicators.yda.clientReplyPercent}}%</span>
  901. </div>
  902. <image class="client_item_icon" v-if="chatIndicators.yda.clientReplyPercent"
  903. :src="chatIndicators.yda.clientReplyPercent > 0 ? '../img/jxs-up1.png' : '../img/jxs-down2.png'">
  904. </image>
  905. </div>
  906. </div>
  907. </div>
  908. </div>
  909. <div id="staffChart" style="width: 100%;height: 200px"></div>
  910. </div>
  911. <div class="box_connect">
  912. <div class="clientCharts_title">客户咨询</div>
  913. <div class="leadGen_box">
  914. <div class="interact_box_bottom">
  915. <div class="interact_item">
  916. <div class="num_item_title">主动咨询会话数</div>
  917. <div class="num_item_count">{{chatIndicators.total.proactiveConsult}}</div>
  918. <div class="num_item_data">
  919. <div>昨日新增:
  920. <span class="selected_color">{{chatIndicators.yda.proactiveConsult}}</span>
  921. </div>
  922. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  923. </div>
  924. </div>
  925. <div class="interact_line"></div>
  926. <div class="interact_item">
  927. <div class="num_item_title">员工回复会话数</div>
  928. <div class="num_item_count">{{chatIndicators.total.memberReply}}</div>
  929. <div class="num_item_data">
  930. <div>昨日新增:
  931. <span class="selected_color">{{chatIndicators.yda.memberReply}}</span>
  932. </div>
  933. <image class="client_item_icon" src="../img/jxs-up1.png"></image>
  934. </div>
  935. </div>
  936. <div class="interact_line"></div>
  937. <div class="interact_item">
  938. <div class="num_item_title">员工平均响应时长</div>
  939. <div class="num_item_count">{{chatIndicators.total.avgReplyDuration ?
  940. formatTime(chatIndicators.total.avgReplyDuration) : ''}}</div>
  941. <div class="num_item_data">
  942. <div>较昨日:
  943. <span v-if="chatIndicators.yda.avgReplyDuration" class="selected_color"
  944. :style="{color: chatIndicators.yda.avgReplyDuration > 0 ? '#FF4E4E' : '#1677FF'}">
  945. {{chatIndicators.yda.avgReplyDuration > 0 ? '+' :
  946. ''}}{{formatTime(chatIndicators.yda.avgReplyDuration)}}</span>
  947. </div>
  948. <image class="client_item_icon" v-if="chatIndicators.yda.avgReplyDuration"
  949. :src="chatIndicators.yda.avgReplyDuration > 0 ? '../img/jxs-up2.png' : '../img/jxs-down1.png'">
  950. </image>
  951. </div>
  952. </div>
  953. </div>
  954. </div>
  955. <div id="clientChart" style="width: 100%;height: 200px"></div>
  956. </div>
  957. <div class="box_connect">
  958. <div class="clientCharts_title">消息舆情分析</div>
  959. <div id="opinionChart" style="width: 100%;height: 380px"></div>
  960. </div>
  961. <div class="box_connect">
  962. <div class="clientCharts_title">客户关注词云图</div>
  963. <div id="wordCloudChart" style="width: 100%;height: 200px"></div>
  964. </div>
  965. <div class="data_tips">—— 每日5:00更新数据 ——</div>
  966. </div>
  967. <div class="page4_content2" v-show="pageTitle === '员工监测'">
  968. <div class="box_connect">
  969. <div class="clientCharts_title">销售进程客户数</div>
  970. <div class="step_list">
  971. <div class="step_box" :class="{'step_box_bg': clientIndex === index}"
  972. v-for="(item, index) in saleIndicators" :key="index" @click="handleClickClient(item, index)">
  973. <div>{{item.processName}}</div>
  974. <div class="step_num" :class="{'step_num_bg': clientIndex === index}">{{item.clientNum}}</div>
  975. </div>
  976. </div>
  977. <div id="clientStepChart" style="width: 100%;height: 200px"></div>
  978. </div>
  979. <div class="box_connect">
  980. <div class="clientCharts_title">销售统计排名</div>
  981. <div class="branch_table" v-if="saleRankData.length > 0">
  982. <div class="branch_header">
  983. <div style="width: 30px;">排名</div>
  984. <div style="width: 80px;">顾问</div>
  985. <div style="width: 40px;">网点</div>
  986. <div style="width: 60px;" v-for="(item, index) in saleRankData[0].cols" :key="index">
  987. {{item.name}}
  988. </div>
  989. </div>
  990. <div class="branch_item" v-for="(item, index) in saleRankData" :key="index">
  991. <div style="width: 30px;">{{index + 1}}</div>
  992. <div style="width: 80px;max-width: 80px;">{{item.memberName}}</div>
  993. <div style="width: 40px;">{{item.outletName}}</div>
  994. <!-- 此处先循环saleRankData[0].cols,是表格头以第一条数据为准 -->
  995. <div style="min-width: 60px;" v-for="(val, valIndex) in saleRankData[0].cols" :key="valIndex">
  996. <span style="min-width: 60px;" v-for="(col, colIndex) in item.cols" :key="colIndex">
  997. {{val.name === col.name ? (col.value ? col.value[0] : '-') : ''}}
  998. </span>
  999. </div>
  1000. </div>
  1001. </div>
  1002. </div>
  1003. <div class="box_connect">
  1004. <div class="clientCharts_title_box">
  1005. <div class="clientCharts_title">聊天超时监测</div>
  1006. <div class="clientCharts_title_right" @click="handleMemberReply">查看详情</div>
  1007. </div>
  1008. <div id="timeOutTrendChart" style="width: 100%;height: 230px"></div>
  1009. </div>
  1010. <div class="box_connect">
  1011. <div class="clientCharts_title">聊天排行榜</div>
  1012. <div class="branch_table">
  1013. <div class="branch_header" style="box-sizing: border-box;">
  1014. <div style="width: 30px;">排名</div>
  1015. <div style="width: 80px;">员工</div>
  1016. <div style="width: 50px;">聊天客户数</div>
  1017. <div style="width: 50px;">主动会话<br />服务数</div>
  1018. <div style="width: 50px;">客户回复<br />会话数</div>
  1019. </div>
  1020. <div class="branch_item" style="box-sizing: border-box;" v-for="(item, index) in chatRankData" :key="index">
  1021. <div style="width: 30px;">{{index + 1}}</div>
  1022. <div style="width: 80px;max-width: 80px;">{{item.memberName}}</div>
  1023. <div style="width: 50px;">{{item.privateChat}}</div>
  1024. <div style="width: 50px;">{{item.proactiveServe}}</div>
  1025. <div style="width: 50px;">{{item.clientReply}}</div>
  1026. </div>
  1027. </div>
  1028. </div>
  1029. <div class="data_tips">—— 每日5:00更新数据 ——</div>
  1030. </div>
  1031. <div class="page4_content2" v-show="pageTitle === '运营任务'">
  1032. <div class="box_connect">
  1033. <div class="clientCharts_title_box">
  1034. <div class="clientCharts_title">总数据</div>
  1035. <div class="clientCharts_title_right" @click="handleDoneReply">查看更多</div>
  1036. </div>
  1037. <div class="branch_table">
  1038. <div class="branch_header" style="box-sizing: border-box;">
  1039. <div style="width: 60px;">网点</div>
  1040. <div style="width: 60px;">下发任务数</div>
  1041. <div style="width: 60px;">任务完成率</div>
  1042. <div style="width: 60px;">互动客户数</div>
  1043. <div>激活率</div>
  1044. </div>
  1045. <div class="branch_item" style="box-sizing: border-box;" v-for="(item, index) in outletCount" :key="index">
  1046. <div style="width: 60px;">{{item.outletName}}</div>
  1047. <div style="width: 60px;">{{item.taskNum}}</div>
  1048. <div style="width: 60px;">{{item.taskCompletePercent ? item.taskCompletePercent + '%' : '-'}}</div>
  1049. <div style="width: 60px;">{{item.interactClient}}</div>
  1050. <div>{{item.activatePercent ? item.activatePercent + '%' : '-'}}</div>
  1051. </div>
  1052. </div>
  1053. </div>
  1054. <div class="box_connect">
  1055. <div class="clientCharts_title">任务完成率</div>
  1056. <div id="taskCompleteChart" style="width: 100%;height: 200px"></div>
  1057. </div>
  1058. <div class="box_connect">
  1059. <div class="clientCharts_title">互动客户数</div>
  1060. <div id="opInteractChart" style="width: 100%;height: 200px"></div>
  1061. </div>
  1062. <div class="box_connect">
  1063. <div class="clientCharts_title">素材排行榜</div>
  1064. <div id="contentRank" style="width: 100%;"></div>
  1065. </div>
  1066. <div class="data_tips">—— 每日5:00更新数据 ——</div>
  1067. </div>
  1068. </div>
  1069. </div>
  1070. </body>
  1071. <script>
  1072. new Vue({
  1073. el: '#qwJxs',
  1074. data() {
  1075. return {
  1076. httpUrl: '',
  1077. bId: null,
  1078. env: '',
  1079. jxsName: '',
  1080. token: '',
  1081. tenancyId: '',
  1082. showPopup: false,
  1083. showMer: false,
  1084. showDatePicker: false,
  1085. showDatePicker2: false,
  1086. showDatePicker3: false,
  1087. actions: [
  1088. { text: '昨日' }, { text: '近7天' }, { text: '近30天' }, { text: '自定义' }
  1089. ],
  1090. keyword: '',
  1091. showSelfDate: false,
  1092. minDate: '',
  1093. maxDate: '',
  1094. merList: [], // 商户列表
  1095. outletsList: [], // 网点列表
  1096. outletsData: [], // 网点列表数据
  1097. deptList: [], // 部门列表
  1098. deptData: [], // 部门列表数据
  1099. pageTitle: '客户资产',
  1100. showPicker: false, // 网点选择器
  1101. showDeptPicker: false, // 部门选择器
  1102. deptName: '', // 部门名称
  1103. deptId: null, // 部门id
  1104. outletName: '', // 网点名称
  1105. outletId: null, // 网点id
  1106. clientIndicators: [], // 客户资产-总数据
  1107. pageStartTime: '',
  1108. pageEndTime: '',
  1109. index: 1,
  1110. showPopover: false,
  1111. lineDate: [], // 客户资产-统计趋势图
  1112. saleAdd: [],
  1113. serveAdd: [],
  1114. interactClient: [],
  1115. formClient: [],
  1116. storeClient: [],
  1117. dealClient: [],
  1118. tableList: [], // 客群包阶段车型
  1119. carIndex: 0,
  1120. carStepData: [], // 客群包阶段车型数据
  1121. intentRankData: [], // 意向车型标签排名
  1122. buyRankData: [], // 已购车型标签排名
  1123. chatIndicators: {
  1124. dayList: [], // 聊天分析-日数据
  1125. opinion: {},
  1126. total: {
  1127. privateChat: 0,
  1128. privateMsgNum: 0,
  1129. groupMsgNum: 0,
  1130. proactiveServe: 0,
  1131. clientReply: 0,
  1132. clientReplyPercent: 0,
  1133. proactiveConsult: 0,
  1134. memberReply: 0,
  1135. avgReplyDuration: 0,
  1136. },
  1137. yda: {
  1138. privateChat: 0,
  1139. privateMsgNum: 0,
  1140. groupMsgNum: 0,
  1141. proactiveServe: 0,
  1142. clientReply: 0,
  1143. clientReplyPercent: 0,
  1144. proactiveConsult: 0,
  1145. memberReply: 0,
  1146. avgReplyDuration: 0,
  1147. },
  1148. },
  1149. interactDate: [], // 聊天分析-总数据图数据
  1150. privateChat: [],
  1151. privateMsgNum: [],
  1152. groupMsgNum: [],
  1153. proactiveServe: [],
  1154. clientReply: [],
  1155. clientReplyPercent: [],
  1156. proactiveConsult: [],
  1157. memberReply: [],
  1158. showItemMemberReply: false, // 显示客户详情响应数据
  1159. currentMemberName: '', // 当前客户名称
  1160. memberId: '', // 当前客户id
  1161. memberDetailReplyData: [], // 客户详情响应数据
  1162. currentItemPage: 1, // 当前客户详情响应数据页码
  1163. itemTotalItems: 0, // 客户详情响应数据总页数
  1164. avgReplyDuration: [],
  1165. totalMsg: [],
  1166. privateMsg: [],
  1167. groupMsg: [],
  1168. maxValue: null,
  1169. wordCloudMap: [], // 客户关注词云图
  1170. saleIndicators: [], // 销售进程客户数
  1171. clientIndex: 0, // 销售进程客户数索引
  1172. clientStepDate: [], // 销售进程客户数-日期
  1173. clientStepNum: [], // 销售进程客户数-客户数
  1174. saleRankData: [], // 销售统计排名数据
  1175. timeOutDate: [], // 聊天超时监测-日期
  1176. timeoutMember: [], // 聊天超时监测-超时客户数
  1177. timeData: '',
  1178. memberStartTime: '',
  1179. memberEndTime: '',
  1180. showDoneReply: false, // 显示已完成响应数据
  1181. doneReplyData: [], // 已完成响应数据
  1182. showMemberReply: false,
  1183. currentPage: 1,
  1184. totalItems: 0,
  1185. memberReplyData: [], // 顾问响应统计数据
  1186. chatRankData: [], // 聊天排行榜数据
  1187. outletCount: [], // 运营任务-总数据
  1188. taskCompleteDate: [], // 运营任务-任务完成率-日期
  1189. taskCompletePercent: [], // 运营任务-任务完成率
  1190. opInteractDate: [], // 运营任务-互动客户数-日期
  1191. opInteractClient: [], // 运营任务-互动客户数
  1192. contentRankData: [], // 运营任务-素材排行榜
  1193. loading: false,
  1194. pageDate: [], // 日期范围
  1195. }
  1196. },
  1197. created() {
  1198. let nowDat = new Date();
  1199. let dateY = nowDat.getFullYear()
  1200. let dateM = nowDat.getMonth()
  1201. let dateD = nowDat.getDate()
  1202. // 设置日期可选最小值minDate、最大值maxDate
  1203. this.minDate = new Date(dateY - 1, dateM, dateD)
  1204. //日历可选范围为一年,dateY + 1
  1205. this.maxDate = new Date(dateY, dateM, dateD - 1)
  1206. this.bId = this.getQueryParam('bId')
  1207. this.env = this.getQueryParam('env')
  1208. if (!this.env || this.env === 'prod') {
  1209. this.httpUrl = 'https://wlapi.wefanbot.com'
  1210. // this.httpUrl = 'http://192.168.1.128:18993'
  1211. } else {
  1212. this.httpUrl = 'http://test.wefanbot.com:18993'
  1213. // this.httpUrl = 'http://192.168.1.128:18993'
  1214. }
  1215. this.token = localStorage.getItem('tokenValue')
  1216. this.tenancyId = localStorage.getItem('tenancyIdValue')
  1217. this.jxsName = localStorage.getItem('tenancyNameValue') || ''
  1218. this.pageStartTime = this.getDateTime(-7)
  1219. this.pageEndTime = this.getDateTime(-1)
  1220. this.memberStartTime = this.getDateTime(-7)
  1221. this.memberEndTime = this.getDateTime(-1)
  1222. this.initialization()
  1223. this.getAdminList()
  1224. },
  1225. methods: {
  1226. onClickTabs(name) {
  1227. this.pageTitle = name
  1228. this.requestData()
  1229. },
  1230. // 初始化
  1231. initialization() {
  1232. this.clientIndicators = []
  1233. this.pageStartTime = this.getDateTime(-7)
  1234. this.pageEndTime = this.getDateTime(-1)
  1235. this.index = 1
  1236. this.outletName = ''
  1237. this.outletId = null
  1238. this.getOutletsData()
  1239. this.deptName = ''
  1240. this.deptId = null
  1241. this.getDeptData() // 部门列表数据
  1242. },
  1243. requestData() {
  1244. if (this.pageTitle === '客户资产') {
  1245. this.getClientIndicators() // 客户资产-总数据
  1246. this.getTrend() // 客户资产-统计趋势图
  1247. this.stepStatistic() // 客户资产-客群包分布
  1248. this.getIntentRank() // 意向车型标签排名
  1249. this.getBuyRank() // 已购车型标签排名
  1250. this.$nextTick(() => {
  1251. this.funnelDraw()
  1252. this.passValue()
  1253. this.intentRankChart()
  1254. this.buyRankChart()
  1255. })
  1256. } else if (this.pageTitle === '聊天分析') {
  1257. this.handlePage(2)
  1258. this.$nextTick(() => {
  1259. this.interactChart()
  1260. this.staffChart()
  1261. this.clientChart()
  1262. this.opinionChart()
  1263. this.wordCloudChart()
  1264. })
  1265. } else if (this.pageTitle === '员工监测') {
  1266. this.handlePage(3)
  1267. this.$nextTick(() => {
  1268. this.clientStepChart()
  1269. this.timeOutTrendChart()
  1270. })
  1271. } else if (this.pageTitle === '运营任务') {
  1272. this.handlePage(4)
  1273. this.$nextTick(() => {
  1274. this.taskCompleteChart()
  1275. this.opInteractChart()
  1276. this.contentRankChart()
  1277. })
  1278. }
  1279. },
  1280. // 获取商户列表(右上角)
  1281. getAdminList() {
  1282. const headers = new Headers()
  1283. headers.append('token', this.token)
  1284. fetch(this.httpUrl + `/scrm/v1/user-info/o/adminList`, {
  1285. method: 'GET',
  1286. headers: headers
  1287. }).then(res => {
  1288. return res.json()
  1289. }).then(result => {
  1290. let { data, code, msg } = result
  1291. if (code === 1) {
  1292. this.merList = data || []
  1293. } else if (code === 10001) {
  1294. this.loginOut()
  1295. } else {
  1296. vant.Toast.fail(msg)
  1297. }
  1298. })
  1299. },
  1300. // 获取网点列表
  1301. getOutletsData() {
  1302. const headers = new Headers()
  1303. headers.append('token', this.token)
  1304. headers.append('tenancyId', this.tenancyId)
  1305. this.outletsList = []
  1306. this.outletsData = []
  1307. fetch(this.httpUrl + `/scrm/v1/tenancy-outlet/options`, {
  1308. method: 'GET',
  1309. headers: headers
  1310. }).then(res => {
  1311. return res.json()
  1312. }).then(result => {
  1313. let { data, code, msg } = result
  1314. if (code === 1) {
  1315. this.outletsList = data || []
  1316. this.outletsData = data && data.length > 0 ? data.map(item => item.name) : []
  1317. } else if (code === 10001) {
  1318. this.loginOut()
  1319. } else {
  1320. vant.Toast.fail(msg)
  1321. }
  1322. }).finally(() => {
  1323. if (this.outletsList.length === 1) {
  1324. this.outletName = this.outletsData[0]
  1325. this.outletId = this.outletsList.find(item => item.name === this.outletName).id || null
  1326. } else if (this.outletsList.length === 0 || this.outletsList.length > 1) {
  1327. this.outletsData.unshift('全部')
  1328. this.outletName = '全部'
  1329. this.outletId = null
  1330. }
  1331. this.requestData()
  1332. })
  1333. },
  1334. // 获取网点列表
  1335. getDeptData() {
  1336. const headers = new Headers()
  1337. headers.append('token', this.token)
  1338. headers.append('tenancyId', this.tenancyId)
  1339. this.deptList = []
  1340. this.deptData = []
  1341. fetch(this.httpUrl + `/scrm/v1/tenancy-outlet-department/options`, {
  1342. method: 'post',
  1343. body: JSON.stringify({
  1344. outletIds: this.outletId ? [this.outletId] : []
  1345. }),
  1346. headers: {
  1347. 'Content-Type': 'application/json',
  1348. 'token': this.token,
  1349. 'tenancyId': this.tenancyId
  1350. }
  1351. }).then(res => {
  1352. return res.json()
  1353. }).then(result => {
  1354. let { data, code, msg } = result
  1355. if (code === 1) {
  1356. this.deptList = data || []
  1357. this.deptData = data && data.length > 0 ? data.map(item => item.name) : []
  1358. } else if (code === 10001) {
  1359. this.loginOut()
  1360. } else {
  1361. vant.Toast.fail(msg)
  1362. }
  1363. }).finally(() => {
  1364. if (this.deptList.length === 1) {
  1365. this.deptName = this.deptData[0]
  1366. this.deptId = this.deptList.find(item => item.name === this.deptName).id || null
  1367. } else if (this.deptList.length === 0 || this.deptList.length > 1) {
  1368. this.deptData.unshift('全部')
  1369. this.deptName = '全部'
  1370. this.deptId = null
  1371. }
  1372. })
  1373. },
  1374. onConfirm(val) {
  1375. this.outletName = val
  1376. if (this.outletName === '全部') {
  1377. this.outletId = null
  1378. } else {
  1379. this.outletId = this.outletsList.find(item => item.name === this.outletName).id || null
  1380. }
  1381. this.showPicker = false
  1382. this.deptId = null
  1383. this.deptName = '全部'
  1384. this.getDeptData()
  1385. if (this.pageTitle === '客户资产') {
  1386. this.getClientIndicators() // 客户资产-总数据
  1387. this.getTrend() // 客户资产-统计趋势图
  1388. this.stepStatistic() // 客户资产-客群包分布
  1389. this.getIntentRank() // 意向车型标签排名
  1390. this.getBuyRank() // 已购车型标签排名
  1391. } else if (this.pageTitle === '聊天分析') {
  1392. this.handlePage(2)
  1393. } else if (this.pageTitle === '员工监测') {
  1394. this.handlePage(3)
  1395. } else if (this.pageTitle === '运营任务') {
  1396. this.handlePage(4)
  1397. }
  1398. },
  1399. onDeptConfirm(val) {
  1400. this.deptName = val
  1401. if (this.deptName === '全部') {
  1402. this.deptId = null
  1403. } else {
  1404. this.deptId = this.deptList.find(item => item.name === this.deptName).id || null
  1405. }
  1406. this.showDeptPicker = false
  1407. if (this.pageTitle === '客户资产') {
  1408. this.getClientIndicators() // 客户资产-总数据
  1409. this.getTrend() // 客户资产-统计趋势图
  1410. this.stepStatistic() // 客户资产-客群包分布
  1411. this.getIntentRank() // 意向车型标签排名
  1412. this.getBuyRank() // 已购车型标签排名
  1413. } else if (this.pageTitle === '聊天分析') {
  1414. this.handlePage(2)
  1415. } else if (this.pageTitle === '员工监测') {
  1416. this.handlePage(3)
  1417. } else if (this.pageTitle === '运营任务') {
  1418. this.handlePage(4)
  1419. }
  1420. },
  1421. handlePage(index) {
  1422. switch (index) {
  1423. case 1:
  1424. this.pageTitle = '客户资产'
  1425. this.initialization()
  1426. break
  1427. case 2:
  1428. this.pageTitle = '聊天分析'
  1429. this.getChatIndicators() // 聊天分析 - 总数据
  1430. this.getWordCloudMap() // 聊天分析 - 词云图
  1431. break
  1432. case 3:
  1433. this.pageTitle = '员工监测'
  1434. this.getSaleIndicators() // 员工监测 - 销售进程
  1435. this.getSaleRank() // 员工监测 - 销售统计排名
  1436. this.getTimeOutTrendChart() // 员工监测 - 聊天超时监测
  1437. this.getChatRank() // 员工监测 - 聊天统计排名
  1438. break
  1439. case 4:
  1440. this.pageTitle = '运营任务'
  1441. this.getOutletCount() // 运营任务 - 总数据
  1442. this.getTaskCompleteChart() // 运营任务 - 任务完成率
  1443. this.getOpInteractChart() // 运营任务 - 互动客户数
  1444. this.getContentRank() // 运营任务 - 素材排行榜
  1445. break
  1446. }
  1447. this.showPopup = false
  1448. },
  1449. // 客户资产-总数据
  1450. getClientIndicators() {
  1451. this.clientIndicators = []
  1452. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/clientIndicators`, {
  1453. method: 'post',
  1454. body: JSON.stringify({
  1455. outletId: this.outletId,
  1456. departmentIds: this.deptId ? [this.deptId] : []
  1457. }),
  1458. headers: {
  1459. 'Content-Type': 'application/json',
  1460. 'token': this.token,
  1461. 'tenancyId': this.tenancyId
  1462. }
  1463. }).then(res => {
  1464. return res.json()
  1465. }).then(result => {
  1466. let { data, code, msg } = result
  1467. if (code === 1) {
  1468. this.clientIndicators = data.reverse() || []
  1469. this.$nextTick(() => {
  1470. this.funnelDraw()
  1471. })
  1472. } else if (code === 10001) {
  1473. this.loginOut()
  1474. } else {
  1475. vant.Toast.fail(msg)
  1476. }
  1477. })
  1478. },
  1479. // 客户资产-总数据(梯形图)
  1480. funnelDraw() {
  1481. let clientIndicators = this.clientIndicators
  1482. let funnelChart = echarts.getInstanceByDom(document.getElementById('funnelChart'))
  1483. if (funnelChart == null) {
  1484. funnelChart = echarts.init(document.getElementById('funnelChart'))
  1485. }
  1486. window.addEventListener('resize', function () {
  1487. funnelChart.resize()
  1488. })
  1489. funnelChart.setOption({
  1490. tooltip: {
  1491. trigger: 'item',
  1492. formatter(param) {
  1493. let label = ''
  1494. clientIndicators.forEach(item => {
  1495. if (item.name === param.data.name) {
  1496. label = item.value
  1497. }
  1498. })
  1499. return param.data.name + ':' + label
  1500. }
  1501. },
  1502. series: [
  1503. {
  1504. type: 'funnel',
  1505. min: 0,
  1506. max: 100,
  1507. width: '50%',
  1508. minSize: '0%', //漏斗最小值的宽度
  1509. maxSize: '100%', //漏斗最大值的宽度
  1510. left: '0%',
  1511. right: '8%',
  1512. top: '8%',
  1513. bottom: '2%',
  1514. gap: 2,
  1515. label: {
  1516. show: false,
  1517. position: 'inside',
  1518. color: '#fff',
  1519. },
  1520. data: clientIndicators.map((item, index) => {
  1521. return {
  1522. value: 40 + (index + 1) * 10,
  1523. name: item.name,
  1524. itemStyle: {
  1525. color: `hsl(215, 100%, ${54 + index * 8}%)`
  1526. },
  1527. }
  1528. })
  1529. },
  1530. {
  1531. type: 'funnel',
  1532. label: {
  1533. position: 'right',
  1534. lineHeight: 20,
  1535. padding: [0, 0, 0, 10],
  1536. formatter: function (param) {
  1537. let label = ''
  1538. let percent = ''
  1539. let showPercent = true; // 默认显示占比
  1540. clientIndicators.forEach(item => {
  1541. if (item.name === param.data.name) {
  1542. label = item.value
  1543. percent = item.percent
  1544. }
  1545. });
  1546. // 特殊处理长文本换行
  1547. const secondLineText = label
  1548. ? `${label}人`
  1549. : (['到店客户', '成交客户'].includes(param.data.name)
  1550. ? '待ONE-ID\n数据打通' // 手动插入换行符
  1551. : '');
  1552. // 关键修改:当显示特殊文本时隐藏占比行
  1553. if (['到店客户', '成交客户'].includes(param.data.name) && !label) {
  1554. showPercent = false;
  1555. }
  1556. const lines = [];
  1557. lines.push(`{firstLine|${param.data.name}:}{secondLine|${secondLineText}}`);
  1558. // 只有需要显示占比时才添加第三行
  1559. if (showPercent) {
  1560. lines.push(`{thirdLine|占比:${percent ? percent + '%' : ''}}`);
  1561. }
  1562. return lines.join('\n');
  1563. },
  1564. // 新增 rich 样式定义
  1565. rich: {
  1566. firstLine: {
  1567. color: '#899EB2', // 第一行颜色
  1568. fontSize: 12, // 第一行字号
  1569. lineHeight: 20 // 保持与外层 lineHeight 一致
  1570. },
  1571. secondLine: {
  1572. color: '#1677FF',
  1573. fontWeight: 'bold',
  1574. fontSize: 14,
  1575. lineHeight: 20,
  1576. width: 150, // 关键:限制宽度触发自动换行
  1577. overflow: 'break', // 允许文本换行
  1578. },
  1579. thirdLine: {
  1580. color: '#1677FF', // 第二行颜色(示例用红色)
  1581. fontSize: 10, // 第二行字号
  1582. lineHeight: 10, // 保持与外层 lineHeight 一致
  1583. }
  1584. }
  1585. },
  1586. labelLine: {
  1587. show: true,
  1588. length: 40, // label拉线的长度根据自己的场景进行设置即可
  1589. lineStyle: {
  1590. width: 1,
  1591. type: 'solid'
  1592. }
  1593. },
  1594. min: 0,
  1595. max: 100,
  1596. minSize: '0%',
  1597. maxSize: 0,
  1598. left: '-20%',
  1599. right: '8%',
  1600. top: '10%',
  1601. bottom: '2%',
  1602. z: 1,
  1603. gap: 2,
  1604. data: clientIndicators.map((item, index) => {
  1605. return {
  1606. value: 40 + (index + 1) * 10,
  1607. name: item.name,
  1608. itemStyle: {
  1609. color: `hsl(215, 100%, ${54 + index * 8}%)`
  1610. },
  1611. }
  1612. })
  1613. }
  1614. ]
  1615. }, true)
  1616. },
  1617. // 切换日期范围
  1618. handleChangeDate(date) {
  1619. this.pageStartTime = date[0]
  1620. this.pageEndTime = date[1]
  1621. this.pageDate = date
  1622. if (this.pageTitle === '客户资产') {
  1623. this.getTrend() // 客户资产-统计趋势图
  1624. } else if (this.pageTitle === '聊天分析') {
  1625. this.handlePage(2)
  1626. } else if (this.pageTitle === '员工监测') {
  1627. this.handlePage(3)
  1628. } else if (this.pageTitle === '运营任务') {
  1629. this.handlePage(4)
  1630. }
  1631. },
  1632. // 客户资产-统计趋势图
  1633. getTrend() {
  1634. this.lineDate = []
  1635. this.saleAdd = []
  1636. this.serveAdd = []
  1637. this.interactClient = []
  1638. this.formClient = []
  1639. this.storeClient = []
  1640. this.dealClient = []
  1641. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/trend`, {
  1642. method: 'post',
  1643. body: JSON.stringify({
  1644. outletId: this.outletId,
  1645. departmentIds: this.deptId ? [this.deptId] : [],
  1646. startTime: this.pageStartTime,
  1647. endTime: this.pageEndTime,
  1648. }),
  1649. headers: {
  1650. 'Content-Type': 'application/json',
  1651. 'token': this.token,
  1652. 'tenancyId': this.tenancyId
  1653. }
  1654. }).then(res => {
  1655. return res.json()
  1656. }).then(result => {
  1657. let { data, code, msg } = result
  1658. if (code === 1) {
  1659. if (data && data.length > 0) {
  1660. data.forEach(item => {
  1661. this.lineDate.push(item.time)
  1662. this.saleAdd.push(item.saleAdd)
  1663. this.serveAdd.push(item.serveAdd)
  1664. this.interactClient.push(item.interactClient)
  1665. this.formClient.push(item.formClient)
  1666. this.storeClient.push(item.storeClient)
  1667. this.dealClient.push(item.dealClient)
  1668. })
  1669. }
  1670. this.$nextTick(() => {
  1671. this.passValue()
  1672. })
  1673. } else if (code === 10001) {
  1674. this.loginOut()
  1675. } else {
  1676. vant.Toast.fail(msg)
  1677. }
  1678. })
  1679. },
  1680. // 切换5个模块(总客户数、互动客户数、留资/报名客户数、邀约到店客户数、成交客户数)
  1681. handleClickItem(index) {
  1682. this.index = index
  1683. this.passValue()
  1684. },
  1685. // 切换三个图表(总客户数、一客一群、销售顾问+服务顾问)
  1686. passValue() {
  1687. if (this.index === 1) {
  1688. this.$nextTick(() => {
  1689. this.adviserChart()
  1690. })
  1691. } else {
  1692. this.$nextTick(() => {
  1693. this.labelChart()
  1694. })
  1695. }
  1696. },
  1697. // 互动客户数、留资/报名客户数、邀约到店客户数、成交客户数(趋势图)
  1698. labelChart() {
  1699. let labelChart = echarts.getInstanceByDom(document.getElementById('labelChart'))
  1700. if (labelChart == null) {
  1701. labelChart = echarts.init(document.getElementById('labelChart'))
  1702. }
  1703. window.addEventListener('resize', function () {
  1704. labelChart.resize()
  1705. })
  1706. let dataText = ''
  1707. let labelData = []
  1708. if (this.index === 2) {
  1709. labelData = this.interactClient
  1710. dataText = '互动客户数'
  1711. } else if (this.index === 3) {
  1712. labelData = this.formClient
  1713. dataText = '留资/报名客户数'
  1714. } else if (this.index === 4) {
  1715. labelData = this.storeClient
  1716. dataText = '邀约到店客户数'
  1717. } else if (this.index === 5) {
  1718. labelData = this.dealClient
  1719. dataText = '成交客户数'
  1720. }
  1721. labelChart.setOption({
  1722. legend: {
  1723. data: [dataText],
  1724. orient: 'horizontal',
  1725. x: 'center',
  1726. y: 'top',
  1727. align: 'right',
  1728. itemWidth: 20,
  1729. itemHeight: 5,
  1730. itemGap: 20,
  1731. textStyle: {//图例文字的样式
  1732. color: '#666666', //图例文字颜色
  1733. fontSize: 10//图例文字大小
  1734. }
  1735. },
  1736. tooltip: {
  1737. trigger: 'axis',
  1738. axisPointer: {
  1739. type: 'shadow'
  1740. },
  1741. },
  1742. grid: {
  1743. top: '10%',
  1744. left: '10%',
  1745. right: '10%',
  1746. bottom: '10%'
  1747. },
  1748. xAxis: {
  1749. type: 'category',
  1750. axisLabel: {
  1751. show: true,
  1752. color: "#666666",
  1753. fontSize: '8',
  1754. },
  1755. data: this.lineDate,
  1756. },
  1757. yAxis: [
  1758. {// 第一种方式
  1759. type: 'value',
  1760. min: 0,
  1761. max: Math.max(...labelData),
  1762. splitNumber: 5,
  1763. interval: Math.max(...labelData) / 5,
  1764. position: 'left',
  1765. axisLabel: {
  1766. show: true,
  1767. color: "#222222",
  1768. fontSize: '8',
  1769. formatter: function (v) {
  1770. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  1771. }
  1772. },
  1773. splitLine: { //网格线
  1774. lineStyle: {
  1775. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  1776. },
  1777. },
  1778. axisTick: { show: false },
  1779. },
  1780. ],
  1781. series: [
  1782. {
  1783. name: dataText,
  1784. type: 'bar',
  1785. stack: 'total',
  1786. color: '#1677FF ',
  1787. data: labelData,
  1788. itemStyle: {
  1789. // 设置柱形图圆角 [左上角,右上角,右下角,左下角]
  1790. borderRadius: [5, 5, 0, 0]
  1791. }
  1792. }
  1793. ],
  1794. }, true)
  1795. },
  1796. // 销售顾问+服务顾问(趋势图)
  1797. adviserChart() {
  1798. let adviserChart = echarts.getInstanceByDom(document.getElementById('adviserChart'))
  1799. if (adviserChart == null) {
  1800. adviserChart = echarts.init(document.getElementById('adviserChart'))
  1801. }
  1802. window.addEventListener('resize', function () {
  1803. adviserChart.resize()
  1804. })
  1805. adviserChart.setOption({
  1806. legend: {
  1807. show: true,
  1808. data: ['销售', '服务'],
  1809. orient: 'horizontal',
  1810. x: 'center',
  1811. y: 'top',
  1812. align: 'right',
  1813. itemWidth: 20,
  1814. itemHeight: 5,
  1815. itemGap: 20,
  1816. textStyle: {//图例文字的样式
  1817. color: '#666666', //图例文字颜色
  1818. fontSize: 10,//图例文字大小
  1819. }
  1820. },
  1821. tooltip: {
  1822. trigger: 'axis',
  1823. axisPointer: {
  1824. type: 'shadow'
  1825. },
  1826. },
  1827. grid: {
  1828. top: '10%',
  1829. left: '10%',
  1830. right: '10%',
  1831. bottom: '10%'
  1832. },
  1833. xAxis: {
  1834. type: 'category',
  1835. axisLabel: {
  1836. show: true,
  1837. color: '#666666',
  1838. fontSize: '8',
  1839. },
  1840. data: this.lineDate,
  1841. },
  1842. yAxis: [
  1843. {// 第一种方式
  1844. type: 'value',
  1845. min: 0,
  1846. max: Math.max(...this.saleAdd, ...this.serveAdd) * 2,
  1847. splitNumber: 5,
  1848. interval: Math.max(...this.saleAdd, ...this.serveAdd) * 2 / 5,
  1849. position: 'left',
  1850. axisLabel: {
  1851. show: true,
  1852. color: '#222222',
  1853. fontSize: '8',
  1854. formatter: function (v) {
  1855. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  1856. }
  1857. },
  1858. splitLine: { //网格线
  1859. lineStyle: {
  1860. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  1861. },
  1862. },
  1863. axisTick: { show: false },
  1864. },
  1865. ],
  1866. series: [
  1867. {
  1868. name: '销售',
  1869. type: 'bar',
  1870. stack: 'total',
  1871. color: '#1677FF',
  1872. data: this.saleAdd,
  1873. },
  1874. {
  1875. name: '服务',
  1876. type: 'bar',
  1877. stack: 'total',
  1878. color: '#5CE56E ',
  1879. data: this.serveAdd,
  1880. itemStyle: {
  1881. // 设置柱形图圆角 [左上角,右上角,右下角,左下角]
  1882. borderRadius: [5, 5, 0, 0]
  1883. }
  1884. }
  1885. ],
  1886. }, true)
  1887. },
  1888. // 切换车型(客户资产-客群包统计)
  1889. handleClickCar(item, index) {
  1890. this.carIndex = index
  1891. this.carStepData = []
  1892. this.carStepData.push(this.tableList.find(ele => ele.carModel === item.carModel))
  1893. },
  1894. // 客户资产-客群包统计数据
  1895. stepStatistic() {
  1896. this.tableList = []
  1897. this.carStepData = []
  1898. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/stepStatistic`, {
  1899. method: 'post',
  1900. body: JSON.stringify({
  1901. outletId: this.outletId,
  1902. departmentIds: this.deptId ? [this.deptId] : [],
  1903. }),
  1904. headers: {
  1905. 'Content-Type': 'application/json',
  1906. 'token': this.token,
  1907. 'tenancyId': this.tenancyId
  1908. }
  1909. }).then(res => {
  1910. return res.json()
  1911. }).then(result => {
  1912. let { data, code, msg } = result
  1913. if (code === 1) {
  1914. this.tableList = data || []
  1915. if (this.tableList.length > 0) {
  1916. this.carStepData.push(this.tableList[0])
  1917. }
  1918. } else if (code === 10001) {
  1919. this.loginOut()
  1920. } else {
  1921. vant.Toast.fail(msg)
  1922. }
  1923. })
  1924. },
  1925. // 意向车型标签排名
  1926. getIntentRank() {
  1927. this.intentRankData = []
  1928. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/intentRank`, {
  1929. method: 'post',
  1930. body: JSON.stringify({
  1931. outletId: this.outletId,
  1932. departmentIds: this.deptId ? [this.deptId] : [],
  1933. }),
  1934. headers: {
  1935. 'Content-Type': 'application/json',
  1936. 'token': this.token,
  1937. 'tenancyId': this.tenancyId
  1938. }
  1939. }).then(res => {
  1940. return res.json()
  1941. }).then(result => {
  1942. let { data, code, msg } = result
  1943. if (code === 1) {
  1944. this.intentRankData = data || []
  1945. this.$nextTick(() => {
  1946. this.intentRankChart()
  1947. })
  1948. } else if (code === 10001) {
  1949. this.loginOut()
  1950. } else {
  1951. vant.Toast.fail(msg)
  1952. }
  1953. })
  1954. },
  1955. intentRankChart() {
  1956. let intentRankData = this.intentRankData.sort((a, b) => a.clientNum - b.clientNum)
  1957. let rankChart = echarts.getInstanceByDom(document.getElementById('intentRankChart'))
  1958. if (rankChart == null) {
  1959. rankChart = echarts.init(document.getElementById('intentRankChart'))
  1960. }
  1961. rankChart.resize({ height: this.intentRankData.length * 50 + 20 })
  1962. window.addEventListener('resize', function () {
  1963. rankChart.resize()
  1964. })
  1965. rankChart.setOption({
  1966. tooltip: {
  1967. trigger: 'item',
  1968. formatter: '{b}: {c}'
  1969. },
  1970. legend: {
  1971. left: 'center',
  1972. icon: 'circle', //小圆点
  1973. itemWidth: 10,
  1974. itemHeight: 10,
  1975. itemGap: 10, //间隔
  1976. bottom: '10%',
  1977. },
  1978. grid: {
  1979. bottom: "0",
  1980. top: "0",
  1981. left: "0",
  1982. containLabel: true,
  1983. },
  1984. xAxis: {
  1985. type: 'value',
  1986. axisLabel: {
  1987. show: true,
  1988. color: '#666666',
  1989. fontSize: '8',
  1990. },
  1991. splitLine: {
  1992. show: true,
  1993. lineStyle: {
  1994. type: 'dashed' // 设置为虚线
  1995. }
  1996. },
  1997. },
  1998. yAxis: {
  1999. type: 'category',
  2000. axisLabel: {
  2001. formatter: function (value) {
  2002. return value.length > 4 ? value.substring(0, 4) + '...' : value
  2003. },
  2004. showTooltip: true,
  2005. },
  2006. data: this.intentRankData.map(item => {
  2007. return item.tagName
  2008. }) || [],
  2009. },
  2010. series: [
  2011. {
  2012. type: 'bar',
  2013. barWidth: 24,
  2014. barGap: 12,
  2015. itemStyle: {
  2016. color: function (p) {
  2017. // 亮度随索引递增实现渐变
  2018. const lightness = 94 - p.dataIndex * 8;
  2019. return `hsl(127.9, 72.5%, ${Math.min(100, lightness)}%)`;
  2020. }
  2021. },
  2022. data: this.intentRankData.map(item => {
  2023. return item.clientNum
  2024. }) || []
  2025. }
  2026. ]
  2027. })
  2028. },
  2029. // 已购车型标签排名
  2030. getBuyRank() {
  2031. this.buyRankData = []
  2032. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/buyRank`, {
  2033. method: 'post',
  2034. body: JSON.stringify({
  2035. outletId: this.outletId,
  2036. departmentIds: this.deptId ? [this.deptId] : [],
  2037. }),
  2038. headers: {
  2039. 'Content-Type': 'application/json',
  2040. 'token': this.token,
  2041. 'tenancyId': this.tenancyId
  2042. }
  2043. }).then(res => {
  2044. return res.json()
  2045. }).then(result => {
  2046. let { data, code, msg } = result
  2047. if (code === 1) {
  2048. this.buyRankData = data || []
  2049. this.$nextTick(() => {
  2050. this.buyRankChart()
  2051. })
  2052. } else if (code === 10001) {
  2053. this.loginOut()
  2054. } else {
  2055. vant.Toast.fail(msg)
  2056. }
  2057. })
  2058. },
  2059. buyRankChart() {
  2060. let buyRankData = this.buyRankData.sort((a, b) => a.clientNum - b.clientNum)
  2061. let rankChart = echarts.getInstanceByDom(document.getElementById('buyRankChart'))
  2062. if (rankChart == null) {
  2063. rankChart = echarts.init(document.getElementById('buyRankChart'))
  2064. }
  2065. rankChart.resize({ height: this.buyRankData.length * 50 + 20 })
  2066. window.addEventListener('resize', function () {
  2067. rankChart.resize()
  2068. })
  2069. rankChart.setOption({
  2070. tooltip: {
  2071. trigger: 'item',
  2072. formatter: '{b}: {c}'
  2073. },
  2074. legend: {
  2075. left: 'center',
  2076. icon: 'circle', //小圆点
  2077. itemWidth: 10,
  2078. itemHeight: 10,
  2079. itemGap: 10, //间隔
  2080. bottom: '10%',
  2081. },
  2082. grid: {
  2083. bottom: "0",
  2084. top: "0",
  2085. left: "0",
  2086. containLabel: true,
  2087. },
  2088. xAxis: {
  2089. type: 'value',
  2090. axisLabel: {
  2091. show: true,
  2092. color: '#666666',
  2093. fontSize: '8',
  2094. },
  2095. splitLine: {
  2096. show: true,
  2097. lineStyle: {
  2098. type: 'dashed' // 设置为虚线
  2099. }
  2100. },
  2101. },
  2102. yAxis: {
  2103. type: 'category',
  2104. axisLabel: {
  2105. formatter: function (value) {
  2106. return value.length > 4 ? value.substring(0, 4) + '...' : value
  2107. },
  2108. showTooltip: true,
  2109. },
  2110. data: this.buyRankData.map(item => {
  2111. return item.tagName
  2112. }) || [],
  2113. },
  2114. series: [
  2115. {
  2116. type: 'bar',
  2117. barWidth: 24,
  2118. barGap: 12,
  2119. itemStyle: {
  2120. color: function (p) {
  2121. // 亮度随索引递增实现渐变
  2122. const lightness = 87 - p.dataIndex * 8;
  2123. return `hsl(215, 100%, ${Math.min(100, lightness)}%)`;
  2124. }
  2125. },
  2126. data: this.buyRankData.map(item => {
  2127. return item.clientNum
  2128. }) || []
  2129. }
  2130. ]
  2131. })
  2132. },
  2133. // 聊天分析 - 总数据
  2134. getChatIndicators() {
  2135. this.chatIndicators = {
  2136. dayList: [], // 聊天分析-日数据
  2137. opinion: {},
  2138. total: {
  2139. privateChat: 0,
  2140. privateMsgNum: 0,
  2141. groupMsgNum: 0,
  2142. proactiveServe: 0,
  2143. clientReply: 0,
  2144. clientReplyPercent: 0,
  2145. proactiveConsult: 0,
  2146. memberReply: 0,
  2147. avgReplyDuration: 0,
  2148. },
  2149. yda: {
  2150. privateChat: 0,
  2151. privateMsgNum: 0,
  2152. groupMsgNum: 0,
  2153. proactiveServe: 0,
  2154. clientReply: 0,
  2155. clientReplyPercent: 0,
  2156. proactiveConsult: 0,
  2157. memberReply: 0,
  2158. avgReplyDuration: 0,
  2159. },
  2160. }
  2161. this.interactDate = []
  2162. this.privateChat = []
  2163. this.privateMsgNum = []
  2164. this.groupMsgNum = []
  2165. this.proactiveServe = []
  2166. this.clientReply = []
  2167. this.clientReplyPercent = []
  2168. this.proactiveConsult = []
  2169. this.memberReply = []
  2170. this.avgReplyDuration = []
  2171. this.totalMsg = []
  2172. this.privateMsg = []
  2173. this.groupMsg = []
  2174. this.maxValue = null
  2175. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/chatIndicators`, {
  2176. method: 'post',
  2177. body: JSON.stringify({
  2178. outletId: this.outletId,
  2179. departmentIds: this.deptId ? [this.deptId] : [],
  2180. startTime: this.pageStartTime,
  2181. endTime: this.pageEndTime,
  2182. }),
  2183. headers: {
  2184. 'Content-Type': 'application/json',
  2185. 'token': this.token,
  2186. 'tenancyId': this.tenancyId
  2187. }
  2188. }).then(res => {
  2189. return res.json()
  2190. }).then(result => {
  2191. let { data, code, msg } = result
  2192. if (code === 1) {
  2193. this.chatIndicators = {
  2194. dayList: data.dayList || [], // 聊天分析-日数据
  2195. opinion: data.opinion ? data.opinion : {
  2196. negativeGroup: 0,
  2197. positiveGroup: 0,
  2198. neutralGroup: 0,
  2199. negativePrivate: 0,
  2200. positivePrivate: 0,
  2201. neutralPrivate: 0,
  2202. negativeTotal: 0,
  2203. positiveTotal: 0,
  2204. neutralTotal: 0,
  2205. },
  2206. total: data.total ? data.total : {
  2207. privateChat: 0,
  2208. privateMsgNum: 0,
  2209. groupMsgNum: 0,
  2210. proactiveServe: 0,
  2211. clientReply: 0,
  2212. clientReplyPercent: 0,
  2213. proactiveConsult: 0,
  2214. memberReply: 0,
  2215. avgReplyDuration: 0,
  2216. },
  2217. yda: data.yda ? data.yda : {
  2218. privateChat: 0,
  2219. privateMsgNum: 0,
  2220. groupMsgNum: 0,
  2221. proactiveServe: 0,
  2222. clientReply: 0,
  2223. clientReplyPercent: 0,
  2224. proactiveConsult: 0,
  2225. memberReply: 0,
  2226. avgReplyDuration: 0,
  2227. }, // 昨日数据
  2228. }
  2229. this.interactDate = []
  2230. this.privateChat = []
  2231. this.privateMsgNum = []
  2232. this.groupMsgNum = []
  2233. this.proactiveServe = []
  2234. this.clientReply = []
  2235. this.clientReplyPercent = []
  2236. this.proactiveConsult = []
  2237. this.memberReply = []
  2238. this.avgReplyDuration = []
  2239. if (data.dayList && data.dayList.length > 0) {
  2240. data.dayList.forEach(item => {
  2241. this.interactDate.push(item.time)
  2242. this.privateChat.push(item.privateChat)
  2243. this.privateMsgNum.push(item.privateMsgNum)
  2244. this.groupMsgNum.push(item.groupMsgNum)
  2245. this.proactiveServe.push(item.proactiveServe)
  2246. this.clientReply.push(item.clientReply)
  2247. this.clientReplyPercent.push(item.clientReplyPercent)
  2248. this.proactiveConsult.push(item.proactiveConsult)
  2249. this.memberReply.push(item.memberReply)
  2250. this.avgReplyDuration.push(item.avgReplyDuration)
  2251. })
  2252. this.$nextTick(() => {
  2253. this.interactChart()
  2254. this.staffChart()
  2255. this.clientChart()
  2256. })
  2257. }
  2258. this.totalMsg = []
  2259. this.privateMsg = []
  2260. this.groupMsg = []
  2261. this.maxValue = null
  2262. if (data.opinion) {
  2263. this.totalMsg = [data.opinion.negativeTotal, data.opinion.positiveTotal, data.opinion.neutralTotal]
  2264. this.privateMsg = [data.opinion.positivePrivate, data.opinion.negativePrivate, data.opinion.neutralPrivate]
  2265. this.groupMsg = [data.opinion.positiveGroup, data.opinion.negativeGroup, data.opinion.neutralGroup]
  2266. this.maxValue = Math.max.apply(null, [...this.totalMsg, ...this.privateMsg, ...this.groupMsg])
  2267. this.$nextTick(() => {
  2268. this.opinionChart()
  2269. })
  2270. }
  2271. } else if (code === 10001) {
  2272. this.loginOut()
  2273. } else {
  2274. vant.Toast.fail(msg)
  2275. }
  2276. })
  2277. },
  2278. // 聊天分析-总数据趋势图数据
  2279. interactChart() {
  2280. let interactChart = echarts.getInstanceByDom(document.getElementById('interactChart'))
  2281. if (interactChart == null) {
  2282. interactChart = echarts.init(document.getElementById('interactChart'))
  2283. }
  2284. window.addEventListener('resize', function () {
  2285. interactChart.resize()
  2286. })
  2287. interactChart.setOption({
  2288. legend: {
  2289. x: 'center',
  2290. y: 10,
  2291. align: 'right',
  2292. itemWidth: 20,
  2293. itemHeight: 5,
  2294. itemGap: 20,
  2295. textStyle: {//图例文字的样式
  2296. color: '#666666', //图例文字颜色
  2297. fontSize: 10//图例文字大小
  2298. },
  2299. data: [
  2300. {
  2301. name: "私聊客户数",
  2302. // 单独设置图例空心圆,通过设置边框颜色+背景颜色白色实现空心圆
  2303. itemStyle: {
  2304. color: "#fff",
  2305. borderColor: '#1677FF',
  2306. borderWidth: 1,
  2307. },
  2308. },
  2309. {
  2310. name: "私聊消息数",
  2311. // 单独设置图例空心圆,通过设置边框颜色+背景颜色白色实现空心圆
  2312. itemStyle: {
  2313. color: "#fff",
  2314. borderColor: '#5CE56E',
  2315. borderWidth: 1,
  2316. },
  2317. },
  2318. {
  2319. name: "群消息数",
  2320. itemStyle: {
  2321. width: 20,
  2322. height: 5,
  2323. color: "#E6F0FF",
  2324. },
  2325. },
  2326. ]
  2327. },
  2328. tooltip: {
  2329. trigger: 'axis'
  2330. },
  2331. grid: {
  2332. top: '20%',
  2333. left: '10%',
  2334. right: '10%',
  2335. bottom: '10%'
  2336. },
  2337. xAxis: {
  2338. type: 'category',
  2339. axisLabel: {
  2340. show: true,
  2341. color: "#666666",
  2342. fontSize: '8',
  2343. },
  2344. data: this.interactDate,
  2345. },
  2346. yAxis: [
  2347. {// 第一种方式
  2348. type: 'value',
  2349. min: 0,
  2350. max: Math.max(...this.privateMsgNum, ...this.privateChat, ...this.groupMsgNum),
  2351. splitNumber: 5,
  2352. interval: Math.max(...this.privateMsgNum, ...this.privateChat, ...this.groupMsgNum) / 5,
  2353. axisLabel: {
  2354. show: true,
  2355. color: "#222222",
  2356. fontSize: '8',
  2357. formatter: function (v) {
  2358. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  2359. }
  2360. },
  2361. splitLine: { //网格线
  2362. lineStyle: {
  2363. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  2364. },
  2365. },
  2366. axisTick: { show: false },
  2367. },
  2368. ],
  2369. series: [
  2370. {
  2371. name: '私聊客户数',
  2372. type: 'line',
  2373. color: '#1677FF',
  2374. data: this.privateChat,
  2375. symbol: 'none', //去掉折线图中的节点
  2376. smooth: true, //true 为平滑曲线,false为直线
  2377. },
  2378. {
  2379. name: '私聊消息数',
  2380. type: 'line',
  2381. color: '#5CE56E',
  2382. data: this.privateMsgNum,
  2383. symbol: 'none', //去掉折线图中的节点
  2384. smooth: true, //true 为平滑曲线,false为直线
  2385. },
  2386. {
  2387. name: '群消息数',
  2388. type: 'bar', //形状为柱状图
  2389. data: this.groupMsgNum,
  2390. itemStyle: {
  2391. color: ' #E6F0FF',
  2392. },
  2393. emphasis: {
  2394. itemStyle: {
  2395. color: 'rgb(0, 157, 255)'
  2396. }
  2397. },
  2398. }
  2399. ],
  2400. }, true)
  2401. },
  2402. // 聊天分析-员工服务趋势图数据
  2403. staffChart() {
  2404. let staffChart = echarts.getInstanceByDom(document.getElementById('staffChart'))
  2405. if (staffChart == null) {
  2406. staffChart = echarts.init(document.getElementById('staffChart'))
  2407. }
  2408. window.addEventListener('resize', function () {
  2409. staffChart.resize()
  2410. })
  2411. staffChart.setOption({
  2412. legend: {
  2413. orient: 'horizontal',
  2414. x: 'center',
  2415. y: 10,
  2416. align: 'right',
  2417. itemWidth: 20,
  2418. itemHeight: 5,
  2419. itemGap: 20,
  2420. textStyle: {//图例文字的样式
  2421. color: '#666666', //图例文字颜色
  2422. fontSize: 10//图例文字大小
  2423. },
  2424. data: [
  2425. {
  2426. name: "主动服务会话数",
  2427. // 单独设置图例空心圆,通过设置边框颜色+背景颜色白色实现空心圆
  2428. itemStyle: {
  2429. width: 20,
  2430. height: 5,
  2431. color: "#1677FF",
  2432. },
  2433. },
  2434. {
  2435. name: "客户回复会话数",
  2436. // 单独设置图例空心圆,通过设置边框颜色+背景颜色白色实现空心圆
  2437. itemStyle: {
  2438. width: 20,
  2439. height: 5,
  2440. color: "#5CE56E",
  2441. },
  2442. },
  2443. {
  2444. name: "客户回复率",
  2445. itemStyle: {
  2446. color: "#fff",
  2447. borderColor: '#FFA64E',
  2448. borderWidth: 1,
  2449. },
  2450. },
  2451. ]
  2452. },
  2453. tooltip: {
  2454. trigger: 'axis'
  2455. },
  2456. grid: {
  2457. top: '20%',
  2458. left: '10%',
  2459. right: '10%',
  2460. bottom: '10%'
  2461. },
  2462. xAxis: {
  2463. type: 'category',
  2464. axisLabel: {
  2465. show: true,
  2466. color: "#666666",
  2467. fontSize: '8',
  2468. },
  2469. data: this.interactDate,
  2470. },
  2471. yAxis: [
  2472. {// 第一种方式
  2473. type: 'value',
  2474. min: 0,
  2475. max: Math.max(...this.proactiveServe, ...this.clientReply),
  2476. splitNumber: 5,
  2477. interval: Math.max(...this.proactiveServe, ...this.clientReply) / 5,
  2478. axisLabel: {
  2479. show: true,
  2480. color: "#222222",
  2481. fontSize: '8',
  2482. formatter: function (v) {
  2483. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  2484. }
  2485. },
  2486. splitLine: { //网格线
  2487. lineStyle: {
  2488. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  2489. },
  2490. },
  2491. axisTick: { show: false },
  2492. },
  2493. {// 第二种方式
  2494. type: 'value',
  2495. min: 0,
  2496. max: Math.max(...this.clientReplyPercent),
  2497. splitNumber: 5,
  2498. interval: Math.max(...this.clientReplyPercent) / 5,
  2499. axisLabel: {
  2500. show: true,
  2501. color: "#222222",
  2502. fontSize: '8',
  2503. formatter: function (v) {
  2504. return v.toFixed(0) + ' %'; //0表示小数为0位,1表示1位小数,2表示2位小数
  2505. }
  2506. },
  2507. splitLine: { //网格线
  2508. lineStyle: {
  2509. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  2510. },
  2511. },
  2512. axisTick: { show: false },
  2513. },
  2514. ],
  2515. series: [
  2516. {
  2517. name: '主动服务会话数',
  2518. type: 'bar', //形状为柱状图
  2519. data: this.proactiveServe,
  2520. itemStyle: {
  2521. color: ' #1677FF',
  2522. borderRadius: [5, 5, 0, 0]
  2523. },
  2524. emphasis: {
  2525. itemStyle: {
  2526. color: 'rgb(0, 157, 255)'
  2527. }
  2528. },
  2529. },
  2530. {
  2531. name: '客户回复会话数',
  2532. type: 'bar', //形状为柱状图
  2533. data: this.clientReply,
  2534. itemStyle: {
  2535. color: ' #5CE56E',
  2536. borderRadius: [5, 5, 0, 0]
  2537. },
  2538. emphasis: {
  2539. itemStyle: {
  2540. color: 'rgb(0, 157, 255)'
  2541. }
  2542. },
  2543. },
  2544. {
  2545. name: '客户回复率',
  2546. type: 'line',
  2547. color: '#FFA64E',
  2548. symbol: 'none',
  2549. yAxisIndex: 1,
  2550. data: this.clientReplyPercent,
  2551. tooltip: {
  2552. valueFormatter: function (value) {
  2553. return value ? value + ' %' : ''
  2554. }
  2555. },
  2556. smooth: true, //true 为平滑曲线,false为直线
  2557. }
  2558. ],
  2559. }, true)
  2560. },
  2561. // 聊天分析-客户咨询趋势图数据
  2562. clientChart() {
  2563. let clientChart = echarts.getInstanceByDom(document.getElementById('clientChart'))
  2564. if (clientChart == null) {
  2565. clientChart = echarts.init(document.getElementById('clientChart'))
  2566. }
  2567. window.addEventListener('resize', function () {
  2568. clientChart.resize()
  2569. })
  2570. clientChart.setOption({
  2571. legend: {
  2572. orient: 'horizontal',
  2573. x: 'center',
  2574. y: 10,
  2575. align: 'right',
  2576. itemWidth: 16,
  2577. itemHeight: 4,
  2578. itemGap: 10,
  2579. textStyle: {//图例文字的样式
  2580. color: '#666666', //图例文字颜色
  2581. fontSize: 10//图例文字大小
  2582. },
  2583. data: [
  2584. {
  2585. name: "主动咨询会话数",
  2586. // 单独设置图例空心圆,通过设置边框颜色+背景颜色白色实现空心圆
  2587. itemStyle: {
  2588. width: 20,
  2589. height: 5,
  2590. color: "#1677FF",
  2591. },
  2592. },
  2593. {
  2594. name: "员工回复会话数",
  2595. // 单独设置图例空心圆,通过设置边框颜色+背景颜色白色实现空心圆
  2596. itemStyle: {
  2597. width: 20,
  2598. height: 5,
  2599. color: "#5CE56E",
  2600. },
  2601. },
  2602. {
  2603. name: "员工平均响应时长",
  2604. itemStyle: {
  2605. color: "#fff",
  2606. borderColor: '#FFA64E',
  2607. borderWidth: 1,
  2608. },
  2609. },
  2610. ]
  2611. },
  2612. tooltip: {
  2613. trigger: 'axis'
  2614. },
  2615. grid: {
  2616. top: '20%',
  2617. left: '10%',
  2618. right: '10%',
  2619. bottom: '10%'
  2620. },
  2621. xAxis: {
  2622. type: 'category',
  2623. axisLabel: {
  2624. show: true,
  2625. color: "#666666",
  2626. fontSize: '8',
  2627. },
  2628. data: this.interactDate,
  2629. },
  2630. yAxis: [
  2631. {// 第一种方式
  2632. type: 'value',
  2633. min: 0,
  2634. max: Math.max(...this.proactiveConsult, ...this.memberReply),
  2635. splitNumber: 5,
  2636. interval: Math.max(...this.proactiveConsult, ...this.memberReply) / 5,
  2637. axisLabel: {
  2638. show: true,
  2639. color: "#222222",
  2640. fontSize: '8',
  2641. formatter: function (v) {
  2642. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  2643. }
  2644. },
  2645. splitLine: { //网格线
  2646. lineStyle: {
  2647. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  2648. },
  2649. },
  2650. axisTick: { show: false },
  2651. },
  2652. {// 第二种方式
  2653. type: 'value',
  2654. min: 0,
  2655. max: Math.max(...this.avgReplyDuration),
  2656. splitNumber: 5,
  2657. interval: Math.max(...this.avgReplyDuration) / 5,
  2658. axisLabel: {
  2659. show: true,
  2660. color: "#222222",
  2661. fontSize: '8',
  2662. formatter: function (v) {
  2663. return v.toFixed(0) + ' s'; //0表示小数为0位,1表示1位小数,2表示2位小数
  2664. }
  2665. },
  2666. splitLine: { //网格线
  2667. lineStyle: {
  2668. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  2669. },
  2670. },
  2671. axisTick: { show: false },
  2672. },
  2673. ],
  2674. series: [
  2675. {
  2676. name: '主动咨询会话数',
  2677. type: 'bar', //形状为柱状图
  2678. data: this.proactiveConsult,
  2679. itemStyle: {
  2680. color: ' #1677FF',
  2681. borderRadius: [5, 5, 0, 0]
  2682. },
  2683. emphasis: {
  2684. itemStyle: {
  2685. color: 'rgb(0, 157, 255)'
  2686. }
  2687. },
  2688. },
  2689. {
  2690. name: '员工回复会话数',
  2691. type: 'bar', //形状为柱状图
  2692. data: this.memberReply,
  2693. itemStyle: {
  2694. color: ' #5CE56E',
  2695. borderRadius: [5, 5, 0, 0]
  2696. },
  2697. emphasis: {
  2698. itemStyle: {
  2699. color: 'rgb(0, 157, 255)'
  2700. }
  2701. },
  2702. },
  2703. {
  2704. name: '员工平均响应时长',
  2705. type: 'line',
  2706. color: '#FFA64E',
  2707. symbol: 'none',
  2708. yAxisIndex: 1,
  2709. tooltip: {
  2710. valueFormatter: function (value) {
  2711. return value ? value.toFixed(0) + ' s' : ''
  2712. }
  2713. },
  2714. data: this.avgReplyDuration,
  2715. smooth: true, //true 为平滑曲线,false为直线
  2716. }
  2717. ],
  2718. }, true)
  2719. },
  2720. // 聊天分析-消息舆情分析
  2721. opinionChart() {
  2722. let opinionChart = echarts.getInstanceByDom(document.getElementById('opinionChart'))
  2723. if (opinionChart == null) {
  2724. opinionChart = echarts.init(document.getElementById('opinionChart'))
  2725. }
  2726. window.addEventListener('resize', function () {
  2727. opinionChart.resize()
  2728. })
  2729. opinionChart.setOption({
  2730. legend: {
  2731. orient: 'horizontal',
  2732. align: 'right',
  2733. itemWidth: 20,
  2734. itemHeight: 4,
  2735. itemGap: 20,
  2736. textStyle: {//图例文字的样式
  2737. color: '#666666', //图例文字颜色
  2738. fontSize: 10//图例文字大小
  2739. }
  2740. },
  2741. radar: {
  2742. indicator: [
  2743. { name: '负面', max: this.maxValue },
  2744. { name: '中性', max: this.maxValue },
  2745. { name: '正面', max: this.maxValue },
  2746. ],
  2747. radius: 150,
  2748. },
  2749. series: [
  2750. {
  2751. type: 'radar',
  2752. color: '#1677FF',
  2753. data: [
  2754. {
  2755. value: this.totalMsg,
  2756. name: '全部消息',
  2757. itemStyle: {
  2758. color: '#1677FF',
  2759. lineStyle: {
  2760. color: '#1677FF',
  2761. },
  2762. },
  2763. },
  2764. {
  2765. value: this.privateMsg,
  2766. name: '单聊消息',
  2767. itemStyle: {
  2768. color: '#5CE56E',
  2769. lineStyle: {
  2770. color: '#5CE56E',
  2771. },
  2772. },
  2773. },
  2774. {
  2775. value: this.groupMsg,
  2776. name: '群聊消息',
  2777. itemStyle: {
  2778. color: '#FFA64E',
  2779. lineStyle: {
  2780. color: '#FFA64E',
  2781. },
  2782. },
  2783. }
  2784. ]
  2785. },
  2786. ]
  2787. }, true)
  2788. },
  2789. // 聊天分析-词云图
  2790. getWordCloudMap() {
  2791. this.wordCloudMap = []
  2792. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/wordCloudMap`, {
  2793. method: 'post',
  2794. body: JSON.stringify({
  2795. outletId: this.outletId,
  2796. departmentIds: this.deptId ? [this.deptId] : [],
  2797. startTime: this.pageStartTime,
  2798. endTime: this.pageEndTime,
  2799. }),
  2800. headers: {
  2801. 'Content-Type': 'application/json',
  2802. 'token': this.token,
  2803. 'tenancyId': this.tenancyId
  2804. }
  2805. }).then(res => {
  2806. return res.json()
  2807. }).then(result => {
  2808. let { data, code, msg } = result
  2809. if (code === 1) {
  2810. this.wordCloudMap = data || []
  2811. this.$nextTick(() => {
  2812. this.wordCloudChart()
  2813. })
  2814. } else if (code === 10001) {
  2815. this.loginOut()
  2816. } else {
  2817. vant.Toast.fail(msg)
  2818. }
  2819. })
  2820. },
  2821. wordCloudChart() {
  2822. let wordCloudChart = echarts.getInstanceByDom(document.getElementById('wordCloudChart'))
  2823. if (wordCloudChart == null) {
  2824. wordCloudChart = echarts.init(document.getElementById('wordCloudChart'))
  2825. }
  2826. window.addEventListener('resize', function () {
  2827. wordCloudChart.resize()
  2828. })
  2829. wordCloudChart.setOption({
  2830. series: [{
  2831. type: 'wordCloud',
  2832. //maskImage: maskImage,
  2833. sizeRange: [12, 24],
  2834. rotationRange: [0, 0],
  2835. rotationStep: 45,
  2836. gridSize: 8,
  2837. shape: 'pentagon',
  2838. width: '100%',
  2839. height: '100%',
  2840. textStyle: {
  2841. fontFamily: '微软雅黑',
  2842. color: (v) => {
  2843. switch (true) {
  2844. case v.dataIndex <= 5:
  2845. return '#1677FF'
  2846. case 5 < v.dataIndex && v.dataIndex <= 10:
  2847. return 'rgba(22, 119, 255, 0.6)'
  2848. default:
  2849. return 'rgba(22, 119, 255, 0.4)'
  2850. }
  2851. }
  2852. },
  2853. data: this.wordCloudMap,
  2854. }]
  2855. }, true)
  2856. },
  2857. // 销售进程客户数
  2858. getSaleIndicators() {
  2859. this.saleIndicators = []
  2860. this.clientStepDate = []
  2861. this.clientStepNum = []
  2862. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/saleIndicators`, {
  2863. method: 'post',
  2864. body: JSON.stringify({
  2865. outletId: this.outletId,
  2866. departmentIds: this.deptId ? [this.deptId] : [],
  2867. startTime: this.pageStartTime,
  2868. endTime: this.pageEndTime,
  2869. }),
  2870. headers: {
  2871. 'Content-Type': 'application/json',
  2872. 'token': this.token,
  2873. 'tenancyId': this.tenancyId
  2874. }
  2875. }).then(res => {
  2876. return res.json()
  2877. }).then(result => {
  2878. let { data, code, msg } = result
  2879. if (code === 1) {
  2880. this.saleIndicators = data || []
  2881. if (data && data.length) {
  2882. data[0].dayList.forEach(item => {
  2883. this.clientStepDate.push(item.time)
  2884. this.clientStepNum.push(item.clientNum)
  2885. })
  2886. this.$nextTick(() => {
  2887. this.clientStepChart()
  2888. })
  2889. }
  2890. } else if (code === 10001) {
  2891. this.loginOut()
  2892. } else {
  2893. vant.Toast.fail(msg)
  2894. }
  2895. })
  2896. },
  2897. handleClickClient(item, index) {
  2898. this.clientIndex = index
  2899. this.clientStepDate = []
  2900. this.clientStepNum = []
  2901. if (item.dayList && item.dayList.length) {
  2902. this.clientStepDate = item.dayList.map(item => item.time)
  2903. this.clientStepNum = item.dayList.map(item => item.clientNum)
  2904. this.$nextTick(() => {
  2905. this.clientStepChart()
  2906. })
  2907. }
  2908. },
  2909. clientStepChart() {
  2910. let clientStepChart = echarts.getInstanceByDom(document.getElementById('clientStepChart'))
  2911. if (clientStepChart == null) {
  2912. clientStepChart = echarts.init(document.getElementById('clientStepChart'))
  2913. }
  2914. window.addEventListener('resize', function () {
  2915. clientStepChart.resize()
  2916. })
  2917. let text = this.saleIndicators[this.clientIndex].processName
  2918. clientStepChart.setOption({
  2919. legend: {
  2920. show: false,
  2921. },
  2922. tooltip: {
  2923. trigger: 'axis',
  2924. formatter: function (params) {
  2925. return params[0].name + '<br>'
  2926. + text + ': ' + params[0].value
  2927. }
  2928. },
  2929. grid: {
  2930. top: '10%',
  2931. left: '10%',
  2932. right: '10%',
  2933. bottom: '10%'
  2934. },
  2935. xAxis: {
  2936. type: 'category',
  2937. axisLabel: {
  2938. show: true,
  2939. color: "#666666",
  2940. fontSize: '8',
  2941. },
  2942. data: this.clientStepDate,
  2943. },
  2944. yAxis: [
  2945. {// 第一种方式
  2946. type: 'value',
  2947. min: 0,
  2948. max: Math.max(...this.clientStepNum),
  2949. splitNumber: 5,
  2950. interval: Math.max(...this.clientStepNum) / 5,
  2951. position: 'left',
  2952. axisLabel: {
  2953. show: true,
  2954. color: "#222222",
  2955. fontSize: '8',
  2956. formatter: function (v) {
  2957. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  2958. }
  2959. },
  2960. splitLine: { //网格线
  2961. lineStyle: {
  2962. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  2963. },
  2964. },
  2965. axisTick: { show: false },
  2966. },
  2967. ],
  2968. series: [
  2969. {
  2970. type: 'line',
  2971. color: '#1677FF',
  2972. areaStyle: {
  2973. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  2974. { offset: 0, color: 'rgba(22,119,255,0.43)' },
  2975. { offset: 1, color: 'rgba(22,119,255,0)' }
  2976. ])
  2977. }, //填充区域样式
  2978. data: this.clientStepNum,
  2979. symbol: 'none', //去掉折线图中的节点
  2980. smooth: true, //true 为平滑曲线,false为直线
  2981. }
  2982. ],
  2983. }, true)
  2984. },
  2985. // 销售统计排名
  2986. getSaleRank() {
  2987. this.saleRankData = []
  2988. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/saleRank`, {
  2989. method: 'post',
  2990. body: JSON.stringify({
  2991. outletId: this.outletId,
  2992. departmentIds: this.deptId ? [this.deptId] : [],
  2993. startTime: this.pageStartTime,
  2994. endTime: this.pageEndTime,
  2995. }),
  2996. headers: {
  2997. 'Content-Type': 'application/json',
  2998. 'token': this.token,
  2999. 'tenancyId': this.tenancyId
  3000. }
  3001. }).then(res => {
  3002. return res.json()
  3003. }).then(result => {
  3004. let { data, code, msg } = result
  3005. if (code === 1) {
  3006. this.saleRankData = data || []
  3007. } else if (code === 10001) {
  3008. this.loginOut()
  3009. } else {
  3010. vant.Toast.fail(msg)
  3011. }
  3012. })
  3013. },
  3014. // 聊天超时监测
  3015. getTimeOutTrendChart() {
  3016. this.timeOutDate = []
  3017. this.timeoutMember = []
  3018. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/timeOutTrend`, {
  3019. method: 'post',
  3020. body: JSON.stringify({
  3021. outletId: this.outletId,
  3022. departmentIds: this.deptId ? [this.deptId] : [],
  3023. startTime: this.pageStartTime,
  3024. endTime: this.pageEndTime,
  3025. }),
  3026. headers: {
  3027. 'Content-Type': 'application/json',
  3028. 'token': this.token,
  3029. 'tenancyId': this.tenancyId
  3030. }
  3031. }).then(res => {
  3032. return res.json()
  3033. }).then(result => {
  3034. let { data, code, msg } = result
  3035. if (code === 1) {
  3036. if (data && data.length) {
  3037. data.forEach(item => {
  3038. this.timeOutDate.push(item.time)
  3039. this.timeoutMember.push(item.timeoutMember)
  3040. })
  3041. this.$nextTick(() => {
  3042. this.timeOutTrendChart()
  3043. })
  3044. }
  3045. } else if (code === 10001) {
  3046. this.loginOut()
  3047. } else {
  3048. vant.Toast.fail(msg)
  3049. }
  3050. })
  3051. },
  3052. timeOutTrendChart() {
  3053. let timeOutTrendChart = echarts.getInstanceByDom(document.getElementById('timeOutTrendChart'))
  3054. if (timeOutTrendChart == null) {
  3055. timeOutTrendChart = echarts.init(document.getElementById('timeOutTrendChart'))
  3056. }
  3057. window.addEventListener('resize', function () {
  3058. timeOutTrendChart.resize()
  3059. })
  3060. timeOutTrendChart.setOption({
  3061. legend: {
  3062. show: false,
  3063. },
  3064. tooltip: {
  3065. trigger: 'axis',
  3066. formatter: function (params) {
  3067. return params[0].name + ': ' + params[0].value
  3068. }
  3069. },
  3070. grid: {
  3071. top: '10%',
  3072. left: '10%',
  3073. right: '10%',
  3074. bottom: '10%'
  3075. },
  3076. xAxis: {
  3077. type: 'category',
  3078. axisLabel: {
  3079. show: true,
  3080. color: "#666666",
  3081. fontSize: '8',
  3082. },
  3083. data: this.timeOutDate,
  3084. },
  3085. yAxis: [
  3086. {// 第一种方式
  3087. type: 'value',
  3088. min: 0,
  3089. max: Math.max(...this.timeoutMember),
  3090. splitNumber: 5,
  3091. interval: Math.max(...this.timeoutMember) / 5,
  3092. position: 'left',
  3093. axisLabel: {
  3094. show: true,
  3095. color: "#222222",
  3096. fontSize: '8',
  3097. formatter: function (v) {
  3098. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  3099. }
  3100. },
  3101. splitLine: { //网格线
  3102. lineStyle: {
  3103. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  3104. },
  3105. },
  3106. axisTick: { show: false },
  3107. },
  3108. ],
  3109. series: [
  3110. {
  3111. type: 'line',
  3112. color: '#FF4E4E',
  3113. areaStyle: {
  3114. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  3115. { offset: 0, color: 'rgba(255, 78, 78,0.43)' },
  3116. { offset: 1, color: 'rgba(255, 78, 78,0)' }
  3117. ])
  3118. }, //填充区域样式
  3119. data: this.timeoutMember,
  3120. symbol: 'none', //去掉折线图中的节点
  3121. smooth: true, //true 为平滑曲线,false为直线
  3122. }
  3123. ],
  3124. }, true)
  3125. },
  3126. returnOutsideDate() {
  3127. this.memberStartTime = this.pageStartTime
  3128. this.memberEndTime = this.pageEndTime
  3129. if (this.pageStartTime === this.getDateTime(-1) && this.pageEndTime === this.getDateTime(-1)) {
  3130. this.timeData = '昨日'
  3131. } else if (this.pageStartTime === this.getDateTime(-7) && this.pageEndTime === this.getDateTime(-1)) {
  3132. this.timeData = '近7天'
  3133. } else if (this.pageStartTime === this.getDateTime(-30) && this.pageEndTime === this.getDateTime(-1)) {
  3134. this.timeData = '近30天'
  3135. } else {
  3136. this.timeData = '自定义'
  3137. }
  3138. },
  3139. // 顾问响应统计
  3140. handleMemberReply() {
  3141. this.showMemberReply = true
  3142. this.returnOutsideDate()
  3143. this.getMemberReply()
  3144. },
  3145. getMemberReply() {
  3146. this.loading = true
  3147. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/memberReply`, {
  3148. method: 'post',
  3149. body: JSON.stringify({
  3150. outletId: this.outletId,
  3151. departmentIds: this.deptId ? [this.deptId] : [],
  3152. startTime: this.memberStartTime,
  3153. endTime: this.memberEndTime,
  3154. page: this.currentPage,
  3155. pageCount: 10,
  3156. keyword: this.keyword,
  3157. }),
  3158. headers: {
  3159. 'Content-Type': 'application/json',
  3160. 'token': this.token,
  3161. 'tenancyId': this.tenancyId
  3162. }
  3163. }).then(res => {
  3164. return res.json()
  3165. }).then(result => {
  3166. let { data, code, msg } = result
  3167. if (code === 1) {
  3168. this.memberReplyData = data.records || []
  3169. this.totalItems = data.total || 0
  3170. } else if (code === 10001) {
  3171. this.loginOut()
  3172. } else {
  3173. vant.Toast.fail(msg)
  3174. }
  3175. }).finally(() => {
  3176. this.loading = false
  3177. })
  3178. },
  3179. onSelect(val) {
  3180. this.timeData = val.text
  3181. if (this.timeData === '自定义') {
  3182. this.showSelfDate = true
  3183. } else {
  3184. if (this.timeData === '昨日') {
  3185. this.memberStartTime = this.getDateTime(-1)
  3186. this.memberEndTime = this.getDateTime(-1)
  3187. } else if (this.timeData === '近7天') {
  3188. this.memberStartTime = this.getDateTime(-7)
  3189. this.memberEndTime = this.getDateTime(-1)
  3190. } else if (this.timeData === '近30天') {
  3191. this.memberStartTime = this.getDateTime(-30)
  3192. this.memberEndTime = this.getDateTime(-1)
  3193. }
  3194. this.$nextTick(() => {
  3195. if (this.showDoneReply) {
  3196. this.getDoneReply()
  3197. } else {
  3198. if (this.memberId) {
  3199. this.handleItemMemberReplyDetail()
  3200. } else {
  3201. this.getMemberReply()
  3202. }
  3203. }
  3204. })
  3205. }
  3206. },
  3207. onSelfConfirm(date) {
  3208. const [start, end] = date
  3209. if (this.formatDate(new Date()) === this.formatDate(end)) {
  3210. this.formatDate(end) = this.formatDate(start)
  3211. }
  3212. this.memberStartTime = this.formatDate(start)
  3213. this.memberEndTime = this.formatDate(end)
  3214. this.showSelfDate = false
  3215. if (this.showDoneReply) {
  3216. this.getDoneReply()
  3217. } else {
  3218. if (this.memberId) {
  3219. this.handleItemMemberReplyDetail()
  3220. } else {
  3221. this.getMemberReply()
  3222. }
  3223. }
  3224. },
  3225. formatDate(date) {
  3226. return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
  3227. },
  3228. handleSearch() {
  3229. this.getMemberReply()
  3230. },
  3231. handleChangePage(val) {
  3232. this.currentPage = val
  3233. if (this.showDoneReply) {
  3234. this.getDoneReply()
  3235. } else {
  3236. this.getMemberReply()
  3237. }
  3238. },
  3239. closeReply() {
  3240. this.currentPage = 1
  3241. this.totalItems = 0
  3242. this.keyword = ''
  3243. this.timeData = '近7天'
  3244. this.memberStartTime = this.getDateTime(-7)
  3245. this.memberEndTime = this.getDateTime(-1)
  3246. this.memberReplyData = []
  3247. this.showMemberReply = false
  3248. this.showDoneReply = false
  3249. },
  3250. handleItemMemberReply(item) {
  3251. this.showItemMemberReply = true
  3252. this.currentMemberName = item.memberName
  3253. this.memberId = item.memberId
  3254. this.currentItemPage = 1
  3255. this.itemTotalItems = 0
  3256. this.memberDetailReplyData = []
  3257. this.handleItemMemberReplyDetail(item)
  3258. },
  3259. closeItemMemberReply() {
  3260. this.showItemMemberReply = false
  3261. },
  3262. handleChangeItemPage(val) {
  3263. this.currentItemPage = val
  3264. this.handleItemMemberReplyDetail()
  3265. },
  3266. // 顾客响应统计-详情
  3267. handleItemMemberReplyDetail() {
  3268. this.loading = true
  3269. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/memberReplyDetail`, {
  3270. method: 'post',
  3271. body: JSON.stringify({
  3272. outletId: this.outletId,
  3273. departmentIds: this.deptId ? [this.deptId] : [],
  3274. startTime: this.memberStartTime,
  3275. endTime: this.memberEndTime,
  3276. page: this.currentItemPage,
  3277. pageCount: 10,
  3278. memberId: this.memberId,
  3279. }),
  3280. headers: {
  3281. 'Content-Type': 'application/json',
  3282. 'token': this.token,
  3283. 'tenancyId': this.tenancyId
  3284. }
  3285. }).then(res => {
  3286. return res.json()
  3287. }).then(result => {
  3288. let { data, code, msg } = result
  3289. if (code === 1) {
  3290. this.memberDetailReplyData = data.records || []
  3291. this.itemTotalItems = data.total || 0
  3292. } else if (code === 10001) {
  3293. this.loginOut()
  3294. } else {
  3295. vant.Toast.fail(msg)
  3296. }
  3297. }).finally(() => {
  3298. this.loading = false
  3299. })
  3300. },
  3301. // 顾客完成情况统计
  3302. handleDoneReply() {
  3303. this.showDoneReply = true
  3304. this.returnOutsideDate()
  3305. this.getDoneReply()
  3306. },
  3307. getDoneReply() {
  3308. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/operationMemberCnt`, {
  3309. method: 'post',
  3310. body: JSON.stringify({
  3311. outletId: this.outletId,
  3312. departmentIds: this.deptId ? [this.deptId] : [],
  3313. startTime: this.memberStartTime,
  3314. endTime: this.memberEndTime,
  3315. page: this.currentPage,
  3316. pageCount: 10,
  3317. }),
  3318. headers: {
  3319. 'Content-Type': 'application/json',
  3320. 'token': this.token,
  3321. 'tenancyId': this.tenancyId
  3322. }
  3323. }).then(res => {
  3324. return res.json()
  3325. }).then(result => {
  3326. let { data, code, msg } = result
  3327. if (code === 1) {
  3328. this.doneReplyData = data.records || []
  3329. this.totalItems = data.total || 0
  3330. } else if (code === 10001) {
  3331. this.loginOut()
  3332. } else {
  3333. vant.Toast.fail(msg)
  3334. }
  3335. })
  3336. },
  3337. // 聊天排行榜
  3338. getChatRank() {
  3339. this.chatRankData = []
  3340. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/chatRank`, {
  3341. method: 'post',
  3342. body: JSON.stringify({
  3343. outletId: this.outletId,
  3344. departmentIds: this.deptId ? [this.deptId] : [],
  3345. startTime: this.pageStartTime,
  3346. endTime: this.pageEndTime,
  3347. }),
  3348. headers: {
  3349. 'Content-Type': 'application/json',
  3350. 'token': this.token,
  3351. 'tenancyId': this.tenancyId
  3352. }
  3353. }).then(res => {
  3354. return res.json()
  3355. }).then(result => {
  3356. let { data, code, msg } = result
  3357. if (code === 1) {
  3358. this.chatRankData = data || []
  3359. } else if (code === 10001) {
  3360. this.loginOut()
  3361. } else {
  3362. vant.Toast.fail(msg)
  3363. }
  3364. })
  3365. },
  3366. // 运营任务-总数据
  3367. getOutletCount() {
  3368. this.outletCount = []
  3369. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/outletCount`, {
  3370. method: 'post',
  3371. body: JSON.stringify({
  3372. outletId: this.outletId,
  3373. departmentIds: this.deptId ? [this.deptId] : [],
  3374. startTime: this.pageStartTime,
  3375. endTime: this.pageEndTime,
  3376. }),
  3377. headers: {
  3378. 'Content-Type': 'application/json',
  3379. 'token': this.token,
  3380. 'tenancyId': this.tenancyId
  3381. }
  3382. }).then(res => {
  3383. return res.json()
  3384. }).then(result => {
  3385. let { data, code, msg } = result
  3386. if (code === 1) {
  3387. this.outletCount = data || []
  3388. } else if (code === 10001) {
  3389. this.loginOut()
  3390. } else {
  3391. vant.Toast.fail(msg)
  3392. }
  3393. })
  3394. },
  3395. // 运营任务-任务完成率
  3396. getTaskCompleteChart() {
  3397. this.taskCompleteDate = []
  3398. this.taskCompletePercent = []
  3399. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/taskCompletePercent`, {
  3400. method: 'post',
  3401. body: JSON.stringify({
  3402. outletId: this.outletId,
  3403. departmentIds: this.deptId ? [this.deptId] : [],
  3404. startTime: this.pageStartTime,
  3405. endTime: this.pageEndTime,
  3406. }),
  3407. headers: {
  3408. 'Content-Type': 'application/json',
  3409. 'token': this.token,
  3410. 'tenancyId': this.tenancyId
  3411. }
  3412. }).then(res => {
  3413. return res.json()
  3414. }).then(result => {
  3415. let { data, code, msg } = result
  3416. if (code === 1) {
  3417. if (data && data.length) {
  3418. data.forEach(item => {
  3419. this.taskCompleteDate.push(item.time)
  3420. this.taskCompletePercent.push(item.taskCompletePercent)
  3421. })
  3422. this.$nextTick(() => {
  3423. this.taskCompleteChart()
  3424. })
  3425. }
  3426. } else if (code === 10001) {
  3427. this.loginOut()
  3428. } else {
  3429. vant.Toast.fail(msg)
  3430. }
  3431. })
  3432. },
  3433. taskCompleteChart() {
  3434. let taskCompleteChart = echarts.getInstanceByDom(document.getElementById('taskCompleteChart'))
  3435. if (taskCompleteChart == null) {
  3436. taskCompleteChart = echarts.init(document.getElementById('taskCompleteChart'))
  3437. }
  3438. window.addEventListener('resize', function () {
  3439. taskCompleteChart.resize()
  3440. })
  3441. taskCompleteChart.setOption({
  3442. legend: {
  3443. show: false,
  3444. },
  3445. tooltip: {
  3446. trigger: 'axis',
  3447. valueFormatter: function (value) {
  3448. return value ? value.toFixed(2) + ' %' : ''
  3449. }
  3450. },
  3451. grid: {
  3452. top: '10%',
  3453. left: '10%',
  3454. right: '10%',
  3455. bottom: '10%'
  3456. },
  3457. xAxis: {
  3458. type: 'category',
  3459. axisLabel: {
  3460. show: true,
  3461. color: "#666666",
  3462. fontSize: '8',
  3463. },
  3464. data: this.taskCompleteDate,
  3465. },
  3466. yAxis: [
  3467. {// 第一种方式
  3468. type: 'value',
  3469. min: 0,
  3470. max: Math.max(...this.taskCompletePercent),
  3471. splitNumber: 5,
  3472. interval: Math.max(...this.taskCompletePercent) / 5,
  3473. position: 'left',
  3474. axisLabel: {
  3475. show: true,
  3476. color: "#222222",
  3477. fontSize: '8',
  3478. formatter: function (v) {
  3479. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  3480. }
  3481. },
  3482. splitLine: { //网格线
  3483. lineStyle: {
  3484. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  3485. },
  3486. },
  3487. axisTick: { show: false },
  3488. },
  3489. ],
  3490. series: [
  3491. {
  3492. type: 'line',
  3493. color: '#1677FF',
  3494. areaStyle: {
  3495. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  3496. { offset: 0, color: 'rgba(22,119,255,0.43)' },
  3497. { offset: 1, color: 'rgba(22,119,255,0)' }
  3498. ])
  3499. }, //填充区域样式
  3500. data: this.taskCompletePercent,
  3501. symbol: 'none', //去掉折线图中的节点
  3502. smooth: true, //true 为平滑曲线,false为直线
  3503. }
  3504. ],
  3505. }, true)
  3506. },
  3507. // 运营任务 - 互动客户数
  3508. getOpInteractChart() {
  3509. this.opInteractDate = []
  3510. this.opInteractClient = []
  3511. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/interact`, {
  3512. method: 'post',
  3513. body: JSON.stringify({
  3514. outletId: this.outletId,
  3515. departmentIds: this.deptId ? [this.deptId] : [],
  3516. startTime: this.pageStartTime,
  3517. endTime: this.pageEndTime,
  3518. }),
  3519. headers: {
  3520. 'Content-Type': 'application/json',
  3521. 'token': this.token,
  3522. 'tenancyId': this.tenancyId
  3523. }
  3524. }).then(res => {
  3525. return res.json()
  3526. }).then(result => {
  3527. let { data, code, msg } = result
  3528. if (code === 1) {
  3529. if (data && data.length) {
  3530. data.forEach(item => {
  3531. this.opInteractDate.push(item.time)
  3532. this.opInteractClient.push(item.interactClient)
  3533. })
  3534. this.$nextTick(() => {
  3535. this.opInteractChart()
  3536. })
  3537. }
  3538. } else if (code === 10001) {
  3539. this.loginOut()
  3540. } else {
  3541. vant.Toast.fail(msg)
  3542. }
  3543. })
  3544. },
  3545. opInteractChart() {
  3546. let opInteractChart = echarts.getInstanceByDom(document.getElementById('opInteractChart'))
  3547. if (opInteractChart == null) {
  3548. opInteractChart = echarts.init(document.getElementById('opInteractChart'))
  3549. }
  3550. window.addEventListener('resize', function () {
  3551. opInteractChart.resize()
  3552. })
  3553. opInteractChart.setOption({
  3554. legend: {
  3555. show: false,
  3556. },
  3557. tooltip: {
  3558. trigger: 'axis',
  3559. formatter: function (params) {
  3560. return params[0].name + '<br>'
  3561. + '互动客户数: ' + params[0].value
  3562. }
  3563. },
  3564. grid: {
  3565. top: '10%',
  3566. left: '10%',
  3567. right: '10%',
  3568. bottom: '10%'
  3569. },
  3570. xAxis: {
  3571. type: 'category',
  3572. axisLabel: {
  3573. show: true,
  3574. color: "#666666",
  3575. fontSize: '8',
  3576. },
  3577. data: this.opInteractDate,
  3578. },
  3579. yAxis: [
  3580. {// 第一种方式
  3581. type: 'value',
  3582. min: 0,
  3583. max: Math.max(...this.opInteractClient),
  3584. splitNumber: 5,
  3585. interval: Math.max(...this.opInteractClient) / 5,
  3586. position: 'left',
  3587. axisLabel: {
  3588. show: true,
  3589. color: "#222222",
  3590. fontSize: '8',
  3591. formatter: function (v) {
  3592. return v.toFixed(0) //0表示小数为0位,1表示1位小数,2表示2位小数
  3593. }
  3594. },
  3595. splitLine: { //网格线
  3596. lineStyle: {
  3597. type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
  3598. },
  3599. },
  3600. axisTick: { show: false },
  3601. },
  3602. ],
  3603. series: [
  3604. {
  3605. type: 'line',
  3606. color: '#FFA64E',
  3607. areaStyle: {
  3608. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  3609. { offset: 0, color: 'rgba(255, 166, 78 ,0.43)' },
  3610. { offset: 1, color: 'rgba(255, 166, 78 ,0)' }
  3611. ])
  3612. }, //填充区域样式
  3613. data: this.opInteractClient,
  3614. symbol: 'none', //去掉折线图中的节点
  3615. smooth: true, //true 为平滑曲线,false为直线
  3616. }
  3617. ],
  3618. }, true)
  3619. },
  3620. // 运营任务 - 素材排行榜
  3621. getContentRank() {
  3622. this.contentRankData = []
  3623. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/contentRank`, {
  3624. method: 'post',
  3625. body: JSON.stringify({
  3626. outletId: this.outletId,
  3627. departmentIds: this.deptId ? [this.deptId] : [],
  3628. startTime: this.pageStartTime,
  3629. endTime: this.pageEndTime,
  3630. }),
  3631. headers: {
  3632. 'Content-Type': 'application/json',
  3633. 'token': this.token,
  3634. 'tenancyId': this.tenancyId
  3635. }
  3636. }).then(res => {
  3637. return res.json()
  3638. }).then(result => {
  3639. let { data, code, msg } = result
  3640. if (code === 1) {
  3641. this.contentRankData = data.reverse() || []
  3642. this.$nextTick(() => {
  3643. this.contentRankChart()
  3644. })
  3645. } else if (code === 10001) {
  3646. this.loginOut()
  3647. } else {
  3648. vant.Toast.fail(msg)
  3649. }
  3650. })
  3651. },
  3652. contentRankChart() {
  3653. let contentRankData = this.contentRankData.sort((a, b) => a.clientNum - b.clientNum)
  3654. let rankChart = echarts.getInstanceByDom(document.getElementById('contentRank'))
  3655. if (rankChart == null) {
  3656. rankChart = echarts.init(document.getElementById('contentRank'))
  3657. }
  3658. rankChart.resize({ height: this.contentRankData.length * 50 + 20 })
  3659. window.addEventListener('resize', function () {
  3660. rankChart.resize()
  3661. })
  3662. rankChart.setOption({
  3663. tooltip: {
  3664. trigger: 'item',
  3665. confine: true,
  3666. extraCssText: 'max-width:200px; white-space:pre-wrap',
  3667. formatter: '{b}: {c}'
  3668. },
  3669. legend: {
  3670. left: 'center',
  3671. icon: 'circle', //小圆点
  3672. itemWidth: 10,
  3673. itemHeight: 10,
  3674. itemGap: 10, //间隔
  3675. bottom: '10%',
  3676. },
  3677. grid: {
  3678. bottom: "0",
  3679. top: "0",
  3680. left: "0",
  3681. containLabel: true,
  3682. },
  3683. xAxis: {
  3684. type: 'value',
  3685. axisLabel: {
  3686. show: true,
  3687. color: '#666666',
  3688. fontSize: '8',
  3689. },
  3690. splitLine: {
  3691. show: true,
  3692. lineStyle: {
  3693. type: 'dashed' // 设置为虚线
  3694. }
  3695. },
  3696. },
  3697. yAxis: {
  3698. type: 'category',
  3699. axisLabel: {
  3700. formatter: function (value) {
  3701. return value.length > 4 ? value.substring(0, 4) + '...' : value
  3702. },
  3703. showTooltip: true,
  3704. },
  3705. data: this.contentRankData.map(item => {
  3706. return item.title
  3707. }) || [],
  3708. },
  3709. series: [
  3710. {
  3711. type: 'bar',
  3712. barWidth: 24,
  3713. barGap: 12,
  3714. itemStyle: {
  3715. color: function (p) {
  3716. // 亮度随索引递增实现渐变
  3717. const lightness = 87 - p.dataIndex * 8;
  3718. return `hsl(215, 100%, ${Math.min(100, lightness)}%)`;
  3719. }
  3720. },
  3721. data: this.contentRankData.map(item => {
  3722. return item.readNum
  3723. }) || []
  3724. }
  3725. ]
  3726. })
  3727. },
  3728. // 打开右上角弹窗
  3729. handleShowPopup() {
  3730. this.showPopup = true
  3731. },
  3732. // 关闭右上角弹窗
  3733. handleClosePopup() {
  3734. this.showPopup = false
  3735. this.showMer = false
  3736. },
  3737. // 切换商户
  3738. handleSelectMer(item) {
  3739. localStorage.setItem('tenancyIdValue', item.id)
  3740. localStorage.setItem('tenancyNameValue', item.name || '')
  3741. this.tenancyId = item.id
  3742. this.jxsName = item.name || ''
  3743. this.showPopup = false
  3744. this.showMer = false
  3745. this.getDealerIds()
  3746. },
  3747. getDealerIds() {
  3748. const headers = new Headers()
  3749. headers.append('token', this.token)
  3750. headers.append('tenancyId', this.tenancyId)
  3751. fetch(this.httpUrl + `/scrm/v1/dw-dealer/m/getDealers`, {
  3752. method: 'GET',
  3753. headers: headers
  3754. }).then(res => {
  3755. return res.json()
  3756. }).then(result => {
  3757. let { data, code, msg } = result
  3758. if (code === 1) {
  3759. if (data && data.length) {
  3760. if (data[0].type === 1) {
  3761. var currentQueryParams = window.location.search
  3762. window.location.replace('miniJxs.html' + currentQueryParams)
  3763. } else {
  3764. this.initialization()
  3765. }
  3766. }
  3767. } else if (code === 10001) {
  3768. this.loginOut()
  3769. } else {
  3770. vant.Toast.fail(msg)
  3771. }
  3772. })
  3773. },
  3774. // 退出登录
  3775. handleLoginOut() {
  3776. localStorage.removeItem('tokenValue')
  3777. var currentQueryParams = window.location.search
  3778. window.location.replace('jxsLogin.html' + currentQueryParams)
  3779. },
  3780. // token过期,退出登录
  3781. loginOut() {
  3782. vant.Toast({
  3783. message: '登录信息过期,请重新登录',
  3784. })
  3785. // this.handleLoginOut()
  3786. },
  3787. formatTime(seconds) {
  3788. // 处理无效输入(空值/非数字)
  3789. if (seconds == null || seconds === '' || typeof seconds !== 'number') {
  3790. return '--';
  3791. }
  3792. // 确定时间符号和绝对值
  3793. const isNegative = seconds < 0;
  3794. const absSeconds = Math.abs(seconds);
  3795. // 内部格式化函数(处理绝对值)
  3796. const format = (val, unit) => {
  3797. const num = Math.round(val);
  3798. return `${num}${unit}${num > 1 ? '' : ''}`;
  3799. };
  3800. // 根据绝对值大小转换单位
  3801. let formatted;
  3802. if (absSeconds >= 3600) {
  3803. formatted = format(absSeconds / 3600, '小时');
  3804. } else if (absSeconds >= 60) {
  3805. formatted = format(absSeconds / 60, '分钟');
  3806. } else {
  3807. formatted = format(absSeconds, '秒');
  3808. }
  3809. // 添加负号(当原始值为负时)
  3810. return isNegative ? `-${formatted}` : formatted;
  3811. },
  3812. formatNumber(num) {
  3813. const number = Number(num);
  3814. if (isNaN(number) || !isFinite(number)) {
  3815. return num;
  3816. }
  3817. // 整数直接返回
  3818. if (Number.isInteger(number)) {
  3819. return number.toString();
  3820. }
  3821. // 非整数处理:先保留两位小数,再移除末尾的零
  3822. let str = number.toFixed(2);
  3823. // 正则表达式移除末尾的零(保留有效小数位)
  3824. return str.replace(/(\.[1-9]?0+)$|(\.[1-9])0+$/g, '$1$2');
  3825. },
  3826. // 日期格式处理
  3827. getDateTime(day) {
  3828. let today = new Date()
  3829. let targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day
  3830. today.setTime(targetday_milliseconds)
  3831. let tYear = today.getFullYear()
  3832. let tMonth = today.getMonth() + 1
  3833. let tDate = today.getDate()
  3834. if (tMonth < 10) {
  3835. tMonth = '0' + tMonth
  3836. }
  3837. if (tDate < 10) {
  3838. tDate = '0' + tDate
  3839. }
  3840. return tYear + '-' + tMonth + '-' + tDate
  3841. },
  3842. // 截取url中的数据
  3843. getQueryParam(paramName) {
  3844. // 获取当前URL的查询字符串部分
  3845. const queryString = window.location.search;
  3846. // 创建一个URLSearchParams对象
  3847. const urlParams = new URLSearchParams(queryString);
  3848. // 返回指定参数的值,如果不存在则返回null
  3849. return urlParams.get(paramName);
  3850. },
  3851. timeFormat(time, format = 'yyyy-MM-dd hh:mm:ss') {
  3852. if (time === undefined || time === '' || time === null) {
  3853. return '--'
  3854. } else {
  3855. const date = new Date(time)
  3856. const o = {
  3857. 'M+': date.getMonth() + 1,
  3858. 'd+': date.getDate(),
  3859. 'h+': date.getHours(),
  3860. 'm+': date.getMinutes(),
  3861. 's+': date.getSeconds(),
  3862. 'q+': Math.floor((date.getMonth() + 3) / 3),
  3863. 'S': date.getMilliseconds()
  3864. }
  3865. if (/(y+)/.test(format)) {
  3866. format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  3867. }
  3868. for (let k in o) {
  3869. if (new RegExp('(' + k + ')').test(format)) {
  3870. format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
  3871. }
  3872. }
  3873. return format
  3874. }
  3875. },
  3876. }
  3877. })
  3878. </script>
  3879. </html>