Merge pull request #5 from simple321vip/release-1.2

Release 1.2
This commit is contained in:
Guan
2023-02-02 23:03:05 +08:00
committed by GitHub
60 changed files with 3476 additions and 660 deletions
Vendored
-3
View File
@@ -45,9 +45,6 @@ spec:
- name: "volume-m2"
hostPath:
path: "/root/.m2/repository"
- name: "maven-config"
configMap:
name: maven-config
- name: "volume-docker"
hostPath:
path: "/var/run/docker.sock"
+8 -8
View File
@@ -1,17 +1,17 @@
## Vue 3 + Typescript + Vite + pinia + vue-router
## Create project document how to bulid a project
## about creating project document how to bulid a project
before create project, you should install node to promit npm and node command is standy.
npm -v
node -v<br />
// 在想要创建的工程路径下执行以下命令,3到6秒就可以结束
npm init vite@latest
// 1.填写 g-home
// 1.填写 violin-home
// 2.选择vue
// 3.vue.ts
cd g-home
cd violin-home
npm install
## vue-router
@@ -33,19 +33,19 @@
// to enter the home page:
localhost:3000/home?tenantId=XXX&account=YYY&token=ABCDEFG
## 环境配置
## profiles
添加了.env.development ebv.test .env.production 文件
development:
开发环境,使用mock,不需要后台联动
test:
测试环境需要 后台java程序支持,同时需要百度第三方认证。
prod:
生产环境通过 jenkins cicd进行发布配置
生产环境通过 jenkins ci 持续集成 argocd 做cd 持续发布
# 云服务器
nginx as a veb server, i use the official image to build this app image.
# prod server
nginx as a web server, i use the official image to build this app image.
## 发布
## publish
- npm run build 生成dist 文件夹
## 百度网盘开放平台
+9
View File
@@ -74,4 +74,13 @@ export default [
}
},
},
{
url: '/wiki/api/v1/reader/blogs/count',
method: 'GET',
response: () => {
return {
count: 101,
}
},
},
] as MockMethod[]
+45
View File
@@ -0,0 +1,45 @@
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/bookmark/api/v1/bookmark/count',
method: 'get',
response: () => {
return {
count: 53,
}
}
},
{
url: '/bookmark/api/v1/bookmark',
method: 'get',
response: () => {
return [
{
bk_id: '001',
bk_type_id: '2',
bk_type_name: '3',
comment: '4',
url: '5'
},
{
bk_id: '002',
bk_type_id: '2',
bk_type_name: '3',
comment: '4',
url: '5'
}
]
}
},
{
url: '/bookmark/api/v1/bookmark_type',
method: 'get',
response: () => {
return [
]
}
},
] as MockMethod[]
+30
View File
@@ -0,0 +1,30 @@
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/calendar/api/v1/event',
method: 'get',
response: () => {
return [
{
date: '2023-01-09',
title: '春游',
eventInfo: '春节不觉晓,处处闻啼鸟,夜来风雨声,花落知多少',
},
{
date: '2023-01-30',
title: '月底发工资',
eventInfo: '发了工资少一半,还了信用卡再少一半,试问如何攒下钱,只有两个字:做梦',
}
]
}
},
{
url: '/calendar/api/v1/event',
method: 'put',
response: () => {
return {
}
}
},
] as MockMethod[]
+102
View File
@@ -130,5 +130,107 @@ export default [
}
}
},
{
url: '/trader/api/v1/accounts',
method: 'get',
response: ({ body, query }) => {
return {
accounts: [
{
gateway_name: 'cpt',
account_id: '7788',
balance: '7',
frozen: '8',
},
{
gateway_name: 'cpt',
account_id: '778899',
balance: '8',
frozen: '9',
}
],
positions: [
{
symbol: 'czce',
exchange: 'RM301',
direction: '1',
volume: 222,
price: 2500,
frozen: 3,
pnl: 2,
yd_volume: 1,
}
],
trades: [
{
symbol: 'string',
exchange: 'string',
direction: 'string',
volume: 2,
price: 4,
orderid: 'string',
tradeid: 'string',
offset: 'string',
}
],
orders: [{
symbol: 'string',
exchange: 'string',
direction: 'string',
volume: 6,
price: 4,
orderid: 'string',
type: 'string',
offset: 'string',
traded: 7,
status: 'string',
// datetime :datetime
reference: 'string',
}]
}
}
},
{
url: '/trader/api/v1/strategy_file',
method: 'get',
response: ({ body, query }) => {
return [
{
file_name: 'string',
class_name: 'string',
status: 'string',
}
]
}
},
{
url: '/trader/api/v1/strategies',
method: 'get',
response: ({ body, query }) => {
return [
{
strategy_name: 'string',
class_name: 'string',
vt_symbol: 'string',
setting: {},
status: 1,
}
]
}
},
{
url: '/trader/api/v1/strategy_file/load',
method: 'get',
response: ({ body, query }) => {
return [
{
class_names: 'asdasdas'
}
]
}
},
] as MockMethod[]
+28
View File
@@ -0,0 +1,28 @@
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/onenote/api/v1/one_note',
method: 'get',
response: () => {
return [
{
section_id: 'x111',
section_name: 'A',
page_list: [
{
page_id: 'y111',
section_id: 'x111',
page_name: 'B',
},
{
page_id: 'y222',
section_id: 'x111',
page_name: 'C',
},
]
}
]
}
}
] as MockMethod[]
-56
View File
@@ -1,56 +0,0 @@
server {
listen 8080;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /write {
alias /usr/share/nginx/html;
index index.html index.htm;
}
location /home {
alias /usr/share/nginx/html;
index index.html index.htm;
}
location ~ /view {
alias /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
+1555 -43
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -12,8 +12,8 @@
"dependencies": {
"@element-plus/icons-vue": "^1.1.4",
"@types/node": "^17.0.23",
"axios": "^0.26.1",
"aplayer": "^1.10.1",
"axios": "^0.26.1",
"clipboard": "^2.0.10",
"copy-to-clipboard": "^3.3.1",
"echarts": "^5.3.2",
@@ -24,9 +24,14 @@
"lodash-unified": "^1.0.2",
"md-editor-v3": "^1.11.6",
"moment": "^2.29.4",
"node-sass": "^8.0.0",
"pinia": "^2.0.13",
"qs": "^6.10.3",
"sass": "^1.57.1",
"sass-loader": "^13.2.0",
"save": "^2.4.0",
"scss": "^0.2.4",
"style-loader": "^3.3.1",
"type-fest": "^2.12.2",
"vue": "^3.2.25",
"vue-router": "^4.0.14",
@@ -40,10 +45,10 @@
"@vitejs/plugin-vue": "^2.3.0",
"mockjs": "^1.1.0",
"typescript": "^4.5.4",
"v-contextmenu": "^3.0.0",
"vite": "^2.9.13",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6",
"v-contextmenu": "^3.0.0",
"vue-tsc": "^0.29.8"
}
}
+20 -1
View File
@@ -92,5 +92,24 @@ const sortBlogs = (data: Object, btId: string) => {
})
}
const countBlogs = () => {
return service({
url: '/wiki/api/v1/reader/blogs/count',
method: 'GET',
headers: headers,
})
}
export { listAll, updateBtName, putBlogType, removeBlogType, sortBlogTypes, getContent, putBlog, updateContent, deleteContent, sortBlogs }
export {
listAll,
updateBtName,
putBlogType,
removeBlogType,
sortBlogTypes,
getContent,
putBlog,
updateContent,
deleteContent,
sortBlogs,
countBlogs
}
+9 -1
View File
@@ -49,10 +49,18 @@ const delete_bookmarks = (params: Object) => {
})
}
const bookmarks_count = () => {
return service({
url: '/bookmark/api/v1/bookmark/count',
method: 'GET',
})
}
export {
search_bookmark,
put_bookmark,
delete_bookmark,
delete_bookmarks,
update_bookmark
update_bookmark,
bookmarks_count
}
+26
View File
@@ -0,0 +1,26 @@
import { service } from '../utils/request'
const headers = {
'Content-Type': 'application/json;charsetset=UTF-8'
}
const put_event = (data: Object) => {
return service({
url: '/calendar/api/v1/event',
method: 'PUT',
data: data
})
}
const get_event = () => {
return service({
url: '/calendar/api/v1/event',
method: 'GET',
headers: headers
})
}
export {
get_event,
put_event,
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

+70
View File
@@ -0,0 +1,70 @@
<template>
<span class="headerAvatar">
<template v-if="picType === 'avatar'">
<el-avatar v-if="useTenantStore.tenant.headerImg" :size="30" :src="avatar" />
<el-avatar v-else :size="30" :src="noAvatar" />
</template>
<template v-if="picType === 'img'">
<img v-if="useTenantStore.tenant.headerImg" :src="avatar" class="avatar">
<img v-else :src="noAvatar" class="avatar">
</template>
<template v-if="picType === 'file'">
<img :src="file" class="file">
</template>
</span>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { tenantStore } from '@/store/modules/tenant'
import noAvatarPng from '@/assets/noBody.png'
const props = defineProps({
picType: {
type: String,
required: false,
default: 'avatar'
},
picSrc: {
type: String,
required: false,
default: ''
}
})
const path = ref(import.meta.env.VITE_BASE_API + '/')
const noAvatar = ref(noAvatarPng)
const useTenantStore = tenantStore()
const avatar = computed(() => {
if (props.picSrc === '') {
if (useTenantStore.tenant.headerImg !== '' && useTenantStore.tenant.headerImg.slice(0, 4) === 'http') {
return useTenantStore.tenant.headerImg
}
return path.value + useTenantStore.tenant.headerImg
} else {
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
return props.picSrc
}
return path.value + props.picSrc
}
})
const file = computed(() => {
if (props.picSrc && props.picSrc.slice(0, 4) !== 'http') {
return path.value + props.picSrc
}
return props.picSrc
})
</script>
<style scoped>
.headerAvatar {
display: flex;
justify-content: center;
align-items: center;
margin-right: 8px;
}
.file {
width: 80px;
height: 80px;
position: relative;
}
</style>
+43 -35
View File
@@ -1,12 +1,11 @@
<template>
<div class="4444">
<div>
<el-container>
<el-aside width="150px">
<el-aside width="180px">
<SideBar></SideBar>
</el-aside>
<el-container>
<el-header
style="border-bottom-style:solid; border-bottom-width: 0.5px; border-bottom-color:rgba(151, 151, 151, 0.3);">
<el-header>
<NavBar></NavBar>
</el-header>
<el-main>
@@ -20,7 +19,6 @@
<div>
<el-avatar @click="openGithub" src="https://github.githubassets.com/favicons/favicon.svg" />
</div>
</el-footer>
</el-container>
</el-container>
@@ -31,6 +29,32 @@
import MainApp from '../layout/MainApp.vue'
import NavBar from "../layout/NavBar.vue"
import SideBar from "../layout/SideBar.vue"
import { settingsStore } from "@/store/modules/settings"
// -- IMPORT --
const useSettingsStore = settingsStore()
// -- REACTIVE OBJECT --
// -- REF OBJECT --
// -- EVENT DEFINITION
const iniPage = () => {
const screenWidth = document.body.clientWidth
if (screenWidth < 1000) {
useSettingsStore.settings.isMobile = true
// isSider.value = false
// isCollaps.value = true
} else if (screenWidth >= 1000 && screenWidth < 1200) {
useSettingsStore.settings.isMobile = false
// isSider.value = false
// isCollaps.value = true
} else {
useSettingsStore.settings.isMobile = false
// isSider.value = true
// isCollaps.value = false
}
}
const openGithub = () => {
let href = 'https://github.com/simple321vip'
@@ -42,48 +66,32 @@ const openSiteQuery = () => {
window.open(href, '_blank')
}
/**
* AUTO INVOKE FUNCTION
*/
iniPage()
</script>
<style scoped>
/* .el-header,
.el-footer {
color: rgb(51, 51, 51);
text-align: center;
line-height: 60px;
} */
/*
.el-aside {
background-color: #e9eef3;
color: #333;
text-align: left;
line-height: 200px;
.el-header {
border-bottom-style: solid;
border-bottom-width: 0.5px;
border-bottom-color: rgba(151, 151, 151, 0.3);
}
.el-main {
background-color: #e9eef3;
color: #333;
/* line-height: 450px; */
/* vertical-align: top;
padding: 5px;
padding: 16px;
overflow: hidden;
}
body > .el-container {
margin-bottom: 40px;
.el-aside {
margin-left: -10px;
background: #191a23;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
} */
.el-footer {
margin-top: 20px;
display: flex;
justify-content: space-around;
}
+10 -2
View File
@@ -1,11 +1,19 @@
<template>
<section class="section-main" style="height:100%;">
<router-view />
<section class="section-main" v-loading="usesSttingsStore.isLoading" element-loading-text="页面加载中……"
element-loading-background="rgba(0, 0, 0, 0.1)">
<router-view v-if="usesSttingsStore.isRouterAlive" />
</section>
</template>
<script setup lang='ts'>
import { settingsStore } from "@/store/modules/settings"
const usesSttingsStore = settingsStore()
</script>
<style>
.section-main {
height: 100%;
padding: 14px;
}
</style>
+75 -67
View File
@@ -1,88 +1,96 @@
<template>
<div class="nav-main">
<div style="width: 800px;">
<div>
当前时间{{ time }}
<el-row class="pd-0">
<el-col :xs="2" :lg="1" :md="1" :sm="1" :xl="1" style="z-index:100">
<!-- <div class="menu-total" @click="totalCollapse">
<div v-if="isCollapse" class="gvaIcon gvaIcon-arrow-double-right" />
<div v-else class="gvaIcon gvaIcon-arrow-double-left" />
</div> -->
</el-col>
<el-col :xs="10" :lg="14" :md="14" :sm="9" :xl="14" :pull="1">
<!-- 修改为手机端不显示顶部标签 -->
<!-- <el-breadcrumb v-show="!isMobile" class="breadcrumb">
<el-breadcrumb-item
v-for="item in matched.slice(1,matched.length)"
:key="item.path"
>{{ fmtTitle(item.meta.title,route) }}</el-breadcrumb-item>
</el-breadcrumb> -->
</el-col>
<el-col :xs="12" :lg="9" :md="9" :sm="14" :xl="9">
<div class="right-box">
<el-dropdown>
<div class="dp-flex justify-content-center align-items height-full width-full">
<span class="header-avatar" style="cursor: pointer">
<CustomPic />
<span v-show="!useSettingsStore.isMobile" style="margin-left: 5px">{{
useTenantStore.tenant.account
}}</span>
<el-icon>
<arrow-down />
</el-icon>
</span>
</div>
<div>
期货交易时间&nbsp
<el-icon color="yellow">
<Sunrise />
</el-icon>&nbsp 9:00-11:30 &nbsp
<el-icon color="gold">
<Sunny />
</el-icon>&nbsp 13:30-15:00 &nbsp
<el-icon color="blue">
<Moon />
</el-icon>&nbsp 21:00-23:00
</div>
</div>
<el-dropdown trigger="click" v-show="tenant.account">
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>profile</el-dropdown-item>
<el-dropdown-item @click="dialogVisible = true">退出</el-dropdown-item>
<el-dropdown-menu class="dropdown-group">
<el-dropdown-item>
<span style="font-weight: 600;">
当前角色{{ useTenantStore.tenant.account }}
</span>
</el-dropdown-item>
<template v-if="useTenantStore.tenant.account">
<!-- <el-dropdown-item v-for="item in userStore.userInfo.authorities.filter(i=>i.authorityId!==userStore.userInfo.authorityId)" :key="item.authorityId" @click="changeUserAuth(item.authorityId)">
<span>
切换为{{ item.authorityName }}
</span>
</el-dropdown-item> -->
</template>
<el-dropdown-item icon="avatar" @click="toPerson">个人信息</el-dropdown-item>
<el-dropdown-item icon="reading-lamp" @click="useTenantStore.logout"> </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<el-dialog v-model="dialogVisible" title="提示" width="30%">
<span>确认你的登出操作么</span>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="doLogout">确认</el-button>
</span>
</template>
</el-dialog>
<span @click="doLogin" v-show="!tenant.account">登录</span>
</el-col>
</el-row>
</template>
<script setup lang='ts'>
import $moment from "moment";
import { reactive, ref } from "vue";
import router from '../../router'
import { tenantStore } from '../../store/tenant'
import { logout } from '../../api/user'
// obtain user infomation
const tenant = tenantStore()
tenant.reflush()
const dialogVisible = ref(false)
import CustomPic from "@/components/customPic/index.vue";
import { tenantStore } from '@/store/modules/tenant'
import { settingsStore } from '@/store/modules/settings'
// show time
let time = ref<String>($moment().format("YYYY年MM月DD日 HH:mm:ss"));
setInterval(() => {
time.value = $moment().format("YYYY年MM月DD日 HH:mm:ss");
}, 1000);
// -- IMPORT --
const useTenantStore = tenantStore()
const useSettingsStore = settingsStore()
// login logout function
const doLogin = () => {
router.push({
path: '/login'
})
}
const doLogout = () => {
dialogVisible.value = false
logout(tenant.id).catch(() => { console.log(1) }).finally(() => {
tenant.logout()
router.push({
path: '/login'
})
})
// -- REACTIVE OBJECT --
// -- REF OBJECT --
// -- EVENT DEFINITION
const toPerson = () => {
}
useTenantStore.reflush()
</script>
<style>
.open_side {
background: url("../../assets/logo.png") center no-repeat;
background-size: cover;
<style lang="scss" scoped>
.right-box {
padding-top: 16px;
display: flex;
justify-content: flex-end;
align-items: center;
img {
vertical-align: middle;
border: 1px solid #ccc;
border-radius: 6px;
}
}
.nav-main {
.header-avatar {
display: flex;
justify-content: center;
align-items: center;
justify-content: space-between;
/* background-color: bisque; */
}
</style>
+104 -9
View File
@@ -1,27 +1,113 @@
<template>
<div>
<el-menu router class="side_Style" :style="{ height: sideHeight }">
<el-menu-item v-for="(route, index) in current_routes" v-bind:key="index" v-bind:index="route.path"
v-bind:title="route.meta?.name">{{ route.meta?.name }}</el-menu-item>
<el-menu router class="el-menu-vertical" :style="{ height: sideHeight }" :background-color="theme.background"
:active-text-color="theme?.background">
<el-menu-item v-for="(route, index) in current_routes" :key="index" :index="route.path" :title="route.meta?.name"
@click="onclick()">
<template #title>
<div class="gva-menu-item">
<el-icon v-if="index == 0" :size="20">
<Sunny />
</el-icon>
<el-icon v-if="index == 1" :size="20">
<EditPen />
</el-icon>
<el-icon v-if="index == 2" :size="20">
<Star />
</el-icon>
<el-icon v-if="index == 3" :size="20">
<Notebook />
</el-icon>
<el-icon v-if="index == 4" :size="20">
<Calendar />
</el-icon>
<el-icon v-if="index == 5" :size="20">
<MostlyCloudy />
</el-icon>
<el-icon v-if="index == 10" :size="20">
<Setting />
</el-icon>
<span>{{ route.meta?.name }}</span>
</div>
</template>
</el-menu-item>
</el-menu>
</div>
</template>
<script setup lang='ts'>
import { RouteRecordRaw } from "vue-router";
// import { store } from "../../store/index";
import router from "../../router/index";
import { onBeforeMount, ref } from 'vue';
let current_routes = router.options.routes[0].children;
import { onBeforeMount, ref } from 'vue'
import router from "@/router/index"
import { settingsStore } from "@/store/modules/settings"
import { Theme } from "@/entity/index";
// -- IMPORT --
const useSettingsStore = settingsStore()
// -- REACTIVE OBJECT --
// -- REF OBJECT --
let sideHeight = ref("")
let current_routes = router.options.routes[0].children
const theme = ref<Theme>({
background: '#fff',
activeBackground: '#4D70FF',
activeText: '#fff',
normalText: '#333',
hoverBackground: 'rgba(64, 158, 255, 0.08)',
hoverText: '#333'
})
// -- EVENT DEFINITION
const onclick = () => {
activeBackground.value = '#4D70FF'
}
const getTheme = () => {
switch (useSettingsStore.sideMode) {
// white color
case '#fff':
theme.value = {
background: '#fff',
activeBackground: '#4D70FF',
activeText: '#fff',
normalText: '#333',
hoverBackground: 'rgba(64, 158, 255, 0.08)',
hoverText: '#333',
}
break;
// black color
case '#191a23':
theme.value = {
background: '#191a23',
activeBackground: '#4D70FF',
activeText: '#fff',
normalText: '#fff',
hoverBackground: 'rgba(64, 158, 255, 0.08)',
hoverText: '#fff',
}
break;
}
}
/**
* AUTO INVOKE FUNCTION
*/
getTheme()
onBeforeMount(() => {
sideHeight.value = window.innerHeight + 'px'
})
const activeBackground = ref(theme.value.activeBackground)
onclick()
</script>
<style>
<style lang="scss" scoped>
.side_Style {
width: 100px;
}
@@ -30,6 +116,15 @@ onBeforeMount(() => {
width: 200px;
}
.gva-menu-item {
color: #fff;
}
.el-menu-item.is-active {
color: v-bind(activeBackground);
background: v-bind(activeBackground);
}
/* .el-menu-item {
background-color: #01dfd7;
} */
+14 -14
View File
@@ -26,7 +26,7 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus'
import { tenantStore } from '../../store/tenant'
import { tenantStore } from '../../store/modules/tenant'
import router from '../../router'
import baiduCloudImage from "../../assets/baiducloud.png"
import { config, scan } from '../../const/config'
@@ -34,7 +34,7 @@ import { config, scan } from '../../const/config'
let qrcode = config.BAIDU_CLOUD_URL + config.RESPONSE_TYPE + config.CLIENT_ID + config.REDIRECT_URI + config.SCOPE + config.DEVICE_ID + config.QR_CODE + config.DISPLAY
const tenant = tenantStore()
const useTenantStore = tenantStore()
const ruleFormRef = ref<FormInstance>()
const loginForm = reactive({
@@ -66,19 +66,19 @@ const dologin = (form: any) => {
if (!form)
return
form.validate((valid: any) => {
if (valid) {
tenant.login(loginForm.user_id, loginForm.password).then(res => {
console.log(1)
router.push({
path: '/home'
})
})
// form.validate((valid: any) => {
// if (valid) {
// useTenantStore.login(loginForm.user_id, loginForm.password).then(res => {
// console.log(1)
// router.push({
// path: '/home'
// })
// })
} else {
return false
}
})
// } else {
// return false
// }
// })
}
const style = reactive({} as any)
+23 -1
View File
@@ -1,3 +1,5 @@
import { Tenant } from '@/entity';
import { tenantStore } from '@/store/modules/tenant';
import router from '../router'
import { setToken, setTenant } from '../utils/auth'
@@ -41,7 +43,27 @@ const scan_method: any = {
production: (qrcode: string) => {
window.location.href = qrcode
},
development: () => {
development: async () => {
const useTenantStore = tenantStore()
const tenant: Tenant = {
tenant_id: '7788',
account: '小小的测试账户'
}
let token = 'ABCDEFG'
await useTenantStore.login(tenant, token).then(() => {
const { href } = router.resolve({
path: '/'
})
window.open(href, '_self')
}).catch((error) => {
const { href } = router.resolve({
path: '/login'
})
window.open(href, '_self')
})
setToken("token")
setTenant(
{
+24 -2
View File
@@ -1,6 +1,28 @@
type Tenant = {
id: string,
tenant_id: string,
account: string
}
export { Tenant }
type Theme = {
background: string,
activeBackground: string,
activeText: string,
normalText: string,
hoverBackground: string,
hoverText: string,
}
type DataTimeline = {
from: string,
title: string,
showDayAndMonth: boolean,
message: string,
}
type Event = {
event_date: string,
title: string,
event_info: string,
}
export { Tenant, Theme, DataTimeline, Event }
+7 -117
View File
@@ -2,137 +2,27 @@ import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from "element-plus";
import 'element-plus/dist/index.css'
import { store } from './store'
import router from './router'
import { createPinia } from 'pinia'
const store = createPinia()
import '@/permission'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
let app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
import contentmenu from 'v-contextmenu'
import 'v-contextmenu/dist/themes/default.css'
app.use(contentmenu)
import { setupMock } from '../mock'
if (process.env.NODE_ENV === 'development') {
setupMock()
}
let app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(contentmenu)
app.use(router)
app.use(ElementPlus)
app.use(store)
import { getToken, getTenant, setToken, setTenant } from './utils/auth'
import { Tenant } from './entity/index'
import Cookies from 'js-cookie'
import { tenantStore } from './store/tenant'
const whiteList = ['/login', '/register', '/sorryPage']
let url = window.location.href
async function checktoken(url: string) {
if (url.search("register") != -1) {
let arr = url.split('?')
let parameters = arr[1].split('&')
let query_data: { [key: string]: any } = {}
parameters.forEach(parameter => {
let parameter_list = parameter.split("=")
query_data[parameter_list[0]] = parameter_list[1]
})
router.push({
path: '/register',
query: query_data
})
return
}
if (url.search("/home/") != -1) {
let arr = url.split('?')
let parameters = arr[1].split('&')
let query_data: { [key: string]: any } = {}
parameters.forEach(parameter => {
let parameter_list = parameter.split("=")
query_data[parameter_list[0]] = parameter_list[1]
})
const tenant = {
tenant_id: query_data.tenantId,
account: query_data.account
}
const tenant_store = tenantStore()
await tenant_store.login(tenant, query_data.token).then(() => {
const { href } = router.resolve({
path: '/'
});
window.open(href, '_self');
}).catch((error) => {
const { href } = router.resolve({
path: '/login'
});
window.open(href, '_self');
})
}
if (url.search("sorryPage") != -1) {
router.push({
path: '/sorryPage',
})
return
}
}
checktoken(url)
/**
* ルーター監視
* 1、トーケン取得
* 2、トーケンなし場合はログイン画面に遷移
* 3、トーケンあり場合:
*  既にログイン場合はデフォルト /  に遷移
*  
*/
router.beforeEach((to, from, next) => {
console.log(from.path, to.path)
const token = getToken()
if (typeof token === 'string') {
switch (to.path) {
case '/login':
next('/')
break;
case '/':
const tenant = <Tenant>(JSON.parse(getTenant() as string))
if (url.search("write") != -1) {
next('/BlogEditer')
} else if (url.search("view") != -1) {
let bid = Cookies.get('bid')
router.push({
path: '/BlogViewer',
query: { bid: bid }
})
} else {
router.push({
path: '/home',
query: tenant
})
}
break;
default:
next()
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next('/login')
}
}
})
app.mount('#app')
+89
View File
@@ -0,0 +1,89 @@
import router from './router'
import Cookies from 'js-cookie'
import { getToken, getTenant } from './utils/auth'
import { Tenant } from './entity/index'
import { tenantStore } from './store/modules/tenant'
const whiteList = ['/login', '/register', '/sorryPage']
let url = window.location.href
router.beforeEach((to, from, next) => {
const token = getToken()
if (typeof token === 'string') {
switch (to.path) {
case '/login':
next('/')
break;
case '/':
const tenant = <Tenant>(JSON.parse(getTenant() as string))
if (url.search("write") != -1) {
next('/BlogEditer')
} else if (url.search("view") != -1) {
let bid = Cookies.get('bid')
router.push({
path: '/BlogViewer',
query: { bid: bid }
})
} else {
router.push({
path: '/home',
query: tenant
})
}
break;
default:
next()
}
} else {
if (url.search("register") != -1) {
let arr = url.split('?')
let parameters = arr[1].split('&')
let query_data: { [key: string]: any } = {}
parameters.forEach(parameter => {
let parameter_list = parameter.split("=")
query_data[parameter_list[0]] = parameter_list[1]
})
router.push({
path: '/register',
query: query_data
})
}
if (url.search("/home/") != -1) {
let arr = url.split('?')
let parameters = arr[1].split('&')
let query_data: { [key: string]: any } = {}
parameters.forEach(parameter => {
let parameter_list = parameter.split("=")
query_data[parameter_list[0]] = parameter_list[1]
})
const tenant = {
tenant_id: query_data.tenantId,
account: query_data.account
}
const tenant_store = tenantStore()
tenant_store.login(tenant, query_data.token).then(() => {
const { href } = router.resolve({
path: '/'
});
window.open(href, '_self');
}).catch((error) => {
const { href } = router.resolve({
path: '/login'
});
window.open(href, '_self');
})
}
if (url.search("sorryPage") != -1) {
router.push({
path: '/sorryPage',
})
}
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next('/login')
}
}
})
+28 -27
View File
@@ -1,5 +1,6 @@
import { createRouter, createMemoryHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: "/",
@@ -14,103 +15,103 @@ const routes: Array<RouteRecordRaw> = [
},
{
path: '/blog',
component: () => import('../view/blog/index.vue'),
component: resolve => (require('@/view/blog/index.vue'), resolve),
meta: {
name: '博客'
}
},
{
path: '/bookmark',
component: () => import('../view/bookmark/index.vue'),
component: resolve => (require('@/view/bookmark/index.vue'), resolve),
meta: {
name: '书签'
}
},
{
path: '/school',
component: () => import('../view/school/index.vue'),
path: '/onenote',
component: resolve => (require('@/view/onenote/index.vue'), resolve),
meta: {
name: '学习'
name: 'onenote'
}
},
{
path: '/thinking',
component: () => import('../view/thinking/index.vue'),
path: '/calendar',
component: resolve => (require('@/view/calendar/index.vue'), resolve),
meta: {
name: '感悟人生'
name: '日历'
}
},
{
path: '/cloud',
component: () => import('../view/cloud/index.vue'),
component: resolve => (require('@/view/cloud/index.vue'), resolve),
meta: {
name: '个人云盘'
}
},
{
path: '/market',
component: () => import('../view/recommend/index.vue'),
component: resolve => (require('@/view/recommend/index.vue'), resolve),
meta: {
name: '市场行情'
}
},
{
path: '/capital',
component: () => import('../view/capital/index.vue'),
component: resolve => (require('@/view/capital/index.vue'), resolve),
meta: {
name: '资金管理'
}
},
// {
// path: '/trader',
// component: () => import('../view/trader/index.vue'),
// meta: {
// name: 'trader'
// }
// },
{
path: '/strategy',
component: () => import('../view/trader/cta_strategy_file.vue'),
component: resolve => (require('@/view/trader/cta_strategy_file.vue'), resolve),
meta: {
name: '策略模板'
}
},
{
path: '/strategy_instance',
component: () => import('../view/trader/cta_strategy.vue'),
component: resolve => (require('@/view/trader/cta_strategy.vue'), resolve),
meta: {
name: 'CTA策略'
}
},
{
path: '/settings',
component: resolve => (require('@/view/settings/index.vue'), resolve),
meta: {
name: '设置'
}
},
]
},
{
path: "/feedback",
component: () => import('../view/blog/mdview.vue')
component: resolve => (require('@/view/blog/mdview.vue'), resolve),
},
{
path: "/BlogEditer",
component: () => import('../view/blog/createBlog.vue')
component: resolve => (require('@/view/blog/createBlog.vue'), resolve),
},
{
path: "/BlogViewer",
component: () => import('../view/blog/mdview.vue')
component: resolve => (require('@/view/blog/mdview.vue'), resolve),
},
{
path: "/login",
component: () => import('../components/login/login.vue')
component: () => import('@/components/login/login.vue')
},
{
path: "/illustration",
component: () => import('../components/illustration/index.vue')
component: resolve => (require('../components/illustration/login.vue'), resolve)
},
{
path: "/register",
component: () => import('../components/login/register.vue')
component: resolve => (require('../components/login/register.vue'), resolve)
},
{
path: "/sorryPage",
component: () => import('../components/login/sorry.vue')
component: resolve => (require('../components/login/sorry.vue'), resolve)
},
]
+14
View File
@@ -0,0 +1,14 @@
import axios from 'axios'
const service = axios.create()
const get_holiday = () => {
return service({
url: 'https://holidays-jp.github.io/api/v1/2023/date.json',
method: 'GET'
})
}
export {
get_holiday
}
+17
View File
@@ -0,0 +1,17 @@
import axios from 'axios'
const service = axios.create()
export function Commits(page: number) {
return service({
url: 'https://api.github.com/repos/simple321vip/violin-home/commits?page=' + page,
method: 'get'
})
}
export function Members() {
return service({
url: 'https://api.github.com/orgs/FLIPPED-AURORA/members',
method: 'get'
})
}
+30
View File
@@ -0,0 +1,30 @@
import axios from 'axios'
import { ref } from 'vue'
const weatherInfo = ref('对不起主人,我还没有获得天气信息,暂时无法显示哟。')
const amapKey = '8e8baa8a7317586c29ec694895de6e0a'
export const useWeatherInfo = () => {
ip()
return weatherInfo
}
export const ip = async () => {
// key换成你自己的 https://console.amap.com/dev/index
// if (amapKey === '') {
if (amapKey.length == 1) {
return false
}
const res = await axios.get('https://restapi.amap.com/v3/ip?key=' + amapKey)
if (res.data.adcode) {
getWeather(res.data.adcode)
}
}
const getWeather = async (code: string) => {
const response = await axios.get('https://restapi.amap.com/v3/weather/weatherInfo?key=' + amapKey + '&extensions=base&city=' + code)
if (response.data.status === '1') {
const s = response.data.lives[0]
weatherInfo.value = s.city + ' 天气:' + s.weather + ' 温度:' + s.temperature + '摄氏度 风向:' + s.winddirection + ' 风力:' + s.windpower + '级 空气湿度:' + s.humidity
}
}
+3 -67
View File
@@ -1,69 +1,5 @@
import { defineStore, acceptHMRUpdate } from 'pinia'
import { authorize } from '../api/user'
import { getToken, setToken, resetToken, setTenant, getTenant } from '../utils/auth'
import { Tenant } from '../entity/index'
import { createPinia } from "pinia"
const store = createPinia()
interface Record {
isFolder: boolean
path: string
records: Set<Record>
}
/**
* skeleton
*
*
*/
export const tenantStore = defineStore({
id: 'cloud',
state: () => ({
cloud: new Set<Record>(),
}),
getters: {
},
actions: {
logout() {
this.$patch({
})
resetToken()
// we could do other stuff like redirecting the user
},
/**
* Attempt to login a user
* @param {string} user_id
* @param {string} user_password
*/
async login(tenant: any, token: string) {
try {
await authorize({
tenant_id: tenant.tenant_id, token: token
})
setToken(token)
setTenant(tenant)
} catch {
Promise.resolve("authorize error")
}
},
async reflush() {
if (getToken()) {
const tenant = <Tenant>(JSON.parse(getTenant() as string))
const token = <string>getToken()
this.$patch({
})
}
}
},
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(tenantStore, import.meta.hot))
}
export { store }
+29
View File
@@ -0,0 +1,29 @@
import { acceptHMRUpdate, defineStore } from "pinia"
import { computed, ref } from "vue"
export const settingsStore = defineStore('settings', () => {
const settings = ref({
sideMode: '#191a23',
isMobile: false,
isRouterAlive: true,
isLoading: false
})
const sideMode = computed(() => settings.value.sideMode)
const isMobile = computed(() => settings.value.isMobile)
const isRouterAlive = computed(() => settings.value.isRouterAlive)
const isLoading = computed(() => settings.value.isLoading)
return {
settings,
sideMode,
isMobile,
isRouterAlive,
isLoading,
}
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(settingsStore, import.meta.hot))
}
+51
View File
@@ -0,0 +1,51 @@
import { acceptHMRUpdate, defineStore } from "pinia"
import { reactive } from "vue"
import { get_vt_symbols, get_exchanges, get_subscribe_vt_symbols } from '../../api/capital'
export const strategyStore = defineStore('strategy', () => {
const strategy = reactive({
class_names: [],
vt_symbols: new Map(),
subscribe_vt_symbols: [],
exchanges: []
})
const select_exchanges = async () => {
if (strategy.exchanges.length == 0) {
get_exchanges().then(res => {
strategy.exchanges = res.data.exchanges
})
}
}
const select_vt_symbols = async () => {
if (strategy.vt_symbols.size == 0) {
get_vt_symbols().then(res => {
let keys = Object.keys(res.data.vt_symbols)
keys.forEach(key => {
strategy.vt_symbols.set(key, res.data.vt_symbols[key])
})
})
}
}
const select_subscribe_vt_symbols = async () => {
if (strategy.subscribe_vt_symbols.length == 0) {
get_subscribe_vt_symbols().then(res => {
strategy.subscribe_vt_symbols = res.data.subscribe_vt_symbols
})
}
}
return {
strategy,
select_exchanges,
select_vt_symbols,
select_subscribe_vt_symbols
}
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(strategyStore, import.meta.hot))
}
+56
View File
@@ -0,0 +1,56 @@
import { defineStore, acceptHMRUpdate } from 'pinia'
import { authorize } from '../../api/user'
import { getToken, setToken, resetToken, setTenant, getTenant } from '../../utils/auth'
import { Tenant } from '../../entity/index'
import { ref } from 'vue'
export const tenantStore = defineStore('tenant', () => {
const tenant = ref({
account: '',
token: '',
id: '',
headerImg: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
})
const login = async (tenant: Tenant, token: string) => {
try {
await authorize({
tenant_id: tenant.tenant_id, token: token
})
setToken(token)
setTenant(tenant)
} catch {
Promise.resolve("authorize error")
}
}
const logout = async () => {
tenant.value.account = ''
tenant.value.token = ''
tenant.value.id = ''
resetToken()
window.location.reload()
}
const reflush = async () => {
if (getToken()) {
const tenantStorage = <Tenant>(JSON.parse(getTenant() as string))
const token = <string>getToken()
tenant.value.account = tenantStorage.account
tenant.value.token = token
tenant.value.id = tenantStorage.tenant_id
}
}
return {
tenant,
login,
logout,
reflush
}
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(tenantStore, import.meta.hot))
}
-43
View File
@@ -1,43 +0,0 @@
import { acceptHMRUpdate, defineStore } from "pinia"
import { get_vt_symbols, get_exchanges, get_subscribe_vt_symbols } from '../api/capital'
export const strategyStore = defineStore({
id: 'strategy',
state: () => ({
class_names: [],
vt_symbols: new Map(),
subscribe_vt_symbols: [],
exchanges: []
}),
actions: {
async select_exchanges() {
if (this.exchanges.length == 0) {
get_exchanges().then(res => {
this.$patch({ exchanges: res.data.exchanges })
})
}
},
async select_vt_symbols() {
if (this.vt_symbols.size == 0) {
get_vt_symbols().then(res => {
let keys = Object.keys(res.data.vt_symbols)
keys.forEach(key => {
this.vt_symbols.set(key, res.data.vt_symbols[key])
})
})
}
},
async select_subscribe_vt_symbols() {
if (this.subscribe_vt_symbols.length == 0) {
get_subscribe_vt_symbols().then(res => {
this.$patch({ subscribe_vt_symbols: res.data.vt_symbols })
})
}
}
}
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(strategyStore, import.meta.hot))
}
-75
View File
@@ -1,75 +0,0 @@
import { defineStore, acceptHMRUpdate } from 'pinia'
import { authorize } from '../api/user'
import { getToken, setToken, resetToken, setTenant, getTenant } from '../utils/auth'
import { Tenant } from '../entity/index'
/**
* Simulate a login
* @param {string} a
* @param {string} p
*/
// function apiLogin(a, p) {
// if (a === 'ed' && p === 'ed') return Promise.resolve({ isAdmin: true })
// if (p === 'ed') return Promise.resolve({ isAdmin: false })
// return Promise.reject(new Error('invalid credentials'))
// }
export const tenantStore = defineStore({
id: 'tenant',
state: () => ({
account: '',
token: '',
id: ''
}),
getters: {
},
actions: {
logout() {
this.$patch({
account: '',
token: '',
id: ''
})
resetToken()
// we could do other stuff like redirecting the user
},
/**
* Attempt to login a tenant
* @param {object} tenant
* @param {string} token
*/
async login(tenant: any, token: string) {
try {
await authorize({
tenant_id: tenant.tenant_id, token: token
})
setToken(token)
setTenant(tenant)
} catch {
Promise.resolve("authorize error")
}
},
async reflush() {
if (getToken()) {
const tenant = <Tenant>(JSON.parse(getTenant() as string))
const token = <string>getToken()
this.$patch({
account: tenant.account,
token: token,
id: tenant.id
})
}
}
},
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(tenantStore, import.meta.hot))
}
+1
View File
@@ -0,0 +1 @@
$color: red;
+43
View File
@@ -0,0 +1,43 @@
import { addZero } from "./number"
// 对Date的扩展,将 Date 转化为指定格式的String
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
// eslint-disable-next-line no-extend-native
const format = (date: Date, fmt: string) => {
var o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
'S': date.getMilliseconds() // 毫秒
}
if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) }
for (var k in o) {
// if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) }
}
return fmt
}
const formatTimeToStr = (times: any, pattern: string) => {
if (!pattern) {
pattern = 'yyyy-MM-dd hh:mm:ss'
}
let date = format(new Date(times), pattern)
return date.toLocaleString()
}
// 2023-01-03
const toLocalDate = (date: Date) => {
return date.getFullYear() + '-' + addZero(date.getMonth() + 1) + '-' + addZero(date.getDate())
}
export {
formatTimeToStr,
toLocalDate,
}
+11 -1
View File
@@ -2,4 +2,14 @@ const toPercent = (num: number) => {
return (num * 100).toFixed(2) + "%"
}
export { toPercent }
const addZero = (num: number) => {
if (num > 10) {
return num
}
return '0' + num
}
export {
toPercent,
addZero
}
+1 -1
View File
@@ -53,7 +53,7 @@
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { reactive, ref } from 'vue'
import { delete_bookmark_type, post_bookmark_type, get_bookmark_type } from '../../api/bookmark_type'
import type { FormInstance } from 'element-plus'
const formLabelWidth = '140px'
+1 -1
View File
@@ -10,7 +10,7 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ref } from 'vue'
import { put_bookmark_type } from '../../api/bookmark_type'
const bookmark_type_name = ref<String>('')
+8 -8
View File
@@ -3,12 +3,8 @@
<el-form :model="dialog_form">
<el-form-item label="分类" :label-width="formLabelWidth">
<el-select v-model="dialog_form.bk_type_id" placeholder>
<el-option
v-for="(item) in types"
:key="item.bk_type_id"
:value="item.bk_type_id"
:label="item.bk_type_name"
/>
<el-option v-for="(item) in types" :key="item.bk_type_id" :value="item.bk_type_id"
:label="item.bk_type_name" />
</el-select>
<el-form-item label="备注" :label-width="formLabelWidth">
<el-input v-model="dialog_form.comment" autocomplete="off" />
@@ -28,7 +24,7 @@
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { reactive } from 'vue'
import { update_bookmark, put_bookmark } from '../../api/bookmark'
import type { FormInstance } from 'element-plus'
const formLabelWidth = '140px'
@@ -69,15 +65,19 @@ const submit = () => {
</script>
<style scoped>.el-button--text {
<style scoped>
.el-button--text {
margin-right: 15px;
}
.el-select {
width: 300px;
}
.el-input {
width: 300px;
}
.dialog-footer button:first-child {
margin-right: 10px;
}
+19 -19
View File
@@ -14,12 +14,12 @@
<div class="tag_list">
<el-tag class="ml-2 click-icon" :type="item.clicked ? 'danger' : 'info'" v-for="(item) in bookmark_types"
@click="handleTags(item)">{{ item.bk_type_name }}</el-tag>
<el-button type="primary" @click="handleAddType" v-show="Tenant.account">增加</el-button>
<el-button type="primary" @click="handleManageType" v-show="Tenant.account">自定义</el-button>
<el-button type="primary" @click="handleAddType" v-show="useTenantStore.tenant.account">增加</el-button>
<el-button type="primary" @click="handleManageType" v-show="useTenantStore.tenant.account">自定义</el-button>
</div>
</el-form>
<div class="create_dialog">
<el-button type="primary" @click="handleInsert" v-show="Tenant.account">新建</el-button>
<el-button type="primary" @click="handleInsert" v-show="useTenantStore.tenant.account">新建</el-button>
</div>
<el-table ref="multipleTableRef" :data="tableData" @selection-change="handleSelectionChange" style="width: 100%">
@@ -39,9 +39,10 @@
<CopyDocument />
</el-icon>
<el-button class="click-icon" size="small" @click="handleEdit(scope.$index, scope.row)"
v-show="Tenant.account">编辑
v-show="useTenantStore.tenant.account">编辑
</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)" v-show="Tenant.account">
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)"
v-show="useTenantStore.tenant.account">
删除
</el-button>
</template>
@@ -72,34 +73,33 @@
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { search_bookmark, delete_bookmark } from '../../api/bookmark'
import { get_bookmark_type } from '../../api/bookmark_type'
import { reactive, ref, h } from 'vue'
import type { ElTable } from 'element-plus'
import { CopyDocument } from "@element-plus/icons-vue"
import { ElNotification } from 'element-plus'
import copy from 'copy-to-clipboard'
import bookmark_dialog from './dialog.vue'
import bookmarkType_dialog from './Typedialog.vue'
import createType_dialog from './createTypedialog.vue'
import delete_dialog from '../../components/operate/deleteDialog.vue'
import type { ElTable } from 'element-plus'
import { CopyDocument } from "@element-plus/icons-vue";
import { ElNotification } from 'element-plus'
import copy from 'copy-to-clipboard';
import { h } from 'vue'
import { tenantStore } from '../../store/tenant'
import { tenantStore } from '../../store/modules/tenant'
import { search_bookmark, delete_bookmark } from '../../api/bookmark'
import { get_bookmark_type } from '../../api/bookmark_type'
// obtain user infomation
const Tenant = tenantStore()
const useTenantStore = tenantStore()
// 定义书签格式
type Bookmark = {
bk_id: string,
bk_type_id: number,
bk_type_name: String,
comment: String,
url: String
bk_type_name: string,
comment: string,
url: string
}
// 定义 表单格式
type Searchform = {
bk_type_ids: number[],
comment: String
comment: string
}
// 操作code
+150
View File
@@ -0,0 +1,150 @@
<template>
<el-calendar v-model="value" v-if="isComponentActive" v-loading="isComponentLoading"
element-loading-text="主人别着急我在努力加载中^_^">
<template #dateCell="{ data }" lo>
<div class="date-cell-holiday" v-if="Object.keys(holidays).includes(toLocalDate(data.date))">
<span style="color: red;" @click="onclick(data.date)"> {{ data.date.getDate() }}</span><br>
<span>{{ holidays[toLocalDate(data.date)] }}</span>
</div>
<div class="date-cell" v-else>
<span style="color: red;" v-if="data.date.getDay() == 0 || data.date.getDay() == 6" @click="onclick(data.date)">
{{
data.date.getDate()
}}</span>
<span v-else @click="onclick(data.date)"> {{ data.date.getDate() }}</span>
</div>
<div class="date-cell-event" v-if="Object.keys(eventDataObject).includes(toLocalDate(data.date))">
<span>{{ eventDataObject[toLocalDate(data.date)] }}</span>
</div>
</template>
</el-calendar>
<span>待办事项</span>
<el-table :data="eventDataList">
<el-table-column property="event_date" label="Date" width="150" />
<el-table-column property="title" label="title" width="200" />
<el-table-column property="event_info" label="eventInfo" />
</el-table>
<el-dialog v-model="dialogFormVisible" title="待办事项">
<el-form :model="form">
<el-form-item label="日期" :label-width="formLabelWidth">
<span>{{ form.event_date }}</span>
</el-form-item>
<el-form-item label="title" :label-width="formLabelWidth">
<el-input v-model="form.title" autocomplete="off" />
</el-form-item>
<el-form-item label="eventInfo" :label-width="formLabelWidth">
<el-input v-model="form.event_info" autocomplete="off" type="textarea" />
</el-form-item>
<el-form-item label="alert" :label-width="formLabelWidth">
<el-checkbox-group v-model="checkedalerts" :min="0" :max="2">
<el-checkbox v-for="city in alerts" :key="city" :label="city">{{
city
}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogFormVisible = false">Cancel</el-button>
<el-button type="primary" @click="confirm">
Confirm
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { nextTick, onMounted, reactive, ref } from 'vue'
import { get_holiday } from '@/service/calendar'
import { toLocalDate } from '@/utils/date'
import { get_event, put_event } from "@/api/calendar"
import { Event } from "@/entity/index"
import { settingsStore } from "@/store/modules/settings";
// -- IMPORT --
const useSettingsStore = settingsStore()
// -- REACTIVE OBJECT --
const holidays = reactive<any>({})
const eventDataList = reactive<Event[]>([])
const eventDataObject = reactive<any>({})
const form = reactive({
event_date: '',
title: '',
event_info: '',
})
// -- REF OBJECT --
const value = ref(new Date())
const dialogFormVisible = ref(false)
const formLabelWidth = '140px'
const isComponentActive = ref(false)
const isComponentLoading = ref(true)
const checkedalerts = ref([])
const alerts = ['email', 'messageBox', '手机短信', '微信通知']
// -- EVENT DEFINITION
const onclick = (date: Date) => {
form.event_date = toLocalDate(date)
dialogFormVisible.value = true
}
const confirm = async () => {
await put_event(form).then(() => {
})
dialogFormVisible.value = false
handleCommand('refresh')
}
const handleCommand = (command: string) => {
if (command === 'refresh') {
useSettingsStore.settings.isLoading = true
useSettingsStore.settings.isRouterAlive = false
nextTick(() => {
useSettingsStore.settings.isRouterAlive = true
useSettingsStore.settings.isLoading = false
})
} else if (command === 'closeOther') {
// useSettingsStore.closeOther()
} else {
// useSettingsStore.closeLeftOrRight(command)
}
}
/**
* AUTO INVOKE FUNCTION
*/
onMounted(async () => {
await get_holiday().then((resp) => {
Object.keys(resp.data).forEach(element => {
holidays[element] = resp.data[element]
})
})
await get_event().then((response) => {
eventDataList.length = 0
response.data.forEach((record: Event) => {
eventDataList.push(record)
eventDataObject[record.event_date] = record.title
})
})
isComponentActive.value = true
isComponentLoading.value = false
})
</script>
<style lang="scss" scoped>
.date-cell-holiday {
background: #dfd;
}
.date-cell-event {
background: yellow;
}
</style>
+4 -5
View File
@@ -48,7 +48,7 @@
<el-collapse-item title="手动下单" name="2">
<el-select v-model="vt_symbol" placeholder="select a vt_symbol" @change="select_contract">
<el-option v-for="symbol in store.subscribe_vt_symbols" :value="symbol" />
<el-option v-for="symbol in useStrategyStore.strategy.subscribe_vt_symbols" :value="symbol" />
</el-select>
<div style="height: 10px;"></div>
<el-row>
@@ -134,14 +134,13 @@
</template>
<script setup lang="ts">
import { ElMessage, TabsPaneContext } from 'element-plus'
import { reactive, ref, h, onMounted, onUnmounted } from 'vue'
import { get_accounts, send_order, get_tick } from '../../api/capital'
import { strategyStore } from '../../store/strategy'
import { strategyStore } from '../../store/modules/strategy'
// -- IMPORT --
const store = strategyStore()
const useStrategyStore = strategyStore()
// -- INTERFACE OR TYPE DEFINITION --
interface AccountData {
@@ -272,7 +271,7 @@ const on_order = () => {
*/
(() => {
store.select_subscribe_vt_symbols()
useStrategyStore.select_subscribe_vt_symbols()
onMounted(() => {
clearInterval(timer.value)
timer.value = window.setInterval(on_query_accounts(), 3000);
@@ -0,0 +1,126 @@
<template>
<div class="dashboard-line-box">
<div class="dashboard-line-title">
访问趋势
</div>
<div ref="echart" class="dashboard-line" />
</div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts'
import { nextTick, onMounted, onUnmounted, ref, shallowRef } from 'vue'
// import 'echarts/theme/macarons'
var dataAxis: Array<string> = []
for (var i = 1; i < 13; i++) {
dataAxis.push(`${i}`)
}
var data = [
220,
182,
191,
234,
290,
330,
310,
123,
442,
321,
90,
149,
]
var yMax = 500
var dataShadow = []
// eslint-disable-next-line no-redeclare
for (var i = 0; i < data.length; i++) {
dataShadow.push(yMax)
}
const chart = shallowRef()
const echart = ref()
const initChart = () => {
chart.value = echarts.init(echart.value /* 'macarons' */)
setOptions()
}
const setOptions = () => {
chart.value.setOption({
grid: {
left: '40',
right: '20',
top: '40',
bottom: '20',
},
xAxis: {
data: dataAxis,
axisTick: {
show: false,
},
axisLine: {
show: false,
},
z: 10,
},
yAxis: {
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
color: '#999',
},
},
dataZoom: [
{
type: 'inside',
},
],
series: [
{
type: 'bar',
barWidth: '40%',
itemStyle: {
borderRadius: [5, 5, 0, 0],
color: '#188df0',
},
emphasis: {
itemStyle: {
color: '#188df0',
},
},
data: data,
},
],
})
}
onMounted(async () => {
await nextTick()
initChart()
})
onUnmounted(() => {
if (!chart.value) {
return
}
chart.value.dispose()
chart.value = null
})
</script>
<style lang="scss" scoped>
.dashboard-line-box {
.dashboard-line {
background-color: #fff;
height: 360px;
width: 100%;
}
.dashboard-line-title {
font-weight: 600;
margin-bottom: 12px;
}
}
</style>
+122
View File
@@ -0,0 +1,122 @@
<template>
<div class="commit-table">
<div class="commit-table-title">
更新日志
</div>
<div class="log">
<div v-for="(item, key) in dataTimeline" :key="key" class="log-item">
<div class="flex-1 flex key-box">
<span class="key" :class="key < 3 && 'top'">{{ key+ 1 }}</span>
</div>
<div class="flex-5 flex message">{{ item.message }}</div>
<div class="flex-3 flex form">{{ item.from }}</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { Commits } from '@/service/github'
import { formatTimeToStr } from '@/utils/date'
import { DataTimeline } from "@/entity/index";
const loading = ref(true)
const dataTimeline = reactive<DataTimeline[]>([])
const loadCommits = () => {
Commits(0).then(({ data }) => {
loading.value = false
data.forEach((element: any, index: any) => {
if (element.commit.message && index < 10) {
dataTimeline.push({
from: formatTimeToStr(element.commit.author.date, 'yyyy-MM-dd'),
title: element.commit.author.name,
showDayAndMonth: true,
message: element.commit.message,
})
}
})
})
}
loadCommits()
</script>
<style lang="scss" scoped>
.commit-table {
background-color: #fff;
height: 400px;
&-title {
font-weight: 600;
margin-bottom: 12px;
}
.log {
&-item {
display: flex;
justify-content: space-between;
margin-top: 14px;
.key-box {
justify-content: center;
}
.key {
&.top {
background: #314659;
color: #FFFFFF;
;
}
display: inline-flex;
justify-content: center;
align-items: center;
width: 20px;
height: 20px;
border-radius: 50%;
background: #F0F2F5;
text-align: center;
color:rgba($color: #000000, $alpha: 0.65)
}
.message {
color: rgba(0, 0, 0, 0.65);
}
.form {
color: rgba(0, 0, 0, 0.65);
margin-left: 12px;
}
.flex {
line-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flex-1 {
flex: 1;
}
.flex-2 {
flex: 2;
}
.flex-3 {
flex: 3;
}
.flex-4 {
flex: 4;
}
.flex-5 {
flex: 5;
}
}
}
}
</style>
+382 -5
View File
@@ -1,15 +1,392 @@
<template>
<div class="about" ref="bookmarks" id="bookmarks" :style="{
width: '600px',
height: '400px'
}"></div>
<div class="page">
<div class="gva-card-box">
<div class="gva-card gva-top-card">
<div class="gva-top-card-left">
<div class="gva-top-card-left-title">我的主人我们又见面了我有什么能帮助你么^_^</div>
<div class="gva-top-card-left-dot">{{ weatherInfo }}</div>
<div class="gva-top-card-left-rows">
<el-row>
<el-col :span="8" :xs="24" :sm="8">
<div class="flex-center">
<el-icon class="dashboard-icon">
<sort />
</el-icon>
wiki数量 ({{ statistics.wiki_count }})
</div>
</el-col>
<el-col :span="8" :xs="24" :sm="8">
<div class="flex-center">
<el-icon class="dashboard-icon">
<avatar />
</el-icon>
bookmark数量 ({{ statistics.bookmark_count }})
</div>
</el-col>
<!-- <el-col :span="8" :xs="24" :sm="8">
<div class="flex-center">
<el-icon class="dashboard-icon">
<comment />
</el-icon>
好评率 (99%)
</div>
</el-col> -->
</el-row>
</div>
<div class="gva-top-card-left-item">
<div>
{{ time }}
</div>
</div>
<div class="gva-top-card-left-item">
<div>
期货交易时间&nbsp
<el-icon color="yellow">
<Sunrise />
</el-icon>&nbsp 9:00-11:30 &nbsp
<el-icon color="gold">
<Sunny />
</el-icon>&nbsp 13:30-15:00 &nbsp
<el-icon color="blue">
<Moon />
</el-icon>&nbsp 21:00-23:00
</div>
</div>
</div>
<img src="../../assets/dashboard.png" class="gva-top-card-right">
</div>
</div>
<div class="gva-card-box">
<el-card class="gva-card quick-entrance">
<template #header>
<div class="card-header">
<span>快捷入口</span>
</div>
</template>
<el-row :gutter="20">
<el-col v-for="(card, key) in toolCards" :key="key" :span="4" :xs="8" class="quick-entrance-items"
@click="toTarget(card.name)">
<div class="quick-entrance-item">
<div class="quick-entrance-item-icon" :style="{ backgroundColor: card.bg }">
<el-icon>
<component :is="card.icon" :style="{ color: card.color }" />
</el-icon>
</div>
<p>{{ card.label }}</p>
</div>
</el-col>
</el-row>
</el-card>
<!-- <div class="quick-entrance-title"></div> -->
</div>
<div class="gva-card-box">
<div class="gva-card">
<div class="card-header">
<span>数据统计</span>
</div>
<div class="echart-box">
<el-row :gutter="20">
<el-col :xs="24" :sm="18">
<echarts-line />
</el-col>
<el-col :xs="24" :sm="6">
<dashboard-table />
</el-col>
</el-row>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import $moment from "moment"
import EchartsLine from '@/view/dashboard/dashboardCharts/index.vue'
import DashboardTable from '@/view/dashboard/dashboardTable/index.vue'
import { useRouter } from 'vue-router'
import { useWeatherInfo } from '@/service/weather'
import { countBlogs } from "@/api/blog"
import { bookmarks_count } from "@/api/bookmark"
// -- IMPORT --
const weatherInfo = useWeatherInfo()
const router = useRouter()
// -- REACTIVE OBJECT --
// -- REF OBJECT --
let time = ref<String>($moment().format("YYYY年MM月DD日 HH:mm:ss"));
const statistics = ref({
wiki_count: 0,
bookmark_count: 0,
})
const toolCards = ref([
{
label: 'Jenkins',
icon: 'camera',
name: 'Jenkins',
color: '#ff9c6e',
bg: 'rgba(255, 156, 110,.3)'
},
{
label: 'argo-cd',
icon: 'monitor',
name: 'argocd',
color: '#69c0ff',
bg: 'rgba(92, 219, 211,.3)'
},
{
label: 'wiki',
icon: 'document',
name: 'wiki',
color: '#b37feb',
bg: 'rgba(185, 192, 255,.3)'
},
{
label: '代码生成器',
icon: 'cpu',
name: 'autoCode',
color: '#ffd666',
bg: 'rgba(255, 214, 102,.3)'
},
{
label: '表单生成器',
icon: 'document-checked',
name: 'formCreate',
color: '#ff85c0',
bg: 'rgba(255, 133, 192,.3)'
},
{
label: '关于我们',
icon: 'user',
name: 'about',
color: '#5cdbd3',
bg: 'rgba(92, 219, 211,.3)'
}
])
// -- EVENT DEFINITION
const toTarget = (name: string) => {
// router.push({ name })
switch (name) {
case 'Jenkins':
window.open('https://www.violin-home.cn/jenkins/', '_blank')
break;
case 'argocd':
window.open('https://www.violin-home.cn/argo-cd/', '_blank')
break;
case 'wiki':
window.open('https://www.violin-home.cn/docs#/guan/', '_blank')
break;
}
}
/**
* AUTO INVOKE FUNCTION
*/
setInterval(() => {
time.value = $moment().format("YYYY年MM月DD日 HH:mm:ss")
}, 1000)
countBlogs().then((resp) => {
const data = resp.data
statistics.value.wiki_count = data.count
})
bookmarks_count().then((resp) => {
const data = resp.data
statistics.value.bookmark_count = data.count
})
</script>
<style>
<style lang="scss" scoped>
@mixin flex-center {
display: flex;
align-items: center;
}
.page {
background: #f0f2f5;
padding: 0;
.gva-card-box {
padding: 12px 16px;
&+.gva-card-box {
padding-top: 0px;
}
}
.gva-card {
box-sizing: border-box;
background-color: #fff;
border-radius: 2px;
height: auto;
padding: 26px 30px;
overflow: hidden;
box-shadow: 0 0 7px 1px rgba(0, 0, 0, 0.03);
}
.gva-top-card {
height: 260px;
@include flex-center;
justify-content: space-between;
color: #777;
&-left {
height: 100%;
display: flex;
flex-direction: column;
&-title {
font-size: 22px;
color: #343844;
}
&-dot {
font-size: 16px;
color: #6B7687;
margin-top: 24px;
}
&-rows {
// margin-top: 15px;
margin-top: 18px;
color: #6B7687;
width: 600px;
align-items: center;
}
&-item {
+.gva-top-card-left-item {
margin-top: 24px;
}
margin-top: 14px;
}
}
&-right {
height: 600px;
width: 600px;
margin-top: 28px;
}
}
::v-deep(.el-card__header) {
padding: 0;
border-bottom: none;
}
.card-header {
padding-bottom: 20px;
border-bottom: 1px solid #e8e8e8;
}
.quick-entrance-title {
height: 30px;
font-size: 22px;
color: #333;
width: 100%;
border-bottom: 1px solid #eee;
}
.quick-entrance-items {
@include flex-center;
justify-content: center;
text-align: center;
color: #333;
.quick-entrance-item {
padding: 16px 28px;
margin-top: -16px;
margin-bottom: -16px;
border-radius: 4px;
transition: all 0.2s;
&:hover {
box-shadow: 0px 0px 7px 0px rgba(217, 217, 217, 0.55);
}
cursor: pointer;
height: auto;
text-align: center;
// align-items: center;
&-icon {
width: 50px;
height: 50px !important;
border-radius: 8px;
@include flex-center;
justify-content: center;
margin: 0 auto;
i {
font-size: 24px;
}
}
p {
margin-top: 10px;
}
}
}
.echart-box {
padding: 14px;
}
}
.dashboard-icon {
font-size: 20px;
color: rgb(85, 160, 248);
width: 30px;
height: 30px;
margin-right: 10px;
@include flex-center;
}
.flex-center {
@include flex-center;
}
//小屏幕不显示右侧,将登录框居中
@media (max-width: 750px) {
.gva-card {
padding: 20px 10px !important;
.gva-top-card {
height: auto;
&-left {
&-title {
font-size: 20px !important;
}
&-rows {
margin-top: 15px;
align-items: center;
}
}
&-right {
display: none;
}
}
.gva-middle-card {
&-item {
line-height: 20px;
}
}
.dashboard-icon {
font-size: 18px;
}
}
}
</style>
+11 -10
View File
@@ -5,14 +5,14 @@
<el-row>
<el-col :span="4">
<el-select v-model="exchange" placeholder="select a exchange">
<el-option v-for="ex in store.exchanges" :value="ex" />
<el-option v-for="ex in useStrategyStore.strategy.exchanges" :value="ex" />
</el-select>
</el-col>
<el-col :span="1">
</el-col>
<el-col :span="4">
<el-select v-model="vt_symbol" placeholder="select a vt_symbol">
<el-option v-for="symbol in store.vt_symbols.get(exchange)" :value="symbol" />
<el-option v-for="symbol in useStrategyStore.strategy.vt_symbols.get(exchange)" :value="symbol" />
</el-select>
</el-col>
<el-col :span="1">
@@ -56,15 +56,16 @@
<script setup lang="ts">
import { ref, h, onMounted, onUnmounted, reactive, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { get_ticks, subscribe, concel_subscribe } from '../../api/capital'
import { strategyStore } from '../../store/strategy'
import * as echarts from 'echarts'
import { Contextmenu, ContextmenuItem } from "v-contextmenu"
import { get_ticks, subscribe, concel_subscribe } from '../../api/capital'
import { strategyStore } from '../../store/modules/strategy'
import { toPercent } from '../../utils/number'
import * as echarts from 'echarts'
// -- IMPORT --
const currentInstance = getCurrentInstance()
const store = strategyStore()
const useStrategyStore = strategyStore()
// -- INTERFACE OR TYPE DEFINITION --
interface TickData {
@@ -104,7 +105,7 @@ const on_subscribe = () => {
h('i', { style: 'color: green' }, "行情订阅成功"),
]),
})
store.select_subscribe_vt_symbols()
useStrategyStore.select_subscribe_vt_symbols()
on_ticks()
}).catch(error => {
ElMessage({
@@ -189,7 +190,7 @@ const on_ticks = () => {
window.clearInterval(timer.value)
})
store.select_subscribe_vt_symbols()
useStrategyStore.select_subscribe_vt_symbols()
.catch(error => {
ElMessage({
message: h('p', null, [
@@ -198,7 +199,7 @@ const on_ticks = () => {
})
})
store.select_vt_symbols()
useStrategyStore.select_vt_symbols()
.catch((error) => {
ElMessage({
message: h('p', null, [
@@ -207,7 +208,7 @@ const on_ticks = () => {
})
})
store.select_exchanges()
useStrategyStore.select_exchanges()
.catch((error) => {
ElMessage({
message: h('p', null, [
+26
View File
@@ -0,0 +1,26 @@
<template>
<el-button text @click="open">Click to open the Message Box</el-button>
</template>
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import type { Action } from 'element-plus'
const open = () => {
ElMessageBox.alert('This is a message', 'Title', {
// if you want to disable its autofocus
// autofocus: false,
confirmButtonText: 'OK',
callback: (action: Action) => {
ElMessage({
type: 'info',
message: `action: ${action}`,
})
},
})
}
</script>
<style>
</style>
-12
View File
@@ -1,12 +0,0 @@
<template>
<div class="dashboard">感悟这个东西暂时没有什么太多想法以后会被删掉把</div>
</template>
<script setup lang="ts">
</script>
<style>
.dashboard {
background-color: beige;
}
</style>
+5 -6
View File
@@ -61,8 +61,10 @@
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { onMounted, reactive, ref, h } from 'vue'
import { ElMessage } from 'element-plus'
import create_strategy_dialog from './dialog.vue'
import { strategyStore } from '../../store/modules/strategy'
import {
get_strategies,
init_strategy,
@@ -72,9 +74,6 @@ import {
get_strategy_status,
get_strategy_load_files,
} from '../../api/cta_strategy'
import { h } from 'vue'
import { ElMessage } from 'element-plus'
import { strategyStore } from '../../store/strategy'
type Strategy = {
strategy_name: string,
@@ -84,7 +83,7 @@ type Strategy = {
status: number,
}
const store = strategyStore()
const useStrategyStore = strategyStore()
let createStrategyDialogVisible = ref(false)
const strategy_list = reactive<Strategy[]>([])
const dialogRef = ref()
@@ -133,7 +132,7 @@ const on_status = (row: any) => {
onMounted(() => {
on_list()
get_strategy_load_files().then(res => {
store.$patch({ class_names: res.data.class_names })
useStrategyStore.strategy.class_names = res.data.class_names
}).catch(error => {
ElMessage({
message: h('p', null, [
+2 -5
View File
@@ -66,17 +66,14 @@
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { reactive, ref, h } from 'vue'
import { UploadInstance, UploadProps, UploadRawFile, genFileId, ElMessage, ElButton, ElIcon, ElTable, ElTableColumn, ElUpload } from 'element-plus'
import {
get_strategy_files,
load_strategy_file,
unload_strategy_file,
remove_strategy_file
} from '../../api/cta_strategy'
import { genFileId } from 'element-plus'
import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
import { h } from 'vue'
import { ElMessage } from 'element-plus'
// -- INTERFACE OR TYPE DEFINITION --
interface StrategyFile {
+4 -4
View File
@@ -7,12 +7,12 @@
</el-form-item>
<el-form-item label="vt_symbol" prop="vt_symbol">
<el-select v-model="ruleForm.vt_symbol" placeholder="select a vt_symbol">
<el-option v-for="vt_symbol in store.subscribe_vt_symbols" :value="vt_symbol" />
<el-option v-for="vt_symbol in useStrategyStore.strategy.subscribe_vt_symbols" :value="vt_symbol" />
</el-select>
</el-form-item>
<el-form-item label="class_name" prop="class_name">
<el-select v-model="ruleForm.class_name" placeholder="select a class_name">
<el-option v-for="name in store.class_names" :value="name" />
<el-option v-for="name in useStrategyStore.strategy.class_names" :value="name" />
</el-select>
</el-form-item>
<el-form-item label="setting:">
@@ -47,9 +47,9 @@ import type { FormInstance, FormRules } from 'element-plus'
import { create_strategy } from '../../api/cta_strategy'
import { h } from 'vue'
import { ElMessage } from 'element-plus'
import { strategyStore } from '../../store/strategy'
import { strategyStore } from '../../store/modules/strategy'
const store = strategyStore()
const useStrategyStore = strategyStore()
const formSize = ref('default')
const ruleFormRef = ref<FormInstance>()
+2 -3
View File
@@ -6,10 +6,9 @@
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { onMounted, ref, reactive } from 'vue'
import * as echarts from 'echarts'
import { EChartsOption } from 'echarts';
import { onMounted, ref } from 'vue'
import { EChartsOption } from 'echarts'
import { generateOHLC, option } from '../../service/trader'
import { get_stock_data } from '../../api/trader'
+6
View File
@@ -1,5 +1,11 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": [
"./src/*"
]
},
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
+21 -2
View File
@@ -1,7 +1,8 @@
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteCompression from 'vite-plugin-compression';
import viteCompression from 'vite-plugin-compression'
import { viteMockServe } from 'vite-plugin-mock'
import { resolve } from 'path'
// https://vitejs.cn/guide/env-and-mode.html#env-files
export default defineConfig(({ mode }) => {
@@ -16,6 +17,24 @@ export default defineConfig(({ mode }) => {
localEnabled: true,
}),
],
base: env.VITE_RES_URL
pluginOptions: {
'style-resources-loader': {
preProcessor: 'scss',
patterns: []
}
},
base: env.VITE_RES_URL,
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/style/mixin.scss";`
}
}
}
}
})