# 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