index.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <template>
  2. <echart-base :options="options" v-model:loading="loading"></echart-base>
  3. </template>
  4. <script lang="ts">
  5. import { defineComponent, PropType, ref, watch, watchEffect } from 'vue';
  6. import { QueryHistoryDatasRsp, QueryQuoteDayRsp, QueryHistoryDatas, CycleType } from '@/services/go/quote/interface';
  7. import { QueryHistoryDatas as queryHistoryDatas } from '@/services/go/quote';
  8. import { handleEchart, ChartData } from './setup';
  9. import EchartBase from '../echart-base/index.vue';
  10. import moment from 'moment';
  11. export default defineComponent({
  12. name: 'EchartKline',
  13. components: {
  14. EchartBase,
  15. },
  16. props: {
  17. // 周期类型
  18. cycleType: {
  19. type: Number as PropType<CycleType>,
  20. required: true,
  21. },
  22. // 实时行情数据
  23. quoteData: {
  24. type: Object as PropType<QueryQuoteDayRsp>,
  25. required: true,
  26. },
  27. },
  28. setup(props) {
  29. const loading = ref(true);
  30. const { chartData, options, updateOptions, initOptions } = handleEchart();
  31. // 处理图表数据
  32. const handleData = (rawData: QueryHistoryDatasRsp[]): ChartData => {
  33. const datas: number[][] = [],
  34. times: string[] = [];
  35. rawData.forEach((item) => {
  36. const { o, c, h, l, ts } = item;
  37. const t = moment(ts).format('YYYY/MM/DD');
  38. times.push(t);
  39. datas.push([o, c, h, l]);
  40. });
  41. const { last, lasttime: lastTime } = props.quoteData;
  42. return {
  43. datas,
  44. times,
  45. last,
  46. lastTime,
  47. ma5: calcMA(rawData, 5),
  48. ma10: calcMA(rawData, 10),
  49. ma15: calcMA(rawData, 15),
  50. };
  51. };
  52. // 计算平均线
  53. const calcMA = (rawData: QueryHistoryDatasRsp[], count: number) => {
  54. const result: string[] = [];
  55. if (rawData.length >= count) {
  56. // 所有非补充数据的索引id
  57. const dataIndexs = rawData.reduce((prev: number[], cur, index) => {
  58. if (!cur.f) prev.push(index);
  59. return prev;
  60. }, []);
  61. // 均线起始位置
  62. const startIndex = dataIndexs[count - 1];
  63. rawData.forEach((item, index) => {
  64. if (index < startIndex) {
  65. result.push('-');
  66. } else {
  67. const j = dataIndexs.findIndex((val) => val === index);
  68. // 判断是否补充数据
  69. if (j === -1) {
  70. // 取上个平均值
  71. result.push(result[result.length - 1]);
  72. } else {
  73. // 向后取MA数
  74. const splitIndexs = dataIndexs.slice(j - (count - 1), j + 1);
  75. // 计算总价
  76. const total = splitIndexs.reduce((sum, val) => sum + rawData[val].c, 0);
  77. // 计算均线
  78. result.push((total / count).toFixed(2));
  79. }
  80. }
  81. });
  82. }
  83. return result;
  84. };
  85. // 监听周期选项变化
  86. watchEffect(() => {
  87. loading.value = true;
  88. const params: QueryHistoryDatas = {
  89. cycleType: props.cycleType,
  90. goodsCode: props.quoteData.goodscode,
  91. isAsc: true,
  92. };
  93. // 查询K线数据
  94. queryHistoryDatas(params).then((res) => {
  95. chartData.value = handleData(res);
  96. initOptions();
  97. });
  98. });
  99. watch(
  100. () => props.quoteData.last,
  101. (val) => {
  102. if (!loading.value) {
  103. chartData.value.last = val;
  104. updateOptions();
  105. }
  106. }
  107. );
  108. return {
  109. loading,
  110. options,
  111. };
  112. },
  113. });
  114. </script>