| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- <template>
- <el-dialog :title="title" :visible.sync="dialogVisible" width="1200px" append-to-body @close="handleClose">
- <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
- <!-- 基础信息区域 -->
- <div class="form-section">
- <div class="section-header">
- <i class="el-icon-info"></i>
- <span class="section-title">基础信息</span>
- </div>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="选择设备" prop="devId">
- <el-select
- v-model="formData.devId"
- filterable
- remote
- :remote-method="searchDevice"
- :loading="deviceLoading"
- placeholder="请输入设备位号或名称搜索"
- style="width: 100%"
- @change="handleDeviceChange"
- @focus="handleDeviceFocus"
- :disabled="!!formData.planId"
- clearable>
- <el-option
- v-for="device in deviceOptions"
- :key="device.devId"
- :label="`${device.devTag} - ${device.devName}`"
- :value="device.devId">
- <span style="float: left">{{ device.devTag }}</span>
- <span style="float: right; color: #8492a6; font-size: 13px">{{ device.devName }}</span>
- </el-option>
- <div v-if="deviceOptions.length === 0 && !deviceLoading" style="padding: 10px; text-align: center; color: #909399;">
- 请输入设备位号或名称进行搜索
- </div>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="计划开始时间" prop="planTime">
- <el-date-picker
- v-model="formData.planTime"
- type="date"
- value-format="yyyy-MM-dd"
- placeholder="选择计划开始时间"
- style="width: 100%">
- </el-date-picker>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="计划结束时间" prop="planEndTime">
- <el-date-picker
- v-model="formData.planEndTime"
- type="date"
- value-format="yyyy-MM-dd"
- placeholder="选择计划结束时间"
- style="width: 100%">
- </el-date-picker>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="责任人" prop="responsible">
- <el-select
- v-model="formData.responsible"
- placeholder="请选择责任人"
- style="width: 100%"
- clearable
- filterable>
- <el-option
- v-for="staff in staffOptions"
- :key="staff.staffid"
- :label="`${staff.name} (${staff.staffid})`"
- :value="staff.staffid">
- </el-option>
- <div v-if="staffOptions.length === 0" style="padding: 10px; text-align: center; color: #909399;">
- 暂无人员数据
- </div>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="审批人" prop="approver">
- <el-select
- v-model="formData.approver"
- placeholder="请选择审批人"
- style="width: 100%"
- clearable
- filterable
- :disabled="!!formData.planId">
- <el-option
- v-for="staff in staffOptions"
- :key="staff.staffid"
- :label="`${staff.name} (${staff.staffid})`"
- :value="staff.staffid">
- </el-option>
- <div v-if="staffOptions.length === 0" style="padding: 10px; text-align: center; color: #909399;">
- 暂无人员数据
- </div>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="备注" prop="remarks">
- <el-input v-model="formData.remarks" type="textarea" :rows="2" placeholder="请输入备注" />
- </el-form-item>
- </el-col>
- </el-row>
- </div>
- <!-- 设备信息展示 -->
- <div class="form-section" v-if="selectedDevice">
- <div class="section-header">
- <i class="el-icon-s-platform"></i>
- <span class="section-title">设备信息</span>
- </div>
- <el-descriptions :column="3" border size="small">
- <el-descriptions-item label="装置">{{ selectedDevice.plant }}</el-descriptions-item>
- <el-descriptions-item label="设备位号">{{ selectedDevice.devTag }}</el-descriptions-item>
- <el-descriptions-item label="设备名称">{{ selectedDevice.devName }}</el-descriptions-item>
- <el-descriptions-item label="位置">{{ selectedDevice.devLoc }}</el-descriptions-item>
- <el-descriptions-item label="设备类型">{{ selectedDevice.devType }}</el-descriptions-item>
- <el-descriptions-item label="区域负责人">{{ selectedDevice.areaResponsible }}</el-descriptions-item>
- </el-descriptions>
- </div>
- <!-- 部件列表及维修记录选择 -->
- <div class="form-section" v-if="compoList.length > 0">
- <div class="section-header">
- <i class="el-icon-s-grid"></i>
- <span class="section-title">部件维修选择</span>
- </div>
- <el-table
- :data="compoList"
- border
- size="small"
- :height="500"
- style="margin-top: 10px">
- <el-table-column type="index" label="序号" width="60" align="center" />
- <el-table-column label="部件名称" prop="compoName" width="150" :show-overflow-tooltip="true" />
- <el-table-column label="检查频率/日期" width="120" align="center">
- <template slot-scope="scope">
- <div style="line-height: 1.2;">
- <div style="font-weight: bold; margin-bottom: 2px;">{{ translateFrequency(scope.row.checkFreq) || '-' }}</div>
- <div style="font-size: 12px; color: #666;">{{ scope.row.lastCheckDate ? parseTime(scope.row.lastCheckDate, '{y}-{m}-{d}') : '-' }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="维修频率/日期" width="120" align="center">
- <template slot-scope="scope">
- <div style="line-height: 1.2;">
- <div style="font-weight: bold; margin-bottom: 2px;">{{ translateFrequency(scope.row.maintFreq) || '-' }}</div>
- <div style="font-size: 12px; color: #666;">{{ scope.row.lastMaintDate ? parseTime(scope.row.lastMaintDate, '{y}-{m}-{d}') : '-' }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="更换频率/日期" width="120" align="center">
- <template slot-scope="scope">
- <div style="line-height: 1.2;">
- <div style="font-weight: bold; margin-bottom: 2px;">{{ translateFrequency(scope.row.replaceFreq) || '-' }}</div>
- <div style="font-size: 12px; color: #666;">{{ scope.row.lastReplaceDate ? parseTime(scope.row.lastReplaceDate, '{y}-{m}-{d}') : '-' }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="本次维修" width="100" align="center">
- <template slot-scope="scope">
- <el-checkbox
- v-model="scope.row.needMaint"
- :disabled="scope.row.recordStatus === 2 || scope.row.recordStatus === '2'"
- @change="handleMaintCheckChange(scope.row)"
- >需要维修</el-checkbox>
- </template>
- </el-table-column>
- <el-table-column label="维修形式" width="200" align="center">
- <template slot-scope="scope">
- <el-radio-group
- v-model="scope.row.maintType"
- :disabled="!scope.row.needMaint || scope.row.recordStatus === 2 || scope.row.recordStatus === '2'"
- @change="handleMaintTypeChange(scope.row)"
- style="display: flex; flex-direction: row; gap: 0px;">
- <el-radio label="1" style="margin-right: 0; margin-left: 0;">检查</el-radio>
- <el-radio label="2" style="margin-right: 0; margin-left: 0;">维修</el-radio>
- <el-radio label="3" style="margin-right: 0; margin-left: 0;">更换</el-radio>
- </el-radio-group>
- </template>
- </el-table-column>
- <el-table-column label="负责人" width="150" align="center">
- <template slot-scope="scope">
- <el-select
- v-model="scope.row.maintResponsible"
- :placeholder="getResponsiblePlaceholder(scope.row.maintType)"
- style="width: 100%"
- :disabled="!scope.row.needMaint || scope.row.recordStatus === 2 || scope.row.recordStatus === '2'"
- clearable
- filterable>
- <el-option
- v-for="staff in staffOptions"
- :key="staff.staffid"
- :label="`${staff.name} (${staff.staffid})`"
- :value="staff.staffid">
- </el-option>
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="维修状态" width="100" align="center">
- <template slot-scope="scope">
- <el-tag
- v-if="scope.row.recordStatus !== undefined && scope.row.recordStatus !== null"
- :type="getRecordStatusTagType(scope.row.recordStatus)"
- size="small"
- >
- {{ getRecordStatusText(scope.row.recordStatus) }}
- </el-tag>
- <span v-else>-</span>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="handleSubmit" v-if="!formData.planId">提交申请</el-button>
- <el-button type="primary" @click="handleSubmit" v-else-if="formData.approvalStatus !== '1'">确 定</el-button>
- <el-button type="primary" @click="handleSubmit" v-else>再次提交申请</el-button>
- <el-button @click="handleCancel">取 消</el-button>
- </div>
- </el-dialog>
- </template>
- <script>
- import { listRel_device, getRel_device } from "@/api/reliability/rel_device";
- import { listRel_compo } from "@/api/reliability/rel_compo";
- import { listStaffmgrAll } from "@/api/plant/staffmgr";
- import { parseTime as formatTime } from "@/utils/ruoyi";
- export default {
- name: "MaintPlanForm",
- props: {
- visible: {
- type: Boolean,
- default: false
- },
- title: {
- type: String,
- default: "设备维修计划"
- },
- form: {
- type: Object,
- default: () => ({})
- }
- },
- data() {
- return {
- dialogVisible: this.visible,
- formData: {},
- rules: {
- devId: [
- { required: true, message: "请选择设备", trigger: "change" }
- ],
- planTime: [
- { required: true, message: "请选择计划开始时间", trigger: "change" }
- ],
- approver: [
- { required: true, message: "请选择审批人", trigger: "change" }
- ]
- },
- // 设备相关
- deviceOptions: [],
- deviceLoading: false,
- selectedDevice: null,
- // 部件相关
- compoList: [],
- // 所有人员选项
- staffOptions: []
- };
- },
- watch: {
- visible(newVal) {
- this.dialogVisible = newVal;
- if (newVal) {
- this.initForm();
- }
- },
- dialogVisible(newVal) {
- if (!newVal) {
- this.$emit('update:visible', false);
- }
- },
- form: {
- handler(newVal) {
- if (newVal && Object.keys(newVal).length > 0) {
- this.formData = { ...newVal };
- if (this.formData.relDevice) {
- this.selectedDevice = this.formData.relDevice;
- if (this.formData.relDevice.devId && !this.formData.devId) {
- this.formData.devId = this.formData.relDevice.devId;
- }
- if (this.formData.planId && this.formData.relDevice.devId) {
- this.deviceOptions = [this.formData.relDevice];
- }
- // 自动填充设备负责人(如果还没有设置责任人)
- if (this.formData.relDevice.areaResponsible && this.staffOptions.length > 0 && !this.formData.responsible) {
- const staff = this.staffOptions.find(s => s.staffid === this.formData.relDevice.areaResponsible);
- if (staff) {
- this.formData.responsible = staff.name;
- }
- }
- if (this.formData.compoList && this.formData.compoList.length > 0) {
- this.initCompoListFromData(this.formData.compoList);
- } else if (this.selectedDevice.devTag) {
- this.loadCompoList(this.selectedDevice.devTag);
- }
- } else if (this.formData.devId) {
- // 当从外部传入 devId 时,需要加载设备信息并添加到 deviceOptions
- this.loadDeviceInfo(this.formData.devId);
- getRel_device(this.formData.devId).then(response => {
- // 确保 deviceOptions 中包含该设备,以便下拉框能正确显示
- const deviceExists = this.deviceOptions.find(d => d.devId === this.formData.devId);
- if (!deviceExists) {
- this.deviceOptions = [response.data];
- }
- });
- }
- const convertIdsToNames = () => {
- // 审批人和责任人都已经是staffId,无需转换,直接使用
- // 显示时通过 el-option 的 label 显示"名称 (员工号)"格式
- };
- if (this.staffOptions.length > 0) {
- this.$nextTick(convertIdsToNames);
- } else {
- const checkStaffOptions = () => {
- if (this.staffOptions.length > 0) {
- this.$nextTick(convertIdsToNames);
- } else {
- setTimeout(checkStaffOptions, 100);
- }
- };
- checkStaffOptions();
- }
- } else if (!newVal || Object.keys(newVal).length === 0) {
- this.resetForm();
- }
- },
- deep: true,
- immediate: true
- }
- },
- created() {
- this.getStaffList();
- },
- methods: {
- /** 查询人员列表 */
- getStaffList() {
- listStaffmgrAll().then(response => {
- this.staffOptions = response.rows || response.data || [];
- }).catch(error => {
- console.error('加载人员数据失败:', error);
- });
- },
- /** 初始化表单 */
- initForm() {
- if (!this.formData.planId && (!this.formData.devId && !this.formData.planTime)) {
- this.resetForm();
- }
- },
- /** 表单重置 */
- resetForm() {
- this.formData = {
- planId: null,
- devId: null,
- plant: null,
- devName: null,
- devTag: null,
- planTime: null,
- approvalStatus: "0",
- responsible: null,
- completionStatus: "0",
- processId: null,
- approver: null,
- delFlag: null,
- createrCode: null,
- createdate: null,
- updaterCode: null,
- updatedate: null,
- deptId: null,
- remarks: null,
- maintComponents: []
- };
- this.selectedDevice = null;
- this.compoList = [];
- this.deviceOptions = [];
- this.$nextTick(() => {
- if (this.$refs.form) {
- this.$refs.form.clearValidate();
- }
- });
- },
- /** 设备下拉框获得焦点 */
- handleDeviceFocus() {
- // 预留方法,可在此处加载默认设备列表
- },
- /** 设备选择改变 */
- handleDeviceChange(devId) {
- if (!devId) {
- this.selectedDevice = null;
- this.compoList = [];
- return;
- }
- // 获取设备详情
- getRel_device(devId).then(response => {
- this.selectedDevice = response.data;
- this.formData.plant = response.data.plant;
- this.formData.devName = response.data.devName;
- this.formData.devTag = response.data.devTag;
- // 自动填充设备负责人(areaResponsible)
- if (response.data.areaResponsible && this.staffOptions.length > 0) {
- const staff = this.staffOptions.find(s => s.staffid === response.data.areaResponsible);
- if (staff) {
- this.formData.responsible = staff.name;
- }
- }
- // 加载该设备的部件列表(使用devTag)
- if (this.selectedDevice.devTag) {
- this.loadCompoList(this.selectedDevice.devTag);
- }
- });
- },
- /** 搜索设备 */
- searchDevice(query) {
- if (query !== '') {
- this.deviceLoading = true;
- listRel_device({
- devTag: query,
- devName: query,
- pageNum: 1,
- pageSize: 50
- }).then(response => {
- this.deviceOptions = response.rows || [];
- this.deviceLoading = false;
- }).catch(() => {
- this.deviceLoading = false;
- this.deviceOptions = [];
- });
- } else {
- this.deviceOptions = [];
- }
- },
- /** 加载设备信息 */
- loadDeviceInfo(devId) {
- getRel_device(devId).then(response => {
- this.selectedDevice = response.data;
- // 将当前设备添加到deviceOptions中,以便下拉框显示
- const deviceExists = this.deviceOptions.find(d => d.devId === devId);
- if (!deviceExists) {
- this.deviceOptions = [response.data];
- }
- // 自动填充设备负责人(areaResponsible),如果还没有设置责任人
- if (response.data.areaResponsible && this.staffOptions.length > 0 && !this.formData.responsible) {
- const staff = this.staffOptions.find(s => s.staffid === response.data.areaResponsible);
- if (staff) {
- this.formData.responsible = staff.name;
- }
- }
- // 使用selectedDevice的devTag来加载部件列表
- if (this.selectedDevice && this.selectedDevice.devTag) {
- this.loadCompoList(this.selectedDevice.devTag);
- }
- });
- },
- /** 从后端数据初始化部件列表 */
- initCompoListFromData(compoListData) {
- this.compoList = compoListData.map(compo => ({
- ...compo,
- needMaint: false,
- maintType: '',
- maintResponsible: '',
- recordStatus: null,
- checkFreq: compo.inspFreq || '',
- lastCheckDate: compo.lastInspDate || '',
- maintFreq: compo.fixFreq || '',
- lastMaintDate: compo.lastFixDate || '',
- replaceFreq: compo.replaceFreq || '',
- lastReplaceDate: compo.lastReplaceDate || '',
- inspector: compo.inspector || '',
- fixer: compo.fixer || '',
- inspectorName: compo.inspectorName || '',
- fixerName: compo.fixerName || '',
- }));
- this.$nextTick(() => {
- setTimeout(() => {
- this.markSelectedComponents();
- }, 100);
- });
- },
- /** 加载部件列表 */
- loadCompoList(devTag) {
- const targetDevTag = devTag || (this.selectedDevice ? this.selectedDevice.devTag : null);
- if (!targetDevTag) {
- return;
- }
- listRel_compo({
- devTag: targetDevTag,
- pageNum: 1,
- pageSize: 1000
- }).then(response => {
- const compos = response.rows || [];
- this.initCompoListFromData(compos);
- });
- },
- /** 标记已选择的部件(根据维修记录) */
- markSelectedComponents() {
- if (!this.compoList || this.compoList.length === 0) {
- return;
- }
- const maintRecords = this.formData.maintRecordsList || this.formData.maintRecords || [];
- if (!this.formData.planId || !maintRecords || maintRecords.length === 0) {
- return;
- }
- const markComponents = () => {
- this.compoList.forEach(compo => {
- const record = maintRecords.find(r => r.compoId == compo.compoId);
- if (record) {
- compo.recordStatus = record.recordStatus;
- // 如果recordStatus为-1(删除申请中),则不勾选维修
- if (record.recordStatus === -1 || record.recordStatus === '-1') {
- compo.needMaint = false;
- compo.maintType = '';
- compo.maintResponsible = '';
- } else {
- compo.needMaint = true;
- compo.maintType = record.maintType;
- // 责任人存储staffId
- if (record.responsible) {
- compo.maintResponsible = record.responsible;
- } else {
- // 没有记录的responsible,根据维修类型使用默认值
- if (compo.maintType === '1') {
- compo.maintResponsible = compo.inspector || '';
- } else if (compo.maintType === '2' || compo.maintType === '3') {
- compo.maintResponsible = compo.fixer || '';
- }
- }
- }
- }
- });
- };
- if (this.staffOptions.length > 0) {
- this.$nextTick(markComponents);
- } else {
- const checkStaffOptions = () => {
- if (this.staffOptions.length > 0) {
- this.$nextTick(markComponents);
- } else {
- setTimeout(checkStaffOptions, 100);
- }
- };
- checkStaffOptions();
- }
- },
- /** 维修选择改变 */
- handleMaintCheckChange(compo) {
- if (!compo.needMaint) {
- compo.maintType = '';
- compo.maintResponsible = '';
- }
- },
- /** 维修形式改变 */
- handleMaintTypeChange(compo) {
- if (compo.maintType === '1') {
- compo.maintResponsible = compo.inspector || '';
- } else if (compo.maintType === '2' || compo.maintType === '3') {
- compo.maintResponsible = compo.fixer || '';
- } else {
- compo.maintResponsible = '';
- }
- },
- /** 根据姓名获取工号 */
- getStaffIdByName(name) {
- if (!name) return '';
- const staff = this.staffOptions.find(s => s.name === name);
- return staff ? staff.staffid : '';
- },
- getResponsiblePlaceholder(maintType) {
- switch(maintType) {
- case '1': return '选择检查人';
- case '2': return '选择维修人';
- case '3': return '选择更换人';
- default: return '选择负责人';
- }
- },
- /** 翻译频率字段 */
- translateFrequency(frequency) {
- if (!frequency) return '';
- const match = frequency.match(/^(\d+)([ym])$/);
- if (match) {
- const number = match[1];
- const unit = match[2];
- switch (unit) {
- case 'y':
- return `${number}年一次`;
- case 'm':
- return `${number}月一次`;
- default:
- return frequency;
- }
- }
- return frequency;
- },
- /** 时间格式化 */
- parseTime(time, pattern) {
- return formatTime(time, pattern);
- },
- /** 获取维修状态文本 */
- getRecordStatusText(status) {
- if (status === -1 || status === '-1') return '删除申请中';
- if (status === 0 || status === '0') return '新增申请中';
- if (status === 1 || status === '1') return '待完成';
- if (status === 2 || status === '2') return '已完成';
- return status != null ? status : '-';
- },
- /** 获取维修状态标签类型 */
- getRecordStatusTagType(status) {
- if (status === -1 || status === '-1') return 'danger';
- if (status === 0 || status === '0') return 'warning';
- if (status === 1 || status === '1') return 'info';
- if (status === 2 || status === '2') return 'success';
- return '';
- },
- /** 提交表单 */
- handleSubmit() {
- this.$refs.form.validate(valid => {
- if (valid) {
- if (this.compoList.length > 0) {
- const maintComponents = this.compoList
- .filter(compo => compo.needMaint)
- .map(compo => ({
- compoId: compo.compoId,
- compoName: compo.compoName,
- maintType: compo.maintType,
- responsible: compo.maintResponsible,
- inspectContent: '',
- maintContent: '',
- maintResult: '',
- maintCost: null,
- maintDuration: null,
- processLoss: '',
- attachments: '',
- remarks: ''
- }));
- this.formData.maintComponents = maintComponents;
- }
- // 审批人和责任人都已经是staffId格式,无需转换
- this.$emit('submit', this.formData);
- }
- });
- },
- /** 取消 */
- handleCancel() {
- this.handleClose();
- },
- /** 关闭弹窗 */
- handleClose() {
- this.resetForm();
- this.$emit('update:visible', false);
- this.$emit('cancel');
- }
- }
- };
- </script>
- <style scoped lang="scss">
- .form-section {
- margin-bottom: 20px;
- .section-header {
- display: flex;
- align-items: center;
- margin-bottom: 15px;
- padding-bottom: 10px;
- border-bottom: 1px solid #e4e7ed;
- .el-icon-info,
- .el-icon-s-platform,
- .el-icon-s-grid,
- .el-icon-setting {
- font-size: 18px;
- color: #409EFF;
- margin-right: 8px;
- }
- .section-title {
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- }
- }
- }
- .dialog-footer {
- text-align: right;
- }
- // 紧凑的radio按钮样式
- ::v-deep .el-table .el-radio__label {
- padding-left: 2px !important;
- }
- </style>
|