You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
14 KiB
JavaScript
159 lines
14 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const b = 'D:/opencode/haoliang/frontend/src/views';
|
|
function w(d, f, c) { fs.writeFileSync(path.join(b, d, f), c, 'utf8'); console.log('OK: ' + d + '/' + f); }
|
|
|
|
// WorkerListPage
|
|
w('worker', 'WorkerListPage.vue', `<template>
|
|
<div>
|
|
<div style="margin-bottom:16px"><el-button type="primary" @click="handleAdd">+ 新增工人</el-button></div>
|
|
<el-form :inline="true" style="margin-bottom:16px">
|
|
<el-form-item label="状态"><el-select v-model="query.isEnabled" clearable><el-option label="启用" :value="1"/><el-option label="停用" :value="0"/></el-select></el-form-item>
|
|
<el-form-item><el-input v-model="query.keyword" placeholder="工号/姓名" clearable/></el-form-item>
|
|
<el-form-item><el-button type="primary" @click="loadData">查询</el-button><el-button @click="query={};loadData()">重置</el-button></el-form-item>
|
|
</el-form>
|
|
<el-table :data="tableData" border stripe v-loading="loading">
|
|
<el-table-column type="selection" width="40"/>
|
|
<el-table-column prop="code" label="工号" width="120"/>
|
|
<el-table-column prop="name" label="姓名" width="120"><template #default="{row}"><el-link type="primary" @click="goDetail(row.id)">{{row.name}}</el-link></template></el-table-column>
|
|
<el-table-column label="状态" width="80" align="center"><template #default="{row}"><el-tag :type="row.isEnabled?'success':'danger'" size="small">{{row.isEnabled?'启用':'停用'}}</el-tag></template></el-table-column>
|
|
<el-table-column prop="machineCount" label="绑定机床数" width="100" align="center"/>
|
|
<el-table-column prop="machineNames" label="绑定机床" show-overflow-tooltip/>
|
|
<el-table-column label="操作" width="120" align="center"><template #default="{row}">
|
|
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
|
<el-button link type="danger" @click="handleDelete(row)" :disabled="row.machineCount>0">删除</el-button>
|
|
</template></el-table-column>
|
|
</el-table>
|
|
<div v-if="selectedRows.length" style="margin-top:12px;padding:8px 12px;background:#ecf5ff;border-radius:4px">
|
|
已选{{selectedRows.length}}项 <el-button size="small" @click="batchStatus(1)">批量启用</el-button><el-button size="small" @click="batchStatus(0)">批量停用</el-button>
|
|
</div>
|
|
<el-dialog v-model="dialogVisible" :title="editingId?'编辑工人':'新增工人'" width="500px" destroy-on-close>
|
|
<el-form :model="form" label-width="100px">
|
|
<el-form-item label="工号" required><el-input v-model="form.code" maxlength="50"/></el-form-item>
|
|
<el-form-item label="姓名" required><el-input v-model="form.name" maxlength="50"/></el-form-item>
|
|
<el-form-item label="绑定机床"><el-select v-model="form.machineIds" multiple filterable><el-option v-for="m in availableMachines" :key="m.id" :label="m.name" :value="m.id"/></el-select></el-form-item>
|
|
</el-form>
|
|
<template #footer><el-button @click="dialogVisible=false">取消</el-button><el-button type="primary" :loading="submitting" @click="handleSubmit">保存</el-button></template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import {ref,reactive,onMounted} from 'vue'
|
|
import {useRouter} from 'vue-router'
|
|
import {ElMessage,ElMessageBox} from 'element-plus'
|
|
import request from '@/utils/request'
|
|
import {useMockMode} from '@/composables/useMockMode'
|
|
const router=useRouter();const{isMock}=useMockMode()
|
|
const loading=ref(false);const tableData=ref<any[]>([]);const selectedRows=ref<any[]>([])
|
|
const dialogVisible=ref(false);const submitting=ref(false);const editingId=ref<number|null>(null)
|
|
const availableMachines=ref<any[]>([])
|
|
const query=reactive({isEnabled:undefined as any,keyword:''})
|
|
const form=reactive({code:'',name:'',machineIds:[] as number[]})
|
|
function goDetail(id:number){router.push((isMock.value?'/mock/worker/':'/worker/')+id)}
|
|
async function loadData(){loading.value=true;try{const r:any=await request.get('/admin/worker',{params:query});tableData.value=r.data?.items||[]}finally{loading.value=false}}
|
|
function handleAdd(){editingId.value=null;Object.assign(form,{code:'',name:'',machineIds:[]});dialogVisible.value=true}
|
|
function handleEdit(row:any){editingId.value=row.id;Object.assign(form,{code:row.code,name:row.name,machineIds:[]});dialogVisible.value=true}
|
|
async function handleSubmit(){submitting.value=true;try{await request.post(editingId.value?'/admin/worker/update':'/admin/worker',{...form,id:editingId.value});ElMessage.success('保存成功');dialogVisible.value=false;loadData()}finally{submitting.value=false}}
|
|
async function handleDelete(row:any){await ElMessageBox.confirm('确定删除【'+row.name+'】?此操作不可恢复。','提示',{type:'warning'});await request.post('/admin/worker/delete',{id:row.id});ElMessage.success('已删除');loadData()}
|
|
async function batchStatus(isEnabled:number){await ElMessageBox.confirm('确定对选中的'+selectedRows.value.length+'项操作?','提示',{type:'warning'});await request.post('/admin/worker/batch-status',{ids:selectedRows.value.map((r:any)=>r.id),isEnabled});ElMessage.success('操作成功');loadData()}
|
|
async function loadDrops(){const r:any=await request.get('/admin/worker/available-machines');availableMachines.value=r.data?.items||[]}
|
|
onMounted(()=>{loadData();loadDrops()})
|
|
</script>`);
|
|
|
|
// WorkerDetailPage
|
|
w('worker', 'WorkerDetailPage.vue', `<template>
|
|
<div>
|
|
<div style="display:flex;align-items:center;gap:12px;margin-bottom:20px">
|
|
<el-button @click="$router.back()"><el-icon><ArrowLeft /></el-icon> 返回</el-button>
|
|
<span style="font-size:16px;font-weight:bold">工人详情:{{detail.name}}</span>
|
|
</div>
|
|
<el-row :gutter="20">
|
|
<el-col :span="12"><el-card shadow="hover"><template #header><span>基本信息</span></template>
|
|
<el-descriptions :column="2" border size="small">
|
|
<el-descriptions-item label="工号">{{detail.code}}</el-descriptions-item>
|
|
<el-descriptions-item label="姓名">{{detail.name}}</el-descriptions-item>
|
|
<el-descriptions-item label="状态"><el-tag :type="detail.isEnabled?'success':'danger'" size="small">{{detail.isEnabled?'启用':'停用'}}</el-tag></el-descriptions-item>
|
|
<el-descriptions-item label="绑定机床数">{{detail.machineCount||0}}</el-descriptions-item>
|
|
</el-descriptions>
|
|
</el-card></el-col>
|
|
<el-col :span="12"><el-card shadow="hover"><template #header><span>7天产量趋势</span></template>
|
|
<div ref="chartRef" style="height:200px"></div>
|
|
</el-card></el-col>
|
|
</el-row>
|
|
<el-card shadow="hover" style="margin-top:20px"><template #header><span>绑定机床</span></template>
|
|
<el-table :data="machines" border stripe size="small">
|
|
<el-table-column prop="machineName" label="机床名称"/><el-table-column prop="deviceCode" label="device_code"/><el-table-column prop="workshopName" label="车间"/><el-table-column prop="brandName" label="品牌"/>
|
|
<el-table-column label="在线" align="center"><template #default="{row}"><el-tag :type="row.isOnline?'success':'danger'" size="small">{{row.isOnline?'在线':'离线'}}</el-tag></template></el-table-column>
|
|
<el-table-column prop="programName" label="当前程序"/>
|
|
</el-table>
|
|
</el-card>
|
|
<el-card shadow="hover" style="margin-top:20px"><template #header><span>今日产量</span></template>
|
|
<el-table :data="todayProd" border stripe size="small">
|
|
<el-table-column prop="machineName" label="机床名称"/><el-table-column prop="programName" label="程序名"/><el-table-column prop="quantity" label="产量" align="center"/><el-table-column prop="runTime" label="运行时间" align="center"/><el-table-column prop="cuttingTime" label="切削时间" align="center"/>
|
|
</el-table>
|
|
</el-card>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import {ref,onMounted,nextTick,onBeforeUnmount} from 'vue'
|
|
import {useRoute} from 'vue-router'
|
|
import request from '@/utils/request'
|
|
import * as echarts from 'echarts'
|
|
const route=useRoute()
|
|
const detail=ref<any>({});const machines=ref<any[]>([]);const todayProd=ref<any[]>([])
|
|
const chartRef=ref<HTMLElement>();let chart:echarts.ECharts|null=null
|
|
async function loadData(){
|
|
const id=route.params.id
|
|
const[d,m,t]:any[]=await Promise.all([request.get('/admin/worker/detail',{params:{id}}),request.get('/admin/worker/machines',{params:{id}}),request.get('/admin/worker/production/today',{params:{id}})])
|
|
detail.value=d.data||{};machines.value=m.data?.items||[];todayProd.value=t.data?.items||[]
|
|
const trend:any=await request.get('/admin/worker/production/trend',{params:{id}})
|
|
await nextTick()
|
|
if(chartRef.value){chart=echarts.init(chartRef.value);const items=trend.data?.items||[];chart.setOption({xAxis:{type:'category',data:items.map((i:any)=>i.date.slice(5))},yAxis:{type:'value'},series:[{type:'line',data:items.map((i:any)=>i.quantity),smooth:true,areaStyle:{opacity:0.1}}],tooltip:{trigger:'axis'},grid:{left:40,right:20,top:10,bottom:30}})}
|
|
}
|
|
onMounted(loadData);onBeforeUnmount(()=>{chart?.dispose()})
|
|
</script>`);
|
|
|
|
// ProductionPage
|
|
w('production', 'ProductionPage.vue', `<template>
|
|
<div>
|
|
<el-row :gutter="20" style="margin-bottom:20px">
|
|
<el-col :span="6"><el-card shadow="hover"><div style="text-align:center;padding:10px"><div style="color:#909399;font-size:14px">总产量</div><div style="font-size:28px;font-weight:bold">{{summary.totalQuantity?.toLocaleString()}}</div></div></el-card></el-col>
|
|
<el-col :span="6"><el-card shadow="hover"><div style="text-align:center;padding:10px"><div style="color:#909399;font-size:14px">运行机床</div><div style="font-size:28px;font-weight:bold">{{summary.activeMachineCount}}</div></div></el-card></el-col>
|
|
<el-col :span="6"><el-card shadow="hover"><div style="text-align:center;padding:10px"><div style="color:#909399;font-size:14px">切削总时</div><div style="font-size:28px;font-weight:bold">{{summary.totalCuttingTime}}</div></div></el-card></el-col>
|
|
<el-col :span="6"><el-card shadow="hover"><div style="text-align:center;padding:10px"><div style="color:#909399;font-size:14px">平均产量</div><div style="font-size:28px;font-weight:bold">{{summary.avgQuantityPerMachine}}</div></div></el-card></el-col>
|
|
</el-row>
|
|
<el-table :data="tableData" border stripe v-loading="loading">
|
|
<el-table-column prop="date" label="日期" width="110"/><el-table-column prop="machineName" label="机床" width="120"/><el-table-column prop="programName" label="程序名" width="140" show-overflow-tooltip/>
|
|
<el-table-column label="产量" width="80" align="center"><template #default="{row}">{{row.dataStatus==='data_missing'?'-':row.quantity}}</template></el-table-column>
|
|
<el-table-column prop="runTime" label="运行时间" width="100" align="center"/><el-table-column prop="cuttingTime" label="切削时间" width="100" align="center"/>
|
|
<el-table-column label="日状态" width="80" align="center"><template #default="{row}"><el-tag :type="row.dataStatus==='normal'?'info':row.dataStatus==='offline'?'danger':'warning'" size="small">{{row.dataStatus==='normal'?'正常':row.dataStatus==='offline'?'离线':'缺失'}}</el-tag></template></el-table-column>
|
|
<el-table-column label="修正" width="80" align="center"><template #default="{row}">{{row.isAdjusted?'✓':'-'}}</template></el-table-column>
|
|
<el-table-column label="操作" width="100" align="center"><template #default="{row}"><el-button link type="primary" @click="handleAdjust(row)">修正</el-button></template></el-table-column>
|
|
</el-table>
|
|
<el-pagination v-model:current-page="page.page" v-model:page-size="page.pageSize" :page-sizes="[20,50,100]" :total="page.total" background layout="total,sizes,prev,pager,next,jumper"/>
|
|
<el-dialog v-model="adjustVisible" title="修正产量" width="500px" destroy-on-close>
|
|
<el-form :model="adjustForm" label-width="100px">
|
|
<el-form-item label="当前产量"><el-input :model-value="adjustForm.currentQty" disabled/></el-form-item>
|
|
<el-form-item label="修正后产量" required><el-input-number v-model="adjustForm.newQty" :min="0"/></el-form-item>
|
|
<el-form-item label="修正原因" required><el-input v-model="adjustForm.reason" type="textarea" maxlength="500"/></el-form-item>
|
|
</el-form>
|
|
<template #footer><el-button @click="adjustVisible=false">取消</el-button><el-button type="primary" :loading="submitting" @click="doAdjust">确认修正</el-button></template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import {ref,reactive,onMounted} from 'vue'
|
|
import {ElMessage,ElMessageBox} from 'element-plus'
|
|
import request from '@/utils/request'
|
|
const loading=ref(false);const tableData=ref<any[]>([]);const summary=ref<any>({})
|
|
const page=reactive({page:1,pageSize:20,total:0})
|
|
const adjustVisible=ref(false);const submitting=ref(false)
|
|
const adjustForm=reactive({currentQty:0,newQty:0,reason:'',id:0})
|
|
async function loadData(){loading.value=true;try{const[s,d]:any[]=await Promise.all([request.get('/admin/production/daily-summary'),request.get('/admin/production/daily',{params:page})]);summary.value=s.data||{};tableData.value=d.data?.items||[];page.total=d.data?.total||0}finally{loading.value=false}}
|
|
function handleAdjust(row:any){adjustForm.currentQty=row.quantity;adjustForm.newQty=row.quantity||0;adjustForm.reason='';adjustForm.id=row.id;adjustVisible.value=true}
|
|
async function doAdjust(){await ElMessageBox.confirm('确定修正产量?修正后将记录审计日志。','提示',{type:'warning'});submitting.value=true;try{await request.post('/admin/production/adjust',adjustForm);ElMessage.success('修正成功');adjustVisible.value=false;loadData()}finally{submitting.value=false}}
|
|
onMounted(loadData)
|
|
</script>`);
|
|
|
|
console.log('gen3 done: worker list+detail, production');
|