# sybh **Repository Path**: sybh_1/sybh ## Basic Information - **Project Name**: sybh - **Description**: htu-zuihou - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-12-16 - **Last Updated**: 2025-01-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 船舶燃料大数据分析可视化 ### 项目名称:船舶燃料大数据分析可视化 **数据来源** | 名称 | 来源 | | ------------------------------------ | ------------------------------------------------------------ | | 某海上运输公司年分析报告 | [https://www.kaggle.com/ ](http://)|| | ship_id | 轮船编号 | 1-120 | |--------------------|---------|-------------| | ship_type | 轮船类型 | 不同轮船的油耗不同 | | route_id | 路线编号 | 路线也是影响排放的原因 | | month | 月份 | 一月到十二月 | | distance | 距离 | 0-1000 | | fuel_type | 燃料类型 |HFO的燃料会有更多的碳排放| | fuel_consumption | 燃料消耗 | 轮船运行的结果 | | CO2_emissions | 二氧化碳排放量 |碳排放量影响全球气候 | | weather_conditions | 天气情况 |影响运行速度 | | engine_efficiency | 能源效率 |低于百分之百 | 按船型划分的燃料消耗量: o 油轮的平均燃料消耗量最高,反映出其较大的尺寸和载货量。 o 冲浪船消耗的燃料最少,使其能够高效进行短途高速旅行。 二氧化碳排放量: o 燃料消耗量和 CO2 排放量之间存在很强的正相关 (r ≈ 0.997),这证实了较高的燃料使用量会导致更大的排放量。 统计分析: o 方差分析检验揭示了不同船型的燃料消耗存在显著差异。 o Tukey HSD 分析可精确定位哪些船舶类型的燃料消耗和排放不同,提供可操作的见解。 #### 上传原始数据到HDFS ```bash hdfs dfs -mkdir -p /ship-data/ods ``` ```bash hdfs dfs -put ship_fuel_efficiency.csv /ship-data/ods ``` #### 创建 hive 数据库 ```sql create database lihaozhe; ``` #### 创建 mysql 数据库 ```sql create database lihaozhe; ``` ## 工程文件 1. 数据分析 ship-spark 2. 数据接口 ship-api 3. 数据可视化 ship-view ## 数据分析 > [ship-spark](./ship-spark) ### pom.xml ``` 4.0.0 org.springframework.boot spring-boot-starter-parent 3.3.5 cn.lhz springboot 1.0.0 springboot springboot 21 21 ${jdk.version} ${jdk.version} ${jdk.version} utf-8 utf-8 UTF-8 true true 2.17.0 3.17.0 2.1.4 2.0.53 2.0.53 2.11.0 1.1.2 5.8.32 5.11.2 2.0.0 2.18.0 1.18.34 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-configuration-processor true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test cn.hutool hutool-all ${hutool.version} com.google.code.gson gson ${gson.version} org.apache.commons commons-lang3 ${commons-lang3.version} commons-io commons-io ${commons-io.version} com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter 4.5.0 org.apache.maven.plugins maven-compiler-plugin 3.13.0 ${jdk.version} ${jdk.version} UTF-8 org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok ``` ### spark工具类 > hive.properties ```properties warehouse.dir=hdfs://lihaozhe:8020/user/hive/warehouse metastore.uris=thrift://lihaozhe:9083 ``` > mysql.properties ```properties url=jdbc:mysql://lihaozhe schema=lihaozhe user=root password=lihaozhe ``` > cn.lhz.util.spark.SparkUtil.scala ```scala package cn.lhz.util.spark import org.apache.spark.SparkConf import org.apache.spark.sql.SparkSession import java.util.Properties object SparkUtil { def apply(): SparkSession = { System.setProperty("HADOOP_USER_NAME", "root") val sparkConf = new SparkConf() if (!sparkConf.contains("spark.master")) { sparkConf.setMaster("local") } val prop = new Properties() prop.load(this.getClass.getClassLoader.getResourceAsStream("hive.properties")) val sparkSession: SparkSession = SparkSession .builder() .appName("Spark SQL JDBC") .config(conf = sparkConf) .config("spark.sql.warehouse.ship", prop.getProperty("warehouse.ship")) .config("hive.metastore.uris", prop.getProperty("metastore.uris")) .enableHiveSupport() .getOrCreate() sparkSession } def mysqlConnectionProperties(tableName: String): Properties = { val prop = new Properties() prop.load(this.getClass.getClassLoader.getResourceAsStream("mysql.properties")) val schema = prop.remove("schema") prop.put("tableName", schema + "." + tableName) prop } def mysqlConnectionProperties(schema: String, tableName: String): Properties = { val prop = new Properties() prop.load(this.getClass.getClassLoader.getResourceAsStream("mysql.properties")) prop.remove("schema") prop.put("tableName", schema + "." + tableName) prop } /** * 百分比转换 * * @param number 浮点数 * @return 百分比 */ def rate(number: Double): Double = { BigDecimal(number).setScale(4, BigDecimal.RoundingMode.HALF_UP).toDouble * 100 } } ``` ### 数据清洗 >ship-efficiency.csv #### hive 建表 ``` CREATE TABLE raw_shipping_data ( ship_id STRING, ship_type STRING, route_id STRING, month STRING, distance DOUBLE, fuel_type STRING, fuel_consumption DOUBLE, CO2_emissions DOUBLE, weather_conditions STRING, engine_efficiency DOUBLE ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE; -- 加载数据到原始表中 LOAD DATA INPATH '/root/data/ship_fuel_efficiency.csv' INTO TABLE raw_shipping_data; -- 创建一个清洗后的表 CREATE TABLE cleaned_shipping_data AS SELECT ship_id, ship_type, route_id, month, distance, fuel_type, fuel_consumption, CO2_emissions, weather_conditions, engine_efficiency FROM raw_shipping_data WHERE -- 过滤掉有缺失值的行 ship_id IS NOT NULL AND ship_type IS NOT NULL AND route_id IS NOT NULL AND month IS NOT NULL AND distance IS NOT NULL AND fuel_type IS NOT NULL AND fuel_consumption IS NOT NULL AND CO2_emissions IS NOT NULL AND weather_conditions IS NOT NULL AND engine_efficiency IS NOT NULL AND -- 过滤掉不合理的数据(例如负距离或负燃料消耗) distance >= 0 AND fuel_consumption >= 0 AND CO2_emissions >= 0 AND engine_efficiency > 0; -- 删除原始表(如果不再需要) DROP TABLE raw_shipping_data; -- 创建数据库(如果尚未存在) CREATE DATABASE IF NOT EXISTS my_database; -- 使用数据库 USE my_database; -- 创建表(如果尚未存在) CREATE TABLE IF NOT EXISTS my_table ( ship_id STRING, ship_type STRING, route_id STRING, month INT, distance DOUBLE, fuel_type STRING, fuel_consumption DOUBLE, CO2_emissions DOUBLE, weather_conditions STRING, engine_efficiency DOUBLE ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' STORED AS TEXTFILE; -- 加载数据 LOAD DATA LOCAL INPATH '/path/to/data.csv' INTO TABLE my_table; -- 查看前几行数据 SELECT * FROM my_table LIMIT 10; -- 删除重复行 DELETE FROM my_table WHERE ship_id IN ( SELECT ship_id FROM ( SELECT ship_id, ROW_NUMBER() OVER (PARTITION BY ship_id ORDER BY ship_id) AS row_num FROM my_table ) t WHERE t.row_num > 1 ); -- 处理缺失值 INSERT OVERWRITE TABLE my_table SELECT COALESCE(ship_id, 'Unknown') AS ship_id, COALESCE(ship_type, 'Unknown') AS ship_type, COALESCE(route_id, 'Unknown') AS route_id, COALESCE(month, -1) AS month, COALESCE(distance, 0) AS distance, COALESCE(fuel_type, 'Unknown') AS fuel_type, COALESCE(fuel_consumption, 0) AS fuel_consumption, COALESCE(CO2_emissions, 0) AS CO2_emissions, COALESCE(weather_conditions, 'Unknown') AS weather_conditions, COALESCE(engine_efficiency, 0) AS engine_efficiency FROM my_table; -- 处理异常值,例如删除距离超过某个阈值的记录 DELETE FROM my_table WHERE distance > 10000; -- 假设10000是距离的合理上限 -- 将清洗后的数据导出到新的表中 INSERT OVERWRITE TABLE clean_ship_data SELECT * FROM my_table; ``` ### cardio ETL ``` package cn.lhz.cardio.etl import cn.lhz.util.spark.SparkUtil import org.apache.spark.sql.SaveMode import org.apache.spark.sql.functions.col import org.apache.spark.sql.types.IntegerType /** * 对 cardio.csv 进行数据清洗 过滤掉包含空值的行 * * @author 李登科 * @version 1.0.0 */ object CardioEtl { def main(args: Array[String]): Unit = { // 获取 SparkSession 对象 val sparkSession = SparkUtil() // 定义源数据在HDFS文件系统的路径 val originPath: String = "/heart-data/ods/cardio.csv" // 读取 csv 文件 获取 dataFrame val df = sparkSession.read.option("header", "true").csv(originPath) // 字段集合 val cols = Array("id", "age", "gender", "height", "weight", "ap_hi", "ap_lo", "cholesterol", "gluc", "smoke", "alco", "active", "cardio") // 过滤掉有空值的数据行 df.na.drop(cols) // 为字段指定数据类型 val table = df.select( col("id") cast (IntegerType), col("age") cast (IntegerType), col("gender") cast (IntegerType), col("height") cast (IntegerType), col("weight") cast (IntegerType), col("ap_hi") cast (IntegerType), col("ap_lo") cast (IntegerType), col("cholesterol") cast (IntegerType), col("gluc") cast (IntegerType), col("smoke") cast (IntegerType), col("alco") cast (IntegerType), col("active") cast (IntegerType), col("cardio") cast (IntegerType), ) // 保存数据到 hive table.write.mode(SaveMode.Overwrite).saveAsTable("lihaozhe.dwd_cardio") // 释放资源 sparkSession.stop() } } ``` ### 服务器提交job spark-submit --master yarn --deploy-mode cluster --class cn.lhz.cardio.CardioEtl heart-spark.jar ### 数据接口 > springboot工程 ### pom.xml ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 3.4.0 cn.lhz tour-analysis-presto 0.0.1 tour-analysis-presto tour-analysis-presto 21 21 ${jdk.version} ${jdk.version} ${jdk.version} utf-8 utf-8 UTF-8 true true 2.17.0 3.17.0 1.2.23 2.1.4 2.0.53 2.0.53 2.11.0 1.1.2 5.8.32 5.11.2 2.0.0 2.18.0 2.9.18 1.18.34 3.5.9 3.0.4 9.1.0 3.4.0 0.289 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-web com.baomidou mybatis-plus-spring-boot3-starter ${mybatis-plus.version} com.baomidou mybatis-plus-jsqlparser ${mybatis-plus.version} com.baomidou mybatis-plus-generator ${mybatis-plus.version} org.springframework.boot spring-boot-configuration-processor true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test cn.hutool hutool-all ${hutool.version} com.github.binarywang java-testdata-generator 1.1.2 org.apache.commons commons-lang3 ${commons-lang3.version} commons-io commons-io ${commons-io.version} com.google.code.gson gson ${gson.version} org.webjars layui ${layui.version} com.alibaba druid ${druid.version} com.mysql mysql-connector-j ${mysql.version} com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter 4.5.0 org.apache.maven.plugins maven-compiler-plugin 3.13.0 UTF-8 ${jdk.version} ${jdk.version} org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok ${project.name} public aliyun nexus https://maven.aliyun.com/repository/public true public aliyun nexus https://maven.aliyun.com/repository/public true false ``` ### 导入工具类 > 导入 cn.lhz.util 包 ### 导入配置类 > 导入 cn.lhz.config 包 1. 全局异常处理 2. Mybatis Plus 分页方言 3. openApi 配置 ### 图表VO类 ```java package cn.lhz.vo; import cn.lhz.util.annotation.RowKeyAnnotation; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Chart { @RowKeyAnnotation private String name; private Object value; } ``` ### application.yml ```yaml server: port: 8080 servlet: context-path: /api spring: application: name: ship-api jackson: serialization: FAIL_ON_EMPTY_BEANS: false # json 序列化排除值为 null 的属性 default-property-inclusion: non_null # 配置 Date 类的时间格式,如果不涉及可以不加 date-format: yyyy-MM-dd HH:mm:ss # 配置 Date 类的时区,如果不涉及可以不加 time-zone: GMT+8 thymeleaf: #缓冲的配置 cache: false check-template: true check-template-location: true #开启MVC thymeleaf 视图解析 enabled: true #模板的模式,支持 HTML, XML TEXT JAVASCRIPT mode: HTML #编码 可不用配置 encoding: UTF-8 #配置模板路径,默认是templates,可以不用配置 prefix: classpath:templates # 文件后缀名 suffix: .html #内容类别,可不用配置 servlet: content-type: text/html;charset=utf-8 datasource: driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/lihaozhe?allowPublicKeyRetrieval=true&sslMode=DISABLED&useUnicode=true&characterEncoding=UTF8&useSSL=false&useServerPrepStmts=false&rewriteBatchedStatements=true&cachePrepStmts=true&allowMultiQueries=true&serverTimeZone=Aisa/Shanghai username: root password: lihaozhe mybatis-plus: # 如果是放在src/main/java目录下 classpath:/com/lihaozhe/*/mapper/*Mapper.xml # 如果是放在resource目录 classpath:/mapper/*Mapper.xml mapper-locations: classpath:mapper/*.xml #实体扫描,多个package用逗号或者分号分隔 type-aliases-package: cn.lhz.dto,cn.lhz.vo configuration: #配置返回数据库(column下划线命名&&返回java实体是驼峰命名),自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId) map-underscore-to-camel-case: true cache-enabled: false #配置JdbcTypeForNull, oracle数据库必须配置 jdbc-type-for-null: 'null' log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #是否激活 swagger true or false springdoc: swagger-ui: path: /swagger-ui tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: 'default' paths-to-match: '/**' packages-to-scan: cn.lhz.controller # knife4j的增强配置,不需要增强可以不配 knife4j: enable: true setting: language: zh_cn basic: # 启用基本认证 enable: true # 设置用户名 username: admin # 设置密码 password: lihaozhe ## vue+echarts+datav ### 1、创建工程 ```bash npm create vite@latest ``` ```bash cd heart-view npm install npm run dev ``` ### 2、安装项目依赖模块 ```bash npm install @types/node --save-dev npm install vue-router@4 npm install animate.css --save npm install gsap --save npm install fetch --save npm install axios --save npm install pinia npm install less less-loader -D npm install sass sass-loader --save-dev npm install scss scss-loader --save-dev npm install element-plus --save npm install -D unplugin-vue-components unplugin-auto-import npm install echarts echarts-wordcloud --save npm install @kjgl77/datav-vue3 ``` ### 3、配置项目 > vite.config.ts ```typescript import {defineConfig} from 'vite' const base_url:string = 'http://192.168.10.10:8080' // https://vitejs.dev/config/ export default defineConfig({ server: { host: '0.0.0.0', strictPort: true, open: false, proxy: { // 使用 proxy 实例 '/api': { target: base_url, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, 'api'), }, } }, }) ``` #### 3.1 配置路径别名 > `vite.config.ts` > > ```typescript > import { resolve } from 'path' > > resolve: { > alias: { > '@': resolve(__dirname, 'src') > }, > // 引入文件的时候,可以忽略掉以下文件后缀 > // extensions: ['.js', '.mjs', '.vue', '.json', '.less', '.css'] > }, > ``` ```typescript import {defineConfig} from 'vite' import { resolve } from 'path' // import { resolve } from 'mode:path' const base_url:string = 'http://192.168.10.10:8080' // https://vitejs.dev/config/ export default defineConfig({ server: { host: '0.0.0.0', strictPort: true, open: false, proxy: { // 使用 proxy 实例 '/api': { target: base_url, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, 'api'), }, } }, resolve:{//路径别名 alias:{ '@': resolve(__dirname,'./src') } }, }) ``` > `ts.config.node.json` > > ```json > /* 路径别名 */ > "types": ["node"], > "baseUrl": ".", > "paths": { > "@/*": ["src/*"] > ``` ```json { "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", "target": "ES2022", "lib": ["ES2023"], "module": "ESNext", "skipLibCheck": true, /* Bundler mode */ "moduleResolution": "Bundler", "allowImportingTsExtensions": true, "isolatedModules": true, "moduleDetection": "force", "noEmit": true, /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true, /* 路径别名 */ "types": ["node"], "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["vite.config.ts"] } ``` #### 3.2 引入路由 ##### 3.2.1 创建路由出口视图并在 `app.vue` 组件中引入 路由出口视图 > src/components/DataV.vue ```vue ``` > `app.vue` ```vue ``` ##### 3.2.2 创建路由文件 > src/routers/router.ts ```typescript // 1. 定义路由组件. // 也可以从其他文件导入 import {createMemoryHistory, createRouter, RouteRecordRaw} from 'vue-router' // 2. 定义一些路由 const routes: Array = [ ] // 3. 创建路由实例并传递 `routes` 配置 // 你可以在这里输入更多的配置,但我们在这里 // 暂时保持简单 const router = createRouter({ // 4. 内部提供了 history 模式的实现。 // memory 模式。createMemoryHistory // hash 模式。createWebHashHistory // html5 模式。createWebHistory history: createMemoryHistory(), routes, }) export default router ``` ##### 3.2.3 引入路由配置文件 > `main.ts` ```typescript import {createApp} from 'vue'; import './style.css'; import App from './App.vue'; import router from "./routers/router.ts"; const app = createApp(App); app.use(router); app.mount('#app'); ``` ##### 3.3 引入 `animate.css` 动画库 > `main.ts` > > ```typescript > import 'animate.css' > ``` ```typescript import {createApp} from 'vue'; import './style.css'; import 'animate.css' import App from './App.vue'; import router from "./routers/router.ts"; const app = createApp(App); app.use(router); app.mount('#app'); ``` ##### 3.4 引入 `pinia` ##### 3.4.1 编写状态管理文件`strore.ts` > src/strors/store.ts ```typescript import {defineStore} from 'pinia' export const useStore = defineStore('main', () => { // ref() 和 reactive() 就是 state 属性 // computed() 就是 getters // function() 就是 actions return {} }); ##### 3.4.2 引入 `pinia` > main.ts > > ```typescript > import {createPinia} from "pinia"; > // 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行 > // const pinia = createPinia() > // app.use(pinia) > app.use(createPinia()) > ``` ```typescript import {createApp} from 'vue'; import './style.css'; import 'animate.css' import App from './App.vue'; import router from "./routers/router.ts"; import {createPinia} from "pinia"; const app = createApp(App); // 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行 // const pinia = createPinia() // app.use(pinia) app.use(createPinia()) app.use(router); app.mount('#app'); ``` #### 3.5 配置 `scss` ##### 3.5.1 编写`scss` 变量存储文件 `scss_variable.scss` > src/styles/scss_variable.scss ```scss // 单个图表 宽度和高度 $chart-width: 100%; $chart-height: 100%; ``` ##### 3.5.2 引入 `scss` 变量配置文件 `scss_variable.scss` > `vite.config.ts` > > ```typescript > css: { > preprocessorOptions: { > scss: { > // additionalData: '@import "./src/styles/scss_variable.scss";' > additionalData: `@use "./src/styles/scss_variable.scss" as *;`, > } > } > } > ``` ```typescript import {defineConfig} from 'vite' import { resolve } from 'path' const base_url:string = 'http://192.168.10.10:8080' // https://vitejs.dev/config/ export default defineConfig({ server: { host: '0.0.0.0', strictPort: true, open: false, proxy: { // 使用 proxy 实例 '/api': { target: base_url, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, 'api'), }, } }, resolve:{//路径别名 alias:{ '@': resolve(__dirname,'./src') } }, css: { preprocessorOptions: { scss: { // additionalData: '@import "./src/styles/scss_variable.scss";' additionalData: `@use "./src/styles/scss_variable.scss" as *;`, } } } }) ``` #### 3.6 配置 `element plus` > 完整引入 > > 按需导入 > > 自动导入(本配置使用自动加载) > `vite.config.ts` ```typescript import {defineConfig} from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import {ElementPlusResolver} from 'unplugin-vue-components/resolvers' import { resolve } from 'path' const base_url:string = 'http://192.168.10.10:8080' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ // resolvers: [ElementPlusResolver({importStyle: "sass"})], resolvers: [ElementPlusResolver()], }), ], server: { host: '0.0.0.0', strictPort: true, open: false, proxy: { // 使用 proxy 实例 '/api': { target: base_url, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, 'api'), }, } }, resolve:{//路径别名 alias:{ '@': resolve(__dirname,'./src') } }, css: { preprocessorOptions: { scss: { // additionalData: '@import "./src/styles/scss_variable.scss";' additionalData: `@use "./src/styles/scss_variable.scss" as *;`, } } } }) ``` #### 3.7 echarts公共组件 > src/components/ChartLhz.vue ```vue ``` #### 3.8 引入 `datav` > commons.css ```css html, body { width: 100%; height: 100%; padding: 0; margin: 0; } ``` > typescript > // 引入 DataV > import DataVVue3 from '@kjgl77/datav-vue3' ```typescript import {createApp} from 'vue' // import './style.css' import './assets/css/commons.css' import 'animate.css' import {createPinia} from "pinia" import App from './App.vue' import DataVVue3 from '@kjgl77/datav-vue3' import router from './routers/router.ts' // import axios from 'axios' // axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token') // axios.defaults.baseURL = 'http://localhost:8080' const app = createApp(App) // 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行 // const pinia = createPinia() // app.use(pinia) app.use(createPinia()) app.use(DataVVue3) app.use(router) app.mount('#app') ``` #### 3.9 工具 > src/utils/lhz-util.ts ```typescript /** * 数据转换 */ class Transpose { /** * 行列转换 * @param matrix 二维矩阵 * @return 行列转换后的二维矩阵 */ transposeMatrix(matrix: any[][]): any[][] { // 获取原矩阵的行数和列数 const rows = matrix.length; const cols = matrix[0].length; // 初始化转置矩阵 const transposed = new Array(cols).fill(0).map(() => new Array(rows).fill(0)); // 转置操作 for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { transposed[j][i] = matrix[i][j]; } } return transposed; } /** * 中国 省份 直辖市 特别行政区 名称转换 * @param regionName 转换前地区名称只有完整地区名称前两个字 * @return 完整地区名称 */ formatRegionName(regionName: string): string { let map = new Map(); map.set("北京", "北京市"); map.set("天津", "天津市"); map.set("河北", "河北省"); map.set("山西", "山西省"); map.set("内蒙古", "内蒙古自治区"); map.set("辽宁", "辽宁省"); map.set("吉林", "吉林省"); map.set("黑龙江", "黑龙江省"); map.set("上海", "上海市"); map.set("江苏", "江苏省"); map.set("浙江", "浙江省"); map.set("安徽", "安徽省"); map.set("福建", "福建省"); map.set("江西", "江西省"); map.set("山东", "山东省"); map.set("河南", "河南省"); map.set("湖北", "湖北省"); map.set("湖南", "湖南省"); map.set("广东", "广东省"); map.set("广西", "广西壮族自治区"); map.set("海南", "海南省"); map.set("重庆", "重庆市"); map.set("四川", "四川省"); map.set("贵州", "贵州省"); map.set("云南", "云南省"); map.set("西藏", "西藏自治区"); map.set("陕西", "陕西省"); map.set("甘肃", "甘肃省"); map.set("青海", "青海省"); map.set("青海", "青海省"); map.set("宁夏", "宁夏回族自治区"); map.set("新疆", "新疆维吾尔自治区"); map.set("台湾", "台湾省"); map.set("香港", "香港特别行政区"); map.set("澳门", "澳门特别行政区"); return map.get(regionName) || regionName; } } /** * 身份证信息 */ class idCard { /** * 获取出生日期 * @param idCard 身份证 * @return 出生日期 yyyy-MM-dd 格式 */ getBirthday(idCard: string): string { // return idCard.substring(6, 10) + '-' + idCard.substring(10, 12) + '-' + idCard.substring(12, 14); let array = []; array.push(idCard.substring(6, 10)); array.push(idCard.substring(10, 12)); array.push(idCard.substring(12, 14)); return array.join('-'); } /** * 获取年龄 * @param idCard 身份证 * @return 年龄 */ getAge(idCard: string) { let date = new Date(); let age = date.getFullYear() - parseInt(idCard.substring(6, 10)) - 1; let month = date.getMonth() + 1; if (parseInt(idCard.substring(10, 12)) < month || parseInt(idCard.substring(10, 12)) == month && parseInt(idCard.substring(10, 12)) <= date.getDate()) { age++; } return age; } /** * 获取性别 * @param idCard 身份证 * @returns 1代表男性 0代表女性 */ getGender(idCard: string): number { return parseInt(idCard.substring(16, 17)) % 2 === 1 ? 1 : 0; } } export default { transpose: new Transpose(), idCardUtil: new idCard(), }; ``` ### 4、页面布局 #### 4.1 全局scss > src/styles/scss_variable.scss ```scss html, body { width: 100vw; height: 100vh; margin: 0; padding: 0; } #app_container { margin: 0; padding: 0; height: 100vh; background-color: #1F2327; color: #fff; #dv-full-screen-container { // 全屏容器可在此处设置背景图片 } } .lhz-row, .lhz-col { width: 100%; height: 100%; display: flex; flex: 1; } .lhz-row { flex-direction: row; justify-content: space-between; } .lhz-col { flex-direction: column; align-items: center; } #### 4.2 主页布局 > src/components/DataV.vue > > 该页面使用了element-plus 布局标签 ```vue #### 4.3 头部标题 > src/views/TopHeader/IndexView.vue ```vue #### 4.4 主页引入头部组件 > src/components/DataV.vue ```vue