|
|
@@ -0,0 +1,292 @@
|
|
|
+import { reactive, computed, toRefs } from 'vue'
|
|
|
+import { handlePriceColor } from '@/filters'
|
|
|
+import { queryErmcpGoods, queryQuoteDay } from '@/services/api/goods'
|
|
|
+import { defineStore } from '../store'
|
|
|
+import { timerTask } from '@/utils/timer'
|
|
|
+import eventBus from '@/services/bus'
|
|
|
+import moment from 'moment'
|
|
|
+
|
|
|
+/**
|
|
|
+ * 期货存储对象
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+export const useFuturesStore = defineStore(() => {
|
|
|
+ const state = reactive({
|
|
|
+ loading: false,
|
|
|
+ goodsList: <Model.GoodsRsp[]>[], // 商品列表
|
|
|
+ quotes: <Partial<Model.QuoteDayRsp>[]>[], // 行情数据
|
|
|
+ goodsQuoteList: <Model.GoodsQuote[]>[], // 商品行情列表
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取商品列表
|
|
|
+ const getGoodsList = () => {
|
|
|
+ timerTask.clearTimeout('quoteDay')
|
|
|
+ queryErmcpGoods().then((res) => {
|
|
|
+ state.goodsList = res.data
|
|
|
+ const codes = res.data.map((e) => e.goodscode)
|
|
|
+ if (codes.length) {
|
|
|
+ getQuoteDay(codes)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // 获取商品盘面信息
|
|
|
+ const getQuoteDay = (codes: string[]) => {
|
|
|
+ state.loading = true
|
|
|
+ queryQuoteDay({
|
|
|
+ data: {
|
|
|
+ goodsCodes: codes.join(',')
|
|
|
+ }
|
|
|
+ }).then((res) => {
|
|
|
+ state.goodsList.forEach((e) => {
|
|
|
+ const quoteDay = res.data.find((q) => q.goodscode === e.goodscode)
|
|
|
+ const item: Model.GoodsQuote = {
|
|
|
+ goodsid: e.goodsid,
|
|
|
+ goodscode: e.goodscode,
|
|
|
+ goodsname: e.goodsname,
|
|
|
+ goodsgroupid: e.goodsgroupid,
|
|
|
+ goodunitid: e.goodunitid,
|
|
|
+ marketid: e.marketid,
|
|
|
+ trademode: e.trademode,
|
|
|
+ agreeunit: e.agreeunit,
|
|
|
+ decimalplace: e.decimalplace,
|
|
|
+ quoteminunit: e.quoteminunit,
|
|
|
+ quotegear: e.quotegear,
|
|
|
+ last: quoteDay?.last ?? 0,
|
|
|
+ lasttime: quoteDay?.lasttime ?? '',
|
|
|
+ bid: quoteDay?.bid ?? 0,
|
|
|
+ bid2: quoteDay?.bid2 ?? 0,
|
|
|
+ bid3: quoteDay?.bid3 ?? 0,
|
|
|
+ bid4: quoteDay?.bid4 ?? 0,
|
|
|
+ bid5: quoteDay?.bid5 ?? 0,
|
|
|
+ bidvolume: quoteDay?.bidvolume ?? 0,
|
|
|
+ bidvolume2: quoteDay?.bidvolume2 ?? 0,
|
|
|
+ bidvolume3: quoteDay?.bidvolume3 ?? 0,
|
|
|
+ bidvolume4: quoteDay?.bidvolume4 ?? 0,
|
|
|
+ bidvolume5: quoteDay?.bidvolume5 ?? 0,
|
|
|
+ ask: quoteDay?.ask ?? 0,
|
|
|
+ ask2: quoteDay?.ask2 ?? 0,
|
|
|
+ ask3: quoteDay?.ask3 ?? 0,
|
|
|
+ ask4: quoteDay?.ask4 ?? 0,
|
|
|
+ ask5: quoteDay?.ask5 ?? 0,
|
|
|
+ askvolume: quoteDay?.askvolume ?? 0,
|
|
|
+ askvolume2: quoteDay?.askvolume2 ?? 0,
|
|
|
+ askvolume3: quoteDay?.askvolume3 ?? 0,
|
|
|
+ askvolume4: quoteDay?.askvolume4 ?? 0,
|
|
|
+ askvolume5: quoteDay?.askvolume5 ?? 0,
|
|
|
+ lastvolume: quoteDay?.lastvolume ?? 0,
|
|
|
+ presettle: quoteDay?.presettle ?? 0,
|
|
|
+ opened: quoteDay?.opened ?? 0,
|
|
|
+ highest: quoteDay?.highest ?? 0,
|
|
|
+ lowest: quoteDay?.lowest ?? 0,
|
|
|
+ limitup: quoteDay?.limitup ?? 0,
|
|
|
+ limitdown: quoteDay?.limitdown ?? 0,
|
|
|
+ averageprice: quoteDay?.averageprice ?? 0,
|
|
|
+ rise: 0,
|
|
|
+ change: 0,
|
|
|
+ amplitude: 0,
|
|
|
+ bidColor: '',
|
|
|
+ bid2Color: '',
|
|
|
+ bid3Color: '',
|
|
|
+ bid4Color: '',
|
|
|
+ bid5Color: '',
|
|
|
+ askColor: '',
|
|
|
+ ask2Color: '',
|
|
|
+ ask3Color: '',
|
|
|
+ ask4Color: '',
|
|
|
+ ask5Color: '',
|
|
|
+ lastColor: '',
|
|
|
+ averagepriceColor: '',
|
|
|
+ openedColor: '',
|
|
|
+ highestColor: '',
|
|
|
+ lowestColor: '',
|
|
|
+ }
|
|
|
+ if (!updateGoodsQuote(item)) {
|
|
|
+ // 未完成-待处理计算和涨跌颜色
|
|
|
+ state.goodsQuoteList.push(item)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }).finally(() => {
|
|
|
+ state.loading = false
|
|
|
+ // 每5分钟获取一次盘面
|
|
|
+ timerTask.setTimeout(() => getQuoteDay(codes), 5 * 60 * 1000, 'quoteDay')
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过 goodscode 获取实时盘面
|
|
|
+ const getGoodsQuote = (code: string | number) => {
|
|
|
+ return computed(() => state.goodsQuoteList.find((e) => e.goodscode === code || e.goodsid === code))
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过 goodscode 获取实时行情报价
|
|
|
+ const getQuotePrice = (goodsCode: string) => {
|
|
|
+ return computed(() => {
|
|
|
+ const quote = getGoodsQuote(goodsCode)
|
|
|
+ return quote.value?.last ?? 0
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过 goodscode 获取实时行情
|
|
|
+ const getQuote = (goodsCode: string) => {
|
|
|
+ return computed(() => {
|
|
|
+ const quote = state.quotes.find((e) => e.goodscode === goodsCode)
|
|
|
+ return {
|
|
|
+ ...quote
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取商品名称
|
|
|
+ const getGoodsName = (code: string | number) => {
|
|
|
+ const quote = state.goodsList.find((e) => e.goodscode === code || e.goodsid === code)
|
|
|
+ return quote?.goodsname ?? ''
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取商品市场ID
|
|
|
+ const getGoodsMarket = (code: string | number) => {
|
|
|
+ const quote = state.goodsList.find((e) => e.goodscode === code || e.goodsid === code)
|
|
|
+ return quote?.marketid ?? 0
|
|
|
+ }
|
|
|
+
|
|
|
+ // 接收行情推送通知
|
|
|
+ const quotePushNotify = eventBus.$on('QuotePushNotify', (res) => {
|
|
|
+ const data = res as Proto.Quote[]
|
|
|
+ data.forEach((item) => {
|
|
|
+ const quote = handleQuote(item)
|
|
|
+ const index = state.quotes.findIndex((e) => e.goodscode === item.goodscode)
|
|
|
+ if (index > -1) {
|
|
|
+ state.quotes[index] = quote
|
|
|
+ } else {
|
|
|
+ state.quotes.push(quote)
|
|
|
+ }
|
|
|
+ if (!state.loading) {
|
|
|
+ updateGoodsQuote(quote)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ // 更新商品数据
|
|
|
+ const updateGoodsQuote = (quote: Partial<Model.QuoteDayRsp>) => {
|
|
|
+ const goods = state.goodsQuoteList.find((e) => e.goodscode === quote.goodscode)
|
|
|
+ if (goods) {
|
|
|
+ // 更新对象属性
|
|
|
+ Object.entries(quote).forEach(([key, value]) => {
|
|
|
+ if (value !== undefined) {
|
|
|
+ type TKey = keyof Model.GoodsQuote
|
|
|
+ (<K extends TKey>(prop: K, value: Model.GoodsQuote[K]) => {
|
|
|
+ goods[prop] = value
|
|
|
+ })(key as TKey, value)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 处理最高最低价
|
|
|
+ if (goods.last) {
|
|
|
+ if (goods.last > goods.highest) {
|
|
|
+ goods.highest = goods.last
|
|
|
+ }
|
|
|
+ if (goods.last < goods.lowest) {
|
|
|
+ goods.lowest = goods.last
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ goods.rise = goods.last ? goods.last - goods.presettle : 0 // 涨跌额/涨跌: 最新价 - 昨结价
|
|
|
+ goods.change = goods.presettle ? goods.rise / goods.presettle : 0 // 涨跌幅/幅度: (最新价 - 昨结价) / 昨结价
|
|
|
+ goods.amplitude = goods.presettle ? (goods.highest - goods.lowest) / goods.presettle : 0 // 振幅: (最高价 - 最低价 ) / 最新价
|
|
|
+
|
|
|
+ // 处理行情价格颜色
|
|
|
+ const handleColor = (value: number) => handlePriceColor(value, goods.presettle)
|
|
|
+
|
|
|
+ goods.bidColor = handleColor(goods.bid)
|
|
|
+ goods.bid2Color = handleColor(goods.bid2)
|
|
|
+ goods.bid3Color = handleColor(goods.bid3)
|
|
|
+ goods.bid4Color = handleColor(goods.bid4)
|
|
|
+ goods.bid5Color = handleColor(goods.bid5)
|
|
|
+ goods.askColor = handleColor(goods.ask)
|
|
|
+ goods.ask2Color = handleColor(goods.ask2)
|
|
|
+ goods.ask3Color = handleColor(goods.ask3)
|
|
|
+ goods.ask4Color = handleColor(goods.ask4)
|
|
|
+ goods.ask5Color = handleColor(goods.ask5)
|
|
|
+ goods.lastColor = handleColor(goods.last)
|
|
|
+ goods.averagepriceColor = handleColor(goods.averageprice)
|
|
|
+ goods.openedColor = handleColor(goods.opened)
|
|
|
+ goods.highestColor = handleColor(goods.highest)
|
|
|
+ goods.lowestColor = handleColor(goods.lowest)
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理行情数据
|
|
|
+ const handleQuote = (quote: Proto.Quote): Partial<Model.QuoteDayRsp> => {
|
|
|
+ const goods = state.goodsList.find((e) => e.goodscode.toUpperCase() === quote.goodscode?.toUpperCase())
|
|
|
+ // 处理报价小数位
|
|
|
+ const handleDeimalplace = (value?: number) => {
|
|
|
+ if (goods && value) {
|
|
|
+ const decimal = Math.pow(10, goods.decimalplace)
|
|
|
+ return value / decimal
|
|
|
+ }
|
|
|
+ return value
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ goodscode: quote.goodscode,
|
|
|
+ last: handleDeimalplace(quote.last),
|
|
|
+ lasttime: (quote.date && quote.time) ? moment(quote.date + quote.time, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss') : undefined,
|
|
|
+ ask: handleDeimalplace(quote.ask),
|
|
|
+ ask2: handleDeimalplace(quote.ask2),
|
|
|
+ ask3: handleDeimalplace(quote.ask3),
|
|
|
+ ask4: handleDeimalplace(quote.ask4),
|
|
|
+ ask5: handleDeimalplace(quote.ask5),
|
|
|
+ askvolume: quote.askvolume,
|
|
|
+ askvolume2: quote.askvolume2,
|
|
|
+ askvolume3: quote.askvolume3,
|
|
|
+ askvolume4: quote.askvolume4,
|
|
|
+ askvolume5: quote.askvolume5,
|
|
|
+ bid: handleDeimalplace(quote.bid),
|
|
|
+ bid2: handleDeimalplace(quote.bid2),
|
|
|
+ bid3: handleDeimalplace(quote.bid3),
|
|
|
+ bid4: handleDeimalplace(quote.bid4),
|
|
|
+ bid5: handleDeimalplace(quote.bid5),
|
|
|
+ bidvolume: quote.bidvolume,
|
|
|
+ bidvolume2: quote.bidvolume2,
|
|
|
+ bidvolume3: quote.bidvolume3,
|
|
|
+ bidvolume4: quote.bidvolume4,
|
|
|
+ bidvolume5: quote.bidvolume5,
|
|
|
+ calloptionpremiums: quote.calloptionpremiums,
|
|
|
+ calloptionpremiums2: quote.calloptionpremiums2,
|
|
|
+ calloptionpremiums3: quote.calloptionpremiums3,
|
|
|
+ calloptionpremiums4: quote.calloptionpremiums4,
|
|
|
+ calloptionpremiums5: quote.calloptionpremiums5,
|
|
|
+ exchangecode: quote.exchangecode,
|
|
|
+ exchangedate: quote.exchangedate,
|
|
|
+ highest: handleDeimalplace(quote.highest),
|
|
|
+ holdvolume: quote.holdvolume,
|
|
|
+ inventory: quote.inventory,
|
|
|
+ lastvolume: quote.lastvolume,
|
|
|
+ limitdown: handleDeimalplace(quote.limitlow),
|
|
|
+ limitup: handleDeimalplace(quote.limithigh),
|
|
|
+ lowest: handleDeimalplace(quote.lowest),
|
|
|
+ opened: handleDeimalplace(quote.opened),
|
|
|
+ preclose: handleDeimalplace(quote.preclose),
|
|
|
+ preholdvolume: quote.preholdvolume,
|
|
|
+ presettle: handleDeimalplace(quote.presettle),
|
|
|
+ putoptionpremiums: handleDeimalplace(quote.putoptionpremiums),
|
|
|
+ putoptionpremiums2: handleDeimalplace(quote.putoptionpremiums2),
|
|
|
+ putoptionpremiums3: handleDeimalplace(quote.putoptionpremiums3),
|
|
|
+ putoptionpremiums4: handleDeimalplace(quote.putoptionpremiums4),
|
|
|
+ putoptionpremiums5: handleDeimalplace(quote.putoptionpremiums5),
|
|
|
+ settle: handleDeimalplace(quote.settle),
|
|
|
+ totalturnover: handleDeimalplace(quote.totalturnover),
|
|
|
+ totalvolume: quote.totalvolume,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...toRefs(state),
|
|
|
+ getQuote,
|
|
|
+ getQuotePrice,
|
|
|
+ getGoodsList,
|
|
|
+ getGoodsQuote,
|
|
|
+ getGoodsName,
|
|
|
+ getGoodsMarket,
|
|
|
+ quotePushNotify,
|
|
|
+ }
|
|
|
+})
|