123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- <template>
- <div class="spatiotemporal-distribution">
- <!-- 筛选条件 -->
- <el-card class="filter-card">
- <el-form :inline="true" :model="form" size="small">
- <el-form-item label="NCBI基因组序列编号">
- <!-- <el-input
- v-model="form.bytName"
- placeholder="请输入病原体名称"
- style="width: 180px"
- @keyup.enter="fetchAllData"
- /> -->
- <el-select
- v-model="form.assemblyAccession"
- filterable
- remote
- reserve-keyword
- placeholder="请输入NCBI基因组序列编号"
- :remote-method="queryInfo"
- :loading="loading"
- @change="handleSelect"
- style="flex: 1"
- >
- <el-option
- v-for="item in Assoptions"
- :key="item.id"
- :label="item.asmName"
- :value="item.asmName"
- >
- </el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="时间">
- <el-date-picker
- v-model="form.dateRange"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="fetchAllData">查询</el-button>
- </el-form-item>
- </el-form>
- </el-card>
- <div class="charts-container">
- <!-- 子图二:分区条形图 -->
- <el-card class="chart-card">
- <div slot="header">地区分布条形图</div>
- <div ref="barChart" style="height: 320px"></div>
- </el-card>
- </div>
- <!-- 地图容器 -->
- <el-row :gutter="20">
- <el-col :span="12">
- <el-card class="map-card">
- <div slot="header">世界地图</div>
- <div ref="worldMapContainer" style="width: 100%; height: 600px"></div>
- </el-card>
- </el-col>
- <el-col :span="12">
- <el-card class="map-card">
- <div slot="header">中国地图</div>
- <div ref="chinaMapContainer" style="width: 100%; height: 600px"></div>
- </el-card>
- </el-col>
- <el-col :span="24">
- <el-card class="map-card">
- <div slot="header">全球流行病学监测数据</div>
- <div v-html="qqlxbxjcsjtxt"></div>
- </el-card>
- </el-col>
- </el-row>
- </div>
- </template>
- <script>
- import * as echarts from "echarts";
- import chinaJson from "echarts/map/json/china.json";
- import worldJson from "echarts/map/json/world.json";
- import {
- getbytzbInfo,
- getbytzzfbnfo,
- getsjbytztqkInfo,
- getzgbytztqkInfo,
- getAssemblyAccessionList,qqlxbxjcsj} from "@/api/statistics/report";
- echarts.registerMap("china", chinaJson);
- echarts.registerMap("world", worldJson);
- export default {
- name: "SpatiotemporalDistribution",
- data() {
- return {
- filters: {
- disease: "",
- subtype: "",
- branch: "",
- dateRange: [],
- region: [],
- },
- diseaseOptions: [],
- diseaseLoading: false,
- subtypeOptions: [],
- branchOptions: [],
- regionOptions: [],
- growthData: [],
- barData: [],
- pieData: [],
- worldMapData: [],
- chinaMapData: [],
- description: "",
- barChart: null,
- worldMapChart: null,
- chinaMapChart: null,
- form: {
- assemblyAccession: "",
- endDate: "",
- startDate: "",
- dateRange: [],
- },
- Assoptions: [],
- AssTimer: null,
- loading: false,
- qqlxbxjcsjtxt:''
- };
- },
- mounted() {
- // this.fetchAllData();
- // 延迟初始化,确保容器尺寸正确
- this.$nextTick(() => {
- this.initCharts();
- });
- },
- methods: {
- // 搜索
- queryInfo(queryString) {
- if (this.ASSTimer) {
- clearTimeout(this.ASSTimer);
- }
- this.ASSTimer = setTimeout(() => {
- if (queryString.length > 0) {
- this.loading = true;
- getAssemblyAccessionList(queryString)
- .then((res) => {
- console.log("查询基因组序列编号", res);
- if (res.data && res.data.length > 0) {
- this.Assoptions = res.data;
- }
- this.loading = false;
- })
- .finally(() => {
- this.loading = false;
- });
- }
- }, 500);
- },
- handleSelect() {
- if (this.form.assemblyAccession) {
- this.fetchAllData();
- }
- },
- async fetchAllData() {
- if (!this.form.assemblyAccession) {
- this.$message.info('请输入NCBI基因组序列编号');
- return;
- }
- if (this.form.dateRange.length > 0) {
- const [startDate, endDate] = this.form.dateRange;
- this.form.startDate = startDate;
- this.form.endDate = endDate;
- } else {
- this.$message.info('请输入时间');
- return;
- }
- // 获取数据
- try {
- const response2 = await getbytzzfbnfo(this.form);
- const response3 = await getsjbytztqkInfo(this.form);
- const response4 = await getzgbytztqkInfo(this.form);
- const response5 = await qqlxbxjcsj(this.form);
- this.barData = response2.data;
- this.worldMapData = response3.data;
- this.chinaMapData = response4.data;
- this.qqlxbxjcsjtxt = response5.msg
- console.log(response5)
- } catch (error) {
- console.error("获取数据失败:", error);
- this.$message.error("获取数据失败,请稍后重试");
- }
- this.renderCharts();
- },
- initCharts() {
- this.barChart = echarts.init(this.$refs.barChart);
- this.worldMapChart = echarts.init(this.$refs.worldMapContainer);
- this.chinaMapChart = echarts.init(this.$refs.chinaMapContainer);
- window.addEventListener("resize", () => {
- this.barChart.resize();
- this.worldMapChart.resize();
- this.chinaMapChart.resize();
- });
- },
- renderCharts() {
- // 子图二:分区条形图
- const regions =
- this.barData.length > 0
- ? Object.keys(this.barData[0]).filter((key) => key !== "day")
- : [];
- const dates = this.barData.map((item) => item.day);
- const seriesData = regions.map((region, index) => ({
- name: region,
- type: "bar",
- data: this.barData.map((item) => item[region]),
- itemStyle: {
- color: ["#DEECF6", "#86DAA7", "#F9D5D5", "#EF98A1", "#FBC99A", "#C2B1D7"][index % 6]
- }
- }));
- this.barChart.setOption({
- // 添加动画效果
- animationDuration: 1000,
- tooltip: {
- trigger: "axis",
- axisPointer: {
- type: "cross",
- crossStyle: {
- color: "#999",
- },
- },
- },
- legend: {
- data: regions,
- },
- xAxis: {
- type: "category",
- data: dates,
- // 优化 x 轴线样式
- axisLine: {
- lineStyle: {
- color: "#999",
- },
- },
- // 优化 x 轴刻度线样式
- axisTick: {
- show: false,
- },
- },
- yAxis: {
- type: "value",
- name: "数量",
- },
- series: seriesData,
- });
- // 处理世界地图数据
- const processedWorldMapData = this.worldMapData.map((item) => {
- // const name = worldRegionMap[item.area] || item.area;
- const value = item.num || 0;
- return {
- name: item.eng,
- value,
- cnName: item.area,
- };
- });
- // 处理中国地图数据
- const processedChinaMapData = this.chinaMapData.map((item) => {
- // const name = chinaRegionMap[item.area] || item.area;
- const value = item.num || 0;
- return {
- name: item.area,
- value,
- };
- });
- // 检查数据是否为空
- if (processedWorldMapData.every((item) => item.value === 0)) {
- console.warn("世界地图数据值全部为 0");
- }
- if (processedChinaMapData.every((item) => item.value === 0)) {
- console.warn("中国地图数据值全部为 0");
- }
- // 世界地图配置
- this.worldMapChart.setOption({
- title: { text: "全球病毒分布", left: "center" },
- tooltip: {
- trigger: "item",
- formatter: (p) =>
- `${p.data?.cnName || p.data?.name}<br/>数量: ${p.value || "-"}`,
- },
- visualMap: {
- min: Math.min(...processedWorldMapData.map((item) => item.value)),
- max: Math.max(...processedWorldMapData.map((item) => item.value)),
- left: "left",
- top: "bottom",
- text: ["高", "低"],
- calculable: true,
- inRange: {
- // 替换为指定的 RGB 颜色
- color: [
- 'rgb(255,155,153)',
- 'rgb(255,211,127)',
- 'rgb(245,245,122)',
- 'rgb(255,255,190)',
- 'rgb(233,255,190)',
- 'rgb(190,255,232)',
- 'rgb(196,235,255)',
- 'rgb(126,226,250)',
- 'rgb(0,197,255)' // 修正 000 为 0
- ]
- },
- },
- series: [
- {
- type: "map",
- map: "world",
- data: processedWorldMapData,
- label: {
- show: false,
- },
- emphasis: {
- itemStyle: {
- areaColor: "#e0e0e0",
- },
- },
- },
- ],
- });
- // 中国地图配置
- this.chinaMapChart.setOption({
- title: { text: "中国病毒分布", left: "center" },
- tooltip: {
- trigger: "item",
- formatter: (p) => `${p.name}<br/>数量: ${p.value || "-"}`,
- },
- visualMap: {
- min: Math.min(...processedChinaMapData.map((item) => item.value)),
- max: Math.max(...processedChinaMapData.map((item) => item.value)),
- left: "left",
- top: "bottom",
- text: ["高", "低"],
- calculable: true,
- inRange: {
- // 替换为指定的 RGB 颜色
- color: [
- 'rgb(255,155,153)',
- 'rgb(255,211,127)',
- 'rgb(245,245,122)',
- 'rgb(255,255,190)',
- 'rgb(233,255,190)',
- 'rgb(190,255,232)',
- 'rgb(196,235,255)',
- 'rgb(126,226,250)',
- 'rgb(0,197,255)' // 修正 000 为 0
- ]
- },
- },
- series: [
- {
- type: "map",
- map: "china",
- data: processedChinaMapData,
- label: {
- show: false,
- },
- emphasis: {
- itemStyle: {
- areaColor: "#e0e0e0",
- },
- },
- },
- ],
- });
- },
- },
- };
- </script>
- <style scoped>
- .spatiotemporal-distribution {
- padding: 24px;
- }
- .filter-card {
- margin-bottom: 16px;
- }
- .charts-container {
- display: flex;
- gap: 16px;
- margin-bottom: 16px;
- }
- .chart-card {
- flex: 1;
- min-width: 0;
- }
- .map-card {
- margin-bottom: 16px;
- }
- .desc-card {
- margin-bottom: 16px;
- }
- .desc-text {
- font-size: 15px;
- line-height: 1.8;
- color: #333;
- }
- </style>
|