diff --git a/.env.development b/.env.development index ecd528e..e0116d3 100644 --- a/.env.development +++ b/.env.development @@ -1 +1,3 @@ -VITE_API_URL=http://192.168.1.27:9528 \ No newline at end of file +VITE_API_URL=http://192.168.1.27:9528 +VITE_TRADINGVIEW_LIBRARY_URL=http://192.168.1.37:6173 +VITE_TRADINGVIEW_DATA_API_URL=https://demo-feed-data.tradingview.com \ No newline at end of file diff --git a/.env.production b/.env.production index ca1bedc..4dcf6cd 100644 --- a/.env.production +++ b/.env.production @@ -1 +1,3 @@ -VITE_API_URL=http://192.168.1.27:9527 \ No newline at end of file +VITE_API_URL=http://192.168.1.27:9527 +VITE_TRADINGVIEW_LIBRARY_URL=http://192.168.1.37:6173 +VITE_TRADINGVIEW_DATA_API_URL=https://demo-feed-data.tradingview.com \ No newline at end of file diff --git a/auto-imports.d.ts b/auto-imports.d.ts index e077f5d..8322c8d 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -196,6 +196,7 @@ declare global { const useElementHover: typeof import('@vueuse/core').useElementHover const useElementSize: typeof import('@vueuse/core').useElementSize const useElementVisibility: typeof import('@vueuse/core').useElementVisibility + const useEnv: typeof import('./src/composables/useEnv').useEnv const useEventBus: typeof import('@vueuse/core').useEventBus const useEventListener: typeof import('@vueuse/core').useEventListener const useEventSource: typeof import('@vueuse/core').useEventSource @@ -559,6 +560,7 @@ declare module 'vue' { readonly useElementHover: UnwrapRef readonly useElementSize: UnwrapRef readonly useElementVisibility: UnwrapRef + readonly useEnv: UnwrapRef readonly useEventBus: UnwrapRef readonly useEventListener: UnwrapRef readonly useEventSource: UnwrapRef diff --git a/index.html b/index.html index 5365544..82d6043 100644 --- a/index.html +++ b/index.html @@ -20,9 +20,6 @@ - - - diff --git a/src/composables/useEnv.ts b/src/composables/useEnv.ts new file mode 100644 index 0000000..57c9ca4 --- /dev/null +++ b/src/composables/useEnv.ts @@ -0,0 +1,3 @@ +export function useEnv(): ImportMetaEnv { + return import.meta.env; +} diff --git a/src/main.ts b/src/main.ts index 1efe6b8..44ba798 100644 --- a/src/main.ts +++ b/src/main.ts @@ -41,28 +41,51 @@ import "./theme/ionic.css"; useTheme(); +function initTradingView() { + const { VITE_TRADINGVIEW_LIBRARY_URL } = useEnv(); + const promise1 = new Promise((resolve) => { + const script = document.createElement("script"); + script.type = "text/javascript"; + script.src = `${VITE_TRADINGVIEW_LIBRARY_URL}/charting_library/charting_library.standalone.js`; + script.async = true; + document.body.appendChild(script); + script.onload = () => resolve(true); + }); + const promise2 = new Promise((resolve) => { + const script = document.createElement("script"); + script.type = "text/javascript"; + script.src = `${VITE_TRADINGVIEW_LIBRARY_URL}/datafeeds/udf/bundle.js`; + script.async = true; + document.body.appendChild(script); + script.onload = () => resolve(true); + }); + return Promise.all([promise1, promise2]); +} + function initApp() { - authClient.getSession().then((session) => { - const pinia = createPinia(); - const userStore = useUserStore(pinia); - userStore.setToken(session.data?.session.token || ""); + initTradingView().then(() => { + authClient.getSession().then((session) => { + const pinia = createPinia(); + const userStore = useUserStore(pinia); + userStore.setToken(session.data?.session.token || ""); - const app = createApp(App) - .use(IonicVue, { - backButtonText: "返回", - mode: "ios", - statusTap: true, - swipeBackEnabled: true, - // rippleEffect: true, - // animated: false, - }) - .use(uiComponents) - .use(pinia) - .use(router) - .use(i18n); + const app = createApp(App) + .use(IonicVue, { + backButtonText: "返回", + mode: "ios", + statusTap: true, + swipeBackEnabled: true, + // rippleEffect: true, + // animated: false, + }) + .use(uiComponents) + .use(pinia) + .use(router) + .use(i18n); - router.isReady().then(() => { - app.mount("#app"); + router.isReady().then(() => { + app.mount("#app"); + }); }); }); } diff --git a/src/tradingview/index.tsx b/src/tradingview/index.tsx index 98020fd..237d5d0 100644 --- a/src/tradingview/index.tsx +++ b/src/tradingview/index.tsx @@ -1,22 +1,60 @@ +import type { ChartingLibraryWidgetOptions } from "#/charting_library"; import type { ResolutionString } from "#/datafeed-api"; +const { VITE_TRADINGVIEW_LIBRARY_URL, VITE_TRADINGVIEW_DATA_API_URL } = useEnv(); + +const defaultOptions = { + container: "tradingview_chart_container", + locale: "zh", + library_path: `${VITE_TRADINGVIEW_LIBRARY_URL}/charting_library/`, + datafeed: new Datafeeds.UDFCompatibleDatafeed(VITE_TRADINGVIEW_DATA_API_URL, 60000), + symbol: "AAPL", + interval: "1D" as ResolutionString, + debug: true, + autosize: true, + // 禁用移动端不友好的功能 + disabled_features: [ + "left_toolbar", // 隐藏左侧绘图工具栏 + "timeframes_toolbar", // 隐藏底部时间框架工具栏 + "volume_force_overlay", // 禁用成交量覆盖在价格图表上 + // 禁用顶部工具栏 + "header_widget", + "header_compare", + "header_symbol_search", + "header_fullscreen_button", + "header_settings", + ], + // 启用移动端友好的功能 + enabled_features: [ + "show_zoom_and_move_buttons_on_touch", // 在触摸设备上显示缩放和移动按钮 + "adaptive_logo", // 在小屏幕设备上隐藏 TradingView logo + ], +} satisfies ChartingLibraryWidgetOptions; + export const TradingViewChart = defineComponent({ name: "TradingViewChart", - setup(props, ctx) { - const chartContainer = ref(); + props: { + options: { + type: Object as PropType>, + required: false, + }, + }, + setup(props) { + const el = ref(null); + onMounted(() => { // eslint-disable-next-line new-cap - const tradingView = new TradingView.widget({ - container: chartContainer.value!, - locale: "en", - library_path: "http://localhost:6173/charting_library/", - datafeed: new Datafeeds.UDFCompatibleDatafeed("https://demo-feed-data.tradingview.com"), - symbol: "AAPL", - interval: "1D" as ResolutionString, - debug: true, + const widget = new TradingView.widget({ + ...defaultOptions, + ...props.options, + container: el.value!, + }); + + widget.onChartReady(() => { + widget.setDebugMode(true); }); }); - return () =>
; + return () =>
; }, }); diff --git a/src/views/trade/index.vue b/src/views/trade/index.vue index 222a090..673873a 100644 --- a/src/views/trade/index.vue +++ b/src/views/trade/index.vue @@ -7,35 +7,6 @@ import TradeSwitch from "./components/trade-switch.vue"; import TradeWay from "./components/trade-way.vue"; const mode = ref<"buy" | "sell">("buy"); -const tradingViewContainer = useTemplateRef("tradingViewContainer"); - -const { chart, series } = useTradingView(tradingViewContainer, { - data: [ - { time: "2024-01-01", open: 42000, high: 43100, low: 41800, close: 42500 }, - { time: "2024-01-02", open: 42500, high: 43500, low: 42200, close: 43000 }, - { time: "2024-01-03", open: 43000, high: 44200, low: 42800, close: 43800 }, - { time: "2024-01-04", open: 43800, high: 44500, low: 43500, close: 44200 }, - { time: "2024-01-05", open: 44200, high: 44800, low: 43900, close: 44500 }, - { time: "2024-01-06", open: 44500, high: 45000, low: 44200, close: 44800 }, - { time: "2024-01-07", open: 44800, high: 45500, low: 44500, close: 45250 }, - { time: "2024-01-08", open: 45250, high: 46000, low: 45100, close: 45800 }, - { time: "2024-01-09", open: 45800, high: 46200, low: 45500, close: 45600 }, - { time: "2024-01-10", open: 45600, high: 45900, low: 45200, close: 45400 }, - { time: "2024-01-11", open: 45400, high: 45800, low: 44900, close: 45100 }, - { time: "2024-01-12", open: 45100, high: 45500, low: 44700, close: 45200 }, - { time: "2024-01-13", open: 45200, high: 45800, low: 45000, close: 45600 }, - { time: "2024-01-14", open: 45600, high: 46500, low: 45500, close: 46300 }, - { time: "2024-01-15", open: 46300, high: 47000, low: 46200, close: 46800 }, - ], -}); - -onMounted(() => { - const panes = chart.value?.panes(); - series.value?.applyOptions({ - upColor: "#3fba6e", - downColor: "#f45531", - }); -});