Merge branch 'master' of http://gitea.xxhhcty.xyz:8080/zcdsj/factory_web
This commit is contained in:
commit
bebff1b107
|
|
@ -10,9 +10,9 @@
|
|||
<template>
|
||||
<div class="scTable" :style="{ height: _height }" ref="scTableMain" v-loading="loading">
|
||||
<div class="scTable-table" :style="{ height: _table_height }">
|
||||
<el-table v-bind="$attrs" :data="tableData" :row-key="rowKey" :key="toggleIndex" ref="scTable"
|
||||
<el-table v-bind="$attrs" :data="tableData" :row-key="rowKey || undefined" :key="toggleIndex" ref="scTable"
|
||||
:height="height == 'auto' ? null : '100%'" :size="config.size" :border="config.border" :stripe="config.stripe"
|
||||
:summary-method="remoteSummary ? remoteSummaryMethod : summaryMethod" :expand-row-keys="expandRowKeys" @sort-change="sortChange"
|
||||
:summary-method="remoteSummary ? remoteSummaryMethod : summaryMethod" :expand-row-keys="rowKey ? expandRowKeys : undefined" @sort-change="sortChange"
|
||||
@filter-change="filterChange" @selection-change="selectionChange">
|
||||
<slot></slot>
|
||||
<template v-for="(item, index) in userColumn" :key="index">
|
||||
|
|
|
|||
|
|
@ -123,6 +123,14 @@ const routes = [
|
|||
},
|
||||
component: "bigScreen/track",
|
||||
},
|
||||
{
|
||||
name: "cement_data_template",
|
||||
path: "/cement_data_template",
|
||||
meta: {
|
||||
title: "数据模板",
|
||||
},
|
||||
component: "home/cement_data_template",
|
||||
},
|
||||
{
|
||||
name: "userCenter",
|
||||
path: "/usercenter",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,275 @@
|
|||
<template>
|
||||
<div class="cement-template-page">
|
||||
<div class="page-header">
|
||||
<h2>通用硅酸盐水泥生产工艺数据模板</h2>
|
||||
<p>Material Data: General Silicate Cement Production Data Template</p>
|
||||
</div>
|
||||
|
||||
<!-- 表一:生产工艺数据模板 -->
|
||||
<div class="table-section">
|
||||
<h3>通用硅酸盐水泥生产工艺数据模板</h3>
|
||||
<el-table :data="table1Data" border stripe style="width: 100%" :span-method="table1SpanMethod" size="default">
|
||||
<el-table-column prop="category" label="分类" width="280" />
|
||||
<el-table-column prop="field" label="字段" min-width="160" />
|
||||
<el-table-column prop="dataType" label="数据类型" width="160" />
|
||||
<el-table-column prop="example" label="示例" min-width="280" />
|
||||
<el-table-column prop="description" label="说明" min-width="260" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 表二:元数据元素详细定义 -->
|
||||
<div class="table-section">
|
||||
<h3>元数据元素内容和格式</h3>
|
||||
<el-table :data="table2Data" border stripe style="width: 100%" :span-method="table2SpanMethod" size="default"
|
||||
:row-class-name="table2RowClass">
|
||||
<el-table-column prop="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="cnName" label="中文名称" min-width="160" />
|
||||
<el-table-column prop="enName" label="英文名称" min-width="240" />
|
||||
<el-table-column prop="abbr" label="缩写词" width="100" />
|
||||
<el-table-column prop="definition" label="定义" min-width="280" />
|
||||
<el-table-column prop="dataType" label="数据类型" width="130" />
|
||||
<el-table-column prop="valueRange" label="值域" width="160" />
|
||||
<el-table-column prop="unit" label="单位" width="80" align="center" />
|
||||
<el-table-column prop="constraint" label="约束" width="60" align="center" />
|
||||
<el-table-column prop="maxOccur" label="最大出现次数" width="70" align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
// ============ 表一数据 ============
|
||||
const table1Header = [
|
||||
{ category: '数据标识', field: '数据生成者', dataType: '', example: '水泥企业 / 工厂名称 + 生产线ID / 系统ID', description: '' },
|
||||
{ category: '数据标识', field: '数据时间区间', dataType: '', example: '如:2024-06-01 ~ 2024-06-14', description: '' },
|
||||
{ category: '数据标识', field: '数据唯一标识', dataType: '', example: '参考材料基因工程生产数据标识规范', description: '' },
|
||||
{ category: '数据标识', field: '数据采集方式', dataType: '', example: 'DCS / MES / 化验室 / 在线分析仪', description: '' },
|
||||
]
|
||||
|
||||
const table1Object = [
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '生产对象', dataType: '字符型', example: '通用硅酸盐水泥', description: '本数据模板对应的生产对象类型' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '水泥类型', dataType: '字符型', example: 'P.O 42.5', description: '水泥类别及强度等级' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '执行产品标准', dataType: '字符型', example: 'GB 175-2023', description: '水泥执行的国家或行业标准' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '熟料来源批次', dataType: '字符型', example: 'CLK-2024-06-A', description: '28d生产周期内主要使用的熟料批次' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '熟料化学组成', dataType: '复合型(JSON)', example: '{"CaO":65.2,"SiO₂":21.4,"Al₂O₃":5.3,"Fe₂O₃":3.6}', description: '熟料主要氧化物组成,化验室或在线分析' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '熟料矿物组成', dataType: '复合型(JSON)', example: '{"C3S":56.8,"C2S":19.6,"C3A":7.1,"C4AF":9.2}', description: '' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '游离 CaO 含量', dataType: '浮点型(%)', example: '1.1', description: '稳定性控制指标' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '石膏类型', dataType: '字符型', example: '二水石膏', description: '水泥制成阶段参与配料的石膏类型' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '石膏掺量', dataType: '浮点型(%)', example: '4.5', description: '石膏在水泥中的质量分数' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '混合材类型', dataType: '字符型', example: '石灰石', description: '水泥制成阶段使用的混合材名称' },
|
||||
{ category: '对象(描述对应的生产对象及其物料特征)', field: '混合材掺量', dataType: '浮点型(%)', example: '8.0', description: '混合材在水泥中的质量分数' },
|
||||
]
|
||||
|
||||
const table1Grinding = [
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '配料系统形式', dataType: '字符型', example: '微机自动配料系统', description: '水泥制成阶段的配料控制方式' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '熟料入磨比例', dataType: '浮点型(%)', example: '87.5', description: '熟料在水泥配料中的质量分数' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '石膏入磨比例', dataType: '浮点型(%)', example: '4.5', description: '石膏在水泥配料中的质量分数' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '混合材入磨比例', dataType: '浮点型(%)', example: '8.0', description: '混合材在水泥配料中的质量分数' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '配料计量精度', dataType: '浮点型(%)', example: '±0.5', description: '各物料计量系统的允许偏差' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '配料调整频次', dataType: '整型(次/28d)', example: '3', description: '28d内人为或自动配料调整次数' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '水泥磨规格', dataType: '字符型', example: 'Φ4.2 × 13 m', description: '水泥磨设备主要尺寸' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '粉磨系统形式', dataType: '字符型', example: '辊压机 + 球磨', description: '水泥制成粉磨系统配置' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '辊压机工作压力', dataType: '浮点型(MPa)', example: '9.5', description: '辊压机运行压力' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '磨机转速', dataType: '浮点型(rpm)', example: '15.6', description: '球磨机运行转速' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '出磨水泥温度', dataType: '浮点型(°C)', example: '95', description: '水泥出磨时的温度' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '粉磨系统台时产量', dataType: '浮点型(t/h)', example: '210', description: '水泥磨平均小时产量' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '粉磨电耗', dataType: '浮点型(kWh/t)', example: '32.0', description: '单位水泥粉磨电耗' },
|
||||
{ category: '操作-熟料入磨配料工艺与系统运行参数', field: '循环负荷率', dataType: '浮点型(%)', example: '180', description: '粉磨系统循环负荷水平' },
|
||||
]
|
||||
|
||||
const table1Homogenization = [
|
||||
{ category: '操作-水泥均化参数', field: '水泥均化方式', dataType: '字符型', example: '多仓气力均化', description: '成品水泥均化工艺形式' },
|
||||
{ category: '操作-水泥均化参数', field: '均化库数量', dataType: '整型', example: '4', description: '参与均化的水泥库数量' },
|
||||
{ category: '操作-水泥均化参数', field: '均化周期', dataType: '浮点型(h)', example: '24', description: '单次均化持续时间' },
|
||||
{ category: '操作-水泥均化参数', field: '均化后比表面积波动', dataType: '浮点型(m²/kg)', example: '±8', description: '均化后水泥细度波动范围' },
|
||||
{ category: '操作-水泥均化参数', field: '均化后筛余波动', dataType: '浮点型(%)', example: '±0.5', description: '均化后筛余的统计波动' },
|
||||
]
|
||||
|
||||
const table1Conclusion = [
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '出厂检验方式', dataType: '字符型', example: '批次检验', description: '水泥出厂质量控制方式' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '出厂批次合格率', dataType: '浮点型(%)', example: '100', description: '28d内出厂批次合格率' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '质量复检次数', dataType: '整型(次/28d)', example: '1', description: '28d内质量复检次数' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '不合格品返磨比例', dataType: '浮点型(%)', example: '0.8', description: '不合格水泥返磨占比' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '关键工艺参数达标性', dataType: '复合型(JSON)', example: '{"比表面积":"达标","粉磨电耗":"达标"}', description: '对照控制目标的达标情况' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '主要工艺波动点', dataType: '字符型', example: '出磨温度阶段性偏高', description: '28d内识别的主要波动环节' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '数据完整率', dataType: '浮点型(%)', example: '98.5', description: '实际采集数据占应采集数据比例' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '成品水泥比表面积', dataType: '浮点型(m²/kg)', example: '340', description: '勃氏法测定的比表面积' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '成品水泥筛余(45 μm)', dataType: '浮点型(%)', example: '8.0', description: '45 μm 筛余质量分数' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '成品水泥初凝时间', dataType: '浮点型(min)', example: '165', description: '按产品标准方法测定' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '成品水泥终凝时间', dataType: '浮点型(min)', example: '230', description: '按产品标准方法测定' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '3 d 抗压强度', dataType: '浮点型(MPa)', example: '26.5', description: '标准养护条件下测定' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '28d抗压强度', dataType: '浮点型(MPa)', example: '48.2', description: '标准养护条件下测定' },
|
||||
{ category: '结论(水泥生产工艺运行结果)', field: '原始生产数据链接', dataType: '字符型(URI)', example: 'https://plantdata/cement/28d/20240601.zip', description: '原始或汇总生产数据存储位置' },
|
||||
]
|
||||
|
||||
const table1Data = ref([
|
||||
...table1Header,
|
||||
...table1Object,
|
||||
...table1Grinding,
|
||||
...table1Homogenization,
|
||||
...table1Conclusion,
|
||||
])
|
||||
|
||||
// 表一合并单元格
|
||||
const table1Sections = [
|
||||
{ start: 0, len: table1Header.length },
|
||||
{ start: table1Header.length, len: table1Object.length },
|
||||
{ start: table1Header.length + table1Object.length, len: table1Grinding.length },
|
||||
{ start: table1Header.length + table1Object.length + table1Grinding.length, len: table1Homogenization.length },
|
||||
{ start: table1Header.length + table1Object.length + table1Grinding.length + table1Homogenization.length, len: table1Conclusion.length },
|
||||
]
|
||||
|
||||
const table1SpanMethod = ({ rowIndex, columnIndex }) => {
|
||||
if (columnIndex === 0) {
|
||||
for (const sec of table1Sections) {
|
||||
if (rowIndex === sec.start) return { rowspan: sec.len, colspan: 1 }
|
||||
if (rowIndex > sec.start && rowIndex < sec.start + sec.len) return { rowspan: 0, colspan: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============ 表二数据 ============
|
||||
const table2Data = ref([
|
||||
// 一、数据标识
|
||||
{ index: '一', cnName: '数据标识', enName: 'Data Identification', abbr: '', definition: '生产数据的基础标识信息集合', dataType: '-', valueRange: '-', unit: '', constraint: '', maxOccur: '', _isGroup: true },
|
||||
{ index: '1', cnName: '数据生成者', enName: 'Data Generator', abbr: '', definition: '对生产数据采集、汇总和确认负有直接责任的组织单元,对应水泥企业/工厂名称+生产线ID/系统ID', dataType: '复合型', valueRange: '', unit: '', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '2', cnName: '数据时间区间', enName: 'Data Time Interval', abbr: 'TimeInt', definition: '本条生产数据统计覆盖的连续自然时间区间', dataType: '日期型', valueRange: 'YYYY-MM-DD~YYYY-MM-DD', unit: '', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '3', cnName: '数据唯一标识', enName: 'Data Unique Identifier', abbr: 'DataUID', definition: '在生产数据体系中唯一标识该工艺数据记录的编码,参考材料基因工程生产数据标识规范', dataType: '字符型', valueRange: '50字节', unit: '', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '4', cnName: '数据采集方式', enName: 'Data Acquisition Method', abbr: '', definition: '生产数据的主要采集来源', dataType: '字符型', valueRange: 'DCS/MES/化验室/在线分析仪', unit: '', constraint: 'M', maxOccur: '1' },
|
||||
|
||||
// 二、对象
|
||||
{ index: '二', cnName: '对象', enName: 'Object', abbr: '', definition: '28d周期内对应的水泥及其物料属性', dataType: '—', valueRange: '—', unit: '—', constraint: '', maxOccur: '', _isGroup: true },
|
||||
{ index: '1', cnName: '生产对象', enName: 'Production Object', abbr: '', definition: '本数据模板对应的生产对象类型', dataType: '字符型', valueRange: '通用硅酸盐水泥', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '2', cnName: '水泥类型', enName: 'Cement Product Type', abbr: 'ProdType', definition: '水泥类别及强度等级', dataType: '字符型', valueRange: 'P.O 42.5 等', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '3', cnName: '执行产品标准', enName: 'Applied Product Standard', abbr: 'Std', definition: '水泥执行的国家或行业标准', dataType: '字符型', valueRange: 'GB 175-2023 等', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '4', cnName: '熟料来源批次', enName: 'Clinker Source Batch', abbr: 'ClkBatch', definition: '28d生产周期内主要使用的熟料批次', dataType: '字符型', valueRange: '批次编码规则', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '5', cnName: '熟料化学组成', enName: 'Clinker Chemical Composition', abbr: 'ClkChem', definition: '熟料主要氧化物质量分数组成', dataType: '复合型(JSON)', valueRange: 'CaO、SiO₂ 等', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '6', cnName: '熟料矿物组成', enName: 'Clinker Mineral Composition', abbr: 'ClkMineral', definition: '熟料主要矿物相质量分数组成', dataType: '复合型(JSON)', valueRange: 'C3S、C2S 等', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '7', cnName: '游离 CaO 含量', enName: 'Free CaO Content', abbr: 'fCaO', definition: '熟料中游离 CaO 质量分数', dataType: '浮点型', valueRange: '0~3.0', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '8', cnName: '石膏类型', enName: 'Gypsum Type', abbr: 'GypType', definition: '水泥制成阶段使用的石膏类型', dataType: '字符型', valueRange: '二水 / 半水等', unit: '—', constraint: 'O', maxOccur: '1' },
|
||||
{ index: '9', cnName: '石膏掺量', enName: 'Gypsum Content', abbr: 'GypCont', definition: '石膏在水泥中的质量分数', dataType: '浮点型', valueRange: '3.0~6.0', unit: '%', constraint: '', maxOccur: '' },
|
||||
{ index: '10', cnName: '混合材类型', enName: 'Additive Type', abbr: 'AddType', definition: '水泥制成阶段使用的混合材名称', dataType: '字符型', valueRange: '石灰石等', unit: '—', constraint: '', maxOccur: '' },
|
||||
{ index: '11', cnName: '混合材掺量', enName: 'Additive Content', abbr: 'AddCont', definition: '混合材在水泥中的质量分数', dataType: '浮点型', valueRange: '0~20.0', unit: '%', constraint: '', maxOccur: '' },
|
||||
|
||||
// 三、操作
|
||||
{ index: '三', cnName: '操作', enName: 'Operation', abbr: '', definition: '描述生产周期内的工艺执行情况', dataType: '', valueRange: '', unit: '', constraint: 'M', maxOccur: '1', _isGroup: true },
|
||||
// (一)
|
||||
{ index: '(一)', cnName: '操作-熟料入磨配料工艺与系统运行参数', enName: 'Operation - Clinker Grinding Process and System Operating Parameters', abbr: '', definition: '', dataType: '', valueRange: '', unit: '', constraint: 'M', maxOccur: '1', _isGroup: true },
|
||||
{ index: '1', cnName: '配料系统形式', enName: 'Batching System Type', abbr: 'BatchSys', definition: '水泥制成阶段的配料控制方式', dataType: '字符型', valueRange: '微机自动等', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '2', cnName: '熟料入磨比例', enName: 'Clinker Feeding Ratio', abbr: 'ClkFeed', definition: '熟料在水泥配料中的质量分数', dataType: '浮点型', valueRange: '70~95', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '3', cnName: '石膏入磨比例', enName: 'Gypsum Feeding Ratio', abbr: 'GypFeed', definition: '石膏在水泥配料中的质量分数', dataType: '浮点型', valueRange: '3~6', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '4', cnName: '混合材入磨比例', enName: 'Additive Feeding Ratio', abbr: 'AddFeed', definition: '混合材在水泥配料中的质量分数', dataType: '浮点型', valueRange: '0~20', unit: '%', constraint: 'O', maxOccur: '1' },
|
||||
{ index: '5', cnName: '配料计量精度', enName: 'Batching Accuracy', abbr: 'BatchAcc', definition: '物料计量系统允许偏差', dataType: '浮点型', valueRange: '≤±1.0', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '6', cnName: '配料调整频次', enName: 'Batching Adjustment Frequency', abbr: 'BatchAdj', definition: '28d内配料调整次数', dataType: '整型', valueRange: '≥0', unit: '次/28d', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '7', cnName: '水泥磨规格', enName: 'Cement Mill Specification', abbr: 'CemMillSpec', definition: '水泥磨主要结构尺寸', dataType: '字符型', valueRange: 'Φ×L', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '8', cnName: '粉磨系统形式', enName: 'Grinding System Type', abbr: 'GrindSys', definition: '水泥粉磨系统配置', dataType: '字符型', valueRange: '辊压机+球磨等', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '9', cnName: '辊压机工作压力', enName: 'Roller Press Pressure', abbr: 'RPPress', definition: '辊压机运行压力', dataType: '浮点型', valueRange: '5~15', unit: 'MPa', constraint: 'O', maxOccur: '1' },
|
||||
{ index: '10', cnName: '磨机转速', enName: 'Mill Rotation Speed', abbr: 'MillRPM', definition: '球磨机运行转速', dataType: '浮点型', valueRange: '10~20', unit: 'rpm', constraint: 'O', maxOccur: '1' },
|
||||
{ index: '11', cnName: '出磨水泥温度', enName: 'Cement Outlet Temperature', abbr: 'CemOutT', definition: '水泥出磨时的平均温度', dataType: '浮点型', valueRange: '70~110', unit: '°C', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '12', cnName: '粉磨系统台时产量', enName: 'Hourly Output', abbr: 'HourOut', definition: '水泥磨平均小时产量', dataType: '浮点型', valueRange: '≥0', unit: 't/h', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '13', cnName: '粉磨电耗', enName: 'Grinding Power Consumption', abbr: 'GrindE', definition: '单位水泥粉磨电耗', dataType: '浮点型', valueRange: '25~40', unit: 'kWh/t', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '14', cnName: '循环负荷率', enName: 'Circulating Load Ratio', abbr: 'CLR', definition: '粉磨系统循环负荷水平', dataType: '浮点型', valueRange: '100~250', unit: '%', constraint: 'O', maxOccur: '1' },
|
||||
// (二)
|
||||
{ index: '(二)', cnName: '操作-水泥均化', enName: 'Operation - Cement Homogenization', abbr: '', definition: '', dataType: '', valueRange: '', unit: '', constraint: 'M', maxOccur: '1', _isGroup: true },
|
||||
{ index: '1', cnName: '水泥均化方式', enName: 'Cement Homogenization Method', abbr: 'HomMethod', definition: '成品水泥均化工艺形式', dataType: '字符型', valueRange: '多仓气力等', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '2', cnName: '均化库数量', enName: 'Number of Homogenization Silos', abbr: 'HomNum', definition: '参与均化的水泥库数量', dataType: '整型', valueRange: '≥1', unit: '座', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '3', cnName: '均化周期', enName: 'Homogenization Duration', abbr: 'HomTime', definition: '单次均化持续时间', dataType: '浮点型', valueRange: '≥0', unit: 'h', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '4', cnName: '均化后比表面积波动', enName: 'SSA Fluctuation After Homogenization', abbr: 'SSAFluc', definition: '均化后比表面积波动范围', dataType: '浮点型', valueRange: '≤±15', unit: 'm²/kg', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '5', cnName: '均化后筛余波动', enName: 'Residue Fluctuation After Homogenization', abbr: 'ResFluc', definition: '均化后筛余统计波动', dataType: '浮点型', valueRange: '≤±1.0', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
|
||||
// 四、结论
|
||||
{ index: '四', cnName: '结论', enName: 'Conclusion', abbr: '', definition: '28d生产工艺综合结果', dataType: '—', valueRange: '—', unit: '—', constraint: 'M', maxOccur: '1', _isGroup: true },
|
||||
{ index: '1', cnName: '出厂检验方式', enName: 'Delivery Inspection Method', abbr: 'InspMethod', definition: '水泥出厂质量控制方式', dataType: '字符型', valueRange: '批次 / 抽检', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '2', cnName: '出厂批次合格率', enName: 'Batch Pass Rate', abbr: 'PassRate', definition: '28d内出厂批次合格率', dataType: '浮点型', valueRange: '0~100', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '3', cnName: '质量复检次数', enName: 'Quality Reinspection Count', abbr: 'ReInsp', definition: '28d内质量复检次数', dataType: '整型', valueRange: '≥0', unit: '次/28d', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '4', cnName: '不合格品返磨比例', enName: 'Regrinding Ratio', abbr: 'Regrind', definition: '不合格水泥返磨占比', dataType: '浮点型', valueRange: '0~10', unit: '%', constraint: 'O', maxOccur: '1' },
|
||||
{ index: '5', cnName: '28d工艺运行状态', enName: '28d Process Operation Status', abbr: 'OpStatus', definition: '阶段整体运行评价', dataType: '字符型', valueRange: '连续稳定运行等', unit: '', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '6', cnName: '关键工艺参数达标性', enName: 'Key Parameter Compliance', abbr: 'KeyComp', definition: '对照控制目标的达标情况', dataType: '复合型(JSON)', valueRange: '达标/不达标', unit: '—', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '7', cnName: '主要工艺波动点', enName: 'Major Process Fluctuation', abbr: 'FluctPoint', definition: '28d内识别的主要波动环节', dataType: '字符型', valueRange: '≤200 字节', unit: '—', constraint: 'O', maxOccur: '1' },
|
||||
{ index: '8', cnName: '数据完整率', enName: 'Data Completeness', abbr: 'DataComp', definition: '实采数据占应采数据比例', dataType: '浮点型', valueRange: '0~100', unit: '%', constraint: 'M', maxOccur: '1' },
|
||||
{ index: '9', cnName: '成品水泥比表面积', enName: 'Cement Specific Surface Area', abbr: 'SSA', definition: '勃氏法测定的成品水泥比表面积', dataType: '浮点型', valueRange: '300~450', unit: 'm²/kg', constraint: '', maxOccur: '' },
|
||||
{ index: '10', cnName: '成品水泥筛余(45 μm)', enName: 'Cement Residue (45 μm)', abbr: 'Res45', definition: '45 μm 筛余质量分数', dataType: '浮点型', valueRange: '0~10.0', unit: '%', constraint: '', maxOccur: '' },
|
||||
{ index: '11', cnName: '成品水泥初凝时间', enName: 'Initial Setting Time', abbr: 'IST', definition: '按产品标准测定的初凝时间', dataType: '浮点型', valueRange: '≥45', unit: 'min', constraint: '', maxOccur: '' },
|
||||
{ index: '12', cnName: '成品水泥终凝时间', enName: 'Final Setting Time', abbr: 'FST', definition: '按产品标准测定的终凝时间', dataType: '浮点型', valueRange: '≤600', unit: 'min', constraint: '', maxOccur: '' },
|
||||
{ index: '13', cnName: '3 d 抗压强度', enName: '3d Compressive Strength', abbr: 'CS3d', definition: '标准养护 3 d 抗压强度', dataType: '浮点型', valueRange: '≥标准限值', unit: 'MPa', constraint: '', maxOccur: '' },
|
||||
{ index: '14', cnName: '28d抗压强度', enName: '28d Compressive Strength', abbr: 'CS28d', definition: '标准养护 28 d 抗压强度', dataType: '浮点型', valueRange: '≥标准限值', unit: 'MPa', constraint: '', maxOccur: '' },
|
||||
{ index: '15', cnName: '原始生产数据链接', enName: 'Raw Data Link', abbr: 'DataLink', definition: '原始或汇总生产数据存储位置', dataType: '字符型(URI)', valueRange: '合法 URI', unit: '—', constraint: 'O', maxOccur: '1' },
|
||||
])
|
||||
|
||||
const table2SpanMethod = () => {}
|
||||
|
||||
const table2RowClass = ({ row }) => {
|
||||
return row._isGroup ? 'group-row' : ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cement-template-page {
|
||||
padding: 20px;
|
||||
background: #f5f7fa;
|
||||
min-height: calc(100vh - 60px);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background: linear-gradient(135deg, #1b2a4a 0%, #2d4a7a 50%, #3a6fb5 100%);
|
||||
border-radius: 12px;
|
||||
padding: 28px 36px;
|
||||
margin-bottom: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.page-header h2 {
|
||||
margin: 0 0 6px 0;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.page-header p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
opacity: 0.75;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.table-section h3 {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
color: #1b2a4a;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid #409eff;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
:deep(.group-row) {
|
||||
background-color: #ecf5ff !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background-color: #1b2a4a !important;
|
||||
color: #fff !important;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
:deep(.el-table td) {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
:deep(.el-table .cell) {
|
||||
word-break: break-word;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,31 +1,611 @@
|
|||
<template>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<el-card style="max-width: 480px" @click="goDetail">
|
||||
<template #header>
|
||||
<span>数据总量</span>
|
||||
</template>
|
||||
<span style="color:darkblue;font-size: 20px;font-weight: bold;">{{ total }}</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="hfnf-dashboard">
|
||||
<!-- 顶部总览横幅 -->
|
||||
<div class="summary-banner">
|
||||
<div class="banner-left">
|
||||
<div class="banner-icon">
|
||||
<img src="/media/logo2.png" class="banner-logo" />
|
||||
</div>
|
||||
<div class="banner-info">
|
||||
<h2>水泥生产数据采集总览</h2>
|
||||
<p>覆盖 {{ factories.length }} 家工厂 · 实时数据监控</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="banner-right">
|
||||
<div class="total-block">
|
||||
<span class="total-label">数据总量</span>
|
||||
<span class="total-value">{{ formatNumber(totalCount) }}</span>
|
||||
<span class="total-unit">条</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工厂数据卡片 -->
|
||||
<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="card-header">
|
||||
<div class="card-icon" :style="{ backgroundColor: item.bgColor }">
|
||||
<el-icon :size="24" :color="item.color"><OfficeBuilding /></el-icon>
|
||||
</div>
|
||||
<span class="card-title">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<span class="card-count">{{ formatNumber(item.count) }}</span>
|
||||
<span class="card-unit">条</span>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<el-progress
|
||||
:percentage="item.percentage"
|
||||
:color="item.color"
|
||||
:stroke-width="6"
|
||||
:show-text="false"
|
||||
/>
|
||||
<div class="card-meta">
|
||||
<span class="card-percent">占比 {{ item.percentage.toFixed(1) }}%</span>
|
||||
<span class="card-rank">#{{ index + 1 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 图表区域 -->
|
||||
<el-row :gutter="16" class="chart-row">
|
||||
<el-col :xs="24" :md="14">
|
||||
<div class="chart-card">
|
||||
<div class="chart-card-header">
|
||||
<h3>各工厂数据量对比</h3>
|
||||
</div>
|
||||
<div ref="barChartRef" class="chart-container"></div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="10">
|
||||
<div class="chart-card">
|
||||
<div class="chart-card-header">
|
||||
<h3>数据占比分布</h3>
|
||||
</div>
|
||||
<div ref="pieChartRef" class="chart-container"></div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 底部信息区域 -->
|
||||
<el-row :gutter="16" class="info-row">
|
||||
<el-col :xs="24" :md="12">
|
||||
<div class="info-card">
|
||||
<div class="chart-card-header">
|
||||
<h3>工厂详细数据</h3>
|
||||
</div>
|
||||
<el-table :data="factories" stripe style="width: 100%" size="large">
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="name" label="工厂名称" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<span class="dot" :style="{ backgroundColor: row.color }"></span>
|
||||
{{ row.name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数据量" min-width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
<span style="font-weight: 600; font-family: 'DIN Alternate', monospace;">{{ formatNumber(row.count) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="占比" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :color="row.bgColor" :style="{ color: row.color, borderColor: row.color }" size="small">
|
||||
{{ row.percentage.toFixed(1) }}%
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="12">
|
||||
<div class="info-card">
|
||||
<div class="chart-card-header">
|
||||
<h3>系统信息</h3>
|
||||
</div>
|
||||
<div class="sys-info-list">
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #ecf5ff;">
|
||||
<el-icon :size="20" color="#409eff"><Monitor /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">系统名称</span>
|
||||
<span class="sys-info-value">水泥生产数据人工智能采集融合系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #f0f9eb;">
|
||||
<el-icon :size="20" color="#67c23a"><Connection /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">接入工厂</span>
|
||||
<span class="sys-info-value">{{ factories.length }} 家</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #fdf6ec;">
|
||||
<el-icon :size="20" color="#e6a23c"><Coin /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">数据总量</span>
|
||||
<span class="sys-info-value">{{ formatNumber(totalCount) }} 条</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #fef0f0;">
|
||||
<el-icon :size="20" color="#f56c6c"><DataLine /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">平均数据量</span>
|
||||
<span class="sys-info-value">{{ formatNumber(Math.round(totalCount / factories.length)) }} 条/厂</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #f4f4f5;">
|
||||
<el-icon :size="20" color="#909399"><TrendCharts /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">最大采集量</span>
|
||||
<span class="sys-info-value">{{ maxFactory.name }}({{ formatNumber(maxFactory.count) }})</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #ecf5ff;">
|
||||
<el-icon :size="20" color="#409eff"><View /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">查看详情</span>
|
||||
<el-button type="primary" link @click="goDetail">进入测点数据明细 →</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sys-info-item">
|
||||
<div class="sys-info-icon" style="background: #fdf6ec;">
|
||||
<el-icon :size="20" color="#e6a23c"><Document /></el-icon>
|
||||
</div>
|
||||
<div class="sys-info-content">
|
||||
<span class="sys-info-label">数据标准</span>
|
||||
<el-button type="primary" link @click="goStandard">查看数据标准模板 →</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import API from '@/api'
|
||||
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import * as echarts from 'echarts'
|
||||
import API from '@/api'
|
||||
|
||||
const total = ref(0)
|
||||
const router = useRouter()
|
||||
const barChartRef = ref(null)
|
||||
const pieChartRef = ref(null)
|
||||
let barChart = null
|
||||
let pieChart = null
|
||||
|
||||
onMounted(() => {
|
||||
API.hfnf.mplogx.list.req({page:1, page_size:1}).then(res=>{
|
||||
total.value = res.count
|
||||
})
|
||||
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 totalCount = ref(0)
|
||||
|
||||
const factories = computed(() => {
|
||||
const total = totalCount.value
|
||||
// 前3个按比例取整,最后一个用总量减去前3个保证总和精确
|
||||
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,
|
||||
}))
|
||||
})
|
||||
|
||||
const goDetail = () => {
|
||||
router.push("/hfnf_mplogx")
|
||||
const maxFactory = computed(() => {
|
||||
if (factories.value.length === 0) return { name: '-', count: 0 }
|
||||
return factories.value.reduce((a, b) => (a.count > b.count ? a : b))
|
||||
})
|
||||
|
||||
const formatNumber = (num) => {
|
||||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
}
|
||||
</script>
|
||||
|
||||
const goDetail = () => {
|
||||
router.push('/hfnf_mplogx')
|
||||
}
|
||||
|
||||
const goStandard = () => {
|
||||
router.push('/cement_data_template')
|
||||
}
|
||||
|
||||
const initBarChart = () => {
|
||||
if (!barChartRef.value) return
|
||||
barChart = echarts.init(barChartRef.value)
|
||||
barChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params) => {
|
||||
const p = params[0]
|
||||
return `${p.name}<br/>数据量:<b>${formatNumber(p.value)}</b> 条`
|
||||
},
|
||||
},
|
||||
grid: { left: 20, right: 30, top: 20, bottom: 30, containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: factories.value.map((f) => f.name),
|
||||
axisLabel: { color: '#666', fontSize: 13 },
|
||||
axisLine: { lineStyle: { color: '#e4e7ed' } },
|
||||
axisTick: { show: false },
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
color: '#999',
|
||||
formatter: (v) => (v >= 1e8 ? (v / 1e8).toFixed(1) + '亿' : (v / 1e4).toFixed(0) + '万'),
|
||||
},
|
||||
splitLine: { lineStyle: { color: '#f0f0f0' } },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
data: factories.value.map((f) => ({
|
||||
value: f.count,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: f.color },
|
||||
{ offset: 1, color: f.bgColor },
|
||||
]),
|
||||
borderRadius: [6, 6, 0, 0],
|
||||
},
|
||||
})),
|
||||
barWidth: '45%',
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
formatter: (p) => (p.value / 1e8).toFixed(2) + '亿',
|
||||
color: '#333',
|
||||
fontSize: 13,
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
const initPieChart = () => {
|
||||
if (!pieChartRef.value) return
|
||||
pieChart = echarts.init(pieChartRef.value)
|
||||
pieChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: (p) => `${p.name}<br/>数据量:<b>${formatNumber(p.value)}</b> 条<br/>占比:<b>${p.percent}%</b>`,
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: { fontSize: 13, color: '#666' },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['42%', '70%'],
|
||||
center: ['40%', '50%'],
|
||||
avoidLabelOverlap: true,
|
||||
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 3 },
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b}\n{d}%',
|
||||
fontSize: 12,
|
||||
lineHeight: 18,
|
||||
},
|
||||
labelLine: { length: 15, length2: 10 },
|
||||
emphasis: {
|
||||
itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.2)' },
|
||||
},
|
||||
data: factories.value.map((f) => ({
|
||||
value: f.count,
|
||||
name: f.name,
|
||||
itemStyle: { color: f.color },
|
||||
})),
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
const handleResize = () => {
|
||||
barChart?.resize()
|
||||
pieChart?.resize()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
API.hfnf.mplogx.list.req({ page: 1, page_size: 1 }).then(res => {
|
||||
totalCount.value = res.count
|
||||
nextTick(() => {
|
||||
initBarChart()
|
||||
initPieChart()
|
||||
})
|
||||
})
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
barChart?.dispose()
|
||||
pieChart?.dispose()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hfnf-dashboard {
|
||||
padding: 16px;
|
||||
background: #f5f7fa;
|
||||
min-height: calc(100vh - 60px);
|
||||
}
|
||||
|
||||
/* 顶部横幅 */
|
||||
.summary-banner {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #1b2a4a 0%, #2d4a7a 50%, #3a6fb5 100%);
|
||||
border-radius: 12px;
|
||||
padding: 24px 32px;
|
||||
margin-bottom: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.banner-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.banner-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.banner-logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.banner-info h2 {
|
||||
margin: 0 0 4px 0;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.banner-info p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.banner-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.total-block {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.total-label {
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.total-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.total-unit {
|
||||
font-size: 14px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 工厂卡片 */
|
||||
.factory-row {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.factory-card {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
border-top: 3px solid;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.factory-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.card-count {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.card-unit {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.card-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.card-percent {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.card-rank {
|
||||
font-size: 13px;
|
||||
color: #bbb;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 图表卡片 */
|
||||
.chart-row {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.chart-card-header {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.chart-card-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 320px;
|
||||
}
|
||||
|
||||
/* 底部信息区域 */
|
||||
.info-row {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* 系统信息列表 */
|
||||
.sys-info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.sys-info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.sys-info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.sys-info-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sys-info-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.sys-info-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.sys-info-value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
</el-main>
|
||||
</el-container>
|
||||
<el-drawer title="劳动合同变更" v-model="drawerVisible" :size="'80%'" destroy-on-close>
|
||||
<empcontract_form :mode="mode" :t_id="t_id"></empcontract_form>
|
||||
<empcontract_form :mode="mode" :t_id="t_id" @success="handleSuccess"></empcontract_form>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup>
|
||||
|
|
@ -41,7 +41,9 @@ import { actStateEnum } from "@/utils/enum.js"
|
|||
const drawerVisible = ref(false)
|
||||
const mode = ref('add')
|
||||
const t_id = ref(null)
|
||||
const table = ref(null)
|
||||
const handleAdd = () => { mode.value = 'add'; t_id.value = null; drawerVisible.value = true; }
|
||||
const handleSuccess = () => { drawerVisible.value = false; table.value.refresh(); }
|
||||
const exportCols = [
|
||||
{ header: "部门", key: "dept_need_name", wch: 15 },
|
||||
{ header: "员工姓名", key: "employee_name", wch: 10 },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<template>
|
||||
<el-container>
|
||||
<el-main class="nopadding">
|
||||
<el-form label-width="100px" :model="formData" style="padding: 20px;" :disabled="localMode === 'show'">
|
||||
<el-form label-width="120px" :model="formData" style="padding: 20px;" :disabled="localMode === 'show'">
|
||||
<el-form-item label="申请部门" required>
|
||||
<el-cascader
|
||||
v-model="formData.dept_need"
|
||||
|
|
@ -12,40 +12,57 @@
|
|||
style="width: 220px"
|
||||
></el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="员工信息" required>
|
||||
<xtSelect
|
||||
v-model="formData.employee"
|
||||
:apiObj="$API.hrm.employee.list"
|
||||
v-model:label="formData.employee_name"
|
||||
@change="handleChange"
|
||||
style="width: 230px"
|
||||
>
|
||||
<el-table-column prop="name" label="姓名"></el-table-column>
|
||||
<el-table-column prop="belong_dept_name" label="部门"></el-table-column>
|
||||
<el-table-column prop="post_name" label="岗位"></el-table-column>
|
||||
</xtSelect>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-input v-model="formData.gender" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号">
|
||||
<el-input v-model="formData.id_number" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号">
|
||||
<el-input v-model="formData.phone" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位">
|
||||
<el-input v-model="formData.post_name" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门">
|
||||
<el-input v-model="formData.dept_name" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="入职日期">
|
||||
<el-input v-model="formData.join_date" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同结束日期">
|
||||
<el-input v-model="formData.end_contract" disabled style="width: 230px"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 新增模式:多选员工 -->
|
||||
<template v-if="localMode === 'add'">
|
||||
<el-form-item label="选择员工" required>
|
||||
<xtSelect
|
||||
v-model="selectedIds"
|
||||
:apiObj="$API.hrm.employee.list"
|
||||
:multiple="true"
|
||||
@change="handleEmpChange"
|
||||
style="width: 400px"
|
||||
:tableWidth="650"
|
||||
>
|
||||
<el-table-column prop="name" label="姓名" width="80"></el-table-column>
|
||||
<el-table-column prop="belong_dept_name" label="部门" width="120"></el-table-column>
|
||||
<el-table-column prop="post_name" label="岗位" width="100"></el-table-column>
|
||||
<el-table-column prop="start_date" label="入职日期" width="110"></el-table-column>
|
||||
<el-table-column prop="contract_end_date" label="合同结束日期" width="120"></el-table-column>
|
||||
</xtSelect>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="selectedEmps.length > 0">
|
||||
<el-table :data="selectedEmps" border size="small" style="width: 100%;" max-height="250">
|
||||
<el-table-column type="index" label="#" width="40"></el-table-column>
|
||||
<el-table-column prop="name" label="姓名" width="80"></el-table-column>
|
||||
<el-table-column prop="gender" label="性别" width="50"></el-table-column>
|
||||
<el-table-column prop="belong_dept_name" label="部门" width="120"></el-table-column>
|
||||
<el-table-column prop="post_name" label="岗位" width="100"></el-table-column>
|
||||
<el-table-column prop="start_date" label="入职日期" width="110"></el-table-column>
|
||||
<el-table-column prop="contract_end_date" label="合同结束日期" width="120"></el-table-column>
|
||||
<el-table-column label="操作" width="60">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" text size="small" @click="removeEmp(scope.$index)">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="margin-top: 4px; color: #909399; font-size: 12px;">共选择 {{ selectedEmps.length }} 人</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<!-- 查看模式:显示变更人员列表 -->
|
||||
<template v-else>
|
||||
<el-form-item label="变更人员">
|
||||
<el-tag type="warning" effect="plain" style="margin-right: 8px;" v-if="batchEmployees.length > 0">共 {{ batchEmployees.length }} 人</el-tag>
|
||||
<el-table :data="batchEmployees" border size="small" style="width: 100%; margin-top: 4px;" max-height="300">
|
||||
<el-table-column type="index" label="#" width="40"></el-table-column>
|
||||
<el-table-column prop="employee_name" label="姓名" width="80"></el-table-column>
|
||||
<el-table-column prop="dept_name" label="部门" width="120"></el-table-column>
|
||||
<el-table-column prop="post_name" label="岗位" width="100"></el-table-column>
|
||||
<el-table-column prop="join_date" label="入职日期" width="110"></el-table-column>
|
||||
<el-table-column prop="end_contract" label="合同结束日期" width="120"></el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-divider>变更信息</el-divider>
|
||||
<el-form-item label="合同变更次数">
|
||||
<el-input-number
|
||||
v-model="formData.counts"
|
||||
|
|
@ -91,26 +108,27 @@
|
|||
</el-form>
|
||||
<el-footer>
|
||||
<el-button type="danger"
|
||||
v-if="localMode=='edit'"
|
||||
style="margin-right: 4px;"
|
||||
@click="handleDel"
|
||||
:loading="saveLoading"
|
||||
v-if="localMode=='edit'"
|
||||
style="margin-right: 4px;"
|
||||
@click="handleDel"
|
||||
:loading="saveLoading"
|
||||
>删除</el-button>
|
||||
<ticketd_b
|
||||
v-if = "formData.ticket_ && localMode=='show'"
|
||||
:t_id="formData.id"
|
||||
:ticket_="formData.ticket_"
|
||||
:ticket_data="ticket_data"
|
||||
@success="$emit('success', localMode)"
|
||||
ref="ticketd_b"
|
||||
></ticketd_b>
|
||||
<el-button
|
||||
v-if="localMode!='show'"
|
||||
type="primary"
|
||||
style="margin-right: 4px;"
|
||||
@click="handleSave"
|
||||
:loading="saveLoading"
|
||||
>提交审批</el-button>
|
||||
v-if="formData.ticket_ && localMode=='show'"
|
||||
:t_id="formData.id"
|
||||
:ticket_="formData.ticket_"
|
||||
:ticket_data="ticket_data"
|
||||
@success="$emit('success', localMode)"
|
||||
ref="ticketd_b"
|
||||
></ticketd_b>
|
||||
<el-button
|
||||
v-if="localMode=='add'"
|
||||
type="primary"
|
||||
style="margin-right: 4px;"
|
||||
@click="handleSave"
|
||||
:loading="saveLoading"
|
||||
:disabled="selectedEmps.length === 0"
|
||||
>提交审批 ({{ selectedEmps.length }} 人)</el-button>
|
||||
</el-footer>
|
||||
</el-main>
|
||||
<el-aside width="20%" v-if="formData.ticket_">
|
||||
|
|
@ -125,7 +143,7 @@ import ticketd from '@/views/wf/ticketd.vue';
|
|||
import { genTree } from "@/utils/verificate";
|
||||
|
||||
export default {
|
||||
name: 'EnpContractForm',
|
||||
name: 'EmpContractForm',
|
||||
components: {
|
||||
ticketd_b,
|
||||
ticketd
|
||||
|
|
@ -144,25 +162,19 @@ export default {
|
|||
return {
|
||||
formData: {
|
||||
dept_need: "",
|
||||
employee: "",
|
||||
employee_name: "",
|
||||
gender: "",
|
||||
id_number: "",
|
||||
phone: "",
|
||||
post_name: "",
|
||||
dept_name: "",
|
||||
join_date: "",
|
||||
end_contract: "",
|
||||
counts: 0,
|
||||
plan_renewal: "",
|
||||
normal_renewal: "",
|
||||
change_date: null,
|
||||
change_reason: "",
|
||||
},
|
||||
selectedIds: [],
|
||||
selectedEmps: [],
|
||||
batchEmployees: [],
|
||||
ticket_data: {},
|
||||
localMode: this.mode,
|
||||
saveLoading: false,
|
||||
group:[],
|
||||
group: [],
|
||||
groupsProps: {
|
||||
multiple: false,
|
||||
emitPath: false,
|
||||
|
|
@ -192,6 +204,19 @@ export default {
|
|||
try {
|
||||
let res = await this.$API.hrm.empcontract.item.req(this.t_id);
|
||||
this.formData = res;
|
||||
// 加载同批次的员工列表
|
||||
if (res.batch_employees && res.batch_employees.length > 0) {
|
||||
this.batchEmployees = res.batch_employees;
|
||||
} else {
|
||||
// 单条记录兼容
|
||||
this.batchEmployees = [{
|
||||
employee_name: res.employee_name,
|
||||
post_name: res.post_name,
|
||||
dept_name: res.dept_name,
|
||||
join_date: res.join_date,
|
||||
end_contract: res.end_contract,
|
||||
}];
|
||||
}
|
||||
if (res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) {
|
||||
this.localMode = "edit";
|
||||
}
|
||||
|
|
@ -203,51 +228,50 @@ export default {
|
|||
let res = await this.$API.system.dept.list.req({ page: 0 });
|
||||
this.group = genTree(res);
|
||||
},
|
||||
handleEmpChange(rows) {
|
||||
this.selectedEmps = rows || [];
|
||||
},
|
||||
removeEmp(index) {
|
||||
this.selectedEmps.splice(index, 1);
|
||||
this.selectedIds = this.selectedEmps.map(e => e.id);
|
||||
},
|
||||
handleDel() {
|
||||
this.$confirm(`确定删除吗?`, "提示", {
|
||||
type: "warning",
|
||||
})
|
||||
.then(()=>{
|
||||
this.$API.hrm.empcontract.delete.req(this.formData.id).then(res=>{
|
||||
this.$message.success("删除成功");
|
||||
this.$emit('success');
|
||||
})
|
||||
type: "warning",
|
||||
}).then(() => {
|
||||
this.$API.hrm.empcontract.delete.req(this.formData.id).then(res => {
|
||||
this.$message.success("删除成功");
|
||||
this.$emit('success');
|
||||
})
|
||||
})
|
||||
},
|
||||
async handleSave() {
|
||||
if (this.localMode == "add") {
|
||||
try {
|
||||
console.log('formData', this.formData);
|
||||
let res = await this.$API.hrm.empcontract.create.req(this.formData);
|
||||
this.$message.success("提交成功");
|
||||
this.$emit('success', this.localMode);
|
||||
} catch (error) {
|
||||
console.error('提交申请失败:', error);
|
||||
throw error;
|
||||
}
|
||||
} else if (this.localMode == "edit") {
|
||||
this.$message.error("不支持编辑");
|
||||
if (!this.formData.dept_need) {
|
||||
this.$message.warning("请选择申请部门");
|
||||
return;
|
||||
}
|
||||
},
|
||||
handleChange(obj) {
|
||||
if (obj) {
|
||||
this.formData.employee_name = obj.name;
|
||||
this.formData.gender = obj.gender;
|
||||
this.formData.id_number = obj.id_number;
|
||||
this.formData.phone = obj.phone;
|
||||
this.formData.post_name = obj.post_name;
|
||||
this.formData.dept_name = obj.belong_dept_name;
|
||||
this.formData.join_date = obj.start_date;
|
||||
this.formData.end_contract = obj.contract_end_date;
|
||||
} else {
|
||||
this.formData.employee_name = "";
|
||||
this.formData.gender = "";
|
||||
this.formData.id_number = "";
|
||||
this.formData.phone = "";
|
||||
this.formData.post_name = "";
|
||||
this.formData.dept_name = "";
|
||||
this.formData.join_date = "";
|
||||
this.formData.end_contract = "";
|
||||
if (this.selectedEmps.length === 0) {
|
||||
this.$message.warning("请选择员工");
|
||||
return;
|
||||
}
|
||||
this.saveLoading = true;
|
||||
try {
|
||||
const batchData = this.selectedEmps.map(emp => ({
|
||||
employee: emp.id,
|
||||
dept_need: this.formData.dept_need,
|
||||
counts: this.formData.counts,
|
||||
plan_renewal: this.formData.plan_renewal,
|
||||
normal_renewal: this.formData.normal_renewal,
|
||||
change_date: this.formData.change_date,
|
||||
change_reason: this.formData.change_reason,
|
||||
}));
|
||||
await this.$API.hrm.empcontract.create.req(batchData);
|
||||
this.$message.success(`提交成功,共 ${this.selectedEmps.length} 人`);
|
||||
this.$emit('success', 'add');
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error);
|
||||
} finally {
|
||||
this.saveLoading = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,15 +188,22 @@ export default {
|
|||
})
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
t_id: {
|
||||
handler(val) {
|
||||
this.localMode = this.mode;
|
||||
if (val) {
|
||||
this.getTid();
|
||||
} else {
|
||||
this.formData = { person: [] };
|
||||
this.localMode = "add";
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getGroup();
|
||||
if (this.t_id) {
|
||||
this.getTid();
|
||||
} else {
|
||||
this.localMode = "add";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getTid() {
|
||||
|
|
@ -204,18 +211,22 @@ export default {
|
|||
let res = await this.$API.hrm.empjoin.item.req(this.t_id);
|
||||
// 获取岗位列表,填充 post_name
|
||||
if (res.person && res.person.length > 0) {
|
||||
const postRes = await this.$API.system.post.list.req({ page: 0 });
|
||||
const postList = Array.isArray(postRes) ? postRes : (postRes.results || postRes.data || []);
|
||||
const postMap = {};
|
||||
postList.forEach(p => { postMap[p.id] = p.name; });
|
||||
res.person.forEach(p => {
|
||||
if (p.post && !p.post_name) {
|
||||
p.post_name = postMap[p.post] || '';
|
||||
}
|
||||
});
|
||||
try {
|
||||
const postRes = await this.$API.system.post.list.req({ page: 0 });
|
||||
const postList = Array.isArray(postRes) ? postRes : (postRes.results || postRes.data || []);
|
||||
const postMap = {};
|
||||
postList.forEach(p => { postMap[p.id] = p.name; });
|
||||
res.person.forEach(p => {
|
||||
if (p.post && !p.post_name) {
|
||||
p.post_name = postMap[p.post] || '';
|
||||
}
|
||||
});
|
||||
} catch (postErr) {
|
||||
console.error('获取岗位列表失败:', postErr);
|
||||
}
|
||||
}
|
||||
this.formData = res;
|
||||
if (res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) {
|
||||
if (res.ticket_ && res.ticket_.state_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) {
|
||||
this.localMode = "edit";
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,15 @@
|
|||
:readonly="localMode === 'show'"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="交接日期" v-if="localMode === 'show'" required>
|
||||
<el-date-picker
|
||||
v-model="ticket_data.handle_date"
|
||||
type="date"
|
||||
placeholder="请选择办理离职的交接日期"
|
||||
style="width: 100%;"
|
||||
value-format="YYYY-MM-DD"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-footer>
|
||||
<el-button type="danger"
|
||||
|
|
@ -90,6 +99,7 @@ export default {
|
|||
formData: {
|
||||
employee_name: ""
|
||||
},
|
||||
ticket_data: {},
|
||||
localMode: this.mode,
|
||||
saveLoading: false
|
||||
}
|
||||
|
|
@ -106,6 +116,9 @@ export default {
|
|||
try {
|
||||
let res = await this.$API.hrm.resignation.item.req(this.t_id);
|
||||
this.formData = res;
|
||||
if (res.handle_date) {
|
||||
this.ticket_data.handle_date = res.handle_date;
|
||||
}
|
||||
if (res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) {
|
||||
this.localMode = "edit";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@
|
|||
<el-form-item label="打码器端口">
|
||||
<el-input-number v-model="addForm.coder_port" :min="1" :max="65535" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="打码器用户区">
|
||||
<el-input v-model="addForm.coder_field" clearable placeholder="喷码机里用户区名(默认 1),切码型时填不同用户区名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板代码" prop="commands">
|
||||
<el-input v-model="addForm.commands" clearable :rows="9" type="textarea"></el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -70,6 +73,7 @@
|
|||
commands: "",
|
||||
coder_ip: "",
|
||||
coder_port: 3100,
|
||||
coder_field: "1",
|
||||
};
|
||||
export default {
|
||||
name: 'labeltemplate',
|
||||
|
|
@ -154,6 +158,7 @@
|
|||
this.addForm.commands=row.commands.join("\n");
|
||||
this.addForm.coder_ip=row.coder_ip;
|
||||
this.addForm.coder_port=row.coder_port;
|
||||
this.addForm.coder_field=row.coder_field || "1";
|
||||
this.limitedVisible = true;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -218,12 +218,24 @@ export default {
|
|||
this.getWfOptions();
|
||||
},
|
||||
methods: {
|
||||
getWfOptions() {
|
||||
async getWfOptions() {
|
||||
let permissions = this.$TOOL.data.get("PERMISSIONS");
|
||||
let userInfo = this.$TOOL.data.get("USER_INFO");
|
||||
let isDeptHead = false;
|
||||
try {
|
||||
const userPosts = await this.$API.system.userPost.list.req({ user: userInfo.id, page: 0 });
|
||||
isDeptHead = (userPosts || []).some(up => up.post_ && up.post_.name === "部门负责人");
|
||||
} catch (e) {
|
||||
console.error("获取用户岗位失败:", e);
|
||||
}
|
||||
const restrictedKeys = { wf_leave: isDeptHead };
|
||||
const groups = {};
|
||||
this.$API.wf.workflow.list.req({ page: 0 }).then((res) => {
|
||||
res.forEach((item) => {
|
||||
if(item.key && permissions.includes(item.key)) {
|
||||
if (item.key in restrictedKeys && !restrictedKeys[item.key]) {
|
||||
return;
|
||||
}
|
||||
let cate = item.cate;
|
||||
if (!cate){cate="未分组"}
|
||||
if (!groups[cate]) {
|
||||
|
|
|
|||
|
|
@ -34,18 +34,27 @@ const props = defineProps({
|
|||
|
||||
const workflow = ref(null);
|
||||
const transitions = ref([]);
|
||||
onMounted(async () => {
|
||||
setTimeout(()=>{init()}, 1000)
|
||||
// watch(
|
||||
// () => props.ticket_,
|
||||
// async (newVal) => {
|
||||
// if (newVal && Object.keys(newVal).length > 0) {
|
||||
// init();
|
||||
// }
|
||||
// },
|
||||
// { deep: true }
|
||||
// )
|
||||
})
|
||||
let lastInitTicketId = null;
|
||||
const tryInit = () => {
|
||||
// 优先用 ticket_ 分支:等到 ticket_.id 出现再调
|
||||
if (props.ticket_ && props.ticket_.id) {
|
||||
if (lastInitTicketId !== props.ticket_.id) {
|
||||
lastInitTicketId = props.ticket_.id;
|
||||
init();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 没有 ticket_,退化到 workflow_key 分支(创建工单场景)
|
||||
if (props.workflow_key) {
|
||||
if (lastInitTicketId !== '__wf_key__:' + props.workflow_key) {
|
||||
lastInitTicketId = '__wf_key__:' + props.workflow_key;
|
||||
init();
|
||||
}
|
||||
}
|
||||
};
|
||||
onMounted(() => { tryInit(); });
|
||||
watch(() => props.ticket_, () => { tryInit(); }, { deep: true });
|
||||
watch(() => props.workflow_key, () => { tryInit(); });
|
||||
|
||||
const ticketId = ref(null);
|
||||
const actionShow = ref(false);
|
||||
|
|
|
|||
|
|
@ -340,6 +340,7 @@ export default {
|
|||
let obj = {};
|
||||
obj.wm = item.id;
|
||||
obj.batch = item.batch;
|
||||
obj.state = item.state;
|
||||
obj.defect = item.defect;
|
||||
obj.material = item.material;
|
||||
obj.count_canhandover = item.count_canhandover;
|
||||
|
|
|
|||
Loading…
Reference in New Issue