This commit is contained in:
caoqianming 2026-07-14 09:10:46 +08:00
commit 02f3d3e3dd
38 changed files with 3256 additions and 1056 deletions

View File

@ -21,8 +21,11 @@ VUE_APP_PJ = 'gx'
# VUE_APP_BASEURL = http://10.50.211.228:2250/
VUE_APP_API_BASEURL = http://127.0.0.1:2226/api
VUE_APP_BASEURL = http://127.0.0.1:2226
# VUE_APP_API_BASEURL = http://127.0.0.1:2226/api
# VUE_APP_BASEURL = http://127.0.0.1:2226
VUE_APP_API_BASEURL = http://10.0.11.51:2250/api
VUE_APP_BASEURL = http://10.0.11.51:2250
# 托克逊
# VUE_APP_API_BASEURL = http://10.50.211.228:2250/api

5
.gitignore vendored
View File

@ -7,6 +7,8 @@ node_modules
/public/glb/
/dist
.VSCodeCounter/
.claude/
.codex/
# local env files
.env.local
@ -14,6 +16,7 @@ node_modules
.env.production
.env.development
# Log files
npm-debug.log*
yarn-debug.log*
@ -28,5 +31,7 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
*.bat
/package-lock.json
/vue.config.js

View File

@ -101,6 +101,14 @@ export default {
`${config.API_URL}/cm/labeltemplate/${id}/send_to_coder/`,
data);
}
},
sendToHanslaser:{
name: "下发到激光",
req: async function(id, data){
return await http.post(
`${config.API_URL}/cm/labeltemplate/${id}/send_to_hanslaser/`,
data);
}
}
}
}

View File

@ -126,6 +126,14 @@ export default {
data);
}
},
get_svs_char: {
name: "获取数据识别",
req: async function(data){
return await http.get(
`${config.API_URL}/em/equipment/get_svs_char/`,
data);
}
}
},
//巡检记录
einspect: {

View File

@ -6,11 +6,24 @@ export default {
name: "列表",
req: async function(data){
return await http.post(
`${config.HOST_URL}/hfnf_api/mplogx/`,
// 同源路径,由 nginx(/factory_api/) 反向代理到统计服务 10.0.11.52:5800
`${config.HOST_URL}/factory_api/mplogx/`,
// "http://10.0.11.52:5800/mplogx/",
data
);
}
},
},
stats: {
list: {
name: "数据统计",
req: async function(params){
return await http.get(
// 同源路径,由 nginx(/factory_api/) 反向代理到统计服务 10.0.11.52:5800
`${config.HOST_URL}/factory_api/stats`,
params
);
}
},
}
}

View File

@ -127,6 +127,7 @@ const routes = [
name: "cement_data_template",
path: "/cement_data_template",
meta: {
hidden: true,
title: "数据模板",
},
component: "home/cement_data_template",
@ -3528,6 +3529,7 @@ const routes = [
path: "/statistic/task_rate",
meta: {
title: "任务进度",
hidden: true,
// icon: "el-icon-DataAnalysis",
perms: ["statistic_wpm"],
},
@ -3595,6 +3597,7 @@ const routes = [
name: "user_statistics",
meta: {
title: "绩效统计",
hidden: true,
icon: "el-icon-trend-charts",
perms: ["statistic_kpi"],
},

View File

@ -1,13 +1,39 @@
<template>
<div class="user-bar">
<div class="screen panel-item" @click="printerSetting">
<el-dropdown
class="screen panel-item"
trigger="click"
@command="handleSettingCommand"
>
<div class="setting-trigger" title="设置">
<el-icon>
<el-icon-setting color="#fff" :size="26"/>
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="printer">
<el-icon><el-icon-printer/></el-icon>
<span style="margin-left:6px">打印设置</span>
</el-dropdown-item>
<el-dropdown-item command="coder">
<el-icon><el-icon-postcard/></el-icon>
<span style="margin-left:6px">喷码设置</span>
</el-dropdown-item>
<el-dropdown-item command="ocr">
<el-icon><el-icon-view/></el-icon>
<span style="margin-left:6px">数字识别设置</span>
</el-dropdown-item>
<el-dropdown-item command="marker">
<el-icon><el-icon-edit-pen/></el-icon>
<span style="margin-left:6px">打码设置</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="screen panel-item" @click="openAddCoder" title="补喷码">
<el-icon>
<el-icon-printer :size="26"/>
</el-icon>
</div>
<div class="screen panel-item" @click="coderSetting" title="喷码设置">
<el-icon>
<el-icon-postcard :size="26"/>
<el-icon-brush :size="26"/>
</el-icon>
</div>
<scan-dialog ref="scanDialog" :type="'info'" @closed="scanClose"> </scan-dialog>
@ -134,6 +160,38 @@
<el-button type="primary" @click="saveCoder">保存</el-button>
</el-footer>
</el-dialog>
<el-dialog title="数字识别设置" v-model="setOcrVisible" width="600px">
<el-form label-width="140px">
<el-form-item label="IP">
<el-input v-model="ocr_ip" placeholder="IP"></el-input>
</el-form-item>
<el-form-item label="Port">
<el-input v-model="ocr_port" placeholder="端口号"></el-input>
</el-form-item>
<el-form-item label="unit">
<el-input v-model="ocr_unit" placeholder="位号"></el-input>
</el-form-item>
</el-form>
<el-footer>
<el-button type="primary" @click="saveOcr">保存</el-button>
</el-footer>
</el-dialog>
<el-dialog title="打码设置" v-model="setMarkerVisible" width="600px">
<el-form label-width="140px">
<el-form-item label="打码IP">
<el-input v-model="marker_ip" placeholder="打码机器分配的IP地址"></el-input>
</el-form-item>
<el-form-item label="打码端口">
<el-input v-model="marker_port" placeholder="打码机器分配的端口号"></el-input>
</el-form-item>
<el-form-item label="数字码模板名">
<el-input v-model="marker_jobname" placeholder="打码机信息模板名, 如 Barcode"></el-input>
</el-form-item>
</el-form>
<el-footer>
<el-button type="primary" @click="saveMarker">保存</el-button>
</el-footer>
</el-dialog>
<el-dialog
v-model="searchVisible"
:width="700"
@ -145,6 +203,41 @@
<search @success="searchVisible = false"></search>
</el-dialog>
<scan-detail ref="scanDetails" v-if="scanVisible" :mlogId="scanId"></scan-detail>
<!-- 补喷码弹窗 -->
<el-dialog title="补喷码" v-model="addCoderVisible" width="720px" destroy-on-close>
<div style="display:flex;gap:8px;margin-bottom:16px">
<el-input
v-model="addCoderSearch"
placeholder="输入板号搜索"
clearable
style="width:320px"
@keyup.enter="searchWpr"
/>
<el-button type="primary" :loading="addCoderSearching" @click="searchWpr">搜索</el-button>
</div>
<el-table :data="wprList" v-loading="addCoderSearching" border size="small">
<el-table-column label="板号" prop="number" min-width="120" />
<el-table-column label="物料名称" min-width="160" show-overflow-tooltip>
<template #default="scope">{{ (scope.row.material_name || '').split('|')[0] }}</template>
</el-table-column>
<el-table-column label="批次号" prop="wm_batch" min-width="130" />
<el-table-column label="操作" width="180" align="center">
<template #default="scope">
<el-button
type="success" size="small"
:loading="!!addCoderLoadingMap[scope.row.id + '_1']"
@click="addCoderSend(scope.row, 'coder_jobname', 'coder_field', '1')"
>喷数字</el-button>
<el-button
type="primary" size="small"
:loading="!!addCoderLoadingMap[scope.row.id + '_2']"
@click="addCoderSend(scope.row, 'coder_jobname2', 'coder_field2', '2')"
>喷二维码</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
</template>
<script>
@ -162,6 +255,8 @@ export default {
visible:false,
setNameVisible:false,
setCoderVisible:false,
setOcrVisible:false,
setMarkerVisible:false,
searchVisible: false,
msg: false,
msgList: {},
@ -181,7 +276,18 @@ export default {
coder_field2:'',
coder_jobname:'',
coder_jobname2:'',
ocr_ip:'192.168.1.231',
ocr_port:'80',
ocr_unit:'',
marker_ip:'',
marker_port:'',
marker_jobname:'',
scanVisible:false,
addCoderVisible: false,
addCoderSearch: '',
addCoderSearching: false,
wprList: [],
addCoderLoadingMap: {},
};
},
watch: {
@ -207,6 +313,12 @@ export default {
this.coder_field2 = localStorage.getItem("coder_field2") || "";
this.coder_jobname = localStorage.getItem("coder_jobname") || "";
this.coder_jobname2 = localStorage.getItem("coder_jobname2") || "";
this.ocr_ip = localStorage.getItem("ocr_ip") || "";
this.ocr_port = localStorage.getItem("ocr_port") || "";
this.ocr_unit = localStorage.getItem("ocr_unit") || "";
this.marker_ip = localStorage.getItem("marker_ip") || "";
this.marker_port = localStorage.getItem("marker_port") || "";
this.marker_jobname = localStorage.getItem("marker_jobname") || "";
},
methods: {
openBook() {
@ -296,6 +408,12 @@ export default {
var element = document.documentElement;
this.$TOOL.screen(element);
},
handleSettingCommand(command){
if(command === 'printer') this.printerSetting();
else if(command === 'coder') this.coderSetting();
else if(command === 'ocr') this.ocrSetting();
else if(command === 'marker') this.markerSetting();
},
printerSetting(){
this.setNameVisible=true;
},
@ -320,6 +438,28 @@ export default {
});
this.setCoderVisible=false;
},
ocrSetting(){
this.setOcrVisible=true;
},
saveOcr(){
this.$TOOL.setOcr({
"ocr_ip":this.ocr_ip,
"ocr_port":this.ocr_port,
"ocr_unit":this.ocr_unit
});
this.setOcrVisible=false;
},
markerSetting(){
this.setMarkerVisible=true;
},
saveMarker(){
this.$TOOL.setMarker({
"marker_ip":this.marker_ip,
"marker_port":this.marker_port,
"marker_jobname":this.marker_jobname
});
this.setMarkerVisible=false;
},
//
showMsg() {
this.msg = true;
@ -333,6 +473,67 @@ export default {
search() {
this.searchVisible = true;
},
openAddCoder() {
this.addCoderVisible = true;
this.addCoderSearch = '';
this.wprList = [];
},
async searchWpr() {
const kw = this.addCoderSearch.trim();
if (!kw) { this.$message.warning('请输入板号'); return; }
this.addCoderSearching = true;
try {
const res = await this.$API.wpm.wpr.list.req({ number: kw, page: 0 });
const list = Array.isArray(res) ? res : (res && res.results) || [];
this.wprList = list;
if (!list.length) this.$message.warning('未找到相关板号');
} finally {
this.addCoderSearching = false;
}
},
addCoderSend(row, coderJobNameKey, coderFieldKey, suffix) {
const that = this;
const key = row.id + '_' + suffix;
if (that.addCoderLoadingMap[key]) return;
const coder_ip = localStorage.getItem('coder_ip') || '';
if (!coder_ip) {
that.$message.error('请先在右上角"喷码设置"配置喷码IP');
return;
}
that.addCoderLoadingMap = { ...that.addCoderLoadingMap, [key]: true };
const release = () => {
const m = { ...that.addCoderLoadingMap };
delete m[key];
that.addCoderLoadingMap = m;
};
const coder_port = localStorage.getItem('coder_port') || '';
const coder_field = localStorage.getItem(coderFieldKey) || '';
const templateName = '喷码模板';
const tdata = {
number: row.number,
name: (row.material_name || '').split('|')[0],
ofrom_name: row.wm_material_ofrom_name || '',
ofrom_batch: row.wm_batch || '',
};
that.$API.cm.labeltemplate.list.req({ name: templateName, page: 0 }).then(res => {
const list = Array.isArray(res) ? res : (res && res.results) || [];
const template = list.find(t => t.name === templateName);
if (!template) {
that.$message.error(`未找到标签模板: ${templateName}`);
return Promise.reject(new Error('no_template'));
}
const body = { tdata_list: [tdata], coder_ip };
if (coder_port) body.coder_port = Number(coder_port);
if (coder_field) body.coder_field = coder_field;
const coder_jobname = localStorage.getItem(coderJobNameKey) || '';
if (coder_jobname) body.coder_jobname = coder_jobname;
return that.$API.cm.labeltemplate.sendToCoder.req(template.id, body);
}).then(() => {
that.$message.success('喷码下发成功');
}).catch(e => {
if (e && e.message !== 'no_template') that.$message.error('喷码下发失败');
}).finally(release);
},
scanClose(data){
let that = this;

View File

@ -414,8 +414,8 @@ export default {
}
this.pmenu = this.$route.meta.breadcrumb
? this.$route.meta.breadcrumb[0]
: {};
let lists = this.pmenu.children;
: { meta: {}, children: [] };
let lists = this.pmenu.children || [];
let perms = this.$TOOL.data.get("PERMISSIONS") || [];
for (var i = 0; i < lists.length; i++) {
if (lists[i].meta && lists[i].meta.perms) {

View File

@ -55,7 +55,14 @@ const _ResizeObserver = window.ResizeObserver;
window.ResizeObserver = class ResizeObserver extends _ResizeObserver {
constructor(callback) {
callback = debounce(callback, 16);
super(callback);
// 先包 try/catch 再 debouncedebounce 用 setTimeout 延迟执行,
// 必须让真正执行回调时也在 try/catch 内,否则元素卸载瞬间
// getComputedStyle 拿到非 Element 的错误会逃出 setTimeout 成为未捕获异常
const safe = (entries, observer) => {
try {
callback(entries, observer);
} catch (e) {}
};
super(debounce(safe, 16));
}
};

View File

@ -7,7 +7,21 @@ const routes = [
path: "/",
component: () => import(/* webpackChunkName: "layout" */ '@/layout'),
redirect: config.DASHBOARD_URL || getBaseDashboard(),
children: []
//固定页:通过按钮跳转、不依赖菜单(动态/静态)的页面
children: [
{
name: "hfnf_mplogx",
path: "/hfnf_mplogx",
meta: { title: "测点数据明细", hidden: true },
component: () => import('@/views/fac_cal/hfnf_mplogx'),
},
{
name: "cement_data_template",
path: "/cement_data_template",
meta: { title: "数据模板", hidden: true },
component: () => import('@/views/fac_cal/cement_data_template'),
},
]
},
{
path: "/login",

View File

@ -18,6 +18,8 @@ axios.interceptors.request.use(
let token = tool.data.get("TOKEN");
if(token){
config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + token
// 记录本次请求实际使用的 token用于 401 时判断是否已被并发刷新过
config._tokenUsed = token;
}
if(!sysConfig.REQUEST_CACHE && config.method == 'get'){
config.params = config.params || {};
@ -49,39 +51,86 @@ axios.interceptors.response.use(
});
}else{
if (error.config.url.indexOf('auth/token/refresh/') != -1) {
isRefreshing = false;
requests=[];
// 刷新接口自身 401refresh token 已失效,清除登录态并跳登录
isRefreshing = false;
requests = [];
tool.data.remove("TOKEN");
tool.data.remove("TOKEN_REFRESH");
console.warn('[auth] refresh token 失效,跳转登录页');
router.push('/login');
return
return Promise.reject(error.response);
}
const currentToken = tool.data.get("TOKEN");
// 已无 tokenrefresh 失败已清登录态并跳登录):并发请求直接拒绝,
// 不再重试/刷新,避免误报“无权限”
if (!currentToken) {
return Promise.reject(error.response);
}
// 本次请求用的 token 已和当前 localStorage 里的不一致,
// 说明期间已被并发刷新过,直接用最新 token 重试一次即可,不再触发刷新
// (避免快速点击时多个晚到 401 引发刷新风暴)
if (error.config._tokenUsed && error.config._tokenUsed !== currentToken && !error.config._retriedAfterRefresh) {
error.config._tokenUsed = currentToken;
error.config._retriedAfterRefresh = true;
return axios(error.config);
}
// 已刷新过 token 仍然 401说明不是 token 过期,而是无权限/持久 401。
// 不再刷新、不跳登录,只提示无权限,避免刷新循环把会话耗到失效。
if (error.config._retriedAfterRefresh) {
console.warn('[auth] 刷新后仍 401判定为无权限不跳登录', error.config.url);
ElNotification.warning({
title: '无权限',
message: (error.response.data && error.response.data.err_msg) || '当前账号无权限访问该资源'
});
return Promise.reject(error.response);
}
if (!isRefreshing) {
isRefreshing = true;
axios({
method: 'post',
url: sysConfig.API_URL+'/auth/token/refresh/',
headers: {
Authorization: `Bearer ${tool.data.get("TOKEN")}`,
},
data:{refresh:tool.data.get("TOKEN_REFRESH")}
}).then(res=>{
// 替换本地的token
tool.data.set("TOKEN", res.data.access);
tool.data.set("TOKEN_TIME", new Date().getTime());
error.config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + res.data.access;
isRefreshing = false;
requests.forEach(cb => cb())
//发起后将requests置空
requests=[];
return axios(error.config)
// 必须 return 刷新 Promise否则即便刷新成功原始请求也会被 reject重试结果被丢弃
return new Promise((resolve, reject) => {
axios({
method: 'post',
url: sysConfig.API_URL+'/auth/token/refresh/',
headers: {
Authorization: `Bearer ${tool.data.get("TOKEN")}`,
},
data:{refresh:tool.data.get("TOKEN_REFRESH")}
}).then(res=>{
// 替换本地的token
tool.data.set("TOKEN", res.data.access);
tool.data.set("TOKEN_TIME", new Date().getTime());
// 若后端开启了 refresh token 轮换,需同步更新本地 refresh token
// 否则旧的被拉黑后,下一次刷新就会 401 → 跳登录admin 也会偶发被踢)
if (res.data && res.data.refresh) {
tool.data.set("TOKEN_REFRESH", res.data.refresh);
}
error.config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + res.data.access;
error.config._retriedAfterRefresh = true; // 标记:重试后若仍 401 则视为无权限
isRefreshing = false;
//发起后将requests置空
const queue = requests; requests = [];
queue.forEach(cb => cb())
resolve(axios(error.config))
}).catch(err=>{
// 刷新失败:复位状态,清登录态,跳登录
isRefreshing = false;
requests = [];
tool.data.remove("TOKEN");
tool.data.remove("TOKEN_REFRESH");
console.warn('[auth] token 刷新失败,跳转登录页', err);
router.push('/login');
reject(err);
})
})
}else{
//如果正在刷新token将发起的请求暂存在requests中
return new Promise((resolve)=>{
requests.push(()=>{
error.config._retriedAfterRefresh = true;
resolve(axios(error.config));
})
})
}
}
}
} else {

View File

@ -155,6 +155,16 @@ tool.setCoder = function (val) {
localStorage.setItem('coder_jobname', val.coder_jobname || '')
localStorage.setItem('coder_jobname2', val.coder_jobname2 || '')
}
tool.setOcr = function (val) {
localStorage.setItem('ocr_ip', val.ocr_ip || '')
localStorage.setItem('ocr_port', val.ocr_port || '')
localStorage.setItem('ocr_unit', val.ocr_unit || '')
}
tool.setMarker = function (val) {
localStorage.setItem('marker_ip', val.marker_ip || '')
localStorage.setItem('marker_port', val.marker_port || '')
localStorage.setItem('marker_jobname', val.marker_jobname || '')
}
/* 复制对象 */
tool.objCopy = function (obj) {
return JSON.parse(JSON.stringify(obj));

View File

@ -0,0 +1,969 @@
<template>
<el-container class="dashboard">
<!-- Header -->
<el-header class="dash-header">
<div class="dash-header-side dash-header-left">
<span class="header-tag">PHOTON · {{ mgroupName }}</span>
<span class="header-status"><i class="led-dot"></i>实时数据</span>
</div>
<div class="dash-header-center">
<div class="dash-title">{{ mgroupName }}工段生产数据看板</div>
<div class="dash-title-deco"><span></span><i></i><span></span></div>
</div>
<div class="dash-header-side dash-header-right">
<div class="dash-day">{{ currentDay }}</div>
<div class="dash-time">{{ currentTime }}</div>
</div>
</el-header>
<el-main class="dash-main">
<!-- KPI Cards -->
<div class="kpi-row">
<div class="kpi-card kpi-c2">
<div class="kpi-meta">
<div class="kpi-label">昨日流转量</div>
<div class="kpi-sub">PROCESSED</div>
</div>
<div class="kpi-value">{{ sctj.rjgs }}</div>
<div class="kpi-bar"></div>
</div>
<div class="kpi-card kpi-c3">
<div class="kpi-meta">
<div class="kpi-label">昨日加工前不良</div>
<div class="kpi-sub">PRE-DEFECT</div>
</div>
<div class="kpi-value">{{ sctj.rjgqbls }}</div>
<div class="kpi-bar"></div>
</div>
<div class="kpi-card kpi-c4">
<div class="kpi-meta">
<div class="kpi-label">昨日合格数</div>
<div class="kpi-sub">QUALIFIED</div>
</div>
<div class="kpi-value">{{ sctj.rhgs }}</div>
<div class="kpi-bar"></div>
</div>
<div class="kpi-card kpi-c5">
<div class="kpi-meta">
<div class="kpi-label">昨日不合格数</div>
<div class="kpi-sub">REJECTED</div>
</div>
<div class="kpi-value">{{ sctj.rbhgs }}</div>
<div class="kpi-bar"></div>
</div>
<div class="kpi-card kpi-c1">
<div class="kpi-meta">
<div class="kpi-label">昨日合格率</div>
<div class="kpi-sub">DAILY QUALITY RATE</div>
</div>
<div class="kpi-value">{{ sctj.rhgl }}</div>
<div class="kpi-bar"></div>
</div>
<div class="kpi-card kpi-c1">
<div class="kpi-meta">
<div class="kpi-label">昨日生产直通率</div>
<div class="kpi-sub">DAILY QUALITY RATE</div>
</div>
<div class="kpi-value">{{ sctj.rztls }}</div>
<div class="kpi-bar"></div>
</div>
</div>
<!-- Top row: 2 panels -->
<el-row :gutter="12" type="flex" class="row-top">
<el-col :span="12" class="col-full">
<div class="panel">
<div class="panel-head">
<span class="panel-title">设备状态</span>
<div class="panel-states">
<span class="state-chip s-run"><i></i>运行<em>{{ hh.yx }}</em></span>
<span class="state-chip s-idle"><i></i>未运行<em>{{ hh.wyx }}</em></span>
<span class="state-chip s-err"><i></i>故障<em>{{ hh.gz }}</em></span>
</div>
</div>
<div class="panel-body" id="scrollContainer">
<dv-scroll-board :config="configDataEq" class="board" />
</div>
<i class="corner tl"></i><i class="corner tr"></i>
<i class="corner bl"></i><i class="corner br"></i>
</div>
</el-col>
<el-col :span="4" class="col-full">
<div class="panel">
<div class="panel-head">
<span class="panel-title">工序余料</span>
</div>
<div class="panel-body" ref="processBox">
<dv-scroll-board :config="configDataProcess" class="board" />
</div>
<i class="corner tl"></i><i class="corner tr"></i>
<i class="corner bl"></i><i class="corner br"></i>
</div>
</el-col>
<el-col :span="8" class="col-full">
<div class="panel">
<div class="panel-head">
<span class="panel-title">昨日损耗分析</span>
</div>
<div class="panel-body chart-body" id="chart2"></div>
<i class="corner tl"></i><i class="corner tr"></i>
<i class="corner bl"></i><i class="corner br"></i>
</div>
</el-col>
</el-row>
<!-- Bottom row: 2 panels -->
<el-row :gutter="12" type="flex" class="row-bottom">
<el-col :span="12" class="col-full">
<div class="panel">
<div class="panel-head">
<span class="panel-title">生产统计</span>
</div>
<div class="panel-body">
<dv-scroll-board :config="configDatas" class="board" />
</div>
<i class="corner tl"></i><i class="corner tr"></i>
<i class="corner bl"></i><i class="corner br"></i>
</div>
</el-col>
<el-col :span="12" class="col-full">
<div class="panel">
<div class="panel-head">
<span class="panel-title">车间库存</span>
</div>
<div class="panel-body">
<dv-scroll-board :config="configDataInm" class="board" />
</div>
<i class="corner tl"></i><i class="corner tr"></i>
<i class="corner bl"></i><i class="corner br"></i>
</div>
</el-col>
</el-row>
</el-main>
</el-container>
</template>
<script>
import * as echarts from "echarts";
import scScrollTavle from "@/components/scScrollTable.vue";
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
export default {
components: { scScrollTavle },
data() {
return {
pieOption: {
backgroundColor: "",
tooltip: { trigger: 'item' },
legend: {
icon: "stack",
right: 10,
orient: 'vertical',
itemWidth: 10,
itemHeight: 10,
textStyle: { color: '#c8f2ff', fontSize: 11 },
},
series: {
name: '不合格占比',
type: 'pie',
radius: ['35%', '65%'],
center: ['38%', '52%'],
itemStyle: {
borderColor: 'rgba(3, 22, 26, 0.8)',
borderWidth: 2,
},
label: { show: false },
labelLine: { show: false },
data: []
}
},
tableHeight: 100,
speed: 2000,
time: null,
hh: {
yx: 0,
wyx: 0,
gz: 0,
},
sctj: {
rjgs: 0,
rjgqbls: 0,
rhgs: 0,
rbhgs: 0,
rhgl: 0,
rztls: 0,
rlzls: 0,
},
dayInterval: null,
chartInterval2: null,
//
configDataInm: {
header: ['物料名称', '批次号', '数量', '生产中'],
headerBGC: 'rgba(0, 229, 255, 0.16)',
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
headerHeight: 38,
rowNum: 8,
align: 'center',
data: [],
waitTime: 1500,
},
configDataProcess: {
headerBGC: 'rgba(0, 229, 255, 0.16)',
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
header: ['物料名', '数量(个)'],
headerHeight: 38,
rowNum: 8,
align: 'center',
columnWidth: [],
data: []
},
//
configDataEq: {
headerBGC: 'rgba(0, 229, 255, 0.16)',
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
header: ['设备名称', '设备编号', '设备状态', '日加工量', '累计加工量'],
headerHeight: 38,
rowNum: 8,
align: 'center',
data: []
},
//
configDatas: {
headerBGC: 'rgba(0, 229, 255, 0.16)',
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
header: ['日期', '物料名', '接收数', '合格数', '不合格数', '交送数'],
headerHeight: 38,
rowNum: 7,
align: 'center',
data: []
},
page: 1,
currentTime: "",
currentDay: "",
mgroupName: "",
mgroupId: "",
today: "",
end_time: '',
start_time: '',
daysList: [],
};
},
mounted() {
let that = this;
let arr = this.$route.path.split("/");
that.mgroup_code = arr[2];
that.page = 1;
that.getMgroups(this.mgroup_code);
that.configDataInm.data = [];
//table
this.tableHeight = document.getElementById("scrollContainer").clientHeight;
this.$nextTick(() => {
const box = this.$refs.processBox;
if (box) {
const w = box.clientWidth - 16;
this.configDataProcess.columnWidth = [Math.max(50, w - 100), 100];
}
});
this.showTime();
this.dayInterval = setInterval(() => {
this.showTime();
}, 1000);
//
let daysArr = this.getMondayOfCurrentWeek();
this.daysArr = daysArr;
let xAxisData = [];
daysArr.forEach((item) => {
let dates = item.split('-');
let obj = dates[1] + '-' + dates[2];
xAxisData.push(obj);
let dayitem = Number(dates[2]);
that.daysList.push(dayitem);
})
that.today = new Date().toISOString().split('T')[0];
that.yesterday =that.$TOOL.dateFormat2(new Date().getTime() - 24 * 60 * 60 * 1000);;
this.xAxisData = xAxisData;
let startDate = new Date(daysArr[0]).getTime() - (1000 * 60 * 60 * 24);
let endDate = new Date(daysArr[6]).getTime() + (1000 * 60 * 60 * 24);
let start_time = this.$TOOL.dateFormat(new Date(startDate), "yyyy-MM-dd");
let end_time = this.$TOOL.dateFormat(new Date(endDate), "yyyy-MM-dd");
this.start_time = start_time;
this.end_time = end_time;
},
beforeDestroy() {
if (this.dayInterval) clearInterval(this.dayInterval);
if (this.chartInterval2) clearInterval(this.chartInterval2);
},
methods: {
getMgroups(code){
let that = this;
that.$API.mtm.mgroup.list.req({page:0,code}).then((res) => {
that.mgroupName = res[0].name;
that.mgroupId = res[0].id;
this.$nextTick(() => {
that.getEqState(that.mgroupId);
this.getMaterials(that.page);
this.getProductLine();
this.getCountnotok();
this.getProcessLeft();
})
});
},
getMondayOfCurrentWeek() {
let today = new Date();
let days = [];
for (let i = 6; i >= 0; i--) {
let date = new Date(today);
date.setDate(today.getDate() - i);
days.push(date.toISOString().split('T')[0]);
}
return days;
},
//
showTime() {
this.currentTime = this.$TOOL.dateFormat(new Date(), "hh:mm:ss");
this.currentDay = this.$TOOL.dateFormat(
new Date(),
"yyyy年MM月dd日"
);
},
setChart(name, option = null) {
let dom = document.getElementById(name);
if (!dom) return null;
var myChart = echarts.getInstanceByDom(dom);
if (myChart == undefined) {
myChart = echarts.init(dom, "dark", {
renderer: "svg",
});
}
if (option == null) {
option = Object.assign({}, this.barOption);
}
setTimeout(() => {
try {
myChart.setOption(option);
} catch (error) { }
}, 500);
return myChart;
},
getProcessLeft() {
let that = this;
let obj = {
query: { mgroup_name: that.mgroupName },
};
that.$API.bi.dataset.exec.req("mgroup_yuliao", obj).then((res) => {
let list = res.data2.ds0;
if (list.length > 0) {
list.forEach((item) => {
if(item.状态=='合格'&&(item.物料名.indexOf('QS')>-1||item.物料名.indexOf('32.2')>-1||item.物料名.indexOf('3D')>-1||item.物料名.indexOf('2.5D')>-1)){
let arr = [];
arr[0] = item.物料名+'('+item.状态+')';
arr[1] = item.数量;
that.configDataProcess.data.push(arr);
}
})
}
})
},
//
getProductLine() {
let that = this;
let obj = {
query: { start_date: that.start_time, end_date: that.end_time, mgroup_name: that.mgroupName },
};
that.$API.bi.dataset.exec.req("lineDay", obj).then((res) => {
let list = res.data2.ds0;
if (list.length > 0) {
list.forEach((item) => {
let dateYes = that.yesterday.split('-')[2];
if (item. == dateYes) {
that.sctj.rjgs += item.生产数;
that.sctj.rjgqbls += item.加工前不良;
that.sctj.rhgs += item.合格数;
that.sctj.rbhgs += item.不合格数;
}
let arr = [];
arr[0] = item. + '-' + item. + '-' + item.;
arr[1] = item.物料名;
arr[2] = item.接收数;
arr[3] = item.生产数;
arr[4] = item.合格数;
arr[5] = item.交送数;
that.configDatas.data.push(arr);
});
that.sctj.rhgl = Number((that.sctj.rhgs / that.sctj.rjgs * 100).toFixed(2));
let total = that.sctj.rjgs+that.sctj.rjgqbls;
that.sctj.rztls = Number((that.sctj.rhgs / total * 100).toFixed(2));
}
});
},
//
getCountnotok() {
let that = this;
let obj = {
query: { start_date: that.yesterday, end_date: that.yesterday,mgroup_name:that.mgroupName }
};
that.$API.bi.dataset.exec.req('notok_dis', obj).then((res) => {
let seriesData = [];
if (res.data2.ds0) {
res.data2.ds0.forEach((item) => {
let obj = {};
obj.name = item.不合格项;
obj.value = item.数量;
seriesData.push(obj);
})
}
that.pieOption.series.data = seriesData;
let index2 = 0;
let chart2 = this.setChart("chart2", that.pieOption);
if (!chart2) return;
this.chartInterval2 = setInterval(function () {
if (index2 < seriesData.length) {
chart2.dispatchAction({ type: "downplay", seriesIndex: 0 });
chart2.dispatchAction({ type: "highlight", seriesIndex: 0, dataIndex: index2 });
chart2.dispatchAction({ type: "showTip", seriesIndex: 0, dataIndex: index2 });
index2++;
} else {
index2 = 0;
}
}, 3000);
})
},
//
getEqState() {
let that = this;
let obj = {
query: { query_date: that.today, mgroup_name: that.mgroupName },
};
that.$API.wpm.ana.equipLastMlog.req({ mgroup: that.mgroupId }).then((res) => {
that.hh.yx = res.运行;
that.hh.wyx = res.未运行;
that.hh.gz = res.故障;
});
that.$API.bi.dataset.exec.req("equit_static", obj).then((res) => {
let list = res.data2.ds0;
if (list.length > 0) {
list.forEach((item) => {
let arr = [];
arr[0] = item.设备名称;
arr[1] = item.设备编号;
if (item.运行状态 == '运行') {
arr[2] = '<span style="color:#00e5ff">● 运行</span>';
} else if (item.运行状态 == '待机') {
arr[2] = '<span style="color:#45b076">● 待机</span>';
} else if (item.运行状态 == '停机') {
arr[2] = '<span style="color:#de3c36">● 停机</span>';
}else if (item.运行状态 == '故障') {
arr[2] = '<span style="color:#de3c36">● 故障</span>';
}else if (item.运行状态 == '离线') {
arr[2] = '<span style="color:#de3c36">● 离线</span>';
}
arr[3] = item.当日加工量 ? item.当日加工量 : 0;
arr[4] = item.累计总加工量 ? item.累计总加工量 : 0;
that.configDataEq.data.push(arr);
});
}
})
},
//
getMaterials(page) {
let that = this;
let query = '{ material_name, batch, count, count_working }';
that.$API.wpm.wmaterial.list.req({ page: page, page_size: 100, mgroup: that.mgroupId, query: query }).then((res) => {
if (res.results.length > 0) {
res.results.forEach((item) => {
let arr = [];
arr[0] = item.material_name;
arr[1] = item.batch;
arr[2] = item.count;
arr[3] = item.count_working;
that.configDataInm.data.push(arr);
})
if(that.configDataInm.data.length<res.count){
that.getMaterials(page+1);
}
}
})
},
},
};
</script>
<style scoped>
@font-face {
font-family: "myfont";
src: url("../../../utils/youShe.ttf");
}
.dashboard,
.dashboard * {
box-sizing: border-box;
}
.dashboard {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
background: #00181c url("/public/img/photon_bg.png") center / cover no-repeat;
color: #fff;
font-family: "Microsoft Yahei" !important;
}
.dashboard::before {
content: "";
position: absolute;
inset: 0;
background:
radial-gradient(ellipse at 20% 0%, rgba(0, 229, 255, 0.10), transparent 55%),
radial-gradient(ellipse at 80% 100%, rgba(0, 122, 153, 0.18), transparent 55%);
pointer-events: none;
z-index: 0;
}
/* ============= Header ============= */
.dash-header {
position: relative;
z-index: 1;
flex: 0 0 72px !important;
height: 72px !important;
padding: 0 24px !important;
display: flex;
align-items: center;
justify-content: space-between;
background: url("/public/img/photon_header.png") center / 100% 100% no-repeat;
}
.dash-header-side {
flex: 0 0 280px;
display: flex;
align-items: center;
gap: 14px;
}
.dash-header-right {
justify-content: flex-end;
}
.dash-header-center {
flex: 1;
text-align: center;
}
.dash-title {
font-family: "myfont", "Microsoft Yahei";
font-size: 30px;
font-weight: bold;
letter-spacing: 8px;
background: linear-gradient(180deg, #ffffff 0%, #b9fbff 55%, #00d4ff 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 22px rgba(0, 212, 255, 0.45);
line-height: 1;
}
.dash-title-deco {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-top: 6px;
}
.dash-title-deco span {
display: inline-block;
width: 90px;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(0, 229, 255, 0.7), transparent);
}
.dash-title-deco i {
display: inline-block;
width: 6px;
height: 6px;
background: #00e5ff;
transform: rotate(45deg);
box-shadow: 0 0 8px #00e5ff;
}
.header-tag {
font-size: 12px;
letter-spacing: 2px;
padding: 4px 10px;
border: 1px solid rgba(0, 229, 255, 0.45);
color: #95ffff;
background: rgba(0, 229, 255, 0.06);
font-weight: bold;
}
.header-status {
font-size: 13px;
color: #95ffff;
display: flex;
align-items: center;
gap: 6px;
}
.led-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #18f1a4;
box-shadow: 0 0 8px #18f1a4;
animation: led-pulse 1.4s ease-in-out infinite;
}
@keyframes led-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.35;
}
}
.dash-day {
font-size: 14px;
color: #c8f2ff;
letter-spacing: 1px;
}
.dash-time {
font-family: "myfont", "Microsoft Yahei";
font-size: 22px;
color: #fff;
letter-spacing: 3px;
text-shadow: 0 0 12px rgba(0, 229, 255, 0.55);
}
/* ============= Main ============= */
.dash-main {
position: relative;
z-index: 1;
flex: 1 1 0 !important;
min-height: 0;
padding: 10px !important;
display: flex;
flex-direction: column;
gap: 10px;
overflow: hidden;
}
/* ============= KPI Strip ============= */
.kpi-row {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
flex: 0 0 92px;
min-height: 0;
}
.kpi-card {
position: relative;
padding: 10px 16px;
background: linear-gradient(135deg, rgba(0, 60, 80, 0.55) 0%, rgba(3, 22, 26, 0.7) 100%);
border: 1px solid rgba(0, 229, 255, 0.22);
display: flex;
align-items: center;
justify-content: space-between;
overflow: hidden;
}
.kpi-card::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at 100% 0%, rgba(0, 229, 255, 0.16), transparent 60%);
pointer-events: none;
}
.kpi-card::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 100%;
background: #00e5ff;
box-shadow: 0 0 10px #00e5ff;
}
.kpi-meta {
z-index: 1;
}
.kpi-label {
font-size: 15px;
letter-spacing: 2px;
color: #d8f6ff;
font-weight: 500;
}
.kpi-sub {
font-size: 10px;
letter-spacing: 2px;
color: rgba(149, 255, 255, 0.45);
margin-top: 4px;
}
.kpi-value {
font-family: "myfont", "Microsoft Yahei";
font-size: 34px;
font-weight: bold;
letter-spacing: 1px;
z-index: 1;
line-height: 1;
}
.kpi-bar {
position: absolute;
left: 0;
bottom: 0;
height: 2px;
width: 100%;
}
.kpi-c1 .kpi-value {
color: #95ffff;
text-shadow: 0 0 14px rgba(0, 229, 255, 0.55);
}
.kpi-c1::after {
background: #00e5ff;
box-shadow: 0 0 10px #00e5ff;
}
.kpi-c1 .kpi-bar {
background: linear-gradient(90deg, #00e5ff, transparent);
}
.kpi-c2 .kpi-value {
color: #c5ff7a;
text-shadow: 0 0 14px rgba(170, 255, 102, 0.55);
}
.kpi-c2::after {
background: #aaff66;
box-shadow: 0 0 10px #aaff66;
}
.kpi-c2 .kpi-bar {
background: linear-gradient(90deg, #aaff66, transparent);
}
.kpi-c3 .kpi-value {
color: #ffd87a;
text-shadow: 0 0 14px rgba(255, 200, 80, 0.55);
}
.kpi-c3::after {
background: #ffb74d;
box-shadow: 0 0 10px #ffb74d;
}
.kpi-c3 .kpi-bar {
background: linear-gradient(90deg, #ffb74d, transparent);
}
.kpi-c4 .kpi-value {
color: #7af0a8;
text-shadow: 0 0 14px rgba(45, 210, 140, 0.55);
}
.kpi-c4::after {
background: #2dd28c;
box-shadow: 0 0 10px #2dd28c;
}
.kpi-c4 .kpi-bar {
background: linear-gradient(90deg, #2dd28c, transparent);
}
.kpi-c5 .kpi-value {
color: #ff8a8a;
text-shadow: 0 0 14px rgba(255, 107, 107, 0.55);
}
.kpi-c5::after {
background: #ff6b6b;
box-shadow: 0 0 10px #ff6b6b;
}
.kpi-c5 .kpi-bar {
background: linear-gradient(90deg, #ff6b6b, transparent);
}
/* ============= Content Rows ============= */
.row-top,
.row-bottom {
display: flex;
min-height: 0;
margin: 0 !important;
}
.row-top {
flex: 1.15 1 0;
}
.row-bottom {
flex: 1 1 0;
}
.col-full {
height: 100%;
display: flex;
flex-direction: column;
}
/* ============= Panel ============= */
.panel {
position: relative;
height: 100%;
background: linear-gradient(180deg, rgba(10, 63, 68, 0.45) 0%, rgba(3, 22, 26, 0.65) 100%);
border: 1px solid rgba(0, 229, 255, 0.18);
display: flex;
flex-direction: column;
overflow: hidden;
}
.panel-head {
position: relative;
height: 36px;
flex: 0 0 36px;
padding: 0 12px;
display: flex;
align-items: center;
gap: 12px;
background: linear-gradient(90deg, rgba(0, 229, 255, 0.16) 0%, rgba(0, 229, 255, 0.02) 60%, rgba(0, 229, 255, 0.08) 100%);
border-bottom: 1px solid rgba(0, 229, 255, 0.18);
}
.panel-head::before {
content: "";
width: 4px;
height: 16px;
background: linear-gradient(180deg, #00e5ff, #007a99);
box-shadow: 0 0 6px rgba(0, 229, 255, 0.6);
}
.panel-title {
font-size: 16px;
font-weight: 600;
color: #fff;
letter-spacing: 2px;
}
.panel-sub {
font-size: 11px;
letter-spacing: 2px;
color: rgba(149, 255, 255, 0.5);
font-weight: 300;
}
.panel-states {
margin-left: auto;
display: flex;
gap: 6px;
}
.state-chip {
font-size: 12px;
padding: 2px 8px;
display: flex;
align-items: center;
gap: 5px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
color: #d8f6ff;
}
.state-chip i {
width: 7px;
height: 7px;
border-radius: 50%;
display: inline-block;
}
.state-chip em {
font-style: normal;
font-weight: bold;
color: #fff;
margin-left: 3px;
}
.s-run i {
background: #00a3f5;
box-shadow: 0 0 6px #00a3f5;
}
.s-idle i {
background: #45b076;
box-shadow: 0 0 6px #45b076;
}
.s-err i {
background: #de3c36;
box-shadow: 0 0 6px #de3c36;
}
.panel-body {
flex: 1 1 0;
min-height: 0;
padding: 8px;
position: relative;
overflow: hidden;
}
.chart-body {
padding: 4px;
}
.board {
width: 100%;
height: 100%;
}
/* ============= Corner brackets ============= */
.corner {
position: absolute;
width: 12px;
height: 12px;
border-color: #00e5ff;
border-style: solid;
pointer-events: none;
z-index: 2;
}
.corner.tl {
top: -1px;
left: -1px;
border-width: 2px 0 0 2px;
}
.corner.tr {
top: -1px;
right: -1px;
border-width: 2px 2px 0 0;
}
.corner.bl {
bottom: -1px;
left: -1px;
border-width: 0 0 2px 2px;
}
.corner.br {
bottom: -1px;
right: -1px;
border-width: 0 2px 2px 0;
}
</style>

View File

@ -132,7 +132,7 @@
id="dashbordProcess"
>
<span class="percentage-value" style="font-size: 16px"
>{{ dialogData.percentage }}%</span
>{{ dialogData.percentage }}</span
>
</el-progress>
<span>完成进度</span>
@ -216,7 +216,7 @@
id="dashbordProcess"
>
<span class="percentage-value" style="font-size: 16px"
>{{ currentData.percentage }}%</span
>{{ currentData.percentage }}</span
>
</el-progress>
<p style="text-align: center">完成进度</p>
@ -444,29 +444,40 @@ export default {
yesterday: "",
dept6Obj: {
deptName: "光学精密加工车间",
percentage: 100,
percentage: "100%",
count_bang: 0,
count_guan: 0,
},
dept7Obj: {
deptName: "光纤预制棒生产车间",
percentage: 100,
percentage: "100%",
count_bang: 0,
},
dept8Obj: {
deptName: "玻璃配合料制备车间",
percentage: 100,
percentage: "100%",
count: 0,
},
dept10Obj: {
deptName: "光纤预制管生产车间",
percentage: 100,
percentage: "100%",
count_guan: 0,
},
isUnmounted: false,
pieChart: null,
line1Chart: null,
line2Chart: null,
line3Chart: null,
bar1Chart: null,
onResize: null,
onCanvasMouseMove: null,
onCanvasClick: null,
canvasEl: null,
};
},
mounted() {
loadBabylon().then(() => {
if (this.isUnmounted) return;
this.initView();
})
},
@ -536,27 +547,22 @@ export default {
that.showTime();
}, 1000);
that.notokTimer = setInterval(() => {
if (that.isUnmounted) return;
let pieDom = document.getElementById("pie");
if (pieDom) {
if (that.deptName == "10车间") {
that.deptName = "7车间";
} else {
that.deptName = "10车间";
}
let deptData = [];
if (that.deptName == "7车间") {
deptData = that.dept7Data;
} else {
deptData = that.dept10Data;
}
that.pieoption.series.data = deptData;
let pieoption = that.pieoption;
let pieChart = echarts.init(pieDom);
pieChart.clear();
pieChart.setOption(pieoption, true);
if (!pieDom) return;
if (that.deptName == "10车间") {
that.deptName = "7车间";
} else {
that.deptName = "10车间";
}
}, 5000);
let deptData =
that.deptName == "7车间" ? that.dept7Data : that.dept10Data;
that.pieoption.series.data = deptData;
if (!that.pieChart || that.pieChart.isDisposed()) {
that.pieChart = echarts.init(pieDom);
}
that.pieChart.setOption(that.pieoption, true);
}, 60000);
that.timerData = setInterval(() => {
that.getDeptDetail();
}, 60000);
@ -592,8 +598,12 @@ export default {
that.getCountDept7();
//1---
let chartDom = document.getElementById("line1");
if (!chartDom) return;
chartDom.style.height = this.blockHeight;
let myChart = echarts.init(chartDom);
if (!that.line1Chart || that.line1Chart.isDisposed()) {
that.line1Chart = echarts.init(chartDom);
}
let myChart = that.line1Chart;
let option = {
tooltip: {
trigger: "axis",
@ -862,8 +872,12 @@ export default {
}
//线
let line3Dom = document.getElementById("line3");
if (!line3Dom) return;
line3Dom.style.height = this.blockHeight;
let line3Chart = echarts.init(line3Dom);
if (!that.line3Chart || that.line3Chart.isDisposed()) {
that.line3Chart = echarts.init(line3Dom);
}
let line3Chart = that.line3Chart;
let line3option = {
tooltip: {
trigger: "axis",
@ -980,12 +994,19 @@ export default {
that.$API.bi.dataset.exec.req("materialCount", obj).then((res) => {
let data = [];
let list = res.data2.ds0;
let names = [];
if (list.length > 0) {
list.forEach((item) => {
let arr = [];
arr[0] = item.material_name ;
arr[1] = item.count;
data.push(arr);
let indexes = names.indexOf(item.material_name);
if(indexes === -1){
names.push(item.material_name);
let arr = [];
arr[0] = item.material_name ;
arr[1] = item.count;
data.push(arr);
}else{
data[indexes][1] = data[indexes][1] + item.count;
}
});
}
that.taskBoard.data = data;
@ -1217,7 +1238,7 @@ export default {
//
const hl1 = new BABYLON.HighlightLayer("hl1", scene);
const hl1Click = new BABYLON.HighlightLayer("hl1Click", scene);
canvas.addEventListener("mousemove", (event) => {
that.onCanvasMouseMove = (event) => {
// 使 scene.pick
const pickResult = scene.pick(
scene.pointerX,
@ -1292,8 +1313,9 @@ export default {
} else {
that.infoVisibel = false;
}
});
canvas.addEventListener("click", (event) => {
};
canvas.addEventListener("mousemove", that.onCanvasMouseMove);
that.onCanvasClick = (event) => {
// 使 scene.pick
const pickResult = scene.pick(
scene.pointerX,
@ -1364,7 +1386,8 @@ export default {
}
}
}
});
};
canvas.addEventListener("click", that.onCanvasClick);
return scene;
};
const scene = createScene(); //Call the createScene function
@ -1374,9 +1397,9 @@ export default {
});
this.engine = engine;
this.scene = scene;
window.addEventListener("resize", function () {
engine.resize();
});
this.canvasEl = canvas;
this.onResize = () => engine.resize();
window.addEventListener("resize", this.onResize);
},
getDeptData(name) {
this.infoVisibel = true;
@ -1505,8 +1528,12 @@ export default {
let that = this;
//2
let bar1 = document.getElementById("bar1");
if (!bar1) return;
bar1.style.height = this.blockHeight;
let bar1Chart = echarts.init(bar1);
if (!that.bar1Chart || that.bar1Chart.isDisposed()) {
that.bar1Chart = echarts.init(bar1);
}
let bar1Chart = that.bar1Chart;
let bar1option = {
tooltip: {
trigger: "axis",
@ -1655,8 +1682,12 @@ export default {
bar1Chart.setOption(bar1option);
//3
let line2Dom = document.getElementById("line2");
if (!line2Dom) return;
line2Dom.style.height = this.blockHeight;
let line2Chart = echarts.init(line2Dom);
if (!that.line2Chart || that.line2Chart.isDisposed()) {
that.line2Chart = echarts.init(line2Dom);
}
let line2Chart = that.line2Chart;
let line2option = {
tooltip: {
trigger: "axis",
@ -1845,8 +1876,12 @@ export default {
line2Chart.setOption(line2option);
//
let pieDom = document.getElementById("pie");
if (!pieDom) return;
pieDom.style.height = this.blockHeight;
let pieChart = echarts.init(pieDom);
if (!that.pieChart || that.pieChart.isDisposed()) {
that.pieChart = echarts.init(pieDom);
}
let pieChart = that.pieChart;
let pieoption = {
color: [
"rgb(237,224,45)",
@ -1914,22 +1949,53 @@ export default {
},
},
beforeUnmount() {
let that = this;
clearInterval(that.timerTime);
clearInterval(that.timerData);
clearInterval(that.notokTimer);
that.timerTime = null;
that.timerData = null;
that.notokTimer = null;
},
beforeDestoryed() {
let that = this;
clearInterval(that.timerTime);
clearInterval(that.timerData);
clearInterval(that.notokTimer);
that.timerTime = null;
that.timerData = null;
that.notokTimer = null;
this.isUnmounted = true;
//
clearInterval(this.timerTime);
clearInterval(this.timerData);
clearInterval(this.notokTimer);
clearInterval(this.heightTimer);
this.timerTime = null;
this.timerData = null;
this.notokTimer = null;
this.heightTimer = null;
// echarts
[
this.pieChart,
this.line1Chart,
this.line2Chart,
this.line3Chart,
this.bar1Chart,
].forEach((c) => {
if (c && !c.isDisposed()) c.dispose();
});
this.pieChart = this.line1Chart = this.line2Chart = this.line3Chart = this.bar1Chart = null;
//
if (this.onResize) {
window.removeEventListener("resize", this.onResize);
this.onResize = null;
}
if (this.canvasEl) {
if (this.onCanvasMouseMove) {
this.canvasEl.removeEventListener("mousemove", this.onCanvasMouseMove);
}
if (this.onCanvasClick) {
this.canvasEl.removeEventListener("click", this.onCanvasClick);
}
this.canvasEl = null;
}
this.onCanvasMouseMove = null;
this.onCanvasClick = null;
// babylon
if (this.scene) {
try { this.scene.dispose(); } catch (e) {}
this.scene = null;
}
if (this.engine) {
try { this.engine.stopRenderLoop(); } catch (e) {}
try { this.engine.dispose(); } catch (e) {}
this.engine = null;
}
},
};
</script>

View File

@ -7,8 +7,11 @@
</div>
<div class="right-panel">
<el-cascader v-model="query.belong_dept" :options="group" :props="groupsProps" clearable placeholder="所在车间"
:show-all-levels="false" @change="handleQuery">
:show-all-levels="false" @change="handleQuery" style="width:180px">
</el-cascader>
<el-select v-model="query.cate" placeholder="设备分类" clearable style="width:180px">
<el-option v-for="item in cateOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
<el-input v-model="query.search" placeholder="设备名称/编号" clearable style="width:200px"></el-input>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
@ -38,7 +41,7 @@
</template>
</el-table-column>
<el-table-column label="购置日期" prop="buy_date">
<el-table-column label="购置日期" prop="buy_date" width="90">
</el-table-column>
<el-table-column label="运行规则" prop="indicate_mgroup_running" width="100">
</el-table-column>
@ -195,6 +198,7 @@ export default {
data() {
return {
runningStateEnum,
cateOptions:[],
deptOptions: [],
dialog: {
save: false,
@ -247,9 +251,16 @@ export default {
};
},
mounted() {
this.getDept()
this.getDept();
this.getCateOptions();
},
methods: {
getCateOptions() {
let that = this;
that.$API.em.ecate.list.req({page:0,type:10}).then(res => {
that.cateOptions = res;
})
},
//
selectionChange(selection) {
this.selectiones = selection;

View File

@ -23,7 +23,7 @@
<!-- 工厂数据卡片 -->
<el-row :gutter="16" class="factory-row">
<el-col :xs="24" :sm="12" :md="6" v-for="(item, index) in factories" :key="item.name">
<div class="factory-card" :style="{ borderTopColor: item.color }" @click="goDetail">
<div class="factory-card" :style="{ borderTopColor: item.color }">
<div class="card-header">
<div class="card-icon" :style="{ backgroundColor: item.bgColor }">
<el-icon :size="24" :color="item.color"><OfficeBuilding /></el-icon>
@ -193,30 +193,32 @@ let pieChart = null
const colors = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c']
const bgColors = ['#ecf5ff', '#f0f9eb', '#fdf6ec', '#fef0f0']
//
const baseFactories = [
{ name: '合肥南方', ratio: 0.4382 },
{ name: '中联万吨', ratio: 0.3081 },
{ name: '铜梁水泥', ratio: 0.1424 },
{ name: '槐坎南方水泥', ratio: 0.1113 },
//
const factoryDefs = [
{ name: '合肥南方', match: (t) => t === 'mplogx' }, //
{ name: '中联万吨', match: (t) => t === 'mplogx_xzzl' }, //
{ name: '铜梁水泥', match: (t) => t === 'mplogx_tlxn' }, //
{ name: '槐坎南方水泥', match: (t) => t.startsWith('mplogx_hknf') }, //
]
const totalCount = ref(0)
const tables = ref([])
const factories = computed(() => {
const total = totalCount.value
// 33
const counts = baseFactories.map(f => Math.round(total * f.ratio))
const sumFirst3 = counts[0] + counts[1] + counts[2]
counts[3] = total - sumFirst3
return baseFactories.map((f, i) => ({
name: f.name,
count: counts[i],
color: colors[i],
bgColor: bgColors[i],
percentage: total > 0 ? (counts[i] / total) * 100 : 0,
}))
return factoryDefs.map((f, i) => {
//
const count = tables.value
.filter((t) => f.match(t.table_name))
.reduce((sum, t) => sum + (t.approximate_row_count || 0), 0)
return {
name: f.name,
count,
color: colors[i],
bgColor: bgColors[i],
percentage: total > 0 ? (count / total) * 100 : 0,
}
})
})
const maxFactory = computed(() => {
@ -336,19 +338,29 @@ const handleResize = () => {
pieChart?.resize()
}
// 退
const handlePopState = () => {
router.push('/cement_data_template')
}
onMounted(() => {
API.hfnf.mplogx.list.req({ page: 1, page_size: 1 }).then(res => {
totalCount.value = res.count
API.hfnf.stats.list.req().then(res => {
tables.value = res.tables || []
totalCount.value = res.summary?.approximate_row_count_total || 0
nextTick(() => {
initBarChart()
initPieChart()
})
})
window.addEventListener('resize', handleResize)
// 使退 popstate
history.pushState(null, '', location.href)
window.addEventListener('popstate', handlePopState)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
window.removeEventListener('popstate', handlePopState)
barChart?.dispose()
pieChart?.dispose()
})

View File

@ -183,7 +183,7 @@
></el-table-column>
<el-table-column
prop="dept_name"
label="完成车间"
label="所在车间"
></el-table-column>
<el-table-column
prop="count"
@ -351,7 +351,7 @@
</el-table-column>
<el-table-column
prop="dept_name"
label="完成车间"
label="所在车间"
/>
<el-table-column
prop="count"

View File

@ -90,6 +90,7 @@
v-model="selectBatch"
value-key="id"
clearable
:multiple="project_code=='gz'&&form.type == 'sale_out'"
filterable
remote = "true"
:style="divStyle"
@ -581,6 +582,13 @@ export default {
that.form.count = Number(that.selectObj.count_canmio);
that.mTracking = that.selectObj.material_.tracking;
that.selectBatchChange(that.selectObj)
}else if(that.type == "sale_out"&&that.project_code=='gz'){
that.form.material = that.selectObj.id;
that.form.unit = that.selectObj.unit;
that.form.unit_price = that.selectObj.unit_price;
that.mTracking = that.selectObj.tracking;
that.selectBatch = [];
that.getBatchOptions();
}else{
var type = this.form.type;
that.form.material = that.selectObj.id;
@ -616,6 +624,26 @@ export default {
let that = this;
that.wprList = [];
that.mioitems = [];
// gz
if(that.form.type == 'sale_out' && that.project_code == 'gz' && Array.isArray(items)){
if(items.length === 0){
that.form.batch = "";
that.form.mb = "";
that.form.count = 0;
that.batchcount = 0;
that.form.warehouse = "";
that.inputBatchDisable = false;
return;
}
let totalCount = items.reduce((sum, it) => sum + Number(it.count_canmio || 0), 0);
that.form.batch = items.map(it => it.batch).join(',');
that.form.mb = items.map(it => it.id).join(',');
that.form.count = totalCount;
that.batchcount = totalCount;
that.form.warehouse = items[0].warehouse;
that.inputBatchDisable = true;
return;
}
if(items){
if(that.form.type == 'sale_out'&&that.project_code=='bxerp'){
let count = 0;
@ -876,7 +904,21 @@ export default {
try {
let res;
if (that.mode == "add") {
res = await that.$API.inm.mioitem.create.req(that.form);
if(that.form.type == 'sale_out' && that.project_code == 'gz' && Array.isArray(that.selectBatch) && that.selectBatch.length > 0){
let payload = that.selectBatch.map(b => ({
mio: that.mioId,
material: that.form.material,
batch: b.batch,
mb: b.id,
count: Number(b.count_canmio),
warehouse: b.warehouse,
unit_price: that.form.unit_price,
note: that.form.note || ''
}));
res = await that.$API.inm.mioitem.create.req(payload);
} else {
res = await that.$API.inm.mioitem.create.req(that.form);
}
} else if (that.mode == "edit") {
res = await that.$API.inm.mioitem.update.req(that.form.id,that.form);
}

View File

@ -31,6 +31,11 @@
clearable
style="width: 200px;"
></el-input>
<el-input v-model="query.handler"
placeholder="操作人"
clearable
style="width: 200px;"
></el-input>
<el-button
type="primary"
icon="el-icon-search"
@ -110,13 +115,24 @@
<span>{{scope.row.data.分检_缺陷项_扭转角不合格?scope.row.data.分检_缺陷项_扭转角不合格:0}}</span>
</template>
</el-table-column>
<el-table-column label="开台人" align="center" class-name="colorheader7">
<el-table-column label="工装" align="center" class-name="colorheader7">
<template #default="scope">
<span>{{toolList[scope.row.pre_info.tooling]}}</span>
</template>
</el-table-column>
<el-table-column label="开台人" align="center" class-name="colorheader1">
<template #default="scope">
<span v-if="scope.row.data.喷码_一体刀_操作人">{{scope.row.data.喷码_一体刀_操作人}}</span>
<span v-if="scope.row.data.喷码_磨床开台_操作人">{{scope.row.data.喷码_磨床开台_操作人}}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" class-name="colorheader1">
<el-table-column label="开台设备" align="center" class-name="colorheader2">
<template #default="scope">
<span v-if="scope.row.data.喷码_一体刀_使用设备">{{scope.row.data.喷码_一体刀_使用设备}}</span>
<span v-if="scope.row.data.喷码_磨床开台_使用设备">{{scope.row.data.喷码_磨床开台_使用设备}}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" class-name="colorheader3">
<template #default="scope">
<span>{{ scope.row.data.分检_缺陷项_备注 }}</span>
</template>
@ -141,17 +157,30 @@ export default {
batch__contains:'',
last_time__gte:'',
last_time__lte:'',
handler:''
},
apiObj: this.$API.wpm.wpr.query,
options:[],
tableData:[],
toolList:{},
};
},
mounted() {
this.getToolings();
},
methods: {
getToolings(){
let that = this;
that.$API.em.equipment.list.req({ page: 0,type:10,cate__code:'7'}).then((res) => {
res.forEach((item) => {
that.toolList[item.id] = item.number;
});
});
},
handleQuery(){
let that = this;
let querys = [[{field:"wm",value:false,compare:"isnull"},{field:"data__分检_日期",compare:"isnull",value:false},{field:"data__has_key",compare:"",value:"分检_批次号"}]];
let obj = {},obj1 = {},obj2 = {},obj3 = {},obj4 = {};
let obj = {},obj1 = {},obj2 = {},obj3 = {},obj4 = {},obj5 = {};
obj.field = 'data__分检_批次号';
obj.value = that.query.batch__contains;
obj.compare = '';
@ -172,6 +201,10 @@ export default {
obj4.value = that.query.number__contains;
obj4.compare = 'contains';
obj5.field = 'data__分检_操作人';
obj5.value = that.query.handler;
obj5.compare = '';
if(that.query.batch__contains!==''&&that.query.batch__contains!==null){
querys[0].push(obj);
}
@ -187,6 +220,9 @@ export default {
if(that.query.number__contains!==''&&that.query.number__contains!==null){
querys[0].push(obj4);
}
if(that.query.handler!==''&&that.query.handler!==null){
querys[0].push(obj5);
}
that.params.querys = querys;
this.$refs.table.queryData(that.params);
},

View File

@ -51,7 +51,11 @@
stripe
>
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="工段名" prop="工段名" fixed="left">
<el-table-column label="工段" prop="工段名" fixed="left">
</el-table-column>
<el-table-column label="工序" prop="工序" fixed="left">
</el-table-column>
<el-table-column label="库存数" prop="物料数量" fixed="left">
</el-table-column>
<el-table-column label="生产数" prop="生产数" fixed="left">
</el-table-column>
@ -133,7 +137,7 @@ export default {
sums[index] = "合计";
return;
}
if (index <total && (index!==0||index!==1||index!==5)) {
if (index <total && (index!==0||index!==1||index!==2||index!==7)) {
const values = data.map((item) =>
Number(item[column.property])
);
@ -151,8 +155,8 @@ export default {
}, 0);
}
}
if(index==5){
sums[index] = ((sums[3]/sums[2])*100).toFixed(2) + '%';
if(index==7){
sums[index] = ((sums[5]/sums[4])*100).toFixed(2) + '%';
}
});
return sums;

View File

@ -17,6 +17,16 @@
placeholder="结束时间"
style="margin-left: 2px; width: 150px"
/>
<el-input v-model="query.material_name"
placeholder="产品名称"
clearable
style="width: 200px;"
></el-input>
<el-input v-model="query.batch"
placeholder="批次号"
clearable
style="width: 200px;"
></el-input>
<el-button
type="primary"
icon="el-icon-search"
@ -226,6 +236,8 @@ export default {
select_cols: "",
mgroup_name: "扭转",
testmgroup_name: "扭后检测",
material_name: "",
batch: "",
},
end_date:'',
start_date:'',
@ -257,6 +269,16 @@ export default {
}else{
query.end_date = that.query.end_date;
}
if(that.query.material_name==''||that.query.material_name==null){
delete query.material_name;
}else{
query.material_name = that.query.material_name;
}
if(that.query.batch==''||that.query.batch==null){
delete query.batch;
}else{
query.batch = that.query.batch;
}
params.query = query;
if(that.activeName=='product'){
biStr = 'product_defect_pb_m';

View File

@ -63,6 +63,12 @@
placeholder="结束时间"
style="margin-left: 2px; width: 150px"
/>
<el-input
v-model="query.material_name"
placeholder="物料名"
clearable
style="width: 200px; margin-left: 2px;"
/>
<el-button
type="primary"
icon="el-icon-search"
@ -96,6 +102,8 @@
<span>{{ scope.row.data.装炉压板出炉_装炉_日期?scope.row.data.装炉压板出炉_装炉_日期:'' }}</span>
</template>
</el-table-column>
<el-table-column label="物料名称" prop="material_name" fixed="left">
</el-table-column>
<el-table-column label="板号" prop="number" fixed="left">
</el-table-column>
<el-table-column label="压前对边" align="center">
@ -201,6 +209,8 @@
<el-table-column label="序号" type="index" width="50" fixed="left"/>
<el-table-column label="板号" prop="number" fixed="left">
</el-table-column>
<el-table-column label="物料名称" prop="material_name" fixed="left">
</el-table-column>
<el-table-column label="炉号" fixed="left">
<template #default="scope">
<span v-if="scope.row.data.装炉压板出炉_设备编号">{{ scope.row.data.装炉压板出炉_设备编号 }}</span>
@ -372,6 +382,8 @@
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="设备编号" prop="设备编号">
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数">
<template #default="scope">
<span v-if="scope.row.总切片数" @click="handleNumClick(scope.row)" style="color:#0052d9;">{{ scope.row.总切片数 }}</span>
@ -425,6 +437,8 @@
<span v-if="scope.row.横压!==null">{{scope.row.横压}}</span>
</template>
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数" prop="总切片数">
</el-table-column>
<el-table-column label="长点">
@ -470,6 +484,8 @@
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="操作人" prop="员工">
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数" prop="总切片数">
</el-table-column>
<el-table-column label="长点">
@ -515,6 +531,8 @@
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="丝高" prop="丝高">
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数" prop="总切片数">
</el-table-column>
<el-table-column label="长点">
@ -629,6 +647,9 @@ export default {
}else{
query.end_date = that.query.end_date;
}
if(that.query.material_name!=''&&that.query.material_name!=null){
query.material_name = that.query.material_name;
}
if(that.activeName=='luhao'){
query.select_cols = that.query.select_cols;
params.query = query;

View File

@ -31,6 +31,12 @@
placeholder="结束时间"
style="margin-left: 2px; width: 150px"
/>
<el-input
v-model="query.material_name"
placeholder="物料名"
clearable
style="width: 200px; margin-left: 2px;"
/>
<el-button
type="primary"
icon="el-icon-search"
@ -55,6 +61,8 @@
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="炉号" prop="设备编号">
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数">
<template #default="scope">
<!-- @click="handleNumClick(scope.row)" -->
@ -133,6 +141,8 @@
<span v-if="scope.row.横压!==null">{{scope.row.横压}}</span>
</template>
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数" prop="总切片数">
</el-table-column>
<el-table-column label="黑网重">
@ -202,6 +212,8 @@
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="操作人" prop="员工">
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数" prop="总切片数">
</el-table-column>
<el-table-column label="黑网重">
@ -271,6 +283,8 @@
<el-table-column type="index" width="50" fixed="left"/>
<el-table-column label="丝高" prop="丝高">
</el-table-column>
<el-table-column label="物料名" prop="物料名">
</el-table-column>
<el-table-column label="总数" prop="总切片数">
</el-table-column>
<el-table-column label="黑网重">
@ -352,7 +366,8 @@ export default {
query:{
end_date:'',
start_date:'',
select_cols: ""
select_cols: "",
material_name:'',
},
end_date:'',
start_date:'',
@ -384,6 +399,9 @@ export default {
}else{
query.end_date = that.query.end_date;
}
if(that.query.material_name!=''&&that.query.material_name!=null){
query.material_name = that.query.material_name;
}
if(that.activeName=='luhao'){
query.select_cols = that.query.select_cols;
query.mgroup_name = '装炉压板出炉';

View File

@ -20,7 +20,9 @@
<el-row :gutter="10">
<el-col :lg="11">
<el-card shadow="never">
<div id="bachart1" style="width:100%;height:300px;"></div>
<div class="chart-scroll" ref="chartScroll">
<div id="bachart1" style="width:100%;height:300px;"></div>
</div>
</el-card>
</el-col>
<el-col :lg="13">
@ -100,11 +102,15 @@ export default {
text: '',
},
grid: {
top: '80px'
top: '150px'
},
tooltip: {
trigger: 'axis'
},
legend: {
top: 30,
left: 10,
},
xAxis: {
type: 'category',
data: []
@ -112,7 +118,6 @@ export default {
yAxis: {
type: 'value'
},
lenged: [],
series: [{
data: [0, 0, 0, 0, 0, 0, 0],
stack: 'Ad',
@ -146,13 +151,11 @@ export default {
that.start_date = year + '-' + month + '-01';
that.end_date = year + '-' + month + '-' + days;
that.queryDate = year + '-' + month;
let duration = that.endWeekNum - that.firstWeekNum + 1;
for (let i = 1; i <= duration; i++) {
for (let i = that.firstWeekNum; i <= that.endWeekNum; i++) {
that.xAxisOrigin.push('第' + i + '周');
}
that.xAxisData = that.xAxisOrigin;
let height = document.getElementById('mainDom').clientHeight;
console.log('height',height);
height= height-60;
that.tableHeight = height;
document.getElementById('bachart1').style.height = height + 'px';
@ -170,12 +173,12 @@ export default {
}
setTimeout(() => {
try {
myChart.setOption(option);
myChart.clear();
myChart.setOption(option, true);
} catch (error) { }
}, 500)
},
queryTypeChange(value) {
console.log(value)
this.queryDate = '';
},
getWeekOfYear(a,b,c) {
@ -197,19 +200,18 @@ export default {
query: { start_date: that.start_date, end_date: that.end_date, mgroup_name: "混料", is_count_utask: -1 },
};
let option = deepCopy(that.basicOption);
option.xAxis.data = that.xAxisData;
option.title.text = '混料统计';
let dateLabels = that.xAxisData;
let exec = that.queryType == '月' ? 'lineWeek' : 'lineMonth';
that.$API.bi.dataset.exec.req(exec, obj).then((res) => {
let dataList = res.data2.ds0 ? res.data2.ds0 : [];
that.dataList = dataList;
if (dataList.length > 0) {
option.series = [];
let seriesData = [], nameList = [];
let nameList = [];
dataList.forEach(ite => {
if (nameList.indexOf(ite.物料名) > -1) { } else {
nameList.push(ite.物料名);
seriesData.push([0,0,0,0,0,0,0,0,0,0,0,0])
let obj = {};
obj.text = ite.物料名;
obj.value = ite.物料名;
@ -230,11 +232,15 @@ export default {
that.specsFilters.push(obj3);
}
})
let seriesData = [];
for (let i = 0; i < dateLabels.length; i++) {
seriesData.push(new Array(modelList.length).fill(0));
}
dataList.forEach(item => {
let indexX = 0, indexY = 0;
if (that.queryType == '月') {
indexX = nameList.indexOf(item.物料名);
indexY = item. - that.firstWeekNum;
indexX = item. - that.firstWeekNum;
indexY = modelList.indexOf(item.型号);
if(dateList.indexOf(item.)>-1){}else{
dateList.push(item.);
let obj = {};
@ -244,22 +250,33 @@ export default {
}
} else {
that.dateFilters = [1,2,3,4,5,6,7,8,9,10,11,12];
indexX = nameList.indexOf(item.物料名);
indexY = item. - 1;
indexX = item. - 1;
indexY = modelList.indexOf(item.型号);
}
if (indexX >= 0 && indexX < seriesData.length && indexY >= 0) {
seriesData[indexX][indexY] += item.合格数;
}
seriesData[indexX][indexY] += item.合格数;
});
option.xAxis.data = modelList;
for (let n = 0; n < seriesData.length; n++) {
let obj = {};
obj.name = nameList[n];
obj.stack = 'Ad';
obj.name = dateLabels[n];
obj.type = 'bar';
obj.barWidth = '15px';
obj.barWidth = '10px';
obj.data = seriesData[n];
option.series.push(obj)
}
let chartDom = document.getElementById('bachart1');
if (chartDom) {
let parentWidth = that.$refs.chartScroll ? that.$refs.chartScroll.clientWidth : chartDom.parentElement.clientWidth;
let needWidth = modelList.length * dateLabels.length * 15;
chartDom.style.width = Math.max(parentWidth, needWidth) + 'px';
let inst = echarts.getInstanceByDom(chartDom);
if (inst) inst.resize();
}
that.setChart("bachart1", option);
} else {
option.xAxis.data = [];
that.setChart("bachart1", option);
}
});
@ -361,4 +378,8 @@ export default {
right: 8px;
z-index: 10;
}
.chart-scroll {
width: 100%;
overflow-x: auto;
}
</style>

View File

@ -2,7 +2,7 @@
<el-container>
<el-header>
<div class="right-panel">
<el-select v-model="queryType" @change="queryTypeChange">
<el-select v-model="queryType" @change="queryTypeChange" style="width: 150px">
<el-option
v-for="item in typeOptions"
:key="item"
@ -17,7 +17,7 @@
type="month"
placeholder="查询月期"
value-format="YYYY-MM"
style="width: 100%"
style="width: 150px"
>
</el-date-picker>
<el-date-picker
@ -26,7 +26,7 @@
type="year"
placeholder="查询年份"
value-format="YYYY"
style="width: 100%"
style="width: 150px"
>
</el-date-picker>
<el-button
@ -41,7 +41,9 @@
<el-row :gutter="10">
<el-col :lg="12">
<el-card shadow="never">
<div id="bachart1"></div>
<div class="chart-scroll">
<div id="bachart1"></div>
</div>
</el-card>
</el-col>
<el-col :lg="12">
@ -55,7 +57,7 @@
<el-table
:data="tableData7"
id="exportDiv7"
:height="300"
:height="500"
:summary-method="getSummaries"
show-summary
>
@ -107,7 +109,9 @@
<el-row :gutter="10">
<el-col :lg="12">
<el-card shadow="never">
<div id="bachart2"></div>
<div class="chart-scroll">
<div id="bachart2"></div>
</div>
</el-card>
</el-col>
<el-col :lg="12">
@ -121,7 +125,7 @@
<el-table
:data="tableData10"
id="exportDiv10"
:height="300"
:height="500"
:summary-method="getSummaries"
show-summary
>
@ -173,7 +177,9 @@
<el-row :gutter="10">
<el-col :lg="12">
<el-card shadow="never">
<div id="bachart3"></div>
<div class="chart-scroll">
<div id="bachart3"></div>
</div>
</el-card>
</el-col>
<el-col :lg="12">
@ -187,7 +193,7 @@
<el-table
:data="tableData6"
id="exportDiv6"
:height="300"
:height="500"
:summary-method="getSummaries2"
show-summary
>
@ -278,6 +284,9 @@ export default {
tooltip: {
trigger: "axis",
},
legend: {
top: 30,
},
xAxis: {
type: "category",
data: [],
@ -285,13 +294,10 @@ export default {
yAxis: {
type: "value",
},
lenged: [],
series: [
{
data: [0, 0, 0, 0, 0, 0, 0],
stack: "Ad",
type: "bar",
barWidth: "15px",
},
],
},
@ -343,8 +349,7 @@ export default {
that.start_date = year + "-" + month + "-01";
that.end_date =year + "-" + month + "-" + days;
that.queryDate = year + "-" + month;
let duration = that.endWeekNum - that.firstWeekNum + 1;
for (let i = 1; i <= duration; i++) {
for (let i = that.firstWeekNum; i <= that.endWeekNum; i++) {
that.xAxisOrigin.push("第" + i + "周");
}
that.xAxisData = that.xAxisOrigin;
@ -366,6 +371,7 @@ export default {
}
setTimeout(() => {
try {
myChart.resize();
myChart.setOption(option);
} catch (error) {}
}, 500);
@ -391,8 +397,8 @@ export default {
that.modelFilters6 = [];
that.specsFilters6 = [];
let option = deepCopy(that.basicOption);
option.xAxis.data = that.xAxisData;
option.title.text = "6车间";
let dateLabels = that.xAxisData;
let exec = that.queryType == "月" ? "lineWeek" : "lineMonth";
let obj = {
query: {
@ -406,12 +412,11 @@ export default {
that.tableData6 = tableData6;
if (tableData6.length > 0) {
option.series = [];
let seriesData = [],nameList = [];
let nameList = [];
tableData6.forEach((ite) => {
if (nameList.indexOf(ite.物料名) > -1) {
}else {
nameList.push(ite.物料名);
seriesData.push([]);
let obj = {};
obj.text = ite.物料名;
obj.value = ite.物料名;
@ -439,15 +444,19 @@ export default {
that.modelFilters6.push(obj4);
}
});
let seriesData = [];
let prodData = [];
for (let i = 0; i < dateLabels.length; i++) {
seriesData.push(new Array(nameList.length).fill(0));
prodData.push(new Array(nameList.length).fill(0));
}
if (that.queryType == "月") {
tableData6.forEach((item) => {
let indexX = nameList.indexOf(item.物料名);
let indexY = item. - that.firstWeekNum;
if(seriesData[indexX][indexY]){
seriesData[indexX][indexY] += item.合格数;
}else{
seriesData[indexX][indexY] =0;
let indexX = item. - that.firstWeekNum;
let indexY = nameList.indexOf(item.物料名);
if (indexX >= 0 && indexX < seriesData.length && indexY >= 0) {
seriesData[indexX][indexY] += item.合格数;
prodData[indexX][indexY] += Number(item.生产数) || 0;
}
if(dateList.indexOf(item.)>-1){}else{
dateList.push(item.);
@ -460,27 +469,105 @@ export default {
} else {
that.dateFilters6 = [1,2,3,4,5,6,7,8,9,10,11,12];
tableData6.forEach((item) => {
let indexX = nameList.indexOf(item.物料名);
let indexY = item.month - 1;
if(seriesData[indexX][indexY]){
seriesData[indexX][indexY] += item.合格数;
}else{
seriesData[indexX][indexY] =0;
let indexX = item. - 1;
let indexY = nameList.indexOf(item.物料名);
if (indexX >= 0 && indexX < seriesData.length && indexY >= 0) {
seriesData[indexX][indexY] += item.合格数;
prodData[indexX][indexY] += Number(item.生产数) || 0;
}
});
}
option.xAxis = { type: "category", data: nameList };
option.yAxis = [
{ type: "value" },
{ type: "value", min: -233.33, max: 100, show: false }
];
option.legend = { top: 30, data: dateLabels };
let barWidth = 10;
let barGap = 0;
let chartDom = document.getElementById("bachart3");
if (chartDom) {
chartDom.style.width = (nameList.length * dateLabels.length * 15) + "px";
}
for (let n = 0; n < seriesData.length; n++) {
let obj = {};
obj.name = nameList[n];
obj.stack = "Ad";
obj.name = dateLabels[n];
obj.type = "bar";
obj.barWidth = "15px";
obj.barWidth = barWidth;
obj.barGap = "0%";
obj.data = seriesData[n];
option.series.push(obj);
}
let totalSeries = seriesData.length;
let curveData = [];
let ratesByMat = [];
for (let mat = 0; mat < nameList.length; mat++) {
let rates = [];
for (let s = 0; s < totalSeries; s++) {
let pass = seriesData[s][mat];
let prod = prodData[s][mat];
rates.push(prod > 0 ? Math.round((pass / prod) * 100) : null);
}
curveData.push({ value: [mat].concat(rates) });
ratesByMat.push(rates);
}
option.tooltip = {
trigger: "axis",
formatter: function (params) {
if (!params || params.length === 0) return "";
let cat = params[0].axisValueLabel;
let matIdx = params[0].dataIndex;
let rates = ratesByMat[matIdx] || [];
let html = '<div style="font-weight:bold">' + cat + '</div>';
let barIdx = 0;
params.forEach(function (p) {
if (p.seriesType !== "bar") return;
let rate = rates[barIdx];
let rateStr = (rate !== null && rate !== undefined) ? rate + "%" : "-";
html += '<div>' +
'<span style="display:inline-block;width:10px;height:10px;background:' + p.color + ';border-radius:50%;margin-right:5px;vertical-align:middle"></span>' +
p.seriesName + ': ' + p.value + ' &nbsp;&nbsp; 合格率 ' + rateStr +
'</div>';
barIdx++;
});
return html;
}
};
option.series.push({
name: "合格率",
type: "custom",
xAxisIndex: 0,
yAxisIndex: 1,
silent: true,
z: 5,
data: curveData,
renderItem: function (params, api) {
let materialIdx = api.value(0);
let centerX = api.coord([materialIdx, 0])[0];
let groupWidth = totalSeries * barWidth + (totalSeries - 1) * barGap;
let halfGroup = groupWidth / 2;
let slotWidth = barWidth + barGap;
let pts = [];
for (let s = 0; s < totalSeries; s++) {
let rate = api.value(s + 1);
if (rate === null || rate === undefined) continue;
let xPx = centerX - halfGroup + barWidth / 2 + s * slotWidth;
let yPx = api.coord([0, rate])[1];
pts.push([xPx, yPx]);
}
if (pts.length < 2) return null;
return {
type: "polyline",
shape: { points: pts, smooth: 0.3 },
style: { stroke: "#333", lineWidth: 1.5, fill: "none" }
};
}
});
that.setChart("bachart3", option);
} else {
option.xAxis.data = [];
let chartDom = document.getElementById("bachart3");
if (chartDom) chartDom.style.width = "100%";
that.setChart("bachart3", option);
}
});
@ -500,8 +587,8 @@ export default {
},
};
let option = deepCopy(that.basicOption);
option.xAxis.data = that.xAxisData;
option.title.text = "预制棒7车间";
let dateLabels = that.xAxisData;
let exec = that.queryType == "月" ? "lineWeek" : "lineMonth";
that.$API.bi.dataset.exec.req(exec, obj).then((res) => {
console.log("7生产车间统计:", res);
@ -509,13 +596,11 @@ export default {
that.tableData7 = tableData7;
if (tableData7.length > 0) {
option.series = [];
let seriesData = [],
nameList = [];
let nameList = [];
tableData7.forEach((ite) => {
if (nameList.indexOf(ite.物料名) > -1) {
} else {
nameList.push(ite.物料名);
seriesData.push([]);
let obj = {};
obj.text = ite.物料名;
obj.value = ite.物料名;
@ -536,12 +621,18 @@ export default {
that.specsFilters7.push(obj3);
}
});
let seriesData = [];
let prodData = [];
for (let i = 0; i < dateLabels.length; i++) {
seriesData.push(new Array(nameList.length).fill(0));
prodData.push(new Array(nameList.length).fill(0));
}
tableData7.forEach((item) => {
let indexX = 0,
indexY = 0;
if (that.queryType == "月") {
indexX = nameList.indexOf(item.物料名);
indexY = item. - that.firstWeekNum;
indexX = item. - that.firstWeekNum;
indexY = nameList.indexOf(item.物料名);
if(dateList.indexOf(item.)>-1){}else{
dateList.push(item.);
let obj = {};
@ -551,27 +642,105 @@ export default {
}
} else {
that.dateFilters7 = [1,2,3,4,5,6,7,8,9,10,11,12];
indexX = nameList.indexOf(item.物料名);
indexY = item. - 1;
indexX = item. - 1;
indexY = nameList.indexOf(item.物料名);
}
if(seriesData[indexX][indexY]){
seriesData[indexX][indexY] += item.合格数;
}else{
seriesData[indexX][indexY] =0;
if (indexX >= 0 && indexX < seriesData.length && indexY >= 0) {
seriesData[indexX][indexY] += item.合格数;
prodData[indexX][indexY] += Number(item.生产数) || 0;
}
});
option.xAxis = { type: "category", data: nameList };
option.yAxis = [
{ type: "value" },
{ type: "value", min: -233.33, max: 100, show: false }
];
option.legend = { top: 30, data: dateLabels };
let barWidth = 10;
let barGap = 0;
let chartDom = document.getElementById("bachart1");
if (chartDom) {
chartDom.style.width = (nameList.length * dateLabels.length * 15) + "px";
}
for (let n = 0; n < seriesData.length; n++) {
let obj = {};
obj.name = nameList[n];
obj.stack = "Ad";
obj.name = dateLabels[n];
obj.type = "bar";
obj.barWidth = "15px";
obj.barWidth = barWidth;
obj.barGap = "0%";
obj.data = seriesData[n];
option.series.push(obj);
}
let totalSeries = seriesData.length;
let curveData = [];
let ratesByMat = [];
for (let mat = 0; mat < nameList.length; mat++) {
let rates = [];
for (let s = 0; s < totalSeries; s++) {
let pass = seriesData[s][mat];
let prod = prodData[s][mat];
rates.push(prod > 0 ? Math.round((pass / prod) * 100) : null);
}
curveData.push({ value: [mat].concat(rates) });
ratesByMat.push(rates);
}
option.tooltip = {
trigger: "axis",
formatter: function (params) {
if (!params || params.length === 0) return "";
let cat = params[0].axisValueLabel;
let matIdx = params[0].dataIndex;
let rates = ratesByMat[matIdx] || [];
let html = '<div style="font-weight:bold">' + cat + '</div>';
let barIdx = 0;
params.forEach(function (p) {
if (p.seriesType !== "bar") return;
let rate = rates[barIdx];
let rateStr = (rate !== null && rate !== undefined) ? rate + "%" : "-";
html += '<div>' +
'<span style="display:inline-block;width:10px;height:10px;background:' + p.color + ';border-radius:50%;margin-right:5px;vertical-align:middle"></span>' +
p.seriesName + ': ' + p.value + ' &nbsp;&nbsp; 合格率 ' + rateStr +
'</div>';
barIdx++;
});
return html;
}
};
option.series.push({
name: "合格率",
type: "custom",
xAxisIndex: 0,
yAxisIndex: 1,
silent: true,
z: 5,
data: curveData,
renderItem: function (params, api) {
let materialIdx = api.value(0);
let centerX = api.coord([materialIdx, 0])[0];
let groupWidth = totalSeries * barWidth + (totalSeries - 1) * barGap;
let halfGroup = groupWidth / 2;
let slotWidth = barWidth + barGap;
let pts = [];
for (let s = 0; s < totalSeries; s++) {
let rate = api.value(s + 1);
if (rate === null || rate === undefined) continue;
let xPx = centerX - halfGroup + barWidth / 2 + s * slotWidth;
let yPx = api.coord([0, rate])[1];
pts.push([xPx, yPx]);
}
if (pts.length < 2) return null;
return {
type: "polyline",
shape: { points: pts, smooth: 0.3 },
style: { stroke: "#333", lineWidth: 1.5, fill: "none" }
};
}
});
that.setChart("bachart1", option);
} else {
option.xAxis.data = [];
let chartDom = document.getElementById("bachart1");
if (chartDom) chartDom.style.width = "100%";
that.setChart("bachart1", option);
}
});
@ -584,8 +753,8 @@ export default {
that.modelFilters = [];
that.specsFilters = [];
let option = deepCopy(that.basicOption);
option.xAxis.data = that.xAxisData;
option.title.text = "预制管10车间";
let dateLabels = that.xAxisData;
let obj = {
query: {
start_date: that.start_date,
@ -599,13 +768,11 @@ export default {
that.tableData10 = tableData10;
if (tableData10.length > 0) {
option.series = [];
let seriesData = [],
nameList = [];
let nameList = [];
tableData10.forEach((ite) => {
if (nameList.indexOf(ite.物料名) > -1) {
} else {
nameList.push(ite.物料名);
seriesData.push([]);
let obj = {};
obj.text = ite.物料名;
obj.value = ite.物料名;
@ -626,12 +793,18 @@ export default {
that.specsFilters.push(obj3);
}
});
let seriesData = [];
let prodData = [];
for (let i = 0; i < dateLabels.length; i++) {
seriesData.push(new Array(nameList.length).fill(0));
prodData.push(new Array(nameList.length).fill(0));
}
tableData10.forEach((item) => {
let indexX = 0,
indexY = 0;
if (that.queryType == "月") {
indexX = nameList.indexOf(item.物料名);
indexY = item. - that.firstWeekNum;
indexX = item. - that.firstWeekNum;
indexY = nameList.indexOf(item.物料名);
if(dateList.indexOf(item.)>-1){}else{
dateList.push(item.);
let obj = {};
@ -641,27 +814,105 @@ export default {
}
} else {
that.dateFilters = [1,2,3,4,5,6,7,8,9,10,11,12];
indexX = nameList.indexOf(item.物料名);
indexY = item. - 1;
indexX = item. - 1;
indexY = nameList.indexOf(item.物料名);
}
if(seriesData[indexX][indexY]){
seriesData[indexX][indexY] += item.合格数;
}else{
seriesData[indexX][indexY] =0;
if (indexX >= 0 && indexX < seriesData.length && indexY >= 0) {
seriesData[indexX][indexY] += item.合格数;
prodData[indexX][indexY] += Number(item.生产数) || 0;
}
});
option.xAxis = { type: "category", data: nameList };
option.yAxis = [
{ type: "value" },
{ type: "value", min: -233.33, max: 100, show: false }
];
option.legend = { top: 30, data: dateLabels };
let barWidth = 10;
let barGap = 0;
let chartDom = document.getElementById("bachart2");
if (chartDom) {
chartDom.style.width = (nameList.length * dateLabels.length * 15) + "px";
}
for (let n = 0; n < seriesData.length; n++) {
let obj = {};
obj.name = nameList[n];
obj.stack = "Ad";
obj.name = dateLabels[n];
obj.type = "bar";
obj.barWidth = "15px";
obj.barWidth = barWidth;
obj.barGap = "0%";
obj.data = seriesData[n];
option.series.push(obj);
}
let totalSeries = seriesData.length;
let curveData = [];
let ratesByMat = [];
for (let mat = 0; mat < nameList.length; mat++) {
let rates = [];
for (let s = 0; s < totalSeries; s++) {
let pass = seriesData[s][mat];
let prod = prodData[s][mat];
rates.push(prod > 0 ? Math.round((pass / prod) * 100) : null);
}
curveData.push({ value: [mat].concat(rates) });
ratesByMat.push(rates);
}
option.tooltip = {
trigger: "axis",
formatter: function (params) {
if (!params || params.length === 0) return "";
let cat = params[0].axisValueLabel;
let matIdx = params[0].dataIndex;
let rates = ratesByMat[matIdx] || [];
let html = '<div style="font-weight:bold">' + cat + '</div>';
let barIdx = 0;
params.forEach(function (p) {
if (p.seriesType !== "bar") return;
let rate = rates[barIdx];
let rateStr = (rate !== null && rate !== undefined) ? rate + "%" : "-";
html += '<div>' +
'<span style="display:inline-block;width:10px;height:10px;background:' + p.color + ';border-radius:50%;margin-right:5px;vertical-align:middle"></span>' +
p.seriesName + ': ' + p.value + ' &nbsp;&nbsp; 合格率 ' + rateStr +
'</div>';
barIdx++;
});
return html;
}
};
option.series.push({
name: "合格率",
type: "custom",
xAxisIndex: 0,
yAxisIndex: 1,
silent: true,
z: 5,
data: curveData,
renderItem: function (params, api) {
let materialIdx = api.value(0);
let centerX = api.coord([materialIdx, 0])[0];
let groupWidth = totalSeries * barWidth + (totalSeries - 1) * barGap;
let halfGroup = groupWidth / 2;
let slotWidth = barWidth + barGap;
let pts = [];
for (let s = 0; s < totalSeries; s++) {
let rate = api.value(s + 1);
if (rate === null || rate === undefined) continue;
let xPx = centerX - halfGroup + barWidth / 2 + s * slotWidth;
let yPx = api.coord([0, rate])[1];
pts.push([xPx, yPx]);
}
if (pts.length < 2) return null;
return {
type: "polyline",
shape: { points: pts, smooth: 0.3 },
style: { stroke: "#333", lineWidth: 1.5, fill: "none" }
};
}
});
that.setChart("bachart2", option);
} else {
option.xAxis.data = [];
let chartDom = document.getElementById("bachart2");
if (chartDom) chartDom.style.width = "100%";
that.setChart("bachart2", option);
}
});
@ -734,9 +985,8 @@ export default {
that.end_date =that.queryDate +"-" +days;
that.firstWeekNum = that.getWeekOfYear(year,month,1);
that.endWeekNum = that.getWeekOfYear(year,month,days);
let duration = that.endWeekNum - that.firstWeekNum + 1;
let xAxisData = [];
for (let i = 1; i <= duration; i++) {
for (let i = that.firstWeekNum; i <= that.endWeekNum; i++) {
xAxisData.push("第" + i + "周");
}
that.xAxisData = xAxisData;
@ -828,12 +1078,17 @@ export default {
</script>
<style scoped>
.chart-scroll {
width: 100%;
overflow-x: auto;
}
#bachart1,
#bachart2,
#bachart3,
#bachart4 {
width: 100%;
height: 300px;
min-width: 100%;
height: 500px;
}
.tables {
position: absolute;

View File

@ -40,7 +40,9 @@
<el-row :gutter="10">
<el-col :lg="12">
<el-card shadow="never">
<scEcharts id="bachart1" height="300px" :option="option"></scEcharts>
<div class="echarts-scroll">
<scEcharts ref="echarts1" id="bachart1" height="300px" :option="option"></scEcharts>
</div>
</el-card>
</el-col>
<el-col :lg="12">
@ -128,9 +130,21 @@ export default {
type: "category",
data: [],
},
yAxis: {
type: "value",
},
yAxis: [
{
type: "value",
name: "数量",
},
{
type: "value",
name: "合格率",
min: 0,
max: 100,
axisLabel: {
formatter: "{value}%",
},
},
],
series: [],
},
nameFilters: [],
@ -189,49 +203,93 @@ export default {
obj.query.order_bys_date = ", 月";
}
let xAxisData = [],nameData=[],seriesData=[];
let colorPalette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
that.$API.bi.dataset.exec.req("lineWeek", obj).then((res) => {
let data = res.data2.ds0;
that.tableData = data;
data.forEach((item) => {
if (xAxisData.indexOf(item.工段) > -1) {
} else {
if (xAxisData.indexOf(item.工段) === -1) {
xAxisData.push(item.工段);
let obj = {};
obj.text = item.工段;
obj.value = item.工段;
that.mgroupFilters.push(obj);
that.mgroupFilters.push({ text: item.工段, value: item.工段 });
}
if (nameData.indexOf(item.物料名) > -1) {
} else {
let obj0 = {};
obj0.text = item.物料名;
obj0.value = item.物料名;
that.nameFilters.push(obj0);
if (nameData.indexOf(item.物料名) === -1) {
nameData.push(item.物料名);
let obj = {
name:'',
type: "bar",
label:{
show: true,
position: "top",
formatter: "{c}",
color: "rgb(64,158,255)",
},
barWidth: "15px",
data:[0, 0, 0, 0, 0, 0, 0, 0],
};
obj.name=item.物料名,
seriesData.push(obj);
that.nameFilters.push({ text: item.物料名, value: item.物料名 });
}
let index = xAxisData.indexOf(item.工段);
let indexY = nameData.indexOf(item.物料名);
seriesData[indexY].data[index] += item.合格数;
});
nameData.forEach((materialName, idx) => {
let color = colorPalette[idx % colorPalette.length];
let barData = xAxisData.map((mgroup) => {
let qualified = 0;
data.forEach((item) => {
if (item.工段 === mgroup && item.物料名 === materialName) {
qualified += Number(item.合格数) || 0;
}
});
return qualified;
});
let passRateData = xAxisData.map((mgroup) => {
let qualified = 0;
let produced = 0;
data.forEach((item) => {
if (item.工段 === mgroup && item.物料名 === materialName) {
qualified += Number(item.合格数) || 0;
produced += Number(item.生产数) || 0;
}
});
return produced > 0
? Number(((qualified / produced) * 100).toFixed(2))
: null;
});
seriesData.push({
name: materialName,
type: "bar",
yAxisIndex: 0,
itemStyle: { color },
label: {
show: true,
position: "top",
formatter: "{c}",
color: color,
},
barWidth: "15px",
data: barData,
});
seriesData.push({
name: materialName + " 合格率",
type: "line",
yAxisIndex: 1,
smooth: true,
data: passRateData,
label: {
show: true,
position: "top",
formatter: "{c}%",
color: color,
},
lineStyle: { color },
itemStyle: { color },
});
});
that.xAxisData = xAxisData;
that.option.xAxis.data = that.xAxisData;
that.option.series = seriesData;
that.$nextTick(() => {
that.resizeChart(xAxisData.length, nameData.length);
});
});
},
resizeChart(xCount, materialCount) {
let chartDiv = document.getElementById("bachart1");
if (!chartDiv) return;
let wrapper = chartDiv.parentElement;
let parentWidth = wrapper.clientWidth;
let groupWidth = Math.max(60, materialCount * 25 + 30);
let neededWidth = xCount * groupWidth + 80;
chartDiv.style.width = Math.max(parentWidth, neededWidth) + "px";
let inst = this.$refs.echarts1 && this.$refs.echarts1.myChart;
if (inst) inst.resize();
},
handleQuery() {
if (this.queryDate !== "" && this.queryDate !== null) {
if (this.queryType == "月") {
@ -313,4 +371,12 @@ export default {
left: 4px;
z-index: 10;
}
.echarts-scroll {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
}
.echarts-scroll > :deep(#bachart1) {
min-width: 100%;
}
</style>

View File

@ -28,7 +28,7 @@
:filter-method="filterModel1" filter-placement="bottom-end" />
<el-table-column label="规格" prop="material_specification" :filters="specsFilters1"
:filter-method="filterSpecs1" filter-placement="bottom-end" />
<el-table-column prop="dept_name" label="完成车间" :filters="deptFilters1"
<el-table-column prop="dept_name" label="所在车间/仓库" :filters="deptFilters1"
:filter-method="filterDept1" filter-placement="bottom-end" />
<el-table-column label="库存合格品数" prop="count" />
</scTable>

View File

@ -540,7 +540,7 @@ export default {
let that = this;
var req = {
page: 0,
state:10,
state__in:'10,34',
tag:that.tag,
mgroupx:that.mgroupId
};
@ -556,6 +556,7 @@ export default {
let that = this;
that.materialOptions = [];
var req = {
tag:that.tag,
mgroupx: that.mgroupId,
page: 0
};
@ -665,7 +666,16 @@ export default {
});
},
addMaterial(){
this.addShow = true;
let that = this;
that.addShow = true;
//
if(that.form.handoverb && that.form.handoverb.length > 0){
that.form.handoverb.forEach(item => {
if(item.wm && that.selectItems.indexOf(item.wm) === -1){
that.selectItems.push(item.wm);
}
});
}
},
delMaterial(index){
this.selectItems.splice(index,1);
@ -715,6 +725,15 @@ export default {
},
materialChange() {
let that = this;
// shangpaipingmo
let scannedMap = {};
if(that.route_code == 'shangpaipingmo'){
(that.form.handoverb || []).forEach(h => {
if(h.wm && h.handoverbw && h.handoverbw.length > 0){
scannedMap[h.wm] = h;
}
});
}
that.form.new_batch = that.route_code=='shangpaipingmo'?that.form.new_batch:"";
let totalCount = 0,data = [];
if(that.selectItems.length>0){
@ -755,15 +774,31 @@ export default {
}
data.forEach((item,index)=>{
item.wm = item.id;
item.count = item.count_canhandover;
totalCount += Number(item.count_canhandover);
item.tracking = item.material_.tracking;
if(item.material_.process_name){
item.process = item.material_.process_name;
}
item.handoverbw = [];
that.getWprList(item.id,index);
let scanned = scannedMap[item.id];
if(scanned){
// handoverbw
item.handoverbw = scanned.handoverbw;
item.count = scanned.count;
totalCount += Number(scanned.count);
} else {
item.count = item.count_canhandover;
totalCount += Number(item.count_canhandover);
item.handoverbw = [];
that.getWprList(item.id,index);
}
})
// checkedStatus handoverbw
that.checkedStatus = data.map(item => {
let scanned = scannedMap[item.id];
if(scanned && scanned.handoverbw && scanned.handoverbw.length > 0){
return scanned.handoverbw.every(w => w.checked !== false);
}
return true;
});
}
that.totalCount = totalCount;
that.form.handoverb = data;
@ -1049,16 +1084,22 @@ export default {
let obj1 = {};
obj1.wpr = res[0].id;
obj1.number = res[0].number;
obj1.checked = true;
that.form.handoverb[indexs].count+=1;
that.form.handoverb[indexs].handoverbw.push(obj1);
that.checkedStatus.push(true)
that.selectItems.push(res[0].id)
}
}else{
that.form.handoverb[indexs].handoverbw = [];
let obj1 = {};
obj1.wpr = res[0].id;
obj1.checked = true;
obj1.number = res[0].number;
that.form.handoverb[indexs].count=1;
that.form.handoverb[indexs].handoverbw.push(obj1);
that.checkedStatus.push(true)
that.selectItems.push(res[0].id)
}
}else{//handoverb
if(that.new_wm==''){
@ -1082,9 +1123,12 @@ export default {
obj2.count = 1;
let obj3 = {};
obj3.wpr = res[0].id;
obj3.checked = true;
obj3.number = res[0].number;
obj2.handoverbw.push(obj3);
that.form.handoverb.push(obj2);
that.checkedStatus.push(true)
that.selectItems.push(res[0].id)
}
})
}else{
@ -1097,9 +1141,12 @@ export default {
obj2.count = 1;
let obj3 = {};
obj3.wpr = res[0].id;
obj3.checked = true;
obj3.number = res[0].number;
obj2.handoverbw.push(obj3);
that.form.handoverb.push(obj2);
that.checkedStatus.push(true)
that.selectItems.push(res[0].id)
}
}
}else{

View File

@ -4,7 +4,7 @@
<div class="left-panel">
<el-button type="primary" @click="tomio('do_out')" v-auth="'mio.do'" v-if="route_code=='qingxi'">领料</el-button>
<el-button type="primary" v-auth="'wmaterial.create'" @click="table_create()">来料</el-button>
<el-button type="primary" v-auth="'handover.create'" @click="table_add(40)">报废</el-button>
<el-button type="primary" v-auth="'handover.create'" @click="table_add(40,'todo')">报废</el-button>
<el-button type="primary" v-auth="'handover.create'" @click="batchConcat()">合批</el-button>
</div>
<div class="right-panel">
@ -512,9 +512,10 @@ export default {
}
},
//
table_add(type) {
table_add(type,tag) {
this.dialog.scrap = true;
this.type = type;
this.tag = tag;
this.$nextTick(() => {
this.$refs.scrapDialog.open("add");
});

View File

@ -3,7 +3,7 @@
<el-header>
<div class="left-panel">
<el-button type="primary" @click="tomio('do_out')" v-auth="'mio.do'" v-if="route_code=='qingxi'">领料</el-button>
<el-button type="primary" v-auth="'handover.create'" @click="table_add(40)">报废</el-button>
<el-button type="primary" v-auth="'handover.create'" @click="table_add(40,'done')">报废</el-button>
<el-button type="primary" v-auth="'handover.create'" @click="batchConcat()">合批</el-button>
<el-button type="primary" @click="tomio('do_in')" v-auth="'mio.doin'">入库</el-button>
</div>
@ -255,6 +255,7 @@
v-if="dialog.scrap"
ref="scrapDialog"
:type="type"
:tag="tag"
:wmItem="wmItem"
:mgroupName="mgroup_name"
:mgroupId="mgroupId"
@ -501,9 +502,10 @@ export default {
}
},
//
table_add(type) {
table_add(type,tag) {
this.dialog.scrap = true;
this.type = type;
this.tag = tag;
this.$nextTick(() => {
this.$refs.scrapDialog.open("add");
});

View File

@ -364,7 +364,13 @@
</scTable>
</el-card>
<!-- 输出物料 输出物料追踪类型为单个-->
<el-card v-else style="width: 100%;margin-bottom:1vh" header="输出物料" shadow="never">
<el-card v-else style="width: 100%;margin-bottom:1vh" shadow="never">
<template #header>
<div style="display:flex;align-items:center;justify-content:space-between;">
<span>输出物料</span>
<el-button size="small" v-if="checkTableShow" @click="$refs.checkTable.openColumnSetting()">列设置</el-button>
</div>
</template>
<check-table
v-if="checkTableShow"
ref="checkTable"
@ -386,6 +392,7 @@
style="width: 100%;height: 500px;"
></check-table>
</el-card>
<div style="height: 100px;"></div>
<save-dialog
v-if="dialog.save"
ref="saveDialog"
@ -670,11 +677,18 @@ export default {
}
that.materialIn = res.material_in!==null?res.material_in:res.mlogb_full[0]?res.mlogb_full[0].material_in:null;
that.deptId = res.belong_dept;
that.checkTableShow = true;
that.apiObjWm = that.$API.wpm.wmaterial.list;
that.$API.wpm.mlogb.list.req(that.paramsOut).then((res) => {
that.tableData2 = res;
})
if(res.qct!==null){
that.checkTableShow = true;
}else{
that.$API.wpm.mlogb.list.req(that.paramsOut).then((res_out) => {
that.tableData2 = res_out;
if(res.is_fix&&res_out[0].qct!==null){
that.mlogItem.qct = res_out[0].qct;
}
that.checkTableShow = true;
})
}
if(!res.is_fix){
that.getcutCount(res.material_in);
that.$API.mtm.routepack.list.req({page:0,search:res.routepack_name}).then((res) => {
@ -700,8 +714,13 @@ export default {
},
getEquipment(){
let that = this;
that.equipmentOtions = [];
that.$API.em.equipment.list.req({page:0,belong_dept:that.dept}).then((res) => {
that.equipmentOtions = res;
res.forEach((item) => {
if(item.cate_name!=="工装"||item.cate_name==null){
that.equipmentOtions.push(item);
}
})
})
},
//

View File

@ -7,9 +7,8 @@
destroy-on-close
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0">
<el-form
<el-container v-loading="loading" style="background: none;">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
@ -115,7 +114,6 @@
<el-button type="primary" :loading="isSaveing" @click="submit">提交</el-button>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-main>
</el-container>
</el-dialog>
</template>

View File

@ -620,6 +620,13 @@ export default {
that.testitems.push(obj)
}
})
res.qct_defects.forEach((item) => {
that.addTemplate[item.defect_name] = false;
let obj = Object.assign({}, item);
obj.canEdit = that.processType=='20'?false:true;
that.qct_defects.push(obj);
})
that.qct_defects_origin = that.qct_defects;
that.getList();
});
},

View File

@ -22,8 +22,9 @@
<el-button type="primary" v-if="!isSubmit&&processType=='20'" @click="check_start">检验</el-button>
<el-button type="primary" v-if="multipleSet" @click="check_set" style="position: absolute;left: 210px;">批量操作</el-button>
<el-input v-if="multipleSet" v-model="wprInputText" @change="wprinputChange" style="width:200px;position: absolute;left: 308px;"></el-input>
<div style="width:fit-content;position: absolute;right: 40px;display: inline-block;">
<div style="display: flex;">
<el-button v-if="!isSubmit" type="success" @click="digital ">数字识别</el-button>
<div style="width:fit-content;position: absolute;right: 0;display: inline-block;">
<div style="display: flex;align-items: center;gap: 8px;">
<el-link v-if="test_file!==''" :href="test_file" target="_blank">{{ test_file_name }}</el-linK>
<scFileImport
v-if="project_code=='tcerp'&&processType=='20'&&!isSubmit"
@ -34,6 +35,14 @@
></scFileImport><!-- :templateUrl="checkTemplate" -->
</div>
</div>
<div v-if="columnSettingVisible" class="col-setting-float-panel" @click.stop>
<div v-for="col in allColumnOptions" :key="col.key" class="col-setting-item">
<el-checkbox
:model-value="isColVisible(col.key)"
@change="toggleColumn(col.key)"
>{{ col.label }}</el-checkbox>
</div>
</div>
</div>
<div class="table-scroll">
<table id="mlogbwlist" class="tables">
@ -45,11 +54,15 @@
<th class="w_50 sticky-cell sticky-left-index">序号</th>
<th class="w_140 sticky-cell sticky-left-batch">物料批次</th>
<th class="w_140 sticky-cell sticky-left-number">物料编号</th>
<th class="w_150" v-if="route_code=='niuzhuan'">生产设备</th>
<th class="w_180" v-if="route_code=='niuzhuan'">扭转日期</th>
<th class="w_80" v-for="item in qct_testitems" :key="item.id">{{ item.testitem_name }}</th>
<th class="w_80" v-for="item in qct_defects" :key="item.id">{{ item.defect_name }}</th>
<th class="w_80">备注</th>
<th class="w_150" v-if="route_code=='niuzhuan'" v-show="isColVisible('equip')">生产设备</th>
<th class="w_180" v-if="route_code=='niuzhuan'" v-show="isColVisible('time')">扭转日期</th>
<th class="w_150" v-if="mgroupName=='喷码'" v-show="isColVisible('tooling')">工装</th>
<th class="w_80" v-for="item in qct_testitems" :key="item.id" v-show="isColVisible('testitem_'+item.id)">{{ item.testitem_name }}</th>
<th class="w_80" v-for="item in qct_defects" :key="item.id" v-show="isColVisible('defect_'+item.id)">
{{ item.defect_name }}
<span style="color:#f56c6c;">{{ getDefectCount(item.defect_name) }}</span>
</th>
<th class="w_80" v-show="isColVisible('note')">备注</th>
<th class="w_150 sticky-cell sticky-right-action" v-if="!isSubmit">操作</th>
</tr>
</thead>
@ -70,7 +83,7 @@
<span v-else>{{ row.number }}</span>
<span v-if="row.wpr_number_out !== null && row.wpr_number_out !== undefined">{{ row.wpr_number_out }}</span>
</td>
<td class="w_150 " v-if="route_code=='niuzhuan'">
<td class="w_150 " v-if="route_code=='niuzhuan'" v-show="isColVisible('equip')">
<select name="pets" id="pet-select" v-if="row.isEdit" style="width: 100%;" v-model="row.equip" :value="row.equip">
<option v-for="item in optionsEq" :key="item.id" :value="item.id">
{{ item.number }}
@ -78,13 +91,21 @@
</select>
<span v-else>{{ row.equip_name }}<span v-if="row.equip_number&&row.equip_number!=null">{{ row.equip_number }}</span></span>
</td>
<td class="w_180 " v-if="route_code=='niuzhuan'">
<td class="w_180 " v-if="route_code=='niuzhuan'" v-show="isColVisible('time')">
<input v-if="row.isEdit" type="datetime-local" id="datetime" v-model="row.work_start_time" @change = "timeChange(row)">
<div v-else>
<span v-if="row.work_start_time!==null">{{ row.work_start_time}}</span>
</div>
</td>
<td class="w_80 " v-for="item in qct_testitems" :key="item.id">
<td class="w_150 " v-if="mgroupName=='喷码'" v-show="isColVisible('tooling')">
<select name="tooling" id="tooling-select" v-if="row.isEdit" style="width: 100%;" v-model="row.tooling" :value="row.tooling">
<option v-for="item in optionsTooling" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
<span v-else>{{ getToolingName(row.wpr_pre_info?.tooling) || row.tooling_name }}</span>
</td>
<td class="w_80 " v-for="item in qct_testitems" :key="item.id" v-show="isColVisible('testitem_'+item.id)">
<span v-if="!row.isEdit || !item.canEdit">{{ row[item.testitem_name] }}</span>
<input v-if="item.testitem_field_type == 'input-number' && row.isEdit && item.canEdit"
type="number" v-model="row[item.testitem_name]" @change="defectCountSun(row)">
@ -101,10 +122,10 @@
<option v-for="item0 in item.testitem_choices" :key="item0" :value="item0">{{ item0 }}</option>
</select>
</td>
<td class="w_80 padding_4 defectBlock" v-for="item in qct_defects" :key="item.id">
<td class="w_80 padding_4 defectBlock" v-for="item in qct_defects" :key="item.id" v-show="isColVisible('defect_'+item.id)">
<input type="checkbox" class="checkboxInput" :disabled="!row.isEdit || !item.canEdit" v-model="row[item.defect_name]" @change="switchChange(row, item,index)">
</td>
<td class="w_80 ">
<td class="w_80 " v-show="isColVisible('note')">
<input v-if="row.isEdit" v-model="row.note" placeholder="备注">
<span v-else style="width: 100%;height: 100%;display: inline-block;">{{ row.note }}</span>
</td>
@ -394,10 +415,15 @@ export default {
wprInputText:"",
project_code:"",
test_file_name:"",
ocr_ip:"",
ocr_port:"",
ocr_unit:"",
canMultiple:false,
selectedAll:false,
checkAll: false,
hideAdd: false,
hiddenColumns: [],
columnSettingVisible: false,
visible: false,
isSaveing:false,
setVisible:false,
@ -432,6 +458,7 @@ export default {
},
optionsEq:[],
optionsTooling:[],
defectlists:[],
testitemlists:[],
selectWprList:[],
@ -445,6 +472,26 @@ export default {
};
},
watch: {},
computed: {
allColumnOptions() {
const cols = [];
if (this.route_code === 'niuzhuan') {
cols.push({ key: 'equip', label: '生产设备' });
cols.push({ key: 'time', label: '扭转日期' });
}
if (this.mgroupName === '喷码') {
cols.push({ key: 'tooling', label: '工装' });
}
this.qct_testitems.forEach(item => {
cols.push({ key: 'testitem_' + item.id, label: item.testitem_name });
});
this.qct_defects.forEach(item => {
cols.push({ key: 'defect_' + item.id, label: item.defect_name });
});
cols.push({ key: 'note', label: '备注' });
return cols;
},
},
mounted() {
let that = this;
if(that.test_file!==''&&that.test_file!==null){
@ -460,6 +507,9 @@ export default {
if(that.route_code=='niuzhuan'){
that.getEquipment4();
}
if(that.mgroupName=='喷码'){
that.getToolings();
}
if(that.qct!==''&&that.qct!==null){//
that.getdefects();
}else{
@ -486,6 +536,8 @@ export default {
}).catch(()=>{
that.getList();
})
}else{
that.getList();
}
}
that.visible = true;
@ -494,6 +546,9 @@ export default {
},500)
that.actionMenuClickHandler = (event) => that.handleDocumentClick(event);
document.addEventListener("click", that.actionMenuClickHandler, true);
that.ocr_ip = localStorage.getItem("ocr_ip") || "";
that.ocr_port = localStorage.getItem("ocr_port") || "";
that.ocr_unit = localStorage.getItem("ocr_unit") || "";
},
beforeUnmount() {
@ -502,6 +557,17 @@ export default {
}
},
methods: {
isColVisible(key) {
return !this.hiddenColumns.includes(key);
},
toggleColumn(key) {
const idx = this.hiddenColumns.indexOf(key);
if (idx > -1) {
this.hiddenColumns.splice(idx, 1);
} else {
this.hiddenColumns.push(key);
}
},
refreshfun(){
this.getList();
},
@ -515,7 +581,14 @@ export default {
if (event.target && event.target.closest(".action-more")) {
return;
}
if (event.target && event.target.closest(".col-setting-float-panel")) {
return;
}
this.openedActionMenu = null;
this.columnSettingVisible = false;
},
openColumnSetting() {
this.columnSettingVisible = !this.columnSettingVisible;
},
check_add(){
let that = this;
@ -551,6 +624,31 @@ export default {
that.optionsEq = res.reverse();
})
},
getToolings() {
let that = this;
that.$API.em.equipment.list.req({page:0,type:10,cate__code:"7",query:"{id,name,number}"}).then((res) => {
that.optionsTooling = Array.isArray(res) ? res : (res.results || []);
})
},
getToolingName(id) {
if (!id) return '';
const item = this.optionsTooling.find(t => t.id == id);
return item ? item.name : id;
},
autoSyncTooling() {
const that = this;
if (that.mgroupName !== '喷码') return;
that.mlogbwlist.forEach((row) => {
const wprTooling = row.wpr_pre_info?.tooling;
if (wprTooling && row.tooling != wprTooling && row.id) {
that.$API.wpm.mlogbw.update.req(row.id, { tooling: wprTooling,number:row.number,mlogb:row.mlogb }).then((res) => {
row.tooling = res.tooling;
row.tooling_name = res.tooling_name;
row.tooling_number = res.tooling_number;
}).catch(() => {});
}
});
},
getEquipments(){
let that = this;
that.$API.em.equipment.list.req({page:0,cate__code:"6"}).then((res) => {
@ -608,7 +706,6 @@ export default {
},
timeChange(row){
let that = this;
console.log('row',row)
let index = that.mlogbwlist.indexOf(row);
if(row.work_start_time!==''&&row.work_start_time!==null&&row.work_start_time!==undefined){
let waveNum = 1;
@ -690,6 +787,9 @@ export default {
that.mlogbwlist.push(obj);
})
}
that.$nextTick(() => {
that.autoSyncTooling();
});
})
},
widthFun(item){
@ -719,6 +819,9 @@ export default {
if(row.equip){
obj.equip = row.equip;
}
if(row.tooling){
obj.tooling = row.tooling;
}
//qct
if((that.qct!==''&&that.qct!==null)||(that.qctId!==''&&that.qctId!==null)){
obj.ftest = {};
@ -762,6 +865,8 @@ export default {
that.mlogbwlist[editIndex].isEdit = false;
that.mlogbwlist[editIndex].equip_name = res.equip_name;
that.mlogbwlist[editIndex].equip_number = res.equip_number;
that.mlogbwlist[editIndex].tooling_name = res.tooling_name;
that.mlogbwlist[editIndex].tooling_number = res.tooling_number;
that.mlogbwlist[editIndex].work_start_time = res.work_start_time;
// that.getList();
return res;
@ -778,6 +883,8 @@ export default {
that.mlogbwlist[editIndex].isEdit = false;
that.mlogbwlist[editIndex].equip_name = res.equip_name;
that.mlogbwlist[editIndex].equip_number = res.equip_number;
that.mlogbwlist[editIndex].tooling_name = res.tooling_name;
that.mlogbwlist[editIndex].tooling_number = res.tooling_number;
that.mlogbwlist[editIndex].work_start_time = res.work_start_time;
// that.getList();
return res;
@ -796,6 +903,12 @@ export default {
formTableEdit(index) {
let that = this;
that.mlogbwlist[index].isEdit = true;
if(that.mgroupName=='喷码'){
const wprTooling = that.mlogbwlist[index].wpr_pre_info?.tooling;
if(wprTooling && that.mlogbwlist[index].tooling != wprTooling){
that.mlogbwlist[index].tooling = wprTooling;
}
}
let date = new Date();
if(that.mlogbwlist[index].work_start_time==''||that.mlogbwlist[index].work_start_time==null){
that.mlogbwlist[index].work_start_time = that.$TOOL.dateFormat(date, 'yyyy-MM-dd hh:mm:ss');
@ -1013,6 +1126,93 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
that.wprNumber = "";
that.setVisible=true;
},
//numbernumber
digital(){
let that = this;
//number
if(!that.ocr_ip || !that.ocr_port || !that.ocr_unit){
that.$message.warning('请先在右上角"数字识别设置"配置IP、端口号和位号');
return;
}
that.$API.em.equipment.get_svs_char.req({
host: that.ocr_ip,
port: that.ocr_port,
flow_unit: that.ocr_unit
}).then((res) => {
if(res.char){
that.mlogbwlist.forEach((item,index) => {
if(item.number==res.char){
let obj = Object.assign({},item);S
obj.isEdit = true;
that.mlogbwlist.splice(index,1);
that.wprInputText = "";
that.mlogbwlist.unshift(obj);
that.$nextTick(() => {
that.selectedindexes.push(obj.id);
that.selectWprList.push(item);
})
//
//
if(that.qct_testitems.length>0 && !!that.setForm.cd_req_addr){
that.$API.em.cd.req({method:that.setForm.cd_req_addr}).then((res) => {
that.qct_testitems.forEach(item0 => {
if(item0.testitem_cd_expr!=null){
that.mlogbwlist[0][item0.testitem_name]= eval(item0.testitem_cd_expr);
item0.cd_expr = true;
that.qct_defects.forEach(item => {
if(item.rule_expression!==''&&item.rule_expression!==undefined&&item.rule_expression!==null){
let str = item.rule_expression.replace(/`/g, '');
str = str.replace(/\${(.*?)}/g, 'row.\$1');
let judge = false;
try {
judge = eval(str);
that.mlogbwlist[0][item.defect_name] = judge;
}catch (error) {
console.error(error);
}
}else{
that.mlogbwlist[0][item.defect_name] = false;
}
});
}
})
let arrs= that.qct_testitems.filter(item => item.testitem_cd_expr!=null)
if(arrs.length>0){
that.seveAuto(0);
}
}).catch((err) => {
this.$notify.error({
title: '获取数据失败',
message: err.data
})
return err;
});
}
}
})
}
}).catch((err) => {
that.$notify.error({
title: '数字识别获取失败',
message: err.data
})
return err;
});
},
seveAuto(index){
let that= this;
let arr2 = that.mlogbwlist.filter(item => item.cd_expr==true);
if(arr2.length>0){
that.formTableSave(that.mlogbwlist[index],index);
}else{
setTimeout(() => {
that.seveAuto(index);
}, 500);
}
},
//
wprinputChange(){
let that = this;
@ -1050,6 +1250,7 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
that.qct_testitems.forEach(item0 => {
if(item0.testitem_cd_expr!=null){
that.mlogbwlist[index][item0.testitem_name]= eval(item0.testitem_cd_expr);
that.mlogbwlist[index].cd_expr = true;
that.qct_defects.forEach(item => {
if(item.rule_expression!==''&&item.rule_expression!==undefined&&item.rule_expression!==null){
let str = item.rule_expression.replace(/`/g, '');
@ -1067,6 +1268,10 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
});
}
})
let arrs= that.qct_testitems.filter(item => {return item.testitem_cd_expr!=null;})
if(arrs.length>0){
that.seveAuto(index);
}
}).catch((err) => {
this.$notify.error({
title: '获取数据失败',
@ -1149,7 +1354,6 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
fullscreen: true,
text: "解析中...请稍等",
});
console.log(res);
this.$API.wpm.mlog.change.req(that.mlogId,{ test_file: res.path }).then((res) => {
loading.close();
this.$message.success("导入成功");
@ -1159,6 +1363,15 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
this.$message.error("导入失败,请重新尝试");
});
},
getDefectCount(defectName){
let count = 0;
this.mlogbwlist.forEach(row => {
if(row[defectName]){
count++;
}
});
return count;
},
hasNull(){
let that = this;
let canSubmit = true;
@ -1363,6 +1576,24 @@ tbody tr:nth-child(odd) .sticky-cell{
.more-menu-btn:hover{
background: #fef0f0;
}
.col-setting-float-panel{
position: absolute;
right: 0;
top: 35px;
z-index: 100;
background: #fff;
border: 1px solid #ebeef5;
border-radius: 4px;
box-shadow: 0 2px 12px rgba(0,0,0,0.12);
padding: 8px 12px;
min-width: 150px;
max-height: 300px;
overflow-y: auto;
}
.col-setting-item{
padding: 4px 0;
line-height: 1.6;
}
.btn{
margin:0 5px;
border: none;

View File

@ -15,14 +15,14 @@
<el-button
v-if="mgroupName=='喷码'"
type="success"
:disabled="selectedRows.length === 0"
:disabled="selectedRows.length === 0||batchCoderLoading2"
:loading="batchCoderLoading"
@click="batchSendToCoder"
>批量喷数字码</el-button>
<el-button
v-if="mgroupName=='喷码'"
type="primary"
:disabled="selectedRows.length === 0"
:disabled="selectedRows.length === 0||batchCoderLoading"
:loading="batchCoderLoading2"
@click="batchSendToCoder2"
>批量喷二维码</el-button>
@ -49,6 +49,26 @@
<el-table-column label="对外编号" prop="number_out" min-width="100px"
v-if="mgroupName=='成品内外初检'||mgroupName=='成品内质复检'||mgroupName=='成品性能检测'||mgroupName=='成品尺寸检测'||mgroupName=='成品外观复检一'||mgroupName=='成品外观复检二'"
></el-table-column>
<el-table-column label="工装" min-width="100px" v-if="mgroupName=='喷码'">
<template #default="scope">
<el-select
v-model="scope.row.pre_info.tooling"
placeholder="选择工装"
clearable
filterable
size="small"
style="width:100%"
@change="handleToolingChange(scope.row)"
>
<el-option
v-for="item in toolingOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="记录数据" prop="oinfo">
<template #default="scope">
<div v-for="(item,index) in scope.row.oinfo" :key="item.id">
@ -66,25 +86,7 @@
</span>
</template>
</el-table-column>
<el-table-column label="工装" min-width="80px" v-if="mgroupName=='喷码'">
<template #default="scope">
<el-select
v-model="scope.row.tooling"
placeholder="选择工装"
clearable
size="small"
style="width:100%"
@change="handleToolingChange(scope.row)"
>
<el-option
v-for="item in toolingOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column
label="操作"
fixed="right"
@ -93,7 +95,9 @@
>
<template #default="scope">
<el-button v-if="mode=='ins'&&mgroupName=='毛坯检测后打码'" @click="QRCode(scope.row)" type="success">二维码</el-button>
<el-button @click="printMaterial(scope.row)" type="primary" v-if="mode==!'ins'&&mgroupName!=='喷码'">打签</el-button>
<el-button v-if="mode=='ins'&&mgroupName=='毛坯检测'" @click="sendToMarker(scope.row)" type="success" :loading="!!markerLoadingIds[scope.row.id]" :disabled="!!markerLoadingIds[scope.row.id]">打码</el-button>
<span v-if="mode=='ins'&&mgroupName=='喷码'"></span>
<el-button v-else @click="printMaterial(scope.row)" type="primary">打签</el-button>
<el-button @click="sendToCoder(scope.row,'coder_jobname','coder_field')" type="success" v-if="mode=='ins'&&mgroupName=='喷码'" :loading="!!coderLoadingIds[scope.row.id]" :disabled="!!coderLoadingIds[scope.row.id]">喷数字码</el-button>
<el-button @click="sendToCoder(scope.row,'coder_jobname2','coder_field2')" type="primary" v-if="mode=='ins'&&mgroupName=='喷码'" :loading="!!coderLoadingIds[scope.row.id]" :disabled="!!coderLoadingIds[scope.row.id]">喷二维码</el-button>
</template>
@ -179,6 +183,7 @@ export default {
printer_name:localStorage.getItem("printer_name"),
apiObjPrint:this.$API.cm.labelmat.fromWm,
coderLoadingIds:{},
markerLoadingIds:{},
};
},
mounted() {
@ -195,7 +200,7 @@ export default {
this.params.wm = this.wm;
this.visible = true;
this.getRowWpr();
// this.getToolingOptions();
this.getToolingOptions();
that.$nextTick(() => {
let heights = document.getElementsByClassName("el-drawer__body")[0].clientHeight;
that.wprTableHeight = heights-20;
@ -205,18 +210,21 @@ export default {
getRowWpr(){
let that = this;
that.$API.wpm.wpr.list.req(that.params).then((res) => {
that.wprList = res;
that.wprList = (Array.isArray(res) ? res : []).map(row => ({
...row,
pre_info: row.pre_info || {},
}));
})
},
getToolingOptions(){
let that = this;
that.$API.mtm.tooling.list.req({ page: 0}).then((res) => {
that.$API.em.equipment.list.req({ page: 0,type:10,cate__code:'7'}).then((res) => {
that.toolingOptions = Array.isArray(res) ? res : (res.results || []);
});
},
handleToolingChange(row){
let that = this;
that.$API.wpm.wpr.update.req(row.id,{tooling:row.tooling}).then(() => {
that.$API.wpm.wpr.update.req(row.id,{pre_info:{tooling:row.pre_info.tooling}}).then(() => {
that.$message.success("工装更新成功");
});
},
@ -346,7 +354,7 @@ export default {
obj.printer_commands = res.commands;
obj.printer_name = that.printer_name;
let printer_ip=localStorage.getItem("printer_ip")||'127.0.0.1';
that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
that.$message.success("打印成功");
});
});
@ -386,14 +394,14 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
params.data = data;
}else{
params.label_template_name = '单件打印模板';
params.data = {number:row.number,name:name};
params.data = {number:row.number,name:name,oname:that.ofromName};
}
that.$API.cm.labeltemplate.commands.req(params).then((res) => {
let obj = {};
obj.printer_commands = res.commands;
obj.printer_name = that.printer_name;
let printer_ip=localStorage.getItem("printer_ip")||'127.0.0.1';
that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
that.$message.success("打印成功");
});
});
@ -474,6 +482,41 @@ that.$API.wpm.prints.req(printer_ip, obj).then((response) => {
return that.$API.cm.labeltemplate.sendToCoder.req(template.id, body);
});
},
//: 1
sendToMarker(row){
let that = this;
if (that.markerLoadingIds[row.id]) return;
let marker_ip = localStorage.getItem('marker_ip') || '';
if (!marker_ip) {
that.$message.error('请先在右上角"打码设置"配置打码IP');
return;
}
let release = () => {
let map = { ...that.markerLoadingIds };
delete map[row.id];
that.markerLoadingIds = map;
};
that.markerLoadingIds = { ...that.markerLoadingIds, [row.id]: true };
let templateName = '打码模板';
that.$API.cm.labeltemplate.list.req({name: templateName, page: 0}).then((res) => {
let list = Array.isArray(res) ? res : (res && res.results) || [];
let template = list.find(t => t.name === templateName);
if (!template) {
that.$message.error(`未找到标签模板: ${templateName}`);
return Promise.reject(new Error('no template'));
}
let body = { tdata_list: [{number: row.number}], coder_ip: marker_ip,coder_port:null };
let marker_port = localStorage.getItem('marker_port') || '';
let marker_jobname = localStorage.getItem('marker_jobname') || '';
if (marker_port) body.coder_port = Number(marker_port);
if (marker_jobname) body.coder_jobname = marker_jobname;
return that.$API.cm.labeltemplate.sendToHanslaser.req(template.id, body);
}).then(() => {
that.$message.success('打码下发成功');
}).catch(e => {
if (e && e.message !== 'no template') that.$message.error('打码下发失败');
}).finally(release);
},
openSplit() {
let that = this;
let data = {

View File

@ -6,282 +6,312 @@
style="width: 90%;"
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
label-position="right"
label-width="100px"
style="padding: 0"
>
<el-row>
<el-col v-if="route==null&&!is_fix">
<el-form-item label="工艺步骤">
<el-select
v-model="form.route"
placeholder="工艺步骤"
clearable
filterable
style="width: 100%"
@change="changeRoute"
>
<el-option
v-for="item in routeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span>[{{ item.routepack_name }}]{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="批次号" prop="wm_in">
<xtSelect
:apiObj="apiObj"
:params="params"
v-model="form.wm_in"
:labelField="'batch'"
v-model:obj="materialrow"
v-model:label="form.batch"
style="width:100%"
@change="materialChange"
>
<el-table-column label="批次号" prop="batch"></el-table-column>
<el-table-column label="名称" prop="material_name"></el-table-column>
<el-table-column label="数量" prop="count"></el-table-column>
<el-table-column label="不良项" prop="defect_name"></el-table-column>
</xtSelect>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="班组">
<el-select
v-model="form.team"
placeholder="班组"
:disabled="mode == 'edit'"
style="width: 100%"
@change="teamChange"
>
<el-option
v-for="item in teamOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="生产设备">
<el-select
v-model="form.equipment"
placeholder="生产设备"
clearable
filterable
class="width100"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.label"
:value="item.id"
>
<span style="float:left">{{item.name}}</span>
<span style="float:right">{{item.number}}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<!-- 操作员多选 -->
<el-col :md="12" :sm="24" v-if="route_code=='saobian'||route_code=='saobianb'||route_code=='chengpinpao'">
<el-form-item label="操作员">
<el-select
v-model="form.handle_users"
placeholder="操作员"
clearable
filterable
multiple
class="width100"
@change="handleUsersChange"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-else>
<el-form-item label="操作员">
<el-select
v-model="form.handle_user"
placeholder="操作员"
clearable
filterable
class="width100"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="12" :xs="24" v-for="item in testitems" :key="item.id">
<el-form-item :label="item.name">
<el-input-number
v-if="item.field_type=='input-number'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input-number
v-if="item.field_type=='input-int'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input
v-if="item.field_type=='input-text'"
v-model="item.value"
class="width-100"
>
</el-input>
<el-select
v-if="item.field_type=='select-text'"
v-model="item.value"
clearable
class="width-100"
>
<el-option
v-for="item0 in item.choices"
:key="item0"
:label="item0"
:value="item0"
>
</el-option>
</el-select>
<el-select
v-if="item.field_type=='selects-text'"
v-model="item.value"
clearable
multiple
class="width-100"
>
<el-option
v-for="item1 in item.choices"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupName=='成品抛'">
<el-form-item label="批次序号">
<el-input-number
v-model="form.index"
:min="0"
:max="99"
placeholder="第几炉,追加到批次"
style="width: 100%"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item
label="开始时间"
prop="work_start_time"
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
label-position="right"
label-width="100px"
style="padding: 0"
>
<el-row>
<el-col v-if="route==null&&!is_fix">
<el-form-item label="工艺步骤">
<el-select
v-model="form.route"
placeholder="工艺步骤"
clearable
filterable
style="width: 100%"
@change="changeRoute"
>
<el-option
v-for="item in routeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<el-date-picker
v-model="form.work_start_time"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="领用数量">
<span>[{{ item.routepack_name }}]{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="批次号" prop="wm_in">
<xtSelect
:apiObj="apiObj"
:params="params"
v-model="form.wm_in"
:labelField="'batch'"
v-model:obj="materialrow"
v-model:label="form.batch"
style="width:100%"
@change="materialChange"
>
<el-table-column label="批次号" prop="batch"></el-table-column>
<el-table-column label="名称" prop="material_name"></el-table-column>
<el-table-column label="数量" prop="count"></el-table-column>
<el-table-column label="不良项" prop="defect_name"></el-table-column>
</xtSelect>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="班组">
<el-select
v-model="form.team"
placeholder="班组"
:disabled="mode == 'edit'"
style="width: 100%"
@change="teamChange"
>
<el-option
v-for="item in teamOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="生产设备">
<el-select
v-model="form.equipment"
placeholder="生产设备"
clearable
filterable
class="width100"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.label"
:value="item.id"
>
<span style="float:left">{{item.name}}</span>
<span style="float:right">{{item.number}}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<!-- 操作员多选 -->
<el-col :md="12" :sm="24" v-if="route_code=='saobian'||route_code=='saobianb'||route_code=='chengpinpao'">
<el-form-item label="操作员">
<el-select
v-model="form.handle_users"
placeholder="操作员"
clearable
filterable
multiple
class="width100"
@change="handleUsersChange"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-else>
<el-form-item label="操作员">
<el-select
v-model="form.handle_user"
placeholder="操作员"
clearable
filterable
class="width100"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="12" :xs="24" v-for="item in testitems" :key="item.id">
<el-form-item :label="item.name">
<el-input-number
v-if="item.field_type=='input-number'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input-number
v-if="item.field_type=='input-int'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input
v-if="item.field_type=='input-text'"
v-model="item.value"
class="width-100"
>
</el-input>
<el-select
v-if="item.field_type=='select-text'"
v-model="item.value"
clearable
class="width-100"
>
<el-option
v-for="item0 in item.choices"
:key="item0"
:label="item0"
:value="item0"
>
</el-option>
</el-select>
<el-select
v-if="item.field_type=='selects-text'"
v-model="item.value"
clearable
multiple
class="width-100"
>
<el-option
v-for="item1 in item.choices"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupName=='成品抛'">
<el-form-item label="批次序号">
<el-input-number
v-model="form.index"
:min="0"
:max="99"
placeholder="第几炉,追加到批次"
style="width: 100%"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item
label="开始时间"
prop="work_start_time"
>
<el-date-picker
v-model="form.work_start_time"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="领用数量">
<el-input-number
v-model="form.count_use"
:min="0"
controls-position="right"
class="width100"
@change = "countUseChange"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="加工前不良" prop="count_pn_jgqbl">
<el-input-number
v-model="form.count_pn_jgqbl"
:min="0"
class="width100"
:disabled="true"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="实际生产数">
<el-input-number
v-model="form.count_real"
:min="0"
class="width100"
controls-position="right"
:disabled="true"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="合格数量">
<el-input-number
v-model="form.count_ok"
class="width100"
:disabled="true"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="不合格数量">
<el-input-number
v-model="form.count_notok"
:disabled="true"
class="width100"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="备注">
<el-input
v-model="form.note"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-divider></el-divider>
<el-row v-if="is_fix">
<el-col style="padding-left: 10px;">不良记录</el-col>
<el-col :md="6" :sm="12" v-for="item in qct_defects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="defectform[item.defect_name]"
:min="0"
class="width-100"
controls-position="right"
@change="countChange"
/>
</el-form-item>
</el-col>
</el-row>
<el-row v-else>
<el-col :span=12>
<el-col>加工前不良</el-col>
<el-row style="width: 98%;">
<el-col :md="12" :sm="24" v-for="item in qct_indefects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="form.count_use"
v-model="defectinform[item.defect_name]"
:min="0"
style="width:100%"
controls-position="right"
class="width100"
@change = "countUseChange"
@change="countinChange"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="加工前不良" prop="count_pn_jgqbl">
<el-input-number
v-model="form.count_pn_jgqbl"
:min="0"
class="width100"
:disabled="true"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="实际生产数">
<el-input-number
v-model="form.count_real"
:min="0"
class="width100"
controls-position="right"
:disabled="true"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="合格数量">
<el-input-number
v-model="form.count_ok"
class="width100"
:disabled="true"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="不合格数量">
<el-input-number
v-model="form.count_notok"
:disabled="true"
class="width100"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="备注">
<el-input
v-model="form.note"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-divider></el-divider>
<el-row v-if="is_fix">
<el-col style="padding-left: 10px;">不良记录</el-col>
<el-col :md="6" :sm="12" v-for="item in qct_defects" :key="item.id">
</el-col>
<el-col :span=12 style="border-left:dotted 1px #ccc;">
<el-col style="padding-left: 10px;">本工段不良</el-col>
<el-row style="width: 98%;">
<el-col :md="12" :sm="24" v-for="item in qct_defects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="defectform[item.defect_name]"
@ -293,49 +323,15 @@
</el-form-item>
</el-col>
</el-row>
<el-row v-else>
<el-col :span=12>
<el-col>加工前不良</el-col>
<el-row style="width: 98%;">
<el-col :md="12" :sm="24" v-for="item in qct_indefects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="defectinform[item.defect_name]"
:min="0"
style="width:100%"
controls-position="right"
@change="countinChange"
/>
</el-form-item>
</el-col>
</el-row>
</el-col>
<el-col :span=12 style="border-left:dotted 1px #ccc;">
<el-col style="padding-left: 10px;">本工段不良</el-col>
<el-row style="width: 98%;">
<el-col :md="12" :sm="24" v-for="item in qct_defects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="defectform[item.defect_name]"
:min="0"
class="width-100"
controls-position="right"
@change="countChange"
/>
</el-form-item>
</el-col>
</el-row>
</el-col>
</el-row>
</el-form>
</el-main>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit"
>保存</el-button
>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-container>
</el-col>
</el-row>
</el-form>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit"
>保存</el-button
>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-dialog>
</template>

View File

@ -6,265 +6,261 @@
style="width: 80%;"
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0 20px 20px 20px">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
label-position="right"
label-width="80px"
style="padding: 0 10px"
>
<el-row>
<el-col :md="12" :sm="24" v-if="mgroupMtype == 20">
<el-form-item
label="外协单位"
prop="supplier"
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
label-position="right"
label-width="80px"
style="padding: 0 10px"
>
<el-row>
<el-col :md="12" :sm="24" v-if="mgroupMtype == 20">
<el-form-item
label="外协单位"
prop="supplier"
>
<el-select
v-model="form.supplier"
placeholder="外协单位"
clearable
:disabled="mode == 'edit'"
style="width: 100%"
>
<el-option
v-for="item in supplierOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mlogtype!=='rework'">
<el-form-item label="工艺步骤">
<el-select
v-model="form.route"
placeholder="工艺步骤"
clearable
filterable
style="width: 100%"
:disabled="mode == 'edit'"
>
<el-option
v-for="item in routeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<el-select
v-model="form.supplier"
placeholder="外协单位"
clearable
:disabled="mode == 'edit'"
style="width: 100%"
>
<el-option
v-for="item in supplierOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mlogtype!=='rework'">
<el-form-item label="工艺步骤">
<el-select
v-model="form.route"
placeholder="工艺步骤"
clearable
filterable
style="width: 100%"
:disabled="mode == 'edit'"
>
<el-option
v-for="item in routeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span>[{{ item.routepack_name }}]{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="班组">
<el-select
v-model="form.team"
placeholder="班组"
:disabled="mode == 'edit'"
style="width: 100%"
>
<el-option
v-for="item in teamOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupName=='磨抛一次抛'">
<el-form-item label="批次序号">
<el-input-number
v-model="form.index"
:min="0"
:max="99"
placeholder="第几炉,追加到批次"
style="width: 100%"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item
label="开始时间"
prop="work_start_time"
<span>[{{ item.routepack_name }}]{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="班组">
<el-select
v-model="form.team"
placeholder="班组"
:disabled="mode == 'edit'"
style="width: 100%"
>
<el-option
v-for="item in teamOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<el-date-picker
:disabled="mode == 'edit'"
v-model="form.work_start_time"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mode == 'edit'">
<el-form-item label="结束时间" prop="work_end_time">
<el-date-picker
v-model="form.work_end_time"
type="datetime"
:disabledDate="disabledDateFn"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="route_code=='chaoxi'||route_code=='chaoxi2'||route_code=='chaoxi3'">
<el-form-item label="操作人">
<el-select
v-model="form.handle_users"
placeholder="操作人"
clearable
filterable
multiple
:disabled="mode == 'edit'"
style="width: 100%"
@change="handleUsersChange"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-else>
<el-form-item label="操作人">
<el-select
v-model="form.handle_user"
placeholder="操作人"
:disabled="mode == 'edit'"
style="width: 100%"
filterable
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="生产设备">
<el-select
v-model="form.equipment"
placeholder="生产设备"
clearable
filterable
:disabled="mode == 'edit'"
style="width: 100%"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.label"
:value="item.id"
>
<span style="float:left">{{item.name}}</span>
<span style="float:right">{{item.number}}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<!-- 黑化 -->
<el-col :md="12" :sm="24" v-if="mgroupName=='黑化'">
<el-form-item label="检验文件">
<sc-upload-file
v-model="fileList"
:multiple="false"
:limit="1"
:accept="['.xlsx', '.xls']"
@success = "fileUPSuccess"
>
<el-button type="primary" icon="el-icon-upload"> </el-button>
</sc-upload-file>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :md="8" :sm="12" :xs="24" v-for="item in testitems" :key="item.id">
<el-form-item :label="item.name">
<el-input-number
v-if="item.field_type=='input-number'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input-number
v-if="item.field_type=='input-int'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input
v-if="item.field_type=='input-text'"
v-model="item.value"
class="width-100"
>
</el-input>
<el-select
v-if="item.field_type=='select-text'"
v-model="item.value"
clearable
class="width-100"
>
<el-option
v-for="item0 in item.choices"
:key="item0"
:label="item0"
:value="item0"
>
</el-option>
</el-select>
<el-select
v-if="item.field_type=='selects-text'"
v-model="item.value"
clearable
multiple
class="width-100"
>
<el-option
v-for="item1 in item.choices"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :md="12" :sm="24">
<el-form-item label="备注">
<el-input
v-model="form.note"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-main>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit">保存</el-button>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-container>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupName=='磨抛一次抛'">
<el-form-item label="批次序号">
<el-input-number
v-model="form.index"
:min="0"
:max="99"
placeholder="第几炉,追加到批次"
style="width: 100%"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item
label="开始时间"
prop="work_start_time"
>
<el-date-picker
:disabled="mode == 'edit'"
v-model="form.work_start_time"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mode == 'edit'">
<el-form-item label="结束时间" prop="work_end_time">
<el-date-picker
v-model="form.work_end_time"
type="datetime"
:disabledDate="disabledDateFn"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="route_code=='chaoxi'||route_code=='chaoxi2'||route_code=='chaoxi3'">
<el-form-item label="操作人">
<el-select
v-model="form.handle_users"
placeholder="操作人"
clearable
filterable
multiple
:disabled="mode == 'edit'"
style="width: 100%"
@change="handleUsersChange"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-else>
<el-form-item label="操作人">
<el-select
v-model="form.handle_user"
placeholder="操作人"
:disabled="mode == 'edit'"
style="width: 100%"
filterable
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="生产设备">
<el-select
v-model="form.equipment"
placeholder="生产设备"
clearable
filterable
:disabled="mode == 'edit'"
style="width: 100%"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.label"
:value="item.id"
>
<span style="float:left">{{item.name}}</span>
<span style="float:right">{{item.number}}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<!-- 黑化 -->
<el-col :md="12" :sm="24" v-if="mgroupName=='黑化'">
<el-form-item label="检验文件">
<sc-upload-file
v-model="fileList"
:multiple="false"
:limit="1"
:accept="['.xlsx', '.xls']"
@success = "fileUPSuccess"
>
<el-button type="primary" icon="el-icon-upload"> </el-button>
</sc-upload-file>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :md="8" :sm="12" :xs="24" v-for="item in testitems" :key="item.id">
<el-form-item :label="item.name">
<el-input-number
v-if="item.field_type=='input-number'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input-number
v-if="item.field_type=='input-int'"
v-model="item.value"
:min="0"
class="width-100"
controls-position="right"
>
</el-input-number>
<el-input
v-if="item.field_type=='input-text'"
v-model="item.value"
class="width-100"
>
</el-input>
<el-select
v-if="item.field_type=='select-text'"
v-model="item.value"
clearable
class="width-100"
>
<el-option
v-for="item0 in item.choices"
:key="item0"
:label="item0"
:value="item0"
>
</el-option>
</el-select>
<el-select
v-if="item.field_type=='selects-text'"
v-model="item.value"
clearable
multiple
class="width-100"
>
<el-option
v-for="item1 in item.choices"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :md="12" :sm="24">
<el-form-item label="备注">
<el-input
v-model="form.note"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit">保存</el-button>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-dialog>
</template>

View File

@ -6,185 +6,181 @@
destroy-on-close
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0 0 20px 0">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
label-position="right"
label-width="100px"
>
<el-row>
<el-col v-if="!hasRoute&&!is_fix">
<el-form-item label="工艺步骤" prop="route">
<el-select
v-model="form.route"
placeholder="工艺步骤"
clearable
filterable
style="width: 100%"
:disabled="mode == 'edit'"
@change="routeChange"
>
<el-option
v-for="item in routeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span>[{{ item.routepack_name }}]{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="批次号" prop="wm_in">
<xtSelect
:apiObj="apiObjM"
v-model="form.wm_in"
v-model:obj="selectObj"
v-model:label="wmInLabel"
:labelField="'batch'"
style="width: 100%;"
:params = "paramsM"
@change="materialBatchChange"
>
<!-- :params = "{type__in: '10,20',is_hidden: false}" -->
<el-table-column label="物料" prop="full_name">
<template #default="scope">
<span v-if="scope.row.state==20" style="color: red;border: 1px solid red;border-radius: 3px;">不合格</span>
<span v-if="scope.row.state==30" style="color: orange;border: 1px solid orange;border-radius: 3px;">返工</span>
<span>{{ scope.row.batch }}({{ scope.row.material_name }})</span>
<el-tag v-if="scope.row.defect_name" type="warning" size="small" effect="plain" style="margin-left: 8px;">{{ scope.row.defect_name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="车间库存" prop="count" width="110px"></el-table-column>
<el-table-column label="可用数量" prop="count_cando" width="110px"></el-table-column>
</xtSelect>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="关联任务">
<el-select
v-model="form.mtask"
placeholder="关联任务"
clearable
style="width: 100%"
@change="getMaterial"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.number"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupName=='黑化'||mgroupName=='退火'">
<el-form-item label="进炉数">
<el-input-number
v-model="batch_count"
class="width-100"
:disabled="true"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item :label="mgroupMtype==10?'领用数量':'批次总数'">
<el-input-number
v-model="form.count_use"
:max="selectObj.count_cando"
:min="0"
class="width-100"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupMtype==10">
<el-form-item label="加工前不良" prop="count_pn_jgqbl">
<el-input-number
v-model="form.count_pn_jgqbl"
:min="0"
:disabled="true"
style="width: 100%"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="备注">
<el-input v-model="form.note"/>
</el-form-item>
</el-col>
</el-row>
<el-divider v-if="(mgroupName=='黑化'||mgroupName=='退火')&&cellsList.length>0"></el-divider>
<el-button
v-if="mgroupName=='黑化'||mgroupName=='退火'"
icon="el-icon-plus"
type="primary"
@click="cellsAdd"
></el-button>
<template v-if="mgroupName=='黑化'||mgroupName=='退火'">
<el-row v-for="(item,$index) in cellsList" :key="item">
<el-col style="display: flex;">
<el-form-item label="第" label-width="50">
<el-input-number
v-model="item.start"
:min="1"
placeholder="层数"
controls-position="right"
/>
</el-form-item>
<el-form-item label="层到第" label-width="65">
<el-input-number
v-model="item.end"
:min="1"
placeholder="层数"
controls-position="right"
/>
</el-form-item>
<el-form-item label="层,总数:" label-width="80">
<el-input-number
v-model="item.count_t"
:min="0"
placeholder="总数量"
controls-position="right"
@change="countTotalChange"
/>
</el-form-item>
<el-button
type="danger"
style="margin: 0 20px;"
@click="cellsDel($index)">删除</el-button>
</el-col>
</el-row>
</template>
<el-divider v-if="qct_defects.length>0"></el-divider>
<el-row>
<el-col :md="12" :sm="24" v-for="item in qct_defects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="defectform[item.defect_name]"
:min="0"
style="width: 100%"
controls-position="right"
@change="countChange"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-main>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit">保存</el-button>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-container>
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
label-position="right"
label-width="100px"
>
<el-row>
<el-col v-if="!hasRoute&&!is_fix">
<el-form-item label="工艺步骤" prop="route">
<el-select
v-model="form.route"
placeholder="工艺步骤"
clearable
filterable
style="width: 100%"
:disabled="mode == 'edit'"
@change="routeChange"
>
<el-option
v-for="item in routeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span>[{{ item.routepack_name }}]{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="批次号" prop="wm_in">
<xtSelect
:apiObj="apiObjM"
v-model="form.wm_in"
v-model:obj="selectObj"
v-model:label="wmInLabel"
:labelField="'batch'"
style="width: 100%;"
:params = "paramsM"
@change="materialBatchChange"
>
<!-- :params = "{type__in: '10,20',is_hidden: false}" -->
<el-table-column label="物料" prop="full_name">
<template #default="scope">
<span v-if="scope.row.state==20" style="color: red;border: 1px solid red;border-radius: 3px;">不合格</span>
<span v-if="scope.row.state==30" style="color: orange;border: 1px solid orange;border-radius: 3px;">返工</span>
<span>{{ scope.row.batch }}({{ scope.row.material_name }})</span>
<el-tag v-if="scope.row.defect_name" type="warning" size="small" effect="plain" style="margin-left: 8px;">{{ scope.row.defect_name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="车间库存" prop="count" width="110px"></el-table-column>
<el-table-column label="可用数量" prop="count_cando" width="110px"></el-table-column>
</xtSelect>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="关联任务">
<el-select
v-model="form.mtask"
placeholder="关联任务"
clearable
style="width: 100%"
@change="getMaterial"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.number"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupName=='黑化'||mgroupName=='退火'">
<el-form-item label="进炉数">
<el-input-number
v-model="batch_count"
class="width-100"
:disabled="true"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item :label="mgroupMtype==10?'领用数量':'批次总数'">
<el-input-number
v-model="form.count_use"
:max="selectObj.count_cando"
:min="0"
class="width-100"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24" v-if="mgroupMtype==10">
<el-form-item label="加工前不良" prop="count_pn_jgqbl">
<el-input-number
v-model="form.count_pn_jgqbl"
:min="0"
:disabled="true"
style="width: 100%"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :md="12" :sm="24">
<el-form-item label="备注">
<el-input v-model="form.note"/>
</el-form-item>
</el-col>
</el-row>
<el-divider v-if="(mgroupName=='黑化'||mgroupName=='退火')&&cellsList.length>0"></el-divider>
<el-button
v-if="mgroupName=='黑化'||mgroupName=='退火'"
icon="el-icon-plus"
type="primary"
@click="cellsAdd"
></el-button>
<template v-if="mgroupName=='黑化'||mgroupName=='退火'">
<el-row v-for="(item,$index) in cellsList" :key="item">
<el-col style="display: flex;">
<el-form-item label="第" label-width="50">
<el-input-number
v-model="item.start"
:min="1"
placeholder="层数"
controls-position="right"
/>
</el-form-item>
<el-form-item label="层到第" label-width="65">
<el-input-number
v-model="item.end"
:min="1"
placeholder="层数"
controls-position="right"
/>
</el-form-item>
<el-form-item label="层,总数:" label-width="80">
<el-input-number
v-model="item.count_t"
:min="0"
placeholder="总数量"
controls-position="right"
@change="countTotalChange"
/>
</el-form-item>
<el-button
type="danger"
style="margin: 0 20px;"
@click="cellsDel($index)">删除</el-button>
</el-col>
</el-row>
</template>
<el-divider v-if="qct_defects.length>0"></el-divider>
<el-row>
<el-col :md="12" :sm="24" v-for="item in qct_defects" :key="item.id">
<el-form-item :label="item.defect_name">
<el-input-number
v-model="defectform[item.defect_name]"
:min="0"
style="width: 100%"
controls-position="right"
@change="countChange"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit">保存</el-button>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-dialog>
</template>