Commit ac2b9088 by cat

zd

parent 4e25153b
# 环境变量配置文件
# 所有环境通用配置
# 应用标题
VUE_APP_TITLE=地震资料处理数字化验收支持平台
# API基础路径
VUE_APP_BASE_API=/dev-api
# 页面标题
VUE_APP_TITLE = 系统
# 开发环境配置
ENV = 'development'
NODE_ENV=development
# 若依管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'
# 应用标题
VUE_APP_TITLE=地震资料处理数字化验收支持平台
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
# API基础路径
VUE_APP_BASE_API=/dev-api
# 页面标题
VUE_APP_TITLE = 系统
# 生产环境配置
ENV = 'production'
NODE_ENV=production
# 应用标题
VUE_APP_TITLE=地震资料处理数字化验收支持平台
# 若依管理系统/生产环境
VUE_APP_BASE_API = '/prod-api'
# API基础路径
VUE_APP_BASE_API=/prod-api
# 页面标题
VUE_APP_TITLE = 系统
# 预发布环境配置
NODE_ENV=production
BABEL_ENV = production
# 应用标题
VUE_APP_TITLE=地震资料处理数字化验收支持平台(预发布)
NODE_ENV = production
# 测试环境配置
ENV = 'staging'
# 若依管理系统/测试环境
VUE_APP_BASE_API = '/stage-api'
# API基础路径
VUE_APP_BASE_API=/stage-api
......@@ -201,7 +201,7 @@
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载系统资源,请耐心等待</div>
<div class="load_title">正在加载地震资料处理数字化验收支持平台资源,请耐心等待</div>
</div>
</div>
</body>
......
......@@ -6,15 +6,16 @@
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
<!-- <img v-if="logo" :src="logo" class="sidebar-logo" /> -->
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">验收支持平台 </h1>
<!-- <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1> -->
</router-link>
</transition>
</div>
</template>
<script>
import logoImg from '@/assets/logo/logo.png'
// import logoImg from '@/assets/logo/logo.png'
import variables from '@/assets/styles/variables.scss'
export default {
......@@ -36,7 +37,7 @@ export default {
data() {
return {
title: process.env.VUE_APP_TITLE,
logo: logoImg
// logo: logoImg
}
}
}
......
......@@ -13,16 +13,18 @@
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
<el-form-item prop="code" v-if="captchaEnabled" class="captcha-item">
<div class="captcha-container">
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码"
@keyup.enter.native="handleLogin">
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" />
</div>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button :loading="loading" size="medium" type="primary" style="width:100%;"
@click.native.prevent="handleLogin">
......@@ -53,8 +55,8 @@ export default {
title: process.env.VUE_APP_TITLE,
codeUrl: "",
loginForm: {
username: "admin",
password: "admin123",
username: "",
password: "",
rememberMe: false,
code: "",
uuid: ""
......@@ -69,7 +71,7 @@ export default {
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/,
message:
'用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号',
trigger: 'blur',
trigger: ['blur', 'change'],
},
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
......@@ -147,70 +149,216 @@ export default {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
height: 100vh;
background-image: url("../assets/images/login-background.jpeg");
background-size: cover;
background-position: center;
background-attachment: fixed;
position: relative;
// 添加渐变遮罩层
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(rgba(111, 111, 111, 0.20) );
z-index: 0;
}
}
.title {
margin: 0px auto 30px auto;
margin: 0px auto 20px auto;
text-align: center;
color: #707070;
color: #ebebeb;
font-size: 24px;
font-weight: 300;
letter-spacing: 2px;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
width: 480px;
padding: 25px 35px 20px 35px;
z-index: 1;
position: relative;
margin-left: 600px;
.el-input {
height: 38px;
height: 50px;
margin-bottom: 10px;
input {
height: 38px;
height: 50px;
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
color: #2c3e50;
font-size: 14px;
padding-left: 45px;
transition: all 0.3s ease;
&:focus {
background: rgba(255, 255, 255, 1);
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
&::placeholder {
color: #a0a0a0;
}
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
height: 20px;
width: 20px;
margin-left: 10;
color: #7f8c8d;
z-index: 2;
}
.el-form-item {
margin-bottom: 12px;
}
.el-checkbox {
margin-bottom: 15px;
.el-checkbox__label {
color: #2c3e50;
font-size: 14px;
}
}
.el-button {
height: 50px;
border-radius: 12px;
font-size: 16px;
font-weight: 500;
letter-spacing: 1px;
background: linear-gradient(135deg, #409eff 0%, #36a3f7 100%);
border: none;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(64, 158, 255, 0.3);
}
&:active {
transform: translateY(0);
}
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
.captcha-container {
display: flex;
align-items: stretch;
gap: 10px;
height: 50px;
}
.captcha-item {
.el-input {
flex: 1;
margin-bottom: 0;
height: 50px;
input {
height: 50px;
line-height: 50px;
}
}
}
.login-code {
width: 33%;
height: 38px;
float: right;
width: 120px;
height: 50px;
border-radius: 12px;
overflow: hidden;
flex-shrink: 0;
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(255, 255, 255, 0.3);
display: flex;
align-items: center;
justify-content: center;
img {
cursor: pointer;
vertical-align: middle;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 12px;
transition: all 0.3s ease;
&:hover {
transform: scale(1.05);
}
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
height: 50px;
line-height: 50px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
color: rgba(255, 255, 255, 0.8);
font-family: 'Helvetica Neue', Arial, sans-serif;
font-size: 13px;
letter-spacing: 1px;
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
z-index: 1;
}
.login-code-img {
height: 38px;
height: 50px;
border-radius: 12px;
}
// 响应式设计
@media (max-width: 768px) {
.login-form {
width: 90%;
max-width: 420px;
padding: 25px 20px 20px 20px;
}
.title {
font-size: 20px;
margin-bottom: 20px;
}
}
.el-input__icon{
height: 50px !important;
margin-left: 10px !important;
}
// 添加一些动画效果
.login-form {
animation: slideInUp 0.8s ease-out;
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
<template>
<div class="app-container">
<el-row :gutter="20">
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
<!--部门数据-->
<pane size="16">
<el-col>
<div class="head-container">
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search"
style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false"
:filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
@node-click="handleNodeClick" />
</div>
</el-col>
</pane>
<!--用户数据-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:user:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
v-hasPermi="['system:user:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport"
v-hasPermi="['system:user:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['system:user:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible"
:show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible"
:show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible"
:show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber"
v-if="columns[4].visible" width="120" />
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.userId !== 1">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']">删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleResetPwd" icon="el-icon-key"
v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</pane>
</splitpanes>
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="60%" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true"
placeholder="请选择归属部门" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password @input="checkPassword" />
<!-- 弱口令警告提示 -->
<div v-if="passwordWarning.show" class="password-warning" :class="{ 'warning-danger': passwordWarning.isWeak }">
<i class="el-icon-warning"></i>
<span>{{ passwordWarning.message }}</span>
</div>
<!-- 密码安全建议 -->
<div v-if="passwordSuggestion" class="password-suggestion">
<i class="el-icon-info"></i>
<span>{{ passwordSuggestion }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{
dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择岗位">
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId"
:disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId"
:disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
</div>
<span>仅允许导入xls、xlsx格式文件。</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"
@click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm">确 定</el-button>
<el-button @click="upload.open = false">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 用户表格数据
userList: null,
// 弹出层标题
title: "",
// 所有部门树选项
deptOptions: undefined,
// 过滤掉已禁用部门树选项
enabledDeptOptions: undefined,
// 是否显示弹出层
open: false,
// 部门名称
deptName: undefined,
// 默认密码
initPassword: undefined,
// 日期范围
dateRange: [],
// 岗位选项
postOptions: [],
// 角色选项
roleOptions: [],
// 表单参数
form: {},
// 密码安全提示
passwordWarning: {
show: false,
isWeak: false,
message: ''
},
passwordSuggestion: '',
defaultProps: {
children: "children",
label: "label"
},
// 用户导入参数
upload: {
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/system/user/importData"
},
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
},
// 列信息
columns: [
{ key: 0, label: `用户编号`, visible: true },
{ key: 1, label: `用户名称`, visible: true },
{ key: 2, label: `用户昵称`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true }
],
// 表单校验
rules: {
userName: [
{ required: true, message: "用户名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" },
{ validator: this.validatePassword, trigger: 'blur' }
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
phonenumber: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
}
}
},
watch: {
// 根据名称筛选部门树
deptName(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getList()
this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.msg
})
},
methods: {
// 密码验证方法
validatePassword(rule, value, callback) {
if (!value) {
callback(new Error('请输入用户密码'))
return
}
callback()
},
/** 查询用户列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
/** 查询部门下拉树结构 */
getDeptTree() {
deptTreeSelect().then(response => {
this.deptOptions = response.data
this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
})
},
// 过滤禁用的部门
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children)
}
return true
})
},
// 筛选节点
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
// 节点单击事件
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.handleQuery()
},
// 用户状态修改
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function () {
row.status = row.status === "0" ? "1" : "0"
})
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: "0",
remark: undefined,
postIds: [],
roleIds: []
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams.deptId = undefined
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId)
this.single = selection.length != 1
this.multiple = !selection.length
},
// 更多操作触发
handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
this.handleResetPwd(row)
break
case "handleAuthRole":
this.handleAuthRole(row)
break
default:
break
}
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = "添加用户"
this.form.password = this.initPassword
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const userId = row.userId || this.ids
getUser(userId).then(response => {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
this.open = true
this.title = "修改用户"
this.form.password = ""
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/,
inputErrorMessage: "用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
return true
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => { })
},
/** 分配角色操作 */
handleAuthRole: function (row) {
const userId = row.userId
this.$router.push("/system/user-auth/role/" + userId)
},
/** 提交按钮 */
submitForm: function () {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
return delUser(userIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => { })
},
/** 导出按钮操作 */
handleExport() {
this.download('system/user/export', {
...this.queryParams
}, `user_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "用户导入"
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.getList()
},
// 提交上传文件
submitFileForm() {
this.$refs.upload.submit()
}
}
}
</script>
<style scoped>
/* 密码安全提示样式 */
.password-warning {
margin-top: 8px;
padding: 8px 12px;
border-radius: 6px;
background-color: rgba(255, 193, 7, 0.1);
border: 1px solid rgba(255, 193, 7, 0.3);
color: #f57c00;
font-size: 12px;
display: flex;
align-items: center;
animation: slideDown 0.3s ease-out;
}
.password-warning i {
margin-right: 6px;
font-size: 14px;
}
.password-warning.warning-danger {
background-color: rgba(244, 67, 54, 0.1);
border-color: rgba(244, 67, 54, 0.3);
color: #d32f2f;
}
.password-suggestion {
margin-top: 6px;
padding: 6px 12px;
border-radius: 6px;
background-color: rgba(33, 150, 243, 0.1);
border: 1px solid rgba(33, 150, 243, 0.3);
color: #1976d2;
font-size: 12px;
display: flex;
align-items: center;
animation: slideDown 0.3s ease-out;
}
.password-suggestion i {
margin-right: 6px;
font-size: 14px;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
\ No newline at end of file
......@@ -330,8 +330,13 @@ export default {
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
{ min: 6, max: 20, message: '用户密码长度必须介于 6 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" },
{
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/,
message: '用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号',
trigger: ['blur', 'change'],
}
],
email: [
{
......
......@@ -327,8 +327,40 @@ export default {
return {
backgroundColor: this.compact ? '#f2f2f2' : '#ffffff',
grid: this.compact ? { top: 6, left: 6, right: 6, bottom: 6, containLabel: false } : { top: 40, left: 50, right: 40, bottom: 50, containLabel: true },
xAxis: this.compact ? { type: 'value', min: this.xMin, max: this.xMax, scale: true, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { show: false }, splitLine: { show: false } } : { type: 'value', min: this.xMin, max: this.xMax, scale: false, axisLine: { show: true }, axisTick: { show: true }, axisLabel: { color: '#666' }, splitLine: { show: true, lineStyle: { color: '#9bb3e7', opacity: 0.6 } } },
yAxis: this.compact ? { type: 'value', min: this.yMin, max: this.yMax, scale: true, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { show: false }, splitLine: { show: false } } : { type: 'value', min: this.yMin, max: this.yMax, scale: false, axisLine: { show: true }, axisTick: { show: true }, axisLabel: { color: '#666' }, splitLine: { show: true, lineStyle: { color: '#9bb3e7', opacity: 0.6 } } },
xAxis: this.compact ? {
type: 'value',
min: this.xMin,
max: this.xMax,
scale: true,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false },
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
opacity: 0.8,
width: 1
}
}
} : { type: 'value', min: this.xMin, max: this.xMax, scale: false, axisLine: { show: true }, axisTick: { show: true }, axisLabel: { color: '#666' }, splitLine: { show: true, lineStyle: { color: '#9bb3e7', opacity: 0.6 } } },
yAxis: this.compact ? {
type: 'value',
min: this.yMin,
max: this.yMax,
scale: true,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false },
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
opacity: 0.8,
width: 1
}
}
} : { type: 'value', min: this.yMin, max: this.yMax, scale: false, axisLine: { show: true }, axisTick: { show: true }, axisLabel: { color: '#666' }, splitLine: { show: true, lineStyle: { color: '#9bb3e7', opacity: 0.6 } } },
series,
tooltip: { trigger: 'item' }
}
......
......@@ -41,16 +41,37 @@
</el-button>
</el-tooltip> -->
</div>
<div v-if="shouldShowThumb" ref="thumbContainer" @click="handleThumbClick" class="right-thumb">
<div class="thumb-title">缩略图</div>
<!-- 缩略图 start-->
<div
v-if="shouldShowThumb"
ref="thumbContainer"
@click="handleThumbClick"
@mousedown="startDrag"
class="right-thumb draggable-thumb"
:style="thumbPosition">
<!-- <div class="thumb-title">缩略图</div> -->
<div ref="thumbHolder" class="thumb-holder">
<YsgcIndex v-if="thumbReady" :key="'thumb-' + routeId + '-' + thumbReady" :compact="true" :width="260"
:height="160" :id-override="routeId" />
</div>
<!-- 拖动指示器 -->
<div class="drag-handle">
<i class="el-icon-rank"></i>
</div>
</div>
<!-- 缩略图 end-->
<!-- 缩略图弹窗 start -->
<el-dialog v-if="shouldShowThumb" title="缩略图预览" :visible.sync="showThumbDialog" width="80%" append-to-body>
<el-dialog
v-if="shouldShowThumb"
title="缩略图预览"
:visible.sync="showThumbDialog"
width="80%"
append-to-body
:z-index="9999999"
:modal="true"
:close-on-click-modal="true"
:close-on-press-escape="true"
custom-class="thumbnail-dialog">
<div style="height: 100%;">
<YsgcIndex :key="'dialog-thumb-' + routeId" :id-override="routeId" @segyLinePick="onThumbLinePick" />
</div>
......@@ -63,11 +84,8 @@
{{ loadingError }}
</div>
<div class="toolbar" v-if="isWidgetReady">
<!-- 左侧内容 -->
<div class="toolbar-left">
<!-- 左侧可以留空,或者将来添加其他控件 -->
</div>
</div>
<div class="split-container" :class="layoutMode === 'vertical' ? 'layout-vertical' : 'layout-horizontal'">
<div class="sync-section" ref="topScroll" @scroll="onScroll('top')">
......@@ -698,6 +716,18 @@ export default {
showThumbDialog: false, // 缩略图大图弹窗可见性
// 是否允许在未指定项目/无接口数据时加载示例数据
shouldLoadDemo: true,
// 缩略图拖动相关
isDragging: false,
dragStartX: 0,
dragStartY: 0,
dragDistance: 0,
dragThreshold: 5, // 拖动阈值,超过这个距离才算拖动
thumbPosition: {
top: '150px',
right: '20px',
left: 'auto',
bottom: 'auto'
},
};
},
computed: {
......@@ -726,7 +756,7 @@ export default {
watch: {
// 监听路由变化,当路由参数改变时重新初始化数据
'$route'(to, from) {
console.log('[index2] 路由变化:', to.query, from.query);
//console.log('[index2] 路由变化:', to.query, from.query);
// 如果路由参数发生变化,重新初始化组件
if (to.query.id !== from.query.id || to.query.zbid !== from.query.zbid) {
this.handleRouteChange();
......@@ -734,7 +764,7 @@ export default {
},
// 监听routeId变化
routeId(newId, oldId) {
console.log('[index2] routeId变化:', newId, oldId);
//console.log('[index2] routeId变化:', newId, oldId);
if (newId !== oldId) {
this.handleRouteChange();
// 强制刷新缩略图
......@@ -823,9 +853,9 @@ export default {
}, 200);
}, 100);
console.log('测试函数已添加:');
console.log('- window.testOuterScrollbarSync() - 测试外层滚动条同步');
console.log('- window.testInternalScrollbarHidden() - 测试内部滚动条隐藏');
//console.log('测试函数已添加:');
//console.log('- window.testOuterScrollbarSync() - 测试外层滚动条同步');
//console.log('- window.testInternalScrollbarHidden() - 测试内部滚动条隐藏');
},
beforeDestroy() {
// 移除右键菜单事件监听
......@@ -833,6 +863,10 @@ export default {
this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
document.removeEventListener('click', this.hideContextMenu);
}
// 清理拖动事件监听
document.removeEventListener('mousemove', this.onDrag);
document.removeEventListener('mouseup', this.stopDrag);
// 移除键盘事件监听
document.removeEventListener('keydown', this.handleKeyDown);
// 移除窗口变化监听
......@@ -841,7 +875,7 @@ export default {
methods: {
// 处理路由变化的方法
async handleRouteChange() {
console.log('[index2] 处理路由变化,重新初始化组件');
//console.log('[index2] 处理路由变化,重新初始化组件');
// 重置组件状态
this.resetToInitialState();
......@@ -897,7 +931,7 @@ export default {
// 强制刷新缩略图
forceRefreshThumb() {
console.log('[index2] 强制刷新缩略图');
//console.log('[index2] 强制刷新缩略图');
this.thumbReady = false;
this.$nextTick(() => {
this.thumbReady = true;
......@@ -994,9 +1028,9 @@ export default {
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate(); } catch (e) { }
},
async handlePrevTrace() {
console.log('[index2] 上一道 clicked');
//console.log('[index2] 上一道 clicked');
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
console.log('[index2] segyList 为空,尝试重新加载');
//console.log('[index2] segyList 为空,尝试重新加载');
try {
await this.loadThumbData();
} catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
......@@ -1008,15 +1042,15 @@ export default {
// 计算上一个索引
this.currentSegyIndex = this.currentSegyIndex > 0 ? this.currentSegyIndex - 1 : this.segyList.length - 1;
console.log('[index2] 切换到上一道,当前索引:', this.currentSegyIndex);
//console.log('[index2] 切换到上一道,当前索引:', this.currentSegyIndex);
// 加载当前segy文件
this.loadCurrentSegy();
},
async handleNextTrace() {
console.log('[index2] 下一道 clicked');
//console.log('[index2] 下一道 clicked');
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
console.log('[index2] segyList 为空,尝试重新加载');
//console.log('[index2] segyList 为空,尝试重新加载');
try {
await this.loadThumbData();
} catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
......@@ -1028,7 +1062,7 @@ export default {
// 计算下一个索引
this.currentSegyIndex = this.currentSegyIndex < this.segyList.length - 1 ? this.currentSegyIndex + 1 : 0;
console.log('[index2] 切换到下一道,当前索引:', this.currentSegyIndex);
//console.log('[index2] 切换到下一道,当前索引:', this.currentSegyIndex);
// 加载当前segy文件
this.loadCurrentSegy();
......@@ -1036,18 +1070,18 @@ export default {
// 加载当前segy文件
async loadCurrentSegy() {
if (this.segyList.length === 0) {
console.log('[index2] 没有segy数据可加载');
//console.log('[index2] 没有segy数据可加载');
return;
}
const currentSegy = this.segyList[this.currentSegyIndex];
if (!currentSegy) {
console.log('[index2] 当前segy数据不存在');
//console.log('[index2] 当前segy数据不存在');
return;
}
console.log('[index2] 加载segy文件 Top/Bottom:', (currentSegy.jbsegyName || currentSegy.jbsegy), (currentSegy.xbsegyName || currentSegy.xbsegy));
console.log('[index2] segy文件路径 Top/Bottom:', currentSegy.jbsegy, currentSegy.xbsegy);
//console.log('[index2] 加载segy文件 Top/Bottom:', (currentSegy.jbsegyName || currentSegy.jbsegy), (currentSegy.xbsegyName || currentSegy.xbsegy));
//console.log('[index2] segy文件路径 Top/Bottom:', currentSegy.jbsegy, currentSegy.xbsegy);
try {
// 双图加载:jbsegy -> 顶部;xbsegy -> 底部
......@@ -1059,7 +1093,7 @@ export default {
},
// 清空当前图表
clearCurrentPlots() {
console.log('[index2] 清空当前图表');
//console.log('[index2] 清空当前图表');
try {
// 清空主图表
if (this._seismicWidget) {
......@@ -1078,7 +1112,7 @@ export default {
},
// 加载segy文件的具体实现
async loadSegyFile(segyPath) {
console.log('[index2] 开始加载segy文件:', segyPath);
//console.log('[index2] 开始加载segy文件:', segyPath);
try {
// 只显示主图表,隐藏底部图表
......@@ -1092,7 +1126,7 @@ export default {
this.createScene(this.$refs.plot);
}
console.log('[index2] segy文件加载完成');
//console.log('[index2] segy文件加载完成');
} catch (error) {
console.error('[index2] 加载segy文件时出错:', error);
......@@ -1152,9 +1186,9 @@ export default {
const url = this.buildSegyURL(segyPath);
// 拉取二进制
console.log('[index2] 即将拉取SEGY', { position, name: displayName, rawPath: segyPath, builtUrl: url });
//console.log('[index2] 即将拉取SEGY', { position, name: displayName, rawPath: segyPath, builtUrl: url });
const blob = await this.fetchSegyBlob(url);
console.log('[index2] 已获取SEGY二进制', { position, name: displayName, size: blob && blob.size, type: blob && blob.type });
//console.log('[index2] 已获取SEGY二进制', { position, name: displayName, size: blob && blob.size, type: blob && blob.type });
const fileName = (displayName || this.extractFileName(segyPath) || 'data.segy');
const filesObj = new File([blob], fileName, { type: blob.type || 'application/octet-stream', lastModified: Date.now() });
const file = new LocalFile(filesObj);
......@@ -1272,7 +1306,7 @@ export default {
const errors = [];
for (const attempt of attempts) {
try {
console.log('[index2] fetchSegyBlob 尝试', { url: attempt.url, withAuth: !!attempt.headers });
//console.log('[index2] fetchSegyBlob 尝试', { url: attempt.url, withAuth: !!attempt.headers });
const res = await fetch(attempt.url, attempt.headers ? { headers: attempt.headers } : {});
if (!res.ok) {
const text = await res.text().catch(() => '');
......@@ -1298,7 +1332,7 @@ export default {
},
// 显示单个图表(隐藏底部图表)
showSingleChart() {
console.log('[index2] 切换到单图表显示模式');
//console.log('[index2] 切换到单图表显示模式');
// 隐藏底部图表容器
const bottomScroll = this.$refs.bottomScroll;
......@@ -1318,7 +1352,7 @@ export default {
},
// 显示双图表(恢复上下或左右布局)
showDualChart() {
console.log('[index2] 切换到双图表显示模式');
//console.log('[index2] 切换到双图表显示模式');
// 显示底部图表容器
const bottomScroll = this.$refs.bottomScroll;
......@@ -1350,14 +1384,101 @@ export default {
this.plots = null;
this._seismicWidget = null;
console.log('[index2] 场景已清空');
//console.log('[index2] 场景已清空');
} catch (e) {
console.warn('[index2] 清空场景时出错:', e);
}
},
handleThumbClick() {
// 如果正在拖动或拖动距离超过阈值,不触发点击事件
if (this.isDragging || this.dragDistance > this.dragThreshold) {
return;
}
this.showThumbDialog = true;
},
// 开始拖动
startDrag(event) {
// 只有点击拖动指示器或缩略图边缘才开始拖动
if (!event.target.closest('.drag-handle') && !event.target.closest('.thumb-holder')) {
return;
}
event.preventDefault();
this.isDragging = false; // 初始状态不是拖动
this.dragDistance = 0;
this.dragStartX = event.clientX;
this.dragStartY = event.clientY;
// 添加全局事件监听
document.addEventListener('mousemove', this.onDrag);
document.addEventListener('mouseup', this.stopDrag);
},
// 拖动中
onDrag(event) {
event.preventDefault();
const deltaX = event.clientX - this.dragStartX;
const deltaY = event.clientY - this.dragStartY;
this.dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// 只有拖动距离超过阈值才开始真正的拖动
if (this.dragDistance > this.dragThreshold) {
if (!this.isDragging) {
this.isDragging = true;
// 添加拖动样式
if (this.$refs.thumbContainer) {
this.$refs.thumbContainer.style.cursor = 'grabbing';
}
}
// 获取当前缩略图的位置
const currentTop = parseInt(this.thumbPosition.top) || 150;
const currentRight = parseInt(this.thumbPosition.right) || 20;
// 计算新位置
let newTop = currentTop + deltaY;
let newRight = currentRight - deltaX;
// 边界检查
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const thumbWidth = 260;
const thumbHeight = 160;
// 限制在窗口范围内
newTop = Math.max(0, Math.min(newTop, windowHeight - thumbHeight));
newRight = Math.max(0, Math.min(newRight, windowWidth - thumbWidth));
// 更新位置
this.thumbPosition = {
top: newTop + 'px',
right: newRight + 'px',
left: 'auto',
bottom: 'auto'
};
// 更新起始位置
this.dragStartX = event.clientX;
this.dragStartY = event.clientY;
}
},
// 停止拖动
stopDrag() {
// 移除全局事件监听
document.removeEventListener('mousemove', this.onDrag);
document.removeEventListener('mouseup', this.stopDrag);
// 恢复样式
if (this.$refs.thumbContainer) {
this.$refs.thumbContainer.style.cursor = 'grab';
}
// 延迟重置拖动状态,避免立即触发点击事件
setTimeout(() => {
this.isDragging = false;
this.dragDistance = 0;
}, 100);
},
// 处理缩略图(绿色线)点击/双击事件
onThumbLinePick(payload) {
try {
......@@ -1385,7 +1506,7 @@ export default {
},
// 测试缩略图方法
testThumb() {
console.log('[index2] ===== testThumb START =====');
//console.log('[index2] ===== testThumb START =====');
// 创建完全独立的测试容器
let testContainer = document.getElementById('thumb-test-container');
......@@ -1414,13 +1535,13 @@ export default {
document.body.appendChild(testContainer);
console.log('[index2] testThumb: independent container created');
console.log('[index2] testContainer size:', testContainer.clientWidth, 'x', testContainer.clientHeight);
console.log('[index2] ===== testThumb END =====');
//console.log('[index2] testThumb: independent container created');
//console.log('[index2] testContainer size:', testContainer.clientWidth, 'x', testContainer.clientHeight);
//console.log('[index2] ===== testThumb END =====');
},
// 测试ECharts方法
testECharts() {
console.log('[index2] ===== testECharts START =====');
//console.log('[index2] ===== testECharts START =====');
// 清理现有容器
let chartContainer = document.getElementById('thumb-chart-container');
......@@ -1452,7 +1573,7 @@ export default {
`);
// 验证样式是否应用
console.log('[index2] Chart container style after setAttribute:', chartContainer.style.position);
//console.log('[index2] Chart container style after setAttribute:', chartContainer.style.position);
// 创建ECharts实例
if (this.thumbChart) {
......@@ -1498,19 +1619,19 @@ export default {
};
this.thumbChart.setOption(testOption, true);
console.log('[index2] ECharts test chart created');
console.log('[index2] ===== testECharts END =====');
//console.log('[index2] ECharts test chart created');
//console.log('[index2] ===== testECharts END =====');
},
// 测试按钮点击
testButtonClick() {
console.log('[index2] ===== testButtonClick START =====');
//console.log('[index2] ===== testButtonClick START =====');
alert('按钮点击测试成功!');
console.log('[index2] ===== testButtonClick END =====');
//console.log('[index2] ===== testButtonClick END =====');
},
// 创建超级明显的缩略图测试
createSuperVisibleThumb() {
console.log('[index2] ===== createSuperVisibleThumb START =====');
//console.log('[index2] ===== createSuperVisibleThumb START =====');
// 清理现有容器
let container = document.getElementById('super-visible-thumb');
......@@ -1554,12 +1675,12 @@ export default {
</div>
`;
console.log('[index2] Super visible container created');
console.log('[index2] Container position:', container.getBoundingClientRect());
//console.log('[index2] Super visible container created');
//console.log('[index2] Container position:', container.getBoundingClientRect());
// 1秒后创建ECharts
setTimeout(() => {
console.log('[index2] Starting ECharts creation...');
//console.log('[index2] Starting ECharts creation...');
// 清理文字,准备ECharts
container.innerHTML = '';
......@@ -1576,16 +1697,16 @@ export default {
box-shadow: 0 0 20px rgba(0,0,255,0.8) !important;
`;
console.log('[index2] Container cleared and styled for ECharts');
console.log('[index2] Container position after styling:', container.getBoundingClientRect());
//console.log('[index2] Container cleared and styled for ECharts');
//console.log('[index2] Container position after styling:', container.getBoundingClientRect());
// 创建ECharts
if (this.thumbChart) {
try {
this.thumbChart.dispose();
console.log('[index2] Previous chart disposed');
//console.log('[index2] Previous chart disposed');
} catch (e) {
console.log('[index2] Error disposing previous chart:', e);
//console.log('[index2] Error disposing previous chart:', e);
}
}
......@@ -1594,7 +1715,7 @@ export default {
width: 300,
height: 200
});
console.log('[index2] ECharts instance created:', this.thumbChart);
//console.log('[index2] ECharts instance created:', this.thumbChart);
} catch (e) {
console.error('[index2] Error creating ECharts instance:', e);
return;
......@@ -1635,13 +1756,13 @@ export default {
try {
this.thumbChart.setOption(option, true);
console.log('[index2] ECharts option set successfully');
//console.log('[index2] ECharts option set successfully');
// 强制渲染
setTimeout(() => {
if (this.thumbChart) {
this.thumbChart.resize();
console.log('[index2] ECharts resized');
//console.log('[index2] ECharts resized');
}
}, 100);
......@@ -1649,33 +1770,33 @@ export default {
console.error('[index2] Error setting ECharts option:', e);
}
console.log('[index2] ECharts creation completed');
//console.log('[index2] ECharts creation completed');
}, 1000);
console.log('[index2] ===== createSuperVisibleThumb END =====');
//console.log('[index2] ===== createSuperVisibleThumb END =====');
},
// 重置缩略图方法
resetThumb() {
console.log('[index2] ===== resetThumb START =====');
//console.log('[index2] ===== resetThumb START =====');
// 清理独立容器
const testContainer = document.getElementById('thumb-test-container');
if (testContainer) {
testContainer.remove();
console.log('[index2] test container removed');
//console.log('[index2] test container removed');
}
const chartContainer = document.getElementById('thumb-chart-container');
if (chartContainer) {
chartContainer.remove();
console.log('[index2] chart container removed');
//console.log('[index2] chart container removed');
}
const superVisibleContainer = document.getElementById('super-visible-thumb');
if (superVisibleContainer) {
superVisibleContainer.remove();
console.log('[index2] super visible container removed');
//console.log('[index2] super visible container removed');
}
// 清理ECharts实例
......@@ -1683,7 +1804,7 @@ export default {
try {
this.thumbChart.dispose();
this.thumbChart = null;
console.log('[index2] ECharts instance disposed');
//console.log('[index2] ECharts instance disposed');
} catch (e) {
console.warn('[index2] Error disposing ECharts:', e);
}
......@@ -1694,15 +1815,15 @@ export default {
if (holder) {
holder.innerHTML = '';
holder.className = 'thumb-holder';
console.log('[index2] original container reset');
//console.log('[index2] original container reset');
}
console.log('[index2] resetThumb: all containers cleaned up');
console.log('[index2] ===== resetThumb END =====');
//console.log('[index2] resetThumb: all containers cleaned up');
//console.log('[index2] ===== resetThumb END =====');
},
// 备用缩略图初始化方法
async initThumbFallback() {
console.log('[index2] ===== initThumbFallback START =====');
//console.log('[index2] ===== initThumbFallback START =====');
try {
// 创建完全独立的ECharts容器
let chartContainer = document.getElementById('thumb-chart-container');
......@@ -1734,7 +1855,7 @@ export default {
`);
// 验证样式是否应用
console.log('[index2] Test chart container style after setAttribute:', chartContainer.style.position);
//console.log('[index2] Test chart container style after setAttribute:', chartContainer.style.position);
// 创建ECharts实例
if (this.thumbChart) {
......@@ -1788,32 +1909,32 @@ export default {
};
this.thumbChart.setOption(simpleOption, true);
console.log('[index2] Simple chart displayed');
//console.log('[index2] Simple chart displayed');
// 检查容器状态
console.log('[index2] Chart container position:', chartContainer.getBoundingClientRect());
console.log('[index2] Chart container style:', {
position: chartContainer.style.position,
top: chartContainer.style.top,
right: chartContainer.style.right,
width: chartContainer.style.width,
height: chartContainer.style.height,
zIndex: chartContainer.style.zIndex,
display: chartContainer.style.display,
visibility: chartContainer.style.visibility
});
//console.log('[index2] Chart container position:', chartContainer.getBoundingClientRect());
//console.log('[index2] Chart container style:', {
// position: chartContainer.style.position,
// top: chartContainer.style.top,
// right: chartContainer.style.right,
// width: chartContainer.style.width,
// height: chartContainer.style.height,
// zIndex: chartContainer.style.zIndex,
// display: chartContainer.style.display,
// visibility: chartContainer.style.visibility
// });
// 然后加载真实数据
await this.loadThumbData();
console.log('[index2] Data loaded, rendering real chart...');
//console.log('[index2] Data loaded, rendering real chart...');
this.renderThumb();
console.log('[index2] Fallback chart initialized successfully in independent container');
//console.log('[index2] Fallback chart initialized successfully in independent container');
} catch (e) {
console.error('[index2] initThumbFallback failed:', e);
}
console.log('[index2] ===== initThumbFallback END =====');
//console.log('[index2] ===== initThumbFallback END =====');
},
async loadThumbData() {
try {
......@@ -1823,11 +1944,11 @@ export default {
const query = route.query || {};
const id = params.zbid || query.zbid || params.id || query.id;
this.thumbId = id || null;
console.log('[index2] loadThumbData id:', id);
//console.log('[index2] loadThumbData id:', id);
// 如果没有id,使用测试数据
if (!id) {
console.log('[index2] No id found, using test data for thumbnail');
//console.log('[index2] No id found, using test data for thumbnail');
this.thumbPoints = [
{ name: '测试点1', x: 10, y: 20 },
{ name: '测试点2', x: 30, y: 40 },
......@@ -1841,19 +1962,19 @@ export default {
}
const res = await toDht(id);
const data = (res && (res.data !== undefined ? res.data : res)) || {};
console.log('[index2] loadThumbData res:', data);
console.log('[index2] data keys:', Object.keys(data));
//console.log('[index2] loadThumbData res:', data);
//console.log('[index2] data keys:', Object.keys(data));
// 井点
const list = Array.isArray(data.ysqqXmxxJxxList) ? data.ysqqXmxxJxxList : [];
console.log('[index2] jxxList length:', list.length);
console.log('[index2] jxxList sample:', list.slice(0, 2));
//console.log('[index2] jxxList length:', list.length);
//console.log('[index2] jxxList sample:', list.slice(0, 2));
this.thumbPoints = list
.filter(it => it && it.x != null && it.y != null)
.map(it => ({ name: String(it.jh || ''), x: Number(it.x), y: Number(it.y) }));
console.log('[index2] thumbPoints:', this.thumbPoints.length);
console.log('[index2] thumbPoints sample:', this.thumbPoints.slice(0, 2));
//console.log('[index2] thumbPoints:', this.thumbPoints.length);
//console.log('[index2] thumbPoints sample:', this.thumbPoints.slice(0, 2));
// 线(SEGY)
// 兼容两种返回结构:
// 1) { ysqqXmxxSegy: [...] }
......@@ -1862,13 +1983,13 @@ export default {
? data.ysqqXmxxSegy
: (Array.isArray(data) ? data : []);
if (!Array.isArray(data.ysqqXmxxSegy) && Array.isArray(data)) {
console.log('[index2] ysqqXmxxSegy not found, using top-level array as segy list');
//console.log('[index2] ysqqXmxxSegy not found, using top-level array as segy list');
}
// 存储完整的segy数据列表
this.segyList = segys;
this.currentSegyIndex = 0; // 重置为第一个
console.log('[index2] segyList length:', this.segyList.length);
console.log('[index2] segyList sample:', this.segyList.slice(0, 2));
//console.log('[index2] segyList length:', this.segyList.length);
//console.log('[index2] segyList sample:', this.segyList.slice(0, 2));
this.thumbLines = segys.map(seg => {
try {
......@@ -1882,7 +2003,7 @@ export default {
return ordered.map(p => [p.x, p.y]);
} catch (e) { return []; }
}).filter(line => line.length > 0);
console.log('[index2] thumbLines:', this.thumbLines.length);
//console.log('[index2] thumbLines:', this.thumbLines.length);
// 边界
const xs = [];
const ys = [];
......@@ -1893,11 +2014,11 @@ export default {
const yMin = ys.length ? Math.min(...ys) : null;
const yMax = ys.length ? Math.max(...ys) : null;
this.thumbBounds = { xMin, xMax, yMin, yMax };
console.log('[index2] thumbBounds:', this.thumbBounds);
//console.log('[index2] thumbBounds:', this.thumbBounds);
// 如果没有数据,添加测试数据来验证图表显示
if (this.thumbPoints.length === 0 && this.thumbLines.length === 0) {
console.log('[index2] 没有数据,添加测试数据');
//console.log('[index2] 没有数据,添加测试数据');
this.thumbPoints = [
{ name: '测试井1', x: 100, y: 200 },
{ name: '测试井2', x: 200, y: 300 },
......@@ -1907,7 +2028,7 @@ export default {
[[100, 200], [150, 250], [200, 300], [250, 280], [300, 150]]
];
this.thumbBounds = { xMin: 100, xMax: 300, yMin: 150, yMax: 300 };
console.log('[index2] 测试数据添加完成:', this.thumbPoints.length, 'points,', this.thumbLines.length, 'lines');
//console.log('[index2] 测试数据添加完成:', this.thumbPoints.length, 'points,', this.thumbLines.length, 'lines');
}
} catch (e) {
console.warn('[index2] loadThumbData failed:', e);
......@@ -1944,8 +2065,8 @@ export default {
yMax: yMax !== null && yMax !== undefined ? yMax : defaultRange.yMax
};
console.log('[index2] buildThumbOption range:', range);
console.log('[index2] buildThumbOption series count:', series.length);
//console.log('[index2] buildThumbOption range:', range);
//console.log('[index2] buildThumbOption series count:', series.length);
// 将数据归一化到 0~100 区间,保证在小图中清晰
const dx = Math.max(1e-9, range.xMax - range.xMin);
......@@ -2021,18 +2142,18 @@ export default {
console.warn('[index2] renderThumb: no chart instance');
return;
}
console.log('[index2] renderThumb: points', this.thumbPoints.length, 'lines', this.thumbLines.length);
//console.log('[index2] renderThumb: points', this.thumbPoints.length, 'lines', this.thumbLines.length);
try {
const option = this.buildThumbOption();
console.log('[index2] renderThumb option:', option);
//console.log('[index2] renderThumb option:', option);
this.thumbChart.setOption(option, true);
// 强制重新渲染
setTimeout(() => {
if (this.thumbChart) {
this.thumbChart.resize();
console.log('[index2] renderThumb: chart resized after render');
//console.log('[index2] renderThumb: chart resized after render');
}
}, 100);
} catch (e) {
......@@ -2050,10 +2171,10 @@ export default {
// 强制设置初始状态,确保不显示滚动条
if (this._isInitialLoad) {
console.log('强制设置初始尺寸,不显示滚动条:', {
width: this.baseCanvasWidth,
height: this.baseCanvasHeight
});
//console.log('强制设置初始尺寸,不显示滚动条:', {
// width: this.baseCanvasWidth,
// height: this.baseCanvasHeight
// });
}
}
} catch (e) { /* ignore */ }
......@@ -2087,11 +2208,11 @@ export default {
if (isInitialState || this._isInitialLoad) {
this.baseCanvasWidth = containerWidth;
this.baseCanvasHeight = containerHeight;
console.log('初始状态,保持容器尺寸:', {
containerSize: { width: containerWidth, height: containerHeight },
viewSize: { width: viewWidth, height: viewHeight },
isInitialLoad: this._isInitialLoad
});
//console.log('初始状态,保持容器尺寸:', {
// containerSize: { width: containerWidth, height: containerHeight },
// viewSize: { width: viewWidth, height: viewHeight },
// isInitialLoad: this._isInitialLoad
// });
return;
}
......@@ -2112,20 +2233,20 @@ export default {
this.baseCanvasWidth = scrollWidth;
this.baseCanvasHeight = scrollHeight;
console.log('用户缩放后更新滚动区域尺寸:', {
containerSize: { width: containerWidth, height: containerHeight },
currentLimits: {
width: viewWidth,
height: viewHeight,
left: currentLimits.getLeft(),
right: currentLimits.getRight(),
top: currentLimits.getTop(),
bottom: currentLimits.getBottom()
},
scaleX, scaleY,
newScrollWidth: scrollWidth,
newScrollHeight: scrollHeight
});
//console.log('用户缩放后更新滚动区域尺寸:', {
// containerSize: { width: containerWidth, height: containerHeight },
// currentLimits: {
// width: viewWidth,
// height: viewHeight,
// left: currentLimits.getLeft(),
// right: currentLimits.getRight(),
// top: currentLimits.getTop(),
// bottom: currentLimits.getBottom()
// },
// scaleX, scaleY,
// newScrollWidth: scrollWidth,
// newScrollHeight: scrollHeight
// });
}
}
} catch (e) {
......@@ -2158,29 +2279,29 @@ export default {
// 方法1: 禁用滚动交互
if (widget.setScrollEnabled) {
widget.setScrollEnabled(false);
console.log('已禁用widget滚动交互');
//console.log('已禁用widget滚动交互');
}
// 方法2: 禁用所有鼠标交互
if (widget.setMouseInteractionsEnabled) {
widget.setMouseInteractionsEnabled(false);
console.log('已禁用widget鼠标交互');
//console.log('已禁用widget鼠标交互');
}
// 尝试其他可能的交互禁用方法
if (widget.setInteractionsEnabled) {
widget.setInteractionsEnabled(false);
console.log('已禁用widget交互');
//console.log('已禁用widget交互');
}
if (widget.setWheelEnabled) {
widget.setWheelEnabled(false);
console.log('已禁用widget滚轮交互');
//console.log('已禁用widget滚轮交互');
}
if (widget.setPanEnabled) {
widget.setPanEnabled(false);
console.log('已禁用widget平移交互');
//console.log('已禁用widget平移交互');
}
// 方法3: 通过setOptions禁用
......@@ -2314,10 +2435,10 @@ export default {
this.baseCanvasHeight = rect.height;
this._isInitialLoad = true;
console.log('强制重置到初始状态:', {
width: this.baseCanvasWidth,
height: this.baseCanvasHeight
});
//console.log('强制重置到初始状态:', {
// width: this.baseCanvasWidth,
// height: this.baseCanvasHeight
// });
}
} catch (e) {
console.warn('重置初始状态失败:', e);
......@@ -2577,7 +2698,7 @@ export default {
} catch (e) { }
}, 100);
console.log('内部滚动条已强制禁用');
//console.log('内部滚动条已强制禁用');
} catch (error) {
console.warn('禁用内部滚动条时出错:', error);
}
......@@ -2620,7 +2741,7 @@ export default {
}
});
console.log('滚动条监控已执行一次');
//console.log('滚动条监控已执行一次');
} catch (e) {
console.warn('滚动条监控失败:', e);
}
......@@ -2738,7 +2859,7 @@ export default {
].join('\n');
widget.setCss(css);
console.log('已通过CSS方法彻底禁用内部滚动条');
//console.log('已通过CSS方法彻底禁用内部滚动条');
} catch (error) {
console.warn('设置滚动条CSS失败:', error);
}
......@@ -2757,7 +2878,7 @@ export default {
this.setupOuterScrollbarSync();
// 启动外层滚动条同步监控
this.startOuterScrollbarSyncMonitor();
console.log('已彻底禁用内部滚动条并启用外层滚动条同步')
//console.log('已彻底禁用内部滚动条并启用外层滚动条同步')
} catch (error) {
console.warn('启用外层滚动条同步失败:', error);
}
......@@ -2829,7 +2950,7 @@ export default {
bottomContainer.addEventListener('scroll', this._syncFromBottomOuter);
this._outerScrollListeners.push({ element: bottomContainer, event: 'scroll', handler: this._syncFromBottomOuter });
console.log('外层滚动条同步已设置(GeoToolkit 3.2.80兼容模式)');
//console.log('外层滚动条同步已设置(GeoToolkit 3.2.80兼容模式)');
} catch (error) {
console.warn('设置外层滚动条同步失败:', error);
}
......@@ -2875,7 +2996,7 @@ export default {
const bottomScrollbars = this.findScrollbarElements(this._seismicWidgetBottom);
if (topScrollbars.length === 0 || bottomScrollbars.length === 0) {
console.log('未找到滚动条DOM元素,跳过DOM同步');
//console.log('未找到滚动条DOM元素,跳过DOM同步');
return;
}
......@@ -2929,7 +3050,7 @@ export default {
this._domScrollListeners.push({ element: scrollbar, event: 'scroll', handler: onBottomScroll });
});
console.log('DOM级别滚动条同步已设置');
//console.log('DOM级别滚动条同步已设置');
} catch (e) {
console.warn('设置DOM滚动条同步失败:', e);
}
......@@ -3118,7 +3239,7 @@ export default {
// 方法4: (禁用)不再启动强力隐藏监控
// this.startAggressiveScrollbarHideMonitor();
console.log('已强制隐藏所有内部滚动条');
//console.log('已强制隐藏所有内部滚动条');
} catch (e) {
console.warn('强制隐藏内部滚动条失败:', e);
}
......@@ -3139,7 +3260,7 @@ export default {
// 禁用滚动条交互
this.disableScrollbarInteractions();
console.log('滚动条隐藏监控已执行一次');
//console.log('滚动条隐藏监控已执行一次');
} catch (e) {
console.warn('滚动条隐藏监控失败:', e);
}
......@@ -3196,18 +3317,18 @@ export default {
// 测试外层滚动条同步(GeoToolkit 3.2.80兼容)
testOuterScrollbarSync() {
try {
console.log('=== 测试外层滚动条同步 ===');
//console.log('=== 测试外层滚动条同步 ===');
// 获取外层滚动容器
const topContainer = this.getOuterScrollContainer(this._seismicWidget);
const bottomContainer = this.getOuterScrollContainer(this._seismicWidgetBottom);
console.log('顶部容器:', topContainer);
console.log('底部容器:', bottomContainer);
//console.log('顶部容器:', topContainer);
//console.log('底部容器:', bottomContainer);
if (topContainer && bottomContainer) {
console.log('顶部容器滚动位置:', { scrollLeft: topContainer.scrollLeft, scrollTop: topContainer.scrollTop });
console.log('底部容器滚动位置:', { scrollLeft: bottomContainer.scrollLeft, scrollTop: bottomContainer.scrollTop });
//console.log('顶部容器滚动位置:', { scrollLeft: topContainer.scrollLeft, scrollTop: topContainer.scrollTop });
//console.log('底部容器滚动位置:', { scrollLeft: bottomContainer.scrollLeft, scrollTop: bottomContainer.scrollTop });
// 测试同步
const testScrollLeft = 100;
......@@ -3216,23 +3337,23 @@ export default {
topContainer.scrollLeft = testScrollLeft;
topContainer.scrollTop = testScrollTop;
console.log('设置顶部容器滚动位置:', { scrollLeft: testScrollLeft, scrollTop: testScrollTop });
//console.log('设置顶部容器滚动位置:', { scrollLeft: testScrollLeft, scrollTop: testScrollTop });
// 检查同步是否生效
setTimeout(() => {
console.log('同步后底部容器滚动位置:', {
scrollLeft: bottomContainer.scrollLeft,
scrollTop: bottomContainer.scrollTop
});
//console.log('同步后底部容器滚动位置:', {
// scrollLeft: bottomContainer.scrollLeft,
// scrollTop: bottomContainer.scrollTop
// });
if (bottomContainer.scrollLeft === testScrollLeft && bottomContainer.scrollTop === testScrollTop) {
console.log('✅ 外层滚动条同步测试成功!');
//console.log('✅ 外层滚动条同步测试成功!');
} else {
console.log('❌ 外层滚动条同步测试失败!');
//console.log('❌ 外层滚动条同步测试失败!');
}
}, 100);
} else {
console.log('❌ 未找到外层滚动容器');
//console.log('❌ 未找到外层滚动容器');
}
} catch (e) {
console.error('测试外层滚动条同步失败:', e);
......@@ -3242,7 +3363,7 @@ export default {
// 测试内部滚动条是否被隐藏
testInternalScrollbarHidden() {
try {
console.log('=== 测试内部滚动条是否被隐藏 ===');
//console.log('=== 测试内部滚动条是否被隐藏 ===');
// 查找所有可能的滚动条元素
const scrollbarSelectors = [
......@@ -3271,14 +3392,14 @@ export default {
});
if (foundScrollbars.length === 0) {
console.log('✅ 未找到任何可见的内部滚动条!');
//console.log('✅ 未找到任何可见的内部滚动条!');
} else {
console.log('❌ 发现以下可见的内部滚动条:');
//console.log('❌ 发现以下可见的内部滚动条:');
foundScrollbars.forEach((item, index) => {
console.log(`${index + 1}. 选择器: ${item.selector}`);
console.log(` 可见性: ${item.visible ? '可见' : '隐藏'}`);
console.log(` 尺寸: ${item.dimensions.width}x${item.dimensions.height}`);
console.log(` 元素:`, item.element);
//console.log(`${index + 1}. 选择器: ${item.selector}`);
//console.log(` 可见性: ${item.visible ? '可见' : '隐藏'}`);
//console.log(` 尺寸: ${item.dimensions.width}x${item.dimensions.height}`);
//console.log(` 元素:`, item.element);
});
// 尝试强制隐藏这些滚动条
......@@ -3286,7 +3407,7 @@ export default {
this.hideScrollbarElement(item.element);
});
console.log('已尝试强制隐藏发现的滚动条');
//console.log('已尝试强制隐藏发现的滚动条');
}
} catch (e) {
console.error('测试内部滚动条隐藏失败:', e);
......@@ -3341,7 +3462,7 @@ export default {
// 方法3: 通过CSS强制隐藏
this.addForceHideScrollbarCSS();
console.log('已强制禁用内部滚动条');
//console.log('已强制禁用内部滚动条');
} catch (error) {
console.warn('强制禁用内部滚动条失败:', error);
}
......@@ -3487,7 +3608,7 @@ export default {
// 不再注入全局隐藏滚动条CSS,避免影响布局
// this.addGlobalScrollbarHideCSS();
console.log('已强制禁用所有内部滚动条');
//console.log('已强制禁用所有内部滚动条');
} catch (e) {
console.warn('强制禁用滚动条失败:', e);
}
......@@ -3695,7 +3816,7 @@ export default {
setTimeout(() => {
// 只在用户主动操作后才更新滚动区域
// 初始加载时不调用 updateScrollAreaSize
console.log('数据加载完成,保持初始尺寸');
//console.log('数据加载完成,保持初始尺寸');
}, 1000);
// 强制禁用内部滚动条
this.forceDisableInternalScrollbars(this._seismicWidget);
......@@ -3721,9 +3842,43 @@ export default {
}
},
handleFileSelect(plot) {
let url = process.env.VUE_APP_BASE_API + "/ndy/dz/getSegyDataFile?fileName=density.segy";
let fileName = 'density.segy';
async handleFileSelect(plot) {
let segys = [];
try {
// 使用 toDht 接口获取数据
//console.log('[handleFileSelect] 开始获取数据,routeId:', this.routeId);
const res = await toDht(this.routeId);
console.log('[handleFileSelect] toDht 接口返回:', res);
const data = (res && (res.data !== undefined ? res.data : res)) || {};
console.log('[handleFileSelect] 解析后的数据:', data);
// 从 ysqqXmxxSegy 数组中获取 jbsegy 字段
segys = Array.isArray(data.ysqqXmxxSegy) ? data.ysqqXmxxSegy : [];
console.log('[handleFileSelect] ysqqXmxxSegy 数组:', segys);
if (segys.length === 0) {
throw new Error('未找到 SEGY 数据');
}
} catch (error) {
console.error('[handleFileSelect] 获取数据失败:', error);
this.loadingError = `获取数据失败: ${error.message}`;
throw error;
}
// 使用第一个 SEGY 数据的 jbsegy 字段
const firstSegy = segys[0];
console.log('[handleFileSelect] 第一个 SEGY 数据:', firstSegy);
let url = firstSegy.jbsegy;
if (url && !url.startsWith('http')) {
url = process.env.VUE_APP_BASE_API + url;
}
let fileName = firstSegy.jbsegyName || 'density.segy';
console.log('[handleFileSelect] 最终 URL:', url);
console.log('[handleFileSelect] 文件名:', fileName);
return fetch(url, {
headers: {
......@@ -3858,7 +4013,7 @@ export default {
// 延迟调用fitToBounds,确保初始状态稳定
setTimeout(() => {
this._seismicWidget.fitToBounds();
console.log('数据加载完成,调用fitToBounds');
//console.log('数据加载完成,调用fitToBounds');
// 再次确保内部滚动条被禁用
this.setScrollbarCSS(this._seismicWidget);
......@@ -3867,7 +4022,7 @@ export default {
// 再延迟标记初始加载结束
setTimeout(() => {
this._isInitialLoad = false;
console.log('初始加载完成,启用滚动区域更新');
//console.log('初始加载完成,启用滚动区域更新');
// 最终确认内部滚动条被禁用
this.setScrollbarCSS(this._seismicWidget);
......@@ -3997,10 +4152,10 @@ export default {
const node = command.getNode();
if (node) {
this.annotations.addChild(node);
console.log('开始编辑:', {
type: node.getType ? node.getType() : '未知类型',
properties: node.getProperties()
});
//console.log('开始编辑:', {
// type: node.getType ? node.getType() : '未知类型',
// properties: node.getProperties()
// });
}
})
.addListener(EditEvents.End, (tool, node) => {
......@@ -4009,10 +4164,10 @@ export default {
tool.editNode(node);
this.selectedShape = node;
this.saveAnnotation(node);
console.log('编辑完成:', {
type: node.getType ? node.getType() : '未知类型',
properties: node.getProperties()
});
//console.log('编辑完成:', {
// type: node.getType ? node.getType() : '未知类型',
// properties: node.getProperties()
// });
}
this.requestRepaint();
});
......@@ -4023,7 +4178,7 @@ export default {
// 设置就绪状态
this.isWidgetReady = true;
console.log('注释工具初始化完成');
//console.log('注释工具初始化完成');
// 强制禁用底部widget的内部滚动条
if (this._seismicWidgetBottom) {
......@@ -4090,32 +4245,32 @@ export default {
}
};
console.log('文本绘制工具配置:', textProperties);
//console.log('文本绘制工具配置:', textProperties);
this.annotationTool.setProperties(textProperties);
// 添加事件监听器来打印文本绘制数据
this.annotationTool.addListener(EditEvents.Start, (tool, command) => {
const node = command.getNode();
const textStyle = node.getTextStyle ? node.getTextStyle() : null;
console.log('开始绘制文本:', {
tool: tool.getMode(),
node: {
type: node.getType ? node.getType() : 'unknown',
properties: node.getProperties(),
bounds: node.getBounds ? node.getBounds() : null
},
textStyle: {
font: textStyle ? textStyle.getFont() : null,
color: textStyle ? textStyle.getColor() : null,
size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
alignment: textStyle ? textStyle.getAlignment() : null
},
currentToolConfig: {
mode: tool.getMode(),
editMode: tool.getEditMode(),
isEnabled: tool.isEnabled()
}
});
// console.log('开始绘制文本:', {
// tool: tool.getMode(),
// node: {
// type: node.getType ? node.getType() : 'unknown',
// properties: node.getProperties(),
// bounds: node.getBounds ? node.getBounds() : null
// },
// textStyle: {
// font: textStyle ? textStyle.getFont() : null,
// color: textStyle ? textStyle.getColor() : null,
// size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
// alignment: textStyle ? textStyle.getAlignment() : null
// },
// currentToolConfig: {
// mode: tool.getMode(),
// editMode: tool.getEditMode(),
// isEnabled: tool.isEnabled()
// }
// });
});
this.annotationTool.addListener(EditEvents.Change, (tool, event) => {
......@@ -4123,23 +4278,23 @@ export default {
if (node) {
const textStyle = node.getTextStyle ? node.getTextStyle() : null;
const previousState = node._previousState || {};
console.log('文本绘制更新:', {
previous: {
properties: previousState.properties || {},
textStyle: previousState.textStyle || {}
},
current: {
properties: node.getProperties(),
bounds: node.getBounds ? node.getBounds() : null,
textStyle: {
font: textStyle ? textStyle.getFont() : null,
color: textStyle ? textStyle.getColor() : null,
size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
alignment: textStyle ? textStyle.getAlignment() : null
}
},
changes: this.detectChanges(previousState, node)
});
//console.log('文本绘制更新:', {
// previous: {
// properties: previousState.properties || {},
// textStyle: previousState.textStyle || {}
// },
// current: {
// properties: node.getProperties(),
// bounds: node.getBounds ? node.getBounds() : null,
// textStyle: {
// font: textStyle ? textStyle.getFont() : null,
// color: textStyle ? textStyle.getColor() : null,
// size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
// alignment: textStyle ? textStyle.getAlignment() : null
// }
// },
// changes: this.detectChanges(previousState, node)
// });
// 保存当前状态用于下次比较
node._previousState = {
properties: { ...node.getProperties() },
......@@ -4165,32 +4320,32 @@ export default {
}
const textStyle = node.getTextStyle ? node.getTextStyle() : null;
console.log('文本绘制完成:', {
node: {
type: node.getType ? node.getType() : 'unknown',
text: text,
properties: node.getProperties(),
bounds: node.getBounds ? node.getBounds() : null
},
styles: {
text: {
font: textStyle ? textStyle.getFont() : null,
color: textStyle ? textStyle.getColor() : null,
size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
alignment: textStyle ? textStyle.getAlignment() : null
},
line: node.getLineStyle ? node.getLineStyle() : null,
fill: node.getFillStyle ? node.getFillStyle() : null
},
validation: {
isValid: Boolean(node && node.getText),
hasRequiredProperties: Boolean(
node.getProperties().ax !== undefined &&
node.getProperties().ay !== undefined
),
hasStyles: Boolean(textStyle)
}
});
//console.log('文本绘制完成:', {
// node: {
// type: node.getType ? node.getType() : 'unknown',
// text: text,
// properties: node.getProperties(),
// bounds: node.getBounds ? node.getBounds() : null
// },
// styles: {
// text: {
// font: textStyle ? textStyle.getFont() : null,
// color: textStyle ? textStyle.getColor() : null,
// size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
// alignment: textStyle ? textStyle.getAlignment() : null
// },
// line: node.getLineStyle ? node.getLineStyle() : null,
// fill: node.getFillStyle ? node.getFillStyle() : null
// },
// validation: {
// isValid: Boolean(node && node.getText),
// hasRequiredProperties: Boolean(
// node.getProperties().ax !== undefined &&
// node.getProperties().ay !== undefined
// ),
// hasStyles: Boolean(textStyle)
// }
// });
}
this.requestRepaint();
});
......@@ -4267,28 +4422,28 @@ export default {
});
// 打印更新后的样式数据
console.log('样式更新:', {
type: shape.getType ? shape.getType() : '未知类型',
text: shape.getText ? shape.getText() : null,
properties: shape.getProperties(),
textStyle: {
font: fontString,
color: this.textStyle.color,
size: this.textStyle.size,
alignment: this.textStyle.align,
bold: this.textStyle.bold,
italic: this.textStyle.italic
},
lineStyle: {
color: this.lineStyle.color,
width: this.lineStyle.width,
pattern: this.lineStyle.pattern
},
fillStyle: {
color: this.fillStyle.color,
pattern: this.fillStyle.pattern
}
});
// console.log('样式更新:', {
// type: shape.getType ? shape.getType() : '未知类型',
// text: shape.getText ? shape.getText() : null,
// properties: shape.getProperties(),
// textStyle: {
// font: fontString,
// color: this.textStyle.color,
// size: this.textStyle.size,
// alignment: this.textStyle.align,
// bold: this.textStyle.bold,
// italic: this.textStyle.italic
// },
// lineStyle: {
// color: this.lineStyle.color,
// width: this.lineStyle.width,
// pattern: this.lineStyle.pattern
// },
// fillStyle: {
// color: this.fillStyle.color,
// pattern: this.fillStyle.pattern
// }
// });
// 强制重绘
if (shape.invalidate) {
......@@ -4320,16 +4475,16 @@ export default {
});
// 打印更新的文本数据
console.log('更新已存在的文本:', {
text: shape.getText(),
properties: shape.getProperties(),
textStyle: {
font: fontString,
size: value,
color: this.textStyle.color,
alignment: this.textStyle.align
}
});
// console.log('更新已存在的文本:', {
// text: shape.getText(),
// properties: shape.getProperties(),
// textStyle: {
// font: fontString,
// size: value,
// color: this.textStyle.color,
// alignment: this.textStyle.align
// }
// });
}
});
}
......@@ -4360,15 +4515,15 @@ export default {
});
// 打印更新的文本数据
console.log('更新已存在的文本:', {
text: shape.getText(),
properties: shape.getProperties(),
textStyle: {
font: fontString,
color: this.textStyle.color,
alignment: this.textStyle.align
}
});
// console.log('更新已存在的文本:', {
// text: shape.getText(),
// properties: shape.getProperties(),
// textStyle: {
// font: fontString,
// color: this.textStyle.color,
// alignment: this.textStyle.align
// }
// });
}
});
}
......@@ -4408,15 +4563,15 @@ export default {
});
// 打印更新后的线条样式数据
console.log('线条样式更新:', {
type: this.selectedShape.getType ? this.selectedShape.getType() : '未知类型',
properties: this.selectedShape.getProperties(),
lineStyle: {
color: this.lineStyle.color,
width: this.lineStyle.width,
pattern: this.lineStyle.pattern
}
});
// console.log('线条样式更新:', {
// type: this.selectedShape.getType ? this.selectedShape.getType() : '未知类型',
// properties: this.selectedShape.getProperties(),
// lineStyle: {
// color: this.lineStyle.color,
// width: this.lineStyle.width,
// pattern: this.lineStyle.pattern
// }
// });
this.requestRepaint();
}
......@@ -4433,15 +4588,15 @@ export default {
});
// 打印每个更新的线条数据
console.log('更新已存在的线条:', {
type: shape.getType ? shape.getType() : '未知类型',
properties: shape.getProperties(),
lineStyle: {
color: this.lineStyle.color,
width: this.lineStyle.width,
pattern: this.lineStyle.pattern
}
});
// console.log('更新已存在的线条:', {
// type: shape.getType ? shape.getType() : '未知类型',
// properties: shape.getProperties(),
// lineStyle: {
// color: this.lineStyle.color,
// width: this.lineStyle.width,
// pattern: this.lineStyle.pattern
// }
// });
}
});
}
......@@ -4551,7 +4706,7 @@ export default {
}
// 默认返回空数组(实线)
console.log('使用默认实线模式,无法识别模式:', pattern);
//console.log('使用默认实线模式,无法识别模式:', pattern);
return [];
},
......@@ -4706,7 +4861,7 @@ export default {
this.plots.redraw();
}
console.log(`成功切换到颜色映射: ${colorMapName}`);
//console.log(`成功切换到颜色映射: ${colorMapName}`);
} catch (error) {
console.error(`切换颜色映射失败: ${error.message}`);
}
......@@ -4980,7 +5135,7 @@ export default {
});
console.log('颜色映射注册成功');
//console.log('颜色映射注册成功');
} catch (error) {
console.error('注册颜色映射失败:', error);
}
......@@ -5028,34 +5183,34 @@ export default {
}
};
console.log('线条绘制工具配置:', pencilProperties);
//console.log('线条绘制工具配置:', pencilProperties);
this.pencilTool = new Paint(pencilProperties);
// 添加事件监听
this.pencilTool
.addListener(EditEvents.Start, (tool, command) => {
const node = command.getNode();
console.log('开始绘制线条:', {
tool: tool.getMode(),
properties: node.getProperties()
});
// console.log('开始绘制线条:', {
// tool: tool.getMode(),
// properties: node.getProperties()
// });
this.annotations.addChild(node);
})
.addListener(EditEvents.Change, (tool, event) => {
const node = tool.getShape();
if (node) {
console.log('线条绘制更新:', {
properties: node.getProperties(),
bounds: node.getBounds ? node.getBounds() : null
});
// console.log('线条绘制更新:', {
// properties: node.getProperties(),
// bounds: node.getBounds ? node.getBounds() : null
// });
}
})
.addListener(EditEvents.End, (tool, node) => {
if (node) {
console.log('线条绘制完成:', {
properties: node.getProperties(),
bounds: node.getBounds ? node.getBounds() : null
});
// console.log('线条绘制完成:', {
// properties: node.getProperties(),
// bounds: node.getBounds ? node.getBounds() : null
// });
}
if (node && this.annotations.indexOfChild(node) === -1) {
......@@ -5142,14 +5297,14 @@ export default {
// 如果没有活动工具,则不显示菜单
if (!activeTool) {
console.log('No active tool');
//console.log('No active tool');
return;
}
// 获取当前选中的形状
const currentShape = activeTool.getShape();
if (!currentShape) {
console.log('No shape selected');
//console.log('No shape selected');
return;
}
......@@ -5164,12 +5319,12 @@ export default {
// 记录当前右键菜单使用的工具
this._contextMenuTool = activeTool;
console.log('Context menu shown:', {
x: this.contextMenu.x,
y: this.contextMenu.y,
tool: activeTool.getMode(),
shape: currentShape ? currentShape.getType() : null
});
// //console.log('Context menu shown:', {
// x: this.contextMenu.x,
// y: this.contextMenu.y,
// tool: activeTool.getMode(),
// shape: currentShape ? currentShape.getType() : null
// });
event.stopPropagation();
},
......@@ -5181,7 +5336,7 @@ export default {
if (this.contextMenu.visible) {
this.contextMenu.visible = false;
this._contextMenuTool = null;
console.log('Context menu hidden');
//console.log('Context menu hidden');
}
},
......@@ -5470,14 +5625,14 @@ export default {
hasStyles: Boolean(textStyle && node.getLineStyle && node.getFillStyle)
};
console.log('标注数据验证:', validation);
//console.log('标注数据验证:', validation);
if (Object.values(validation).every(v => v)) {
this.savedAnnotations.push(annotationData);
console.log('标注数据已保存:', {
data: annotationData,
totalAnnotations: this.savedAnnotations.length
});
// console.log('标注数据已保存:', {
// data: annotationData,
// totalAnnotations: this.savedAnnotations.length
// });
} else {
console.warn('标注数据验证失败:', validation);
}
......@@ -5507,9 +5662,9 @@ export default {
}
try {
console.log('开始恢复文本标注:', {
totalAnnotations: this.savedAnnotations.length
});
// console.log('开始恢复文本标注:', {
// totalAnnotations: this.savedAnnotations.length
// });
// 恢复文本标注
this.savedAnnotations.forEach((data, index) => {
......@@ -5545,10 +5700,10 @@ export default {
textNode.setProperties(fullProperties);
this.annotations.addChild(textNode);
console.log(`恢复文本标注 ${index + 1}/${this.savedAnnotations.length}:`, {
text: data.text || data.properties.text,
position: { x: data.properties.ax, y: data.properties.ay }
});
//console.log(`恢复文本标注 ${index + 1}/${this.savedAnnotations.length}:`, {
// text: data.text || data.properties.text,
// position: { x: data.properties.ax, y: data.properties.ay }
// });
} catch (error) {
console.error(`恢复文本标注 ${index + 1} 时出错:`, {
error: error.message,
......@@ -5583,9 +5738,9 @@ export default {
}
try {
console.log('开始恢复线条标注:', {
totalLines: this.savedLineAnnotations.length
});
// console.log('开始恢复线条标注:', {
// totalLines: this.savedLineAnnotations.length
// });
this.savedLineAnnotations.forEach((data, index) => {
try {
......@@ -5620,11 +5775,11 @@ export default {
// 添加到标注层
this.annotations.addChild(path);
console.log(`恢复线条标注 ${index + 1}/${this.savedLineAnnotations.length}:`, {
points: data.properties.x.length,
style: lineStyle,
bounds: data.bounds
});
// console.log(`恢复线条标注 ${index + 1}/${this.savedLineAnnotations.length}:`, {
// points: data.properties.x.length,
// style: lineStyle,
// bounds: data.bounds
// });
} catch (error) {
console.error(`恢复线条标注 ${index + 1} 时出错:`, {
error: error.message,
......@@ -5692,7 +5847,7 @@ export default {
// 强制重绘
this._seismicWidget.invalidate();
console.log('文本标注已创建在指定位置');
//console.log('文本标注已创建在指定位置');
} catch (error) {
console.error('创建文本标注时出错:', error);
}
......@@ -5884,7 +6039,6 @@ export default {
align-items: flex-start;
justify-content: space-between;
gap: 12px;
margin-bottom: 110px;
/* 顶部操作与地震图拉开距离 */
min-width: 100%;
/* 确保有足够宽度 */
......@@ -5952,6 +6106,45 @@ export default {
/* 固定定位的缩略图,确保始终可见 */
/* 移除模板内固定块样式(改为全局 body 容器) */
/* 可拖动的缩略图样式 */
.draggable-thumb {
cursor: grab;
user-select: none;
transition: none; /* 拖动时禁用过渡动画 */
}
.draggable-thumb:active {
cursor: grabbing;
}
.drag-handle {
position: absolute;
top: 5px;
right: 5px;
width: 20px;
height: 20px;
background: rgba(0, 0, 0, 0.6);
color: white;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
cursor: grab;
z-index: 10;
opacity: 0.7;
transition: opacity 0.2s;
}
.drag-handle:hover {
opacity: 1;
background: rgba(0, 0, 0, 0.8);
}
.drag-handle:active {
cursor: grabbing;
}
/* 双画布容器与滚动/缩放 */
.split-container {
display: flex;
......@@ -6753,14 +6946,14 @@ export default {
top: -9999px !important;
}
/* 确保外层滚动区域可以接收鼠标事件 */
/* 外层滚动区域样式*/
.sync-section {
pointer-events: auto !important;
}
.sync-section::-webkit-scrollbar {
width: 12px;
height: 12px;
width: 4px;
height: 4px;
}
.sync-section::-webkit-scrollbar-track {
......@@ -6769,7 +6962,7 @@ export default {
.sync-section::-webkit-scrollbar-thumb {
background: #888;
border-radius: 6px;
border-radius: 3px;
}
.sync-section::-webkit-scrollbar-thumb:hover {
......@@ -6790,4 +6983,36 @@ export default {
max-height: 160px;
overflow: hidden;
}
/* 缩略图弹窗样式 - 确保不被遮挡 */
.thumbnail-dialog {
z-index: 9999999 !important;
}
.thumbnail-dialog .el-dialog {
z-index: 9999999 !important;
}
.thumbnail-dialog .el-dialog__wrapper {
z-index: 9999999 !important;
}
.thumbnail-dialog .el-overlay {
z-index: 9999998 !important;
}
/* 确保弹窗内容完全可见 */
.thumbnail-dialog .el-dialog__body {
overflow: visible !important;
max-height: none !important;
}
/* 修复可能的容器遮挡问题 */
.app-containers {
overflow: visible !important;
}
.containerBlock {
overflow: visible !important;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment