一、echarts图表库(一个基于javascript的开源的可视化图表库)
npm i echarts@5.3.3安装
Index.vue柱状图、折线图、饼状图
<!-- eslint-disable prettier/prettier -->
<template>
<!-- <div>主界面</div> -->
<el-row :gutter="20">
<el-col :span="12">
<div id="main" style="width: 600px;height:400px;"></div>
</el-col>
<el-col :span="12">
<div id="category" style="width: 600px;height:400px;"></div>
</el-col>
</el-row>
</template>
<!-- eslint-disable prettier/prettier -->
<script>
// * 表示导入所有,as 别名
import * as echarts from 'echarts'//全局导入
import {RequestCategoryList} from '@/api/index.js'
export default {
data(){
return{
categoryList:[]//产品分类
}
},
/**
* vue组件 生命周期函数执行规则:
* vue生命周期created中启动异步任务,不会等待异步任务结果,再执行mounted生命周期函数,
* 如果要在mounted生命周期使用数据,在mounted启动异步任务,接收数据处理后续操作
*/
// created(){
// this.getCategoryList()
// },
mounted() {
// this.drawCategoryBar()
this.getCategoryList()
this.drawBar()
},
methods: {
//获取产品列表
async getCategoryList() {
const data = await RequestCategoryList()
const { resultCode,resultInfo } = data
if (resultCode === 1) {
this.categoryList =resultInfo.list
this.drawCategoryBar()
}
},
drawCategoryBar() {
const categoryX = this.categoryList.map(item=>item.name)
const categoryData = this.categoryList.map(item=>item.id)
// 初始化echarts实例
const echart = echarts.init(document.getElementById('category'));
// 指定图表的配置项和数据
const option ={
title: {//标题
text: '产品分类数量统计',
},
tooltip: {},
legend: {//多个柱状图切换
data: ['分类'],//多个柱状图切换,要跟series里面的name对应起来
},
xAxis: {
data:categoryX,
},
yAxis: {},
series: [
{
name: '分类',
type: 'bar',//柱状图,line折线图
data: categoryData,
}
]
}
// 设置配置
echart.setOption(option)
},
drawBar() {
const echart = echarts.init(document.getElementById('main'));// 初始化echarts实例
// 指定图表的配置项和数据
echart.setOption({
title: {
text: '标题'
},
tooltip: {},
legend: {
data: ['销量', '价格']//多个柱状图切换
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',//柱状图,line折线图
data: [5, 20, 36, 10, 10, 20]
},
{
name: '价格',
type: 'bar',//柱状图,line折线图
data: [10, 9.9, 36, 10, 10, 20]
}
]
});
}
}
}
</script>
<!-- eslint-disable prettier/prettier -->
<style lang="scss" scoped></style>
二、excel导出
安装:
npm i xlsx@0.17.0 -S
npm i file-saver@2.0.5 -S 文件处理
npm i lodash-es -S深克隆工具
utils→xlsxutil.js
/* eslint-disable prettier/prettier */
/* eslint-disable no-redeclare */
import XLSX from 'xlsx'
import fs from 'file-saver'
import { cloneDeep } from 'lodash-es'
import { ElMessage } from 'element-plus'
const s2ab = s => {
var buf
if (typeof ArrayBuffer !== 'undefined') {
buf = new ArrayBuffer(s.length)
var view = new Uint8Array(buf)
for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
return buf
} else {
buf = new Array(s.length)
for (var i = 0; i !== s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff
return buf
}
}
// 自动分析dom元素导出excel
export function excelExport(table, filename) {
// workbook,
const wb = XLSX.utils.table_to_book(table)
/* Export to file (start a download) */
const defaultCellStyle = {
font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
fill: { fgColor: { rgb: 'FFFFAA00' } },
}
const wopts = {
bookType: 'xlsx',
bookSST: false,
type: 'binary',
cellStyle: true,
defaultCellStyle: defaultCellStyle,
showGridLines: false,
}
const wbout = XLSX.write(wb, wopts)
const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
fs.saveAs(blob, filename + '.xlsx')
}
// 使用数据导出excel
export function excelExport2(data, headers, filename) {
const json = cloneDeep(data)
json.forEach(item => {
for (let key in item) {
// eslint-disable-next-line no-prototype-builtins
if (headers.hasOwnProperty(key)) {
item[headers[key]] = item[key]
}
delete item[key]
}
})
// excel 对象
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.json_to_sheet(json, {
header: Object.values(headers),
})
wb.SheetNames.push(filename)
wb.Sheets[filename] = ws
const defaultCellStyle = {
font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
fill: { fgColor: { rgb: 'FFFFAA00' } },
}
const wopts = {
bookType: 'xlsx',
bookSST: false,
type: 'binary',
cellStyle: true,
defaultCellStyle: defaultCellStyle,
showGridLines: false,
}
const wbout = XLSX.write(wb, wopts)
const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
fs.saveAs(blob, filename + '.xlsx')
}
// excel导入
export function excelImport(file, output) {
const type = file.name.split('.')[1]
const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
item => item === type
)
if (!fileType) {
ElMessage.error('格式错误!请重新选择')
return
}
const reader = new FileReader(file)
reader.readAsArrayBuffer(file, 'utf-8')
reader.onloadend = function (e) {
const data = e.target.result
/* Parse file */
// workbook
const wb = XLSX.read(data, {
type: 'buffer',
})
// worksheet
const ws = wb.Sheets[wb.SheetNames[0]]
const htmlstr = XLSX.utils.sheet_to_html(ws)
/* Generate HTML */
output.innerHTML = htmlstr
}
}
list.vue
<!-- eslint-disable prettier/prettier -->
<template>
<div>
<!-- 搜索 -->
<el-row :gutter="20" style="margin-bottom: 10px">
<el-col :span="4" :offset="0">
<el-input v-model="product.name" placeholder="名称搜索" clearable></el-input>
</el-col>
<el-col :span="4" :offset="0">
<el-input v-model="product.shop" placeholder="店铺名称搜索" clearable></el-input>
</el-col>
<el-col :span="4" :offset="0">
<el-input v-model="product.startPrice" placeholder="开始价格搜索" clearable></el-input>
</el-col>
<el-col :span="4" :offset="0">
<el-input v-model="product.endPrice" placeholder="结束价格搜索" clearable></el-input>
</el-col>
<el-col :span="4" :offset="0">
<el-button type="primary" @click="bindSearch">搜索产品</el-button>
</el-col>
</el-row>
<el-button-group>
<el-button type="success" size="small" @click="bindAddGood">添加</el-button>
<el-button type="success" size="small" @click="bindRefresh">刷新</el-button>
<el-button type="success" size="small" @click="bindBatchDelete">批量删除</el-button>
<el-button type="success" size="small" @click="bindExcelExport">导出excel</el-button>
</el-button-group>
<!-- 表格 -->
<el-table :data="goodsList" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" ></el-table-column>
<el-table-column label="序列号" prop="id" width="100"></el-table-column>
<el-table-column label="名称" prop="product"></el-table-column>
<el-table-column label="店铺名称" prop="shop"></el-table-column>
<el-table-column label="图片">
<template #default="scope">
<!-- <el-image
:src="scope.row.picture?.indexOf('http') === -1 ? 'http://10.7.163.142:8089/' + scope.row.picture : scope.row.picture"
style="width: 100px; height: 100px"></el-image> -->
<el-image :src="filterUrl(scope.row.picture)" style="width: 100px; height: 100px"></el-image>
</template>
</el-table-column>
<el-table-column label="价格" prop="price"></el-table-column>
<el-table-column label="类型" prop="categoryname"></el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="success" size="small" @click="bindEdit(scope.row)">编辑</el-button>
<!-- <el-button type="primary" size="small" @click="bindDelete(scope.row.id)">删除</el-button> -->
<el-popconfirm title="确认要删除此记录吗?" @confirm="bindDelete(scope.row.id)" confirm-button-text="Yes"
cancel-button-text="No">
<template #reference>
<el-button type="primary" size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination background layout="total, sizes, prev, pager, next,jumper" :total="total"
:page-sizes="[5, 10, 20]" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
<!-- total-总记录条数
sizes-选择每页几条
:page-sizes="[5,10,20]"
jumper-跳转
@size-change="handleSizeChange"//page-size 改变时触发
-->
<!-- 弹出对话框 -->
<el-dialog :title="type === 'ADD' ? '添加产品' : '编辑产品'" v-model="dialogGoodsFormVisible" width="40%">
<GoodsDialog v-if="dialogGoodsFormVisible" @close="bindClose" :goods="goods" :type="type"></GoodsDialog>
</el-dialog>
</div>
</template>
<!-- eslint-disable prettier/prettier -->
<script>
import { RequestShopList, RequestDeleteGoods, RequestBatchDelete } from '@/api/index.js'
import GoodsDialog from '@/components/GoodsDialog.vue'
import { ElMessage } from 'element-plus'
import { excelExport2 } from '@/utils/xlsxutil.js'
export default {
components: {
GoodsDialog,
},
data() {
return {
// tableData: [
// { id:1,name: '回锅肉', price: 30, category: '荤', url: 'https://image5.suning.cn/uimg/b2c/newcatentries/0000000000-000000000834870991_1_800x800.jpg' },
// { id:2,name: '土豆丝', price: 20, category: '素', url: 'https://image5.suning.cn/uimg/b2c/newcatentries/0000000000-000000000834870991_1_800x800.jpg' },
// ]
goodsList: [],
dialogGoodsFormVisible: false,
total: '',//总记录条数
pageSize: 5,//每页记录条数
pageNo: 1,//当前页号
type: 'ADD',//EDIT 编辑 ADD 添加
goods: null,
product: {
name: '',//搜索产品名称
shop: '',//搜索店铺名称
price: '',//搜索价格
startPrice: '',
endPrice: '',
},
ids: '',//删除商品id集合
}
},
created() {
this.getShopList()
},
methods: {
filterUrl(url) {
return url?.indexOf('http') === -1 ? 'http://10.7.163.142:8089/' + url : url
},
/**
* 产品列表
*/
async getShopList() {
const data = await RequestShopList(this.pageSize, this.pageNo, this.product.name, this.product.shop, this.product.startPrice, this.product.endPrice)
const { resultCode, resultInfo } = data
if (resultCode === 1) {
this.goodsList = resultInfo.list
this.total = resultInfo.total// 总记录条数
}
},
/**
* 编辑产品
*/
async bindEdit(row) {
// console.log('row ', row)
this.goods = row
this.type = 'EDIT'
this.dialogGoodsFormVisible = true
},
/**
* 删除商品
*/
async bindDelete(id) {
const data = await RequestDeleteGoods(id)
const { resultCode } = data
if (resultCode === 1) {
ElMessage({
message: '删除成功',
type: 'success',
})
this.getShopList()
}
},
/**
* 添加-弹出添加表单对话框
*/
bindAddGood() {
this.type = 'ADD'
this.dialogGoodsFormVisible = true
},
/**
* 页大小改变事件
*/
handleSizeChange(value) {
this.pageSize = value
this.getShopList()
},
/**
* 页号改变事件
*/
handleCurrentChange(value) {
this.pageNo = value
this.getShopList()
},
/**
* 刷新
*/
bindRefresh() {
this.product = {}//重置搜索数据
this.getShopList()
},
bindClose() {
this.dialogGoodsFormVisible = false
this.getShopList()
},
/**
* 搜索产品
*/
bindSearch() {
this.getShopList()
},
/*
多选
*/
handleSelectionChange(value) {
// console.log('value ', value) // [{id:10,name:''}] => [10,12,34] => '10,12,34'
const list = value.map(item => item.id)
const ids = list.join(',')
this.ids = ids
},
/*
批量删除
*/
async bindBatchDelete() {
if (this.ids?.split(',').length <= 0) {
ElMessage({
message: '请选择删除产品',
type: 'info',
})
return
}
const data = await RequestBatchDelete(this.ids)
const { resultCode } = data
if (resultCode === 1) {
ElMessage({
message: '批量删除成功',
type: 'success',
})
this.getShopList()
}
},
/**
* 导出excel
*/
bindExcelExport() {
excelExport2(
this.goodsList,
{
id: '序列号',
product: '产品名称',
shop: '店铺名称',
picture: '图片',
price: '价格',
oldprice: '原价',
categoryname: '类型名称',
},
'产品列表'
)
},
}
}
</script>
<!-- eslint-disable prettier/prettier -->
<style lang="scss" scoped>
</style>
三、tinymc富文本框
1.下载依赖
2.下载汉化包
htps//download.tiny.cloud/tinymce/community/anguagepacks/6/zh-Hans.zip?. _ga=2.37613731.2030153498.1660544987-1887555869.1660544987
3.拷贝到项目public目录中
4. 组件中使用
Index.html中引入tinymc
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script src="/tinymce/tinymce.min.js"></script>
<script src="/tinymce/langs/zh-Hans.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Add.vue
<!-- eslint-disable prettier/prettier -->
<template>
<div>
<!-- 富文本框的容器 -->
<textarea id="default-editor"></textarea>
<el-button type="primary" size="default" @click="bindConfirm"
>确定</el-button
>
</div>
</template>
<!-- eslint-disable prettier/prettier -->
<script>
import { ElMessage } from 'element-plus'
export default {
methods: {
bindConfirm() {
console.log(tinymce.activeEditor.getContent())//获取内容,用v-html解析标签
ElMessage.info('添加日志成功!')
},
},
mounted() {
this.$nextTick(() => {
// eslint-disable-next-line no-undef
tinymce.init({//初始化
selector: 'textarea#default-editor',//容器
branding: false,//取消右下角默认提示
height: 600,
plugins: 'advlist link image lists paste',//使用插件
paste_data_images: true, //支持图片粘贴
})
})
},
}
</script>
<!-- eslint-disable prettier/prettier -->
<style lang="scss" scoped></style>
四、百度地图
1. 百度地图使用前要申请密钥(ak)才可使用(需要下载百度app)
2.可以查找适合的示例直接使用lbsyun.baidu.com/index.php?t…
Index.html中引入百度地图API文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="text/javascript"
src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=你的密钥"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
map.vue
<!-- eslint-disable prettier/prettier -->
<template>
<!-- 创建地图容器元素 -->
<div id="container"></div>
</template>
<!-- eslint-disable prettier/prettier -->
<script>
export default {
mounted() {
this.initMap()
},
methods: {
initMap() {
// 创建地图实例
// eslint-disable-next-line no-undef
var map = new BMapGL.Map('container')
// 设置中心点坐标
// eslint-disable-next-line no-undef
var point = new BMapGL.Point(104.047736, 30.636993)
// 地图初始化,同时设置地图展示级别
map.centerAndZoom(point, 15)
// eslint-disable-next-line no-undef
var point1 = new BMapGL.Point(104.044215, 30.634507)
// eslint-disable-next-line no-undef
var marker = new BMapGL.Marker(point1) // 创建标注
map.addOverlay(marker) // 将标注添加到地图中
},
},
}
</script>
<!-- eslint-disable prettier/prettier -->
<style lang="scss" scoped>
#container {
height: 90%;
width: 100%;
}
</style>