Compare commits

...

4 Commits

Author SHA1 Message Date
80937518651731347 7b8dfb496f updated 2026-04-07 08:41:39 +08:00
80937518651731347 9e56963d70 updated 2026-04-07 08:27:40 +08:00
80937518651731347 104766dbe9 Merge branch 'master' of http://124.222.8.13:3000/revisit/DSDSWeb 2026-04-03 14:14:46 +08:00
80937518651731347 a4f9cbd60f 调整banner 2026-04-03 14:14:42 +08:00
21 changed files with 544 additions and 222 deletions

View File

@ -17,8 +17,6 @@ module.exports = merge(prodEnv, {
// VUE_APP_API_URL: '"http://10.10.150.237/"'
VUE_APP_BASE_API: '"/api"',
/** 仅参航科学家报表;与生产一致直连 https服务端 CORS 已放开,避免本地代理 404 */
VUE_APP_UNIT_MEMBER_REPORT_BASE: '"https://weixin.bdsmart.cn/ds1"',
// VUE_APP_BASE_APIURL: '"http://ds2.hzzxq.com/api2"',
VUE_APP_BASE_APIURL: '"http://test.gopmas.com/ds"',
VUE_APP_FULL_API: '"http://10.10.151.5:5555"',

View File

@ -11,12 +11,12 @@ module.exports = {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
/**
* 参航科学家接口单独转发到 weixin须写在通用 /api 之前避免被旧后端吞掉
* unitMember 使用 /ds1-report-proxy /api 时的兜底一致
* 使用数组保证匹配顺序必须先于通配 `/api`否则 unit 会落到 gopmas 导致 404
*/
'/api/report/unit/member.htm': {
proxyTable: [
{
context: '/api/report/unit/member.htm',
target: 'https://weixin.bdsmart.cn',
changeOrigin: true,
secure: true,
@ -24,30 +24,43 @@ module.exports = {
'^/api': '/ds1'
}
},
'/api': {
// target: 'http://120.48.105.88', // 线上
// target: 'http://10.0.90.70', // 测试环境
// target: 'http://1.95.42.191:8080', // 测试环境
// target: 'http://ds2.hzzxq.com/api2', // 测试环境
{
context: '/api/report/unit/total.htm',
target: 'https://weixin.bdsmart.cn',
changeOrigin: true,
secure: true,
pathRewrite: {
'^/api': '/ds1'
}
},
{
context: '/api/report/ship/total.htm',
target: 'https://weixin.bdsmart.cn',
changeOrigin: true,
secure: true,
pathRewrite: {
'^/api': '/ds1'
}
},
{
context: '/api',
target: 'http://test.gopmas.com/ds', // 测试环境
changeOrigin: true, // 是否跨域
secure: false, // 是否使用https
changeOrigin: true,
secure: false,
pathRewrite: {
'^/api': '' // 线上
// '^/service': '/service' //线上
'^/api': ''
}
},
'/geoserver': {
// target: 'http://120.48.105.88', // 线上
{
context: '/geoserver',
target: 'http://124.222.8.13:9801', // 测试环境
changeOrigin: true, // 是否跨域
secure: false, // 是否使用https
changeOrigin: true,
secure: false,
pathRewrite: {
'^/geoserver': '/geoserver' // 线上
// '^/service': '/service' //线上
'^/geoserver': '/geoserver'
}
}
},
],
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST

View File

@ -16,8 +16,6 @@ module.exports = {
// VUE_APP_BASE_API: '"/api"',
// VUE_APP_BASE_APIURL: '"http://ds.hzzxq.com/api"',
VUE_APP_BASE_API: '"./"',
/** 仅参航科学家报表 report/unit/member.htm 使用,与全局 VUE_APP_BASE_API 解耦 */
VUE_APP_UNIT_MEMBER_REPORT_BASE: '"https://weixin.bdsmart.cn/ds1"',
VUE_APP_BASE_APIURL: '"./"',
VUE_APP_FULL_API: '"http://10.10.151.3:5555"',
VUE_APP_BASE_API_FRONT: '"http://10.10.150.128:8080/satellitePub/pub/index.html"',

BIN
dist.zip Normal file

Binary file not shown.

View File

@ -10,6 +10,20 @@ export function reportList(data) {
})
}
/**
* 按平台类型查询平台名称列表统计页 banner 下拉
* 对应 `GET /report/platform/name.htm?platform_type=...`
* @param {string} [platformType='水下自主式无人潜器'] 与后端 platform_type 一致
* @returns {Promise}
*/
export function platformNameList(platformType = '水下自主式无人潜器') {
return request({
url: '/report/platform/name.htm',
method: 'get',
params: { platform_type: platformType }
})
}
// 科考船汇总统计属性
export function shipTotal(data) {
return request({
@ -166,47 +180,31 @@ export function platformRov(data) {
})
}
/**
* ds1 报表独立域名参航科学家/单位汇总等与全局 VUE_APP_BASE_API 解耦
* @returns {string}
*/
function getDs1ReportBase() {
return (
process.env.VUE_APP_UNIT_MEMBER_REPORT_BASE ||
'https://weixin.bdsmart.cn/ds1'
)
}
/**
* 单位维度参航科学家明细按科学家汇总
* 路径与其它报表一致`/report/unit/member.htm` `VUE_APP_BASE_API`生产 `./`解析
* @param {Object} data 请求体需包含 unit单位标识
* @returns {Promise}
*/
export function unitMember(data) {
return request({
baseURL: getDs1ReportBase(),
url: '/report/unit/member.htm',
method: 'post',
type: 'application/x-www-form-urlencoded',
/** 跨域且服务端返回 Access-Control-Allow-Origin: * 时不可带 cookie否则浏览器会拦截 */
withCredentials: false,
data
})
}
/**
* 单位维度汇总统计按单位一行含航次天数人数深潜等
* unitMember 共用 ds1 baseURL
* @param {Object} [data] 可选 unit 等筛选参数空对象表示全部单位
* @returns {Promise}
*/
export function unitTotal(data = {}) {
return request({
baseURL: getDs1ReportBase(),
url: '/report/unit/total.htm',
method: 'post',
type: 'application/x-www-form-urlencoded',
withCredentials: false,
data
})
}

View File

@ -62,21 +62,16 @@
<span>{{ item.diving_sn }}</span>
</div>
<div class="list1">
<div class="list1 list1--block">
<p>设备类型</p>
<span>{{ item.equipment_type }}</span>
</div>
<div class="list1">
<div class="list1 list1--block">
<p>数据样品类型</p>
<span style="font-weight: bold">{{ item.data_type }}</span>
</div>
<div class="list1">
<p>作业类型</p>
<span>{{ item.job_type }}</span>
</div>
</div>
</div>
@ -266,9 +261,6 @@ export default {
{
label: '航次首席'
},
{
label: '数据集名称'
},
{
label: '数据样品类型',
disabled: false
@ -350,9 +342,9 @@ export default {
},
menu4(val) {
if (val) {
this.searchType[4].disabled = true
this.searchType[5].disabled = true
} else {
this.searchType[4].disabled = false
this.searchType[5].disabled = false
}
},
},
@ -429,7 +421,7 @@ export default {
handleCurrentChange4(item) {
this.menu4 = item.name
this.tableData4 = []
this.searchType[4].disabled = true
this.searchType[5].disabled = true
const str = this.searchType.find(item => {
return item.disabled !== true
})
@ -779,6 +771,12 @@ export default {
flex: 1;
min-height: 0;
}
/** 数据样品集:设备类型、数据样品类型各占一整行 */
.left4_list .list1--block {
width: 100%;
flex-basis: 100%;
}
}
/** 筛选结果列表:占满左侧剩余高度并独立滚动 */

View File

@ -10,7 +10,7 @@
</div>
<div class="filter-container">
<div class="search">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;" @keyup.enter.native="getData">
<el-button slot="append" icon="el-icon-search" @click="getData"></el-button>
</el-input>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="filter-container">
<div class="search">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;" @keyup.enter.native="getData">
<el-button slot="append" icon="el-icon-search" @click="getData"></el-button>
</el-input>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="filter-container">
<div class="search">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;" @keyup.enter.native="getData">
<el-button slot="append" icon="el-icon-search" @click="getData"></el-button>
</el-input>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="filter-container">
<div class="search">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;" @keyup.enter.native="getData">
<el-button slot="append" icon="el-icon-search" @click="getData"></el-button>
</el-input>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="filter-container">
<div class="search">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;" @keyup.enter.native="getData">
<el-button slot="append" icon="el-icon-search" @click="getData"></el-button>
</el-input>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="filter-container">
<div class="search">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;">
<el-input placeholder="模糊查询" v-model="params.query" style="width: 300px;" @keyup.enter.native="getData">
<el-button slot="append" icon="el-icon-search" @click="getData"></el-button>
</el-input>
</div>

View File

@ -29,7 +29,7 @@
</div>
<div class="bot_right">
<div class="right1">
<p>依托两器船等各类海洋科考平台设备开展航次科考</p>
<p>依托两器船等各类海洋科考平台设备开展航次科考</p>
</div>
<div class="right2">
<div class="right2_1">
@ -95,12 +95,12 @@
<el-row>
<el-col :span="12">
<div class="dongtai_top">
<img src="../../static/images/shuju3.png" alt="">
<span class="dongtai_title">航次数据更新动态</span>
</div>
</el-col>
<el-col :span="12">
<div class="dongtai_top">
<img src="../../static/images/shuju4.png" alt="">
<span class="dongtai_title">数据样品引用动态</span>
</div>
</el-col>
</el-row>
@ -1027,6 +1027,28 @@ export default {
img {
width: auto;
}
.dongtai_title {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 14px;
font-size: 38px;
font-weight: 600;
color: #ffffff;
letter-spacing: 2px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
&::before,
&::after {
content: '';
flex-shrink: 0;
width: 55px;
height: 3px;
border-radius: 1px;
background-color: rgba(255, 255, 255, 0.23);
}
}
}
.dongtai_bot {

View File

@ -11,13 +11,12 @@
</svg>
</span>
<el-dropdown-menu slot="dropdown" class="banner-type-dropdown-popper">
<el-dropdown-item command="全部无人航行潜水器">全部无人航行潜水器</el-dropdown-item>
<el-dropdown-item command="全部水下自主式无人潜水器">全部水下自主式无人潜水器</el-dropdown-item>
<el-dropdown-item v-for="item in titles" :key="item.tsy_id" :command="item.report_name">
{{ item.report_name }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<p class="banner-title-picker__hint">点击选择</p>
</div>
<div class="numbers">
<div v-for="(item, index) in numbers" :key="index" class="item">
@ -66,15 +65,14 @@
<script>
import Vue from 'vue'
/**
* 无人航行器汇总统计页请求 `/report/platform/auv` 系列接口交互与遥控潜水器汇总页一致ECharts
* 水下自主式无人潜器汇总统计页Banner 平台名来自 `/report/platform/name.htm`其余请求 `/report/platform/auv` 系列交互与遥控潜水器汇总页一致ECharts
*/
import BarChart from './components/BarChart.vue'
import PieChart from './components/PieChart.vue'
import { reportList, platformAuv, auvUnit, auvUnitYear, auvDiving } from '../../api/statistics'
import { filterDictItems } from '../../utils/index'
import { initMapbox } from "@/utils/mapbox-utils";
import { platformNameList, platformAuv, auvUnit, auvUnitYear, auvDiving } from '../../api/statistics'
import { initMapbox } from '@/utils/mapbox-utils'
import { loadVectorLayer, loadJsonPointFeature, showUnitReport } from '@/utils/vector-layer-utils'
import { ColorGenerator } from '@/utils/color-generator';
import { ColorGenerator } from '@/utils/color-generator'
export default {
components: {
@ -83,7 +81,7 @@ export default {
},
data() {
return {
currentTitle: '全部无人航行潜水器',
currentTitle: '全部水下自主式无人潜水器',
titles: [],
numbers: [
{
@ -152,17 +150,33 @@ export default {
}
},
methods: {
//
/**
* Banner 下拉选项`/report/platform/name.htm?platform_type=水下自主式无人潜器`
*/
getTypeList() {
reportList().then(res => {
this.titles = filterDictItems(res.array, '无人航行潜水器')
platformNameList().then(res => {
const raw = res.array || []
this.titles = raw
.map((item, idx) => {
if (typeof item === 'string') {
return { tsy_id: `auv-name-${idx}`, report_name: item }
}
const name =
item.platform_name != null
? item.platform_name
: item.report_name != null ? item.report_name : ''
const id =
item.tsy_id != null ? item.tsy_id : item.id != null ? item.id : `auv-name-${idx}`
return { tsy_id: id, report_name: name }
})
.filter(i => i.report_name)
})
},
//
handleCommand(command) {
this.currentTitle = command
this.removeSingleLineImg()
if (command === '全部无人航行潜水器') {
if (command === '全部水下自主式无人潜水器') {
this.getAuvList()
this.gitAuvDiving()
this.gitAuvUnitYear()
@ -303,8 +317,9 @@ export default {
background-color: #012458;
background-image: url(../../../static/images/bannerny1.jpg);
background-repeat: no-repeat;
// contain cover
background-position: center;
background-size: contain;
background-size: cover;
width: 100%;
height: 480px;
display: flex;
@ -368,16 +383,6 @@ export default {
color: #ffffff;
}
.banner-title-picker__hint {
margin: 14px 0 0;
padding: 0;
font-size: 14px;
font-weight: 400;
letter-spacing: 0.12em;
color: rgba(255, 255, 255, 0.78);
line-height: 1.4;
}
.numbers {
display: flex;
justify-content: space-between;
@ -470,17 +475,71 @@ export default {
<style lang="scss">
.banner-type-dropdown-popper.el-dropdown-menu {
min-width: 240px;
min-width: 260px;
max-height: #{"min(60vh, 420px)"};
overflow-x: hidden;
overflow-y: auto;
padding: 6px 0;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
padding: 8px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.38);
background: linear-gradient(
155deg,
rgba(255, 255, 255, 0.48) 0%,
rgba(248, 252, 255, 0.28) 50%,
rgba(255, 255, 255, 0.16) 100%
);
backdrop-filter: blur(22px) saturate(175%);
-webkit-backdrop-filter: blur(22px) saturate(175%);
box-shadow:
0 4px 6px rgba(0, 0, 0, 0.05),
0 18px 48px rgba(10, 40, 90, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
margin: 6px 0;
background: rgba(255, 255, 255, 0.14);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(10, 132, 193, 0.38);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(10, 132, 193, 0.55);
}
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item {
font-size: 16px;
line-height: 22px;
padding: 14px 22px;
font-size: 18px;
font-weight: 500;
letter-spacing: 0.03em;
line-height: 1.45;
padding: 12px 18px;
margin: 2px 0;
border-radius: 10px;
color: rgba(28, 45, 63, 0.95);
transition:
background 0.2s ease,
color 0.2s ease;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:not(.is-disabled):hover {
background: rgba(10, 132, 193, 0.2);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:focus {
background: rgba(10, 132, 193, 0.17);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item.is-disabled {
color: rgba(28, 45, 63, 0.35);
}
</style>

View File

@ -17,7 +17,6 @@
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<p class="banner-title-picker__hint">点击选择</p>
</div>
<div class="numbers">
<div v-for="(item, index) in numbers" :key="index" class="item">
@ -303,8 +302,9 @@ export default {
background-color: #012458;
background-image: url(../../../static/images/bannerny1.jpg);
background-repeat: no-repeat;
// contain cover
background-position: center;
background-size: contain;
background-size: cover;
width: 100%;
height: 480px;
display: flex;
@ -368,16 +368,6 @@ export default {
color: #ffffff;
}
.banner-title-picker__hint {
margin: 14px 0 0;
padding: 0;
font-size: 14px;
font-weight: 400;
letter-spacing: 0.12em;
color: rgba(255, 255, 255, 0.78);
line-height: 1.4;
}
.numbers {
display: flex;
justify-content: space-between;
@ -470,17 +460,71 @@ export default {
<style lang="scss">
.banner-type-dropdown-popper.el-dropdown-menu {
min-width: 240px;
min-width: 260px;
max-height: #{"min(60vh, 420px)"};
overflow-x: hidden;
overflow-y: auto;
padding: 6px 0;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
padding: 8px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.38);
background: linear-gradient(
155deg,
rgba(255, 255, 255, 0.48) 0%,
rgba(248, 252, 255, 0.28) 50%,
rgba(255, 255, 255, 0.16) 100%
);
backdrop-filter: blur(22px) saturate(175%);
-webkit-backdrop-filter: blur(22px) saturate(175%);
box-shadow:
0 4px 6px rgba(0, 0, 0, 0.05),
0 18px 48px rgba(10, 40, 90, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
margin: 6px 0;
background: rgba(255, 255, 255, 0.14);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(10, 132, 193, 0.38);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(10, 132, 193, 0.55);
}
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item {
font-size: 16px;
line-height: 22px;
padding: 14px 22px;
font-size: 18px;
font-weight: 500;
letter-spacing: 0.03em;
line-height: 1.45;
padding: 12px 18px;
margin: 2px 0;
border-radius: 10px;
color: rgba(28, 45, 63, 0.95);
transition:
background 0.2s ease,
color 0.2s ease;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:not(.is-disabled):hover {
background: rgba(10, 132, 193, 0.2);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:focus {
background: rgba(10, 132, 193, 0.17);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item.is-disabled {
color: rgba(28, 45, 63, 0.35);
}
</style>

View File

@ -17,7 +17,6 @@
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<p class="banner-title-picker__hint">点击选择</p>
</div>
<div class="numbers">
<div v-for="(item, index) in numbers" :key="index" class="item">
@ -302,8 +301,9 @@ export default {
background-color: #012458;
background-image: url(../../../static/images/bannerny1.jpg);
background-repeat: no-repeat;
// contain cover
background-position: center;
background-size: contain;
background-size: cover;
width: 100%;
height: 480px;
display: flex;
@ -367,16 +367,6 @@ export default {
color: #ffffff;
}
.banner-title-picker__hint {
margin: 14px 0 0;
padding: 0;
font-size: 14px;
font-weight: 400;
letter-spacing: 0.12em;
color: rgba(255, 255, 255, 0.78);
line-height: 1.4;
}
.numbers {
display: flex;
justify-content: space-between;
@ -469,17 +459,71 @@ export default {
<style lang="scss">
.banner-type-dropdown-popper.el-dropdown-menu {
min-width: 240px;
min-width: 260px;
max-height: #{"min(60vh, 420px)"};
overflow-x: hidden;
overflow-y: auto;
padding: 6px 0;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
padding: 8px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.38);
background: linear-gradient(
155deg,
rgba(255, 255, 255, 0.48) 0%,
rgba(248, 252, 255, 0.28) 50%,
rgba(255, 255, 255, 0.16) 100%
);
backdrop-filter: blur(22px) saturate(175%);
-webkit-backdrop-filter: blur(22px) saturate(175%);
box-shadow:
0 4px 6px rgba(0, 0, 0, 0.05),
0 18px 48px rgba(10, 40, 90, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
margin: 6px 0;
background: rgba(255, 255, 255, 0.14);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(10, 132, 193, 0.38);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(10, 132, 193, 0.55);
}
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item {
font-size: 16px;
line-height: 22px;
padding: 14px 22px;
font-size: 18px;
font-weight: 500;
letter-spacing: 0.03em;
line-height: 1.45;
padding: 12px 18px;
margin: 2px 0;
border-radius: 10px;
color: rgba(28, 45, 63, 0.95);
transition:
background 0.2s ease,
color 0.2s ease;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:not(.is-disabled):hover {
background: rgba(10, 132, 193, 0.2);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:focus {
background: rgba(10, 132, 193, 0.17);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item.is-disabled {
color: rgba(28, 45, 63, 0.35);
}
</style>

View File

@ -17,7 +17,6 @@
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<p class="banner-title-picker__hint">点击选择</p>
</div>
<div class="numbers">
<div v-for="(item, index) in numbers" :key="index" class="item">
@ -187,7 +186,7 @@ export default {
getShipList(params = {}) {
shipTotal(params).then(res => {
const obj = res.array[0]
this.numbers[0].value = obj.member_total
this.numbers[0].value = obj.voyage_total
this.numbers[1].value = obj.days_total
this.numbers[2].value = obj.unit_total
this.numbers[3].value = obj.dataset_total
@ -296,7 +295,7 @@ export default {
const sortedData = originalData.sort((a, b) => a.year - b.year)
this.barData1 = {
title: '年度航次数',
salesData: sortedData.map(item => item.member_total),
salesData: sortedData.map(item => item.voyage_total),
productCategories: sortedData.map(item => item.year.toString())
}
this.barDataDays = {
@ -328,8 +327,9 @@ export default {
background-color: #012458;
background-image: url(../../../static/images/bannerny1.jpg);
background-repeat: no-repeat;
// contain cover
background-position: center;
background-size: contain;
background-size: cover;
width: 100%;
height: 480px;
display: flex;
@ -393,16 +393,6 @@ export default {
color: #ffffff;
}
.banner-title-picker__hint {
margin: 14px 0 0;
padding: 0;
font-size: 14px;
font-weight: 400;
letter-spacing: 0.12em;
color: rgba(255, 255, 255, 0.78);
line-height: 1.4;
}
.numbers {
display: flex;
justify-content: space-between;
@ -559,17 +549,71 @@ export default {
<style lang="scss">
.banner-type-dropdown-popper.el-dropdown-menu {
min-width: 240px;
min-width: 260px;
max-height: #{"min(60vh, 420px)"};
overflow-x: hidden;
overflow-y: auto;
padding: 6px 0;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
padding: 8px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.38);
background: linear-gradient(
155deg,
rgba(255, 255, 255, 0.48) 0%,
rgba(248, 252, 255, 0.28) 50%,
rgba(255, 255, 255, 0.16) 100%
);
backdrop-filter: blur(22px) saturate(175%);
-webkit-backdrop-filter: blur(22px) saturate(175%);
box-shadow:
0 4px 6px rgba(0, 0, 0, 0.05),
0 18px 48px rgba(10, 40, 90, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
margin: 6px 0;
background: rgba(255, 255, 255, 0.14);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(10, 132, 193, 0.38);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(10, 132, 193, 0.55);
}
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item {
font-size: 16px;
line-height: 22px;
padding: 14px 22px;
font-size: 18px;
font-weight: 500;
letter-spacing: 0.03em;
line-height: 1.45;
padding: 12px 18px;
margin: 2px 0;
border-radius: 10px;
color: rgba(28, 45, 63, 0.95);
transition:
background 0.2s ease,
color 0.2s ease;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:not(.is-disabled):hover {
background: rgba(10, 132, 193, 0.2);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:focus {
background: rgba(10, 132, 193, 0.17);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item.is-disabled {
color: rgba(28, 45, 63, 0.35);
}
</style>

View File

@ -269,8 +269,9 @@ export default {
background-color: #012458;
background-image: url(../../../static/images/bannerny1.jpg);
background-repeat: no-repeat;
// contain cover
background-position: center;
background-size: contain;
background-size: cover;
width: 100%;
height: 480px;
display: flex;

View File

@ -9,17 +9,26 @@
</div>
</div>
</div>
<!-- 地图板块与科考船汇总统计页 ships 一致Mapbox + shipUnit -->
<!-- 地图板块与科考船汇总统计页 ships 一致Mapbox + shipUnit + shipVoyage -->
<div class="map-module">
<div class="bezel">
<div class="map-title">参航单位</div>
<div id="workUnitMap_uuv" ref="workUnitMap_uuv" style="height: 100%;width:100%;" />
</div>
<!-- <div class="bezel">
<div class="map-title">航次地图</div>
<div class="map-year-panel">
<span class="map-year-label">年份</span>
<el-date-picker v-model="voyageYear" type="year" size="small" placeholder="全部" class="map-year" clearable
format="yyyy" @change="selectVoyageYear" />
</div>
<div id="voyageMap_uuv" ref="voyageMap_uuv" style="height: 100%;width:100%;" />
</div> -->
</div>
<div class="unit-toolbar">
<div class="unit-toolbar-inner">
<div class="unit-filter-box">
<span class="banner-unit-label">单位名称</span>
<span class="banner-unit-label">统计单位</span>
<el-select v-model="selectedUnits" class="banner-unit-select" multiple filterable clearable size="small"
placeholder="请选择单位(不选表示全部)" value-key="unit_name" collapse-tags @change="onBannerUnitsChange">
<el-option v-for="unit in unitOptions" :key="unit.unit_id || unit.unit_name" :label="unit.unit_name"
@ -31,24 +40,42 @@
<!-- echarts板块-->
<div class="echarts-module">
<div class="bezel">
<BarChart :title="barVoyageCount.title" :chart-data="barVoyageCount.salesData"
:categories="barVoyageCount.productCategories" chart-type="single" />
<BarChart :title="barVoyageCount.title"
:chart-data="barVoyageCount.salesData"
:categories="barVoyageCount.productCategories"
chart-type="single"
:hide-x-axis-labels="true" />
</div>
<div class="bezel">
<BarChart :title="barVoyageDays.title" :chart-data="barVoyageDays.salesData"
:categories="barVoyageDays.productCategories" chart-type="single" />
<BarChart :title="barVoyageDays.title"
:chart-data="barVoyageDays.salesData"
:categories="barVoyageDays.productCategories"
chart-type="single"
:hide-x-axis-labels="true" />
</div>
<div class="bezel">
<BarChart :title="barPeopleDiving.title" :chart-data="barPeopleDiving.salesData"
:categories="barPeopleDiving.productCategories" chart-type="multiple" />
<BarChart :title="barPeopleDiving.title"
:chart-data="barPeopleDiving.salesData"
:categories="barPeopleDiving.productCategories"
chart-type="multiple"
:hide-x-axis-labels="true" />
</div>
<div class="bezel">
<BarChart :title="barFirstPeopleDiving.title" :chart-data="barFirstPeopleDiving.salesData"
:categories="barFirstPeopleDiving.productCategories" chart-type="multiple" />
<BarChart :title="barFirstPeopleDiving.title"
:chart-data="barFirstPeopleDiving.salesData"
:categories="barFirstPeopleDiving.productCategories"
chart-type="multiple"
:hide-x-axis-labels="true" />
</div>
<div class="bezel">
<BarChart :title="mixedMileage.title" :chart-data="mixedMileage.series" :categories="mixedMileage.categories"
chart-type="mixed" :dual-y-axis="true" left-axis-name="次数" right-axis-name="天数" />
<BarChart :title="mixedMileage.title"
:chart-data="mixedMileage.series"
:categories="mixedMileage.categories"
chart-type="mixed"
:dual-y-axis="true"
left-axis-name="次数"
right-axis-name="天数"
:hide-x-axis-labels="true" />
</div>
</div>
</div>
@ -104,34 +131,34 @@ export default {
unit: '次'
}
],
/** 次数(柱状) */
barVoyageCount: { title: '次数', salesData: [], productCategories: [] },
/** 航次数(柱状) */
barVoyageCount: { title: '航次数', salesData: [], productCategories: [] },
/** 参航天数(柱状) */
barVoyageDays: { title: '参航天数', salesData: [], productCategories: [] },
/** 参航人数、深潜次数(柱状,多系列) */
/** 参航人数、深潜次数(柱状,多系列) */
barPeopleDiving: {
title: '参航人数、深潜次数',
title: '参航人数、深潜次数',
salesData: [
{ name: '参航人数', type: 'bar', data: [] },
{ name: '参航人数', type: 'bar', data: [] },
{ name: '深潜次数', type: 'bar', data: [] }
],
productCategories: []
},
/** 首次参航、首次深潜(柱状,多系列) */
barFirstPeopleDiving: {
title: '首次参航人数、首次深潜数',
title: '首次参航人数、首次深潜数',
salesData: [
{ name: '首次参航人数', type: 'bar', data: [] },
{ name: '首次深潜数', type: 'bar', data: [] }
{ name: '首次深潜数', type: 'bar', data: [] }
],
productCategories: []
},
/** 次数(柱)+ 参航天数(折) */
/** 航次数(柱)+ 参航天数(折) */
mixedMileage: {
title: '次数与参航天数',
title: '航次数与参航天数',
categories: [],
series: [
{ name: '次数', type: 'bar', data: [], yAxisIndex: 0 },
{ name: '航次数', type: 'bar', data: [], yAxisIndex: 0 },
{ name: '参航天数', type: 'line', data: [], yAxisIndex: 1 }
]
}
@ -218,29 +245,29 @@ export default {
this.numbers[0].value = ''
this.numbers[1].value = ''
this.numbers[2].value = ''
this.barVoyageCount = { title: '次数', salesData: [], productCategories: [] }
this.barVoyageCount = { title: '航次数', salesData: [], productCategories: [] }
this.barVoyageDays = { title: '参航天数', salesData: [], productCategories: [] }
this.barPeopleDiving = {
title: '参航人数、深潜次数',
title: '参航人数、深潜次数',
salesData: [
{ name: '参航人数', type: 'bar', data: [] },
{ name: '参航人数', type: 'bar', data: [] },
{ name: '深潜次数', type: 'bar', data: [] }
],
productCategories: []
}
this.barFirstPeopleDiving = {
title: '首次参航人数、首次深潜数',
title: '首次参航人数、首次深潜数',
salesData: [
{ name: '首次参航人数', type: 'bar', data: [] },
{ name: '首次深潜数', type: 'bar', data: [] }
{ name: '首次深潜数', type: 'bar', data: [] }
],
productCategories: []
}
this.mixedMileage = {
title: '次数与参航天数',
title: '航次数与参航天数',
categories: [],
series: [
{ name: '次数', type: 'bar', data: [], yAxisIndex: 0 },
{ name: '航次数', type: 'bar', data: [], yAxisIndex: 0 },
{ name: '参航天数', type: 'line', data: [], yAxisIndex: 1 }
]
}
@ -261,7 +288,7 @@ export default {
this.numbers[2].value = sorted.reduce((s, r) => s + num(r.drving_total), 0)
this.barVoyageCount = {
title: '次数',
title: '航次数',
salesData: voyage,
productCategories: names
}
@ -271,26 +298,26 @@ export default {
productCategories: names
}
this.barPeopleDiving = {
title: '参航人数、深潜次数',
title: '参航人数、深潜次数',
salesData: [
{ name: '参航人数', type: 'bar', data: member },
{ name: '参航人数', type: 'bar', data: member },
{ name: '深潜次数', type: 'bar', data: drving }
],
productCategories: names
}
this.barFirstPeopleDiving = {
title: '首次参航人数、首次深潜数',
title: '首次参航人数、首次深潜数',
salesData: [
{ name: '首次参航人数', type: 'bar', data: fVoyage },
{ name: '首次深潜数', type: 'bar', data: fDrving }
{ name: '首次深潜数', type: 'bar', data: fDrving }
],
productCategories: names
}
this.mixedMileage = {
title: '次数与参航天数',
title: '航次数与参航天数',
categories: names,
series: [
{ name: '次数', type: 'bar', data: voyage, yAxisIndex: 0 },
{ name: '航次数', type: 'bar', data: voyage, yAxisIndex: 0 },
{ name: '参航天数', type: 'line', data: days, yAxisIndex: 1 }
]
}
@ -378,8 +405,9 @@ export default {
background-color: #012458;
background-image: url(../../../static/images/bannerny1.jpg);
background-repeat: no-repeat;
// contain cover
background-position: center;
background-size: contain;
background-size: cover;
width: 100%;
height: 480px;
display: flex;
@ -485,10 +513,10 @@ export default {
}
}
/** Banner 下方:统计单位筛选条,整行容器 + 右侧对齐独立框 */
/** 地图卡片下方:统计单位筛选条,整行容器 + 右侧对齐独立框 */
.unit-toolbar {
width: 100%;
padding: 8px 50px 8px;
padding: 20px 50px 12px;
box-sizing: border-box;
background-color: #ebf1f7;
@ -540,7 +568,7 @@ export default {
}
.map-module {
padding: 10px 50px;
padding: 50px 50px 0;
display: flex;
justify-content: space-between;
gap: 50px;
@ -640,11 +668,10 @@ export default {
}
.echarts-module {
padding: 0 50px 50px;
padding: 16px 50px 50px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 50px;
grid-auto-rows: 300px;
grid-template-columns: 1fr;
row-gap: 32px;
.bezel {
width: 100%;
@ -669,17 +696,71 @@ export default {
<style lang="scss">
.banner-type-dropdown-popper.el-dropdown-menu {
min-width: 240px;
min-width: 260px;
max-height: #{"min(60vh, 420px)"};
overflow-x: hidden;
overflow-y: auto;
padding: 6px 0;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
padding: 8px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.38);
background: linear-gradient(
155deg,
rgba(255, 255, 255, 0.48) 0%,
rgba(248, 252, 255, 0.28) 50%,
rgba(255, 255, 255, 0.16) 100%
);
backdrop-filter: blur(22px) saturate(175%);
-webkit-backdrop-filter: blur(22px) saturate(175%);
box-shadow:
0 4px 6px rgba(0, 0, 0, 0.05),
0 18px 48px rgba(10, 40, 90, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
margin: 6px 0;
background: rgba(255, 255, 255, 0.14);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(10, 132, 193, 0.38);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(10, 132, 193, 0.55);
}
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item {
font-size: 16px;
line-height: 22px;
padding: 14px 22px;
font-size: 18px;
font-weight: 500;
letter-spacing: 0.03em;
line-height: 1.45;
padding: 12px 18px;
margin: 2px 0;
border-radius: 10px;
color: rgba(28, 45, 63, 0.95);
transition:
background 0.2s ease,
color 0.2s ease;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:not(.is-disabled):hover {
background: rgba(10, 132, 193, 0.2);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item:focus {
background: rgba(10, 132, 193, 0.17);
color: #0a84c1;
}
.banner-type-dropdown-popper.el-dropdown-menu .el-dropdown-menu__item.is-disabled {
color: rgba(28, 45, 63, 0.35);
}
</style>

View File

@ -53,6 +53,11 @@ export default {
type: Number,
default: 300
},
/** 是否隐藏 X 轴类目标签 */
hideXAxisLabels: {
type: Boolean,
default: false
},
// stacked
stackName: {
type: String,
@ -80,6 +85,17 @@ export default {
window.removeEventListener('resize', this.handleResize);
},
methods: {
/**
* Y 轴刻度与提示框数值按整数展示不出现小数点
* @param {number|string} value 原始刻度或数据值
* @returns {string}
*/
formatAxisInteger(value) {
const n = Number(value)
if (!Number.isFinite(n)) return String(value)
return String(Math.round(n))
},
initChart() {
this.$nextTick(() => {
this.myChart = echarts.init(this.$refs.chartContainer);
@ -165,6 +181,7 @@ export default {
// Y
return [{
type: 'value',
minInterval: 1,
axisLine: {
show: true,
lineStyle: {
@ -175,7 +192,8 @@ export default {
show: false
},
axisLabel: {
color: '#666'
color: '#666',
formatter: (v) => this.formatAxisInteger(v)
},
splitLine: {
lineStyle: {
@ -192,6 +210,7 @@ export default {
type: 'value',
name: this.leftAxisName || '左轴',
position: 'left',
minInterval: 1,
axisLine: {
show: true,
lineStyle: {
@ -200,7 +219,7 @@ export default {
},
axisLabel: {
color: '#666',
formatter: '{value}'
formatter: (v) => this.formatAxisInteger(v)
},
splitLine: {
show: false
@ -210,6 +229,7 @@ export default {
type: 'value',
name: this.rightAxisName || '右轴',
position: 'right',
minInterval: 1,
axisLine: {
show: true,
lineStyle: {
@ -218,7 +238,7 @@ export default {
},
axisLabel: {
color: '#666',
formatter: '{value}'
formatter: (v) => this.formatAxisInteger(v)
},
splitLine: {
show: false
@ -365,6 +385,7 @@ export default {
show: false
},
axisLabel: {
show: !this.hideXAxisLabels,
color: '#666',
interval: 0,
rotate: this.categories.length > 6 ? 45 : 0,
@ -385,7 +406,7 @@ export default {
params.forEach(param => {
const color = param.color;
const seriesName = param.seriesName;
const value = param.value;
const value = this.formatAxisInteger(param.value);
const marker = `<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;background-color:${color};"></span>`;
result += `
@ -415,8 +436,9 @@ export default {
params.forEach(param => {
const color = param.color;
const seriesName = param.seriesName;
const value = param.value;
const percentage = total > 0 ? ((value / total) * 100).toFixed(1) : 0;
const value = this.formatAxisInteger(param.value);
const raw = Number(param.value);
const percentage = total > 0 && Number.isFinite(raw) ? ((raw / total) * 100).toFixed(1) : 0;
const marker = `<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;background-color:${color};"></span>`;
result += `

View File

@ -107,7 +107,7 @@
</el-card>
</el-col>
<!-- 无人航行潜水器汇总统计 -->
<!-- 水下自主式无人潜水器汇总统计 -->
<el-col :xs="24" :sm="12" :md="8">
<el-card
class="stat-card stat-card--nav stat-card--uuv"
@ -123,7 +123,7 @@
</svg>
</div>
<div class="stat-card__head-text">
<h3 class="stat-card__title">无人航行潜水器汇总统计</h3>
<h3 class="stat-card__title">水下自主式无人潜水器汇总统计</h3>
<p class="stat-card__meta">
<span class="stat-card__badge">{{ uuv.length }} 艘在册</span>
</p>
@ -168,7 +168,7 @@
<span class="stat-metric__label">{{ m.label }}</span>
</div>
</div>
<p class="stat-card__fleet" :title="uuvNamesJoined">单位汇总与参航单位详情页一致 · 点击查看</p>
</div>
</el-card>
</el-col>
@ -202,7 +202,7 @@
<span class="stat-metric__label">{{ m.label }}</span>
</div>
</div>
<p class="stat-card__fleet" :title="uuvNamesJoined">默认单位中国科学院深海科学与工程研究所 · 点击查看详情</p>
</div>
</el-card>
</el-col>
@ -359,7 +359,7 @@ export default {
]
}
return [
{ label: '航次', display: this.formatMetric(s.member_total) + ' 次' },
{ label: '航次', display: this.formatMetric(s.voyage_total) + ' 次' },
{ label: '航次天数', display: this.formatMetric(s.days_total) + ' 天' },
{ label: '参航单位', display: this.formatMetric(s.unit_total) + ' 家' },
{ label: '数据样品', display: this.formatMetric(s.dataset_total) + ' 个' }
@ -411,7 +411,7 @@ export default {
return this.uuvScientistValue
},
/**
* 参航科学家卡片三项指标 Uuv 详情页 banner 一致
* 参航科学家卡片三项指标
* @returns {Array<{ label: string, display: string }>}
*/
uuvScientistMetrics() {
@ -420,13 +420,13 @@ export default {
return [
{ label: '科学家人数', display: '—' },
{ label: '累计参加航次', display: '—' },
{ label: '累计参航天数', display: '—' }
{ label: '累计参加人·天', display: '—' }
]
}
return [
{ label: '科学家人数', display: this.formatMetric(c.scientistCount) + ' 人' },
{ label: '累计参加航次', display: this.formatMetric(c.sumVoyage) + ' 次' },
{ label: '累计参航天数', display: this.formatMetric(c.sumDays) + ' 天' }
{ label: '累计参加人·天', display: this.formatMetric(c.sumDays) + ' 人·天' }
]
}
},