201 lines
9.2 KiB
Vue
201 lines
9.2 KiB
Vue
|
|
<template>
|
|||
|
|
<div>
|
|||
|
|
<div class="card">
|
|||
|
|
<div class="card-body" style="padding:10px 14px;">
|
|||
|
|
<div class="flex-row" style="flex-wrap:wrap;gap:12px;">
|
|||
|
|
<div class="flex-row">
|
|||
|
|
<span class="kv-label">卷号</span>
|
|||
|
|
<input v-model="query.coil_no" class="kv-input" style="width:140px;" @keyup.enter="fetchData" />
|
|||
|
|
</div>
|
|||
|
|
<div class="flex-row">
|
|||
|
|
<span class="kv-label">班次</span>
|
|||
|
|
<select v-model="query.shift" class="kv-input" style="width:90px;">
|
|||
|
|
<option value="">全部</option>
|
|||
|
|
<option v-for="s in ['甲','乙','丙','丁']" :key="s" :value="s">{{ s }}班</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
<div class="flex-row">
|
|||
|
|
<span class="kv-label">开始日期</span>
|
|||
|
|
<input v-model="query.start_date" type="date" class="kv-input" style="width:140px;" />
|
|||
|
|
<span class="kv-label">~</span>
|
|||
|
|
<input v-model="query.end_date" type="date" class="kv-input" style="width:140px;" />
|
|||
|
|
</div>
|
|||
|
|
<div class="flex-row">
|
|||
|
|
<button class="btn btn-primary" @click="fetchData">查询</button>
|
|||
|
|
<button class="btn btn-outline" @click="openDialog()">+ 新增</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="card">
|
|||
|
|
<div class="card-header">
|
|||
|
|
生产实绩
|
|||
|
|
<span class="ch-badge">共 {{ total }} 条</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="table-scroll" v-loading="loading">
|
|||
|
|
<table class="data-table">
|
|||
|
|
<thead>
|
|||
|
|
<tr>
|
|||
|
|
<th>卷号</th><th>班次</th><th>开始时间</th><th>结束时间</th>
|
|||
|
|
<th>处理重量(kg)</th><th>平均速度</th><th>最大速度</th>
|
|||
|
|
<th>酸耗(L)</th><th>入口厚度</th><th>出口厚度</th><th>质量等级</th><th>操作</th>
|
|||
|
|
</tr>
|
|||
|
|
</thead>
|
|||
|
|
<tbody>
|
|||
|
|
<tr v-for="row in tableData" :key="row.id">
|
|||
|
|
<td class="td-num">{{ row.coil_no }}</td>
|
|||
|
|
<td>{{ row.shift || '—' }}</td>
|
|||
|
|
<td class="td-muted">{{ fmtTime(row.start_time) }}</td>
|
|||
|
|
<td class="td-muted">{{ fmtTime(row.end_time) }}</td>
|
|||
|
|
<td class="td-num">{{ row.process_weight || '—' }}</td>
|
|||
|
|
<td class="td-num">{{ row.avg_speed ? row.avg_speed + ' m/min' : '—' }}</td>
|
|||
|
|
<td class="td-num">{{ row.max_speed ? row.max_speed + ' m/min' : '—' }}</td>
|
|||
|
|
<td class="td-num">{{ row.acid_consumption || '—' }}</td>
|
|||
|
|
<td class="td-num">{{ row.inlet_thickness || '—' }}</td>
|
|||
|
|
<td class="td-num">{{ row.outlet_thickness || '—' }}</td>
|
|||
|
|
<td>
|
|||
|
|
<span v-if="row.quality_grade" :class="['badge', gradeClass(row.quality_grade)]">{{ row.quality_grade }}</span>
|
|||
|
|
<span v-else class="td-muted">—</span>
|
|||
|
|
</td>
|
|||
|
|
<td><span class="action-link" @click="openDialog(row)">编辑</span></td>
|
|||
|
|
</tr>
|
|||
|
|
<tr v-if="!tableData.length && !loading">
|
|||
|
|
<td colspan="12" class="td-muted" style="text-align:center;padding:24px;">暂无数据</td>
|
|||
|
|
</tr>
|
|||
|
|
</tbody>
|
|||
|
|
</table>
|
|||
|
|
</div>
|
|||
|
|
<div class="card-body" style="padding:8px 14px;" v-if="total > query.page_size">
|
|||
|
|
<div class="flex-row">
|
|||
|
|
<button class="btn btn-outline" :disabled="query.page<=1" @click="query.page--;fetchData()">上一页</button>
|
|||
|
|
<span class="kv-label">第 {{ query.page }} / {{ Math.ceil(total/query.page_size) }} 页</span>
|
|||
|
|
<button class="btn btn-outline" :disabled="query.page>=Math.ceil(total/query.page_size)" @click="query.page++;fetchData()">下一页</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Modal -->
|
|||
|
|
<div v-if="dialogVisible" class="modal-mask" @click.self="dialogVisible=false">
|
|||
|
|
<div class="modal-box" style="width:680px;">
|
|||
|
|
<div class="modal-header">
|
|||
|
|
{{ editRow ? '编辑实绩' : '新增实绩' }}
|
|||
|
|
<span class="modal-close" @click="dialogVisible=false">✕</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="modal-body">
|
|||
|
|
<div class="grid-2" style="gap:12px;">
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">卷号 *</div>
|
|||
|
|
<input v-model="form.coil_no" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">班次</div>
|
|||
|
|
<select v-model="form.shift" class="kv-input">
|
|||
|
|
<option v-for="s in ['甲','乙','丙','丁']" :key="s" :value="s">{{ s }}班</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">开始时间</div>
|
|||
|
|
<input v-model="form.start_time" type="datetime-local" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">结束时间</div>
|
|||
|
|
<input v-model="form.end_time" type="datetime-local" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">处理重量 (kg)</div>
|
|||
|
|
<input v-model.number="form.process_weight" type="number" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">平均速度 (m/min)</div>
|
|||
|
|
<input v-model.number="form.avg_speed" type="number" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">酸耗 (L)</div>
|
|||
|
|
<input v-model.number="form.acid_consumption" type="number" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">质量等级</div>
|
|||
|
|
<select v-model="form.quality_grade" class="kv-input">
|
|||
|
|
<option value="A1">A1</option>
|
|||
|
|
<option value="A2">A2</option>
|
|||
|
|
<option value="B1">B1</option>
|
|||
|
|
<option value="B2">B2</option>
|
|||
|
|
<option value="C">C</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
<div class="form-field">
|
|||
|
|
<div class="kv-label">操作员</div>
|
|||
|
|
<input v-model="form.operator" class="kv-input" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="modal-footer">
|
|||
|
|
<button class="btn btn-outline" @click="dialogVisible=false">取消</button>
|
|||
|
|
<button class="btn btn-primary" :disabled="saving" @click="save">{{ saving ? '保存中...' : '保存' }}</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import { getProductionRecords, createProductionRecord, updateProductionRecord } from '@/api'
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
name: 'Production',
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
loading: false, saving: false,
|
|||
|
|
tableData: [], total: 0,
|
|||
|
|
query: { page: 1, page_size: 20, coil_no: '', shift: '', start_date: '', end_date: '' },
|
|||
|
|
dialogVisible: false, editRow: null, form: {},
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
created() { this.fetchData() },
|
|||
|
|
methods: {
|
|||
|
|
async fetchData() {
|
|||
|
|
this.loading = true
|
|||
|
|
const params = { ...this.query }
|
|||
|
|
if (params.start_date) params.start_date = params.start_date + 'T00:00:00'
|
|||
|
|
if (params.end_date) params.end_date = params.end_date + 'T23:59:59'
|
|||
|
|
try {
|
|||
|
|
const res = await getProductionRecords(params)
|
|||
|
|
this.tableData = res.data.items
|
|||
|
|
this.total = res.data.total
|
|||
|
|
} finally { this.loading = false }
|
|||
|
|
},
|
|||
|
|
fmtTime(t) { return t ? t.replace('T', ' ').slice(0, 16) : '—' },
|
|||
|
|
gradeClass(g) {
|
|||
|
|
if (g?.startsWith('A')) return 'badge-green'
|
|||
|
|
if (g?.startsWith('B')) return 'badge-blue'
|
|||
|
|
return 'badge-yellow'
|
|||
|
|
},
|
|||
|
|
openDialog(row = null) {
|
|||
|
|
this.editRow = row; this.form = row ? { ...row } : {}; this.dialogVisible = true
|
|||
|
|
},
|
|||
|
|
async save() {
|
|||
|
|
if (!this.form.coil_no) { this.$message.error('卷号不能为空'); return }
|
|||
|
|
this.saving = true
|
|||
|
|
try {
|
|||
|
|
if (this.editRow) await updateProductionRecord(this.editRow.id, this.form)
|
|||
|
|
else await createProductionRecord(this.form)
|
|||
|
|
this.$message.success('保存成功')
|
|||
|
|
this.dialogVisible = false; this.fetchData()
|
|||
|
|
} finally { this.saving = false }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
@import '@/assets/styles/variables';
|
|||
|
|
.action-link { color: $sms-highlight; cursor: pointer; font-size: 12px; margin-right: 12px; &:hover { text-decoration: underline; } }
|
|||
|
|
.form-field { display: flex; flex-direction: column; gap: 5px; }
|
|||
|
|
.modal-mask { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; z-index: 9999; }
|
|||
|
|
.modal-box { background: $bg-card; border: 1px solid $border; border-radius: 6px; width: 640px; max-width: 95vw; max-height: 90vh; display: flex; flex-direction: column; }
|
|||
|
|
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: $bg-panel; border-bottom: 1px solid $border; font-size: 13px; font-weight: 600; color: $sms-highlight; .modal-close { cursor: pointer; color: $text-muted; &:hover { color: $text-primary; } } }
|
|||
|
|
.modal-body { padding: 16px; overflow-y: auto; }
|
|||
|
|
.modal-footer { padding: 10px 16px; background: $bg-panel; border-top: 1px solid $border; display: flex; justify-content: flex-end; gap: 10px; }
|
|||
|
|
</style>
|