父组件表格页面代码:
<template>
<div class="wrapper">
<div class="overview-box">
<div class="box-name">
<div class="flag" />
标的事件
</div>
<p class="con-txt">
{{ similarEventDate
}}{{ queryInfo.symbol }}{{ queryInfo.shortname
}}{{ queryInfo.eventtypename }}{{ pilesNum }}万股
</p>
</div>
<div class="box-name">
<div class="flag" />
事件表格
</div>
<Table
:heads="columns"
:data="tableData"
:maxheight="500"
:haspage="false"
class="table-item"
@sortChange="sortChange"
@goToSimilarDetail="goToSimilarDetail"
/>
</div>
</template>
<script>
import Table from '@/components/TableDynamic/index.vue' // 引入table组件
import {
querySimilarEventData
} from '@/api/queryEvent' // 后端接口
import { mapState } from 'vuex'
export default {
name: 'EventDeatil',
components: {
Table
},
data() {
return {
queryInfo: {},
code: '', // 代码
eventType: '', // 事件类型
eventDate: '', // 事件时间
similarEventDate: '', // 事件时间
pilesNum: '', // 股数
detailInfo: {}, // 明细概述信息
columns: [
{
label: '事件名称',
width: 160,
sortable: true,
prop: 'eventname'
},
{
label: '代码',
width: 93,
sortable: true,
prop: 'symbol'
},
{
label: '事后1日涨跌幅',
type: 'percent',
sortable: true,
prop: 'onedayratio'
},
{
label: '事后3日涨跌幅',
sortable: true,
type: 'percent',
prop: 'threedayratio'
},
{
label: '事后5日涨跌幅',
sortable: true,
type: 'percent',
prop: 'fivedayratio'
},
{
label: '事件偏向',
sortable: true,
prop: 'eventbias',
type: 'deviation'
},
{
label: '相似度',
sortable: true,
prop: 'similarvalue'
}
],
tableData: [],
sortBackupData: []
}
},
computed: {
...mapState({
eventDisplayInfo: (state) => state.event.eventDisplayInfo
})
},
watch: {
eventDisplayInfo: {
handler(newObj) {
this.code = newObj.symbol || ''
this.eventType = newObj.eventtype || ''
this.eventDate = newObj.eventdate || ''
this.queryInfo = newObj || {}
this.getSimilarEventData()
},
deep: true
}
},
created() {},
mounted() {
// 页面路径所传参数
this.code = this.$route.query.symbol || ''
this.eventType = this.$route.query.eventtype || ''
this.eventDate = this.$route.query.eventdate || ''
this.queryInfo = this.$route.query || {}
this.similarEventDate = this.getDate(this.$route.query.eventdate.split(' ')[0])
this.getSimilarEventData() // 获取表格数据
},
methods: {
// 获取表格数据
getSimilarEventData() {
const date = this.eventDate.split(' ')[0]
if (!date) {
this.tableData = []
return
}
const params = {
symbol: this.code,
eventdate: date,
size: 10
}
querySimilarEventData(params).then((res) => {
const data = res.similarItems || []
const arr = []
this.pilesNum = res.Listedshares
data.forEach(el => {
el.similarvalue = this.toDecimal(this.numMul(el.similarvalue, 100)) + '%'
arr.push(el)
})
this.tableData = arr
Object.assign(this, {
tableData: this.tableData,
sortBackupData: this.tableData
})
sessionStorage.setItem('tableData', JSON.stringify(this.tableData))
})
},
// 格式化日期
getDate(date) {
const date1 = new Date(date)
// 获取年份、月份和日期
const year = date1.getFullYear()
const month = date1.getMonth() + 1 // 注意月份从0开始计数,所以需要加上1得到真正的月份(12)
const day = date1.getDate()
return `${year}年${month}月${day}日`
},
// 排序
sortChange({ column, prop, order }) {
if (column.sortable === 'custom') {
if (order) {
const { tableData } = this
this.tableData = this.customSortBuyProp(order, tableData, prop)
} else {
this.tableData = this.sortBackupData
}
}
},
/**
* 根据选定prop排序(无效值排最后)
* @param {String} order 排序顺序ascending/descending
* @param {Array} data 数据
* @param {String} prop 排序属性
* @param {Array} invalidList 无效值定义
*/
customSortBuyProp(order, data, prop, invalidList) {
if (!order) {
return data
}
invalidList = invalidList || [null, undefined, '', '/']
const isAsc = order === 'ascending'
const effectiveArr = [] // 参与排序的数据
const invalidArr = [] // 不参与排序的数据
data.forEach((item) => {
const value = item[prop]
if (invalidList.includes(value)) {
invalidArr.push(item)
} else {
effectiveArr.unshift(item)
}
})
effectiveArr.sort((a, b) => {
const aValue = a[prop]
const bValue = b[prop]
if (aValue > bValue) {
return isAsc ? 1 : -1
} else if (aValue < bValue) {
return isAsc ? -1 : 1
} else {
return 0
}
})
return effectiveArr.concat(invalidArr)
},
// 跳转详情页面
goToSimilarDetail(row) {
let arr = []
arr = [
{ event_date: this.eventDate.substring(0, 10),
event_type: Number(this.eventType),
shortname: this.queryInfo.shortname,
symbol: this.code },
{ event_date: row.eventdate.substring(0, 10),
event_type: row.eventtype,
shortname: row.shortname,
symbol: row.symbol }
]
sessionStorage.setItem('similarParams', JSON.stringify(arr))
const routeUrl = this.$router.resolve({
path: '/similarDetail/index',
query: row
})
window.open(routeUrl.href, '_blank')
}
}
}
</script>
<style lang="scss">
.baseDataPopper {
.content-box {
max-width: 500px;
max-height: 400px;
overflow-y: auto;
white-space: pre-line;
}
}
</style>
<style lang="scss" scoped>
.wrapper {
padding: 0 16px 20px;
background: #ffffff;
box-sizing: border-box;
-webkit-box-sizing: border-box;
.table-item {
padding: 0;
/deep/.table-box {
padding: 0;
}
}
.overview-box {
margin-bottom: 16px;
border: 1px solid #e6e6e6;
border-top: none;
.con-txt {
padding: 0px 17px 10px;
margin: 0;
line-height: 24px;
font-size: 14px;
color: #666666;
.spec {
font-weight: bold;
color: #f33030;
cursor: pointer;
border-bottom: 1px dashed #f33030;
&:hover {
color: #1e81ff;
border-bottom: 1px dashed #1e81ff;
}
}
}
}
.box-name {
padding: 0 16px;
display: flex;
align-items: center;
height: 44px;
font-size: 14px;
font-weight: bold;
color: #333333;
box-sizing: border-box;
-webkit-box-sizing: border-box;
.flag {
margin-right: 8px;
width: 5px;
height: 14px;
background: #1e81ff;
border-radius: 0px 2px 2px 0px;
}
}
.item-title {
margin: 26px 0 16px;
padding-left: 14px;
height: 28px;
line-height: 28px;
font-size: 14px;
font-weight: 600;
color: #333333;
background: url("~@/assets/images/title_bg.png") no-repeat;
background-size: 130px 100%;
position: relative;
&::before {
position: absolute;
content: "";
top: 5px;
left: 0;
width: 3px;
height: 18px;
background: #1e81ff;
}
}
.pagin-box {
margin-top: 20px;
padding-top: 20px;
text-align: center;
position: relative;
&::before {
position: absolute;
content: "";
top: 0;
left: -16px;
right: -16px;
height: 1px;
background: #eeeff1;
}
}
/deep/.pub-pagin-box {
.el-pagination.is-background .btn-next,
.el-pagination.is-background .btn-prev,
.el-pagination.is-background .el-pager li {
font-size: 12px;
font-weight: normal;
color: #666666;
background: #f6f6f6;
border-radius: 3px;
}
.el-pagination.is-background .el-pager li:not(.disabled).active {
color: #ffffff;
background-color: #1e81ff;
}
.el-pagination.is-background .btn-next.disabled,
.el-pagination.is-background .btn-next:disabled,
.el-pagination.is-background .btn-prev.disabled,
.el-pagination.is-background .btn-prev:disabled,
.el-pagination.is-background .el-pager li.disabled {
color: #c0c4cc;
}
.el-pagination__jump,
.el-input__inner {
font-size: 12px;
color: #666666;
}
}
.chart-area {
margin-top: 26px;
padding: 10px 0;
width: 100%;
height: 380px;
background: #ffffff;
border: 1px solid #e6e6e6;
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
/deep/.detail-dialog {
.el-dialog__header {
padding-top: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #f3f3f3;
}
.title-box {
font-size: 16px;
position: relative;
.iconfont {
position: absolute;
right: 0;
cursor: pointer;
}
}
.el-dialog__body {
max-height: 350px;
min-height: 200px;
overflow-y: auto;
}
.content-box {
display: flex;
flex-wrap: wrap;
.item {
margin-bottom: 20px;
display: flex;
flex-shrink: 0;
width: 50%;
padding-right: 10px;
box-sizing: border-box;
&:nth-of-type(2n) {
padding-right: 0;
padding-left: 10px;
}
.name {
width: 120px;
font-weight: bold;
}
.con {
margin-left: 10px;
flex: 1;
}
}
}
}
}
</style>
table组件代码:
<template>
<!-- table-wrapper 具体页面可能也用了该类名控制表格特殊样式 -->
<div :class="'table-wrapper ' + headbg">
<div class="table-box">
<el-table
ref="table"
:data="data"
:height="height === 0 ? undefined : height"
:max-height="maxheight === 0 ? undefined : maxheight"
:highlight-current-row="highlightCurrentRow"
:empty-text="emptyText"
:span-method="spanMethod"
:size="size"
:row-class-name="rowclassname"
:tree-props="treeProps"
:row-key="rowKey"
:row-style="size == 'small' ? { height: '30px' } : {}"
:cell-style="size == 'small' ? { padding: '0px' } : {}"
:stripe="stripe"
style="width: 100%"
tooltip-effect="dark"
border
@cell-dblclick="cellDblclick"
@row-click="rowClick"
@current-change="handleRowChange"
@selection-change="handleSelectionChange"
@sort-change="sortChange"
>
<el-table-column
v-if="hasselection"
:reserve-selection="reserveSelection"
type="selection"
header-align="center"
align="center"
width="40"
/>
<el-table-column
v-if="hasindex && data.length > 0"
:index="indexMethod"
label="序号"
type="index"
header-align="center"
align="center"
class-name="rw-table-index"
width="80"
/>
<el-table-column
v-for="h in heads"
:key="'col' + h.prop"
:prop="h.prop"
:fixed="h.hasFixed"
:align="h.align ? h.align : 'center'"
:header-align="h.hAlign ? h.hAlign : 'center'"
:min-width="h.minWidth ? h.minWidth : '128'"
:width="h.width ? h.width: 'auto'"
:sortable="h.sortable ? 'custom' : false"
:label-class-name="h.hasWrap ? 'hasWrap' : ''"
>
<template #header>
<el-tooltip
:content="h.label"
overflow
effect="dark"
placement="top-start"
>
<div class="dialog-box-title">
{{ h.label }}
</div>
</el-tooltip>
<div v-if="h.label === '相似度'">
<span
style="margin-right:8px;"
/>
<el-popover
placement="top-start"
width="250"
trigger="hover"
content="针对付费订单,使用截止时间来源于合同,可能和最终实施的使用截止日期存在差异。"
>
<i
slot="reference"
class="tips-icon el-icon-question"
/>
</el-popover>
</div>
</template>
<template slot-scope="scope">
<div
v-if="h.type === 'starIcon'"
class="star-icon-box">
<i
v-for="(item, i) in 5"
:key="'icon' + i"
:style="{
color: scope.row[h.prop] > i ? '#F7BA2A' : '#DAE0E7',
}"
:class="
scope.row[h.prop] > i
? 'iconxingxing-tianchong'
: 'iconxingxing'
"
class="iconfont star-icon"
/>
</div>
<template v-else-if="h.type === 'largeText'">
<el-tooltip
popper-class="baseDataPopper"
effect="dark"
placement="bottom-start">
<div :style="scope.row[h.prop + 'Style']">{{ scope.row[h.prop] }}</div>
<template slot="content">
<div class="content-box">{{ scope.row[h.prop] }}</div>
</template>
</el-tooltip>
</template>
<template v-else-if="h.prop === 'similarvalue'">
<div
class="similarText"
@click="goToSimilarDetail(scope.row)">{{ scope.row[h.prop] }}</div>
</template>
<template v-else-if="h.type === 'date'">
<div >{{ formatDate(new Date(scope.row[h.prop])) }}</div>
</template>
<div
v-else
:class="h.type == 'price' || h.type == 'percent'
? (scope.row[h.prop] == 0 || scope.row[h.prop] == null)
? 'zero'
: scope.row[h.prop] > 0
? 'up'
: 'down'
: ''
"
:style="scope.row[h.prop + 'Style']"
>
{{
scope.row[h.prop] === "" ? '' : (h.type == "price"
? toDecimal(scope.row[h.prop], 4)
: h.type == "percent"
? ( scope.row[h.prop] ? toDecimal(numMul(scope.row[h.prop], 100)) + '%' : '-')
: h.type == "date"
? scope.row[h.prop].split(' ')[0].replace(/\-/g, "")
: h.type == "deviation"? eventBiasClick(scope.row[h.prop]): scope.row[h.prop])
}}
</div>
</template>
</el-table-column>
<slot />
<div slot="empty">暂无数据</div>
</el-table>
</div>
<div
v-if="haspage"
class="table-pagination">
<el-pagination
:total="total"
:current-page="pageindex"
:page-size="pagesize"
background
layout="prev, pager, next, jumper"
@current-change="pageChange"
@size-change="pageSizeChange"
/>
</div>
</div>
</template>
<script>
import { eventBiasHandle } from '@/utils/business'
import common from '@/utils/common'
export default {
name: 'CsTable',
props: {
heads: {
type: Array,
required: true
},
// 表格的数据
data: {
type: Array,
required: true
},
stripe: {
type: Boolean,
default: true
},
rowKey: {
type: String,
default: ''
},
emptydata: {
type: String,
default: ''
},
height: {
type: [Number, String],
default: 0
},
maxheight: {
type: [Number, String],
default: 0
},
total: {
type: Number,
default: 0
},
url: {
type: String,
default: ''
},
pagesize: {
type: Number,
default: 0
},
pageindex: {
type: Number,
default: 1
},
hasindex: {
type: Boolean,
default: false
},
hasselection: {
type: Boolean,
default: false
},
reserveSelection: {
type: Boolean,
default: false
},
haspage: {
type: Boolean,
default: true
},
highlightCurrentRow: {
// 是否有点击选中效果
type: Boolean,
default: false
},
size: {
type: String,
default: 'medium'
},
headbg: {
type: String,
default: ''
},
spanMethod: {
type: Function,
default: function({ row, column, rowIndex, columnIndex }) {}
},
// eslint-disable-next-line vue/require-default-prop
rowclassname: [String, Function],
treeProps: {
type: Object,
default: () => {
return { children: 'children', hasChildren: 'hasChildren' }
}
}
},
data() {
return {
emptyText: '暂无数据'
}
},
mounted() {
if (this.emptydata !== '') {
this.emptyText = this.emptydata
}
},
methods: {
goToSimilarDetail(row) {
this.$emit('goToSimilarDetail', row)
},
eventBiasClick(val) {
return eventBiasHandle(val)
},
pageChange(val) {
this.$emit('pageChange', this.pagesize, val)
},
pageSizeChange(val) {
if (val * (this.pageindex - 1) <= this.total) {
this.$emit('pageChange', val, this.pageindex)
} else {
this.$emit('pageChange', val, 1)
}
},
sortChange(column, prop, order) {
this.$emit('sortChange', column)
},
indexMethod(index) {
return this.pagesize * (this.pageindex - 1) + index + 1
},
handleSelectionChange(val) {
this.$emit('selection-change', val)
},
cellDblclick(row, column, cell, event) {
this.$emit('cell-dblclick', row, column, cell, event)
},
rowClick(row, column, event) {
this.$emit('rowClick', row, column, event)
},
clearSelection() {
this.$refs.table.clearSelection()
},
toggleAllSelection() {
this.$refs.table.toggleAllSelection()
},
toggleRowSelection(row) {
this.$refs.table.toggleRowSelection(row)
},
handleRowChange(row) {
if (this.highlightCurrentRow) {
this.$emit('handleCurRow', row)
}
},
doLayout() {
this.$refs.table.doLayout()
},
formatDate(date, format = 'YYYY-MM-dd') {
return common.formatDate(date, format)
}
}
}
</script>
<style lang="scss">
.baseDataPopper {
.content-box {
max-width: 500px;
max-height: 400px;
overflow-y: auto;
white-space: pre-line;
}
}
</style>
<style scoped lang="scss">
.el-icon-question {
color: #1e81ff;
margin-right: 8px;
}
.similarText {
text-decoration: underline;
color: #1e81ff;
cursor: pointer;
}
.table-wrapper {
padding: 17px 0 20px;
.table-box {
padding: 0 16px;
}
}
.el-table {
/deep/thead {
tr,
th {
padding-top: 0;
padding-bottom: 0;
font-size: 14px;
color: #333333;
font-weight: normal;
background: #fcfcfc;
}
th {
.cell {
display: flex;
justify-content: center;
align-items: center;
line-height: 16px;
white-space: pre;
.dialog-box-title{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.hasWrap {
display: flex;
justify-content: center;
}
}
.caret-wrapper {
width: 14px;
.sort-caret {
left: 2px;
}
}
}
/deep/tr {
height: 44px !important;
td {
padding-top: 4px;
padding-bottom: 4px;
color: #666666;
font-size: 14px;
}
&.el-table__row--striped td {
background: #fcfcfc !important;
}
}
/deep/.el-table__body tr.current-row > td {
background-color: #eff4f9;
}
.star-icon-box {
.star-icon {
margin-right: 6px;
font-size: 14px;
&:nth-last-of-type(1) {
margin-right: 0;
}
}
}
}
/deep/.table-pagination {
margin-top: 20px;
padding-top: 20px;
text-align: center;
border-top: 1px solid #eeeff1;
.el-pagination.is-background .btn-next,
.el-pagination.is-background .btn-prev,
.el-pagination.is-background .el-pager li {
font-size: 12px;
font-weight: normal;
color: #666666;
background: #f6f6f6;
border-radius: 3px;
}
.el-pagination.is-background .el-pager li:not(.disabled).active {
color: #ffffff;
background-color: #1e81ff;
}
.el-pagination.is-background .btn-next.disabled,
.el-pagination.is-background .btn-next:disabled,
.el-pagination.is-background .btn-prev.disabled,
.el-pagination.is-background .btn-prev:disabled,
.el-pagination.is-background .el-pager li.disabled {
color: #c0c4cc;
}
.el-pagination__jump,
.el-input__inner {
font-size: 12px;
color: #666666;
}
}
.up {
color: #ed5959;
}
.down {
color: #33ad34;
}
.zero {
color: #333;
}
</style>
父组件详情页面代码:
<template>
<div>
<div
v-loading="loading"
class="main-wrapper">
<div class="main-box">
<el-card class="box-card">
<div class="title">详情</div>
<div class="tab-box">
<div
v-for="(item, index) in tabList"
:key="index"
class="item-tab"
@click="handleClick(item, index)">
<div
:class="activeIndex === index ? 'color' : ''"
class="tab"
>{{ item }}</div>
<div
v-if="activeIndex === index"
class="line-box"/>
</div>
</div>
<div class="table">
<ColumnTable
ref="columnTable"
:header-list="headerList"
:table-data="tableData"
:active-index="activeIndex"
@addRow ="addRow"
@delRow ="delRow"
/>
</div>
</el-card>
</div>
</div>
<!-- 添加事件表格 -->
<el-dialog
v-if="dialogVisible"
:visible.sync="dialogVisible"
title="选择事件"
width="60%"
class="dialog"
@close="cancelSelect">
<el-form
ref="ruleForm"
:model="ruleForm"
:rules="rules"
label-width="100px"
class="demo-ruleForm">
<el-form-item
label="事件"
prop="similarVal">
<el-select
v-model="ruleForm.similarVal"
:multiple-limit="2"
placeholder="请选择"
multiple
collapse-tags>
<el-option
v-for="item in similarOptions"
:key="`${getDate(item.eventdate.substring(0, 10))}${item.symbol}${item.shortname}解禁`"
:label="`${getDate(item.eventdate.substring(0, 10))}${item.symbol}${item.shortname}解禁`"
:value="`${getDate(item.eventdate.substring(0, 10))}${item.symbol}${item.shortname}解禁`"/>
</el-select>
</el-form-item>
<el-form-item class="btnOptions">
<el-button
@click="cancelSelect">取消</el-button>
<el-button
type="primary"
style="margin-left:20px"
@click="submitForm('ruleForm')">确定</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import ColumnTable from '@/components/ColumnTable' // 引入父组件表格
import { querySimilarTableData } from '@/api/queryEvent' // 后端接口
export default {
components: {
ColumnTable
},
data() {
return {
tabList: ['基本信息', '财务信息', '行情走势', '分类业务'],
activeIndex: 0,
headerList: [
{
label: '',
value: 'class',
headerAlign: 'left',
minWidth: '110',
align: 'center'
},
{
label: '基本信息',
value: 'baseInfo',
headerAlign: 'left',
minWidth: '80',
align: 'center'
},
{
label: '公司规模',
value: 'CirculatedMarketValue',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '公司性质',
value: 'OwnshipID',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '注册地址',
value: 'RegisterAddress',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '注册资本(元)',
value: 'RegisterCapital',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '办公地址',
value: 'OfficeAddress',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '上市日期',
value: 'IPODate',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '主营业务',
value: 'MainBusiness',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '所属行业',
value: 'IndustryCode',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '总股本(万股)',
value: 'TotalShare',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '流通股本(万股)',
value: 'CirculatedShare',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '财务信息',
value: 'financialInfo',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '净资产收益率(%)',
value: 'ROEA',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '净利润率(%)',
value: 'ROA2A',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '营业成本率(%)',
value: 'OperatingCostRatio',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '营业利润率(%)',
value: 'OperatingProfiToRevenue',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '销售期间费用率(%)',
value: 'PeriodExpenseRate',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '投资收益率(%)',
value: 'ReturnOnInvestment',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '应收账款周转率(%)',
value: 'ReceivableTurnoverA',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '总资产周转率(%)',
value: 'AssetTurnoverA',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '股东权益周转率(%)',
value: 'EequityTurnoverA',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '行情走势',
value: 'marketTrend',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '个股事后1日涨跌幅(%)',
value: 'onedayratio',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '个股事后3日涨跌幅(%)',
value: 'threedayratio',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '个股事后5日涨跌幅(%)',
value: 'fivedayratio',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '大盘收益率(%)',
value: 'marketreturn',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '行业收益率(%)',
value: 'industryreturn',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '分类业务',
value: 'age',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '解禁占比(%)',
value: 'Proportion2',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '总限售股数(万股)',
value: 'TotalLockShares',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '剩余限售股数量(万股)',
value: 'RemainedLockShares',
headerAlign: 'left',
minWidth: '90',
align: 'center'
},
{
label: '解禁股东数',
value: 'HolderNumber',
headerAlign: 'left',
minWidth: '90',
align: 'center'
}
],
ruleForm: {
similarVal: [] // 下拉框选中值
},
rules: {
similarVal: [
{ required: true, message: '请选择相似事件', trigger: 'change' }
]
},
tableData: [], // 表格数据
queryParams: [], // 请求参数
queryParams1: [], // 请求参数
loading: false, // 加载状态
dialogVisible: false, // 是否显示添加事件弹框
similarOptions: [] // 下拉框选项数据
}
},
mounted() {
let arr = []
arr = sessionStorage.getItem('similarParams')
this.queryParams = JSON.parse(arr)
this.queryParams.forEach(i => {
const tableList = sessionStorage.getItem('tableData')
this.similarOptions = JSON.parse(tableList).filter((item) => item.symbol !== i.symbol)
})
this.getSimilarTableData(this.queryParams)
},
methods: {
// tab栏切换点击(滚动条锚点定位)
handleClick(item, index) {
this.activeIndex = index
if (this.activeIndex == 0) {
document.documentElement.scrollTop = 0
} else {
// 获取需要滚动到的元素
const targetElement = document.getElementById('title')
// 将页面滚动至目标元素处
targetElement.scrollIntoView({ behavior: 'smooth' })
}
},
// 获取表格数据
getSimilarTableData(params) {
this.loading = true
this.tableData = []
querySimilarTableData(params).then(res => {
this.loading = false
res.forEach((item, index) => {
params.forEach((i, idx) => {
if (index === idx) {
const title = this.getDate(i.event_date)
item.RegisterCapital = this.money(item.RegisterCapital)
item.ROEA = this.toDecimal(item.ROEA, 4)
item.ROA2A = this.toDecimal(item.ROA2A, 4)
item.OperatingCostRatio = this.toDecimal(item.OperatingCostRatio, 4)
item.OperatingProfiToRevenue = this.toDecimal(item.OperatingProfiToRevenue, 4)
item.PeriodExpenseRate = this.toDecimal(item.PeriodExpenseRate, 4)
item.ReturnOnInvestment = this.toDecimal(item.ReturnOnInvestment, 4)
item.ReceivableTurnoverA = this.toDecimal(item.ReceivableTurnoverA, 4)
item.AssetTurnoverA = this.toDecimal(item.AssetTurnoverA, 4)
item.EequityTurnoverA = this.toDecimal(item.EequityTurnoverA, 4)
item.onedayratio = this.toDecimal(item.onedayratio, 2)
item.threedayratio = this.toDecimal(item.threedayratio, 2)
item.fivedayratio = this.toDecimal(item.fivedayratio, 2)
item.marketreturn = this.toDecimal(item.marketreturn, 2)
item.industryreturn = this.toDecimal(item.industryreturn, 2)
item.Proportion2 = this.toDecimal(item.Proportion2, 4)
const obj = {
class: `${title}${i.symbol}${i.shortname}解禁`,
...item
}
this.tableData.push(obj)
}
})
})
const obj1 = {
class: '添加其他事件',
AssetTurnoverA: '', CirculatedMarketValue: '', CirculatedShare: null, EequityTurnoverA: '', HolderNumber: null, IPODate: '', IndustryCode: '', MainBusiness: '', OfficeAddress: '', OperatingCostRatio: '', OperatingProfiToRevenue: '', OwnshipID: '', PeriodExpenseRate: '', Proportion2: '', ROA2A: '', ROEA: '', ReceivableTurnoverA: '', RegisterAddress: '', RegisterCapital: '', RemainedLockShares: null, ReturnOnInvestment: '', Symbol: '', TotalLockShares: null, TotalShare: null, fivedayratio: '', industryreturn: '', marketreturn: '', onedayratio: '', threedayratio: ''
}
this.tableData.push(obj1)
})
},
// 格式化日期
getDate(date) {
const date1 = new Date(date)
// 获取年份、月份和日期
const year = date1.getFullYear()
const month = date1.getMonth() + 1 // 注意月份从0开始计数,所以需要加上1得到真正的月份(12)
const day = date1.getDate()
return `${year}年${month}月${day}日`
},
// 新增事件
addRow() {
this.ruleForm.similarVal = []
this.tableData.forEach(res => {
this.similarOptions.forEach(i => {
if (res.class === `${this.getDate(i.eventdate.substring(0, 10))}${i.symbol}${i.shortname}解禁`) {
this.ruleForm.similarVal.push(res.class)
}
})
})
this.dialogVisible = true
},
// 删除事件
delRow(label) {
const index = this.tableData.findIndex(item => item.class === label)
const selectItem = this.tableData.splice(index, 1)
const arr = this.ruleForm.similarVal.filter(i => i !== selectItem[0].class)
this.ruleForm.similarVal = arr
},
// 取消选择事件
cancelSelect() {
this.dialogVisible = false
},
// 点击确定添加事件
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.queryParams1 = []
let queryParams2 = []
let tableParams = []
this.ruleForm.similarVal.forEach(i => {
queryParams2 = this.similarOptions.filter((item) => `${this.getDate(item.eventdate.substring(0, 10))}${item.symbol}${item.shortname}解禁` === i)
queryParams2.forEach(item => {
const obj = {
event_date: item.eventdate.substring(0, 10),
event_type: Number(item.eventtype),
shortname: item.shortname,
symbol: item.symbol
}
this.queryParams1.push(obj)
tableParams = this.queryParams.concat(this.queryParams1)
})
})
this.getSimilarTableData(tableParams)
this.dialogVisible = false
} else {
console.log('error submit!!')
return false
}
})
}
}
}
</script>
<style lang="scss" scoped>
/deep/ .el-select {
width: 320px !important;
}
/deep/ .el-select > .el-input {
width: 350px;
}
/deep/ .el-dialog {
height: 50%;
position: relative;
}
/deep/ .el-dialog__footer {
position: absolute;
bottom: 20px;
right: 20px;
}
.select-title {
margin-left: 100px;
}
.main-wrapper {
margin: 77px auto 0;
max-width: 1200px;
box-sizing: border-box;
.main-box {
display: flex;
.box-card {
width: 100%;
.title {
font-size: 14px;
font-family: Noto Sans S Chinese;
font-weight: bold;
color: #333333;
}
.tab-box {
display: flex;
align-items: center;
margin: 35px 57px 37px 57px;
.item-tab {
margin-right: 36px;
width: 67px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
cursor: pointer;
position: relative;
.tab {
font-size: 14px;
font-family: Noto Sans S Chinese;
font-weight: 400;
color: #333333;
}
.color {
color: #1E81FF;
}
}
.line-box {
width: 67px;
height: 1px;
background: #1E81FF;
position: absolute;
content: "";
bottom: -3px;
left: 0;
}
}
.table {
margin: 33px 57px 56px;
}
}
}
}
.btnOptions {
position: absolute;
right: 20px;
bottom: 20px;
}
</style>
加减表格子组件代码:<!-- 表格行列转换 -->
<template>
<el-table
ref="table"
:data="getTableData[0]"
border
style="width: 100%;"
>
<template v-for="(item, index) in getTableData[1]">
<el-table-column
:key="index"
:label="item.label"
:prop="item.value"
:header-align="item.headerAlign || 'center'"
:min-width="item.minWidth || 80"
:align="item.align || 'center'"
>
<template slot-scope="scope">
<!-- {{ tableFormatter(item.value, scope.row) }}-{{ index }}-{{ scope.$index }} index代表表格列索引,scope.$index代表表格行索引 -->
<div
:class="(scope.$index === 0 && activeIndex == 0) || (scope.$index === 11 && activeIndex == 1) || (scope.$index === 21 && activeIndex == 2) || (scope.$index === 27 && activeIndex == 3) ? 'title-text' : ''"
:style="{textAlign: (scope.$index === 4 || scope.$index > 8) && index > 0 ? 'right' : (index === 0 ? 'center' : 'left')}"
:id="(scope.$index === 0 && activeIndex == 0) || (scope.$index === 11 && activeIndex == 1) || (scope.$index === 21 && activeIndex == 2) || (scope.$index === 27 && activeIndex == 3) ? 'title' : ''">
{{ tableFormatter(item.value, scope.row) }}
</div>
</template>
<template
slot="header"
slot-scope="scope">
<div
v-if="scope.$index == tableData.length"
class="ceil">
{{ scope.column.label }}
<i
class="el-icon-circle-plus-outline"
@click="addRow()" />
</div>
<div
v-else-if="scope.$index>2&&scope.$index<tableData.length"
class="ceil">
{{ scope.column.label }}
<i
class="el-icon-remove-outline"
@click="delRow(scope.column.label)"/>
</div>
<span v-else>{{ scope.column.label }}</span>
</template>
</el-table-column>
</template>
</el-table>
</template>
<script>
export default {
props: {
headerList: {
type: Array,
default: () => []
},
tableData: {
type: Array,
default: () => []
},
activeIndex: {
type: Number,
default: 0
}
},
data() {
return {
}
},
computed: {
getTableData() {
return this.fotmatterTableData(this.tableData, this.headerList)
}
},
methods: {
fotmatterTableData(data, header) {
const enddata = []
const endheader = []
header.forEach((item, index) => {
if (index === 0) {
endheader.push({
label: header[index].label,
value: 'mainIndex',
headerAlign: header[index].headerAlign,
minWidth: header[index].minWidth,
align: header[index].align
})
data.forEach((ele, idx) => {
endheader.push({
label: ele[header[index].value],
value: `type${idx}`
})
})
} else {
const obj = {
mainIndex: header[index].label
}
data.forEach((ele, ind) => {
obj[`type${ind}`] = ele[header[index].value]
})
enddata.push(obj)
}
})
console.log('end===', enddata, endheader)
return [enddata, endheader]
},
// 列表格式化
tableFormatter(prop, row) {
if (row[prop] || row[prop] == 0) {
if (prop === 'mainIndex') {
if (row.unit) {
return `${row[prop]}(${row.unit})`
}
return row[prop]
}
return row[prop]
}
return ''
},
randomStr() {
return Math.random().toString().slice(3, 8)
},
addRow() {
this.$emit('addRow')
},
delRow(label) {
this.$emit('delRow', label)
}
}
}
</script>
<style scoped>
.title-text {
background: rgba(30,129,255,0.1);
color: #1E81FF;
width: 100%;
height: 24px;
}
/deep/ .el-table th > .cell {
padding-left: 0 !important;
padding-right: 0 !important;
}
/deep/ .cell {
padding-left: 0 !important;
padding-right: 0 !important;
height: 100%;
}
/deep/ td {
padding: 0;
}
.el-icon-circle-plus-outline {
cursor: pointer;
color: #1E81FF;
font-size: 16px;
}
.el-icon-remove-outline {
cursor: pointer;
color: #707070;
font-size: 16px;
}
</style>