feat: 添加 TradingView 相关环境变量和初始化逻辑;重构交易视图组件
This commit is contained in:
@@ -1 +1,3 @@
|
|||||||
VITE_API_URL=http://192.168.1.27:9528
|
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
|
||||||
@@ -1 +1,3 @@
|
|||||||
VITE_API_URL=http://192.168.1.27:9527
|
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
|
||||||
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@@ -196,6 +196,7 @@ declare global {
|
|||||||
const useElementHover: typeof import('@vueuse/core').useElementHover
|
const useElementHover: typeof import('@vueuse/core').useElementHover
|
||||||
const useElementSize: typeof import('@vueuse/core').useElementSize
|
const useElementSize: typeof import('@vueuse/core').useElementSize
|
||||||
const useElementVisibility: typeof import('@vueuse/core').useElementVisibility
|
const useElementVisibility: typeof import('@vueuse/core').useElementVisibility
|
||||||
|
const useEnv: typeof import('./src/composables/useEnv').useEnv
|
||||||
const useEventBus: typeof import('@vueuse/core').useEventBus
|
const useEventBus: typeof import('@vueuse/core').useEventBus
|
||||||
const useEventListener: typeof import('@vueuse/core').useEventListener
|
const useEventListener: typeof import('@vueuse/core').useEventListener
|
||||||
const useEventSource: typeof import('@vueuse/core').useEventSource
|
const useEventSource: typeof import('@vueuse/core').useEventSource
|
||||||
@@ -559,6 +560,7 @@ declare module 'vue' {
|
|||||||
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']>
|
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']>
|
||||||
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']>
|
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']>
|
||||||
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']>
|
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']>
|
||||||
|
readonly useEnv: UnwrapRef<typeof import('./src/composables/useEnv')['useEnv']>
|
||||||
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']>
|
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']>
|
||||||
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']>
|
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']>
|
||||||
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']>
|
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']>
|
||||||
|
|||||||
@@ -20,9 +20,6 @@
|
|||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Ionic App" />
|
<meta name="apple-mobile-web-app-title" content="Ionic App" />
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||||
|
|
||||||
<script type="text/javascript" src="http://localhost:6173/charting_library/charting_library.standalone.js"></script>
|
|
||||||
<script type="text/javascript" src="http://localhost:6173/datafeeds/udf/bundle.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
3
src/composables/useEnv.ts
Normal file
3
src/composables/useEnv.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function useEnv(): ImportMetaEnv {
|
||||||
|
return import.meta.env;
|
||||||
|
}
|
||||||
23
src/main.ts
23
src/main.ts
@@ -41,7 +41,29 @@ import "./theme/ionic.css";
|
|||||||
|
|
||||||
useTheme();
|
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() {
|
function initApp() {
|
||||||
|
initTradingView().then(() => {
|
||||||
authClient.getSession().then((session) => {
|
authClient.getSession().then((session) => {
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
const userStore = useUserStore(pinia);
|
const userStore = useUserStore(pinia);
|
||||||
@@ -65,6 +87,7 @@ function initApp() {
|
|||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setupMocks().then(() => {
|
setupMocks().then(() => {
|
||||||
|
|||||||
@@ -1,22 +1,60 @@
|
|||||||
|
import type { ChartingLibraryWidgetOptions } from "#/charting_library";
|
||||||
import type { ResolutionString } from "#/datafeed-api";
|
import type { ResolutionString } from "#/datafeed-api";
|
||||||
|
|
||||||
export const TradingViewChart = defineComponent({
|
const { VITE_TRADINGVIEW_LIBRARY_URL, VITE_TRADINGVIEW_DATA_API_URL } = useEnv();
|
||||||
name: "TradingViewChart",
|
|
||||||
setup(props, ctx) {
|
const defaultOptions = {
|
||||||
const chartContainer = ref<HTMLDivElement>();
|
container: "tradingview_chart_container",
|
||||||
onMounted(() => {
|
locale: "zh",
|
||||||
// eslint-disable-next-line new-cap
|
library_path: `${VITE_TRADINGVIEW_LIBRARY_URL}/charting_library/`,
|
||||||
const tradingView = new TradingView.widget({
|
datafeed: new Datafeeds.UDFCompatibleDatafeed(VITE_TRADINGVIEW_DATA_API_URL, 60000),
|
||||||
container: chartContainer.value!,
|
|
||||||
locale: "en",
|
|
||||||
library_path: "http://localhost:6173/charting_library/",
|
|
||||||
datafeed: new Datafeeds.UDFCompatibleDatafeed("https://demo-feed-data.tradingview.com"),
|
|
||||||
symbol: "AAPL",
|
symbol: "AAPL",
|
||||||
interval: "1D" as ResolutionString,
|
interval: "1D" as ResolutionString,
|
||||||
debug: true,
|
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",
|
||||||
|
props: {
|
||||||
|
options: {
|
||||||
|
type: Object as PropType<Partial<ChartingLibraryWidgetOptions>>,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const el = ref<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
const widget = new TradingView.widget({
|
||||||
|
...defaultOptions,
|
||||||
|
...props.options,
|
||||||
|
container: el.value!,
|
||||||
|
});
|
||||||
|
|
||||||
|
widget.onChartReady(() => {
|
||||||
|
widget.setDebugMode(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => <div ref={chartContainer} class="w-full h-150" />;
|
return () => <div ref={el} class="w-full h-70" />;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,35 +7,6 @@ import TradeSwitch from "./components/trade-switch.vue";
|
|||||||
import TradeWay from "./components/trade-way.vue";
|
import TradeWay from "./components/trade-way.vue";
|
||||||
|
|
||||||
const mode = ref<"buy" | "sell">("buy");
|
const mode = ref<"buy" | "sell">("buy");
|
||||||
const tradingViewContainer = useTemplateRef<HTMLDivElement>("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",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -62,8 +33,7 @@ onMounted(() => {
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content :fullscreen="true">
|
<ion-content :fullscreen="true">
|
||||||
<!-- <div ref="tradingViewContainer" class="h-50" /> -->
|
<TradingViewChart class="mb-5" />
|
||||||
<TradingViewChart />
|
|
||||||
<div class="grid grid-cols-5">
|
<div class="grid grid-cols-5">
|
||||||
<div class="col-span-3 space-y-2">
|
<div class="col-span-3 space-y-2">
|
||||||
<TradeSwitch v-model:active="mode" />
|
<TradeSwitch v-model:active="mode" />
|
||||||
|
|||||||
16
types/env.d.ts
vendored
16
types/env.d.ts
vendored
@@ -1,3 +1,19 @@
|
|||||||
// env.d.ts
|
// env.d.ts
|
||||||
/// <reference types="vitest" />
|
/// <reference types="vitest" />
|
||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ViteTypeOptions {
|
||||||
|
// 添加这行代码,你就可以将 ImportMetaEnv 的类型设为严格模式,
|
||||||
|
// 这样就不允许有未知的键值了。
|
||||||
|
// strictImportMetaEnv: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_API_URL: string;
|
||||||
|
readonly VITE_TRADINGVIEW_LIBRARY_URL: string;
|
||||||
|
readonly VITE_TRADINGVIEW_DATA_API_URL: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user