1142 lines
32 KiB
Vue
1142 lines
32 KiB
Vue
<script setup lang="ts">
|
||
import { nextTick, ref, computed } from 'vue'
|
||
import { Edit, Plus, Delete, View, Hide,Operation } from '@element-plus/icons-vue'
|
||
|
||
import { ElMessageBox, ElTable, ElMessage, ElLoading } from 'element-plus'
|
||
import type { CollapseModelValue } from 'element-plus'
|
||
import axios from 'axios'
|
||
|
||
import HomeView from './HomeView.vue'
|
||
const message = ref(''); // 用于存储要发送的消息
|
||
|
||
// --------------------后台数据--------------
|
||
/**
|
||
* 请求后端接口数据,侧边栏的信息,当前是获取指定用户的信息。与万策页面是关联的,用户登录过后,可在
|
||
* 万策页面进行保存筛选条件(保存的是一个请求参数),可在数据库的user_strategy表中查看。
|
||
* 通过https://wance.cqxqg.tech/api/v1/strategy/getStockPageList接口发送请求得到相关股票数据。
|
||
* 后端的逻辑处理可在src/akshare_data/router.py文件中查看。
|
||
* 由于user_strategy表中的信息仅仅是请求参数,对我在后续中对分组管理操作无法对接,所以我将请求返回来的数据进行存储在
|
||
* 新的一个数据库表中,名为new_user_strategy的数据库表中。
|
||
* 最后通过新的接口,得到股票数据,显示在侧边栏中。
|
||
* 下面代码的逻辑大致就是这样。
|
||
*/
|
||
axios({
|
||
url: 'http://127.0.0.1:8012/akshare/userstrategy',
|
||
method: 'get',
|
||
})
|
||
.then(async (res) => {
|
||
|
||
const loading = ElLoading.service({
|
||
lock: true,
|
||
text: 'Loading',
|
||
background: 'rgba(255, 255, 255, 0.7)',
|
||
})
|
||
|
||
|
||
let userstockinfo = res.data
|
||
let promises = []
|
||
|
||
for (let i = 0; i < userstockinfo.length; i++) {
|
||
const element = userstockinfo[i]
|
||
let postinfo = {
|
||
pageNo: element.strategy_request.pageNo,
|
||
pageSize: element.strategy_request.pageSize,
|
||
year: element.strategy_request.year,
|
||
indexType: element.strategy_request.indexType,
|
||
thsIndexCode: element.strategy_request.thsIndexCode,
|
||
}
|
||
|
||
// 创建一个Promise并将其添加到promises数组中
|
||
promises.push(
|
||
axios
|
||
.post(
|
||
'https://wance.cqxqg.tech/api/v1/strategy/getStockPageList',
|
||
postinfo,
|
||
{
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
}
|
||
)
|
||
.then((res) => {
|
||
// console.log(res.data.data.list)
|
||
let nowdata = res.data.data.list
|
||
|
||
let opt = []
|
||
for (let j = 0; j < nowdata.length; j++) {
|
||
let flag = Number(nowdata[j].pctChg) > 0 ? true : false
|
||
let prc2 = parseFloat(
|
||
(Number(nowdata[j].pctChg) / 100).toFixed(2)
|
||
)
|
||
opt.push({
|
||
code: nowdata[j].stockCode,
|
||
name: nowdata[j].stockName,
|
||
market: nowdata[j].industryName,
|
||
newprice: Number(nowdata[j].psPercentage),
|
||
amplitudetype: flag,
|
||
amplitude: prc2,
|
||
type: element.strategy_request.indexType
|
||
})
|
||
}
|
||
|
||
myitems.value.push({
|
||
id: '100096',
|
||
label: element.strategy_request.strategy_name,
|
||
value: element.strategy_request.strategy_name,
|
||
state: true,
|
||
info: opt,
|
||
inputClass: 'fixed',
|
||
fixchange: false,
|
||
})
|
||
|
||
// 存在自己的数据库表中
|
||
let newpostparam = {
|
||
id: 100096,
|
||
strategy_name: element.strategy_request.strategy_name,
|
||
message: myitems.value,
|
||
info: opt,
|
||
}
|
||
// console.log(newpostparam)
|
||
|
||
return axios.post(
|
||
'http://127.0.0.1:8012/akshare/newuserstrategy',
|
||
newpostparam
|
||
)
|
||
})
|
||
)
|
||
}
|
||
|
||
// 等待所有Promise完成
|
||
await Promise.all(promises)
|
||
|
||
// 所有异步操作完成后,执行最后的axios.get请求
|
||
axios.get('http://127.0.0.1:8012/akshare/newget').then((res) => {
|
||
console.log(res.data)
|
||
if (res.data.code == 200) {
|
||
loading.close()
|
||
ElMessage.success('数据获取成功')
|
||
items.value = res.data.data
|
||
addstocklog.value = res.data.data
|
||
}
|
||
|
||
|
||
})
|
||
})
|
||
.catch((err) => {
|
||
console.log(err)
|
||
})
|
||
|
||
const activeNames = ref(['0'])
|
||
|
||
const showChangeVisible = ref(true)
|
||
|
||
const handleTitleClick = async () => {
|
||
showChangeVisible.value = !showChangeVisible.value
|
||
}
|
||
|
||
const dialogVisible = ref(false)
|
||
const handleClose = (done: () => void) => {
|
||
ElMessageBox.confirm('当前操作会关闭对话框?', {
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
})
|
||
.then(() => {
|
||
done()
|
||
})
|
||
.catch(() => {})
|
||
}
|
||
|
||
// -------------------股票信息-------------------------------
|
||
/**
|
||
* 股票信息,通过axios请求后端接口,得到股票信息,并保存在stocktypes.value中。
|
||
* stocktypes.value是一个数组,数组中的每个元素都是一个对象,对象中包含股票的信息,
|
||
* 包括股票的id、label、value、state、info等属性。
|
||
* stocktypes.value是一个数组,数组中的每个元素都是一个对象,对象中包含股票的信息,
|
||
* 包括股票的id、label、value、state、info等属性。
|
||
*/
|
||
interface StockType {
|
||
id?: string
|
||
label: string
|
||
value: string
|
||
state: boolean
|
||
info: Equity[]
|
||
message?: { info: Equity[] }[]
|
||
}
|
||
|
||
let cacheinfo = ref<Equity[]>([])
|
||
|
||
/**
|
||
* 固定分类,始终有港股、美股、沪深等分类。
|
||
* stocktypes.value是一个数组,数组中的每个元素都是一个对象,对象中包含股票的信息,
|
||
* 包括股票的id、label、value、state、info等属性。
|
||
*/
|
||
let stocktypes = ref<StockType[]>([
|
||
{
|
||
id: '1',
|
||
label: '港股',
|
||
value: '港股',
|
||
state: true,
|
||
info: [],
|
||
},
|
||
{
|
||
id: '2',
|
||
label: '美股',
|
||
value: '美股',
|
||
state: true,
|
||
info: [],
|
||
},
|
||
{
|
||
id: '3',
|
||
label: '沪深',
|
||
value: '沪深',
|
||
state: true,
|
||
info: [],
|
||
}
|
||
])
|
||
|
||
const fetchData = async () => {
|
||
const urls = [
|
||
'http://127.0.0.1:8012/akshare/ganggudata',
|
||
'http://127.0.0.1:8012/akshare/meigudata',
|
||
'http://127.0.0.1:8012/akshare/hushendata'
|
||
];
|
||
|
||
try {
|
||
const responses = await Promise.all(urls.map(url => axios.get(url)));
|
||
responses.forEach((res, index) => {
|
||
stocktypes.value[index].info = res.data;
|
||
cacheinfo.value.push(res.data);
|
||
});
|
||
} catch (error) {
|
||
console.error('Error fetching data:', error);
|
||
}
|
||
};
|
||
|
||
fetchData();
|
||
|
||
|
||
|
||
|
||
// --------------------切换是否可见--------------------------
|
||
const changestate = (item: any) => {
|
||
item.state = !item.state
|
||
}
|
||
|
||
let asideshow = computed(() => {
|
||
return stocktypes.value.filter((item) => item.state)
|
||
})
|
||
|
||
// ---------------------新增股票测试数据---------------------------
|
||
interface Equity {
|
||
code: string
|
||
name: string
|
||
market: string
|
||
newprice: number
|
||
amplitudetype: boolean
|
||
amplitude: number
|
||
type?: string
|
||
}
|
||
|
||
// ---------------------往info数组里面加股票数据-------------------
|
||
const inputhandle = ref('')
|
||
const filterTableData = computed(() =>{
|
||
let newarr = cacheinfo.value.flat();
|
||
return newarr.filter(
|
||
(data) =>
|
||
!inputhandle.value ||
|
||
data.code.toLowerCase().includes(inputhandle.value.toLowerCase()) ||
|
||
data.name.includes(inputhandle.value)
|
||
);
|
||
})
|
||
// 添加新股票完成
|
||
const handleEdit = (index: number, row: Equity) => {
|
||
stocklog.value?.info.push(row)
|
||
// 添加后移除,也可以不移除
|
||
// tableData2.value = tableData2.value.filter((data) => data.code !== row.code)
|
||
let mes = myitems.value[index] || ''
|
||
// 存在自己的数据库表中
|
||
let newpostparam = {
|
||
id: 100096,
|
||
strategy_name: chosename.value,
|
||
message: [mes],
|
||
info: showdata.value,
|
||
}
|
||
axios.post('http://127.0.0.1:8012/akshare/newupdata', newpostparam)
|
||
}
|
||
|
||
// ---------------------------------新增分组测试数据----------------------------------
|
||
interface NewAddGroup extends StockType {
|
||
inputClass: string
|
||
fixchange: boolean
|
||
strategy_name?: string
|
||
}
|
||
const items = ref<NewAddGroup[]>([])
|
||
const myitems = ref<NewAddGroup[]>([])
|
||
// items.value = [
|
||
// {
|
||
// label: '川股',
|
||
// value: '川股',
|
||
// state: true,
|
||
// info: [],
|
||
// inputClass: 'fixed',
|
||
// fixchange: false,
|
||
// },
|
||
// ]
|
||
|
||
// ---------------------------------自定义分组修改-------------------------------------
|
||
const inputdemo = ref<(HTMLInputElement | null)[]>([])
|
||
// 保存之前的的值
|
||
let rename = ref('')
|
||
const changeEdit = async (item: any, index: number) => {
|
||
item.fixchange = true
|
||
rename.value = item.strategy_name
|
||
await nextTick()
|
||
// 如果切换到编辑状态,聚焦输入框
|
||
if (!item.fixchange) {
|
||
nextTick(() => {
|
||
const inputElement = inputdemo.value[index]
|
||
if (inputElement) {
|
||
inputElement.focus()
|
||
}
|
||
})
|
||
}
|
||
}
|
||
const changeDelete = (item: any, index: number) => {
|
||
ElMessageBox.confirm('当前操作会删除分组,是否继续?', {
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
})
|
||
.then(() => {
|
||
// 从 items 数组中删除对应项
|
||
items.value.splice(index, 1)
|
||
console.log(item.strategy_name)
|
||
|
||
let newpostparam = {
|
||
strategy_name: item.strategy_name,
|
||
}
|
||
|
||
// 删除分组完成
|
||
axios.post('http://127.0.0.1:8012/akshare/newdel', newpostparam)
|
||
})
|
||
.catch(() => {
|
||
console.log('这是取消操作按钮信息')
|
||
})
|
||
}
|
||
|
||
const handleFocus = (item: any, index: number) => {
|
||
// 切换当前元素的 fixchange 状态
|
||
// item.fixchange = true;
|
||
}
|
||
const handleBlur = (item: any, index: number) => {
|
||
console.log(item);
|
||
|
||
item.fixchange = false
|
||
if (rename.value != item.strategy_name) {
|
||
axios({
|
||
method: 'get',
|
||
url: 'http://127.0.0.1:8012/akshare/newmodify',
|
||
params: {
|
||
strategy_name: rename.value,
|
||
new_strategy_name: inputdemo.value[index]?.value,
|
||
},
|
||
}).then((res) => {
|
||
// console.log(res.data)
|
||
})
|
||
}
|
||
}
|
||
|
||
// ---------------------------------添加分组------------------------------
|
||
let addialog = ref(false)
|
||
let addinput = ref('')
|
||
const addialogT = async() => {
|
||
let regex = /^[^\s]{1,10}$/
|
||
if (!regex.test(addinput.value)) {
|
||
ElMessageBox.alert('分组名称不能为空或超过10个字符', '提示', {
|
||
confirmButtonText: '确定',
|
||
})
|
||
return
|
||
}
|
||
|
||
// 添加到数据库中
|
||
let newpostparam = {
|
||
id: 100096,
|
||
strategy_name: addinput.value,
|
||
message: [],
|
||
info: [],
|
||
}
|
||
let promises = []
|
||
promises.push(axios.post('http://127.0.0.1:8012/akshare/newadd', newpostparam).then(res => {
|
||
console.log(res.data);
|
||
if (res.data.code === 200){
|
||
ElMessage.success('新建分组成功')
|
||
items.value.push({
|
||
label: addinput.value,
|
||
value: addinput.value,
|
||
inputClass: 'fixed',
|
||
fixchange: false,
|
||
state: true,
|
||
info: [],
|
||
})
|
||
addinput.value = ''
|
||
addialog.value = false
|
||
}
|
||
if (res.data.code === 204){
|
||
ElMessage.error('该分组已存在')
|
||
}
|
||
|
||
}))
|
||
|
||
// 等待所有Promise完成
|
||
await Promise.all(promises)
|
||
|
||
|
||
|
||
// 所有异步操作完成后,执行最后的axios.get请求
|
||
axios.get('http://127.0.0.1:8012/akshare/newget').then((res) => {
|
||
// console.log(res.data)
|
||
if (res.data.code == 200) {
|
||
ElMessage.success('数据获取成功')
|
||
items.value = res.data.data
|
||
addstocklog.value = res.data.data
|
||
}
|
||
|
||
|
||
})
|
||
}
|
||
|
||
// --------------------------------------------------------------------
|
||
|
||
// --------------------------------操作列表的逻辑-----------------------------------
|
||
|
||
const delvisible = ref(false)
|
||
const clevisible = ref(false)
|
||
// 被选中的
|
||
let alreadySelected = ref<Equity[]>([])
|
||
// 选中checkbox
|
||
const handleselect = (val: Equity[]) => {
|
||
// 这里的val已经是一个记录被选中元素的数组,直接进行赋值即可
|
||
alreadySelected.value = val
|
||
}
|
||
// 删除已选元素的函数逻辑
|
||
const removeSelected = () => {
|
||
// 清空已选中元素的选中状态
|
||
alreadySelected.value.forEach((selectedItem) => {
|
||
const index = stocklog.value?.info.findIndex(
|
||
(item) =>
|
||
item.code === selectedItem.code &&
|
||
item.name === selectedItem.name &&
|
||
item.market === selectedItem.market
|
||
)
|
||
if (index !== undefined && index !== -1) {
|
||
stocklog.value?.info.splice(index, 1)
|
||
}
|
||
})
|
||
// 清空已选中元素数组
|
||
alreadySelected.value = []
|
||
}
|
||
|
||
const delmyselect = () => {
|
||
removeSelected()
|
||
|
||
delvisible.value = false
|
||
|
||
// 存在自己的数据库表中
|
||
let newpostparam = {
|
||
id: 100096,
|
||
strategy_name: chosename.value,
|
||
message: [
|
||
{
|
||
id: '100096',
|
||
label: chosename.value,
|
||
value: chosename.value,
|
||
state: true,
|
||
info: showdata.value,
|
||
inputClass: 'fixed',
|
||
fixchange: false,
|
||
},
|
||
],
|
||
info: showdata.value,
|
||
}
|
||
axios.post('http://127.0.0.1:8012/akshare/newupdata', newpostparam)
|
||
}
|
||
|
||
// 清空所有元素
|
||
const clearall = () => {
|
||
if (stocklog.value) {
|
||
stocklog.value.info = []
|
||
|
||
let newpostparam = {
|
||
id: 100096,
|
||
strategy_name: chosename.value,
|
||
message: [],
|
||
info: [],
|
||
}
|
||
axios.post('http://127.0.0.1:8012/akshare/newupdata', newpostparam)
|
||
} else {
|
||
console.warn('stocktypes 数组为空')
|
||
}
|
||
clevisible.value = false
|
||
}
|
||
// 当用户手动勾选全选 Checkbox 时触发的事件
|
||
const handleSelectionChange = (val: Equity[]) => {
|
||
// 这里的val已经是一个记录被选中元素的数组,直接精选复制即可
|
||
alreadySelected.value = val
|
||
}
|
||
// ----------------------------------------------------------------------------------
|
||
|
||
// --------------------------------自选分组切换的逻辑-----------------------------------
|
||
|
||
let stocklog = ref<StockType | null>(null)
|
||
let addstocklog = ref<any>(null)
|
||
|
||
// 将 stocktypes 的第一项数据赋值给 stocklog
|
||
if (stocktypes.value.length > 0) {
|
||
stocklog.value = stocktypes.value[0]
|
||
} else {
|
||
console.warn('stocktypes 数组为空,无法赋值给 stocklog')
|
||
}
|
||
|
||
// 判断选择的第几项,这里记录一下点击的是那一只分组
|
||
let chosename = ref<string>('港股')
|
||
|
||
const nowchose = (item: any) => {
|
||
stocklog.value = item
|
||
addstocklog.value = item
|
||
|
||
chosename.value = item.strategy_name
|
||
}
|
||
// 利用计算属性将股票数据展示出来
|
||
let showdata = computed(() => {
|
||
return stocklog.value?.info || []
|
||
})
|
||
|
||
// ---------------------------------------------------------------------------------
|
||
|
||
// -----------------------------侧边栏股票选择---------------------------------------
|
||
let kindofstock = ref()
|
||
const clickTypeState = (val: CollapseModelValue) => {
|
||
kindofstock.value = val
|
||
}
|
||
// 定义一个URL映射对象
|
||
const stockUrls = {
|
||
'港股': 'http://127.0.0.1:8012/akshare/ganggudataK',
|
||
'美股': 'http://127.0.0.1:8012/akshare/meigudataK',
|
||
'沪深': 'http://127.0.0.1:8012/akshare/hushendataK'
|
||
} as any;
|
||
|
||
// 定义一个通用的发送请求的函数
|
||
const fetchStockData = (url: string, symbol: string, startDate: string, endDate: string) => {
|
||
axios({
|
||
url: url,
|
||
method: 'get',
|
||
params: {
|
||
symbol: symbol,
|
||
start_date: startDate,
|
||
end_date: endDate
|
||
},
|
||
}).then((res) => {
|
||
console.log('数据传输成功');
|
||
}).catch(error => {
|
||
console.error('请求失败,请检查URL是否正确或稍后重试。', error);
|
||
});
|
||
};
|
||
|
||
const chioseStock = (item: any) => {
|
||
message.value = item.code; // 设置消息内容
|
||
const stockType = kindofstock.value;
|
||
const url = stockUrls[stockType];
|
||
|
||
if (url) {
|
||
fetchStockData(url, item.code, '2023-01-01', getDate());
|
||
} else {
|
||
console.error('未找到对应的股票类型');
|
||
}
|
||
};
|
||
// ---------------------------------------------
|
||
// -------------------------------更新日期-----------------------------------------
|
||
const getDate = () => {
|
||
const date = new Date();
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0'); // 补零
|
||
const day = String(date.getDate()).padStart(2, '0'); // 补零
|
||
let formattedDate = `${year}-${month}-${day}`;
|
||
return formattedDate
|
||
}
|
||
|
||
// 定义一个URL映射对象
|
||
const urls = {
|
||
hs300: 'http://127.0.0.1:8012/akshare/stock',
|
||
zz500: 'http://127.0.0.1:8012/akshare/stock',
|
||
sse: 'http://127.0.0.1:8012/akshare/stock',
|
||
szse: 'http://127.0.0.1:8012/akshare/stock',
|
||
zz1000: 'http://127.0.0.1:8012/akshare/stock',
|
||
gz2000: 'http://127.0.0.1:8012/akshare/stock',
|
||
ganggu: 'http://127.0.0.1:8012/akshare/ganggudataK',
|
||
meigu: 'http://127.0.0.1:8012/akshare/meigudataK',
|
||
hushen: 'http://127.0.0.1:8012/akshare/hushendataK'
|
||
} as any;
|
||
|
||
const sendmessage = (content: any, url: string) => {
|
||
axios({
|
||
url: url,
|
||
method: 'get',
|
||
params: {
|
||
symbol: content.type === 'ganggu' || content.type === 'meigu' || content.type === 'hushen' ? content.code : 'sz' + content.code,
|
||
start_date: '2023-01-01',
|
||
end_date: getDate()
|
||
},
|
||
}).then((res) => {
|
||
console.log('数据传输成功');
|
||
}).catch(error => {
|
||
console.error('请求失败,请检查URL是否正确或稍后重试。', error);
|
||
});
|
||
};
|
||
|
||
|
||
const showkline = (content: any) => {
|
||
message.value = content.code; // 设置消息内容
|
||
// console.log(content);
|
||
|
||
const url = urls[content.type] || urls['ganggu']; // 默认使用 'ganggu' URL
|
||
if (url) {
|
||
sendmessage(content, url);
|
||
} else {
|
||
console.error('未找到对应的URL类型');
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<div class="container">
|
||
<div class="box">
|
||
<div class="head">
|
||
<div class="item">名称</div>
|
||
<div class="item">最新价</div>
|
||
<div class="item">涨跌幅</div>
|
||
</div>
|
||
<div class="all">
|
||
<div class="showchange" @click="handleTitleClick">全部</div>
|
||
<div plain @click="dialogVisible = true">
|
||
<el-icon><Operation /></el-icon>
|
||
</div>
|
||
|
||
<el-dialog
|
||
v-model="dialogVisible"
|
||
:modal="false"
|
||
:mask="false"
|
||
title="分组管理"
|
||
:before-close="handleClose"
|
||
width="1000"
|
||
>
|
||
<hr />
|
||
<div class="onedialog">
|
||
<div class="oneconleft">
|
||
<div class="onecontitle">自选分组</div>
|
||
<div class="onestocks">
|
||
<div class="one-item-name">全部</div>
|
||
<div class="one-items">
|
||
<div
|
||
class="one-item"
|
||
v-for="item in stocktypes"
|
||
:key="item.value"
|
||
>
|
||
<div class="stock1" @click="nowchose(item)">
|
||
{{ item.value }}
|
||
</div>
|
||
<div v-if="item.state" @click="changestate(item)">
|
||
<el-icon><View /></el-icon>
|
||
</div>
|
||
<div v-if="!item.state" @click="changestate(item)">
|
||
<el-icon><Hide /></el-icon>
|
||
</div>
|
||
</div>
|
||
|
||
<div
|
||
v-for="(item, index) in items"
|
||
:key="index"
|
||
class="one-item"
|
||
>
|
||
<div class="stock2">
|
||
<input
|
||
:class="{
|
||
fixed: !item.fixchange,
|
||
isfixed: item.fixchange,
|
||
}"
|
||
type="text"
|
||
v-model="item.strategy_name"
|
||
@focus="handleFocus(item, index)"
|
||
@blur="handleBlur(item, index)"
|
||
@click="nowchose(item)"
|
||
:ref="(el) => (inputdemo[index] = el as HTMLInputElement)"
|
||
:readonly="!item.fixchange"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<el-icon><Edit @click="changeEdit(item, index)" /></el-icon>
|
||
<el-icon
|
||
><Delete @click="changeDelete(item, index)"
|
||
/></el-icon>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="oneadd">
|
||
<el-button type="primary" size="small" @click="addialog = true">
|
||
<el-icon><Plus /></el-icon>添加分组
|
||
</el-button>
|
||
|
||
<el-dialog v-model="addialog" title="添加分组" width="300">
|
||
<div class="addtext">
|
||
<div>请输入自选股分组名称</div>
|
||
<el-input
|
||
v-model="addinput"
|
||
placeholder="最多10个字"
|
||
></el-input>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button type="primary" @click="addialogT()"
|
||
>确认</el-button
|
||
>
|
||
<el-button @click="addialog = false">取消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="oneconcenter">
|
||
<div class="onecontitle">股票列表详情</div>
|
||
<div class="onetable">
|
||
<el-table
|
||
border
|
||
:data="showdata"
|
||
style="width: 100%; font-size: 12px;height: 350px;"
|
||
@select-all="handleSelectionChange"
|
||
@select="handleselect"
|
||
>
|
||
<el-table-column type="selection" />
|
||
<el-table-column property="code" label="代码" />
|
||
<el-table-column property="name" label="名称" />
|
||
<el-table-column property="type" label="市场" />
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="oneconright">
|
||
<div class="onecontitle">加入股票</div>
|
||
<div class="add">
|
||
<el-input
|
||
v-model="inputhandle"
|
||
size="small"
|
||
placeholder="代码/名称"
|
||
/>
|
||
<el-table
|
||
v-if="inputhandle"
|
||
:data="filterTableData"
|
||
style="width: 100%; height: 160px; font-size: 12px"
|
||
>
|
||
<el-table-column label="代码" prop="code" />
|
||
<el-table-column label="名称" prop="name" />
|
||
<el-table-column>
|
||
<template #header> 操作 </template>
|
||
<template #default="scope">
|
||
<el-button
|
||
size="small"
|
||
@click="handleEdit(scope.$index, scope.row)"
|
||
>
|
||
加入
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div class="listedit">
|
||
<div>列表操作</div>
|
||
<div>
|
||
<el-popover :visible="delvisible" placement="top" :width="160">
|
||
<p>是否删除已选中?</p>
|
||
<div style="text-align: right; margin: 0">
|
||
<el-button size="small" text @click="delvisible = false"
|
||
>否</el-button
|
||
>
|
||
<el-button
|
||
size="small"
|
||
type="primary"
|
||
@click="delmyselect()"
|
||
>是</el-button
|
||
>
|
||
</div>
|
||
<template #reference>
|
||
<el-button
|
||
type="primary"
|
||
plain
|
||
size="small"
|
||
@click="delvisible = true"
|
||
>删除</el-button
|
||
>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
<div>
|
||
<el-popover :visible="clevisible" placement="top" :width="160">
|
||
<p>是否全部清空?</p>
|
||
<div style="text-align: right; margin: 0">
|
||
<el-button size="small" text @click="clevisible = false"
|
||
>否</el-button
|
||
>
|
||
<el-button size="small" type="primary" @click="clearall()"
|
||
>是</el-button
|
||
>
|
||
</div>
|
||
<template #reference>
|
||
<el-button
|
||
type="primary"
|
||
plain
|
||
size="small"
|
||
@click="clevisible = true"
|
||
>清空</el-button
|
||
>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<!-- <el-button @click="dialogVisible = false">取消</el-button> -->
|
||
<el-button type="primary" @click="dialogVisible = false"
|
||
>关闭</el-button
|
||
>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
|
||
<div class="demo-collapse" :style="{ display: showChangeVisible ? 'block' : 'none' }">
|
||
<el-collapse v-model="activeNames" accordion @change="clickTypeState">
|
||
|
||
<el-collapse-item
|
||
:title="item.value"
|
||
:name="item.label"
|
||
v-for="(item, index) in asideshow"
|
||
:key="item.label"
|
||
|
||
>
|
||
<div class="stock" v-for="content in item.info" :key="content.name" @click="chioseStock(content)">
|
||
<div class="stockname" :title="content.name">{{ content.name }}</div>
|
||
<div :class="{upcolor: content.amplitudetype,downcolor: !content.amplitudetype}" :title="kindofstock">
|
||
{{ content.newprice }}
|
||
</div>
|
||
<div :class="{stockchangeup: content.amplitudetype,stockchangedown: !content.amplitudetype}">
|
||
{{
|
||
content.amplitudetype ? '+' + content.amplitude : content.amplitude
|
||
}}
|
||
</div>
|
||
</div>
|
||
</el-collapse-item>
|
||
|
||
|
||
<el-collapse-item
|
||
:title="item.strategy_name"
|
||
:name="item.strategy_name"
|
||
v-for="(item, index) in items"
|
||
:key="item.label"
|
||
>
|
||
<div
|
||
class="stock"
|
||
v-for="content in item.info"
|
||
:key="content.name"
|
||
@click="showkline(content)"
|
||
>
|
||
<div class="stockname" :title="content.name">
|
||
{{ content.name }}
|
||
</div>
|
||
<div
|
||
:class="{
|
||
upcolor: content.amplitudetype,
|
||
downcolor: !content.amplitudetype,
|
||
}"
|
||
>
|
||
{{ content.newprice }}
|
||
</div>
|
||
<div
|
||
:class="{
|
||
stockchangeup: content.amplitudetype,
|
||
stockchangedown: !content.amplitudetype,
|
||
}"
|
||
>
|
||
{{
|
||
content.amplitudetype
|
||
? '+' + content.amplitude
|
||
: content.amplitude
|
||
}}
|
||
</div>
|
||
</div>
|
||
</el-collapse-item>
|
||
|
||
</el-collapse>
|
||
</div>
|
||
</div>
|
||
<div class="shape">
|
||
<HomeView :message="message"/>
|
||
</div>
|
||
</div>
|
||
|
||
</template>
|
||
|
||
<style scoped>
|
||
.container{
|
||
width: 100vw;
|
||
height: 100vh;
|
||
display: flex;
|
||
}
|
||
.box {
|
||
width: 300px;
|
||
/* flex: 3; */
|
||
height: 100vh;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
box-sizing: border-box;
|
||
background-color: var(--my-common-bgc-2);
|
||
position: relative;
|
||
border-right: 1px solid var(--my-light-br-1);
|
||
border-left: 1px solid var(--my-light-br-1);
|
||
|
||
}
|
||
.shape{
|
||
flex: 1;
|
||
height: 100vh;
|
||
}
|
||
iframe{
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.head {
|
||
/* width: 300px; */
|
||
background-color: var(--my-common-bgc-2);
|
||
color: var(--my-common-bgc-1);
|
||
display: flex;
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
padding:2px 0 0 12px;
|
||
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 999;
|
||
}
|
||
.item {
|
||
font-size: 13px;
|
||
width: 52px;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
}
|
||
.all {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 13px;
|
||
padding: 10px 12px;
|
||
box-sizing: border-box;
|
||
position: sticky;
|
||
top: 17px;
|
||
z-index: 99;
|
||
color: var(--my-common-bgc-1);
|
||
background-color: var(--my-common-bgc-2);
|
||
}
|
||
.showchange {
|
||
flex: 1;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.onedialog {
|
||
display: flex;
|
||
height: 376px;
|
||
padding: 10px;
|
||
overflow: auto;
|
||
}
|
||
.onecontitle {
|
||
font-size: 13px;
|
||
font-weight: 550;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 999;
|
||
background-color: #fff;
|
||
}
|
||
.onestocks {
|
||
margin-top: 10px;
|
||
font-size: 12px;
|
||
background-color: #ececec;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
}
|
||
.oneadd {
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 10px 0;
|
||
}
|
||
.one-item-name {
|
||
padding: 5px 10px;
|
||
background-color: #e7ebf3;
|
||
}
|
||
.one-item {
|
||
padding: 5px 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.one-items{
|
||
height: 277px;
|
||
overflow: auto;
|
||
}
|
||
.oneconleft {
|
||
flex: 2;
|
||
min-width: 158px;
|
||
box-sizing: border-box;
|
||
padding-right: 10px;
|
||
height: 376px;
|
||
overflow: auto;
|
||
position: relative;
|
||
}
|
||
.oneconcenter {
|
||
flex: 3;
|
||
max-width: 320px;
|
||
padding: 0 10px;
|
||
border-left: 2px solid #ececec;
|
||
box-sizing: border-box;
|
||
height: 376px;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
.onetable {
|
||
font-size: 12px;
|
||
/* border: 1px solid red; */
|
||
margin-top: 10px;
|
||
box-sizing: border-box;
|
||
}
|
||
.oneconright {
|
||
flex: 2;
|
||
box-sizing: border-box;
|
||
padding-left: 10px;
|
||
position: relative;
|
||
}
|
||
|
||
.add {
|
||
margin-top: 10px;
|
||
width: 100%;
|
||
max-width: 300px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.addtext {
|
||
padding: 10px 20px;
|
||
}
|
||
.addtext > div {
|
||
margin-bottom: 20px;
|
||
}
|
||
.listedit {
|
||
font-size: 13px;
|
||
font-weight: 550;
|
||
margin-top: 10px;
|
||
}
|
||
.listedit > div {
|
||
margin-bottom: 10px;
|
||
}
|
||
.stock {
|
||
flex: 1;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
margin-bottom: 5px;
|
||
cursor: pointer;
|
||
|
||
}
|
||
:deep(.el-collapse-item__header){
|
||
background-color: var(--my-common-bgc-2) !important;
|
||
color: var(--my-common-bgc-1);
|
||
padding-left: 12px;
|
||
}
|
||
|
||
.stock1 {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 5px;
|
||
cursor: pointer;
|
||
}
|
||
.stock2 {
|
||
flex: 1;
|
||
display: flex;
|
||
justify-content: left;
|
||
align-items: center;
|
||
margin-bottom: 5px;
|
||
cursor: pointer;
|
||
}
|
||
.stockname {
|
||
width: 52px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.upcolor {
|
||
color: rgb(204, 42, 42);
|
||
}
|
||
.stockchangeup {
|
||
color: rgb(204, 42, 42);
|
||
background-color: rgba(255, 0, 0, 0.12);
|
||
border-radius: 4px;
|
||
width: 50px;
|
||
text-align: center;
|
||
}
|
||
.downcolor {
|
||
color: rgb(80, 165, 72);
|
||
}
|
||
.stockchangedown {
|
||
color: rgb(80, 165, 72);
|
||
background-color: rgba(60, 255, 0, 0.12);
|
||
border-radius: 4px;
|
||
width: 50px;
|
||
text-align: center;
|
||
/* padding: 2px; */
|
||
}
|
||
:deep(.el-collapse-item__content) {
|
||
padding-bottom: 0;
|
||
max-height: 250px;
|
||
overflow-y: auto;
|
||
background-color: var(--my-common-bgc-2) !important;
|
||
color: var(--my-common-fc-1);
|
||
}
|
||
:deep(.el-collapse-item__content)::-webkit-scrollbar {
|
||
width: 0 !important;
|
||
}
|
||
|
||
|
||
|
||
:deep(.demo-collapse) {
|
||
padding-left: 0;
|
||
}
|
||
|
||
.fixed {
|
||
outline: none;
|
||
border: none;
|
||
background-color: transparent;
|
||
font-size: 12px;
|
||
color: rgb(88, 87, 87);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.isfixed {
|
||
border: none;
|
||
outline: 1px solid rgb(131, 200, 218);
|
||
font-size: 12px;
|
||
}
|
||
/* 设置滚动条的样式 */
|
||
::-webkit-scrollbar {
|
||
width: 0;
|
||
}
|
||
|
||
</style>
|