前端开发常用
1、git的基本操作
1、推送到远程仓库0)创建一个文件夹,右键打开Git Bash Here1)git init //初始化仓库2)git add . //添加文件到暂存区3)git commit -m '说明' //将缓存区内容添加到本地仓库4)git push//将本地项目推送到远程仓库上git push origin master //将本地项目推送到origin远程仓库的master分支上git remote add origin 仓库地址 //将本地仓库与远程仓库关联起来
M:没有将修改的内容保存或暂存
2、拉取到本地仓库1)进入要克隆的文件夹里,右键打开Git Bash Here2)找到远程仓库的地址,并复制该地址3)使用git clone 远程仓库地址 克隆代码到本地//克隆只需要执行一次4)git pull 拉取代码
3、合并子分支git branch//查分支git checkout 分支名 //切换分支1)切换到master分支2)git merge 分支名//合并子分支到主分支出现冲突:两个分支都修改了同一文件同一行代码按钮1:保留旧的;按钮2:保留新的;按钮3:都保留;按钮4:二者对比解决冲突后要记得保存
4、添加/生成SSH公钥git config --lsit//查看1)绑定账户邮箱:git config --global user.name "用户名"git config --global user.email "邮箱"2)生成sshkey:ssh-keygen -t rsa -C "邮箱" 一直回车3)ssh-agent -s4)打开C盘–>用户–>你的用户名–>找到.ssh文件夹(linux下为cat ~/.ssh/id_rsa.pub),复制里面的内容,打开gitee,进入设置,ssh设置,粘贴到公钥,点击添加即可
5、将git客户端与码云绑定ssh -T git@gitee.com
6、合并两个仓库1)// 添加要合并仓库的远程地址,这里将其命名为 merge_branch git remote add merge_branch 地址 git remote -v //查看仓库地址2)//从远程仓库下载第二个仓库的代码git fetch merge_branch3)//创建dev分支,并将第二个仓库代码放在dev上git checkout -b dev merge_branch/master//将从第二个仓库下载的 master 分支作为要合入的项目,需要先将其分支 checkout 到一个新分支上4)//切换回原来的分支git checkout master5)//合并两个分支git merge dev git merge --no-ff --allow-unrelated-histories dev
2、echarts
2.1、echarts图表的使用
1、 获取一个dom节点,该节点必须写宽高var myChart = echarts.init(document.querySelector(ele)); myChart.setOption({})
2、legend://图例icon:'' itemHeight//高numberitemWidth//宽numberitemStyle: //图例样式color:颜色align:位置textStyle: //图例文字样式color:颜色right:距离左侧
3、grid:
4、series:1)//设置渐变色itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0,color: 'rgb(0, 221, 214)'},{offset: 1,color: 'rgb(28, 126, 215)'}])}2)series-bar.stack: 'Total'//数据堆叠3)symbolSize: 10, //设定实心点的大小
5、xAxis://x轴
6、yAxis://y轴1)nameTextStyle: {color: "#fff"}//y轴上方单位的颜色2)axisLine: {//y轴线的颜色以及宽度show: true,//显示lineStyle: {color: '#666',width: 1,type: 'solid'}}3)nameGap: '20',//y轴单位字位置
7、window.onresize = function () {myChart.resize();}
showBackground: true//显示柱状图柱子背景
2.2、echarts图表的优化
1、使用echarts图表后页面加载过慢:
2、将初始化变量提出挂载后钩子函数,var myChart = null;并声明为null
3、在每次组件销毁前,手动销毁myChart,并解绑事件onBeforeUnmount(()=>{myChart && myChart.clear();if (myChart != null) {myChart.dispose()myChart = null;}window.removeEventListener("resize", resize);})
4、//页面改变重绘图表var resize = ()=> myChart.resize();window.addEventListener('resize',resize)
3、json-server使用


大佬笔记入门篇:https://blog.csdn.net/zhou139856/article/details/125757250?spm=1001.2014.3001.5502
大佬笔记进阶篇:https://blog.csdn.net/zhou139856/article/details/125760197?spm=1001.2014.3001.5502
4、typeScript
4.1、安装
安装:npm install -g typescript 或 cnpm install -g typescript
查看版本:tsc-v
4.2、声明
1、基本数据类型约束:number、string、boolean、undefined、null
2、引用数据类型:1)数组类型:写法一:var arr1:Array<number> = [] //:Array数组,数组里只能放数字类型 写法二:var arr2:number[] = [] //number数字类型,[]数组2)对象类型:写法一:var obj:{name:string,age:number}={name:'',age:1}//对象里必须有字符串类型的name,数字类型的age,且只能有这两个//写法二:使用interface关键字定义对象类型interface Person{name:string,age:name}var obj:Person = {name:string,age:name}//必须两个都有//写法三:使用type关键字定义对象类型type Good = {name:string,price:number,isfree:boolean}var g:Good = {name:string,price:number,isfree:boolean}//三个都要有3)interface和type区别相同点:都可以用来定义对象类型(给对象类型起别名)不同点:interface只能用于对象类型,type可以用于任何任何类型4)void//无类型,用于函数返回值5)any//任何类型,可以省略,不需要写6)unknown//any的安全类型,了解7)never//代表从不会出现的类型,了解8)元组类型//赋值时必须遵循定义的顺序和类型,是一种严格的数组9)enum枚举类型//从0开始,(别名)enum sex{male,//可以用0代替female//可以用1代替}10)多种类型
3、函数:function fn(num:string):string{}//返回值必须为string类型function fn(num:string)void{}//没有返回值void
4、泛型:<类型>//使用时临时定义类型
3.3、使用
1、.ts文件//包含类型信息和可执行代码用途:减少代码书写时可能出现的错误编译:tsc -w index.ts //-w持久监听,自动刷新 index.ts文件名
2、.d.ts文件//只包含类型信息,不可编译
3、内置类型声明文件
4、///三斜线指令,引入库
5、vue文件中书写ts代码,需要在<script lang='ts'></script>标签上添加lang='ts'
5、项目打包发布
项目部署工具:ftp上传、scp2上传、Jenkins、k8s
Jenkins:Build Now:自动git拉取,打包并部署configure:查看配置
6、node.js
1、认识node
node是一个软件,是一个开源和跨平台的JavaScript运行时环境。
当JavaScript运行 在node软件上,js称为一门后端语言
当JavaScript运行在浏览器软件上,js称为一门前端语言
ECMAScript + 模块组成
2、安装node?
官网下载安装,安装完毕后,按win+r输入cmd打开终端,输入node -v 出现版本号则安装成功
nvm版本管理工具//node版本的监控
3、nodejs模块
1、分类:内置模块:node自带的模块自定义模块:自己定义的模块//遵循Commonjs规范第三方模块:下载别人写的好的模块
2、自定义模块遵循Commonjs规范:导出:语法一:module.exports.x = x;语法二:module.exports = {a,fn};语法三:exports.a = a;导入:require('路径')
3、导入第三方模块语法一:npm install swiper === npm i swiper//安装第三方swiper包npm install 模块名 --savenpm install 模块名 -S//生产阶段需要的模块,package.json里存储在dependencies里,直接安装,默认dependencies里语法二:npm install swiper --save--dev//开发阶段需要的模块,package.json里存储在devDependencies里语法三:有些包比较常用,想要只下载一次,多次使用npm i 模块名 -global //下载到本地一个目录里npm root -g //查看你下载到了哪个位置删除命令 npm uninstall 模块名4、包说明工具//package.json语法一:npm init //手动生成一个包说明书语法二:npm init --yes//自动生成一个包说明书下载包,下载到了node_modules文件夹,package.json记录了你下载的包作用:下载第三方包过多,会导致node_modules文件夹过大,可以把node_modules删除掉,package.json里会有记录,需要时候执行一下npm i命令即可下载所有依赖包也可以安装rimraf第三方模块,用于删除node_modules更迅速
4、内置模块
1、fs模块fs读取语法: const fs = require('fs');//引入//异步读取fs.readFile('读取的内容',[编码格式],function(err,data){});//读取哪个文件,什么格式,读取完调用回调函数,参数一错误,参数二代表读取的数据//同步读取let data = fs.readFileSyn('读取的内容',[编码格式]);fs写入语法:let fs = require('fs');//引入fs.writeFile('写入的内容','写的内容',[编码格式],function(err,data){});fs.writeFileSyn('写入的内容','写的内容',{encoding :[编码格式]});
2、path模块:语法: const path = require('path');1)join:path.join("a","b","c") //把三个拼接成一个路径2)_dirname:当前文件所在路径
3、url模块:语法: const url = require('url');url.parse(路径) //解析路径,拿到协议、ip...url.parse(路径,true) // 直接将返回结果query的属性变成对象形式
4、http模块:语法: const http = require('http');let app = http.createServer(function(req,res){//返回值为创建好的服务应用res.write('响应给前端的内容')//可以多行,需要配合end结束请求res.end('响应给前端的内容')//并结束请求})//req包含所有的请求信息 res包含所有的响应信息 app.listen(8989,()=>{})//监听端口号
5、常用模块
创建说明书 npm init -y
1.express//用于搭建服务,对http模块的封装1)下载express模块 npm i express2)搭建服务器 const app = express();3)get和post请求app.get(路径,(req,res)=>{req.query//获取请求参数})app.post(路径,(req,res)=>{//post请求需要添加以下两行代码app.use(express.urlencoded({ extended: false }));app.use(express.json());req.body//获取请求参数})
2.nodemonnpm i -g nodemon//安装nodemon 文件名//启动
3.nrmnpm i -g nrm//安装nrm test//查询镜像速度nrm use 镜像名//切换镜像
6、express路由
1、路由概念:端口号后面的就叫做路由post和get必须请求路由相同才可use则是开头相同即可
2、express.use('/public',express.static('public'))//以public开头的资源可以直接访问
6.1、express路由的分离
1.创建一张路由表let userRouter = express.Router()//空表
2.向路由表中挂载路由userRouter.post('/login',function(req,res){})导出 路由表 module.exports = userRouter3.当接口路由以/user访问时,会自动进入到这张路由表a
app.use('/user',require('./router/user'));//接口以/user访问时,会自动进入到路由表(./router/user)中找
6.2、例如
目录图
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uZdT9Uof-1683697329988)(E:\web\course\JavaScript\笔记\assets\1678164894048.png)]](https://img-blog.csdnimg.cn/320ddb0a09e149638e90169df35f48b5.png)
1、创建一个文件夹,并初始化说明文件 npm init -y
2、下载第三方模块express npm i express3、server.js文件const express = require('express');const app = express();//创建服务器//以'/user'开头的接口会响应'router/user'文件里,对对应路由处理app.use('/user', require('./router/user'));//监听端口app.listen(6666, () => {console.log('开启成功');})4、user.js文件const express = require('express');let userRouter = express.Router();//创建空表userRouter.post('/login', (req, res) => {res.send('登录接口');})userRouter.post('/register', (req, res) => {res.send('注册接口');})//导出路由表module.exports = userRouter;
7、中间件
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKy2GUwn-1683697329988)(E:\web\course\JavaScript\笔记\assets\1678172944841.png)]](https://img-blog.csdnimg.cn/39588b37919946599d06e8fb88e6060a.png)
概念:一个函数,有请求也有响应,继续向下走nextfunction(req,res,next){next();//继续向下}
1.应用级别中间件:应用级别的中间件(也称为全局中间件):通过app.use()或者app.get()或者app.post(),绑定到app实例上的中间件。例如:添加一个记录访问时间的中间件app.use(function (req, res, next) {fs.writeFileSync('info.txt', new Date().toLocaleString() + '---\n', { flag: 'a', encoding: 'utf-8' });next();})
2.路由级别的中间件:加在某一个路由表上例如:购物车一系列接口,访问需要判断是否携带token,如果在每个接口里都写判断,代码比较冗余,利用路由级别中间件先判断是否有token,有的话再向下执行具体接口,没有直接返回没带token,这样只用写一次。3.请求级别的中间件:写在具体的请求对应的处理函数前面
8、mongodb数据库
8.1、安装mongodb
官网:https://www.mongodb.com/
下载地址:https://www.mongodb.com/download-center/community
安装成功后,创建一个文件,用于存放数据库文件
启动:在mongodb安装目录的bin文件夹路径里输入cmd打开终端,输入mongod --dbpath后面跟上自己创建的文件夹的路径例如:C:\mongodb\bin mongod --dbpath c:\data\db2.基本指令:show dbs //查看非空的库use 数据库名 //切换数据库或创建一个空的数据库db //查看当前所在数据库db.表名/集合名.insert(JSON格式数据) //创建表并添加内容db.表名/集合名.drop() //删除表内容...
8.2、mongoose第三方模块
1、概念:用于连接mongodb数据库
2、使用:npm i mongoose //下载mongoose模块 //在npm里搜索mongoose模块,直接复制一下代码即可const mongoose = require('mongoose') //导入mongoose模块mongoose.connect('mongodb://localhost:27017/h52220').then(function(){console.log("连接成功");})
3、使用express连接数据库,并操作数据(CRUD增删改查)3.1、express搭建服务○ 下载引入express○ express 创建服务器对象app○ 写接口 ○ 监听端口号开服务器3.2 mongoose ○ 连接mongodb数据库○ 定义Schema规则○ 定义model:根据规则生成的一个表○ 使用model进行数据增删改查操作3.3、常用方法//增Model.insertMany([{key:value}])//删Model.deleteMany({条件},err=>{})Model.deleteOne({条件},err=>{})//查Model.countDocuments({条件})Model.find({条件},{可选字段返回:0/1},{skip:0,limit:10})Model.findOne({条件},{可选字段返回:0/1})//改Model.updateMany({条件},{$set:{key:value}},res=>{})Model.updateOne({条件},{$set:{key:value}},res=>{})
9、如何生成token
1、安装第三方的工具包 jsonwebtoken
2、生成token
let token jwt.sign({id:1,username:'zs'},'zhangsan',{expiresIn:'1h'})
3、解密token
jwt.verify(token,'zhangsan',(err,data)=>{if(!err) console.log(data)//解密出的对象
})
10、mockjs的使用
10.1、模拟数据
1、安装:npm i mockjs
2、创建mock文件夹,并导入mockjs
3、借用Mock的api来模拟数据:var res = Mock.mock({//生成数据//"list|100":在list数组中,生成100个规定格式的对象"list|100":[{"id|+1":1, //"id|+1":1 实现id自增,且从1开始name:'@cname', //@name英文名占位符,@cname中文名占位符"age|0-120":20, //"age|0-120":20 表示生成0-120的数字"sex|2":true, //"sex|2":true 表示随机布尔,2表示概率问题,true(2):false(1),二比一的概率,}]})
4、生成数据的规则:1)"list|100" 配合数组使用,会根据数组元素生成100个元素2)"list|+1" 如果属性的值是数字,会以数字为初始值,会自动加1(要配和1使用)3)"age|20-50" 如果属性的值是数字,会根据数字的范围生成随机整数4)"sex|1" 如果属性的值是布尔,会根据概率生成true或false5)占位符:@cname 生成中文名字 @name 生成英文名字@province 省 @city 市 @county 区@county(true) 生成有联系的省市区 @email 邮箱@image(100x100,@color) 生成占位图片并规定大小,设置随机颜色@dataimage(100x100,@color) 生成一个随机的数据图片
10.2、模拟请求
//mockjs本身自带ajax请求拦截的能力,当请求地址和请求方式一致时,会自动拦截请求,处理请求,返回响应数据
//请求方式必须小写
1、Mock.mock('/api/list,get',(req,res)=>{//req.query 获取请求参数//return resreturn {code:200,msg:"新增成功"};
})
11、UmiJS(react框架)
官网:umijs.org
特点:Umi是一个基于路由的构建的框架,集成了各种第三方库,不需要程序员自己安装
1、安装:1)npm create @umijs/umi-app //下载安装,输入y同意安装2)npm i //下载安装依赖包3)npm start //启动项目
2、pages:存放页面
3、.umirc.ts:路由配置表//配置请求代理devServer:{proxy:{"/api":{target:"请求地址",changeOrigin:true,pathRewrite:{}}}}
4、状态管理:1)在src里创建一个models文件,一个文件即是一个模块2)export default{namespace:'userlist', //模块名称state:{管理的数据},reducers:{//定义同步方法,纯函数user_add(state,action){//每一个方法都有一个state和action//深拷贝//处理逻辑//返回新的state}},effects:{//定义异步方法}}3)同步actionimport {useDispatch,useSelector} from 'umi'var dispatch = useDispatch();dispatch({type:模块名称/同步方法名,payload:参数})例如:dispatch({type:userlist/user_add,payload:参数})4)异步action1)*request_userlist是一个Generator函数,用于处理异步逻辑,接收两个参数,第一个参数是个对象,包含了当前 action 的 payload 属性;第二个参数是一个对象,包含了 call、put 和 select 方法2)其中 call 方法用于调用异步函数,put 方法用于触发同步 action,select 方法用于获取 state 中的数据。3)yield call( user_list, payload ) 调用了一个异步函数 user_list,并将 payload 作为参数传入。*request_userlist({ payload }, { call, put, select }) {var res = yield call(user_list, payload);yield put({ type: 'save_userlist', payload: res.data.data })// 触发同步action , 保存数据}
12、linux
12.1、文件
1、文件作用:etc配置、lib库、sbin命令、usr用户安装的、bin用户安装的软件、dev蓝牙键盘等设备、home用户.开头的文件默认是隐藏的
2、drwxr-xr-x 1 lj Administrators 0 May 16 09:17 apk1)d表示目录,如果是文件则是 -2)rwxr-xr-x表示该文件或目录的权限,分三组,每组三个字符,第一组为所有者权限,第二组所属组权限,第三组其他用户权限,r表示可读,w表示可写,x表示可执行,-表示没有权限3)1 表示文件或目录的硬链接数4)lj表示所有者用户名 //谁的文件5)Administrators 表示文件或目录所属组名6)0 表示文件或目录大小(字节为单位)7)May 16 09:17 //最后修改时间8)文件名
12.2、指令
1、pwd:打印当前路径(绝对路径)
2、clear:清屏
3、常识:~:当前用户文件夹/:根文件夹
4、cd / //切换到根文件夹cd ~ //切换到当前用户文件夹cd .. //切换到上一级文件夹cd . //切换到当前文件夹
5、创建目录(文件夹):mkdir 目录名
6、rm:删除文件, rmdir删除目录
7、ls:列出目录或文件列表 -l 详细信息 //最左边有d代表文件夹 -a 列出所有文件(包括隐藏文件)
8、vi:打开并编辑文件按i进入编辑模式,写内容按esc并按: 进入命令模式w保存q退出 //要保存才能退出 wq保存并退出q!强制退出 //可以不保存直接退出wq!强制保存并退出set nu //显示行号,临时的dd //删除行dw //删除一个单词(光标需要放在单词开头)
9、mv:移动文件或目录
10、touch:创建一个新的空文件
11、cat:将文件内容输出到终端
12、cp:复制文件或目录
13、grep:在文件中查找指定的字符串
14、find:查找文件或目录
15、tar:用于压缩和解压缩文件1)tar -czvf archive.tar.gz file1 file2 //将file1、file2打包为一个名为archive.tar.gz的压缩文件2)tar -xzvf archive.tar.gz //解压archive.tar.gz到当前目录
16、chmod:更改文件或目录的权限
17、chown:更改文件或目录的所有者
18、ps:显示当前运行的进程
19、top:查看系统资源占用情况
20、ssh:远程登录到另一台机器
21、scp:在本地和远程之间复制文件
22、ping:测试网络连接的状态
23、echo:用于将字符串或变量的值输出到终端上echo "Hello World" > hello.txt //输出到文件echo "Hello Again" >> hello.txt //追加到文件
24、less:逐页显示文件内容
25、date // 显示当前日期
26、history//显示最近敲的命令history 10 //显示十条
13、数据库(mysql)
1、切换版本:指定端口号:mysql -uroot -P端口号 -p密码
见思维导图
14、mysql+vue3增删改查
14.1、后端
1、设计数据结构,建表
create dabatase demo;
CREATE TABLE goods( good_id INT PRIMARY KEY AUTO_INCREMENT,good_type VARCHAR(100),good_name VARCHAR(100) NOT NULL,good_num INT NOT NULL
);
2、连接mysql数据库
const mysql = require('mysql');const conn = mysql.createConnection({host: '127.0.0.1',user: 'root',password: '数据库密码',port: '端口号',database: '数据库名'
})conn.connect((err) => {if (err) throw err;console.log("mysql 数据库连接成功!");
});module.exports = conn;
3、创建一个服务,监听端口
const express = require('express');const app = express();
//处理post参数
// app.use(express.json());
// app.use(express.urlencoded({ extended: false }));const goodsRouter = require('./router/goods')
app.use('/api/goods', goodsRouter)app.listen('8888', () => {console.log("服务端运行在 http://localhost:8888");
})
4、编写接口逻辑
const express = require('express');//创建express子路由
const goodsRouter = express.Router();//连接数据库
const conn = require('../db/index.js')//分页查询
goodsRouter.get('/list', (req, res) => {let params = req.query;let page_num = params.page_num || 1;let page_size = params.page_size || 10;// const sql = `select * from goods limit ${(page_num - 1) * page_size},${page_size}`const sql = `select * from goods`;conn.query(sql, (err, data) => {if (err) {res.send({ code: 400, msg: '查询失败' });} else {res.send({ code: 200, msg: '查询成功', data })}})
})//添加商品
goodsRouter.get('/add', (req, res) => {const params = req.query;const goodsType = params.good_type;const goodsName = params.good_name;const goodsNum = params.good_num;const sql = `insert into goods(good_type,good_name,good_num) values(?,?,?)`;conn.query(sql, [goodsType, goodsName, goodsNum], (err, data) => {if (err) {res.send({ code: 400, msg: '新增商品失败' })} {res.send({ code: 200, msg: '新增商品成功', data });}})
})//修改商品
goodsRouter.get('/update', (req, res) => {const params = req.query;const id = params.good_id;const goodsType = params.good_type;const goodsName = params.good_name;const goodsNum = params.good_num;const sql = `update goods set good_type=?,good_name=?,good_num=? where good_id=?`;conn.query(sql, [goodsType, goodsName, goodsNum, id], (err, data) => {if (err) {res.send({ code: 400, msg: '修改失败' });} else {res.send({ code: 200, msg: '修改成功', data });}})
})//删除商品
goodsRouter.get('/del', (req, res) => {const params = req.query;const id = params.good_id;const sql = `delete from goods where good_id=?`;conn.query(sql, [id], (err, data) => {if (err) {res.send({ code: 400, msg: '删除失败' });} {res.send({ code: 200, msg: '删除成功', data });}})
})module.exports = goodsRouter;
14.2、前端
1、配置反向代理,将请求发送到后端对应接口
server: {proxy: {'/api': {target: 'http://localhost:8888'}}}
2、一个请求一个函数管理
3、编写页面,及逻辑,根据需求向后端发送请求
15、表格封装
1.1、封装
1.2、使用
{{ scope.$index + 1 }}
1.3、思路
1、将Table组件通用的js逻辑,以及一些通用的样式,封装在组件内部,实现逻辑和样式的复用,对外暴露一些属性,把数据和列配置传入组件内部,在外部可以通过列配置可以对表格列进行类型、插槽、表头、数据进行配置,并向外暴露了单选,多选,选项改变三个事件
16、文件上传
16.1、前端逻辑
1、<input type="file" onChange={changeFile}/> //创建一个file文件上传,并绑定一个值改变事件
var [fileDate,setFileDate] = useState(null);//点击上传之后,值改变,后赋值给fileDate
var changeFile = (e)=>{setFileDate(e.target.files[0])
}
//在点击提交后,创建一个formData表单对象const formData = new FormData();
//通过append配置名,及数据formData.append("file", fileDate);
//向后端发送
axios.post('http://localhost:8888/api/user/file',formData,{headers:{'Content-Type': 'multipart/form-data'}
}).then((res=>{console.log(res);
})).catch(error=>{console.log(error);
})
16.2、后端逻辑(仅供参考)
const upload = multer({ dest: './src/db/' }); // 文件上传到uploads目录下
router.post('api/user/file', upload.single("file"), (req, res) => {try {// 获取文件名和文件类型const { originalname } = req.file;// 生成唯一的文件名,我通过的是时间戳+文件名const filename = `${Date.now()}-${originalname}`;// 文件保存路径const filePath = path.join(__dirname, '../db/', filename);//写入文件fs.writeFile(filePath, req.file.buffer);res.send('文件上传成功');} catch {res.status(500).send('Sever error')}
});
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
