diff --git a/hb_client/src/assets/pageBg.jpg b/hb_client/src/assets/pageBg.jpg new file mode 100644 index 0000000..a1764a0 Binary files /dev/null and b/hb_client/src/assets/pageBg.jpg differ diff --git a/hb_client/src/assets/scss/_variables.scss b/hb_client/src/assets/scss/_variables.scss new file mode 100644 index 0000000..80edb92 --- /dev/null +++ b/hb_client/src/assets/scss/_variables.scss @@ -0,0 +1,98 @@ +// 颜色 +$colors: ( + "primary": #1A5CD7, + "info-1": #4394e4, + "info": #4b67af, + "white": #ffffff, + "light": #f9f9f9, + "grey-1": #999999, + "grey": #666666, + "dark-1": #5f5f5f, + "dark": #222222, + "black-1": #171823, + "black": #000000, + "icon": #5cd9e8 +); + +// 字体大小 +$base-font-size: 0.2rem; +$font-sizes: ( + xxs: 0.1, + //8px + xs: 0.125, + //10px + sm: 0.2875, + //12px + md: 0.1625, + //13px + lg: 0.175, + //14px + xl: 0.2, + //16px + xxl: 0.225, + //18px + xxxl: 0.25 //20px,,,, +); + +// 宽高 +.w-100 { + width: 100%; +} +.h-100 { + height: 100%; +} + +//flex +.d-flex { + display: flex; +} +.flex-column { + flex-direction: column; +} +.flex-wrap { + flex-wrap: wrap; +} +.flex-nowrap { + flex-wrap: nowrap; +} +$flex-jc: ( + start: flex-start, + end: flex-end, + center: center, + between: space-between, + around: space-around, + evenly: space-evenly, +); + +$flex-ai: ( + start: flex-start, + end: flex-end, + center: center, + stretch: stretch, +); + +.flex-1 { + flex: 1; +} + +//.mt-1 => margin top +//spacing +$spacing-types: ( + m: margin, + p: padding, +); +$spacing-directions: ( + t: top, + r: right, + b: bottom, + l: left, +); +$spacing-base-size: 0.5rem; +$spacing-sizes: ( + 0: 0, + 1: 0.5, + 2: 1, + 3: 1.5, + 4: 2, + 5: 2.5, +); diff --git a/hb_client/src/assets/scss/index.scss b/hb_client/src/assets/scss/index.scss new file mode 100644 index 0000000..3630421 --- /dev/null +++ b/hb_client/src/assets/scss/index.scss @@ -0,0 +1,144 @@ +#index { + color: #d3d6dd; + width: 1920px; + height: 1080px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + transform-origin: left top; + overflow: hidden; + + .bg { + width: 100%; + height: 100%; + padding: 16px 16px 0 16px; + background-image: url("../../assets/pageBg.jpg"); + background-size: cover; + background-position: center center; + } + + .host-body { + .dv-dec-10, + .dv-dec-10-s { + width: 33.3%; + height: 5px; + } + .dv-dec-10-s { + transform: rotateY(180deg); + } + .dv-dec-8 { + width: 200px; + height: 50px; + } + .title { + position: relative; + width: 500px; + text-align: center; + background-size: cover; + background-repeat: no-repeat; + + .title-text { + font-size: 24px; + position: absolute; + bottom: 0; + left: 50%; + transform: translate(-50%); + } + + .dv-dec-6 { + position: absolute; + bottom: -30px; + left: 50%; + width: 250px; + height: 8px; + transform: translate(-50%); + } + } + + // 第二行 + .aside-width { + width: 40%; + } + .react-r-s, + .react-l-s { + background-color: #0f1325; + } + + // 平行四边形 + .react-right { + &.react-l-s { + text-align: right; + width: 500px; + } + font-size: 18px; + width: 300px; + line-height: 50px; + text-align: center; + transform: skewX(-45deg); + + .react-after { + position: absolute; + right: -25px; + top: 0; + height: 50px; + width: 50px; + background-color: #0f1325; + transform: skewX(45deg); + } + + .text { + display: inline-block; + transform: skewX(45deg); + } + } + + .react-left { + &.react-l-s { + width: 500px; + text-align: left; + } + font-size: 18px; + width: 300px; + height: 50px; + line-height: 50px; + text-align: center; + transform: skewX(45deg); + background-color: #0f1325; + + .react-before { + position: absolute; + left: -25px; + top: 0; + height: 50px; + width: 50px; + background-color: #0f1325; + transform: skewX(-45deg); + } + + .text { + display: inline-block; + transform: skewX(-45deg); + } + } + + .body-box { + margin-top: 16px; + display: flex; + flex-direction: column; + + //下方区域的布局 + .content-box { + display: grid; + grid-template-columns: 2fr 3fr 5fr 3fr 2fr; + } + + // 底部数据 + .bototm-box { + margin-top: 10px; + display: grid; + grid-template-columns: repeat(2, 50%); + } + } + } +} diff --git a/hb_client/src/assets/scss/style.scss b/hb_client/src/assets/scss/style.scss new file mode 100644 index 0000000..143bdb3 --- /dev/null +++ b/hb_client/src/assets/scss/style.scss @@ -0,0 +1,154 @@ +@import "./variables"; + +// 全局样式 +* { + margin: 0; + padding: 0; + list-style-type: none; + outline: none; + box-sizing: border-box; +} + +html { + margin: 0; + padding: 0; +} +body { + font-family: Arial, Helvetica, sans-serif; + //line-height: 1.2em; + background-color: #f1f1f1; + margin: 0; + padding: 0; +} +a { + color: #343440; + text-decoration: none; +} +.clearfix { + &::after { + content: ""; + display: table; + height: 0; + line-height: 0; + visibility: hidden; + clear: both; + } +} +//浮动 +.float-r { + float: right; +} +//浮动 +.float-l { + float: left; +} +// 字体加粗 +.fw-b { + font-weight: bold; +} +//文章一行显示,多余省略号显示 +.title-item { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.bg-color-black { + background-color: rgba(19, 25, 47, 0.6); +} +.bg-color-blue { + background-color: #1a5cd7; +} +.colorBlack { + color: #272727 !important; + &:hover { + color: #272727 !important; + } +} +.colorGrass { + color: #33cea0; + &:hover { + color: #33cea0 !important; + } +} +.colorRed { + color: #ff5722; + &:hover { + color: #ff5722 !important; + } +} +.colorText { + color: #d3d6dd !important; + &:hover { + color: #d3d6dd !important; + } +} +.colorBlue { + color: #257dff !important; + &:hover { + color: #257dff !important; + } +} +//颜色 +@each $colorkey, $color in $colors { + .text-#{$colorkey} { + color: $color; + } + .bg-#{$colorkey} { + background-color: $color; + } +} +//对齐 +@each $var in (left, center, right) { + .text-#{$var} { + text-align: $var !important; + } +} +//flex +@each $key, $value in $flex-jc { + .jc-#{$key} { + justify-content: $value; + } +} +@each $key, $value in $flex-ai { + .ai-#{$key} { + align-items: $value; + } +} +//字体 +@each $fontkey, $fontvalue in $font-sizes { + .fs-#{$fontkey} { + font-size: $fontvalue * $base-font-size; + } +} +//.mt-1 => margin top +//spacing +@each $typekey, $type in $spacing-types { + //.m-1 + @each $sizekey, $size in $spacing-sizes { + .#{$typekey}-#{$sizekey} { + #{$type}: $size * $spacing-base-size; + } + } + //.mx-1 + @each $sizekey, $size in $spacing-sizes { + .#{$typekey}x-#{$sizekey} { + #{$type}-left: $size * $spacing-base-size; + #{$type}-right: $size * $spacing-base-size; + } + .#{$typekey}y-#{$sizekey} { + #{$type}-top: $size * $spacing-base-size; + #{$type}-bottom: $size * $spacing-base-size; + } + } + //.mt-1 + @each $directionkey, $direction in $spacing-directions { + @each $sizekey, $size in $spacing-sizes { + .#{$typekey}#{$directionkey}-#{$sizekey} { + #{$type}-#{$direction}: $size * $spacing-base-size; + } + } + } + .#{$typekey} { + #{$type}: 0; + } +} diff --git a/hb_client/src/components/echart/chartRate.vue b/hb_client/src/components/echart/chartRate.vue new file mode 100644 index 0000000..58b6fd7 --- /dev/null +++ b/hb_client/src/components/echart/chartRate.vue @@ -0,0 +1,104 @@ + + + + + + + + + + diff --git a/hb_client/src/components/echart/index.vue b/hb_client/src/components/echart/index.vue new file mode 100644 index 0000000..db61b5e --- /dev/null +++ b/hb_client/src/components/echart/index.vue @@ -0,0 +1,65 @@ + + + + + + + diff --git a/hb_client/src/components/echart/theme.json b/hb_client/src/components/echart/theme.json new file mode 100644 index 0000000..ce81aba --- /dev/null +++ b/hb_client/src/components/echart/theme.json @@ -0,0 +1,490 @@ +{ + "color": [ + "#2d8cf0", + "#19be6b", + "#ff9900", + "#E46CBB", + "#9A66E4", + "#ed3f14" + ], + "backgroundColor": "rgba(0,0,0,0)", + "textStyle": {}, + "title": { + "textStyle": { + "color": "#516b91" + }, + "subtextStyle": { + "color": "#93b7e3" + } + }, + "line": { + "itemStyle": { + "normal": { + "borderWidth": "2" + } + }, + "lineStyle": { + "normal": { + "width": "2" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true + }, + "radar": { + "itemStyle": { + "normal": { + "borderWidth": "2" + } + }, + "lineStyle": { + "normal": { + "width": "2" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true + }, + "bar": { + "itemStyle": { + "normal": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + }, + "emphasis": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + } + } + }, + "pie": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "scatter": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "boxplot": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "parallel": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "sankey": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "funnel": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "gauge": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "candlestick": { + "itemStyle": { + "normal": { + "color": "#edafda", + "color0": "transparent", + "borderColor": "#d680bc", + "borderColor0": "#8fd3e8", + "borderWidth": "2" + } + } + }, + "graph": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + } + }, + "lineStyle": { + "normal": { + "width": 1, + "color": "#aaa" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true, + "color": [ + "#2d8cf0", + "#19be6b", + "#f5ae4a", + "#9189d5", + "#56cae2", + "#cbb0e3" + ], + "label": { + "normal": { + "textStyle": { + "color": "#eee" + } + } + } + }, + "map": { + "itemStyle": { + "normal": { + "areaColor": "#f3f3f3", + "borderColor": "#516b91", + "borderWidth": 0.5 + }, + "emphasis": { + "areaColor": "rgba(165,231,240,1)", + "borderColor": "#516b91", + "borderWidth": 1 + } + }, + "label": { + "normal": { + "textStyle": { + "color": "#000" + } + }, + "emphasis": { + "textStyle": { + "color": "rgb(81,107,145)" + } + } + } + }, + "geo": { + "itemStyle": { + "normal": { + "areaColor": "#f3f3f3", + "borderColor": "#516b91", + "borderWidth": 0.5 + }, + "emphasis": { + "areaColor": "rgba(165,231,240,1)", + "borderColor": "#516b91", + "borderWidth": 1 + } + }, + "label": { + "normal": { + "textStyle": { + "color": "#000" + } + }, + "emphasis": { + "textStyle": { + "color": "rgb(81,107,145)" + } + } + } + }, + "categoryAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#fff" + } + }, + "splitLine": { + "show": false, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "valueAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#fff" + } + }, + "splitLine": { + "show": false, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "logAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "timeAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "toolbox": { + "iconStyle": { + "normal": { + "borderColor": "#999" + }, + "emphasis": { + "borderColor": "#666" + } + } + }, + "legend": { + "textStyle": { + "color": "#fff" + } + }, + "tooltip": { + "axisPointer": { + "lineStyle": { + "color": "#ccc", + "width": 1 + }, + "crossStyle": { + "color": "#ccc", + "width": 1 + } + } + }, + "timeline": { + "lineStyle": { + "color": "#8fd3e8", + "width": 1 + }, + "itemStyle": { + "normal": { + "color": "#8fd3e8", + "borderWidth": 1 + }, + "emphasis": { + "color": "#8fd3e8" + } + }, + "controlStyle": { + "normal": { + "color": "#8fd3e8", + "borderColor": "#8fd3e8", + "borderWidth": 0.5 + }, + "emphasis": { + "color": "#8fd3e8", + "borderColor": "#8fd3e8", + "borderWidth": 0.5 + } + }, + "checkpointStyle": { + "color": "#8fd3e8", + "borderColor": "rgba(138,124,168,0.37)" + }, + "label": { + "normal": { + "textStyle": { + "color": "#8fd3e8" + } + }, + "emphasis": { + "textStyle": { + "color": "#8fd3e8" + } + } + } + }, + "visualMap": { + "color": [ + "#516b91", + "#59c4e6", + "#a5e7f0" + ] + }, + "dataZoom": { + "backgroundColor": "rgba(0,0,0,0)", + "dataBackgroundColor": "rgba(255,255,255,0.3)", + "fillerColor": "rgba(167,183,204,0.4)", + "handleColor": "#a7b7cc", + "handleSize": "100%", + "textStyle": { + "color": "#333" + } + }, + "markPoint": { + "label": { + "normal": { + "textStyle": { + "color": "#eee" + } + }, + "emphasis": { + "textStyle": { + "color": "#eee" + } + } + } + } +} diff --git a/hb_client/src/main.js b/hb_client/src/main.js index d9d4487..368bb23 100644 --- a/hb_client/src/main.js +++ b/hb_client/src/main.js @@ -16,10 +16,15 @@ import router from './router' import { plugin } from "vue-function-api"; import '@/icons' // icon import '@/permission' // permission control -import tableHeight from '@/directive/el-table/index' +import tableHeight from '@/directive/el-table/index'; +import echarts from 'echarts'; +import dataV from '@jiaminghi/data-view'; +// 引入全局css +import './assets/scss/style.scss'; Vue.component(CollapseTransition.name, CollapseTransition); Vue.use(tableHeight).use(plugin); - +Vue.prototype.$echarts = echarts; +Vue.use(dataV); /** * If you don't want to use mock-server * you want to use MockJs for mock api diff --git a/hb_client/src/router/index.js b/hb_client/src/router/index.js index eb72c9b..980eabf 100644 --- a/hb_client/src/router/index.js +++ b/hb_client/src/router/index.js @@ -36,7 +36,6 @@ export const constantRoutes = [ component: () => import('@/views/login/index'), hidden: true }, - { path: '/404', component: () => import('@/views/404'), @@ -53,6 +52,11 @@ export const constantRoutes = [ meta: { title: '首页', icon: 'dashboard', affix: true,keepAlive: false } }] }, + { + path: '/index', + component: () => import('@/views/bigScreen/index'), + meta: { title: '大屏', icon: 'dashboard', affix: true,keepAlive: false } + }, { path: '/changepassword', component: Layout, diff --git a/hb_client/src/utils/drawMixin.js b/hb_client/src/utils/drawMixin.js new file mode 100644 index 0000000..93e1236 --- /dev/null +++ b/hb_client/src/utils/drawMixin.js @@ -0,0 +1,57 @@ +// 屏幕适配 mixin 函数 + +// * 默认缩放值 +const scale = { + width: '1', + height: '1', +} + +// * 设计稿尺寸(px) +const baseWidth = 1920 +const baseHeight = 1080 + +// * 需保持的比例(默认1.77778) +const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5)) + +export default { + data() { + return { + // * 定时函数 + drawTiming: null + } + }, + mounted () { + this.calcRate() + window.addEventListener('resize', this.resize) + }, + beforeDestroy () { + window.removeEventListener('resize', this.resize) + }, + methods: { + calcRate () { + const appRef = this.$refs["appRef"] + if (!appRef) return + // 当前宽高比 + const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5)) + if (appRef) { + if (currentRate > baseProportion) { + // 表示更宽 + scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5) + scale.height = (window.innerHeight / baseHeight).toFixed(5) + appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)` + } else { + // 表示更高 + scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5) + scale.width = (window.innerWidth / baseWidth).toFixed(5) + appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)` + } + } + }, + resize () { + clearTimeout(this.drawTiming) + this.drawTiming = setTimeout(() => { + this.calcRate() + }, 200) + } + }, +} \ No newline at end of file diff --git a/hb_client/src/utils/index.js b/hb_client/src/utils/index.js index 722c202..706a269 100644 --- a/hb_client/src/utils/index.js +++ b/hb_client/src/utils/index.js @@ -382,3 +382,56 @@ const arrChange = arr => arr.map(item => { } return res }) + +/** + * @param {Function} fn 防抖函数 + * @param {Number} delay 延迟时间 + */ +/*export function debounce(fn, delay) { + let timer; + return function () { + const context = this; + const args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; +}*/ + +/** + * @param {date} time 需要转换的时间 + * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss + */ +export function formatTimeBigScreen(time, fmt) { + if (!time) return ''; + else { + const date = new Date(time); + const o = { + 'M+': date.getMonth() + 1, + 'd+': date.getDate(), + 'H+': date.getHours(), + 'm+': date.getMinutes(), + 's+': date.getSeconds(), + 'q+': Math.floor((date.getMonth() + 3) / 3), + S: date.getMilliseconds(), + }; + if (/(y+)/.test(fmt)) + fmt = fmt.replace( + RegExp.$1, + (date.getFullYear() + '').substr(4 - RegExp.$1.length) + ); + for (const k in o) { + if (new RegExp('(' + k + ')').test(fmt)) { + fmt = fmt.replace( + RegExp.$1, + RegExp.$1.length === 1 + ? o[k] + : ('00' + o[k]).substr(('' + o[k]).length) + ); + } + } + return fmt; + } +} + diff --git a/hb_client/src/utils/resizeMixin.js b/hb_client/src/utils/resizeMixin.js new file mode 100644 index 0000000..a4d25bc --- /dev/null +++ b/hb_client/src/utils/resizeMixin.js @@ -0,0 +1,32 @@ +// 混入代码 resize-mixins.js +import { debounce } from '@/utils'; +const resizeChartMethod = '$__resizeChartMethod'; + +export default { + data() { + // 在组件内部将图表 init 的引用映射到 chart 属性上 + return { + chart: null, + }; + }, + created() { + window.addEventListener('resize', this[resizeChartMethod], false); + }, + activated() { + // 防止 keep-alive 之后图表变形 + if (this.chart) { + this.chart.resize() + } + }, + beforeDestroy() { + window.removeEventListener('reisze', this[resizeChartMethod]); + }, + methods: { + // 防抖函数来控制 resize 的频率 + [resizeChartMethod]: debounce(function() { + if (this.chart) { + this.chart.resize(); + } + }, 300), + }, +}; diff --git a/hb_client/src/views/bigScreen/bottomLeft.vue b/hb_client/src/views/bigScreen/bottomLeft.vue new file mode 100644 index 0000000..45131d4 --- /dev/null +++ b/hb_client/src/views/bigScreen/bottomLeft.vue @@ -0,0 +1,308 @@ + + + + + + + + + 数据统计图 + + + + + + + + + + + + diff --git a/hb_client/src/views/bigScreen/bottomRight.vue b/hb_client/src/views/bigScreen/bottomRight.vue new file mode 100644 index 0000000..e163bb4 --- /dev/null +++ b/hb_client/src/views/bigScreen/bottomRight.vue @@ -0,0 +1,466 @@ + + + + + + + + + 工单修复以及满意度统计图 + + + + + + + + + + + + + + + diff --git a/hb_client/src/views/bigScreen/center.vue b/hb_client/src/views/bigScreen/center.vue new file mode 100644 index 0000000..a8f52ce --- /dev/null +++ b/hb_client/src/views/bigScreen/center.vue @@ -0,0 +1,271 @@ + + + + + {{ item.title }} + + + + + + + + + + + 年度负责人组件达标榜 + + + + + 今日任务通过率 + + + + 今日任务达标率 + + + + + + + + + + + + + diff --git a/hb_client/src/views/bigScreen/centerLeft1.vue b/hb_client/src/views/bigScreen/centerLeft1.vue new file mode 100644 index 0000000..6f35776 --- /dev/null +++ b/hb_client/src/views/bigScreen/centerLeft1.vue @@ -0,0 +1,242 @@ + + + + + + + + + 任务通过率 + + + + + + + + + + + + + + + {{ item.text }} + (件) + + + + + + + + + + diff --git a/hb_client/src/views/bigScreen/centerRight1.vue b/hb_client/src/views/bigScreen/centerRight1.vue new file mode 100644 index 0000000..466fd3d --- /dev/null +++ b/hb_client/src/views/bigScreen/centerRight1.vue @@ -0,0 +1,75 @@ + + + + + + + + + 人员到岗情况 + + + + + + + + + + + diff --git a/hb_client/src/views/bigScreen/centerRight2.vue b/hb_client/src/views/bigScreen/centerRight2.vue new file mode 100644 index 0000000..5827186 --- /dev/null +++ b/hb_client/src/views/bigScreen/centerRight2.vue @@ -0,0 +1,88 @@ + + + + + + + + 产品销售渠道分析 + + + + + + + + + + + diff --git a/hb_client/src/views/bigScreen/index.vue b/hb_client/src/views/bigScreen/index.vue new file mode 100644 index 0000000..128b0ce --- /dev/null +++ b/hb_client/src/views/bigScreen/index.vue @@ -0,0 +1,148 @@ + + + + Loading... + + + + + + + 航玻车间可视化平台 + + + + + + + + + + + + 数据分析1 + + + 数据分析2 + + + + + 车间详情展示 + + + + {{ dateYear }} {{ dateWeek }} {{ dateDay }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hb_server/apps/hrm/serializers.py b/hb_server/apps/hrm/serializers.py index 9371ff4..dc1eb06 100644 --- a/hb_server/apps/hrm/serializers.py +++ b/hb_server/apps/hrm/serializers.py @@ -10,6 +10,8 @@ from django.db.models.query import Prefetch class EmployeeSerializer(DynamicFieldsSerializerMixin, ModelSerializer): name = serializers.CharField(source='user.name', read_only=True) dept_ = OrganizationSimpleSerializer(source='user.dept', read_only=True) + is_atwork = serializers.BooleanField(source='user.is_atwork', read_only=True) + last_check_time = serializers.DateTimeField(source='user.last_check_time', read_only=True) class Meta: model = Employee exclude = ['face_data'] diff --git a/hb_server/apps/inm/migrations/0029_fifo_pu_order.py b/hb_server/apps/inm/migrations/0029_fifo_pu_order.py new file mode 100644 index 0000000..ff2736d --- /dev/null +++ b/hb_server/apps/inm/migrations/0029_fifo_pu_order.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.9 on 2022-01-27 07:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pum', '0004_puorder_puorderitem'), + ('inm', '0028_alter_fifoitem_files'), + ] + + operations = [ + migrations.AddField( + model_name='fifo', + name='pu_order', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.puorder', verbose_name='关联采购订单'), + ), + ] diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py index ee9d786..4042844 100644 --- a/hb_server/apps/inm/models.py +++ b/hb_server/apps/inm/models.py @@ -2,6 +2,7 @@ from django.db import models from django.db.models.base import Model import django.utils.timezone as timezone from django.db.models.query import QuerySet +from apps.pum.models import PuOrder from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords @@ -78,6 +79,8 @@ class FIFO(CommonADModel): User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True) inout_date = models.DateField('出入库日期', null=True, blank=True) remark = models.CharField('备注', max_length=1000, default='') + pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单', + null=True, blank=True, on_delete=models.CASCADE) class FIFOItem(BaseModel): diff --git a/hb_server/apps/pum/migrations/0004_puorder_puorderitem.py b/hb_server/apps/pum/migrations/0004_puorder_puorderitem.py new file mode 100644 index 0000000..03bb346 --- /dev/null +++ b/hb_server/apps/pum/migrations/0004_puorder_puorderitem.py @@ -0,0 +1,53 @@ +# Generated by Django 3.2.9 on 2022-01-27 07:47 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('mtm', '0044_subproduction_need_combtest'), + ('pum', '0003_remove_vendor_material'), + ] + + operations = [ + migrations.CreateModel( + name='PuOrder', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('number', models.CharField(max_length=100, unique=True, verbose_name='订单编号')), + ('is_audited', models.BooleanField(default=False, verbose_name='是否审核')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puorder_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='puorder_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ('vendor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pum.vendor', verbose_name='供应商')), + ], + options={ + 'verbose_name': '采购订单', + 'verbose_name_plural': '采购订单', + }, + ), + migrations.CreateModel( + name='PuOrderItem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('count', models.PositiveIntegerField(default=0, verbose_name='所需数量')), + ('delivered_count', models.PositiveIntegerField(default=0, verbose_name='已到货数量')), + ('delivery_date', models.DateField(verbose_name='截止到货日期')), + ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='采购材料')), + ('pu_order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_pu_order', to='pum.puorder', verbose_name='关联采购订单')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/hb_server/apps/pum/models.py b/hb_server/apps/pum/models.py index bf5d5a7..d66086a 100644 --- a/hb_server/apps/pum/models.py +++ b/hb_server/apps/pum/models.py @@ -5,7 +5,7 @@ from django.db.models.query import QuerySet from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords - +from apps.mtm.models import Material class Vendor(CommonAModel): @@ -23,4 +23,26 @@ class Vendor(CommonAModel): verbose_name_plural = verbose_name def __str__(self): - return self.name \ No newline at end of file + return self.name + +class PuOrder(CommonAModel): + """ + 采购订单信息 + """ + number = models.CharField('订单编号', max_length=100, unique=True) + vendor = models.ForeignKey(Vendor, verbose_name='供应商', on_delete=models.CASCADE) + is_audited = models.BooleanField('是否审核', default=False) + class Meta: + verbose_name = '采购订单' + verbose_name_plural = verbose_name + +class PuOrderItem(BaseModel): + """ + 采购具体项目 + """ + material = models.ForeignKey(Material, verbose_name='采购材料', on_delete=models.CASCADE) + count = models.PositiveIntegerField('所需数量', default=0) + delivered_count = models.PositiveIntegerField('已到货数量', default=0) + delivery_date = models.DateField('截止到货日期') + pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单', + on_delete=models.CASCADE, null=True, blank=True, related_name='item_pu_order') \ No newline at end of file diff --git a/hb_server/apps/pum/serializers.py b/hb_server/apps/pum/serializers.py index 037f7ef..4fe4ae7 100644 --- a/hb_server/apps/pum/serializers.py +++ b/hb_server/apps/pum/serializers.py @@ -1,9 +1,31 @@ from rest_framework.serializers import ModelSerializer - -from .models import Vendor +from apps.mtm.serializers import MaterialSimpleSerializer +from .models import PuOrder, PuOrderItem, Vendor class VendorSerializer(ModelSerializer): class Meta: model = Vendor fields = '__all__' + +class VendorSimpleSerializer(ModelSerializer): + class Meta: + model = Vendor + fields = ['id', 'name'] + +class PuOrderItemSerializer(ModelSerializer): + material_ = MaterialSimpleSerializer(source='material', read_only=True) + class Meta: + model = PuOrderItem + fields = '__all__' + +class PuOrderSerializer(ModelSerializer): + vendor_ = VendorSimpleSerializer(source='vendor', read_only=True) + items = PuOrderItemSerializer(source='item_pu_order', many=True, read_only=True) + class Meta: + model = PuOrder + fields = '__all__' + +class PuOrderCreateUpdateSerializer(ModelSerializer): + class Meta: + fields = ['number', 'vendor'] \ No newline at end of file diff --git a/hb_server/apps/pum/views.py b/hb_server/apps/pum/views.py index 1258ca9..ec11c43 100644 --- a/hb_server/apps/pum/views.py +++ b/hb_server/apps/pum/views.py @@ -1,8 +1,10 @@ + from django.shortcuts import render from rest_framework.viewsets import ModelViewSet - -from apps.pum.models import Vendor -from apps.pum.serializers import VendorSerializer +from rest_framework.mixins import CreateModelMixin, DestroyModelMixin +from rest_framework.viewsets import GenericViewSet +from apps.pum.models import PuOrder, Vendor +from apps.pum.serializers import PuOrderCreateUpdateSerializer, PuOrderSerializer, VendorSerializer from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin @@ -19,3 +21,27 @@ class VendorViewSet(CreateUpdateModelAMixin, ModelViewSet): filterset_fields = [] ordering_fields = ['create_time'] ordering = ['-create_time'] + + +class PuOrderViewSet(CreateUpdateModelAMixin, ModelViewSet): + """ + 采购订单-增删改查 + """ + perms_map = {'get': '*', 'post': '*', + 'put': '*', 'delete': '*'} + queryset = PuOrder.objects.select_related('vendor').\ + prefetch_related('item_pu_order').all() + serializer_class = PuOrderSerializer + search_fields = ['number', 'vendor__name'] + filterset_fields = ['vendor'] + ordering = ['-create_time'] + + def get_serializer_class(self): + if self.action in ['create', 'update']: + return PuOrderCreateUpdateSerializer + return super().get_serializer_class() + + + +class PuOrderItemViewSet(CreateModelMixin, DestroyModelMixin, GenericViewSet): + pass \ No newline at end of file diff --git a/hb_server/apps/sam/migrations/0012_alter_order_delivery_date.py b/hb_server/apps/sam/migrations/0012_alter_order_delivery_date.py new file mode 100644 index 0000000..00af49b --- /dev/null +++ b/hb_server/apps/sam/migrations/0012_alter_order_delivery_date.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2022-01-27 07:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sam', '0011_order_need_mtest'), + ] + + operations = [ + migrations.AlterField( + model_name='order', + name='delivery_date', + field=models.DateField(verbose_name='截止交货日期'), + ), + ] diff --git a/hb_server/apps/sam/models.py b/hb_server/apps/sam/models.py index c652520..ce2ef62 100644 --- a/hb_server/apps/sam/models.py +++ b/hb_server/apps/sam/models.py @@ -58,7 +58,7 @@ class Order(CommonAModel): count = models.PositiveIntegerField('所需数量', default=0) planed_count = models.PositiveIntegerField('已排数量', default=0) delivered_count = models.PositiveIntegerField('已交货数量', default=0) - delivery_date = models.DateField('交货日期') + delivery_date = models.DateField('截止交货日期') need_mtest = models.BooleanField('是否需要军检', default=False) class Meta: verbose_name = '订单信息' diff --git a/hb_server/apps/srm/views.py b/hb_server/apps/srm/views.py index 9dd73cc..d8531c0 100644 --- a/hb_server/apps/srm/views.py +++ b/hb_server/apps/srm/views.py @@ -1,5 +1,6 @@ from django.shortcuts import render +from numpy import number from rest_framework import serializers from rest_framework.generics import ListAPIView, CreateAPIView from rest_framework.views import APIView @@ -78,10 +79,11 @@ class AtWorkCountView(CreateAPIView): serializer.is_valid(raise_exception=True) vdata = serializer.validated_data ret = ClockRecord.objects.filter( - create_time__year = vdata['year'], - create_time__month = vdata['month'] + update_time__year = vdata['year'], + update_time__month = vdata['month'] ).values( user_id = F('create_by'), + number = F('create_by__employee_user__number'), username = F('create_by__username'), name = F('create_by__name'), dept_name = F('create_by__dept__name')).annotate( diff --git a/hb_server/apps/system/serializers.py b/hb_server/apps/system/serializers.py index 209061c..d59d538 100644 --- a/hb_server/apps/system/serializers.py +++ b/hb_server/apps/system/serializers.py @@ -137,14 +137,14 @@ class UserListSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializ """ 用户列表序列化 """ - dept_name = serializers.StringRelatedField(source='dept') - roles_name = serializers.StringRelatedField(source='roles', many=True) + dept_ = OrganizationSimpleSerializer(source='dept', read_only=True) + roles_ = RoleSerializer(source='roles', many=True) class Meta: model = User fields = ['id', 'name', 'phone', 'email', 'position', 'username', 'is_active', 'date_joined', - 'dept_name', 'dept', 'roles', 'avatar', - 'roles_name', 'is_atwork', 'last_check_time'] + 'dept_', 'dept', 'roles', 'avatar', + 'roles_', 'is_atwork', 'last_check_time'] @staticmethod def setup_eager_loading(queryset): diff --git a/hb_server/apps/system/views.py b/hb_server/apps/system/views.py index 9ef7c28..3664054 100644 --- a/hb_server/apps/system/views.py +++ b/hb_server/apps/system/views.py @@ -261,7 +261,7 @@ class UserViewSet(ModelViewSet): # 根据请求类型动态变更serializer if self.action == 'create': return UserCreateSerializer - elif self.action == 'list': + elif self.action in ['list', 'retrieve']: return UserListSerializer return UserModifySerializer diff --git a/hb_server/requirements.txt b/hb_server/requirements.txt index 3d3b1be..500f758 100644 --- a/hb_server/requirements.txt +++ b/hb_server/requirements.txt @@ -11,3 +11,4 @@ psutil==5.8.0 pillow==8.3.1 opencv-python==4.5.3.56 django-celery-results==2.2.0 +numpy==1.21.2 diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index e7b3ca5..30bc9be 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -1,3 +1,4 @@ +import os from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.parsers import MultiPartParser @@ -6,10 +7,9 @@ from PIL import Image from django.conf import settings from rest_framework import status from datetime import datetime -import os -import uuid import cv2 from server.settings import BASE_DIR +import numpy as np # class UploadFileView(APIView): # permission_classes = [IsAuthenticated] @@ -39,16 +39,33 @@ class GenSignature(APIView): def post(self, request, *args, **kwargs): path = (BASE_DIR + request.data['path']).replace('\\', '/') - image = cv2.imread(path, cv2.IMREAD_UNCHANGED) - size = image.shape - for i in range(size[0]): - for j in range(size[1]): - if image[i][j][0]>100 and image[i][j][1]>100 and image[i][j][2]>100: - image[i][j][3] = 0 - else: - image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0 - cv2.imwrite(path,image) - return Response(request.data, status=status.HTTP_200_OK) + try: + image = cv2.imread(path, cv2.IMREAD_UNCHANGED) + size = image.shape + width = size[0] # 宽度 + height = size[1] # 高度 + if size[2] != 4: # 判断 + background = np.zeros((size[0], size[1], 4)) + for yh in range(height): + for xw in range(width): + background[xw, yh, :3] = image[xw, yh] + background[xw, yh, 3] = 255 + image = background + size = image.shape + for i in range(size[0]): + for j in range(size[1]): + if image[i][j][0]>100 and image[i][j][1]>100 and image[i][j][2]>100: + image[i][j][3] = 0 + else: + image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0 + ext = os.path.splitext(path) + new_path = ext[0] + '.png' + cv2.imwrite(new_path, image) + return Response({'path':new_path.replace(BASE_DIR, '')}, status=status.HTTP_200_OK) + except: + return Response('签名照处理失败,请重新上传', + status=status.HTTP_400_BAD_REQUEST) + import time class UpdateDevelop(APIView):
{{ item.title }}
+ {{ item.text }} + (件) +