├── public └── favicon.ico ├── src ├── assets │ ├── logo.png │ ├── js │ │ ├── storage.js │ │ ├── cart.js │ │ └── api.js │ └── css │ │ └── cart.css ├── shims-vue.d.ts ├── request.ts ├── main.ts ├── components │ ├── details │ │ ├── Manager.vue │ │ ├── allocate │ │ │ ├── Bond.vue │ │ │ ├── Industry.vue │ │ │ ├── Stock.vue │ │ │ ├── Concentrate.vue │ │ │ ├── IndustrySw.vue │ │ │ ├── Asset.vue │ │ │ └── AllocateHis.vue │ │ ├── charts │ │ │ ├── CyclePerformance.vue │ │ │ ├── ScaleChange.vue │ │ │ ├── RiskTraceShort.vue │ │ │ ├── Turnover.vue │ │ │ ├── HistoryStyle.vue │ │ │ ├── Performance.vue │ │ │ ├── HolderInfo.vue │ │ │ ├── Statistic.vue │ │ │ ├── Style.vue │ │ │ └── Brinson.vue │ │ ├── DetailLayout.vue │ │ ├── Allocate.vue │ │ ├── manager │ │ │ ├── Managed.vue │ │ │ └── TopHolding.vue │ │ ├── Fact.vue │ │ ├── KeyPortfolio.vue │ │ └── Attribution.vue │ ├── etf │ │ ├── ETFLayout.vue │ │ ├── ETFRecent.vue │ │ ├── ETFCategory.vue │ │ └── ETFHome.vue │ ├── Cart.vue │ ├── layout │ │ ├── Layout.vue │ │ └── Header.vue │ ├── dashboard │ │ ├── Simple.vue │ │ ├── Detail.vue.jsx.map │ │ ├── Detail.vue │ │ └── Detail.vue.jsx │ ├── Home.vue │ ├── Dashboard.vue │ ├── portfolio │ │ ├── Portfolio.vue.jsx.map │ │ ├── Portfolio.vue.jsx │ │ └── Portfolio.vue │ ├── screen │ │ ├── AddToPool.vue │ │ └── ScreenResult.vue │ ├── News.vue │ └── cart │ │ ├── Basic.vue │ │ ├── General.vue │ │ └── CartTable.vue.jsx.map ├── App.vue └── router │ └── index.ts ├── .gitignore ├── vite.config.ts ├── index.html ├── tsconfig.json ├── package.json └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PengchuanC/fund_vue3/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PengchuanC/fund_vue3/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | .idea 7 | dist.tar.gz 8 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import vueJsx from '@vitejs/plugin-vue-jsx' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue(), vueJsx()] 8 | }) 9 | -------------------------------------------------------------------------------- /src/request.ts: -------------------------------------------------------------------------------- 1 | import {extend} from "umi-request"; 2 | 3 | 4 | const baseURL = "https://product.nomuraoi-sec.com/api/v1" 5 | // const baseURL = "http://localhost:8000/api/v1" 6 | const request = extend({ 7 | prefix: baseURL, 8 | timeout: 50000, 9 | useCache: true 10 | }) 11 | 12 | export default request; 13 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import element from 'element-plus' 3 | import 'element-plus/lib/theme-chalk/index.css' 4 | import vxe from 'vxe-table' 5 | import 'vxe-table/lib/style.css' 6 | import locale from 'element-plus/lib/locale/lang/zh-cn' 7 | 8 | import App from './App.vue' 9 | import router from './router' 10 | 11 | const app = createApp(App) 12 | app.use(router) 13 | app.use(element, { locale }) 14 | app.use(vxe) 15 | 16 | app.mount('#app') 17 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 基金筛选系统 8 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "jsx": "preserve", 8 | "sourceMap": true, 9 | "resolveJsonModule": true, 10 | "esModuleInterop": true, 11 | "lib": ["esnext", "dom"], 12 | "types": ["vite/client"], 13 | "skipLibCheck": true, 14 | "noImplicitAny": false 15 | }, 16 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 17 | } 18 | -------------------------------------------------------------------------------- /src/components/details/Manager.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 25 | 26 | 39 | -------------------------------------------------------------------------------- /src/assets/js/storage.js: -------------------------------------------------------------------------------- 1 | 2 | export default class Storage { 3 | static saveSearchHistory(search){ 4 | let history = Storage.loadSearchHistory() 5 | for (const v in Object.keys(history)) { 6 | if (history[v].label === search.label){ 7 | return 8 | } 9 | } 10 | history.unshift(search) 11 | history = Array.from(new Set(history)) 12 | history = history.slice(0, 15) 13 | localStorage.setItem('searchHistory', JSON.stringify(history)) 14 | } 15 | 16 | static loadSearchHistory(){ 17 | let historyStr = localStorage.getItem('searchHistory') 18 | let history = JSON.parse(historyStr) 19 | return history || [] 20 | } 21 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fund", 3 | "version": "2.0.0", 4 | "scripts": { 5 | "dev": "vite --host", 6 | "build": "vue-tsc --noEmit && vite build", 7 | "serve": "vite preview" 8 | }, 9 | "dependencies": { 10 | "@vitejs/plugin-vue-jsx": "^1.1.7", 11 | "dayjs": "^1.10.6", 12 | "echarts": "^5.1.2", 13 | "element-plus": "^1.0.2-beta.71", 14 | "numeral": "^2.0.6", 15 | "umi-request": "^1.3.9", 16 | "vue": "^3.2.4", 17 | "vue-router": "4.0.11", 18 | "vxe-table": "^4.0.26", 19 | "xe-utils": "^3.3.1" 20 | }, 21 | "devDependencies": { 22 | "@types/numeral": "^2.0.1", 23 | "@vitejs/plugin-vue": "^1.4.0", 24 | "@vue/compiler-sfc": "^3.2.4", 25 | "typescript": "^4.2.4", 26 | "vite": "^2.5.0", 27 | "vue-tsc": "^0.2.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/etf/ETFLayout.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 34 | 35 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 49 | -------------------------------------------------------------------------------- /src/assets/css/cart.css: -------------------------------------------------------------------------------- 1 | .overview { 2 | width: 100%; 3 | } 4 | 5 | .head-wrapper { 6 | width: 100%; 7 | background-color: #f0f0f0; 8 | text-align: left; 9 | } 10 | 11 | h4 { 12 | margin: 10px; 13 | } 14 | 15 | .selection-area { 16 | text-align: left; 17 | width: 100%; 18 | padding: 0 20px; 19 | margin: 5px 0; 20 | } 21 | 22 | .items-wrapper { 23 | display: inline-flex; 24 | width: 100%; 25 | } 26 | 27 | .target { 28 | font-weight: normal; 29 | width: 200px; 30 | } 31 | 32 | .selection-items { 33 | display: flex; 34 | flex-wrap: wrap; 35 | justify-content: flex-start; 36 | width: 100%; 37 | margin-bottom: 10px; 38 | border-bottom: #cccccc dashed 1px; 39 | } 40 | 41 | .selection-items > .checkbox { 42 | margin-right: 20px; 43 | } 44 | 45 | .risk-selector { 46 | width: 600px; 47 | min-width: 400px; 48 | } 49 | 50 | .selector-items { 51 | display: flex; 52 | flex-wrap: wrap; 53 | justify-content: flex-start; 54 | width: 100%; 55 | margin-bottom: 10px; 56 | } 57 | 58 | .data-present { 59 | width: 100%; 60 | margin: 0 0 10px; 61 | } 62 | 63 | .submit-button { 64 | margin-left: 20px; 65 | } -------------------------------------------------------------------------------- /src/components/Cart.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 40 | 41 | -------------------------------------------------------------------------------- /src/components/details/allocate/Bond.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 49 | 50 | 61 | -------------------------------------------------------------------------------- /src/components/details/allocate/Industry.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 51 | 52 | 63 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import {createRouter, createWebHistory} from "vue-router"; 2 | 3 | const routes = [ 4 | { 5 | name: 'home', 6 | path: '/home', 7 | component: () => import('../components/Home.vue'), 8 | meta: {keepAlive: true} 9 | }, 10 | { 11 | name: 'cart', 12 | path: '/cart', 13 | component: () => import('../components/Cart.vue'), 14 | meta: {keepAlive: true} 15 | }, 16 | { 17 | name: 'etf', 18 | path: '/etf', 19 | component: () => import('../components/etf/ETFLayout.vue'), 20 | meta: {keepAlive: true} 21 | }, 22 | { 23 | name: 'screen', 24 | path: '/screen', 25 | component: () => import('../components/Screen.vue') 26 | }, 27 | { 28 | name: 'dashboard', 29 | path: '/dashboard', 30 | component: () => import('../components/Dashboard.vue'), 31 | meta: {keepAlive: true} 32 | }, 33 | { 34 | name: 'news', 35 | path: '/news', 36 | component: () => import('../components/News.vue'), 37 | meta: {keepAlive: true} 38 | }, 39 | { 40 | name: 'portfolio', 41 | path: '/portfolio', 42 | component: () => import('../components/portfolio/Portfolio.vue'), 43 | meta: {keepAlive: true} 44 | }, 45 | { 46 | name: 'info', 47 | path: '/info/:secucode(\\d+)', 48 | component: () => import('../components/details/DetailLayout.vue'), 49 | meta: {keepAlive: true} 50 | }, 51 | { 52 | path: '/', 53 | redirect: () => { 54 | return {name: 'home'} 55 | } 56 | }, 57 | ] 58 | 59 | export default createRouter({ 60 | end: false, 61 | history: createWebHistory(), 62 | sensitive: false, 63 | strict: false, 64 | routes 65 | }) 66 | -------------------------------------------------------------------------------- /src/components/details/allocate/Stock.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 54 | 55 | 66 | -------------------------------------------------------------------------------- /src/components/etf/ETFRecent.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 82 | 83 | -------------------------------------------------------------------------------- /src/components/details/charts/CyclePerformance.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 81 | 82 | 93 | -------------------------------------------------------------------------------- /src/components/details/DetailLayout.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 68 | 69 | -------------------------------------------------------------------------------- /src/components/layout/Layout.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 50 | 51 | -------------------------------------------------------------------------------- /src/components/details/charts/ScaleChange.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 92 | 93 | 99 | -------------------------------------------------------------------------------- /src/components/details/Allocate.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 62 | 63 | 89 | -------------------------------------------------------------------------------- /src/components/dashboard/Simple.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 67 | 68 | -------------------------------------------------------------------------------- /src/components/details/allocate/Concentrate.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 91 | 92 | 102 | -------------------------------------------------------------------------------- /src/components/details/charts/RiskTraceShort.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 92 | 93 | 99 | -------------------------------------------------------------------------------- /src/components/details/charts/Turnover.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 96 | 97 | 103 | -------------------------------------------------------------------------------- /src/components/details/charts/HistoryStyle.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 95 | 96 | 107 | -------------------------------------------------------------------------------- /src/components/details/charts/Performance.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 100 | 101 | 104 | -------------------------------------------------------------------------------- /src/components/details/allocate/IndustrySw.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 101 | 102 | 112 | -------------------------------------------------------------------------------- /src/components/details/manager/Managed.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 116 | 117 | 129 | -------------------------------------------------------------------------------- /src/components/details/Fact.vue: -------------------------------------------------------------------------------- 1 |