Add all dashboard projects
56
机加设备生产运营看板二/src/App.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<t-loading :loading="isLoading" size="large" text="加载中(大)...">
|
||||
<router-view/>
|
||||
</t-loading>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import {useAppStore} from "@/store/app.js";
|
||||
import {storeToRefs} from "pinia";
|
||||
|
||||
const store = useAppStore();
|
||||
// storeToRefs 响应式解构赋值 pinia
|
||||
const {isLoading} = storeToRefs(store);
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
// 定义的全局变量
|
||||
body {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/*修改提示框样式 更醒目*/
|
||||
.el-message-box {
|
||||
|
||||
// 标题
|
||||
.el-message-box__title {
|
||||
font-size: 35px;
|
||||
font-weight: 700;
|
||||
color: rgb(255, 143, 0);
|
||||
}
|
||||
|
||||
// 提示文本
|
||||
.el-message-box__message p {
|
||||
font-size: 24px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
// icon图标
|
||||
.el-message-box__status {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.el-message-box__btns {
|
||||
justify-content: space-evenly;
|
||||
|
||||
.el-button {
|
||||
width: 48%;
|
||||
height: 6vh;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
BIN
机加设备生产运营看板二/src/assets/404_images/404.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
机加设备生产运营看板二/src/assets/404_images/404_cloud.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
机加设备生产运营看板二/src/assets/dashboard/category-panel-frame.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
机加设备生产运营看板二/src/assets/dashboard/title-frame.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
机加设备生产运营看板二/src/assets/font/DS-DIGI.TTF
Normal file
BIN
机加设备生产运营看板二/src/assets/font/DS-DIGIB.TTF
Normal file
BIN
机加设备生产运营看板二/src/assets/font/DS-DIGII.TTF
Normal file
BIN
机加设备生产运营看板二/src/assets/font/DS-DIGIT.TTF
Normal file
4
机加设备生产运营看板二/src/assets/font/font.css
Normal file
@@ -0,0 +1,4 @@
|
||||
@font-face{
|
||||
font-family:electronicFont;
|
||||
src:url(./DS-DIGIT.TTF)
|
||||
}
|
||||
BIN
机加设备生产运营看板二/src/assets/font/font.zip
Normal file
BIN
机加设备生产运营看板二/src/assets/image/MachineTool.png
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
机加设备生产运营看板二/src/assets/image/Robot.png
Normal file
|
After Width: | Height: | Size: 320 KiB |
BIN
机加设备生产运营看板二/src/assets/image/image4.png
Normal file
|
After Width: | Height: | Size: 329 B |
50
机加设备生产运营看板二/src/components/HelloWorld.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<button type="button" @click="count++">count is {{ count }}</button>
|
||||
<p>
|
||||
Edit
|
||||
<code>components/HelloWorld.vue</code> to test HMR
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Check out
|
||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
||||
>create-vue</a
|
||||
>, the official Vue + Vite starter
|
||||
</p>
|
||||
<p>
|
||||
Learn more about IDE Support for Vue in the
|
||||
<a
|
||||
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
|
||||
target="_blank"
|
||||
>Vue Docs Scaling up Guide</a
|
||||
>.
|
||||
</p>
|
||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
||||
<el-button type="primary">21321312</el-button>
|
||||
<t-button disabled loading>确定</t-button>
|
||||
<t-button variant="dashed" ghost>幽灵按钮</t-button>
|
||||
<icon name="cps-icon-home-sheep" url="https://tdesign.gtimg.com/icon/default-demo/index.js" size="2em" />
|
||||
|
||||
123
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Icon } from 'tdesign-icons-vue-next';
|
||||
|
||||
defineProps({
|
||||
msg: String,
|
||||
})
|
||||
|
||||
const count = ref(0)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
||||
50
机加设备生产运营看板二/src/main.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import {createApp} from 'vue'
|
||||
import App from './App.vue'
|
||||
//ElementPlus
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
// TDesign
|
||||
import TDesign from 'tdesign-vue-next'
|
||||
// 引入组件库的少量全局样式变量
|
||||
import 'tdesign-vue-next/es/style/index.css'
|
||||
// DataV 大屏组件
|
||||
import DataVVue3 from '@kjgl77/datav-vue3'
|
||||
import '@kjgl77/datav-vue3/dist/style.css'
|
||||
// pinia
|
||||
import {createPinia} from 'pinia'
|
||||
//router
|
||||
import router from './router/index.js'
|
||||
//crud
|
||||
import curdVue3 from './utils/curdVue3'
|
||||
// el-icon
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
|
||||
const app = createApp(App)
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
// 提供全局方法
|
||||
|
||||
|
||||
app.use(ElementPlus, {
|
||||
locale: zhCn,
|
||||
})
|
||||
|
||||
app.use(TDesign)
|
||||
app.use(DataVVue3)
|
||||
const pinia = createPinia() // 创建 Pinia 实例
|
||||
app.use(pinia)
|
||||
app.use(curdVue3)
|
||||
app.use(router)
|
||||
|
||||
app.provide('CreateData', app.config.globalProperties.CreateData)
|
||||
app.provide('ExecDatabase', app.config.globalProperties.ExecDatabase)
|
||||
app.provide('ExecDatabaseByParam', app.config.globalProperties.ExecDatabaseByParam)
|
||||
// app.provide('ExecWritePLC', app.config.globalProperties.ExecWritePLC)
|
||||
// app.provide('ExecReadPLC', app.config.globalProperties.ExecReadPLC)
|
||||
// app.provide('ExecIMESAPI', app.config.globalProperties.ExecIMESAPI)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
// useRouteGuard(); // 使用路由守卫
|
||||
27
机加设备生产运营看板二/src/router/index.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import {createRouter, createWebHashHistory} from "vue-router";
|
||||
|
||||
// cookies
|
||||
|
||||
// 创建routes
|
||||
const routes = [
|
||||
{
|
||||
// 重定向
|
||||
path: "/home",
|
||||
redirect: "/",
|
||||
},
|
||||
{
|
||||
//质检任务看板
|
||||
path: "/",
|
||||
name: "root",
|
||||
component: () => import("@/views/index.vue"),
|
||||
children: [],
|
||||
}
|
||||
];
|
||||
|
||||
//History路由模型
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(import.meta.env.BASE_URL),
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
||||
76
机加设备生产运营看板二/src/router/useRouteGuard.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import { inject } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {ElMessage} from "element-plus";
|
||||
import Cookies from "vue-cookies";
|
||||
|
||||
|
||||
export function useRouteGuard() {
|
||||
const router = useRouter();
|
||||
const CreateData = inject('CreateData');
|
||||
const ExecDatabase = inject('ExecDatabase');
|
||||
let userId = Cookies.get('userId')
|
||||
// 防止首次或者刷新界面路由失效
|
||||
let registerRouteFresh = true
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (registerRouteFresh) {
|
||||
if(userId !== ''){
|
||||
// 获取权限列表
|
||||
var param = []
|
||||
param[0] = ['userId', userId]
|
||||
var Data = CreateData('11', '基础表_权限模块_查询', param)
|
||||
ExecDatabase(Data).then(response => {
|
||||
if(response.data.length > 0){
|
||||
routerData.value.userRouterList = response.data
|
||||
// 创建动态路由列表
|
||||
const dynamicRoutes = dynamicRouter(response.data);
|
||||
|
||||
dynamicRoutes.forEach((route) => {
|
||||
// 检查是否已存在该路由,避免重复添加
|
||||
if (!router.hasRoute(route.name)) {
|
||||
router.addRoute('root', route);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
ElMessage.warning('该角色未分配角色模块,请先进行分配!')
|
||||
}
|
||||
next({ ...to, replace: true })
|
||||
registerRouteFresh = false
|
||||
})
|
||||
}else{
|
||||
next({ ...to, replace: true })
|
||||
registerRouteFresh = false
|
||||
}
|
||||
} else {
|
||||
if (to.meta.title) {
|
||||
window.document.title = to.meta.title;
|
||||
}
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
// 递归替换引入component
|
||||
function dynamicRouter(routerList) {
|
||||
const list = [];
|
||||
routerList.forEach((route) => {
|
||||
const routeItem = {
|
||||
path: '/' + route.path,
|
||||
name:route.path,
|
||||
meta: {
|
||||
title: route.权限模块,
|
||||
},
|
||||
component: async () => {
|
||||
try {
|
||||
const component = await import(`@/views/${route.path}/index.vue`);
|
||||
console.log(component)
|
||||
return component.default || component;
|
||||
} catch (error) {
|
||||
console.error('引入路由组件失败,请确认地址是否配置正确:', error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
};
|
||||
list.push(routeItem);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
28
机加设备生产运营看板二/src/store/app.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import {defineStore} from 'pinia'
|
||||
|
||||
|
||||
// 第一个参数是应用程序中 store 的唯一 id
|
||||
export const useAppStore = defineStore('AppData', {
|
||||
// 其它配置项
|
||||
state: () => {
|
||||
return {
|
||||
user: {
|
||||
AID: '',
|
||||
name: '',
|
||||
classes: '',
|
||||
teamGroup: '',
|
||||
role: '',
|
||||
userName: '',
|
||||
password: '',
|
||||
opName: '',
|
||||
},
|
||||
isLoading: false,
|
||||
routerData: {
|
||||
userRouterList: [],
|
||||
nowRouterPath: '',
|
||||
nowRouterTitle: '',
|
||||
selected: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
})
|
||||
15
机加设备生产运营看板二/src/utils/auth.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const TokenKey = 'Admin-Token'
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
return Cookies.set(TokenKey, token)
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
||||
435
机加设备生产运营看板二/src/utils/curd.js
Normal file
@@ -0,0 +1,435 @@
|
||||
import { ExcelDownLoad } from '@/utils/request'
|
||||
import request from '@/utils/request'
|
||||
import Cookie from 'js-cookie'
|
||||
import { type } from './tool' // type判断传入值的类型,比typeof更详细
|
||||
export default {
|
||||
exportExcel_NPOI(param) {
|
||||
console.log(param, 1)
|
||||
download(`${ExcelDownLoad}?param=${param}`)
|
||||
},
|
||||
// 用于生成传通讯服务器参数。
|
||||
// 传入参数
|
||||
// 1)type:11查询;12增删改,必须
|
||||
// 2)name:存储过程名,必须
|
||||
// 3)data:存储过程参数名和对应值,例如:
|
||||
// param[0] = ['工艺计划流水号', this.工艺计划流水号] 输入参数
|
||||
// param[1] = ['PageCurrent', '1111', 'int', '1'] output参数
|
||||
// 数组里四个分别对应:存储过程参数名(必须);存储过程参数值(必须);参数类型(若是output必须);参数是否为output(0否1是)
|
||||
// 4)pageSize,pageList:分页使用,可选
|
||||
CreateData(type, name, data, pageSize, pageList) {
|
||||
var param_Str = ''
|
||||
var param_array = []
|
||||
if (type === '7') {
|
||||
data.map(v => {
|
||||
pageSize.map(h => {
|
||||
const val = h.toString()
|
||||
if (!v[val]) {
|
||||
this.$set(v, val, '')
|
||||
}
|
||||
})
|
||||
})
|
||||
param_Str = data
|
||||
} else {
|
||||
if (data !== undefined) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
param_array.push({
|
||||
name: data[i][0],
|
||||
value: data[i][1],
|
||||
type: data[i][2],
|
||||
output: data[i][3]
|
||||
})
|
||||
}
|
||||
param_Str = JSON.stringify(param_array)
|
||||
}
|
||||
}
|
||||
var obj = []
|
||||
obj[0] = {}
|
||||
obj[0].type = type
|
||||
obj[0].name = name
|
||||
obj[0].param = param_Str
|
||||
obj[0].pageSize = pageSize
|
||||
obj[0].pageList = pageList
|
||||
obj[0].UserID = Cookie.get('username')
|
||||
obj[0].ModularID = ''//this.$router.currentRoute.path
|
||||
console.log(obj[0], 'obj[0]')
|
||||
var numn = JSON.stringify(obj[0])
|
||||
return numn
|
||||
},
|
||||
// 新通讯11/12---<
|
||||
ExecDatabase(data) {
|
||||
return request({
|
||||
url: '',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
},
|
||||
// 高精原CreateData
|
||||
// Vue.prototype.CreateData = function(type, name, data, pageSize, pageList) {
|
||||
// var paramStr = ''
|
||||
// var paramarray = []
|
||||
// if (data !== undefined) {
|
||||
// for (let i = 0; i < data.length; i++) {
|
||||
// paramarray.push({
|
||||
// name: data[i][0],
|
||||
// value: data[i][1],
|
||||
// type: data[i][2],
|
||||
// output: data[i][3]
|
||||
// })
|
||||
// }
|
||||
// paramStr = JSON.stringify(paramarray)
|
||||
// }
|
||||
// var obj = []
|
||||
// obj[0] = {}
|
||||
// obj[0].type = type
|
||||
// obj[0].name = name
|
||||
// obj[0].param = paramStr
|
||||
// obj[0].pageSize = pageSize
|
||||
// obj[0].pageList = pageList
|
||||
// var numn = JSON.stringify(obj[0])
|
||||
// return numn
|
||||
// }
|
||||
|
||||
// 用于打开增加框,方法能重置表单,并使表单内容回到初始化状态。
|
||||
// 传入参数
|
||||
// 1)表单名称,字符串形式如'form',必须
|
||||
// 2) 打开表单后需要做什么,可以传数组[this.dialogvisiale = false, fetchData],也可以传回调函数function() { this.dialogvisiale = false } 可选
|
||||
addForm(form, callback) {
|
||||
if (type(form) === 'string') {
|
||||
if (this.$refs[form]) { // 判断是否需要重置表单,如果需要重置表单
|
||||
this.$refs[form].resetFields()
|
||||
}
|
||||
if (type(callback) === 'array') { // 判断传入是否为数组,如果是遍历数组,遇到函数将函数体变成函数执行,其余正常执行
|
||||
if (callback && callback.length !== 0) {
|
||||
for (let i = 0, len = callback.length; i < len; i++) {
|
||||
typeof callback[i] === 'function' ? callback[i]() : callback[i]
|
||||
}
|
||||
}
|
||||
} else if (type(callback) === 'function') { // 判断传入是否为回调函数
|
||||
callback.call(this) // 回调函数执行,需将this改为该组件
|
||||
}
|
||||
this[form] = Object.assign(this.$data[form], this.$options.data()[form]) // 将表单中的数据变为初始状态。其中,this.$options.data是所有初始化的数据,this.$data是目前的数据
|
||||
} else {
|
||||
console.error('传入参数错误')
|
||||
}
|
||||
},
|
||||
// 用于打开编辑框,方法能自动传入行的数据到对应的表单中,并将表单中所有纯数字转成int。前提是行的名称需跟表单名称一样。
|
||||
// 传入参数
|
||||
// 1) 编辑这一行的row
|
||||
// 2)表单名称,字符串形式如'form'
|
||||
// 3) 打开编辑需要做什么,同样是[] 和 function
|
||||
editForm(row, form, callback) {
|
||||
if (type(row) === 'object' && type(form) === 'string') {
|
||||
if (this.$refs[form]) { // 判断是否需要重置表单
|
||||
this.$refs[form].resetFields()
|
||||
}
|
||||
const isNum = /^[0-9]+$/ // 正则表达式,是否全都为纯数字
|
||||
for (const prop in this[form]) { // 遍历表单,当表单和row中属性名一样时,表单row中的属性赋值给form
|
||||
isNum.lastIndex = 0 // 正则每一次匹配后的索引归0,否则循环会造成问题
|
||||
isNum.exec(row[prop]) ? this[form][prop] = parseInt(row[prop]) : this[form][prop] = row[prop] // 通过正则匹配数字,当匹配成功后,将字符串转为int。当然你也不用担心空转成NaN,因为''匹配通不过!
|
||||
}
|
||||
if (type(callback) === 'array') { // 这部分处理与打开表单相同
|
||||
if (callback && callback.length !== 0) {
|
||||
for (let i = 0, len = callback.length; i < len; i++) {
|
||||
typeof callback[i] === 'function' ? callback[i]() : callback[i]
|
||||
}
|
||||
}
|
||||
} else if (type(callback) === 'function') {
|
||||
callback.call(this)
|
||||
}
|
||||
} else {
|
||||
console.error('传入参数错误')
|
||||
}
|
||||
},
|
||||
// 用于获取下拉框中的数据
|
||||
// 传入参数
|
||||
// 1)请求数据函数引用如getXXX,必须
|
||||
// 2)数组的实行名称['XXXX名称', 'XXXX代码'],必须
|
||||
// 3)需要用哪个数组接收这个结果,字符串形式。如在组件也需要用this.select,传入值就为'select',必须
|
||||
// 4) 请求函数传入的参数,可选
|
||||
getSelect(requestData, select, carrier, param) {
|
||||
if (type(requestData) === 'function' && type(select) === 'array' && type(carrier) === 'string') {
|
||||
if (type(param) === 'array') {
|
||||
requestData(...param).then(response => { // 这个方法没什么难度,不注释了
|
||||
this[carrier] = []
|
||||
for (let i = 0, len = response.data.length; i < len; i++) {
|
||||
if (select.length === 2) {
|
||||
this[carrier].push({
|
||||
label: response.data[i][select[0]],
|
||||
value: response.data[i][select[1]]
|
||||
})
|
||||
} else {
|
||||
this[carrier].push({
|
||||
value: response.data[i][select[0]]
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
requestData(param).then(response => { // 这个方法没什么难度,不注释了
|
||||
this[carrier] = []
|
||||
for (let i = 0, len = response.data.length; i < len; i++) {
|
||||
if (select.length === 2) {
|
||||
this[carrier].push({
|
||||
label: response.data[i][select[0]],
|
||||
value: response.data[i][select[1]]
|
||||
})
|
||||
} else {
|
||||
this[carrier].push({
|
||||
value: response.data[i][select[0]]
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.error('参数传递错误')
|
||||
}
|
||||
},
|
||||
// 普通获取数据
|
||||
// 传入参数
|
||||
// 1) 请求数据函数引用如getXXX,必须
|
||||
// 2) 需要用哪个数组接收这个结果,字符串形式。如在组件也需要用this.select,传入值就为'select',必须
|
||||
// 3) 请求函数传入的参数,可选
|
||||
getData(requestData, carrier, param) {
|
||||
if (type(requestData) === 'function' && type(carrier) === 'string') {
|
||||
if (type(param) === 'undefined') {
|
||||
requestData(param).then(response => {
|
||||
const data = response.data
|
||||
this[carrier] = data
|
||||
})
|
||||
} else {
|
||||
let Param = []
|
||||
if (type(param) !== 'array') {
|
||||
Param.push(param)
|
||||
} else {
|
||||
Param = param
|
||||
}
|
||||
requestData(...Param).then(response => {
|
||||
const data = response.data
|
||||
this[carrier] = data
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.error('传入参数错误')
|
||||
}
|
||||
},
|
||||
// 获取表格数据,将表格中的年月日时分秒,转换成年月日
|
||||
// 传入参数
|
||||
// 1)请求数据函数引用如getXXX,必须
|
||||
// 2)请求的参数,可选
|
||||
// 3)接受值,数组,一般是['table','total','loading']顺序不能变
|
||||
getTable(requestData, param, e) {
|
||||
requestData(...param).then(response => {
|
||||
const data = response.data.rows
|
||||
this[e[0]] = []
|
||||
this[e[1]] = 0
|
||||
if (data && data.length > 0) {
|
||||
const isTime = /^\d{4}([-\/.])\d{1,2}\1\d{1,2}/ // 判断是否是时间的正则表达式
|
||||
for (let i = 0, len = data.length; i < len; i++) { // 循环得到每一条数据
|
||||
for (const prop in data[i]) { // 循环每一条的每一项
|
||||
isTime.lastIndex = 0 // 正则每一次指针复位
|
||||
if (isTime.test(data[i][prop])) { // 判断是否是时间,如果是切割
|
||||
data[i][prop] = data[i][prop].split(' ')[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
this[e[0]] = data
|
||||
this[e[1]] = parseInt(response.data.total)
|
||||
} else {
|
||||
this[e[0]] = []
|
||||
// console.log('暂无数据')
|
||||
}
|
||||
}).then(() => {
|
||||
this[e[2]] = false
|
||||
})
|
||||
},
|
||||
// 添加表格数据
|
||||
// 传入参数
|
||||
// 1) 请求数据函数引用如getXXX,必须
|
||||
// 2) 请求的参数,可选
|
||||
// 3) 验证的表单名称,必须
|
||||
// 4) 回调函数,必须
|
||||
addTable(requestData, param, form, callback) {
|
||||
if (type(callback) === 'function' && type(requestData) === 'function' && type(form) === 'string') {
|
||||
console.log(this.$refs[form])
|
||||
this.$refs[form].validate((valid) => {
|
||||
console.log(valid)
|
||||
if (valid) {
|
||||
requestData(...param).then(response => {
|
||||
if (response.data[0].result === '1') {
|
||||
this.$message.success('增加成功')
|
||||
callback.call(this)
|
||||
} else { this.$message.error('增加失败') }
|
||||
})
|
||||
} else {
|
||||
console.error('error submit!!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.error('参数传递错误')
|
||||
}
|
||||
},
|
||||
// 编辑表格数据
|
||||
// 传入参数
|
||||
// 1) 请求数据函数引用如getXXX,必须
|
||||
// 2) 请求的参数,可选
|
||||
// 3) 验证的表单名称,必须
|
||||
// 4) 回调函数,必须
|
||||
editTable(requestData, param, form, callback) {
|
||||
if (type(callback) === 'function' && type(requestData) === 'function' && type(form) === 'string') {
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (valid) {
|
||||
requestData(...param).then(response => {
|
||||
if (response.data[0].result === '1') {
|
||||
this.$message.success('修改成功')
|
||||
callback.call(this) // 回调函数修正this指向组件本身
|
||||
} else { this.$message.error('修改失败') }
|
||||
})
|
||||
} else {
|
||||
console.error('error submit!!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.error('参数传递错误')
|
||||
}
|
||||
},
|
||||
// 删除表格数据
|
||||
// 传入参数
|
||||
// 1) 请求数据函数引用如getXXX,必须
|
||||
// 2) id传入删除条件,必须
|
||||
// 3) 回调函数,必须
|
||||
deleteRow(requestData, id, callback) {
|
||||
if (type(callback) === 'function' && type(requestData) === 'function') {
|
||||
if (this.tableData && this.tableData.length === 1 && this.pageCurrent > 1) { // 判断删除的是否是最后一页最后一行,如果是且不是第一页,页数减一
|
||||
this.pageCurrent--
|
||||
}
|
||||
this.$confirm('此操作将永久删除该行, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
requestData(id).then(response => {
|
||||
if (response.data[0].result === '1') {
|
||||
this.$message.success('删除成功')
|
||||
callback.call(this) // 回调函数修正this指向组件本身
|
||||
} else { this.$message.error('数据占用') }
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除'
|
||||
})
|
||||
})
|
||||
} else {
|
||||
console.error('参数传递错误')
|
||||
}
|
||||
},
|
||||
// 设置字段宽度
|
||||
setColumnWidth(str) {
|
||||
let columnWidth = 0
|
||||
if (str === '日期') {
|
||||
columnWidth = 90
|
||||
} else if (str === '订单编号' || str === '领料单号' || str === '调拨单号' || str === '订单号' || str === '机床名称') {
|
||||
columnWidth = 140
|
||||
} else if (str === '合同编号' || str === '补货单号') {
|
||||
columnWidth = 140
|
||||
} else if (str === '产品名称' || str === '部件名称') {
|
||||
columnWidth = 110
|
||||
} else if (str === '序号') {
|
||||
columnWidth = 60
|
||||
} else if (str === '单位') {
|
||||
columnWidth = 60
|
||||
} else if (str === '数量' || str === '库存') {
|
||||
columnWidth = 80
|
||||
} else if (str === '单价') {
|
||||
columnWidth = 90
|
||||
} else if (str === '金额') {
|
||||
columnWidth = 120
|
||||
} else if (str === '状态' || str === '类型' || str === '选入' || str === '选出') {
|
||||
columnWidth = 80
|
||||
} else if (str === '付款方式') {
|
||||
columnWidth = 100
|
||||
} else if (str === '买方' || str === '买方名称') {
|
||||
columnWidth = 150
|
||||
} else if (str === '外协厂家' || str === '调入仓库' || str === '调出仓库') {
|
||||
columnWidth = 150
|
||||
} else if (str === '姓名') {
|
||||
columnWidth = 80
|
||||
} else if (str === '日期时间') {
|
||||
columnWidth = 140
|
||||
} else if (str === '工序') {
|
||||
columnWidth = 80
|
||||
} else if (str === '物料名称' || str === '工件名称' || str === '零件名称') {
|
||||
columnWidth = 140
|
||||
} else if (str === '图号或型号' || str === '规格' || str === '零件图号' || str === '图号' || str === '图号/型号') {
|
||||
columnWidth = 120
|
||||
} else if (str === '物料编码' || str === '物料编号') {
|
||||
columnWidth = 120
|
||||
} else if (str === '材料') {
|
||||
columnWidth = 80
|
||||
} else if (str === '仓位' || str === '库位') {
|
||||
columnWidth = 90
|
||||
} else if (str === '品名/规格/型号') {
|
||||
columnWidth = 140
|
||||
} else if (str === '备注') {
|
||||
columnWidth = 120
|
||||
} else if (str === '工序名称') {
|
||||
columnWidth = 150
|
||||
} else if (str === '工序说明') {
|
||||
columnWidth = 300
|
||||
} else if (str === '加工工时M' || str === '加工时长H' || str === '加工时长M') {
|
||||
columnWidth = 90
|
||||
} else if (str === '加工设备') {
|
||||
columnWidth = 130
|
||||
} else if (str === '产品详情' || str === '详情') {
|
||||
columnWidth = 340
|
||||
} else if (str === '最低库存') {
|
||||
columnWidth = 110
|
||||
} else if (str === '本次到货数' || str === '本次入库' || str === '补货数') {
|
||||
columnWidth = 100
|
||||
} else {
|
||||
columnWidth = 110
|
||||
}
|
||||
return columnWidth
|
||||
}
|
||||
}
|
||||
function download(url) {
|
||||
getBlob(url, function(blob, filename) {
|
||||
console.log(blob, filename, 2)
|
||||
saveAs(blob, filename)
|
||||
})
|
||||
}
|
||||
|
||||
function getBlob(url, cb) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', url, true)
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = function() {
|
||||
if (xhr.status === 200) {
|
||||
const name = xhr.getResponseHeader('content-disposition').split('=')[1]
|
||||
var filename = decodeURIComponent(name)
|
||||
cb(xhr.response, filename)
|
||||
}
|
||||
}
|
||||
xhr.send()
|
||||
}
|
||||
|
||||
function saveAs(blob, filename) {
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
navigator.msSaveBlob(blob, filename)
|
||||
} else {
|
||||
var link = document.createElement('a')
|
||||
var body = document.querySelector('body')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = filename
|
||||
// fix Firefox
|
||||
link.style.display = 'none'
|
||||
body.appendChild(link)
|
||||
link.click()
|
||||
body.removeChild(link)
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
}
|
||||
|
||||
135
机加设备生产运营看板二/src/utils/curdVue3.js
Normal file
@@ -0,0 +1,135 @@
|
||||
import request from '@/utils/request'
|
||||
import Cookie from 'js-cookie'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
app.config.globalProperties.CreateData = function (type, name, data, pageSize, pageList) {
|
||||
var param_Str = ''
|
||||
var param_array = []
|
||||
if (type === '7') {
|
||||
data.map(v => {
|
||||
pageSize.map(h => {
|
||||
const val = h.toString()
|
||||
if (!v[val]) {
|
||||
this.$set(v, val, '')
|
||||
}
|
||||
})
|
||||
})
|
||||
param_Str = data
|
||||
} else {
|
||||
if (data !== undefined) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
param_array.push({
|
||||
name: data[i][0],
|
||||
value: data[i][1],
|
||||
type: data[i][2],
|
||||
output: data[i][3]
|
||||
})
|
||||
}
|
||||
param_Str = JSON.stringify(param_array)
|
||||
}
|
||||
}
|
||||
var obj = []
|
||||
obj[0] = {}
|
||||
obj[0].type = type
|
||||
obj[0].name = name
|
||||
obj[0].param = param_Str
|
||||
obj[0].pageSize = pageSize
|
||||
obj[0].pageList = pageList
|
||||
obj[0].UserID = Cookie.get('username')
|
||||
obj[0].ModularID = ''//this.$router.currentRoute.path
|
||||
console.log(obj[0], 'obj[0]')
|
||||
var numn = JSON.stringify(obj[0])
|
||||
return numn
|
||||
}
|
||||
app.config.globalProperties.ExecDatabase = function (data) {
|
||||
return request({
|
||||
url: '',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
app.config.globalProperties.ExecDatabaseByParam = function (type, name, data, pageSize, pageList) {
|
||||
var param_Str = ''
|
||||
var param_array = []
|
||||
if (type === '7') {
|
||||
data.map(v => {
|
||||
pageSize.map(h => {
|
||||
const val = h.toString()
|
||||
if (!v[val]) {
|
||||
this.$set(v, val, '')
|
||||
}
|
||||
})
|
||||
})
|
||||
param_Str = data
|
||||
} else {
|
||||
if (data !== undefined) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
param_array.push({
|
||||
name: data[i][0],
|
||||
value: data[i][1],
|
||||
type: data[i][2],
|
||||
output: data[i][3]
|
||||
})
|
||||
}
|
||||
param_Str = JSON.stringify(param_array)
|
||||
}
|
||||
}
|
||||
var obj = []
|
||||
obj[0] = {}
|
||||
obj[0].type = type
|
||||
obj[0].name = name
|
||||
obj[0].param = param_Str
|
||||
obj[0].pageSize = pageSize
|
||||
obj[0].pageList = pageList
|
||||
obj[0].UserID = Cookie.get('username')
|
||||
obj[0].ModularID = ''//this.$router.currentRoute.path
|
||||
console.log(obj[0], 'obj[0]')
|
||||
var numn = JSON.stringify(obj[0])
|
||||
return request({
|
||||
url: '',
|
||||
method: 'post',
|
||||
data: numn
|
||||
})
|
||||
}
|
||||
|
||||
// app.config.globalProperties.ExecWritePLC = function (opName, tagTypeCodeID, value) {
|
||||
// return request({
|
||||
// url: window.g.API_MES_URL + '/api/imes/Web_WritePLC',
|
||||
// method: 'post',
|
||||
// data: {
|
||||
// tagTypeCodeID: tagTypeCodeID,
|
||||
// OPName: opName,
|
||||
// tagValue: value,
|
||||
// }
|
||||
// }).catch(function (error) {
|
||||
// // 如果接口调用失败,弹出错误弹窗
|
||||
// ElMessage.error('写入PLC数据接口失败: ' + error.message)
|
||||
// });
|
||||
// }
|
||||
// app.config.globalProperties.ExecReadPLC = function (opName, tagTypeCodeID) {
|
||||
// return request({
|
||||
// url: window.g.API_MES_URL + '/api/imes/Web_ReadPLC',
|
||||
// method: 'post',
|
||||
// data: {
|
||||
// tagTypeCodeID: tagTypeCodeID,
|
||||
// OPName: opName,
|
||||
// }
|
||||
// }).catch(function (error) {
|
||||
// // 如果接口调用失败,弹出错误弹窗
|
||||
// ElMessage.error('读取PLC数据接口失败: ' + error.message)
|
||||
// });
|
||||
// }
|
||||
// app.config.globalProperties.ExecIMESAPI = function (apiName, param) {
|
||||
// return request({
|
||||
// url: window.g.API_MES_URL + '/api/imes/' + apiName,
|
||||
// method: 'post',
|
||||
// data: param
|
||||
// }).catch(function (error) {
|
||||
// // 如果接口调用失败,弹出错误弹窗
|
||||
// ElMessage.error('调用MES' + apiName + '接口失败: ' + error.message)
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
96
机加设备生产运营看板二/src/utils/index.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Created by jiachenpan on 16/11/18.
|
||||
*/
|
||||
|
||||
export function parseTime(time, cFormat) {
|
||||
if (arguments.length === 0) {
|
||||
return null
|
||||
}
|
||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if (('' + time).length === 10) time = parseInt(time) * 1000
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
m: date.getMonth() + 1,
|
||||
d: date.getDate(),
|
||||
h: date.getHours(),
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
})
|
||||
return time_str
|
||||
}
|
||||
|
||||
export function formatTime(time, option) {
|
||||
time = +time * 1000
|
||||
const d = new Date(time)
|
||||
const now = Date.now()
|
||||
|
||||
const diff = (now - d) / 1000
|
||||
|
||||
if (diff < 30) {
|
||||
return '刚刚'
|
||||
} else if (diff < 3600) {
|
||||
// less 1 hour
|
||||
return Math.ceil(diff / 60) + '分钟前'
|
||||
} else if (diff < 3600 * 24) {
|
||||
return Math.ceil(diff / 3600) + '小时前'
|
||||
} else if (diff < 3600 * 24 * 2) {
|
||||
return '1天前'
|
||||
}
|
||||
if (option) {
|
||||
return parseTime(time, option)
|
||||
} else {
|
||||
return (
|
||||
d.getMonth() +
|
||||
1 +
|
||||
'月' +
|
||||
d.getDate() +
|
||||
'日' +
|
||||
d.getHours() +
|
||||
'时' +
|
||||
d.getMinutes() +
|
||||
'分'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function zeroFill(i) {
|
||||
if (i >= 0 && i <= 9) {
|
||||
return '0' + i
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
export function getNowDAY() { // 默认显示今天
|
||||
// 获取当前时间
|
||||
const date = new Date()
|
||||
const month = zeroFill(date.getMonth() + 1)
|
||||
const day = zeroFill(date.getDate())
|
||||
const time = date.getFullYear() + '-' + month + '-' + day
|
||||
return time
|
||||
}
|
||||
|
||||
export function get90DAY() { // 3个月显示今天
|
||||
var Data = new Date()
|
||||
Data.setTime(Data.getTime() - 3600 * 1000 * 24 * 90)
|
||||
const month = zeroFill(Data.getMonth() + 1)
|
||||
const day = zeroFill(Data.getDate())
|
||||
const time = Data.getFullYear() + '-' + month + '-' + day
|
||||
return time
|
||||
}
|
||||
104
机加设备生产运营看板二/src/utils/mqtt.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import mqtt from 'mqtt'
|
||||
export { Mqtt }
|
||||
class Mqtt {
|
||||
constructor(config) {
|
||||
this.connection = {
|
||||
host: config.host,
|
||||
port: config.port,
|
||||
endpoint: config.endpoint || '/mqtt',
|
||||
clean: config.clean || true,
|
||||
connectTimeout: config.connectTimeout || 4000,
|
||||
reconnectPeriod: config.reconnectPeriod || 4000,
|
||||
clientId: config.clientId || uuid(),
|
||||
username: config.username || '',
|
||||
password: config.password || ''
|
||||
}
|
||||
this.client = {
|
||||
connected: false
|
||||
}
|
||||
}
|
||||
// 创建连接
|
||||
createConnection() {
|
||||
// 连接字符串, 通过协议指定使用的连接方式
|
||||
// ws 未加密 WebSocket 连接
|
||||
// wss 加密 WebSocket 连接
|
||||
// mqtt 未加密 TCP 连接
|
||||
// mqtts 加密 TCP 连接
|
||||
// wxs 微信小程序连接
|
||||
// alis 支付宝小程序连接
|
||||
const { host, port, endpoint, ...options } = this.connection
|
||||
const connectUrl = `ws://${host}:${port}${endpoint}`
|
||||
try {
|
||||
this.client = mqtt.connect(connectUrl, options)
|
||||
} catch (error) {
|
||||
// 连接错位、
|
||||
this.connectError(error)
|
||||
}
|
||||
}
|
||||
connectError(error) {
|
||||
console.log('mqtt.connect error', error)
|
||||
}
|
||||
// 订阅主题
|
||||
doSubscribe(subscription) {
|
||||
const { topic, qos } = subscription
|
||||
let subscribeSuccess = false
|
||||
this.client.subscribe(topic, { qos }, (error, res) => {
|
||||
if (error) {
|
||||
subscribeSuccess = false
|
||||
console.log('Subscribe to topics error', error)
|
||||
} else {
|
||||
subscribeSuccess = true
|
||||
console.log('Subscribe to topics res', res)
|
||||
}
|
||||
})
|
||||
return subscribeSuccess
|
||||
}
|
||||
// 取消订阅
|
||||
doUnSubscribe(subscription) {
|
||||
const { topic } = subscription
|
||||
let unSubscribeSuccess = false
|
||||
this.client.unsubscribe(topic, error => {
|
||||
if (error) {
|
||||
unSubscribeSuccess = false
|
||||
console.log('Unsubscribe error', error)
|
||||
} else {
|
||||
unSubscribeSuccess = true
|
||||
}
|
||||
})
|
||||
return unSubscribeSuccess
|
||||
}
|
||||
// 发送消息
|
||||
doPublish(publish) {
|
||||
const { topic, qos, payload } = publish
|
||||
let doPublishSuccess = false
|
||||
this.client.publish(topic, payload, qos, error => {
|
||||
if (error) {
|
||||
doPublishSuccess = false
|
||||
console.log('Publish error', error)
|
||||
} else {
|
||||
doPublishSuccess = true
|
||||
}
|
||||
})
|
||||
return doPublishSuccess
|
||||
}
|
||||
// 断开连接
|
||||
destroyConnection() {
|
||||
let destroyConnectionSuccess = false
|
||||
if (this.client.connected) {
|
||||
try {
|
||||
this.client.end()
|
||||
this.client = {
|
||||
connected: false
|
||||
}
|
||||
destroyConnectionSuccess = true
|
||||
console.log('Successfully disconnected!')
|
||||
} catch (error) {
|
||||
destroyConnectionSuccess = false
|
||||
console.log('Disconnect failed', error.toString())
|
||||
}
|
||||
}
|
||||
return destroyConnectionSuccess
|
||||
}
|
||||
}
|
||||
|
||||
35
机加设备生产运营看板二/src/utils/request.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import axios from 'axios'
|
||||
// import store from '@/store'
|
||||
import {ElMessage} from 'element-plus' // 引入Element Plus的消息提示组件
|
||||
const name_config = `OP8888`
|
||||
// import.meta.env.VITE_BASE_URL
|
||||
console.log(window.g)
|
||||
const request_config = window.g.API_WEB_URL + `/submit/MESCommonBase.ashx`
|
||||
export const name = name_config
|
||||
const service = axios.create({
|
||||
baseURL: request_config,
|
||||
timeout: 1000 * 5 // 请求超时时间
|
||||
})
|
||||
|
||||
// && config.data.name !== '菜单系统模块_通知信息_查询数据' && config.data.name !== '菜单系统模块_首页信息_查询数据1' && config.data.name !== '菜单系统模块_首页信息_查询数据2'
|
||||
service.interceptors.request.use(config => {
|
||||
|
||||
return config
|
||||
}, error => {
|
||||
if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
|
||||
ElMessage({
|
||||
message: '请求超时,请稍后再试。',
|
||||
type: 'error',
|
||||
duration: 5000
|
||||
})
|
||||
} else {
|
||||
ElMessage({
|
||||
message: '请求失败,请稍后再试。',
|
||||
type: 'error',
|
||||
duration: 5000
|
||||
})
|
||||
}
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
export default service
|
||||
90
机加设备生产运营看板二/src/utils/setMethods.js
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
/**
|
||||
* Parse the time to string
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} cFormat
|
||||
* @returns {string}
|
||||
*/
|
||||
export function parseTime(time, cFormat) {
|
||||
if (arguments.length === 0) {
|
||||
return null
|
||||
}
|
||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
|
||||
time = parseInt(time)
|
||||
}
|
||||
if (typeof time === 'number' && time.toString().length === 10) {
|
||||
time = time * 1000
|
||||
}
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
m: date.getMonth() + 1,
|
||||
d: date.getDate(),
|
||||
h: date.getHours(),
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') {
|
||||
return ['日', '一', '二', '三', '四', '五', '六'][value]
|
||||
}
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
})
|
||||
// eslint-disable-next-line
|
||||
return time_str
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json to excel
|
||||
* tableJson 导出数据 ; filenames导出表的名字; autowidth表格宽度自动 true or false; bookTypes xlsx & csv & txt
|
||||
* @param {(Object)} tableJson
|
||||
* @param {string} filenames
|
||||
* @param {boolean} autowidth
|
||||
* @param {string} bookTypes
|
||||
*/
|
||||
export function json2excel(tableJson, filenames, autowidth, bookTypes) {
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
var tHeader = []
|
||||
var dataArr = []
|
||||
var sheetnames = []
|
||||
for (var i in tableJson) {
|
||||
tHeader.push(tableJson[i].tHeader)
|
||||
dataArr.push(formatJson(tableJson[i].filterVal, tableJson[i].tableDatas))
|
||||
sheetnames.push(tableJson[i].sheetName)
|
||||
}
|
||||
console.log(dataArr, 9191)
|
||||
excel.export_json_to_excel2({
|
||||
header: tHeader,
|
||||
data: dataArr,
|
||||
sheetname: sheetnames,
|
||||
filename: filenames,
|
||||
autoWidth: autowidth,
|
||||
bookType: bookTypes
|
||||
})
|
||||
})
|
||||
}
|
||||
// 数据过滤,时间过滤
|
||||
function formatJson(filterVal, jsonData) {
|
||||
return jsonData.map(v =>
|
||||
filterVal.map(j => {
|
||||
if (j === 'timestamp') {
|
||||
return parseTime(v[j])
|
||||
} else {
|
||||
return v[j]
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
361
机加设备生产运营看板二/src/utils/tool.js
Normal file
@@ -0,0 +1,361 @@
|
||||
// 数组去重
|
||||
export function arrayUnique(arr) {
|
||||
arr.filter((element, index, arr) => {
|
||||
return arr.indexOf(element) === index
|
||||
})
|
||||
}
|
||||
|
||||
// 数组去重,数组中值是对象
|
||||
export function arrayUnique2(arr, name) {
|
||||
const hash = {}
|
||||
return arr.reduce(function (item, next) {
|
||||
hash[next[name]] ? '' : hash[next[name]] = true && item.push(next)
|
||||
return item
|
||||
}, [])
|
||||
}
|
||||
|
||||
// 时间转时间戳
|
||||
export function timeToStamp(time) {
|
||||
const date = new Date(time)
|
||||
return date.getTime()
|
||||
}
|
||||
|
||||
// 数组的深度拷贝
|
||||
export function arrDeepCopy(arr) {
|
||||
const newArr = []
|
||||
for (const prop in arr) newArr[prop] = typeof arr[prop] === 'object' ? arrDeepCopy(arr[prop]) : arr[prop]
|
||||
return newArr
|
||||
}
|
||||
|
||||
// 对象的深度拷贝
|
||||
export function objDeepCopy(obj) {
|
||||
const newObj = {}
|
||||
for (const prop in obj) newObj[prop] = typeof obj[prop] === 'object' ? objDeepCopy(obj[prop]) : obj[prop]
|
||||
return newObj
|
||||
}
|
||||
|
||||
function zeroFill(i) {
|
||||
if (i >= 0 && i <= 9) {
|
||||
return '0' + i
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前时间(yyyy-mm-dd hh:mm:ss)
|
||||
export function getNowTime() {
|
||||
const date = new Date()
|
||||
const month = zeroFill(date.getMonth() + 1)
|
||||
const day = zeroFill(date.getDate())
|
||||
const hour = zeroFill(date.getHours())
|
||||
const minute = zeroFill(date.getMinutes())
|
||||
const second = zeroFill(date.getSeconds())
|
||||
const time = date.getFullYear() + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
|
||||
return time
|
||||
}
|
||||
|
||||
export function getNowTime2() {
|
||||
const date66 = new Date()
|
||||
const month66 = zeroFill(date66.getMonth() + 1)
|
||||
const day66 = zeroFill(date66.getDate())
|
||||
const date = date66.getFullYear() + '-' + month66 + '-' + day66
|
||||
// var date = '2019-3-31'
|
||||
var arr = date.split('-')
|
||||
var year = arr[0] // 获取当前日期的年份
|
||||
var month = arr[1] // 获取当前日期的月份
|
||||
var day = arr[2] // 获取当前日期的日
|
||||
// var days = new Date(year, month, 0)
|
||||
// days = days.getDate() // 获取当前日期中月的天数
|
||||
var year2 = year
|
||||
var month2 = parseInt(month) - 1
|
||||
if (month2 === 0) {
|
||||
year2 = parseInt(year2) - 1
|
||||
month2 = 12
|
||||
}
|
||||
var day2 = day
|
||||
var days2 = new Date(year2, month2, 0)
|
||||
days2 = days2.getDate()
|
||||
if (day2 > days2) {
|
||||
day2 = days2
|
||||
}
|
||||
if (month2 < 10) {
|
||||
month2 = '0' + month2
|
||||
}
|
||||
var t2 = year2 + '-' + month2 + '-' + day2
|
||||
return t2
|
||||
}
|
||||
|
||||
// 获取当前时间(yyyy-mm-dd)
|
||||
export function getNowShotTime() {
|
||||
const date = new Date()
|
||||
const month = zeroFill(date.getMonth() + 1)
|
||||
const day = zeroFill(date.getDate())
|
||||
const time = date.getFullYear() + '-' + month + '-' + day
|
||||
return time
|
||||
}
|
||||
|
||||
// 获取当前时间(yyyy/mm/dd)
|
||||
export function getNowShotTime1() {
|
||||
const date = new Date()
|
||||
const month = zeroFill(date.getMonth() + 1)
|
||||
const day = zeroFill(date.getDate())
|
||||
const time = date.getFullYear() + '/' + month + '/' + day
|
||||
return time
|
||||
}
|
||||
|
||||
// 获取当前0晨
|
||||
export function getNowTime1() {
|
||||
const date = new Date()
|
||||
const month = zeroFill(date.getMonth() + 1)
|
||||
const year = zeroFill(date.getFullYear())
|
||||
const day = zeroFill(date.getDate())
|
||||
let hour = zeroFill(date.getHours())
|
||||
hour = hour < 10 ? ('0' + hour) : hour
|
||||
let minute = zeroFill(date.getMinutes())
|
||||
minute = minute < 10 ? ('0' + minute) : minute
|
||||
let second = zeroFill(date.getSeconds())
|
||||
second = second < 10 ? ('0' + second) : second
|
||||
// const hour = '00'
|
||||
// const minute = '00'
|
||||
// const second = '00'
|
||||
const time = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
|
||||
return time
|
||||
}
|
||||
|
||||
export function getNowTime3(date) {
|
||||
const month = zeroFill2(date.getMonth() + 1)
|
||||
const day = zeroFill(date.getDate())
|
||||
return date.getFullYear() + '-' + month + '-' + day
|
||||
}
|
||||
|
||||
function zeroFill2(i) {
|
||||
if (i >= 0 && i <= 9) {
|
||||
if (i === 0) {
|
||||
return '01'
|
||||
} else {
|
||||
return '0' + i
|
||||
}
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
// 工时统计上个月26-本月25
|
||||
export function getTime26() {
|
||||
const date = new Date()
|
||||
const day = date.getDate()
|
||||
if (day >= 25) {
|
||||
var month = zeroFill(date.getMonth() + 1)
|
||||
if (month === 0) {
|
||||
month = 12
|
||||
const day = 26
|
||||
const time = date.getFullYear() - 1 + '-' + month + '-' + day
|
||||
return time
|
||||
} else {
|
||||
const day = 26
|
||||
const time = date.getFullYear() + '-' + month + '-' + day
|
||||
return time
|
||||
}
|
||||
} else {
|
||||
var month2 = zeroFill(date.getMonth() + 1) - 1
|
||||
if (month2 === 0) {
|
||||
month2 = 12
|
||||
const day = 26
|
||||
const time = date.getFullYear() - 1 + '-' + month2 + '-' + day
|
||||
return time
|
||||
} else {
|
||||
const day = 26
|
||||
const time = date.getFullYear() + '-' + month2 + '-' + day
|
||||
return time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getTime25() {
|
||||
const date = new Date()
|
||||
const day = date.getDate()
|
||||
if (day >= 25) {
|
||||
const month = zeroFill(date.getMonth() + 2)
|
||||
const day2 = 25
|
||||
const time = date.getFullYear() + '-' + month + '-' + day2
|
||||
return time
|
||||
} else {
|
||||
const month = zeroFill(date.getMonth() + 1)
|
||||
const day2 = 25
|
||||
const time = date.getFullYear() + '-' + month + '-' + day2
|
||||
return time
|
||||
}
|
||||
}
|
||||
|
||||
// 判断类型
|
||||
export function type(target) {
|
||||
const ret = typeof (target)
|
||||
const template = {
|
||||
'[object Array]': 'array',
|
||||
'[object Object]': 'object',
|
||||
'[object String]': 'string - object',
|
||||
'[object Number]': 'Number - object',
|
||||
'[object Boolean]': 'Boolean - object'
|
||||
}
|
||||
if (target === null) {
|
||||
return 'null'
|
||||
}
|
||||
if (ret === 'object') {
|
||||
const str = Object.prototype.toString.call(target)
|
||||
return template[str]
|
||||
} else {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
export function SectionToChinese(section) {
|
||||
const chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
|
||||
const chnUnitChar = ['', '十', '百', '千']
|
||||
let strIns = ''
|
||||
let chnStr = ''
|
||||
let unitPos = 0
|
||||
let zero = true
|
||||
while (section > 0) {
|
||||
const v = section % 10
|
||||
if (v === 0) {
|
||||
if (!zero) {
|
||||
zero = true
|
||||
chnStr = chnNumChar[v] + chnStr
|
||||
}
|
||||
} else {
|
||||
zero = false
|
||||
strIns = chnNumChar[v]
|
||||
strIns += chnUnitChar[unitPos]
|
||||
chnStr = strIns + chnStr
|
||||
}
|
||||
unitPos++
|
||||
section = Math.floor(section / 10)
|
||||
}
|
||||
return chnStr
|
||||
}
|
||||
|
||||
export function sleep(time) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, time)
|
||||
})
|
||||
}
|
||||
|
||||
export function groupBy(datas, keys) {
|
||||
const list = datas || []
|
||||
const groups = []
|
||||
const result = []
|
||||
list.forEach(v => {
|
||||
const key = {}
|
||||
keys.forEach(k => {
|
||||
key[k] = v[k]
|
||||
})
|
||||
let group = groups.find(v => {
|
||||
return v._key === JSON.stringify(key)
|
||||
})
|
||||
if (!group) {
|
||||
group = {
|
||||
_key: JSON.stringify(key),
|
||||
key: key
|
||||
}
|
||||
groups.push(group)
|
||||
}
|
||||
group.data1 = group.data1 || 0
|
||||
group.key.数量 = group.data1 += v.数量
|
||||
group.data2 = group.data2 || ''
|
||||
group.key.机床图号_组号 = group.data2 += (v.机床图号 || '') + '-' + (v.组号 ? v.组号.split('组')[0] : '') + '<br/>'
|
||||
group.data3 = group.data3 || 0
|
||||
group.key.合计 = group.data3 += v.合计
|
||||
})
|
||||
groups.map(v => {
|
||||
result.push(v.key)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
// 去除js浮点加法bug
|
||||
export function numAdd(arg1, arg2) {
|
||||
var r1, r2, m
|
||||
try {
|
||||
r1 = arg1.toString().split('.')[1].length
|
||||
} catch (e) {
|
||||
r1 = 0
|
||||
}
|
||||
try {
|
||||
r2 = arg2.toString().split('.')[1].length
|
||||
} catch (e) {
|
||||
r2 = 0
|
||||
}
|
||||
m = Math.pow(10, Math.max(r1, r2))
|
||||
return (arg1 * m + arg2 * m) / m
|
||||
}
|
||||
|
||||
// 去除js浮点减法bug
|
||||
export function numSubtract(arg1, arg2) {
|
||||
var r1, r2, m, n
|
||||
try {
|
||||
r1 = arg1.toString().split('.')[1].length
|
||||
} catch (e) {
|
||||
r1 = 0
|
||||
}
|
||||
try {
|
||||
r2 = arg2.toString().split('.')[1].length
|
||||
} catch (e) {
|
||||
r2 = 0
|
||||
}
|
||||
m = Math.pow(10, Math.max(r1, r2))
|
||||
n = (r1 >= r2) ? r1 : r2
|
||||
return ((arg1 * m - arg2 * m) / m).toFixed(n)
|
||||
}
|
||||
|
||||
// 去除js浮点乘法bug
|
||||
export function numMultiply(arg1, arg2) {
|
||||
var m = 0
|
||||
var s1 = arg1.toString()
|
||||
var s2 = arg2.toString()
|
||||
try {
|
||||
m += s1.split('.')[1].length
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
try {
|
||||
m += s2.split('.')[1].length
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
|
||||
}
|
||||
|
||||
// 去除js浮点除法bug
|
||||
export function numDivide(arg1, arg2) {
|
||||
var t1 = 0
|
||||
var t2 = 0
|
||||
var r1, r2
|
||||
try {
|
||||
t1 = arg1.toString().split('.')[1].length
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
try {
|
||||
t2 = arg2.toString().split('.')[1].length
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
r1 = Math.Number(arg1.toString().replace('.', ''))
|
||||
r2 = Math.Number(arg2.toString().replace('.', ''))
|
||||
return (r1 / r2) * Math.pow(10, t2 - t1)
|
||||
}
|
||||
|
||||
export function base64ImgtoFile(dataurl, filename = 'file') {
|
||||
const arr = dataurl.split(',')
|
||||
const mime = arr[0].match(/:(.*?);/)[1]
|
||||
const suffix = mime.split('/')[1]
|
||||
const bstr = atob(arr[1])
|
||||
let n = bstr.length
|
||||
const u8arr = new Uint8Array(n)
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n)
|
||||
}
|
||||
return new File([u8arr], `${filename}.${suffix}`, {
|
||||
type: mime
|
||||
})
|
||||
}
|
||||
32
机加设备生产运营看板二/src/utils/validate.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Created by jiachenpan on 16/11/18.
|
||||
*/
|
||||
|
||||
export function isvalidUsername(str) {
|
||||
const user = /^[0-9]{5,7}$/
|
||||
return true
|
||||
}
|
||||
|
||||
/* 合法uri*/
|
||||
export function validateURL(textval) {
|
||||
const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
|
||||
return urlregex.test(textval)
|
||||
}
|
||||
|
||||
/* 小写字母*/
|
||||
export function validateLowerCase(str) {
|
||||
const reg = /^[a-z]+$/
|
||||
return reg.test(str)
|
||||
}
|
||||
|
||||
/* 大写字母*/
|
||||
export function validateUpperCase(str) {
|
||||
const reg = /^[A-Z]+$/
|
||||
return reg.test(str)
|
||||
}
|
||||
|
||||
/* 大小写字母*/
|
||||
export function validatAlphabets(str) {
|
||||
const reg = /^[A-Za-z]+$/
|
||||
return reg.test(str)
|
||||
}
|
||||
248
机加设备生产运营看板二/src/views/404.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404">
|
||||
<div class="pic-404">
|
||||
<img
|
||||
class="pic-404__parent"
|
||||
src="@/assets/404_images/404.png"
|
||||
alt="404"
|
||||
/>
|
||||
<img
|
||||
class="pic-404__child left"
|
||||
src="@/assets/404_images/404_cloud.png"
|
||||
alt="404"
|
||||
/>
|
||||
<img
|
||||
class="pic-404__child mid"
|
||||
src="@/assets/404_images/404_cloud.png"
|
||||
alt="404"
|
||||
/>
|
||||
<img
|
||||
class="pic-404__child right"
|
||||
src="@/assets/404_images/404_cloud.png"
|
||||
alt="404"
|
||||
/>
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops">OOPS!</div>
|
||||
<div class="bullshit__info">
|
||||
版权所有
|
||||
<a class="link-type" href="https://wallstreetcn.com" target="_blank"
|
||||
>华尔街见闻</a
|
||||
>
|
||||
</div>
|
||||
<div class="bullshit__headline">{{ message }}</div>
|
||||
<div class="bullshit__info">
|
||||
请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告
|
||||
</div>
|
||||
<a href="/" class="bullshit__return-home">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Page404",
|
||||
computed: {
|
||||
message() {
|
||||
return "网管说这个页面你不能进......";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.wscn-http404-container {
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
}
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
padding: 0 50px;
|
||||
overflow: hidden;
|
||||
.pic-404 {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 600px;
|
||||
overflow: hidden;
|
||||
&__parent {
|
||||
width: 100%;
|
||||
}
|
||||
&__child {
|
||||
position: absolute;
|
||||
&.left {
|
||||
width: 80px;
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
animation-name: cloudLeft;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
&.mid {
|
||||
width: 46px;
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
animation-name: cloudMid;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
&.right {
|
||||
width: 62px;
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
animation-name: cloudRight;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
@keyframes cloudLeft {
|
||||
0% {
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 33px;
|
||||
left: 188px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 81px;
|
||||
left: 92px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 97px;
|
||||
left: 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudMid {
|
||||
0% {
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 40px;
|
||||
left: 360px;
|
||||
opacity: 1;
|
||||
}
|
||||
70% {
|
||||
top: 130px;
|
||||
left: 180px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 160px;
|
||||
left: 120px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudRight {
|
||||
0% {
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 120px;
|
||||
left: 460px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 180px;
|
||||
left: 340px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 200px;
|
||||
left: 300px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bullshit {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 300px;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
&__oops {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 40px;
|
||||
color: #1482f0;
|
||||
opacity: 0;
|
||||
margin-bottom: 20px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__headline {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
margin-bottom: 10px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.1s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__info {
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
color: grey;
|
||||
opacity: 0;
|
||||
margin-bottom: 30px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__return-home {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 110px;
|
||||
height: 36px;
|
||||
background: #1482f0;
|
||||
border-radius: 100px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
opacity: 0;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
828
机加设备生产运营看板二/src/views/index.vue
Normal file
@@ -0,0 +1,828 @@
|
||||
<template>
|
||||
<div
|
||||
class="machining-two-page"
|
||||
:style="{ width: `${style.width}px`, height: `${style.height}px`, transform: style.transform }"
|
||||
>
|
||||
<header class="dashboard-header">
|
||||
<div class="brand">
|
||||
<img class="brand-logo" :src="clientLogoUrl" alt="RENLY" />
|
||||
</div>
|
||||
<h1>机加设备生产运营看板(二)</h1>
|
||||
<div class="clock">{{ currentTime }}</div>
|
||||
</header>
|
||||
|
||||
<main class="dashboard-body">
|
||||
<section v-for="card in summaryCards" :key="card.title" class="panel summary-card" :class="card.className">
|
||||
<img class="summary-icon" :src="card.icon" alt="" />
|
||||
<div class="summary-content">
|
||||
<div class="summary-title">{{ card.title }}</div>
|
||||
<div class="summary-label">总数</div>
|
||||
<div class="summary-number">
|
||||
<strong :class="card.valueClass">{{ card.value }}</strong>
|
||||
<span>{{ card.unit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="card.people" class="absence-list">
|
||||
<div v-for="person in card.people" :key="person.name">
|
||||
<span>{{ person.name }}</span>
|
||||
<span>({{ person.station }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel work-detail-panel">
|
||||
<div class="panel-title">在制任务明细</div>
|
||||
<div class="table-box datav-table main-task-table">
|
||||
<dv-scroll-board :config="inProcessBoardConfig" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel urgent-list-panel">
|
||||
<div class="panel-title">加急任务列表</div>
|
||||
<div class="table-box datav-table">
|
||||
<dv-scroll-board :config="urgentBoardConfig" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel process-task-panel">
|
||||
<div class="panel-title">关键工序任务明细</div>
|
||||
<div class="table-box datav-table">
|
||||
<dv-scroll-board :config="keyProcessBoardConfig" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel start-task-panel">
|
||||
<div class="panel-title">正在开工任务</div>
|
||||
<div class="table-box datav-table">
|
||||
<dv-scroll-board :config="startedBoardConfig" />
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import { computed, inject, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
const tableData = ref([])
|
||||
const CreateData = inject('CreateData')
|
||||
const ExecDatabase = inject('ExecDatabase')
|
||||
defineOptions({
|
||||
name: 'MachiningOperationTwoDashboard'
|
||||
})
|
||||
|
||||
const clientLogoUrl = './public/ClientLogo.png'
|
||||
const svgData = svg => 'data:image/svg+xml;utf8,' + encodeURIComponent(svg)
|
||||
const lineIcon = (color, body, viewBox = '0 0 64 64') => {
|
||||
const size = parseFloat(viewBox.split(' ')[2]) || 64
|
||||
const sw = size <= 28 ? 1.4 : 2.0
|
||||
return svgData(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="' + viewBox + '" fill="none">' +
|
||||
'<g stroke="' + color + '" stroke-width="' + sw + '" stroke-linecap="round" stroke-linejoin="round">' +
|
||||
body +
|
||||
'</g></svg>'
|
||||
)
|
||||
}
|
||||
|
||||
const icons = {
|
||||
clipboard: lineIcon('#35c36a', '<rect x="18" y="13" width="31" height="42" rx="3"/><path d="M27 13h13l-3-6h-8zM25 27h16M25 36h16M25 45h16"/>'),
|
||||
rocket: lineIcon('#248cff', '<path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2Z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09Z"/><circle cx="15" cy="9" r="1.5"/>', '0 0 24 24'),
|
||||
shield: lineIcon('#6954dd', '<path d="M32 8 52 17v15c0 12-8 20-20 25-12-5-20-13-20-25V17z"/><circle cx="32" cy="32" r="9"/><path d="M32 22v4M32 38v4M22 32h4M38 32h4M25 25l3 3M36 36l3 3M39 25l-3 3M28 36l-3 3"/>'),
|
||||
user: lineIcon('#ff941e', '<circle cx="32" cy="19" r="10"/><path d="M14 55c2-12 9-19 18-19s16 7 18 19z"/>')
|
||||
}
|
||||
|
||||
const style = reactive({
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
transform: 'scaleY(1) scaleX(1) translate(-50%, -50%)'
|
||||
})
|
||||
const currentTime = ref('')
|
||||
let clockTimer = null
|
||||
let resizeHandler = null
|
||||
|
||||
// 将 computed 改为 ref
|
||||
const summaryCards = ref([
|
||||
{
|
||||
title: '在制任务汇总',
|
||||
value: 84,
|
||||
unit: '单',
|
||||
icon: icons.clipboard,
|
||||
className: 'wip-card',
|
||||
valueClass: 'green-text'
|
||||
},
|
||||
{
|
||||
title: '加急任务汇总',
|
||||
value: 26,
|
||||
unit: '单',
|
||||
icon: icons.rocket,
|
||||
className: 'urgent-card',
|
||||
valueClass: 'blue-text'
|
||||
},
|
||||
{
|
||||
title: '关键工序任务',
|
||||
value: 14,
|
||||
unit: '单',
|
||||
icon: icons.shield,
|
||||
className: 'key-card',
|
||||
valueClass: 'purple-text'
|
||||
},
|
||||
{
|
||||
title: '缺勤人员',
|
||||
value: 4,
|
||||
unit: '人',
|
||||
icon: icons.user,
|
||||
className: 'absence-card',
|
||||
valueClass: 'orange-text',
|
||||
people: [
|
||||
{ name: '张三', station: '铣床1#' },
|
||||
{ name: '王五', station: '车床2#' },
|
||||
{ name: '孙八', station: '磨床1#' },
|
||||
{ name: '郑十一', station: '检验台1#' }
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
|
||||
const inProcessRows = ref([
|
||||
])
|
||||
|
||||
const urgentRows = ref([
|
||||
{ productionOrder: 'MO260428-001', salesOrder: 'SO260413-001', materialName: '主轴壳体', materialCode: 'MP-BOX-001', processName: '精铣', assignQty: 120, prevPassQty: 105, urgentQty: 15, assignee: '张伟' },
|
||||
{ productionOrder: 'MO260428-002', salesOrder: 'SO260413-005', materialName: '法兰盘', materialCode: 'MP-FLANGE-002', processName: '镗孔', assignQty: 80, prevPassQty: 68, urgentQty: 12, assignee: '李强' },
|
||||
{ productionOrder: 'MO260428-003', salesOrder: 'SO260414-002', materialName: '齿轮轴', materialCode: 'MP-GEAR-001', processName: '磨削', assignQty: 60, prevPassQty: 48, urgentQty: 12, assignee: '王磊' },
|
||||
{ productionOrder: 'MO260428-004', salesOrder: 'SO260414-003', materialName: '端盖', materialCode: 'MP-COVER-003', processName: '钻孔', assignQty: 90, prevPassQty: 75, urgentQty: 15, assignee: '刘洋' },
|
||||
{ productionOrder: 'MO260428-005', salesOrder: 'SO260414-007', materialName: '导轨座', materialCode: 'MP-RAIL-002', processName: '精镗', assignQty: 70, prevPassQty: 60, urgentQty: 10, assignee: '赵峰' },
|
||||
{ productionOrder: 'MO260428-006', salesOrder: 'SO260415-001', materialName: '轴承座', materialCode: 'MP-BEAR-001', processName: '铣平面', assignQty: 50, prevPassQty: 42, urgentQty: 8, assignee: '陈晨' },
|
||||
{ productionOrder: 'MO260428-007', salesOrder: 'SO260415-003', materialName: '联轴器', materialCode: 'MP-COUP-001', processName: '车削', assignQty: 40, prevPassQty: 32, urgentQty: 8, assignee: '周杰' },
|
||||
{ productionOrder: 'MO260428-008', salesOrder: 'SO260415-005', materialName: '垫板', materialCode: 'MP-PLATE-001', processName: '钻孔', assignQty: 100, prevPassQty: 88, urgentQty: 12, assignee: '孙鹏' }
|
||||
])
|
||||
|
||||
const keyProcessRows = ref([
|
||||
{ productionOrder: 'MO260428-201', salesOrder: 'SO260413-001', materialName: '主轴壳体', materialCode: 'MP-BOX-001', processName: '精镗面', assignQty: 120, prevPassQty: 105, urgentQty: 15, assignee: '周检' },
|
||||
{ productionOrder: 'MO260428-202', salesOrder: 'SO260413-002', materialName: '法兰盘', materialCode: 'MP-FLANGE-002', processName: '镗孔尺寸', assignQty: 80, prevPassQty: 68, urgentQty: 12, assignee: '吕检' },
|
||||
{ productionOrder: 'MO260428-203', salesOrder: 'SO260413-003', materialName: '齿轮轴', materialCode: 'MP-GEAR-001', processName: '磨削圆度', assignQty: 60, prevPassQty: 48, urgentQty: 12, assignee: '何检' },
|
||||
{ productionOrder: 'MO260428-204', salesOrder: 'SO260413-004', materialName: '端盖', materialCode: 'MP-COVER-003', processName: '平面度', assignQty: 90, prevPassQty: 75, urgentQty: 15, assignee: '郭检' },
|
||||
{ productionOrder: 'MO260428-205', salesOrder: 'SO260414-001', materialName: '导轨座', materialCode: 'MP-RAIL-002', processName: '平行度', assignQty: 70, prevPassQty: 60, urgentQty: 10, assignee: '丁检' },
|
||||
{ productionOrder: 'MO260428-206', salesOrder: 'SO260414-002', materialName: '轴承座', materialCode: 'MP-BEAR-001', processName: '孔距尺寸', assignQty: 50, prevPassQty: 42, urgentQty: 8, assignee: '黄检' },
|
||||
{ productionOrder: 'MO260428-207', salesOrder: 'SO260414-003', materialName: '联轴器', materialCode: 'MP-COUP-001', processName: '端面跳动', assignQty: 40, prevPassQty: 32, urgentQty: 8, assignee: '蒋检' },
|
||||
{ productionOrder: 'MO260428-208', salesOrder: 'SO260414-004', materialName: '垫板', materialCode: 'MP-PLATE-001', processName: '厚度', assignQty: 100, prevPassQty: 88, urgentQty: 12, assignee: '韩检' }
|
||||
])
|
||||
|
||||
const startedRows = ref([
|
||||
{ productionOrder: 'MO260429-301', salesOrder: 'SO260415-101', materialName: '箱体壳体', materialCode: 'MP-BOX-009', processName: '粗铣', assignQty: 30 },
|
||||
{ productionOrder: 'MO260429-302', salesOrder: 'SO260415-102', materialName: '轴套', materialCode: 'MP-SHAFT-008', processName: '轴车', assignQty: 24 },
|
||||
{ productionOrder: 'MO260429-303', salesOrder: 'SO260415-103', materialName: '端盖', materialCode: 'MP-CAP-006', processName: '钻孔', assignQty: 20 },
|
||||
{ productionOrder: 'MO260429-304', salesOrder: 'SO260415-104', materialName: '支架', materialCode: 'MP-BRKT-009', processName: '平面铣', assignQty: 16 },
|
||||
{ productionOrder: 'MO260429-305', salesOrder: 'SO260415-105', materialName: '导轨座', materialCode: 'MP-RAIL-010', processName: '铣槽', assignQty: 18 },
|
||||
{ productionOrder: 'MO260429-306', salesOrder: 'SO260415-106', materialName: '盖板', materialCode: 'MP-COVER-011', processName: '攻丝', assignQty: 22 },
|
||||
{ productionOrder: 'MO260429-307', salesOrder: 'SO260415-107', materialName: '连接板', materialCode: 'MP-PLATE-010', processName: '钻孔', assignQty: 28 },
|
||||
{ productionOrder: 'MO260429-308', salesOrder: 'SO260415-108', materialName: '滑块', materialCode: 'MP-SLIDER-009', processName: '精磨', assignQty: 14 }
|
||||
])
|
||||
|
||||
const extendRows = (rows, minRows, idKey = 'productionOrder') => {
|
||||
const result = [...rows]
|
||||
let round = 1
|
||||
while (result.length < minRows) {
|
||||
rows.forEach(row => {
|
||||
if (result.length >= minRows) return
|
||||
const suffix = String(round + 1).padStart(2, '0')
|
||||
result.push({
|
||||
...row,
|
||||
[idKey]: row[idKey].replace(/(\d+)$/, value => String(Number(value) + round * 100).padStart(value.length, '0'))
|
||||
|| `${row[idKey]}-${suffix}`
|
||||
})
|
||||
})
|
||||
round += 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const boardBaseConfig = {
|
||||
headerBGC: 'rgba(8, 65, 126, .94)',
|
||||
oddRowBGC: 'rgba(5, 28, 65, .52)',
|
||||
evenRowBGC: 'rgba(3, 20, 51, .42)',
|
||||
headerHeight: 34,
|
||||
waitTime: 1400,
|
||||
carousel: 'single',
|
||||
hoverPause: true,
|
||||
align: 'center',
|
||||
index: false
|
||||
}
|
||||
|
||||
const progressText = value => (
|
||||
'<div class="progress-cell">' +
|
||||
'<span class="progress-track"><span class="progress-fill" style="width:' + value + '%"></span></span>' +
|
||||
'<strong>' + Number(value).toFixed(1) + '%</strong>' +
|
||||
'</div>'
|
||||
)
|
||||
|
||||
const inProcessBoardConfig = computed(() => ({
|
||||
...boardBaseConfig,
|
||||
rowNum: 12,
|
||||
columnWidth: [126, 130, 116, 136, 88, 80, 80, 158],
|
||||
header: ['生产订单', '销售订单', '物料名称', '物料编码', '工序名称', '分配数量', '完成数量', '进度百分比%'],
|
||||
data: extendRows(inProcessRows.value, 18).map(row => [
|
||||
row.productionOrder,
|
||||
row.salesOrder,
|
||||
row.materialName,
|
||||
row.materialCode,
|
||||
row.processName,
|
||||
row.assignQty,
|
||||
row.finishQty,
|
||||
progressText(row.progress)
|
||||
])
|
||||
}))
|
||||
|
||||
const urgentBoardConfig = computed(() => makeTaskBoard(urgentRows.value))
|
||||
const keyProcessBoardConfig = computed(() => makeTaskBoard(keyProcessRows.value))
|
||||
|
||||
const startedBoardConfig = computed(() => ({
|
||||
...boardBaseConfig,
|
||||
rowNum: 8,
|
||||
columnWidth: [160, 170, 140, 176, 140, 128],
|
||||
header: ['生产订单', '销售订单', '物料名称', '物料编码', '工序名称', '分配数量'],
|
||||
data: extendRows(startedRows.value, 12).map(row => [
|
||||
row.productionOrder,
|
||||
row.salesOrder,
|
||||
row.materialName,
|
||||
row.materialCode,
|
||||
row.processName,
|
||||
row.assignQty
|
||||
])
|
||||
}))
|
||||
|
||||
function makeTaskBoard(rows) {
|
||||
return {
|
||||
...boardBaseConfig,
|
||||
rowNum: 8,
|
||||
columnWidth: [122, 132, 132, 152, 92, 82, 92, 82, 94],
|
||||
header: ['生产订单', '销售订单', '物料名称', '物料编码', '工序名称', '分配数量', '加急数量', '指派对象'],
|
||||
data: extendRows(rows, 12).map(row => [
|
||||
row.productionOrder,
|
||||
row.salesOrder,
|
||||
row.materialName,
|
||||
row.materialCode,
|
||||
row.processName,
|
||||
row.assignQty,
|
||||
row.urgentQty,
|
||||
row.assignee
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
refreshClock()
|
||||
clockTimer = window.setInterval(refreshClock, 1000)
|
||||
setScale()
|
||||
resizeHandler = setScale
|
||||
window.addEventListener('resize', resizeHandler)
|
||||
searchDashboardData()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (clockTimer) {
|
||||
window.clearInterval(clockTimer)
|
||||
clockTimer = null
|
||||
}
|
||||
if (resizeHandler) {
|
||||
window.removeEventListener('resize', resizeHandler)
|
||||
resizeHandler = null
|
||||
}
|
||||
})
|
||||
const queryDashboardData = (procedureName, applyData) => {
|
||||
let data
|
||||
if (typeof CreateData !== 'function' || typeof ExecDatabase !== 'function') {
|
||||
|
||||
return
|
||||
}
|
||||
data = CreateData('11', procedureName, [])
|
||||
ExecDatabase(data).then(response => {
|
||||
const rows = getResponseRows(response)
|
||||
if (rows.length > 0) {
|
||||
tableData.value = rows
|
||||
applyData(rows)
|
||||
nextTick(() => {
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const getResponseRows = response => {
|
||||
if (response && Array.isArray(response.data)) {
|
||||
return response.data
|
||||
}
|
||||
if (response && response.data && Array.isArray(response.data.result)) {
|
||||
return response.data.result
|
||||
}
|
||||
return []
|
||||
}
|
||||
const searchDashboardData = () => {
|
||||
searchUrgentData()
|
||||
searchInProcessData()
|
||||
searchInProcessData2()
|
||||
}
|
||||
const searchUrgentData = () => {
|
||||
queryDashboardData('机加设备生产运营看板_加急任务查询', applyUrgentData)
|
||||
}
|
||||
const searchInProcessData = () => {
|
||||
queryDashboardData('机加设备生产运营看板_机加在制查询', applyInProcessData)
|
||||
}
|
||||
|
||||
const searchInProcessData2 = () => {
|
||||
queryDashboardData('机加设备生产运营看板_机加在制查询2', applyInProcessData2)
|
||||
}
|
||||
|
||||
// 修改赋值逻辑
|
||||
const applyUrgentData = rows => {
|
||||
const first = getFirstRow(rows)
|
||||
console.log(first)
|
||||
// 加急任务汇总卡片是索引1
|
||||
if (first.加急订单总数 !== undefined) {
|
||||
summaryCards.value[1].value = first.加急订单总数
|
||||
}
|
||||
urgentRows .value = rows.map(row => ({
|
||||
productionOrder: row.订单编号,
|
||||
salesOrder:row.合同号,
|
||||
materialName: row.物料描述,
|
||||
materialCode: row.物料编号,
|
||||
assignQty: row.计划数量,
|
||||
urgentQty: row.加急数量,
|
||||
prevPassQty:'',
|
||||
processName:row.工序名称,
|
||||
assignee:row.指派对象,
|
||||
}))
|
||||
|
||||
}
|
||||
const applyInProcessData = rows => {
|
||||
const first = getFirstRow(rows)
|
||||
startedRows .value = rows.map(row => ({
|
||||
productionOrder: row.订单号,
|
||||
salesOrder:row.合同号,
|
||||
materialName: row.零件名称,
|
||||
materialCode: row.零件编码,
|
||||
assignQty: row.分配数,
|
||||
processName:row.工序名称,
|
||||
assignee:row.指派对象,
|
||||
}))
|
||||
|
||||
}
|
||||
const applyInProcessData2 = rows => {
|
||||
const first = getFirstRow(rows)
|
||||
summaryCards.value[0].value = first.总数
|
||||
inProcessRows .value = rows.map(row => ({
|
||||
productionOrder: row.订单号,
|
||||
salesOrder:row.合同号,
|
||||
materialName: row.零件名称,
|
||||
materialCode: row.零件编码,
|
||||
assignQty: row.分配数,
|
||||
processName:row.工序名称,
|
||||
assignee: row.指派对象,
|
||||
finishQty: row.完成数量,
|
||||
progress: ((row.完成数量 / row.分配数) * 100).toFixed(2)
|
||||
}))
|
||||
|
||||
}
|
||||
const getFirstRow = rows => {
|
||||
if (Array.isArray(rows) && rows.length > 0) {
|
||||
return rows[0]
|
||||
}
|
||||
return {}
|
||||
}
|
||||
const refreshClock = () => {
|
||||
const now = new Date()
|
||||
const pad = value => String(value).padStart(2, '0')
|
||||
const weeks = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
|
||||
currentTime.value = `${now.getFullYear()}年${pad(now.getMonth() + 1)}月${pad(now.getDate())}日 ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())} ${weeks[now.getDay()]}`
|
||||
}
|
||||
|
||||
const setScale = () => {
|
||||
const scale = getScale()
|
||||
style.transform = `scaleY(${scale.y}) scaleX(${scale.x}) translate(-50%, -50%)`
|
||||
}
|
||||
|
||||
const getScale = () => ({
|
||||
x: window.innerWidth / style.width,
|
||||
y: window.innerHeight / style.height
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:global(html),
|
||||
:global(body),
|
||||
:global(#app) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #010716;
|
||||
}
|
||||
|
||||
:global(.t-loading),
|
||||
:global(.t-loading__parent) {
|
||||
min-height: 100%;
|
||||
background: #010716;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.machining-two-page {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
color: #dce9ff;
|
||||
font-family: "Microsoft YaHei", "PingFang SC", Arial, sans-serif;
|
||||
transform-origin: 0 0;
|
||||
transition: 0.3s;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(18, 88, 176, 0.07) 1px, transparent 1px),
|
||||
linear-gradient(180deg, rgba(18, 88, 176, 0.055) 1px, transparent 1px),
|
||||
radial-gradient(ellipse at 50% -4%, rgba(19, 101, 209, 0.38), rgba(4, 27, 76, 0.16) 28%, transparent 58%),
|
||||
linear-gradient(180deg, #010716 0%, #021330 48%, #010716 100%);
|
||||
background-size: 66px 66px, 66px 66px, auto, auto;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
position: relative;
|
||||
height: 76px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 18px;
|
||||
border-top: 3px solid rgba(82, 148, 224, .9);
|
||||
background:
|
||||
linear-gradient(112deg, rgba(8, 24, 70, .96) 0 16%, rgba(2, 8, 27, .98) 16% 30%, rgba(5, 23, 60, .78) 50%, rgba(2, 8, 27, .98) 70% 100%);
|
||||
}
|
||||
|
||||
.dashboard-header::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 323px;
|
||||
right: 323px;
|
||||
bottom: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, #0c6dc4 18%, #4ee7ff 50%, #0c6dc4 82%, transparent);
|
||||
box-shadow: 0 0 12px rgba(51, 210, 255, .78);
|
||||
}
|
||||
|
||||
.brand {
|
||||
width: 318px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
width: 194px;
|
||||
height: 47px;
|
||||
padding: 2px 8px;
|
||||
object-fit: contain;
|
||||
object-position: left center;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dashboard-header h1 {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 20px;
|
||||
margin: 0;
|
||||
transform: translateX(-50%);
|
||||
color: #fbfdff;
|
||||
font-size: 34px;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
letter-spacing: 13px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 10px rgba(255, 255, 255, .35);
|
||||
}
|
||||
|
||||
.clock {
|
||||
margin-left: auto;
|
||||
min-width: 468px;
|
||||
color: #dfe6f4;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dashboard-body {
|
||||
position: relative;
|
||||
height: calc(100% - 76px);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(0, 214, 255, .76);
|
||||
border-radius: 5px;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(6, 40, 94, .22), transparent 18%, transparent 82%, rgba(6, 40, 94, .22)),
|
||||
radial-gradient(circle at 8% 0, rgba(24, 120, 230, .14), transparent 28%),
|
||||
linear-gradient(180deg, rgba(4, 29, 73, .92), rgba(2, 12, 34, .98));
|
||||
box-shadow:
|
||||
inset 0 0 24px rgba(0, 123, 255, .22),
|
||||
0 0 9px rgba(0, 210, 255, .42);
|
||||
}
|
||||
|
||||
.panel::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background:
|
||||
linear-gradient(90deg, #21e1ff 0 18px, transparent 18px) left top / 76px 1px no-repeat,
|
||||
linear-gradient(180deg, #21e1ff 0 18px, transparent 18px) left top / 1px 76px no-repeat,
|
||||
linear-gradient(270deg, #21e1ff 0 18px, transparent 18px) right top / 76px 1px no-repeat,
|
||||
linear-gradient(180deg, #21e1ff 0 18px, transparent 18px) right top / 1px 76px no-repeat,
|
||||
linear-gradient(90deg, #21e1ff 0 18px, transparent 18px) left bottom / 76px 1px no-repeat,
|
||||
linear-gradient(0deg, #21e1ff 0 18px, transparent 18px) left bottom / 1px 76px no-repeat,
|
||||
linear-gradient(270deg, #21e1ff 0 18px, transparent 18px) right bottom / 76px 1px no-repeat,
|
||||
linear-gradient(0deg, #21e1ff 0 18px, transparent 18px) right bottom / 1px 76px no-repeat;
|
||||
filter: drop-shadow(0 0 6px rgba(0, 226, 255, .72));
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
top: 10px;
|
||||
height: 128px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 38px;
|
||||
}
|
||||
|
||||
.wip-card {
|
||||
left: 14px;
|
||||
width: 466px;
|
||||
}
|
||||
|
||||
.urgent-card {
|
||||
left: 496px;
|
||||
width: 424px;
|
||||
}
|
||||
|
||||
.key-card {
|
||||
left: 934px;
|
||||
width: 404px;
|
||||
}
|
||||
|
||||
.absence-card {
|
||||
left: 1352px;
|
||||
width: 554px;
|
||||
padding-right: 28px;
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
width: 79px;
|
||||
height: 79px;
|
||||
margin-right: 34px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.summary-content {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.summary-title {
|
||||
margin-bottom: 8px;
|
||||
color: #e8f1ff;
|
||||
font-size: 20px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
margin-bottom: 2px;
|
||||
color: #b9c8df;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.summary-number {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.summary-number strong {
|
||||
font-size: 50px;
|
||||
line-height: .9;
|
||||
font-weight: 900;
|
||||
letter-spacing: 6px;
|
||||
text-shadow: 0 0 13px currentColor;
|
||||
}
|
||||
|
||||
.summary-number span {
|
||||
padding-bottom: 3px;
|
||||
color: #d8e4f8;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.green-text {
|
||||
color: #28d961;
|
||||
}
|
||||
|
||||
.blue-text {
|
||||
color: #09a8ff;
|
||||
}
|
||||
|
||||
.purple-text {
|
||||
color: #7459ef;
|
||||
}
|
||||
|
||||
.orange-text {
|
||||
color: #ff951c;
|
||||
}
|
||||
|
||||
.absence-list {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 32px;
|
||||
padding-left: 24px;
|
||||
color: #f1f5ff;
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
line-height: 27px;
|
||||
border-left: 1px solid rgba(47, 144, 225, .32);
|
||||
}
|
||||
|
||||
.absence-list div {
|
||||
display: grid;
|
||||
grid-template-columns: 66px 1fr;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #f4f8ff;
|
||||
font-size: 21px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 8px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, .42);
|
||||
}
|
||||
|
||||
.panel-title::before,
|
||||
.panel-title::after {
|
||||
content: "";
|
||||
width: 50px;
|
||||
height: 1px;
|
||||
margin: 0 12px;
|
||||
background: linear-gradient(90deg, transparent, rgba(34, 166, 255, .5));
|
||||
}
|
||||
|
||||
.panel-title::after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.work-detail-panel {
|
||||
left: 14px;
|
||||
top: 149px;
|
||||
width: 938px;
|
||||
height: 818px;
|
||||
}
|
||||
|
||||
.urgent-list-panel {
|
||||
left: 968px;
|
||||
top: 149px;
|
||||
width: 938px;
|
||||
height: 270px;
|
||||
}
|
||||
|
||||
.process-task-panel {
|
||||
left: 968px;
|
||||
top: 431px;
|
||||
width: 938px;
|
||||
height: 270px;
|
||||
}
|
||||
|
||||
.start-task-panel {
|
||||
left: 968px;
|
||||
top: 713px;
|
||||
width: 938px;
|
||||
height: 254px;
|
||||
}
|
||||
|
||||
.table-box {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
right: 12px;
|
||||
top: 49px;
|
||||
bottom: 14px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(0, 148, 231, .78);
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.table-box::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.datav-table :deep(.dv-scroll-board) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #c2cbe0;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.datav-table :deep(.header) {
|
||||
color: #d5e2f8;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(180deg, rgba(12, 73, 143, .96), rgba(5, 43, 97, .96)) !important;
|
||||
}
|
||||
|
||||
.datav-table :deep(.header-item),
|
||||
.datav-table :deep(.ceil) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 2px;
|
||||
border-right: 1px solid rgba(0, 164, 255, .55);
|
||||
border-bottom: 1px solid rgba(0, 164, 255, .42);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.datav-table :deep(.header-item:last-child),
|
||||
.datav-table :deep(.ceil:last-child) {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.datav-table :deep(.rows) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.datav-table :deep(.row-item) {
|
||||
color: #c2cbe0 !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
.datav-table :deep(.row-item .ceil) {
|
||||
color: #c2cbe0 !important;
|
||||
font-weight: 400 !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.datav-table :deep(.header .header-item) {
|
||||
color: #d5e2f8 !important;
|
||||
font-weight: 800 !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.main-task-table :deep(.row-item) {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.datav-table :deep(.progress-cell) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.datav-table :deep(.progress-track) {
|
||||
position: relative;
|
||||
width: 78px;
|
||||
height: 16px;
|
||||
border: 1px solid rgba(73, 160, 232, .76);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
background: rgba(14, 41, 67, .92);
|
||||
box-shadow: inset 0 0 9px rgba(16, 130, 255, .25);
|
||||
}
|
||||
|
||||
.datav-table :deep(.progress-fill) {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(90deg, #314dff 0%, #126dff 55%, #22e6ff 100%);
|
||||
box-shadow: 0 0 10px rgba(23, 150, 255, .75);
|
||||
}
|
||||
|
||||
.datav-table :deep(.progress-cell strong) {
|
||||
min-width: 46px;
|
||||
color: #62c6ec;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||