股票k线图信息

This commit is contained in:
xlmessage 2025-02-12 18:48:17 +08:00
commit a42e22161e
36 changed files with 11269 additions and 0 deletions

30
.gitignore vendored Normal file

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

3
.vscode/extensions.json vendored Normal file

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

33
README.md Normal file

@ -0,0 +1,33 @@
# asideviewts
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```

1
env.d.ts vendored Normal file

@ -0,0 +1 @@
/// <reference types="vite/client" />

20
index.html Normal file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<style>
body{
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

3513
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

32
package.json Normal file

@ -0,0 +1,32 @@
{
"name": "asideviewts",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build"
},
"dependencies": {
"axios": "^1.7.9",
"echarts": "^5.6.0",
"element-plus": "^2.9.1",
"pinia": "^2.3.1",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.0",
"@types/node": "^22.10.2",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0",
"npm-run-all2": "^7.0.2",
"typescript": "~5.6.3",
"vite": "^6.0.5",
"vite-plugin-vue-devtools": "^7.6.8",
"vue-tsc": "^2.1.10"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

9
src/App.vue Normal file

@ -0,0 +1,9 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView />
</template>

101
src/assets/base.css Normal file

@ -0,0 +1,101 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgb(168, 168, 168);
--my-common-bgc-1:#fff;
--my-common-bgc-2:#1F1F1F;
--my-common-fc-1:#fff;
--my-common-fc-2:#000;
--my-light-bgc-1: #ffffff;
--my-light-bgc-2: #000000;
--my-light-br-1: #e7ebf3;
--my-light-br-2: #ffffff;
--my-light-fc-1: #414040;
--my-light-fc-2: #414040;
}
/* semantic color variables for this project */
/* :root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} */

1
src/assets/logo.svg Normal file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

After

Width:  |  Height:  |  Size: 276 B

35
src/assets/main.css Normal file

@ -0,0 +1,35 @@
@import './base.css';
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
padding: 3px;
}
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2);
}
}
@media (min-width: 1024px) {
body {
display: flex;
place-items: center;
}
#app {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
}
}

840
src/end/DayDesign.vue Normal file

@ -0,0 +1,840 @@
<script setup>
import { onMounted, inject, ref, nextTick, onUnmounted, onBeforeUnmount } from 'vue'
// pinia
import useEcharts from '@/store/usethemestore'
const echartsState = useEcharts()
echartsState.optionConfigData()
//echarts
let echarts = inject('echarts')
//
const chartsInfo = ref(null)
// K线
const mKline = ref(null)
//
let heightList = ref([])
//
const dynamicsHeight = () => {
//
let domHeightList = chartsInfo.value.offsetHeight
//
if (clicklist.value.length) {
//
heightList.value = []
//
heightList.value.push(domHeightList * (1 - clicklist.value.length * 0.15))
// K线
mKline.value.style.height = `${heightList.value[0]}px`
//
heightList.value.push(domHeightList * 0.15)
console.log(heightList.value)
} else {
//
heightList.value = []
// K线
mKline.value.style.height = `${domHeightList}px`
}
}
//
let chartConfigs = ref([
{
id: 1,
name: 'MAVOL',
attId: 'charts1',
status: false,
options: {
tooltip: {
trigger: 'axis', //
axisPointer: {
//
type: 'cross', //
label: {
backgroundColor: '#6a7985', //
},
},
},
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
],
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
series: [
{
name: 'Email',
type: 'line',
stack: 'Total',
data: [120, 132, 101, 134, 90, 230, 210],
},
{
name: 'Union Ads',
type: 'line',
stack: 'Total',
data: [220, 182, 191, 234, 290, 330, 310],
},
{
name: 'Video Ads',
type: 'line',
stack: 'Total',
data: [150, 232, 201, 154, 190, 330, 410],
},
{
name: 'Direct',
type: 'line',
stack: 'Total',
data: [320, 332, 301, 334, 390, 330, 320],
},
{
name: 'Search Engine',
type: 'line',
stack: 'Total',
data: [820, 932, 901, 934, 1290, 1330, 1320],
},
],
},
},
{
id: 2,
name: 'VOL',
attId: 'charts2',
status: false,
options: {
// title: {
// text: 'Stacked Area Chart',
// },
// tooltip: {
// trigger: 'axis',
// axisPointer: {
// type: 'cross',
// label: {
// backgroundColor: '#6a7985',
// },
// },
// },
// legend: {
// data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine'],
// },
// toolbox: {
// feature: {
// saveAsImage: {},
// },
// },
// grid: {
// left: '3%',
// right: '4%',
// bottom: '3%',
// containLabel: true,
// },
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
],
xAxis: [
{
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
],
yAxis: [
{
type: 'value',
},
],
series: [
{
name: 'Email',
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [120, 132, 101, 134, 90, 230, 210],
},
{
name: 'Union Ads',
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [220, 182, 191, 234, 290, 330, 310],
},
{
name: 'Video Ads',
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [150, 232, 201, 154, 190, 330, 410],
},
{
name: 'Direct',
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [320, 332, 301, 334, 390, 330, 320],
},
{
name: 'Search Engine',
type: 'line',
stack: 'Total',
label: {
show: true,
position: 'top',
},
areaStyle: {},
emphasis: {
focus: 'series',
},
data: [820, 932, 901, 934, 1290, 1330, 1320],
},
],
},
},
{
id: 3,
name: 'MACD',
attId: 'charts3',
status: false,
options:{
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
],
}
},
{
id: 4,
name: 'KDJ',
attId: 'charts4',
status: false,
options:{
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
],
}
},
{
id: 5,
name: 'RSI',
attId: 'charts5',
status: false,
options:{
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
],
}
},
])
//
const clicklist = ref([])
//
const addChart = (item) => {
//
if (clicklist.value.includes(item.name)) {
//
echarts.dispose(item.name)
//
clicklist.value = clicklist.value.filter((content) => content !== item.name)
// false
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = false
}
})
//
dynamicsHeight()
//
nextTick(() => {
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = false
// configecharts
configecharts()
}
})
})
} else {
//
clicklist.value.push(item.name)
// true
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = true
}
})
//
dynamicsHeight()
//
nextTick(() => {
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = true
// configecharts
configecharts()
// commonecharts
commonecharts(item.attId, item.options)
}
})
})
}
}
const upColor = '#ec0000';
const upBorderColor = '#8A0000';
const downColor = '#00da3c';
const downBorderColor = '#008F28';
// Each item: opencloselowesthighest
const data0 = splitData([
['2013/1/24', 2320.26, 2320.26, 2287.3, 2362.94],
['2013/1/25', 2300, 2291.3, 2288.26, 2308.38],
['2013/1/28', 2295.35, 2346.5, 2295.35, 2346.92],
['2013/1/29', 2347.22, 2358.98, 2337.35, 2363.8],
['2013/1/30', 2360.75, 2382.48, 2347.89, 2383.76],
['2013/1/31', 2383.43, 2385.42, 2371.23, 2391.82],
['2013/2/1', 2377.41, 2419.02, 2369.57, 2421.15],
['2013/2/4', 2425.92, 2428.15, 2417.58, 2440.38],
['2013/2/5', 2411, 2433.13, 2403.3, 2437.42],
['2013/2/6', 2432.68, 2434.48, 2427.7, 2441.73],
['2013/2/7', 2430.69, 2418.53, 2394.22, 2433.89],
['2013/2/8', 2416.62, 2432.4, 2414.4, 2443.03],
['2013/2/18', 2441.91, 2421.56, 2415.43, 2444.8],
['2013/2/19', 2420.26, 2382.91, 2373.53, 2427.07],
['2013/2/20', 2383.49, 2397.18, 2370.61, 2397.94],
['2013/2/21', 2378.82, 2325.95, 2309.17, 2378.82],
['2013/2/22', 2322.94, 2314.16, 2308.76, 2330.88],
['2013/2/25', 2320.62, 2325.82, 2315.01, 2338.78],
['2013/2/26', 2313.74, 2293.34, 2289.89, 2340.71],
['2013/2/27', 2297.77, 2313.22, 2292.03, 2324.63],
['2013/2/28', 2322.32, 2365.59, 2308.92, 2366.16],
['2013/3/1', 2364.54, 2359.51, 2330.86, 2369.65],
['2013/3/4', 2332.08, 2273.4, 2259.25, 2333.54],
['2013/3/5', 2274.81, 2326.31, 2270.1, 2328.14],
['2013/3/6', 2333.61, 2347.18, 2321.6, 2351.44],
['2013/3/7', 2340.44, 2324.29, 2304.27, 2352.02],
['2013/3/8', 2326.42, 2318.61, 2314.59, 2333.67],
['2013/3/11', 2314.68, 2310.59, 2296.58, 2320.96],
['2013/3/12', 2309.16, 2286.6, 2264.83, 2333.29],
['2013/3/13', 2282.17, 2263.97, 2253.25, 2286.33],
['2013/3/14', 2255.77, 2270.28, 2253.31, 2276.22],
['2013/3/15', 2269.31, 2278.4, 2250, 2312.08],
['2013/3/18', 2267.29, 2240.02, 2239.21, 2276.05],
['2013/3/19', 2244.26, 2257.43, 2232.02, 2261.31],
['2013/3/20', 2257.74, 2317.37, 2257.42, 2317.86],
['2013/3/21', 2318.21, 2324.24, 2311.6, 2330.81],
['2013/3/22', 2321.4, 2328.28, 2314.97, 2332],
['2013/3/25', 2334.74, 2326.72, 2319.91, 2344.89],
['2013/3/26', 2318.58, 2297.67, 2281.12, 2319.99],
['2013/3/27', 2299.38, 2301.26, 2289, 2323.48],
['2013/3/28', 2273.55, 2236.3, 2232.91, 2273.55],
['2013/3/29', 2238.49, 2236.62, 2228.81, 2246.87],
['2013/4/1', 2229.46, 2234.4, 2227.31, 2243.95],
['2013/4/2', 2234.9, 2227.74, 2220.44, 2253.42],
['2013/4/3', 2232.69, 2225.29, 2217.25, 2241.34],
['2013/4/8', 2196.24, 2211.59, 2180.67, 2212.59],
['2013/4/9', 2215.47, 2225.77, 2215.47, 2234.73],
['2013/4/10', 2224.93, 2226.13, 2212.56, 2233.04],
['2013/4/11', 2236.98, 2219.55, 2217.26, 2242.48],
['2013/4/12', 2218.09, 2206.78, 2204.44, 2226.26],
['2013/4/15', 2199.91, 2181.94, 2177.39, 2204.99],
['2013/4/16', 2169.63, 2194.85, 2165.78, 2196.43],
['2013/4/17', 2195.03, 2193.8, 2178.47, 2197.51],
['2013/4/18', 2181.82, 2197.6, 2175.44, 2206.03],
['2013/4/19', 2201.12, 2244.64, 2200.58, 2250.11],
['2013/4/22', 2236.4, 2242.17, 2232.26, 2245.12],
['2013/4/23', 2242.62, 2184.54, 2182.81, 2242.62],
['2013/4/24', 2187.35, 2218.32, 2184.11, 2226.12],
['2013/4/25', 2213.19, 2199.31, 2191.85, 2224.63],
['2013/4/26', 2203.89, 2177.91, 2173.86, 2210.58],
['2013/5/2', 2170.78, 2174.12, 2161.14, 2179.65],
['2013/5/3', 2179.05, 2205.5, 2179.05, 2222.81],
['2013/5/6', 2212.5, 2231.17, 2212.5, 2236.07],
['2013/5/7', 2227.86, 2235.57, 2219.44, 2240.26],
['2013/5/8', 2242.39, 2246.3, 2235.42, 2255.21],
['2013/5/9', 2246.96, 2232.97, 2221.38, 2247.86],
['2013/5/10', 2228.82, 2246.83, 2225.81, 2247.67],
['2013/5/13', 2247.68, 2241.92, 2231.36, 2250.85],
['2013/5/14', 2238.9, 2217.01, 2205.87, 2239.93],
['2013/5/15', 2217.09, 2224.8, 2213.58, 2225.19],
['2013/5/16', 2221.34, 2251.81, 2210.77, 2252.87],
['2013/5/17', 2249.81, 2282.87, 2248.41, 2288.09],
['2013/5/20', 2286.33, 2299.99, 2281.9, 2309.39],
['2013/5/21', 2297.11, 2305.11, 2290.12, 2305.3],
['2013/5/22', 2303.75, 2302.4, 2292.43, 2314.18],
['2013/5/23', 2293.81, 2275.67, 2274.1, 2304.95],
['2013/5/24', 2281.45, 2288.53, 2270.25, 2292.59],
['2013/5/27', 2286.66, 2293.08, 2283.94, 2301.7],
['2013/5/28', 2293.4, 2321.32, 2281.47, 2322.1],
['2013/5/29', 2323.54, 2324.02, 2321.17, 2334.33],
['2013/5/30', 2316.25, 2317.75, 2310.49, 2325.72],
['2013/5/31', 2320.74, 2300.59, 2299.37, 2325.53],
['2013/6/3', 2300.21, 2299.25, 2294.11, 2313.43],
['2013/6/4', 2297.1, 2272.42, 2264.76, 2297.1],
['2013/6/5', 2270.71, 2270.93, 2260.87, 2276.86],
['2013/6/6', 2264.43, 2242.11, 2240.07, 2266.69],
['2013/6/7', 2242.26, 2210.9, 2205.07, 2250.63],
['2013/6/13', 2190.1, 2148.35, 2126.22, 2190.1]
]);
function splitData(rawData) {
const categoryData = [];
const values = [];
for (var i = 0; i < rawData.length; i++) {
categoryData.push(rawData[i].splice(0, 1)[0]);
values.push(rawData[i]);
}
return {
categoryData: categoryData,
values: values
};
}
function calculateMA(dayCount) {
var result = [];
for (var i = 0, len = data0.values.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++) {
sum += +data0.values[i - j][1];
}
result.push(sum / dayCount);
}
return result;
}
// Echarts便使echarts.connect()
const configecharts = (options = {}) => {
// _echarts_instance_
document.getElementById('main').removeAttribute('_echarts_instance_')
// k线
let chartBox = echarts.init(document.getElementById('main'))
// 使piniaoption
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30']
},
grid: [{
left: '3%',
right: '3%',
bottom: '5%',
}],
xAxis: {
type: 'category',
data: data0.categoryData,
boundaryGap: false,
axisLine: { onZero: false },
splitLine: { show: false },
min: 'dataMin',
max: 'dataMax'
},
yAxis: {
scale: true,
splitArea: {
show: true
}
},
dataZoom: [
{
type: 'inside',
start: 50,
end: 100
},
{
show: true,
type: 'slider',
top: '90%',
start: 50,
end: 100
}
],
series: [
{
name: '日K',
type: 'candlestick',
data: data0.values,
itemStyle: {
color: upColor,
color0: downColor,
borderColor: upBorderColor,
borderColor0: downBorderColor
},
markPoint: {
label: {
formatter: function (param) {
return param != null ? Math.round(param.value) + '' : '';
}
},
data: [
{
name: 'Mark',
coord: ['2013/5/31', 2300],
value: 2300,
itemStyle: {
color: 'rgb(41,60,85)'
}
},
{
name: 'highest value',
type: 'max',
valueDim: 'highest'
},
{
name: 'lowest value',
type: 'min',
valueDim: 'lowest'
},
{
name: 'average value on close',
type: 'average',
valueDim: 'close'
}
],
tooltip: {
formatter: function (param) {
return param.name + '<br>' + (param.data.coord || '');
}
}
},
markLine: {
symbol: ['none', 'none'],
data: [
[
{
name: 'from lowest to highest',
type: 'min',
valueDim: 'lowest',
symbol: 'circle',
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
},
{
type: 'max',
valueDim: 'highest',
symbol: 'circle',
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
}
],
{
name: 'min line on close',
type: 'min',
valueDim: 'close'
},
{
name: 'max line on close',
type: 'max',
valueDim: 'close'
}
]
}
},
{
name: 'MA5',
type: 'line',
data: calculateMA(5),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA10',
type: 'line',
data: calculateMA(10),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA20',
type: 'line',
data: calculateMA(20),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA30',
type: 'line',
data: calculateMA(30),
smooth: true,
lineStyle: {
opacity: 0.5
}
}
]
};
//
chartBox.setOption(option)
// mergeOptions
// ?
chartBox.setOption(options)
//
chartBox.group = 'group1'
//
window.addEventListener('resize', function () {
chartBox.resize()
})
return chartBox
}
//Echarts便使echarts.connect()
const commonecharts = (containerId, options = {}) => {
// _echarts_instance_
document.getElementById(containerId).removeAttribute('_echarts_instance_')
//
const chart = echarts.init(document.getElementById(containerId))
//
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
grid: {
top: '10%',
left: '3%',
right: '3%',
bottom: '20%',
},
dataZoom: [
{
type: 'inside',
},
],
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: true,
},
],
}
//
chart.setOption(option)
// mergeOptions
chart.setOption(options)
//
chart.group = 'group1'
//
window.addEventListener('resize', function () {
chartBox2.resize()
})
return chart
}
//
echarts.connect('group1')
onMounted(() => {
dynamicsHeight()
configecharts()
})
onBeforeUnmount(()=>{
echarts.disconnect()
})
</script>
<template>
<div class="box">
<div class="chartsinfo" ref="chartsInfo">
<!-- K线图 -->
<div
id="main"
ref="mKline"
class="flex-item"
:style="{ height: `${heightList[0]}px` }"
></div>
<div
v-if="chartConfigs[0].status"
id="charts1"
ref="charts1"
:style="{ height: `${heightList[1]}px` }"
></div>
<div
v-if="chartConfigs[1].status"
id="charts2"
ref="charts2"
:style="{ height: `${heightList[1]}px` }"
></div>
<div
v-if="chartConfigs[2].status"
id="charts3"
ref="charts3"
:style="{ height: `${heightList[1]}px` }"
></div>
<div
v-if="chartConfigs[3].status"
id="charts4"
ref="charts4"
:style="{ height: `${heightList[1]}px` }"
></div>
<div
v-if="chartConfigs[4].status"
id="charts5"
ref="charts5"
:style="{ height: `${heightList[1]}px` }"
></div>
</div>
<!-- 底部的各个图表选项信息 -->
<ul class="typelist">
<li
v-for="(item, index) in chartConfigs"
:key="index"
@click="addChart(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
<style scoped>
.box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.chartsinfo {
height: calc(100vh - 20px);
}
.typelist {
margin-top: auto;
position: relative;
z-index: 99999999;
color: #191919;
width: 100%;
font-size: 12px;
display: flex;
list-style: none;
padding: 0;
}
.typelist > li {
padding: 2px 8px;
cursor: pointer;
}
.active {
color: #2d98b9;
}
</style>

957
src/end/EndDesign.vue Normal file

@ -0,0 +1,957 @@
<script setup>
import {
onMounted,
inject,
ref,
nextTick,
onBeforeUnmount,
} from 'vue'
import {
calculateMA,
calculateStdDeviation,
calculateMACD,
calculateKDJ,
calculateRSI,
calculateVOL,
} from './computedInfo'
let charts1 = ref(null)
let charts2 = ref(null)
let charts3 = ref(null)
let charts4 = ref(null)
//
let szdata = ref([])
let kdata = ref([])
let xdata = ref([])
let closedata = ref([])
let ma5 = ref()
//
let StdDev = ref()
let topStdDev = ref()
let downStdDev = ref()
let rsi1 = ref()
let rsi2 = ref()
let rsi3 = ref()
let vol = ref()
let interval = ref()
import request from '@/utils/request'
let baseURL = 'http://127.0.0.1:8015'
const redata = () => {
try {
request({
url: baseURL + '/stock',
method: 'get',
params: {
symbol: 'sz000001',
start_date: '2021-01-01',
end_date: '2022-12-31',
},
}).then((res) => {
xdata.value = Object.values(res.date)
let { open, close, low, high, volume } = res
for (let i = 0; i < Object.keys(open).length; i++) {
kdata.value.push([open[i], close[i], low[i], high[i]])
closedata.value.push(close[i])
}
// 5线
ma5.value = calculateMA(closedata.value, 5)
StdDev.value = calculateStdDeviation(closedata.value)
topStdDev.value = closedata.value.map((item) =>
parseFloat((item + StdDev.value).toFixed(2))
)
downStdDev.value = closedata.value.map((item) =>
parseFloat((item - StdDev.value).toFixed(2))
)
// MACD
let { dif, dea, macd } = calculateMACD(closedata.value)
//
macd = macd.map(function (value) {
return {
value: value,
itemStyle: {
color: value >= 0 ? '#FF0000' : '#00FF00', //
},
}
})
chartConfigs.value[0].options.series[0].data = dif
chartConfigs.value[0].options.series[1].data = dea
chartConfigs.value[0].options.series[2].data = macd
chartConfigs.value[0].options.xAxis.data = xdata.value
// vol
vol.value = calculateVOL(close, high, low)
chartConfigs.value[1].options.xAxis.data = xdata.value
chartConfigs.value[1].options.series[0].data = vol.value
// KDJ
let { kValues, dValues, jValues } = calculateKDJ(res)
chartConfigs.value[2].options.series[0].data = kValues
chartConfigs.value[2].options.series[1].data = dValues
chartConfigs.value[2].options.series[2].data = jValues
chartConfigs.value[2].options.xAxis.data = xdata.value
// RSI
rsi1.value = calculateRSI(closedata.value)
rsi2.value = calculateRSI(closedata.value, 12)
rsi3.value = calculateRSI(closedata.value, 24)
chartConfigs.value[3].options.series[0].data = rsi1.value
chartConfigs.value[3].options.series[1].data = rsi2.value
chartConfigs.value[3].options.series[2].data = rsi3.value
chartConfigs.value[3].options.xAxis.data = xdata.value
dynamicsHeight()
configecharts()
})
} catch (err) {
console.error('请求失败:', err)
}
}
//echarts
let echarts = inject('echarts')
//
const chartsInfo = ref(null)
// K线
const mKline = ref(null)
//
let heightList = ref([])
//
const dynamicsHeight = () => {
//
let domHeightList = chartsInfo.value.offsetHeight
//
// if (clicklist.value.length) {
// //
// heightList.value = []
// //
// heightList.value.push(domHeightList * (1 - clicklist.value.length * 0.15))
// // K线
// mKline.value.style.height = `${heightList.value[0]}px`
// //
// heightList.value.push(domHeightList * 0.15)
// console.log(heightList.value)
// } else {
// //
// heightList.value = []
// // K线
// mKline.value.style.height = `${domHeightList}px`
// }
console.log(chartsInfo.value.children.length)
//
let childrenLength = chartsInfo.value.children.length
if (childrenLength) {
//
heightList.value = []
//
heightList.value.push(domHeightList * (1 - childrenLength * 0.15))
// K线
mKline.value.style.height = `${heightList.value[0]}px`
//
heightList.value.push(domHeightList * 0.15)
console.log(heightList.value)
} else {
//
heightList.value = []
// K线
mKline.value.style.height = `${domHeightList}px`
}
}
//
let chartConfigs = ref([
{
id: 1,
name: 'MACD',
attId: 'charts1',
status: false,
options: {
animation: false,
tooltip: {
trigger: 'axis', //
axisPointer: {
//
type: 'cross', //
label: {
backgroundColor: '#6a7985', //
},
},
},
dataZoom: [
{
type: 'inside',
},
{
type: 'slider',
show: false,
},
],
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
},
yAxis: {
type: 'value',
},
series: [
{
name: 'DIF',
type: 'line',
itemStyle: {
normal: {
color: 'rgba(204,102,0,1)',
},
},
symbol: 'none',
data: [],
},
{
name: 'DEA',
type: 'line',
itemStyle: {
normal: {
color: 'rgba(0,128,255,1)',
},
},
symbol: 'none',
data: [],
},
{
name: 'MACD',
type: 'bar',
barWidth: '1',
// symbol: 'none',
data: [],
},
],
},
},
{
id: 2,
name: 'VOL',
attId: 'charts2',
status: false,
options: {
animation: false,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985',
},
},
},
dataZoom: [
{
type: 'inside',
},
{
type: 'slider',
show: false,
},
],
xAxis: {
type: 'category',
data: [],
},
yAxis: {
type: 'value',
// splitNumber: 3 ,
interval: 10,
},
series: [
{
name: 'VOL',
type: 'bar',
data: [],
},
],
},
},
{
id: 3,
name: 'KDJ',
attId: 'charts3',
status: false,
options: {
animation: false,
tooltip: {
trigger: 'axis', //
axisPointer: {
//
type: 'cross', //
label: {
backgroundColor: '#6a7985', //
},
},
},
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
{
type: 'slider',
show: false,
},
],
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
},
series: [
{
name: 'K',
type: 'line',
data: [],
symbol: 'none',
smooth: true,
// lineStyle: {
// width: 1,
// },
// areaStyle: {
// opacity: 0.5,
// },
// itemStyle: {
// color: 'rgba(0,128,255,1)',
// },
},
{
name: 'D',
type: 'line',
data: [],
symbol: 'none',
smooth: true,
// lineStyle: {
// width: 1,
// },
// areaStyle: {
// opacity: 0.5,
// },
// itemStyle: {
// color: 'rgba(0,128,255,1)',
// },
},
{
name: 'J',
type: 'line',
data: [],
symbol: 'none',
smooth: true,
// lineStyle: {
// width: 1,
// },
// areaStyle: {
// opacity: 0.5,
// },
// itemStyle: {
// color: 'rgba(0,128,255,1)',
// },
},
],
},
},
{
id: 4,
name: 'RSI',
attId: 'charts4',
status: false,
options: {
animation: false,
tooltip: {
trigger: 'axis', //
axisPointer: {
//
type: 'cross', //
label: {
backgroundColor: '#6a7985', //
},
},
},
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 0],
start: 20,
end: 100,
},
{
type: 'slider',
show: false,
},
],
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
},
series: [
{
name: 'rsi1',
type: 'line',
data: [],
symbol: 'none',
smooth: true,
// lineStyle: {
// width: 1,
// },
// areaStyle: {
// opacity: 0.5,
// },
// itemStyle: {
// color: 'rgba(0,128,255,1)',
// },
},
{
name: 'rsi2',
type: 'line',
data: [],
symbol: 'none',
smooth: true,
// lineStyle: {
// width: 1,
// },
// areaStyle: {
// opacity: 0.5,
// },
// itemStyle: {
// color: 'rgba(0,128,255,1)',
// },
},
{
name: 'rsi3',
type: 'line',
data: [],
symbol: 'none',
smooth: true,
// lineStyle: {
// width: 1,
// },
// areaStyle: {
// opacity: 0.5,
// },
// itemStyle: {
// color: 'rgba(0,128,255,1)',
// },
},
],
},
},
])
//
const clicklist = ref([])
//
const addChart = (item) => {
// domId
// let domToRemove = chartBoxList.value.find(element => element.domId === item.attId)
// if(domToRemove){
// domToRemove.chart.dispose()
// }
// let indexToRemove = chartBoxList.value.findIndex(element => element.domId === item.attId)
// //
// if (indexToRemove !== -1) {
// chartBoxList.value.splice(indexToRemove, 1)
// }
//
if (clicklist.value.includes(item.name)) {
//
// clicklist.value = clicklist.value.filter((content) => content !== item.name)
// if (item.attId === 'charts1') {
// charts1.value.style.display = 'none'
// }
//
dynamicsHeight()
//
nextTick(() => {
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = false
// configecharts
configecharts()
}
})
})
} else {
//
// clicklist.value.push(item.name)
// true
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = true
}
})
//
dynamicsHeight()
//
nextTick(() => {
chartConfigs.value.forEach((element) => {
if (element.name == item.name) {
element.status = true
// configecharts
configecharts()
// commonecharts
// commonecharts(item.attId, item.options)
if (!clicklist.value.includes(item.name)) {
commonecharts(item.attId, item.options)
clicklist.value.push(item.name)
}
// if (item.attId === 'charts1') {
// charts1.value.style.display = 'block'
// }
}
})
})
}
}
// Echarts便使echarts.connect()
const configecharts = (options = {}) => {
// _echarts_instance_
document.getElementById('main').removeAttribute('_echarts_instance_')
// k线
let chartBox = echarts.init(document.getElementById('main'))
// 使piniaoption
const option = {
animation: false,
tooltip: {
trigger: 'axis', //
axisPointer: {
//
type: 'cross', //
label: {
backgroundColor: '#6a7985', //
},
animation: false,
},
// formatter: (params)=> {
// let str = '<div style="padding: 3px 12px;width: 161px;background: #FFFFFF;border: 1px solid #DCDFE6;box-shadow:none; opacity: 1;border-radius: 4px;"><span style="color:#606062;font-size: 12px;">' + params[0].axisValue + "</span><br />";
// params.forEach((item) => {
// str +=
// '<span style="color:#f00;font-size: 12px;color: #1D1D20;"><span style="float:left; margin-top:8px; margin-right:5px;border-radius:50%;width:6px;height:6px;background-color:'+item.color+'"></span>' + "&nbsp;&nbsp;&nbsp;&nbsp;" + item.data + "</span>";
// });
// str += '</div>'
// return str;
// // console.log(params[0]);
// }
},
legend: {
data: ['KLine', 'MA5', 'BOLL1', 'BOLL2'],
},
grid: [
{
left: '3%',
right: '3%',
bottom: '5%',
},
],
xAxis: [
{
type: 'category',
data: xdata.value,
gridIndex: 0,
scale: true,
boundaryGap: false,
axisLine: { onZero: false },
splitLine: { show: false },
splitNumber: 20,
min: 'dataMin',
max: 'dataMax',
sampling: 'lttb', // 线
},
],
yAxis: [
{
gridIndex: 0,
scale: true,
splitArea: {
show: false,
},
},
],
dataZoom: [
{
type: 'slider',
},
{
type: 'inside',
},
],
series: [
{
name: 'KLine',
type: 'candlestick',
xAxisIndex: 0,
yAxisIndex: 0,
data: kdata.value,
itemStyle: {
normal: {
color: '#ef232a',
color0: '#14b143',
borderColor: '#ef232a',
borderColor0: '#14b143',
},
},
// markArea: {
// silent: true,
// itemStyle: {
// normal: {
// color: 'Honeydew',
// },
// },
// data: [],
// },
// markPoint: {
// data: [
// { type: 'max', name: '' },
// { type: 'min', name: '' },
// ],
// },
// markLine: {
// label: {
// normal: {
// position: 'middle',
// textStyle: { color: 'Blue', fontSize: 12 },
// },
// },
// data: [],
// symbol: ['circle', 'none'],
// },
},
{
name: 'MA5',
type: 'line',
xAxisIndex: 0,
yAxisIndex: 0,
data: ma5.value,
symbol: 'none',
smooth: true,
lineStyle: {
normal: {
opacity: 0.5,
},
},
},
{
name: 'BOLL1',
type: 'line',
xAxisIndex: 0,
yAxisIndex: 0,
data: topStdDev.value,
symbol: 'none',
smooth: true,
lineStyle: {
normal: {
opacity: 0.5,
color: 'red',
},
},
// areaStyle: {
// // 线
// normal: {
// //
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1,
// [
// //
// {
// offset: 0,
// color: 'rgba(255, 46, 106, 0.21)'
// },
// {
// offset: 1,
// color: 'rgba(255, 46, 106, 0)'
// }
// ],
// false
// )
// }
// }
},
{
name: 'BOLL2',
type: 'line',
xAxisIndex: 0,
yAxisIndex: 0,
data: downStdDev.value,
symbol: 'none',
smooth: true,
lineStyle: {
normal: {
opacity: 0.5,
color: 'green',
},
},
// areaStyle: {
// // 线
// normal: {
// //
// color:'white'
// }
// }
},
// {
// name: '',
// type: 'line',
// xAxisIndex: 0,
// yAxisIndex: 0,
// data: ma5.value,
// smooth: true,
// lineStyle: {
// normal: {
// opacity: 0.5,
// },
// },
// },
],
}
//
chartBox.setOption(option)
// mergeOptions
// ?
chartBox.setOption(options)
//
chartBox.group = 'group1'
//
window.addEventListener('resize', function () {
chartBox.resize()
})
}
// chart
let chartBoxList = ref([])
//Echarts便使echarts.connect()
const commonecharts = (containerId, options = {}) => {
// _echarts_instance_
document.getElementById(containerId).removeAttribute('_echarts_instance_')
//
const chart = echarts.init(document.getElementById(containerId))
chartBoxList.value.push({
chart,
chartid: chart.id,
domId: containerId,
})
console.log(chartBoxList.value)
//
const option = {
xAxis: {
type: 'category',
data: xdata.value,
},
yAxis: {
type: 'value',
},
grid: {
top: '10%',
left: '3%',
right: '3%',
bottom: '20%',
},
dataZoom: [
{
type: 'inside',
},
],
series: [
{
data: [1, 2, 3, 4, 5, 6, 7, 2, 12, 12, 34],
type: 'line',
smooth: true,
},
],
}
//
chart.setOption(option)
// mergeOptions
chart.setOption(options)
//
chart.group = 'group1'
//
window.addEventListener('resize', function () {
chart.resize()
})
return chart
}
//
echarts.connect('group1')
onMounted(() => {
redata()
const chart = echarts.init(charts1.value)
console.log(chart)
charts1.value.style.height = `${200}px`
//
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
grid: {
top: '10%',
left: '3%',
right: '3%',
bottom: '20%',
},
dataZoom: [
{
type: 'inside',
},
],
series: [
{
data: [1, 2, 3, 4, 5, 6, 7, 2, 12, 12, 34],
type: 'line',
smooth: true,
},
],
}
//
chart.setOption(option)
// mergeOptions
// chart.setOption(options)
//
chart.group = 'group1'
//
window.addEventListener('resize', function () {
chart.resize()
})
})
onBeforeUnmount(() => {
// echarts.disconnect()
})
</script>
<template>
<div class="box">
<div class="chartsinfo" ref="chartsInfo">
<!-- K线图 -->
<div
id="main"
ref="mKline"
class="flex-item"
:style="{ height: `${heightList[0]}px` }"
></div>
<div
id="charts1"
ref="charts1"
:style="{ height: `${heightList[1]}px` }"
></div>
<!-- <div
v-if="chartConfigs[1].status"
id="charts2"
ref="charts2"
:style="{ height: `${heightList[1]}px` }"
></div>
<div
v-if="chartConfigs[2].status"
id="charts3"
ref="charts3"
:style="{ height: `${heightList[1]}px` }"
></div>
<div
v-if="chartConfigs[3].status"
id="charts4"
ref="charts4"
:style="{ height: `${heightList[1]}px` }"
></div> -->
</div>
<!-- 底部的各个图表选项信息 -->
<ul class="typelist">
<li
v-for="(item, index) in chartConfigs"
:key="index"
@click="addChart(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
<style scoped>
.box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.chartsinfo {
height: calc(100vh - 20px);
}
.typelist {
margin-top: auto;
position: relative;
z-index: 99999999;
width: 100%;
color: #191919;
font-size: 12px;
display: flex;
list-style: none;
padding: 0;
}
.typelist > li {
padding: 2px 8px;
cursor: pointer;
}
.typelist > li:hover {
color: gold;
}
.active {
color: #2d98b9;
}
</style>

1752
src/end/NewDesign.vue Normal file

File diff suppressed because it is too large Load Diff

32
src/end/NodataView.vue Normal file

@ -0,0 +1,32 @@
<script setup></script>
<template>
<div class="con">
<div class="nodata">
<div class="text">当前股票没有数据</div>
</div>
</div>
</template>
<style scoped>
.con {
width: 100%;
height: 100%;
background-color: var(--my-common-bgc-2);
}
.nodata {
min-height: calc(100vh - 50px);
/* height: calc(100vh - 22px); */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.text{
font-size: 30px;
font-weight: bold;
/*字体粗细*/
-webkit-text-stroke: 1px var(--my-common-fc-1);
/*描边*/
-webkit-text-fill-color: transparent;
}
</style>

293
src/end/computedInfo.js Normal file

@ -0,0 +1,293 @@
// 计算移动平均线MA的函数接收收盘价格数组和计算所需的天数作为参数
export function calculateMA (closingPrices, dayCount) {
// 检查数据点的数量是否足够计算移动平均线
if (closingPrices.length < dayCount) {
return null // 数据不足返回null
}
let result = []
// 从第dayCount个数据点开始计算因为前dayCount-1个数据点不足以计算一个完整的移动平均线
for (let i = 0; i <= closingPrices.length - dayCount; i++) {
let sum = 0
// 计算当前窗口内所有价格的总和
for (let j = 0; j < dayCount; j++) {
sum += closingPrices[i + j]
}
// 计算并添加移动平均线值到结果数组
result.push(sum / dayCount)
}
result = result.map(item => parseFloat(item.toFixed(2)))
return result // 返回计算出的移动平均线值数组
}
// 计算标准差的函数
export function calculateStdDeviation (prices) {
if (prices.length === 0) {
throw new Error("价格数组不能为空")
}
// 计算平均值
const mean = prices.reduce((sum, price) => sum + price, 0) / prices.length
// 计算每个价格与平均值的差的平方和
const varianceSum = prices.reduce((sum, price) => sum + Math.pow(price - mean, 2), 0)
// 计算方差样本方差使用N-1作为分母
const variance = varianceSum / (prices.length - 1)
// 计算标准差(方差的平方根),取两位小数
const stDeviation = parseFloat(Math.sqrt(variance).toFixed(2))
return stDeviation
}
export function calculateEMA (prices, period) {
let ema = []
let multiplier = 2 / (period + 1)
let previousEMA = prices.reduce((sum, price) => sum + price, 0) / period // 初始EMA为前period天的收盘价平均值
ema.push(previousEMA) // 添加第一个EMA值
for (let i = period; i < prices.length; i++) {
let currentEMA = (prices[i] - previousEMA) * multiplier + previousEMA
ema.push(currentEMA)
previousEMA = currentEMA
}
// 我们只关心最后一个EMA值即最新周期的EMA但这里返回整个EMA数组以便调试
return ema
}
// 计算DIF的函数但dif数组长度将受限于价格数组和EMA计算所需的最小长度
export function calculateDIF (prices, shortPeriod, longPeriod) {
// 确保价格数组足够长以计算所需的EMA
if (prices.length < longPeriod + 1) {
return [] // 或抛出错误
}
// 计算整个价格数组的EMA但通常只关注最近的EMA值
let shortEMA = calculateEMA(prices, shortPeriod)
let longEMA = calculateEMA(prices, longPeriod)
// DIF数组从两个EMA数组都有值的起始位置开始计算
let dif = []
let startIndex = Math.max(shortEMA.length - 1, longEMA.length - 1) - (longPeriod - 1) // 找到两个EMA都能计算的起始索引可能需要根据实际情况调整
// 注意这里的startIndex计算可能需要根据实际需求进行调整因为它依赖于EMA数组的实际可用长度和所需的计算周期。
// 下面的循环确保了只有当两个EMA数组在相同索引处都有值时才计算DIF。
for (let i = startIndex; i < Math.min(shortEMA.length, longEMA.length); i++) {
dif.push(shortEMA[i] - longEMA[i])
}
// 如果需要可以在dif数组前面填充null或0以使其长度与prices相同但这在金融分析上可能没有意义
// while (dif.length < prices.length) {
// dif.unshift(null); // 或0或其他适当的填充值
// }
return dif // 返回DIF数组其长度可能小于prices数组
}
// 计算DEA的函数
export function calculateDEA (dif, deaPeriod) {
// DEA就是DIF的EMA所以直接使用calculateEMA函数计算DIF数组的EMA
return calculateEMA(dif, deaPeriod)
}
// MACD指标的计算函数
export function calculateMACD (
prices,
shortPeriod = 12,
longPeriod = 26,
deaPeriod = 9
) {
function calculateEMA (prices, period) {
let ema = []
let multiplier = 2 / (period + 1)
let sum = 0
for (let i = 0; i < period; i++) {
sum += prices[i]
}
let previousEMA = sum / period
ema.push(previousEMA)
for (let i = period; i < prices.length; i++) {
let currentEMA = (prices[i] - previousEMA) * multiplier + previousEMA
ema.push(currentEMA)
previousEMA = currentEMA
}
return ema
}
let shortEMA = calculateEMA(prices, shortPeriod)
let longEMA = calculateEMA(prices, longPeriod)
let dif = []
for (let i = 0; i < Math.min(shortEMA.length, longEMA.length); i++) {
dif.push(shortEMA[i] - longEMA[i])
}
let dea = calculateEMA(dif, deaPeriod)
let macd = []
for (let i = 0; i < Math.min(dif.length, dea.length); i++) {
macd.push((dif[i] - dea[i]) * 2)
}
// 将dif, dea, macd中的值保留两位小数
dif = dif.map((item) => parseFloat(item.toFixed(2)))
dea = dea.map((item) => parseFloat(item.toFixed(2)))
macd = macd.map((item) => parseFloat(item.toFixed(2)))
return {
dif,
dea,
macd
}
}
// ----------------------------计算KDJ指标的函数----------------------------
// 数据整理
export function changeShape (res) {
// 获取对象的键(这里我们知道键是 'date', 'low', 'high', 'close',但为了通用性,我们还是获取所有键)
const keys = Object.keys(res)
// 初始化一个空数组来存储结果
let result = []
// 假设所有对象的属性date, low, high, close都有相同的索引范围
// 这里我们取第一个对象的键集合来确定索引范围假设它们都有0和1这两个键
const indexRange = Object.keys(res.date) // 或者使用任何其他对象的键集合,因为它们应该有相同的索引
// 遍历索引范围
for (let index of indexRange) {
// 将索引转换为数字类型,以便进行数学运算(虽然在这个例子中它们已经是数字字符串)
const numIndex = parseInt(index, 10)
// 收集对应索引的值到一个子数组中
const row = [
res.date[numIndex],
res.low[numIndex],
res.high[numIndex],
res.close[numIndex]
]
// 将子数组添加到结果数组中
result.push(row)
}
return result
}
// 计算函数
export function calculateKDJ (prices) {
prices = changeShape(prices)
let lows = []
let highs = []
let closes = []
// 提取最低价、最高价、收盘价数组
prices.forEach((price) => {
lows.push(price[1])
highs.push(price[2])
closes.push(price[3])
})
let kValues = []
let dValues = []
let jValues = []
let period = 9 // 默认的计算周期,可以根据实际情况调整
for (let i = 0; i < closes.length; i++) {
if (i < period - 1) {
kValues.push(10)
dValues.push(10)
jValues.push(10)
continue
}
// 计算RSV值未成熟随机值
let lowPeriod = Math.min(...lows.slice(i - period + 1, i + 1))
let highPeriod = Math.max(...highs.slice(i - period + 1, i + 1))
let rsv = ((closes[i] - lowPeriod) / (highPeriod - lowPeriod)) * 100
if (i === period - 1) {
kValues.push(rsv)
dValues.push(rsv)
} else {
// 计算K值一般采用加权移动平均的方式这里简化为前一日K值的2/3加上今日RSV的1/3
let k = (2 / 3) * kValues[i - 1] + (1 / 3) * rsv
kValues.push(k)
// 计算D值一般是前一日D值的2/3加上今日K值的1/3
let d = (2 / 3) * dValues[i - 1] + (1 / 3) * k
dValues.push(d)
}
// 计算J值一般公式为3*K - 2*D
let j = 3 * kValues[i] - 2 * dValues[i]
jValues.push(j)
}
kValues = kValues.map(item => parseFloat(item.toFixed(2)))
dValues = dValues.map(item => parseFloat(item.toFixed(2)))
jValues = jValues.map(item => parseFloat(item.toFixed(2)))
return {
kValues,
dValues,
jValues
}
}
// -------------------------------------------------------------------
// ----------------------------计算RSI指标的函数----------------------------
// RSI 的时间跨度推荐 6、12、24 三个值6 日近似一周的时间周期12 日可以看作半个月的时间跨度,而 24 日约为一个月的时间跨度。
// 短期 RSI 对于价格的变化情况反应比较灵敏RSI 的值波动较大;长期 RSI 值反应相对迟钝,其波动相对较小。
export function calculateRSI (closePrices, period = 6) {
let gains = []
let losses = []
let rsi = []
for (let i = 0; i < closePrices.length; i++) {
if (i === 0) {
gains.push(0)
losses.push(0)
} else {
let diff = closePrices[i] - closePrices[i - 1]
if (diff > 0) {
gains.push(diff)
losses.push(0)
} else {
gains.push(0)
losses.push(Math.abs(diff))
}
}
if (i >= period - 1) {
let sumGain = 0
let sumLoss = 0
for (let j = i - (period - 1); j <= i; j++) {
sumGain += gains[j]
sumLoss += losses[j]
}
let avgGain = sumGain / period
let avgLoss = sumLoss / period
let rs = avgGain / avgLoss
rsi.push(100 - (100 / (1 + rs)))
}
}
rsi = rsi.map(item => parseFloat(item.toFixed(2)))
return rsi
}
// ----------------------------计算VOL指标的函数----------------------------
export function calculateVOL (close, high, low) {
let arr = []
let volvalues = Object.values(close)
let highvalues = Object.values(high)
let lowvalues = Object.values(low)
for (let i = 0; i < volvalues.length; i++) {
let change = (highvalues[i] + lowvalues[i]) / 2
arr.push({
value: volvalues[i],
itemStyle: {
color: volvalues[i] >= change ? '#FF0000' : '#00FF00' // 根据值的正负设置颜色
}
})
}
return arr
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,32 @@
<template>
<component :is="currentComponent" />
</template>
<script>
import { defineComponent, computed } from 'vue';
import { useRoute } from 'vue-router';
import NewDesign from '@/end/NewDesign.vue';
import NewStyleDesign from '@/endnew/NewStyleDesign.vue';
import NodataView from '@/end/NodataView.vue';
export default defineComponent({
setup() {
const route = useRoute();
const currentComponent = computed(() => {
//
if (route.params.type === 'vertical') {
return NewDesign;
} else if (route.params.type === 'grid') {
return NewStyleDesign;
}
//
return NewDesign;
});
return {
currentComponent
};
}
});
</script>

24
src/main.ts Normal file

@ -0,0 +1,24 @@
import './assets/base.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 使用 element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import { createPinia } from "pinia";
// 引入echarts
import * as echarts from 'echarts';
const app = createApp(App)
app.use(ElementPlus)
app.config.globalProperties.$echarts = echarts
app.use(router)
app.use(createPinia())
app.mount('#app')

63
src/router/index.ts Normal file

@ -0,0 +1,63 @@
import { createRouter, createWebHashHistory } from 'vue-router';
// const route = useRoute();
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'root',
redirect: '/thenew', // 默认重定向到 /thenew
component: () => import('@/views/TheNewView.vue'), // 顶级路由组件
children: [
{
path: 'thenew',
name: 'thenew',
// component: () => import('@/views/HomeView.vue'), // HomeView 是 TheNewView 的子组件
redirect: '/thenew/nodata', // 默认重定向到 /thenew/hour-line
children: [
{
path: 'hour-line',
name: 'hour-line',
component: () => import('@/end/NewDesign.vue') // 嵌套子路由
},
{
path: 'hour-line2',
name: 'hour-line2',
component: () => import('@/endnew/NewStyleDesign.vue') // 嵌套子路由
},
{
path: 'day-line',
name: 'day-line',
component: () => import('@/end/NodataView.vue') // 嵌套子路由
},
{
path: 'week-line',
name: 'week-line',
component: () => import('@/end/NodataView.vue') // 嵌套子路由
},
{
path: 'month-line',
name: 'month-line',
component: () => import('@/end/NodataView.vue') // 嵌套子路由
},
{
path: 'year-line',
name: 'year-line',
component: () => import('@/end/NodataView.vue') // 嵌套子路由
},
{
path: 'nodata',
name: 'nodata',
component: () => import('@/end/NodataView.vue') // 嵌套子路由
}
]
}
]
}
]
});
export default router;

5
src/shims-vue.d.ts vendored Normal file

@ -0,0 +1,5 @@
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}

5
src/store/index.ts Normal file

@ -0,0 +1,5 @@
import { createPinia } from "pinia";
const pinia = createPinia()
export default pinia

@ -0,0 +1,30 @@
import { defineStore } from 'pinia'
//数组处理
const useTheme = defineStore("Theme", {
state: () => ({
theme: false,
fontcolor:'#fff',
style:'vertical'
}),
actions: {
toggleFontcolor(){
if(this.theme){
this.fontcolor = '#000'
}else{
this.fontcolor = '#fff'
}
},
toggleDarkTheme(){
this.theme = false
},
optionConfigData () {
}
}
})
export default useTheme

2
src/uilts/vscode.ts Normal file

@ -0,0 +1,2 @@
// @ts-ignore
// export const vscode= window.acquireVsCodeApi();

37
src/utils/echarts.js Normal file

@ -0,0 +1,37 @@
//这个必须要引入的
import * as echarts from "echarts/core";
/** 引入柱状图and折线图图表图表后缀都为 Chart*/
import { BarChart, LineChart } from "echarts/charts";
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
} from "echarts/components";
// 标签自动布局,全局过渡动画等特性
import { LabelLayout, UniversalTransition } from "echarts/features";
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from "echarts/renderers";
// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
BarChart,
LabelLayout,
UniversalTransition,
CanvasRenderer,
LineChart,
]);
// 导出
export default echarts;

45
src/utils/http.js Normal file

@ -0,0 +1,45 @@
import axios from 'axios'
const request = axios.create({
method :"GET",
timeout:2000,
})
// 请求拦截器
request.interceptors.request.use(config => {
console.log("请求拦截成功")
// 例如给后端传递token,config是配置参数
//如有需要注意使用token的时候需要引入cookie方法或者用本地localStorage等方法推荐js-cookie
//const token = getCookie('名称');//这里取token之前你肯定需要先拿到token,存一下
//if(token){
//config.params = {'token':token} //如果要求携带在参数中
//config.headers.token= token; //如果要求携带在请求头中
return config
},
error => {
console.log('请求拦截失败')
return Promise.reject(error)
}
)
// 响应拦截器
request.interceptors.response.use(res => {
console.log("响应拦截成功")
if (res.status != 200) {
return
} else {
return res
}
},
error => {
console.log("响应拦截失败")
return Promise.reject(error)
}
)
export default (url, method = "GET", params = {}) => {
return request({
url,
method,
params
})
}
// export default request

57
src/utils/request.js Normal file

@ -0,0 +1,57 @@
// 进行axios的二次封装
import axios from "axios";
// 第一步利用axios对象的create方法去创建axios实例(其他的配置:基础路径,超时的时间)
let request=axios.create({
// 基础路径
baseURL:import.meta.env.VITE_APP_BASE_API,//基础路径上会携带/api
timeout:5000//超时的时间的设置
});
// 第二步:request实例添加请求与响应拦截器
request.interceptors.request.use((config)=>{
// config配置对象headers属性请求头经常给服务器端携带公共参数
// 返回配置对象
return config
})
// 第三步:响应拦截器
request.interceptors.response.use((response)=>{
// 成功回调
// 简化数据
console.log(response);
if(response.status==200){
return response.data.message
}
},(error)=>{
// 失败回调处理http网络问题
// 定义一个变量:存储网络错误信息
console.log(error);
let message=''
// http状态码
let status=error.response.status
switch(status){
case 401:
message='TOKEN过期'
break;
case 403:
message ='无权访问'
break;
case 404:
message ='请求地址错误'
break;
case 500:
message ='服务器出现问题'
break;
default:
message='网络出现问题'
break
}
return Promise.reject(error)
})
// 对外暴露
export default request

2
src/utils/vscode.ts Normal file

@ -0,0 +1,2 @@
// @ts-ignore
// export const vscode= window.acquireVsCodeApi();

240
src/views/HomeView.vue Normal file

@ -0,0 +1,240 @@
<script setup>
import { onMounted, ref, watch} from 'vue' //
import { RouterView, useRouter } from 'vue-router'
import { storeToRefs } from 'pinia'
import usethemestore from '../store/usethemestore'
const themeStore = usethemestore()
const { theme, style } = storeToRefs(themeStore)
const router = useRouter()
let routerViewKey = ref(0) // RouterView key
const props = defineProps({
message: {
type: String,
default: '', //
},
});
const lightFunc = () => {
theme.value = true
document.documentElement.style.setProperty('--my-common-bgc-2', '#fff');
document.documentElement.style.setProperty('--my-light-br-1', '#e7ebf3');
document.documentElement.style.setProperty('--my-common-bgc-1', '#1F1F1F');
document.documentElement.style.setProperty('--my-common-fc-1', '#1F1F1F');
}
const darkFunc = () => {
theme.value = false
document.documentElement.style.setProperty('--my-common-bgc-2', '#1F1F1F');
document.documentElement.style.setProperty('--my-light-br-1', '#ffffff');
document.documentElement.style.setProperty('--my-common-bgc-1', '#fff');
document.documentElement.style.setProperty('--my-common-fc-1', '#fff');
}
const verticalFunc = () => {
style.value = 'vertical'
router.push({
path: `/thenew/hour-line`,
params: { type: 'vertical' },
})
// routerViewKey.value = routerViewKey.value + 1
}
const gridFunc = () => {
style.value = 'grid'
router.push({
path: `/thenew/hour-line2`,
params: { type: 'grid' },
})
// routerViewKey.value = routerViewKey.value + 1
}
onMounted(() => {
watch(() => props.message, (news,old) => {
routerViewKey.value = routerViewKey.value + 1
router.push(`/thenew/hour-line`)
activeIndex.value = 0
})
})
const headerData = ref([
'日K',
'周K',
'月K',
'季K',
'年K',
// '1',
// '3',
// '5',
// '15',
// '30',
// '1',
// '2',
// '3',
// '4',
])
//
let routerList = [
'hour-line',
'day-line',
'week-line',
'month-line',
'year-line',
]
//
const activeIndex = ref(0)
//
function handleClick(index) {
//
activeIndex.value = index
//
router.push(`/thenew/${routerList[index]}`)
}
</script>
<template>
<div class="content">
<ul class="timelist">
<li
class="item"
v-for="(item, index) in headerData"
:key="item"
:class="{ active: activeIndex === index }"
@click="handleClick(index)"
>
{{ item }}
</li>
<li class="item">
<el-dropdown :hide-on-click="false">
<span class="el-dropdown-link">
<div v-if="theme">
<svg t="1739345471358" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7366" width="16" height="16"><path d="M85.333333 128h853.333334v768H85.333333V128z m85.333334 85.333333v597.333334h682.666666V384h-341.333333V213.333333H170.666667z" p-id="7367" fill="#2c2c2c"></path></svg>
</div>
<div v-else>
<svg t="1739345471358" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7366" width="16" height="16"><path d="M85.333333 128h853.333334v768H85.333333V128z m85.333334 85.333333v597.333334h682.666666V384h-341.333333V213.333333H170.666667z" p-id="7367" fill="#ffffff"></path></svg>
</div>
<!-- <svg t="1737685184492" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1032" width="16" height="16"><path d="M831.085714 896h-612.571428V437.028571l-118.857143-118.857142 201.142857-201.142858 10.057143 10.057143c113.371429 113.371429 298.057143 113.371429 412.342857 0l10.057143-10.057143L950.857143 334.628571l-118.857143 118.857143V896z m-585.142857-27.428571h557.714286V441.6l106.971428-106.971429L732.342857 155.428571C610.742857 266.971429 423.314286 266.971429 301.714286 155.428571L138.057143 318.171429l106.971428 106.971428V868.571429z" fill="#2c2c2c" p-id="1033"></path></svg> -->
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div @click="verticalFunc">
<el-tooltip
class="box-item"
effect="light"
content="垂直"
placement="left"
>
<svg t="1739337693471" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6034" width="16" height="16"><path d="M85.333333 213.333333h853.333334v597.333334H85.333333V213.333333z m85.333334 85.333334v85.333333h682.666666V298.666667H170.666667z m682.666666 170.666666H170.666667v85.333334h682.666666v-85.333334z m0 170.666667H170.666667v85.333333h682.666666v-85.333333z" p-id="6035" fill="#2c2c2c"></path></svg>
</el-tooltip>
</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="gridFunc">
<el-tooltip
class="box-item"
effect="light"
content="网格"
placement="left"
>
<svg t="1739339260343" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7012" width="14" height="14"><path d="M85.333333 128h853.333334v768H85.333333V128z m85.333334 170.666667v213.333333h298.666666V298.666667H170.666667z m384 0v213.333333h298.666666V298.666667h-298.666666z m298.666666 298.666666h-298.666666v213.333334h298.666666v-213.333334z m-384 213.333334v-213.333334H170.666667v213.333334h298.666666z" p-id="7013" fill="#2c2c2c"></path></svg>
</el-tooltip>
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</li>
<li class="item">
<el-dropdown :hide-on-click="false">
<span class="el-dropdown-link">
<div v-if="theme">
<svg t="1737685184492" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1032" width="16" height="16"><path d="M831.085714 896h-612.571428V437.028571l-118.857143-118.857142 201.142857-201.142858 10.057143 10.057143c113.371429 113.371429 298.057143 113.371429 412.342857 0l10.057143-10.057143L950.857143 334.628571l-118.857143 118.857143V896z m-585.142857-27.428571h557.714286V441.6l106.971428-106.971429L732.342857 155.428571C610.742857 266.971429 423.314286 266.971429 301.714286 155.428571L138.057143 318.171429l106.971428 106.971428V868.571429z" fill="#2c2c2c" p-id="1033"></path></svg>
</div>
<div v-else>
<svg t="1737685184492" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1032" width="16" height="16"><path d="M831.085714 896h-612.571428V437.028571l-118.857143-118.857142 201.142857-201.142858 10.057143 10.057143c113.371429 113.371429 298.057143 113.371429 412.342857 0l10.057143-10.057143L950.857143 334.628571l-118.857143 118.857143V896z m-585.142857-27.428571h557.714286V441.6l106.971428-106.971429L732.342857 155.428571C610.742857 266.971429 423.314286 266.971429 301.714286 155.428571L138.057143 318.171429l106.971428 106.971428V868.571429z" fill="#ffffff" p-id="1033"></path></svg>
</div>
<!-- <svg t="1737685184492" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1032" width="16" height="16"><path d="M831.085714 896h-612.571428V437.028571l-118.857143-118.857142 201.142857-201.142858 10.057143 10.057143c113.371429 113.371429 298.057143 113.371429 412.342857 0l10.057143-10.057143L950.857143 334.628571l-118.857143 118.857143V896z m-585.142857-27.428571h557.714286V441.6l106.971428-106.971429L732.342857 155.428571C610.742857 266.971429 423.314286 266.971429 301.714286 155.428571L138.057143 318.171429l106.971428 106.971428V868.571429z" fill="#2c2c2c" p-id="1033"></path></svg> -->
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div @click="lightFunc">
<el-tooltip
class="box-item"
effect="light"
content="Light"
placement="left"
>
<svg t="1737685432082" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3218" width="16" height="16"><path d="M504.832 144h24.08c6.608 0 11.952 4.48 11.952 9.984v80.208c0 5.504-5.344 9.984-11.952 9.984h-24.08c-6.608 0-11.968-4.48-11.968-9.984V153.984c0-5.52 5.36-9.984 11.968-9.984z m10.304 541.92c96.432 0 174.608-78.176 174.608-174.608 0-96.448-78.176-174.624-174.608-174.624S340.528 414.88 340.528 511.312c0 96.432 78.176 174.608 174.608 174.608z m0 48c-122.944 0-222.608-99.68-222.608-222.608 0-122.944 99.664-222.624 222.608-222.624s222.608 99.68 222.608 222.624c0 122.928-99.68 222.608-222.608 222.608z m-10.24-355.792a9.52 9.52 0 0 1 10.24 9.488v247.2a9.696 9.696 0 0 1-10.448 9.648 133.584 133.584 0 0 1 0.208-266.336z m263.184-135.056l17.024 17.024c4.672 4.672 5.28 11.632 1.376 15.536L729.6 332.512c-3.904 3.904-10.864 3.296-15.52-1.376l-17.04-17.024c-4.672-4.672-5.28-11.632-1.376-15.552l56.88-56.864c3.904-3.92 10.864-3.296 15.52 1.376z m110.528 261.76v24.08c0 6.608-4.48 11.952-9.984 11.952h-80.208c-5.504 0-9.984-5.344-9.984-11.952v-24.08c0-6.608 4.48-11.968 9.984-11.968h80.208c5.52 0 9.984 5.36 9.984 11.968z m-93.504 257.68l-17.024 17.024c-4.672 4.672-11.632 5.28-15.536 1.376l-56.88-56.864c-3.904-3.92-3.296-10.88 1.376-15.536l17.024-17.04c4.672-4.672 11.632-5.28 15.536-1.376l56.88 56.88c3.92 3.904 3.296 10.88-1.376 15.536z m-256.192 116.096h-24.08c-6.608 0-11.968-4.48-11.968-9.984v-80.208c0-5.504 5.36-9.984 11.968-9.984h24.08c6.608 0 11.952 4.48 11.952 9.984v80.208c0 5.52-5.344 9.984-11.952 9.984z m-268.528-100.448l-14.272-14.272a10.016 10.016 0 0 1 0-14.16l56.88-56.88a10.016 10.016 0 0 1 14.16 0l14.272 14.272a10.016 10.016 0 0 1 0 14.176l-56.864 56.864a10.016 10.016 0 0 1-14.176 0zM144 528.912v-24.08c0-6.608 4.48-11.968 9.984-11.968h80.208c5.504 0 9.984 5.36 9.984 11.968v24.08c0 6.608-4.48 11.952-9.984 11.952H153.984c-5.52 0-9.984-5.344-9.984-11.952z m104.64-268.8l17.024-17.04c4.672-4.672 11.632-5.28 15.536-1.376l56.88 56.864c3.904 3.92 3.296 10.88-1.376 15.552l-17.04 17.024c-4.672 4.672-11.616 5.28-15.52 1.376l-56.88-56.88c-3.92-3.904-3.296-10.88 1.36-15.52z" fill="#2c2c2c" p-id="3219"></path></svg>
</el-tooltip>
</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="darkFunc">
<el-tooltip
class="box-item"
effect="light"
content="Dark"
placement="left"
>
<svg t="1737685471806" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3524" width="16" height="16"><path d="M504.832 144h24.08c6.608 0 11.952 4.48 11.952 9.984v80.208c0 5.504-5.344 9.984-11.952 9.984h-24.08c-6.608 0-11.968-4.48-11.968-9.984V153.984c0-5.52 5.36-9.984 11.968-9.984z m263.248 99.072l17.024 17.024c4.672 4.672 5.28 11.632 1.376 15.536L729.6 332.512c-3.904 3.904-10.864 3.296-15.52-1.376l-17.04-17.024c-4.672-4.672-5.28-11.632-1.376-15.552l56.88-56.864c3.904-3.92 10.864-3.296 15.52 1.376z m110.528 261.76v24.08c0 6.608-4.48 11.952-9.984 11.952h-80.208c-5.504 0-9.984-5.344-9.984-11.952v-24.08c0-6.608 4.48-11.968 9.984-11.968h80.208c5.52 0 9.984 5.36 9.984 11.968z m-93.504 257.68l-17.024 17.024c-4.672 4.672-11.632 5.28-15.536 1.376l-56.88-56.864c-3.904-3.92-3.296-10.88 1.376-15.536l17.024-17.04c4.672-4.672 11.632-5.28 15.536-1.376l56.88 56.88c3.92 3.904 3.296 10.88-1.376 15.536z m-256.192 116.096h-24.08c-6.608 0-11.968-4.48-11.968-9.984v-80.208c0-5.504 5.36-9.984 11.968-9.984h24.08c6.608 0 11.952 4.48 11.952 9.984v80.208c0 5.52-5.344 9.984-11.952 9.984z m-268.528-100.448l-14.272-14.272a10.016 10.016 0 0 1 0-14.16l56.88-56.88a10.016 10.016 0 0 1 14.16 0l14.272 14.272a10.016 10.016 0 0 1 0 14.176l-56.864 56.864a10.016 10.016 0 0 1-14.176 0zM144 528.912v-24.08c0-6.608 4.48-11.968 9.984-11.968h80.208c5.504 0 9.984 5.36 9.984 11.968v24.08c0 6.608-4.48 11.952-9.984 11.952H153.984c-5.52 0-9.984-5.344-9.984-11.952z m104.64-268.8l17.024-17.04c4.672-4.672 11.632-5.28 15.536-1.376l56.88 56.864c3.904 3.92 3.296 10.88-1.376 15.552l-17.04 17.024c-4.672 4.672-11.616 5.28-15.52 1.376l-56.88-56.88c-3.92-3.904-3.296-10.88 1.36-15.52zM515.12 685.92c96.432 0 174.608-78.176 174.608-174.608 0-96.448-78.176-174.624-174.608-174.624S340.528 414.88 340.528 511.312c0 96.432 78.176 174.608 174.608 174.608z m0 48c-122.944 0-222.608-99.68-222.608-222.608 0-122.944 99.664-222.624 222.608-222.624s222.608 99.68 222.608 222.624c0 122.928-99.68 222.608-222.608 222.608zM478.288 427.52a82.8 82.8 0 0 0-1.68 16.64c0 43.936 34.32 79.552 76.64 79.552a74.624 74.624 0 0 0 48.544-17.984c4.544-3.872 14.72-2.4 15.392 3.184 0.592 4.848 0.896 9.792 0.896 14.8 0 64.224-50.144 116.272-112 116.272s-112-52.048-112-116.272c0-48.064 28.096-89.312 68.176-107.024 6.976-3.088 17.312 4.576 16.032 10.832z" fill="#2c2c2c" p-id="3525"></path></svg>
</el-tooltip>
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</li>
</ul>
<div class="view">
<RouterView :key="routerViewKey"></RouterView>
</div>
</div>
</template>
<style scoped>
.content {
/* width: 100vw; */
height: 100vh;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.timelist {
/* background-color: white; */
background-color: var(--my-common-bgc-2) !important;
/* color: #414040; */
color: var(--my-common-fc-1);
font-size: 13px;
display: flex;
list-style: none;
border-bottom: 1px solid rgb(175, 173, 173);
box-sizing: border-box;
margin: 0;
padding: 2px 0;
}
.timelist > li {
padding: 0 8px;
cursor: pointer;
}
.timelist > li:nth-child(6){
margin-left: auto;
/* margin-right: 10px; */
}
.active {
color: #2d98b9;
}
.view {
height: calc(100vh - 27px);
}
::-webkit-scrollbar {
width: 0;
}
</style>

1237
src/views/TheNewView.vue Normal file

File diff suppressed because it is too large Load Diff

12
tsconfig.app.json Normal file

@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
tsconfig.json Normal file

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

18
tsconfig.node.json Normal file

@ -0,0 +1,18 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

30
vite.config.ts Normal file

@ -0,0 +1,30 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
base: './',
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
server: {
open: true,
proxy: {
"/api/v1": {
// target: "http://10.1.5.188:8011/",
target: "http://127.0.0.1:8012",
changeOrigin: true,
rewrite: path => path.replace(/^\/api\/v1/, ''),
},
},
},
})