salesPanel.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. <template>
  2. <div>
  3. <borderTemplate borderBox="width: 31.250vw;height: 35.417vw;" title="销售面板" detailTitle="查看详情" @dialog="$emit('dialog')" systemappid="277" push_path="/salesData">
  4. <template slot="content">
  5. <div class="justify-content">
  6. <div class="justify-content-left">
  7. <div class="box-border">
  8. <el-button v-if="typeSelect == '订单'" type="primary" class="btn-select" @click="typeChange('订单')">{{$t(`订单`)}}</el-button>
  9. <el-button type="text" v-else class="btn-unSelect" @click="typeChange('订单')">{{$t(`订单`)}}</el-button>
  10. </div>
  11. <div class="box-border">
  12. <el-button type="primary" v-if="typeSelect == '出货'" class="btn-select" @click="typeChange('出货')">{{$t(`出货`)}}</el-button>
  13. <el-button type="text" class="btn-unSelect" v-else @click="typeChange('出货')">{{$t(`出货`)}}</el-button>
  14. </div>
  15. <div class="box-border">
  16. <el-button type="primary" v-if="typeSelect == '开票'" class="btn-select" @click="typeChange('开票')">{{$t(`开票`)}}</el-button>
  17. <el-button type="text" class="btn-unSelect" v-else @click="typeChange('开票')">{{$t(`开票`)}}</el-button>
  18. </div>
  19. <div class="box-border">
  20. <el-button type="primary" v-if="typeSelect == '回款'" class="btn-select" @click="typeChange('回款')">{{$t(`回款`)}}</el-button>
  21. <el-button type="text" class="btn-unSelect" v-else @click="typeChange('回款')">{{$t(`回款`)}}</el-button>
  22. </div>
  23. </div>
  24. <div>
  25. <el-select v-model="param.content.dateType" class="inline-16" size="small" @change="dateTypeChange" :popper-append-to-body="false">
  26. <el-option :label="$t('去年')" value="去年"></el-option>
  27. <el-option :label="$t('本年')" value="本年"></el-option>
  28. <el-option :label="$t('本季')" value="本季"></el-option>
  29. <el-option :label="$t('本月')" value="本月"></el-option>
  30. </el-select>
  31. </div>
  32. </div>
  33. <div class="content-style-pie">
  34. <div style="width: 7.292vw;height: 7.292vw;margin: 0.781vw 0 0 1.042vw;">
  35. <el-progress
  36. color="#6395fa"
  37. type="circle"
  38. :percentage="percentage"
  39. :stroke-width="15"
  40. :width="progressWidth"
  41. :format="format"
  42. ></el-progress>
  43. </div>
  44. <div class="content-style-content">
  45. <div class="font1">
  46. {{$t(`实际金额(元)`)}}
  47. </div>
  48. <div>
  49. <span class="font2">
  50. <span v-if="list.amount > 10000">
  51. {{tool.formatAmount(tool.unitConversion(list.amount, 10000), 2)}}
  52. <span class="font3">{{$t(`万`)}}</span>
  53. </span>
  54. <span v-else>
  55. {{tool.formatAmount(tool.unitConversion(list.amount, 10000), 2)}}
  56. </span>
  57. </span>
  58. </div>
  59. <div>
  60. <span class="font4">{{$t(`年同比`)}}:</span>
  61. <span class="font5" style="margin-right: 0.417vw">{{ Math.round(list.tbxsje * 100 * 100) / 100 }}%</span>
  62. <img style="vertical-align: middle" v-if="list.tbxsje > 0" width="8" height="7" src="../../../assets/icons/up.png" alt="">
  63. <img style="vertical-align: middle" v-if="list.tbxsje < 0" width="8" height="7" src="../../../assets/icons/down.png" alt="">
  64. <span class="font4" style="margin-left:1.042vw ">{{$t(`年环比`)}}:</span>
  65. <span class="font5" style="margin-right: 0.417vw">{{ Math.round(list.hbxsje * 100 * 100) / 100 }}%</span>
  66. <img style="vertical-align: middle" v-if="list.hbxsje > 0" width="8" height="7" src="../../../assets/icons/up.png" alt="">
  67. <img style="vertical-align: middle" v-if="list.hbxsje < 0" width="8" height="7" src="../../../assets/icons/down.png" alt="">
  68. </div>
  69. <div class="font1" style="margin-top:1.042vw ">
  70. {{$t(`目标金额(元)`)}}
  71. </div>
  72. <div>
  73. <span class="font6">
  74. <span v-if="list.target_l > 10000">
  75. {{tool.formatAmount(tool.unitConversion(list.target_l, 10000), 2)}}
  76. <span class="font7">{{$t(`万`)}}</span>
  77. </span>
  78. <span v-else>
  79. {{tool.formatAmount(tool.unitConversion(list.target_l, 10000), 2)}}
  80. </span>
  81. </span>
  82. </div>
  83. <div>
  84. <span class="font4">{{$t(`目标达成率`)}}:</span>
  85. <span class="font5">{{ Math.round((list.wcamount * 100)* 100) / 100 }}%</span>
  86. <span class="font4" style="margin-left:0.842vw">{{$t(`实际与目标差额`)}}:</span>
  87. <span class="font5" >
  88. <span v-if="list.unamount > 10000">
  89. {{tool.formatAmount(tool.unitConversion(list.unamount, 10000), 2)}}
  90. <span class="font5">{{$t(`万元`)}}</span>
  91. </span>
  92. <span v-else>
  93. {{tool.formatAmount(tool.unitConversion(list.unamount, 10000), 2)}}
  94. <span class="font5">{{$t(`元`)}}</span>
  95. </span>
  96. </span>
  97. </div>
  98. </div>
  99. </div>
  100. <div style="margin-top: 1.042vw">
  101. <div style="display:flex;justify-content: right">
  102. <datePicker ref="pickerRef" type="year" @selectTime="pickerChange" format="yyyy" value_format="yyyy"></datePicker>
  103. </div>
  104. <div id="salesPanelChart" style="height: 14.5vw"></div>
  105. </div>
  106. </template>
  107. </borderTemplate>
  108. </div>
  109. </template>
  110. <script>
  111. import borderTemplate from '../components/borderTemplate'
  112. import {DualAxes} from "@antv/g2plot";
  113. import datePicker from "../components/datePicker";
  114. export default {
  115. name: "salesPanel",
  116. components:{borderTemplate,datePicker},
  117. data(){
  118. return {
  119. typeSelect:'订单',
  120. chartCustomerLine:null,
  121. param:{
  122. id:20231009125304,
  123. content:{
  124. dataid:'',
  125. datatype:'1',
  126. dateType:'本年',
  127. type:'',
  128. where:{
  129. isleave:''
  130. }
  131. }
  132. },
  133. list:'',
  134. windowWidth: document.documentElement.clientWidth, //实时屏幕宽度
  135. progressWidth: (9.65 * document.documentElement.clientWidth) / 100,
  136. percentage:0,
  137. paramChart:{
  138. "id": 20241009093604,
  139. "content": {
  140. "type": '',
  141. "dataid": '',
  142. "year": 2024,
  143. "datatype": 1,
  144. "where": {
  145. "isleave": ""
  146. }
  147. }
  148. },
  149. saledateRows:[],
  150. tbzzl:[],
  151. }
  152. },
  153. methods:{
  154. async listData(init,time){
  155. const res = await this.$api.requested(this.param)
  156. this.list = res.data
  157. this.percentage = Math.round(this.list.wcamount * 100 * 100) / 100;
  158. if (init){
  159. this.renderPie()
  160. }else {
  161. // if (time){
  162. // this.queryModel()
  163. // }
  164. this.queryModel()
  165. }
  166. },
  167. dateTypeChange(){
  168. this.listData(false,false)
  169. },
  170. pickerChange(val){
  171. this.paramChart.content.year = val
  172. this.listData(false,true)
  173. },
  174. typeChange(val){
  175. if (val == '订单'){
  176. this.typeSelect = '订单'
  177. this.param.content.datatype = 1
  178. this.paramChart.content.datatype = 1
  179. }else if (val == '出货'){
  180. this.typeSelect = '出货'
  181. this.param.content.datatype = 2
  182. this.paramChart.content.datatype = 2
  183. }else if (val == '开票'){
  184. this.typeSelect = '开票'
  185. this.param.content.datatype = 3
  186. this.paramChart.content.datatype = 3
  187. }else if (val == '回款'){
  188. this.typeSelect = '回款'
  189. this.param.content.datatype = 4
  190. this.paramChart.content.datatype = 4
  191. }
  192. this.listData()
  193. },
  194. format(percentage) {
  195. return this.$t("目标达成率") + '\n\n' + percentage + "%";
  196. },
  197. /*渲染图表*/
  198. async queryModel(){
  199. const res = await this.$api.requested(this.paramChart)
  200. this.saledateRows = res.data.saledateRows
  201. let lastYear = []
  202. let nowYear = []
  203. let k=0
  204. for (var i=0;i<res.data.saledateRows.length;i++){
  205. if (res.data.saledateRows[i].name === '去年同期金额'){
  206. lastYear[k]=res.data.saledateRows[i]
  207. k++
  208. }
  209. }
  210. let x=0
  211. for (var i=0;i<res.data.saledateRows.length;i++){
  212. if (res.data.saledateRows[i].name === '本年金额'){
  213. nowYear[x]=res.data.saledateRows[i]
  214. x++
  215. }
  216. }
  217. let saledateRows = nowYear.concat(lastYear)
  218. this.saledateRows = saledateRows.map((item)=>{
  219. let value = item.value/10000
  220. return {
  221. "date":item.date,
  222. "name":item.name + '(万元)',
  223. "value":value
  224. /*"value":item.value*/
  225. }
  226. })
  227. this.tbzzl = res.data.tbzzlRows.map((item)=>{
  228. return {
  229. "date":item.date,
  230. "name":item.name,
  231. "value":Math.round(((item.value *100)*100)/100)
  232. }
  233. })
  234. this.chartCustomerLine.changeData([this.saledateRows,this.tbzzl])
  235. },
  236. renderPie(){
  237. this.chartCustomerLine = new DualAxes('salesPanelChart', {
  238. data: [this.saledateRows,this.tbzzl],
  239. xField: 'date',
  240. yField: ['value','value'],
  241. xAxis:{
  242. label:{
  243. style:{
  244. fill:'#CFDCE5'
  245. }
  246. }
  247. },
  248. yAxis:{
  249. value:{
  250. label:{
  251. style:{
  252. fill:'#CFDCE5'
  253. }
  254. }
  255. }
  256. },
  257. geometryOptions: [
  258. {
  259. geometry: 'column',
  260. isGroup: true,
  261. seriesField: 'name',
  262. color:['#3685FC','#6CD2A1'],
  263. // label:{
  264. // position:top,
  265. // formatter: (datum) =>{
  266. // return '¥' + this.tool.formatAmount(datum.value,2)
  267. // }
  268. // }
  269. },
  270. {
  271. geometry: 'line',
  272. seriesField: 'name',
  273. color: '#ECB937',
  274. smooth: true,
  275. // label:{
  276. // formatter: (datum) =>{
  277. // return datum.value + '%'
  278. // }
  279. // }
  280. },
  281. ],
  282. tooltip: {
  283. formatter: (datum) => {
  284. return {
  285. name:datum.name,
  286. value:datum.name != '同比增长率'?'¥'+this.tool.formatAmount(datum.value,2):datum.value + '%'
  287. }
  288. },
  289. },
  290. legend:{
  291. itemName:{
  292. style:{
  293. fill:'#CFDCE5'
  294. }
  295. },
  296. }
  297. });
  298. this.chartCustomerLine.render();
  299. this.queryModel()
  300. },
  301. },
  302. }
  303. </script>
  304. <style>
  305. .justify-content{
  306. display: flex;
  307. justify-content: space-between;
  308. margin-top: 1.042vw;
  309. }
  310. .justify-content-left{
  311. display: flex;
  312. justify-content: left;
  313. }
  314. .justify-content-left .box-border{
  315. width: 3.125vw;
  316. height: 1.563vw;
  317. border-radius: 0.104vw 0.104vw 0.104vw 0.104vw;
  318. margin-right: 0.521vw;
  319. text-align: center;
  320. }
  321. .justify-content-left .box-border .btn-select{
  322. font-family: Microsoft YaHei, Microsoft YaHei;
  323. font-weight: 400;
  324. font-size: 0.833vw;
  325. color: #E6F4FF;
  326. font-style: normal;
  327. text-transform: none;
  328. }
  329. .justify-content-left .box-border .btn-unSelect{
  330. font-family: Microsoft YaHei, Microsoft YaHei;
  331. font-weight: 400;
  332. font-size: 0.729vw;
  333. color: #CFDCE5;
  334. font-style: normal;
  335. text-transform: none;
  336. text-align: center;
  337. }
  338. .content-style-pie{
  339. width: 29.167vw;
  340. height: 11.458vw;
  341. background: #001E41;
  342. box-shadow: 0.000vw 0.156vw 0.313vw 0.052vw rgba(0,0,0,0.16);
  343. border-radius: 5.729vw 5.729vw 0.313vw 5.729vw;
  344. border: 0.052vw solid #CFDCE5;
  345. margin-top: 1.042vw;
  346. box-sizing: border-box;
  347. display: flex;
  348. justify-content: left;
  349. }
  350. .content-style-content{
  351. margin-top: 0.917vw;
  352. margin-left: 4.250vw;
  353. }
  354. .content-style-content .font1{
  355. font-family: Microsoft YaHei, Microsoft YaHei;
  356. font-weight: 400;
  357. font-size: 0.938vw;
  358. color: #CFDCE5;
  359. text-align: left;
  360. font-style: normal;
  361. text-transform: none;
  362. }
  363. .content-style-content .font2{
  364. font-family: Microsoft YaHei, Microsoft YaHei;
  365. font-weight: bold;
  366. font-size: 1.250vw;
  367. color: #6CD2A1;
  368. text-align: left;
  369. font-style: normal;
  370. text-transform: none;
  371. }
  372. .content-style-content .font3{
  373. font-family: Microsoft YaHei, Microsoft YaHei;
  374. font-weight: bold;
  375. font-size: 0.625vw;
  376. color: #6CD2A1;
  377. text-align: left;
  378. font-style: normal;
  379. text-transform: none;
  380. }
  381. .content-style-content .font4{
  382. font-family: Microsoft YaHei, Microsoft YaHei;
  383. font-weight: 400;
  384. font-size: 0.625vw;
  385. color: #CFDCE5;
  386. text-align: left;
  387. font-style: normal;
  388. text-transform: none;
  389. }
  390. .content-style-content .font5{
  391. font-family: Microsoft YaHei, Microsoft YaHei;
  392. font-weight: 400;
  393. font-size: 0.625vw;
  394. color: #E6F4FF;
  395. text-align: left;
  396. font-style: normal;
  397. text-transform: none;
  398. }
  399. .content-style-content .font6{
  400. font-family: Microsoft YaHei, Microsoft YaHei;
  401. font-weight: bold;
  402. font-size: 1.250vw;
  403. color: #FFFFFF;
  404. text-align: left;
  405. font-style: normal;
  406. text-transform: none;
  407. }
  408. .content-style-content .font7{
  409. font-family: Microsoft YaHei, Microsoft YaHei;
  410. font-weight: bold;
  411. font-size: 0.625vw;
  412. color: #FFFFFF;
  413. text-align: left;
  414. font-style: normal;
  415. text-transform: none;
  416. }
  417. </style>
  418. <style scoped>
  419. /deep/ .el-progress__text {
  420. position: absolute;
  421. top: 50%; /* 设置垂直居中 */
  422. left: 50%;
  423. transform: translateX(-50%) translateY(-50%); /* 移动到圆环中心 */
  424. font-family: Microsoft YaHei, Microsoft YaHei;
  425. font-weight: bold;
  426. font-size: 0.833vw !important;
  427. color: #E6F4FF !important;
  428. font-style: normal;
  429. text-transform: none;
  430. }
  431. /deep/ .el-button--primary:focus, .el-button--primary:hover {
  432. background: #6090f8;
  433. border-color: #6090f8;
  434. color: #6090f8;
  435. }
  436. /deep/ .element.style {
  437. font-size: 15.9386px;
  438. }
  439. ::v-deep .el-progress__text {
  440. white-space: pre;
  441. }
  442. </style>