Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop

This commit is contained in:
caoqianming 2022-01-29 15:25:24 +08:00
commit 53bf894773
8 changed files with 824 additions and 34 deletions

View File

@ -153,8 +153,7 @@ export const asyncRoutes = [
meta: { title: '产品管理', icon: 'example', perms: ['mtm_productprocess'] }
},
]
}
,
},
{
path: '/pm',
component: Layout,
@ -208,8 +207,7 @@ export const asyncRoutes = [
}
]
}
,
},
{
path: '/wpm',
component: Layout,
@ -339,8 +337,7 @@ export const asyncRoutes = [
hidden: true
}
]
}
,
},
{
path: '/qm',
component: Layout,
@ -407,7 +404,6 @@ export const asyncRoutes = [
]
},
{
path: '/personnel',
component: Layout,
@ -435,8 +431,7 @@ export const asyncRoutes = [
},
]
}
,
},
{
path: '/inm',
component: Layout,
@ -492,29 +487,67 @@ export const asyncRoutes = [
]
},
{
path: '/procurement',
component: Layout,
redirect: '/procurement/vendor',
name: 'procurement',
meta: { title: '采购管理', icon: 'example', perms: ['procurement_set'] },
children: [
{
path: 'vendor',
name: 'vendor',
component: () => import('@/views/procurement/vendor'),
meta: { title: '供应商', icon: 'example', perms: ['vendor_manage'] }
},
{
path: 'vendor',
name: 'vendor',
component: () => import('@/views/procurement/vendor'),
meta: { title: '采购订单', icon: 'example', perms: ['vendor_manage'] }
}
]
},
{
path: '/procurement',
component: Layout,
redirect: '/procurement/vendor',
name: 'procurement',
meta: { title: '采购管理', icon: 'example', perms: ['procurement_set'] },
children: [
{
path: 'vendor',
name: 'vendor',
component: () => import('@/views/procurement/vendor'),
meta: { title: '供应商', icon: 'example', perms: ['vendor_manage'] }
},
{
path: 'vendor',
name: 'vendor',
component: () => import('@/views/procurement/vendor'),
meta: { title: '采购订单', icon: 'example', perms: ['vendor_manage'] }
}
]
},
{
path: '/statistics',
component: Layout,
redirect: '/statistics/progressStatistics',
name: 'statistics',
meta: { title: '统计分析', icon: 'example', perms: ['workflow_manage'] },
children: [
{
path: 'progressStatistics',
name: 'progressStatistics',
component: () => import('@/views/statistics/progressStatistics'),
meta: { title: '进度统计', icon: 'example', perms: ['workflow_index'] }
},
{
path: 'materialStatistics',
name: 'materialStatistics',
component: () => import('@/views/statistics/materialStatistics'),
meta: { title: '物料统计', icon: 'example', perms: ['workflow_index'] }
},
{
path: 'personStatistics',
name: 'personStatistics',
component: () => import('@/views/statistics/personStatistics'),
meta: { title: '人员统计', icon: 'example', perms: ['workflow_index'] }
},
{
path: 'costStatistics',
name: 'costStatistics',
component: () => import('@/views/statistics/costStatistics'),
meta: { title: '成本统计', icon: 'example', perms: ['workflow_index'] }
},
{
path: 'testStatistics',
name: 'testStatistics',
component: () => import('@/views/statistics/testStatistics'),
meta: { title: '检验统计', icon: 'example', perms: ['workflow_index'] }
},
]
},
{
path: '/workflow',
component: Layout,
@ -700,6 +733,12 @@ export const asyncRoutes = [
component: () => import('@/views/testModel/faceLogin'),
meta: { title: '人脸识别登录', icon: 'example' }
},
{
path: 'caram',
name: 'caram',
component: () => import('@/views/testModel/caram'),
meta: { title: '相机调用', icon: 'example' }
},
{
path: 'markImage',
name: 'markImage',

View File

@ -0,0 +1,69 @@
<template>
<div :id="id" :class="className" style="width: 100%!important;" :style="{ height: height, width: width }"/>
</template>
<script>
export default {
name: "charts",
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '2.5rem'
},
options: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null
}
},
watch: {
options: {
handler(options) {
this.chart.setOption(options, true)
},
deep: true
}
},
mounted() {
this.initChart();
/*window.addEventListener("resize",function () {
this.chart = this.$echarts.init(document.getElementById(this.id));
let myCharts=document.getElementById(this.id); // 增加这一行
myCharts.style.width=window.innerWidth-400+ 'px'; // 再增加这一行
this.$echarts.init(document.getElementById(this.id)).resize();
})*/
},
beforeDestroy() {
this.chart.dispose();
this.chart = null
},
methods: {
initChart() {
this.chart = this.$echarts.init(document.getElementById(this.id));
this.chart.setOption(this.options);
}
}
}
</script>
<style scoped>
.chartsName{
width: 100%!important;
}
</style>

View File

@ -1,10 +1,10 @@
<template>
<div></div>
</template>
<script>
export default {
name: "largeScreen"
name: "costStatistics"
}
</script>

View File

@ -0,0 +1,364 @@
<template>
<div class="app-container">
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
<el-tab-pane label="废料统计" name="废料统计">
<el-row :gutter="5">
<el-col :span="3" style="height: 1px"></el-col>
<el-col :span="5">
<div class="chartsTitle">废料原因占比</div>
<Echart
:options="pieOptions"
id="pieChart"
height="400px"
width="260px"
></Echart>
</el-col>
<el-col :span="13">
<div class="chartsTitle">废料原因统计</div>
<div id="barChart" style="width:100%;height: 400px;"></div>
</el-col>
</el-row>
<div style="padding: 20px;">
<div class="chartsTitle">废料明细表</div>
<el-table
small
:data="list"
fit stripe
size="mini"
pager-count="3"
style="border-top: 1px solid #f5f5f5;"
>
<el-table-column label="序号" type="index">
</el-table-column>
<el-table-column label="物料编号" prop="card">
</el-table-column>
<el-table-column label="物料型号" prop="sco">
</el-table-column>
<el-table-column label="物料名称" prop="name" show-overflow-tooltip>
</el-table-column>
<el-table-column label="报废原因" prop="reason">
</el-table-column>
<el-table-column label="报废数量" prop="num">
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="采购统计" name="采购统计">
<el-row :gutter="5" v-if="activeName==='采购统计'">
<el-col :span="2" style="height: 1px;"></el-col>
<el-col :span="10">
<div class="chartsTitle">采购物料表</div>
<charts
:id="chartId1"
:options="barOptions"
:className="chartsName"
height="400px"
width="600px"
>
</charts>
</el-col>
<el-col :span="10">
<div class="chartsTitle">采购供应商表</div>
<charts
:id="chartId2"
:options="barOptions"
:className="chartsName"
height="400px"
width="600px"
>
</charts>
</el-col>
</el-row>
<div style="padding: 20px">
<div class="chartsTitle">采购明细表</div>
<el-table
small
:data="list"
fit stripe
size="mini"
pager-count="3"
style="border-top: 1px solid #f5f5f5;"
>
<el-table-column label="序号" type="index" width="50">
</el-table-column>
<el-table-column label="名称" prop="name" show-overflow-tooltip>
</el-table-column>
<el-table-column label="数量" prop="num" show-overflow-tooltip>
</el-table-column>
<el-table-column label="单位" prop="name" show-overflow-tooltip>
</el-table-column>
<el-table-column label="供应商" prop="sco" show-overflow-tooltip>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="废料来源" name="废料来源">
<el-row>
<el-col v-if="activeName==='废料来源'">
<div class="chartsTitle">废料来源</div>
<charts
:id="chartId3"
:options="barOptions"
:className="chartsName"
height="400px"
>
</charts>
</el-col>
</el-row>
<div style="padding: 20px;">
<div class="chartsTitle">废料来源明细表</div>
<el-table
small
:data="list"
fit stripe
size="mini"
pager-count="3"
style="border-top: 1px solid #f5f5f5;"
>
<el-table-column label="序号" type="index">
</el-table-column>
<el-table-column label="编号" prop="card">
</el-table-column>
<el-table-column label="名称" prop="name" show-overflow-tooltip>
</el-table-column>
<el-table-column label="数量" prop="num">
</el-table-column>
<el-table-column label="供应商" prop="sco" show-overflow-tooltip>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import charts from './charts.vue'
import Echart from '@/components/echart';
export default {
name: "materialStatistics",
components: {
charts,
Echart
},
data() {
return {
chartId1:'chart1',
chartId2:'chart2',
chartId3:'chart3',
barChart:null,
barChart1:null,
pieOptions: {},
barOptions: {},
activeName:'废料统计',
chartsName:"chartsName",
cdata: {
xData: ["气泡", "划痕"],
seriesData: [
{value: 30, name: "气泡"},
{value: 70, name: "划痕"},
]
},
chartData: {
xAxisData: ["气泡", "划痕"],
seriesData: [30, 70],
},
xAxisbar:["供应商1", "供应商2", "供应商3", "供应商4", "供应商5", "供应商6", "供应商7"],
barData: [80, 95, 96, 96, 96, 98, 99],
list: [
{id: 1, name: 'HIehd91', card: '3331', sco: 'REF-31',num:2,reason:"气泡"},
{id: 2, name: 'HIehd92', card: '3332', sco: 'REF-32',num:1,reason:"划痕"},
{id: 3, name: 'HIehd93', card: '3333', sco: 'REF-33',num:3,reason:"擦伤"},
{id: 4, name: 'HIehd94', card: '3334', sco: 'REF-34',num:2,reason:"气泡"},
{id: 5, name: 'HIehd95', card: '3335', sco: 'REF-35',num:1,reason:"擦伤"},
{id: 6, name: 'HIehd96', card: '3336', sco: 'REF-36',num:2,reason:"气泡"},
{id: 7, name: 'HIehd97', card: '3337', sco: 'REF-37',num:1,reason:"划痕"},
],
}
},
watch: {
cdata: {
handler(newData) {
this.pieOptions = {
color: [
"#32c5e9",
"#ffdb5c"
],
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
toolbox: {
show: true
},
calculable: true,
series: [
{
name: '废料原因',
type: 'pie', // 设置图表类型为饼图
radius: '65%', // 饼图的半径外半径为可视区尺寸容器高宽中较小一项 55% 长度
center: ['50%', '50%'], //圆心位置
data:newData.seriesData
}
]
}
},
immediate: true,
},
immediate: true,
deep: true
},
methods: {
drawChart() {
let that = this;
this.barChart = this.$echarts.init(document.getElementById('barChart'));
this.barChart.setOption({
grid: {
top: '10%',
left: '3%',
right: '5%',
bottom: '1%',
containLabel: true
},
tooltip: {
trigger: 'item',
formatter: function (params) {
let color = params.color;//图例颜色
let htmlStr = '<div>';
htmlStr += params.name + '<br/>';
htmlStr += '<span style="height:10px;width:10px;font-size:12px;border-radius:5px;margin-right:5px;font-family:Consolas;display:inline-block;background:' + color + ';"></span>';
htmlStr += params.seriesName + '' + params.value + '%';
htmlStr += '</div>';
return htmlStr;
}
},
xAxis: {
axisTick: {
show: false
},
splitLine: {
show: false, //去掉X轴分割线
},
data: that.chartData.xAxisData,
},
yAxis: {
axisLine: {
show: true,//y轴线
},
axisTick: {
show: false//Y轴刻度线
},
axisLabel: {
color: '#333333'//Y轴文本颜色
},
splitLine: {
show: true, //Y轴分割线
lineStyle: {
color: '#dddddd'//Y轴分割线颜色
}
},
},
series: [{
name: '成品率',
type: 'bar',
barWidth: 20,
data: that.chartData.seriesData,
label: {
show: true, //开启显示
position: 'top', //在上方显示
formatter: '{c}%',//显示百分号
textStyle: { //数值样式
color: 'black',//字体颜色
fontSize: 10//字体大小
}
},
itemStyle: {
color: '#409EFF'
},
}]
});
},
handleClick(tab){
// console.log(tab);
// debugger;
},
},
mounted() {
this.drawChart();
this.barOptions ={
grid: {
top: '10%',
left: '3%',
right: '5%',
bottom: '1%',
containLabel: true
},
tooltip: {
trigger: 'item',
formatter: function (params) {
let color = params.color;//图例颜色
let htmlStr = '<div>';
htmlStr += params.name + '<br/>';
htmlStr += '<span style="height:10px;width:10px;font-size:12px;border-radius:5px;margin-right:5px;font-family:Consolas;display:inline-block;background:' + color + ';"></span>';
htmlStr += params.seriesName + '' + params.value + '%';
htmlStr += '</div>';
return htmlStr;
}
},
xAxis: {
axisTick: {
show: false
},
splitLine: {
show: false, //去掉X轴分割线
},
data: this.xAxisbar,
},
yAxis: {
axisLine: {
show: true,//y轴线
},
axisTick: {
show: false//Y轴刻度线
},
axisLabel: {
color: '#333333'//Y轴文本颜色
},
splitLine: {
show: true, //Y轴分割线
lineStyle: {
color: '#dddddd'//Y轴分割线颜色
}
},
},
series: [{
name: '成品率',
type: 'bar',
barWidth: 20,
data: this.barData,
label: {
show: true, //开启显示
position: 'top', //在上方显示
formatter: '{c}',//显示百分号
textStyle: { //数值样式
color: 'black',//字体颜色
fontSize: 10//字体大小
}
},
itemStyle: {
color: '#409EFF'
},
}]
}
}
}
</script>
<style scoped>
.chartsTitle{
text-align: center;
height: 35px;
line-height: 35px;
font-size: 22px;
}
</style>

View File

@ -0,0 +1,13 @@
<template>
<div></div>
</template>
<script>
export default {
name: "personStatistics"
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,175 @@
<template>
<div class="app-container">
<el-row :gutter="5">
<el-col :span="8">
<el-card>
<Echart
:options="pieOptions"
id="pieChart"
height="400px"
width="260px"
></Echart>
</el-card>
</el-col>
<el-col :span="16">
<el-card>
<charts
:id="chartId1"
:options="barOptions"
:className="chartsName"
height="400px"
width="600px"
>
</charts>
</el-card>
</el-col>
</el-row>
<el-col>
<el-card>
<charts
:id="chartId2"
:options="barOptions"
:className="chartsName"
height="480px"
width="100%"
>
</charts>
</el-card>
</el-col>
</div>
</template>
<script>
import charts from './charts.vue'
import Echart from '@/components/echart';
export default {
name: "progressStatistics",
components: {
Echart,
charts
},
data() {
return {
chartsName:'barChart',
chartId1:'chart1',
chartId2:'chart2',
pieOptions: {},
barOptions: {},
cdata: {
xData: ["交付率", "逾期率"],
seriesData: [
{value: 99, name: "交付率"},
{value: 1, name: "逾期率"},
]
},
xAxisbar:["冷加工", "热弯", "钢化", "镀膜", "夹层", "包边", "装框"],
barData: [80, 95, 96, 96, 96, 98, 99],
}
},
watch: {
cdata: {
handler(newData) {
this.pieOptions = {
color: [
"#32c5e9",
"#ffdb5c"
],
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
toolbox: {
show: true
},
calculable: true,
series: [
{
name: '访问来源',
type: 'pie', // 设置图表类型为饼图
radius: '65%', // 饼图的半径外半径为可视区尺寸容器高宽中较小一项 55% 长度
center: ['50%', '50%'], //圆心位置
data:newData.seriesData
}
]
}
},
immediate: true,
},
immediate: true,
deep: true
},
methods: {
},
mounted() {
this.barOptions ={
grid: {
top: '10%',
left: '3%',
right: '5%',
bottom: '1%',
containLabel: true
},
tooltip: {
trigger: 'item',
formatter: function (params) {
let color = params.color;//图例颜色
let htmlStr = '<div>';
htmlStr += params.name + '<br/>';
htmlStr += '<span style="height:10px;width:10px;font-size:12px;border-radius:5px;margin-right:5px;font-family:Consolas;display:inline-block;background:' + color + ';"></span>';
htmlStr += params.seriesName + '' + params.value + '%';
htmlStr += '</div>';
return htmlStr;
}
},
xAxis: {
axisTick: {
show: false
},
splitLine: {
show: false, //去掉X轴分割线
},
data: this.xAxisbar,
},
yAxis: {
axisLine: {
show: true,//y轴线
},
axisTick: {
show: false//Y轴刻度线
},
axisLabel: {
color: '#333333'//Y轴文本颜色
},
splitLine: {
show: true, //Y轴分割线
lineStyle: {
color: '#dddddd'//Y轴分割线颜色
}
},
},
series: [{
name: '成品率',
type: 'bar',
barWidth: 20,
data: this.barData,
label: {
show: true, //开启显示
position: 'top', //在上方显示
formatter: '{c}%',//显示百分号
textStyle: { //数值样式
color: 'black',//字体颜色
fontSize: 10//字体大小
}
},
itemStyle: {
color: '#409EFF'
},
}]
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,13 @@
<template>
<div></div>
</template>
<script>
export default {
name: "testStatistics"
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,117 @@
<template>
<div>
<el-button type="primary" @click="openVideo">打开摄像头</el-button>
<el-button @click="closeVideo">关闭摄像头</el-button>
<el-button type="danger" @click="screenshot">截图</el-button>
<div>
<video id="video" ref="video" />
</div>
<canvas ref="canvas" width="400" height="300" style="display:none" />
<!-- 截图展示图片 -->
<img ref="screenshot">
</div>
</template>
<script>
export default {
name: "caram",
methods:{
// 打开摄像头
openVideo() {
// 老的浏览器可能根本没有实现 mediaDevices所以我们可以先设置一个空的对象
console.log("navigator.mediaDevices", navigator.mediaDevices);
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 一些浏览器部分支持 mediaDevices我们不能直接给对象设置 getUserMedia
// 因为这样可能会覆盖已有的属性这里我们只会在没有getUserMedia属性的时候添加它
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = constraints => {
// 首先如果有getUserMedia的话就获得它
const getUserMedia =
navigator.getUserMedia ||
(navigator.getUserMedia =
navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia ||
navigator.msGetUserMedia);
console.log("getUserMedia", getUserMedia);
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
return Promise.reject(new Error("该浏览器暂不支持摄像头!"));
}
// 否则为老的navigator.getUserMedia方法包裹一个Promise
return new Promise((resolve, reject) => {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
const constraints = {
audio: true,
video: {
width: { ideal: 1280, max: 1920 },
height: { ideal: 720, max: 1080 }
}
};
console.log("window.navigator", window.navigator);
window.navigator.mediaDevices
.getUserMedia(constraints)
.then(stream => {
const video = this.$refs.video;
// 旧的浏览器可能没有srcObject
if ("srcObject" in video) {
video.srcObject = stream;
} else {
// 防止在新的浏览器里使用它因为它已经不再支持了
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = e => {
video.play();
};
})
.catch(err => {
console.log(err.name + ": " + err.message);
});
},
// 截图
screenshot() {
// 获取视频
const video = this.$refs.video;
// 获取截图的地址
const screenshot = this.$refs.screenshot;
// 获取canvas
const canvas = this.$refs.canvas;
// 渲染一个2d平面的视图
const ctx = canvas.getContext("2d");
// 设置canvas 视图文件地址和大小
ctx.drawImage(video, 0, 0, 400, 300);
// 将数据转为base64赋值给img标签的src属性
screenshot.src = canvas.toDataURL("image/png");
console.log("screenshot.src", screenshot.src);
const imgData = canvas
.toDataURL("image/png")
.replace("image/png", "image/octet-stream");
// 下载图片到本地
const save_link = document.createElementNS(
"http://www.w3.org/1999/xhtml",
"a"
);
save_link.href = imgData;
save_link.download = "file_" + new Date().getTime() + ".png";
save_link.click();
},
// 关闭摄像头
closeVideo() {
console.log("srcObject", this.$refs.video.srcObject);
const srcObject = this.$refs.video.srcObject ? this.$refs.video.srcObject.getTracks() : this.$refs.video.src.getTracks()
srcObject.forEach(track => {
track.stop();
this.$refs.video.src = null;
});
},
}
}
</script>
<style scoped>
</style>