445 lines
16 KiB
Vue
445 lines
16 KiB
Vue
<template>
|
||
<el-container style="height:100%">
|
||
<el-header class = 'containerHead'>
|
||
<HeaderPage :pageTitle = 'pageTitle'></HeaderPage>
|
||
<el-button class = 'btnReturnHomePage' @click="returnHome">
|
||
<el-tooltip content = '返回首页'>
|
||
<el-icon><ArrowLeft /></el-icon>
|
||
</el-tooltip>
|
||
</el-button>
|
||
</el-header>
|
||
<el-main class ='container_Tools_Main'>
|
||
<!-- 折叠版存放约束条件显示 -->
|
||
<el-container class = 'containerConstraints'>
|
||
<el-collapse v-model = 'activeNames'>
|
||
<el-collapse-item name = '1'>
|
||
<div class = 'divConstraintView' v-for="(i,index) in Constraints" :key="index">
|
||
{{"逻辑关系:" + i.merge + " 约束列:" + search_clu_name(i.col_id) + " " +Condition_to_string(i)}}
|
||
<button @click="constraint_delete(index)">删除</button>
|
||
</div>
|
||
</el-collapse-item>
|
||
</el-collapse>
|
||
</el-container>
|
||
<!-- 工具栏 -->
|
||
<el-header class ='containerTools'>
|
||
<el-button class = 'btnDelete'>
|
||
<el-tooltip content = '删除所有'>
|
||
<el-icon><Delete /></el-icon>
|
||
</el-tooltip>
|
||
</el-button>
|
||
<el-button class = 'btnSearch' @click = 'searchDialogVisible = true'>
|
||
<el-tooltip content = '条件查找'>
|
||
<el-icon><Search /></el-icon>
|
||
</el-tooltip>
|
||
<!-- 条件查找对应的对话框 -->
|
||
<!-- @author myz
|
||
@brief: 自实现的对话框用于提交约束条件添加
|
||
@params: colDate 表头属性的数据
|
||
@v-model:isVisible 控制对话框可见的v-model
|
||
@confirm: @confirm 处理子部件的confirm事件 -->
|
||
<ConstraintSearchDialog
|
||
:colData = 'clueCols'
|
||
v-model:isVisible = 'searchDialogVisible'
|
||
@confirm = 'handleSearchDialogConfirm'
|
||
/>
|
||
</el-button>
|
||
<el-button class = 'btnMore' @click="dochart">
|
||
<el-tooltip content = '更多'>
|
||
<el-icon><More /></el-icon>
|
||
</el-tooltip>
|
||
</el-button>
|
||
</el-header>
|
||
<EditDialog :columns="cols" ref="editDialog" :editDataID="currentEditDataID"></EditDialog>
|
||
<el-main class = 'containerMain'>
|
||
<el-table
|
||
class = 'containerTable'
|
||
:data="formattedTableData"
|
||
height="100%"
|
||
style="width: 100%"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="55" style="background-color: black;"/>
|
||
<el-table-column class = 'containerTabHead'
|
||
v-for="(column, index) in cols"
|
||
:key="index"
|
||
:prop="column.prop"
|
||
:label="column.label"
|
||
/>
|
||
<el-table-column fixed="right" width = 150px label="操作">
|
||
<template #header>
|
||
<div style="display: flex; justify-self: flex-end; padding-left: 38px;">操作</div>
|
||
</template>
|
||
<template #default="scope">
|
||
<!-- 使用插槽将数据传入到方法watchClue中 -->
|
||
<el-button class = 'btnItemEdit' size="small" @click="editClue(scope.row)">编辑</el-button>
|
||
<el-button class = 'btnItemDelete' size="small" @click="deleteClue(scope.row)"> 删除 </el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-main>
|
||
<!-- </el-main> -->
|
||
</el-main>
|
||
</el-container>
|
||
</template>
|
||
|
||
<script>
|
||
const activeNames = ref(['1']);
|
||
// 解决刷新率问题
|
||
const debounce = (fn, delay) => {
|
||
let timer;
|
||
return (...args) => {
|
||
if (timer) {
|
||
clearTimeout(timer)
|
||
}
|
||
timer = setTimeout(() => {
|
||
fn(...args)
|
||
}, delay)
|
||
}
|
||
};
|
||
// 解决刷新率问题
|
||
const _ResizeObserver = window.ResizeObserver;
|
||
window.ResizeObserver = class ResizeObserver extends _ResizeObserver{
|
||
constructor(callback) {
|
||
callback = debounce(callback, 200);
|
||
super(callback);
|
||
}
|
||
};
|
||
|
||
import ConstraintSearchDialog from "@/components/components_cluespage/ConstraintSearchDialog.vue"
|
||
import EditDialog from "@/components/components_cluespage/EditDialog.vue"
|
||
import HeaderPage from "@/views/HeaderPage.vue"
|
||
import {ref} from 'vue'
|
||
|
||
export default{
|
||
components:{
|
||
ConstraintSearchDialog,
|
||
HeaderPage,
|
||
EditDialog,
|
||
|
||
},
|
||
name:'CluesPage',
|
||
data(){
|
||
// 接收传入的id
|
||
const clueId = this.$route.params.id;
|
||
const pageTitle = this.$route.params.pageTitle;
|
||
// console.log("接收到的线索库ID:", clueId)
|
||
const generateMockData = (cols, numRows = 20) => {
|
||
const data = [];
|
||
for (let i = 0; i < numRows; i++) {
|
||
const row = { col_id: (i + 1).toString() };
|
||
cols.forEach((col, index) => {
|
||
row[`col_${index + 1}`] = `data_${i + 1}_${index + 1}`;
|
||
});
|
||
data.push(row);
|
||
}
|
||
return data;
|
||
};
|
||
|
||
const clueCols = generateColumns(4); // 生成包含10列的列定义数组, 实际运行时可能需要注释掉,防止与data中的冲突
|
||
|
||
// 生成10列的列定义数组
|
||
function generateColumns(numCols) {
|
||
const columns = [];
|
||
for (let i = 1; i <= numCols; i++) {
|
||
columns.push({ col_id: `${i}`, col_name: `Column ${i}` });
|
||
}
|
||
return columns;
|
||
}
|
||
|
||
|
||
return {
|
||
// 用于查找功能对话框的变量
|
||
searchDialogVisible : false,
|
||
// 查找所用变量
|
||
"Constraints":[// 注意 用的是复数形式
|
||
{"merge":"AND","col_id":"3","type":"double","down":"0","up":"INF","inside":"","date":""}, // 满足第1_3列(实数),范围为大于等于0的
|
||
{"merge":"AND","col_id":"2","type":"date","down":"","up":"","inside":"","date":"03.06.2024,30.06.2024"}, // 同时满足第!_2列(日期),早于2024/1/1的
|
||
{"merge":"OR","col_id":"4","type":"string","down":"","up":"","inside":"AAA","date":""} // 或者满足第1_4列(字符串),存在“AAA”这个连续字串的
|
||
],
|
||
// 显示当前页面的名称
|
||
pageTitle,
|
||
clueId,
|
||
chart:false,
|
||
currentEditDataID: {},
|
||
selectedColumnData :{},
|
||
clueCols, // 这个实际运行时可能要改为 clueCols[]
|
||
clueData: generateMockData(clueCols, 20), // 生成 20 行数据, 实际运行时:clueData:[],
|
||
}
|
||
},
|
||
methods:{
|
||
// 处理子部件的confirm事件
|
||
handleSearchDialogConfirm(form){
|
||
console.log("提交约束条件", form);
|
||
const newConstraint = {
|
||
"merge": form.logic,
|
||
"col_id": form.col_id,
|
||
"type": form.type,
|
||
"inside": form.search_string,
|
||
"up": form.max_limit,
|
||
"down": form.min_limit,
|
||
"date": form.continuous_time[0] + ',' + form.continuous_time[1],
|
||
}
|
||
this.Constraints.push(newConstraint);
|
||
},
|
||
// 根据属性id显示属性
|
||
search_clu_name(aa){
|
||
for (let col of this.clueCols) {
|
||
if(aa == col.col_id)
|
||
return col.col_name;
|
||
}
|
||
},
|
||
Condition_to_string(Constraint){
|
||
if(Constraint.type == "string"){
|
||
return " 包含 " + Constraint.inside;
|
||
}
|
||
if(Constraint.up == "INF" && Constraint.down == "INF"){
|
||
return " 类型为 " + Constraint.type;
|
||
}
|
||
if(Constraint.up == "INF" && Constraint.type == "double"){
|
||
return " 大于等于 " + Constraint.down;
|
||
}
|
||
if(Constraint.down == "INF" && Constraint.type == "double"){
|
||
return " 小于等于 " + Constraint.up;
|
||
}
|
||
if(Constraint.type == "double")return " 在 " + Constraint.down + " 和 " + Constraint.up + "之间";
|
||
if(Constraint.type == "date")return "在 " + Constraint.date + "之间";
|
||
},
|
||
constraint_delete(index){
|
||
this.Constraints.splice(index, 1);
|
||
},
|
||
dochart(){
|
||
const table=JSON.stringify(this.clueData);
|
||
const column=JSON.stringify(this.cols);
|
||
this.$router.push({name:'Graph',params:{columns:column,tabledata:table}})
|
||
},
|
||
handleSelectionChange(selection) {
|
||
// 在这里处理选择变化,selection 是选中的行数据数组
|
||
|
||
this.selectedColumnData = selection;
|
||
console.log( this.selectedColumnData);
|
||
console.log('选择的行数据:', selection);
|
||
},
|
||
receiveSrow(value) {
|
||
// 在这里处理传递过来的值
|
||
this.srow = value;
|
||
console.log("djlasj",value);
|
||
},
|
||
// 返回首页的动态路由
|
||
returnHome(){
|
||
this.$router.push({name:'Table'})
|
||
},
|
||
// 获取所有列名
|
||
getClueCols(){
|
||
this.$axios.post('http://localhost:8000/showClueCol/', {table_id:this.clueId}).then(response=>{
|
||
this.clueCols = response.data;
|
||
})
|
||
},
|
||
// 获取某一线索库数据
|
||
getClueData(){
|
||
this.$axios.post('http://localhost:8000/showClue/',{table_id:this.clueId}).then(response=>{
|
||
this.clueData = response.data;
|
||
})
|
||
},
|
||
mergeCols(){
|
||
// 创建一个映射表,便于查找列名
|
||
const colMap = this.clueCols.reduce((acc, col) => {
|
||
acc[col.col_id] = col.col_name;
|
||
return acc;
|
||
}, {});
|
||
|
||
// 遍历clueData的第一个元素,构造新数组
|
||
// 注意:这里假设所有对象的结构一致,且至少有一个元素
|
||
const mergedColumns = Object.keys(this.clueData[0]).map(key => {
|
||
if (key.startsWith('col_')) {
|
||
const colId = key.replace('col_', ''); // 提取数字部分
|
||
if(colId != 'id'){//排除id列
|
||
return { prop: key, label: colMap[colId] || '未知列名' };
|
||
}
|
||
}
|
||
return null; // 或者忽略非col_开头的键
|
||
}).filter(Boolean); // 过滤掉null值
|
||
|
||
// 检查合并后的结果
|
||
// console.log('合并之后的表头:',mergedColumns);
|
||
return mergedColumns;
|
||
},
|
||
deleteClue(row){
|
||
const postData = {
|
||
table_id:this.clueId,
|
||
clue_id:row.clue_id
|
||
};
|
||
//console.log(row)
|
||
this.$axios.post('http://localhost:8000/delClue/',postData).then(response=>{
|
||
const message = response.data.message;
|
||
// 根据返回消息,进行不同的操作
|
||
if(message == "删除成功"){
|
||
// 调用this.$message组件进行弹窗提示
|
||
this.$message({
|
||
type:'success',
|
||
message:'删除成功!'
|
||
});
|
||
// 刷新页面
|
||
location.reload();
|
||
}else if(message == "删除失败"){
|
||
this.$message({
|
||
type:'error',
|
||
message:'删除失败,请重试!'
|
||
});
|
||
}
|
||
})
|
||
.catch(error=>{
|
||
// 使用自定义的错误处理
|
||
this.$handleNetError(error);
|
||
});
|
||
},
|
||
// 编辑线索记录按钮
|
||
editClue(row){
|
||
let editDataID = {
|
||
table_id:this.clueId,
|
||
clue_id:row.col_id
|
||
};
|
||
this.$refs.editDialog.dialogVisible = true; // 对话框是否可见
|
||
this.$refs.editDialog.formData = this.formatFormData(row); // 表单数据
|
||
this.currentEditDataID = editDataID;
|
||
console.log(editDataID);
|
||
},
|
||
// 将数据格式化成表单数据
|
||
formatFormData(row) {
|
||
const formData = {};
|
||
this.cols.forEach(col => {
|
||
if (col.prop !== 'id') {
|
||
formData[col.prop] = row[col.prop];
|
||
}
|
||
});
|
||
|
||
return formData;
|
||
},
|
||
},
|
||
computed: {
|
||
cols(){
|
||
if (this.clueCols.length && this.clueData.length) {
|
||
// console.log('cols: ', this.mergeCols());
|
||
return this.mergeCols();
|
||
}
|
||
return []; // 或者返回一个空数组,直到数据加载完成
|
||
},
|
||
|
||
formattedTableData() {
|
||
// 保留原始ID,同时格式化其他数据以匹配动态表头
|
||
const Data = this.clueData.map(row => {
|
||
const newRow = { ...row }; // 复制row以避免修改原始数据
|
||
// 根据动态列,重新组织数据对象
|
||
this.cols.forEach(col => {
|
||
if (col.label !== 'ID') {
|
||
newRow[col.label] = newRow[col.prop];
|
||
// console.log('newRow:',newRow)
|
||
// delete newRow[col.label]; // 如果需要,可以删除原始格式的属性,按照label会去掉id,
|
||
}
|
||
});
|
||
// console.log('newRow: ', newRow)
|
||
return newRow;
|
||
});
|
||
// console.log('展示的数据:', Data);
|
||
// console.log('Data.col_id:', Data[0].col_id);
|
||
return Data;
|
||
}
|
||
},
|
||
watch: {
|
||
// 调试约束条件添加的方法
|
||
searchDialogVisible(newValue){
|
||
console.log(newValue);
|
||
},
|
||
Constraints(newv,oldv){
|
||
console.log(newv);
|
||
},
|
||
},
|
||
//加载页面的时候获取数据
|
||
beforeMount() {
|
||
// this.getClueCols();
|
||
// this.getClueData();
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.el-container{
|
||
padding: 0;
|
||
}
|
||
.containerTools{
|
||
height:6%;
|
||
padding:2%;
|
||
display:flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
}
|
||
.containerHead{
|
||
padding:0;
|
||
height:8%;
|
||
padding :0;
|
||
width: 100%;
|
||
display:flex;
|
||
justify-content: space-between;
|
||
background-color: white;
|
||
align-items: center;
|
||
}
|
||
.HeaderPage{
|
||
width: 90%;
|
||
}
|
||
.btnReturnHomePage{
|
||
font-size: large;
|
||
width: 3%;
|
||
font-weight: 25px;
|
||
}
|
||
.container_Tools_Main{
|
||
padding:0;
|
||
background-color: #f5f6fa;
|
||
height: 92%;
|
||
width: 100%;
|
||
}
|
||
.el-button{
|
||
background-color: transparent;
|
||
margin:2;
|
||
padding:2;
|
||
border: 0;
|
||
color: #0e5858;
|
||
font-size: 24px;
|
||
}
|
||
.el-button:hover{
|
||
background-color: rgba(255, 255, 255, 0.7);
|
||
}
|
||
/* 设置表格 */
|
||
.containerMain{
|
||
background-color: #f5f6fa;
|
||
padding: 10px;
|
||
padding-top: 0;
|
||
height:90%;
|
||
overflow: auto;
|
||
}
|
||
.btnItemDelete{
|
||
background-color: lightcoral;
|
||
color: white;
|
||
border-radius: 14px;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
}
|
||
.btnItemDelete:hover{
|
||
background: rgba(240, 128, 128, 0.647);
|
||
}
|
||
.btnItemEdit{
|
||
background-color: #1DAFAF;
|
||
color: white;
|
||
border-radius: 14px;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
}
|
||
.btnItemEdit:hover{
|
||
background: #1dafafd2;
|
||
}
|
||
|
||
.btnDelete,.btnSearch,.btnMore{
|
||
text-align: start;
|
||
padding: 0.6%;
|
||
margin: 0;
|
||
}
|
||
|
||
</style> |