ZN
5 小时以前 aaf2e90e8f2967dde6f3bd5351523234881e2c98
Merge remote-tracking branch 'origin/dev_KTHG' into dev_KTHG
已添加3个文件
已修改14个文件
1606 ■■■■■ 文件已修改
README.md 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/favicon/KTHGico.ico 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/logo/KTHGLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
multiple/config.json 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/spareParts.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/ProductSelectDialog.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/components/formDia.vue 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/index.vue 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/MaintainModal.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/spareParts/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/DetailDialog.vue 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 577 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/Record.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/New.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Qualified.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -11,10 +11,10 @@
## å¹³å°ç®€ä»‹
* æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
* é…å¥—后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) æˆ– [RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast) ç‰ˆæœ¬ã€‚
* å‰ç«¯æŠ€æœ¯æ ˆï¼ˆ[Vue2](https://cn.vuejs.org) + [Element](https://github.com/ElemeFE/element) + [Vue CLI](https://cli.vuejs.org/zh)),请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui)。
* é˜¿é‡Œäº‘折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)  
- æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
- é…å¥—后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) æˆ– [RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast) ç‰ˆæœ¬ã€‚
- å‰ç«¯æŠ€æœ¯æ ˆï¼ˆ[Vue2](https://cn.vuejs.org) + [Element](https://github.com/ElemeFE/element) + [Vue CLI](https://cli.vuejs.org/zh)),请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui)。
- é˜¿é‡Œäº‘折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)  
## å‰ç«¯è¿è¡Œ
@@ -33,7 +33,7 @@
# æž„建测试环境 yarn build:stage
# æž„建生产环境 yarn build:prod
# æž„建生产环境 yarn build:prod -- --company="AAA"
# æž„建生产环境 yarn build:prod -- --company="KTHG"
# å‰ç«¯è®¿é—®åœ°å€ http://localhost:80
```
@@ -102,7 +102,6 @@
        <td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
    </tr>
</table>
## è‹¥ä¾å‰åŽç«¯åˆ†ç¦»äº¤æµç¾¤
multiple/assets/favicon/KTHGico.ico
multiple/assets/logo/KTHGLogo.png
multiple/config.json
@@ -7,15 +7,15 @@
    "logo": "logo/HYSNLogo.png",
    "favicon": "favicon/HYSNico.ico"
  },
  "TEST": {
  "KTHG": {
    "env": {
      "VITE_APP_TITLE": "中小企业数字化转型二级套餐包",
      "VITE_BASE_API": "http://1.15.17.182:9003",
      "VITE_JAVA_API": "http://1.15.17.182:9002"
      "VITE_APP_TITLE": "坤泰化工信息管理",
      "VITE_BASE_API": "http://1.15.17.182:9011",
      "VITE_JAVA_API": "http://1.15.17.182:9010"
    },
    "screen": "screen/HYSNView.png",
    "logo": "logo/ZGLTLogo.png",
    "favicon": "favicon/favicon.ico"
    "screen": "screen/DHDCView.png",
    "logo": "logo/KTHGLogo.png",
    "favicon": "favicon/KTHGico.ico"
  },
  "screen": "/src/assets/images/login-background.png",
  "logo": "/src/assets/logo/logo.png",
src/api/equipmentManagement/spareParts.js
@@ -20,6 +20,15 @@
  });
};
// æŸ¥è¯¢å¤‡ä»¶é€‰é¡¹
export const getSparePartsOptions = (params) => {
  return request({
    url: "/spareParts/getByIdDeviceId",
    method: "get",
    params,
  });
};
/**
 * @desc æ–°å¢ž
 */
src/views/basicData/product/ProductSelectDialog.vue
@@ -20,6 +20,7 @@
      @selection-change="handleSelectionChange" @select="handleSelect">
      <el-table-column type="selection" width="55" />
      <el-table-column type="index" label="序号" width="60" />
      <el-table-column prop="parentName" label="类型" min-width="160" />
      <el-table-column prop="productName" label="产品大类" min-width="160" />
      <el-table-column prop="model" label="型号名称" min-width="200" />
      <el-table-column prop="unit" label="单位" min-width="160" />
src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -1,90 +1,185 @@
<template>
  <div>
    <el-dialog :title="operationType === 'add' ? '新增巡检任务' : '编辑巡检任务'"
               v-model="dialogVisitable" width="800px" @close="cancel">
      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
               v-model="dialogVisitable"
               width="900px"
               @close="cancel">
      <el-form ref="formRef"
               :model="form"
               :rules="rules"
               label-width="180px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备名称" prop="taskId">
              <el-select v-model="form.taskId" @change="setDeviceModel">
                <el-option
                  v-for="(item, index) in deviceOptions"
            <el-form-item label="巡检任务名称"
                          prop="taskName">
              <el-input v-model="form.taskName"
                        placeholder="请输入巡检任务名称"
                        type="textarea" />
              <!-- <el-select v-model="form.taskId"
                         @change="setDeviceModel">
                <el-option v-for="(item, index) in deviceOptions"
                  :key="index"
                  :label="item.deviceName"
                  :value="item.id"
                ></el-option>
              </el-select>
                           :value="item.id"></el-option>
              </el-select> -->
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="巡检人" prop="inspector">
              <el-select v-model="form.inspector" placeholder="请选择" multiple clearable>
                <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/>
            <el-form-item label="巡检人"
                          prop="inspector">
              <el-select v-model="form.inspector"
                         placeholder="请选择"
                         multiple
                         clearable>
                <el-option v-for="item in userList"
                           :label="item.nickName"
                           :value="item.userId"
                           :key="item.userId" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row v-show="false">
          <el-col :span="12">
            <el-form-item label="必须拍照视为巡检成功"
                          prop="takePhone">
              <el-radio-group v-model="form.takePhone">
                <el-radio :label="true">是</el-radio>
                <el-radio :label="false">否</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="上传相册照片"
                          prop="takeAlbum">
              <el-radio-group v-model="form.takeAlbum">
                <el-radio :label="false">不可</el-radio>
                <el-radio :label="true">可</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="备注" prop="remarks">
              <el-input v-model="form.remarks" placeholder="请输入备注" type="textarea" />
            <el-form-item label="备注"
                          prop="remarks">
              <el-input v-model="form.remarks"
                        placeholder="请输入备注"
                        type="textarea" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="任务频率" prop="frequencyType">
              <el-select v-model="form.frequencyType" placeholder="请选择" clearable>
                <el-option label="每日" value="DAILY"/>
                <el-option label="每周" value="WEEKLY"/>
                <el-option label="每月" value="MONTHLY"/>
            <el-form-item label="任务频率"
                          prop="frequencyType">
              <el-select v-model="form.frequencyType"
                         placeholder="请选择"
                         clearable>
                <el-option label="每日"
                           value="DAILY" />
                <el-option label="每周"
                           value="WEEKLY" />
                <el-option label="每月"
                           value="MONTHLY" />
                <!-- <el-option label="季度" value="QUARTERLY"/> -->
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-time-picker v-model="form.frequencyDetail" placeholder="选择时间" format="HH:mm"
          <el-col :span="12"
                  v-if="form.frequencyType === 'DAILY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-time-picker v-model="form.frequencyDetail"
                              placeholder="选择时间"
                              format="HH:mm"
                              value-format="HH:mm" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-select v-model="form.week" placeholder="请选择" clearable style="width: 50%">
                <el-option label="周一" value="MON"/>
                <el-option label="周二" value="TUE"/>
                <el-option label="周三" value="WED"/>
                <el-option label="周四" value="THU"/>
                <el-option label="周五" value="FRI"/>
                <el-option label="周六" value="SAT"/>
                <el-option label="周日" value="SUN"/>
          <el-col :span="12"
                  v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-select v-model="form.week"
                         placeholder="请选择"
                         clearable
                         style="width: 50%">
                <el-option label="周一"
                           value="MON" />
                <el-option label="周二"
                           value="TUE" />
                <el-option label="周三"
                           value="WED" />
                <el-option label="周四"
                           value="THU" />
                <el-option label="周五"
                           value="FRI" />
                <el-option label="周六"
                           value="SAT" />
                <el-option label="周日"
                           value="SUN" />
              </el-select>
              <el-time-picker v-model="form.time" placeholder="选择时间" format="HH:mm"
                              value-format="HH:mm"  style="width: 50%"/>
              <el-time-picker v-model="form.time"
                              placeholder="选择时间"
                              format="HH:mm"
                              value-format="HH:mm"
                              style="width: 50%" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                  v-model="form.frequencyDetail"
          <el-col :span="12"
                  v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-date-picker v-model="form.frequencyDetail"
                  type="datetime"
                  clearable
                  placeholder="选择开始日期"
                  format="DD,HH:mm"
                  value-format="DD,HH:mm"
              />
                              value-format="DD,HH:mm" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                  v-model="form.frequencyDetail"
          <el-col :span="12"
                  v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-date-picker v-model="form.frequencyDetail"
                  type="datetime"
                  clearable
                  placeholder="选择开始日期"
                  format="MM,DD,HH:mm"
                  value-format="MM,DD,HH:mm"
              />
                              value-format="MM,DD,HH:mm" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12"
                  v-if="form.frequencyType === 'DAILY' && form.frequencyType">
            <el-form-item label="时限(小时)"
                          prop="inspectionDeadline">
              <el-input v-model="form.inspectionDeadline"
                        type="number"
                        placeholder="请输入备注">
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12"
                  v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="时限(天)"
                          prop="inspectionDeadline">
              <el-input v-model="form.inspectionDeadline"
                        placeholder="请输入备注"
                        type="number">
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12"
                  v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="时限(天)"
                          prop="inspectionDeadline">
              <el-input v-model="form.inspectionDeadline"
                        placeholder="请输入备注"
                        type="number">
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
@@ -92,7 +187,8 @@
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancel">取消</el-button>
          <el-button type="primary" @click="submitForm">保存</el-button>
          <el-button type="primary"
                     @click="submitForm">保存</el-button>
        </div>
      </template>
    </el-dialog>
@@ -101,34 +197,42 @@
<script setup>
import {reactive, ref, getCurrentInstance, toRefs} from "vue";
import useUserStore from '@/store/modules/user'
  import useUserStore from "@/store/modules/user";
import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
const { proxy } = getCurrentInstance()
const emit = defineEmits()
const userStore = useUserStore()
  const { proxy } = getCurrentInstance();
  const emit = defineEmits();
  const userStore = useUserStore();
const dialogVisitable = ref(false);
const operationType = ref('add');
  const operationType = ref("add");
const deviceOptions = ref([]);
const data = reactive({
  form: {
    taskId: undefined,
    taskName: undefined,
    inspector: '',
    inspectorIds: '',
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
    week: '',
    time: ''
      inspector: "",
      inspectorIds: "",
      remarks: "",
      frequencyType: "",
      frequencyDetail: "",
      week: "",
      time: "",
      takePhone: true,
      takeAlbum: false,
      inspectionDeadline: "",
  },
    rules: {
        taskId: [{ required: true, message: "请选择设备", trigger: "change" },],
        inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" },],
      // taskId: [{ required: true, message: "请选择设备", trigger: "change" }],
      taskName: [
        { required: true, message: "请输入巡检任务名称", trigger: "blur" },
      ],
      inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" }],
        dateStr: [{ required: true, message: "请选择登记时间", trigger: "change" }],
        frequencyType: [{ required: true, message: "请选择任务频率", trigger: "change" }],
      frequencyType: [
        { required: true, message: "请选择任务频率", trigger: "change" },
      ],
        frequencyDetail: [
            {
                required: true,
@@ -136,24 +240,31 @@
                trigger: "change",
                validator: (rule, value, callback) => {
                    if (!form.value.frequencyType) {
                        callback()
                        return
              callback();
              return;
                    }
                    if (form.value.frequencyType === 'WEEKLY') {
            if (form.value.frequencyType === "WEEKLY") {
                        if (!form.value.week || !form.value.time) {
                            callback(new Error("请选择日期和时间"))
                callback(new Error("请选择日期和时间"));
                        } else {
                            callback()
                callback();
                        }
                    } else {
                        if (!value) {
                            callback(new Error("请选择日期"))
                callback(new Error("请选择日期"));
                        } else {
                            callback()
                callback();
                        }
                    }
                }
            }
          },
        },
      ],
      inspectionDeadline: [
        {
          required: true,
          message: "请输入时限",
          trigger: "blur",
        },
        ],
        week: [
            {
@@ -161,13 +272,13 @@
                message: "请选择星期",
                trigger: "change",
                validator: (rule, value, callback) => {
                    if (form.value.frequencyType === 'WEEKLY' && !value) {
                        callback(new Error("请选择星期"))
            if (form.value.frequencyType === "WEEKLY" && !value) {
              callback(new Error("请选择星期"));
                    } else {
                        callback()
              callback();
                    }
                }
            }
          },
        },
        ],
        time: [
            {
@@ -175,113 +286,115 @@
                message: "请选择时间",
                trigger: "change",
                validator: (rule, value, callback) => {
                    if (form.value.frequencyType === 'WEEKLY' && !value) {
                        callback(new Error("请选择时间"))
            if (form.value.frequencyType === "WEEKLY" && !value) {
              callback(new Error("请选择时间"));
                    } else {
                        callback()
              callback();
                    }
                }
            }
        ]
    }
})
const { form, rules } = toRefs(data)
const userList = ref([])
          },
        },
      ],
    },
  });
  const { form, rules } = toRefs(data);
  const userList = ref([]);
const loadDeviceName = async () => {
  const { data } = await getDeviceLedger();
  deviceOptions.value = data;
};
const setDeviceModel = (id) => {
  const option = deviceOptions.value.find((item) => item.id === id);
  const setDeviceModel = id => {
    const option = deviceOptions.value.find(item => item.id === id);
  if (option) {
    form.value.taskName = option.deviceName;
  }
}
  };
// æ‰“开弹框
const openDialog = async (type, row) => {
  dialogVisitable.value = true
  operationType.value = type
    dialogVisitable.value = true;
    operationType.value = type;
  
  // é‡ç½®è¡¨å•
  resetForm();
  
  // åŠ è½½ç”¨æˆ·åˆ—è¡¨
  userListNoPageByTenantId().then((res) => {
    userListNoPageByTenantId().then(res => {
    userList.value = res.data;
  });
  
  // åŠ è½½è®¾å¤‡åˆ—è¡¨
  await loadDeviceName();
  
  if (type === 'edit' && row) {
    form.value = {...row}
    form.value.inspector = form.value.inspectorIds.split(',').map(Number)
    if (type === "edit" && row) {
      form.value = { ...row };
      form.value.inspector = form.value.inspectorIds.split(",").map(Number);
    
    // å¦‚果有设备ID,自动设置设备信息
    if (form.value.taskId) {
      setDeviceModel(form.value.taskId);
      // if (form.value.taskId) {
      //   setDeviceModel(form.value.taskId);
      // }
    }
  }
}
  };
// å…³é—­å¯¹è¯æ¡†
const cancel = () => {
  resetForm()
  dialogVisitable.value = false
  emit('closeDia')
}
    resetForm();
    dialogVisitable.value = false;
    emit("closeDia");
  };
// é‡ç½®è¡¨å•函数
const resetForm = () => {
  if (proxy.$refs.formRef) {
    proxy.$refs.formRef.resetFields()
      proxy.$refs.formRef.resetFields();
  }
  // é‡ç½®è¡¨å•数据确保设备信息正确重置
  form.value = {
    taskId: undefined,
    taskName: undefined,
    inspector: '',
    inspectorIds: '',
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
    week: '',
    time: ''
  }
}
      inspector: "",
      inspectorIds: "",
      remarks: "",
      frequencyType: "",
      frequencyDetail: "",
      week: "",
      time: "",
      takePhone: true,
      takeAlbum: false,
      inspectionDeadline: "",
    };
  };
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(async valid => {
    if (valid) {
      try {
        form.value.inspectorIds = form.value.inspector.join(',')
        delete form.value.inspector
          form.value.inspectorIds = form.value.inspector.join(",");
          delete form.value.inspector;
        
        if (form.value.frequencyType === 'WEEKLY') {
          let frequencyDetail = ''
          frequencyDetail = form.value.week + ',' + form.value.time
          form.value.frequencyDetail = frequencyDetail
          if (form.value.frequencyType === "WEEKLY") {
            let frequencyDetail = "";
            frequencyDetail = form.value.week + "," + form.value.time;
            form.value.frequencyDetail = frequencyDetail;
        }
        
        let res = await userStore.getInfo()
        form.value.registrantId = res.user.userId
          let res = await userStore.getInfo();
          form.value.registrantId = res.user.userId;
        
        await addOrEditTimingTask(form.value)
        cancel()
        proxy.$modal.msgSuccess('提交成功')
          await addOrEditTimingTask(form.value);
          cancel();
          proxy.$modal.msgSuccess("提交成功");
      } catch (error) {
        proxy.$modal.msgError('提交失败,请重试')
          proxy.$modal.msgError("提交失败,请重试");
      }
    }
  })
}
defineExpose({ openDialog })
    });
  };
  defineExpose({ openDialog });
</script>
<style scoped>
</style>
src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
@@ -1,83 +1,32 @@
<template>
  <div>
    <el-dialog title="查看附件"
               v-model="dialogVisitable" width="800px" @close="cancel">
               v-model="dialogVisitable"
               width="800px"
               @close="cancel">
      <div class="upload-container">
        <!-- ç”Ÿäº§å‰ -->
        <div class="form-container">
          <div class="title">生产前</div>
          <div class="title">附件列表</div>
          <!-- å›¾ç‰‡åˆ—表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in beforeProductionImgs" :key="index"
            <img v-for="(item, index) in beforeProductionImgs"
                 :key="index"
                 @click="showMedia(beforeProductionImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
                 :src="item"
                 style="max-width: 100px; height: 100px; margin: 5px;"
                 alt="">
          </div>
          <!-- è§†é¢‘列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in beforeProductionVideos"
            <div v-for="(videoUrl, index) in beforeProductionVideos"
                :key="index"
                @click="showMedia(beforeProductionVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
                 style="position: relative; margin: 10px; cursor: pointer;">
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
          </div>
        </div>
        <!-- ç”Ÿäº§åŽ -->
        <div class="form-container">
          <div class="title">生产后</div>
          <!-- å›¾ç‰‡åˆ—表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in afterProductionImgs" :key="index"
                 @click="showMedia(afterProductionImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
          </div>
          <!-- è§†é¢‘列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in afterProductionVideos"
                :key="index"
                @click="showMedia(afterProductionVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
          </div>
        </div>
        <!-- ç”Ÿäº§é—®é¢˜ -->
        <div class="form-container">
          <div class="title">生产问题</div>
          <!-- å›¾ç‰‡åˆ—表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in productionIssuesImgs" :key="index"
                 @click="showMedia(productionIssuesImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
          </div>
          <!-- è§†é¢‘列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in productionIssuesVideos"
                :key="index"
                @click="showMedia(productionIssuesVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
                <img src="@/assets/images/video.png"
                     alt="播放"
                     style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
@@ -85,35 +34,33 @@
        </div>
      </div>
    </el-dialog>
    <!-- ç»Ÿä¸€åª’体查看器 -->
    <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer">
      <div class="media-viewer-content" @click.stop>
    <div v-if="isMediaViewerVisible"
         class="media-viewer-overlay"
         @click.self="closeMediaViewer">
      <div class="media-viewer-content"
           @click.stop>
        <!-- å›¾ç‰‡ -->
        <vue-easy-lightbox
            v-if="mediaType === 'image'"
        <vue-easy-lightbox v-if="mediaType === 'image'"
            :visible="isMediaViewerVisible"
            :imgs="mediaList"
            :index="currentMediaIndex"
            @hide="closeMediaViewer"
        ></vue-easy-lightbox>
                           @hide="closeMediaViewer"></vue-easy-lightbox>
        <!-- è§†é¢‘ -->
        <div v-else-if="mediaType === 'video'" style="position: relative;">
          <video
              :src="mediaList[currentMediaIndex]"
        <div v-else-if="mediaType === 'video'"
             style="position: relative;">
          <video :src="mediaList[currentMediaIndex]"
              autoplay
              controls
              style="max-width: 90vw; max-height: 80vh;"
          />
                 style="max-width: 90vw; max-height: 80vh;" />
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import VueEasyLightbox from 'vue-easy-lightbox';
  import { ref } from "vue";
  import VueEasyLightbox from "vue-easy-lightbox";
const { proxy } = getCurrentInstance();
// æŽ§åˆ¶å¼¹çª—显示
@@ -133,34 +80,34 @@
const isMediaViewerVisible = ref(false);
const currentMediaIndex = ref(0);
const mediaList = ref([]); // å­˜å‚¨å½“前要查看的媒体列表(含图片和视频对象)
const mediaType = ref('image'); // image | video
  const mediaType = ref("image"); // image | video
const javaApi = proxy.javaApi;
// å¤„理 URL:将 Windows è·¯å¾„转换为可访问的 URL
function processFileUrl(fileUrl) {
  if (!fileUrl) return '';
    if (!fileUrl) return "";
  
  // å¦‚æžœ URL æ˜¯ Windows è·¯å¾„格式(包含反斜杠),需要转换
  if (fileUrl && fileUrl.indexOf('\\') > -1) {
    if (fileUrl && fileUrl.indexOf("\\") > -1) {
    // æŸ¥æ‰¾ uploads å…³é”®å­—的位置,从那里开始提取相对路径
    const uploadsIndex = fileUrl.toLowerCase().indexOf('uploads');
      const uploadsIndex = fileUrl.toLowerCase().indexOf("uploads");
    if (uploadsIndex > -1) {
      // ä»Ž uploads å¼€å§‹æå–路径,并将反斜杠替换为正斜杠
      const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, '/');
      fileUrl = '/' + relativePath;
        const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, "/");
        fileUrl = "/" + relativePath;
    } else {
      // å¦‚果没有找到 uploads,提取最后一个目录和文件名
      const parts = fileUrl.split('\\');
        const parts = fileUrl.split("\\");
      const fileName = parts[parts.length - 1];
      fileUrl = '/uploads/' + fileName;
        fileUrl = "/uploads/" + fileName;
    }
  }
  
  // ç¡®ä¿æ‰€æœ‰éž http å¼€å¤´çš„ URL éƒ½æ‹¼æŽ¥ baseUrl
  if (fileUrl && !fileUrl.startsWith('http')) {
    if (fileUrl && !fileUrl.startsWith("http")) {
    // ç¡®ä¿è·¯å¾„以 / å¼€å¤´
    if (!fileUrl.startsWith('/')) {
      fileUrl = '/' + fileUrl;
      if (!fileUrl.startsWith("/")) {
        fileUrl = "/" + fileUrl;
    }
    // æ‹¼æŽ¥ baseUrl
    fileUrl = javaApi + fileUrl;
@@ -193,9 +140,9 @@
      videos.push(fileUrl);
    } else if (item.contentType) {
      // å¦‚果有 contentType,使用 contentType åˆ¤æ–­
      if (item.contentType.startsWith('image/')) {
        if (item.contentType.startsWith("image/")) {
        images.push(fileUrl);
      } else if (item.contentType.startsWith('video/')) {
        } else if (item.contentType.startsWith("video/")) {
        videos.push(fileUrl);
      }
    }
@@ -205,12 +152,18 @@
}
// æ‰“开弹窗并加载数据
const openDialog = async (row) => {
  const openDialog = async row => {
  // ä½¿ç”¨æ­£ç¡®çš„字段名:commonFileListBefore, commonFileListAfter
  // productionIssues å¯èƒ½ä¸å­˜åœ¨ï¼Œä½¿ç”¨ç©ºæ•°ç»„
  const { images: beforeImgs, videos: beforeVids } = processItems(row.commonFileListBefore || []);
  const { images: afterImgs, videos: afterVids } = processItems(row.commonFileListAfter || []);
  const { images: issueImgs, videos: issueVids } = processItems(row.productionIssues || []);
    const { images: beforeImgs, videos: beforeVids } = processItems(
      row.commonFileListBefore || []
    );
    const { images: afterImgs, videos: afterVids } = processItems(
      row.commonFileListAfter || []
    );
    const { images: issueImgs, videos: issueVids } = processItems(
      row.productionIssues || []
    );
  
  beforeProductionImgs.value = beforeImgs;
  beforeProductionVideos.value = beforeVids;
@@ -236,7 +189,7 @@
function closeMediaViewer() {
  isMediaViewerVisible.value = false;
  mediaList.value = [];
  mediaType.value = 'image';
    mediaType.value = "image";
}
// è¡¨å•关闭方法
@@ -254,6 +207,7 @@
  padding: 20px;
  border: 1px solid #dcdfe6;
  box-sizing: border-box;
    margin-bottom: 20px;
  
  .form-container {
    flex: 1;
src/views/equipmentManagement/inspectionManagement/index.vue
@@ -151,6 +151,78 @@
      },
    },
    {
      prop: "inspectionDeadlinetxt",
      label: "期限",
      minWidth: 150,
    },
    {
      prop: "inspectionStatus",
      label: "巡检状态",
      minWidth: 150,
      dataType: "tag",
      formatType: params => {
        const typeMap = {
          å·²å®Œæˆ: "info",
          æœªå·¡æ£€: "warning",
          è¶…期: "danger",
        };
        return typeMap[params] || "info";
      },
    },
    {
      prop: "frequencyDetail",
      label: "开始日期与时间",
      minWidth: 150,
      formatter: (row, column, cellValue) => {
        // å…ˆåˆ¤æ–­æ˜¯å¦æ˜¯å­—符串
        if (typeof cellValue !== "string") return "";
        let val = cellValue;
        const replacements = {
          MON: "周一",
          TUE: "周二",
          WED: "周三",
          THU: "周四",
          FRI: "周五",
          SAT: "周六",
          SUN: "周日",
        };
        // ä½¿ç”¨æ­£åˆ™ä¸€æ¬¡æ€§æ›¿æ¢æ‰€æœ‰åŒ¹é…é¡¹
        return val.replace(
          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
          match => replacements[match]
        );
      },
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "createTime", label: "登记日期", minWidth: 100 },
  ]);
  const columns1 = ref([
    { prop: "taskName", label: "巡检任务名称", minWidth: 160 },
    { prop: "remarks", label: "备注", minWidth: 150 },
    { prop: "inspector", label: "执行巡检人", minWidth: 150, slot: "inspector" },
    {
      prop: "frequencyType",
      label: "频次",
      minWidth: 150,
      // formatter: (_, __, val) => ({
      //   DAILY: "每日",
      //   WEEKLY: "每周",
      //   MONTHLY: "每月",
      //   QUARTERLY: "季度"
      // }[val] || "")
      formatData: params => {
        return params === "DAILY"
          ? "每日"
          : params === "WEEKLY"
          ? "每周"
          : params === "MONTHLY"
          ? "每月"
          : params === "QUARTERLY"
          ? "季度"
          : "";
      },
    },
    {
      prop: "frequencyDetail",
      label: "开始日期与时间",
      minWidth: 150,
@@ -221,7 +293,7 @@
    if (value === "taskManage") {
      const operationColumn = getOperationColumn(["edit"]);
      tableColumns.value = [
        ...columns.value,
        ...columns1.value,
        ...(operationColumn ? [operationColumn] : []),
      ];
      operationsArr.value = ["edit"];
@@ -293,6 +365,13 @@
          return processedItem;
        });
        tableData.value.forEach(item => {
          item.inspectionStatus = getFileStatus(item);
          item.inspectionDeadlinetxt =
            item.frequencyType === "DAILY"
              ? item.inspectionDeadline + "小时"
              : item.inspectionDeadline + "天";
        });
        total.value = res.data.total || 0;
      })
      .finally(() => {
@@ -345,7 +424,61 @@
      })
      .catch(() => {});
  };
  const getFileStatus = record => {
    console.log(record);
    if (record.takePhone) {
      if (record.commonFileListBefore && record.commonFileListBefore.length) {
        return "已完成";
      }
      if (record.frequencyType == "DAILY") {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(小时)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const hoursDiff = (now - createTime) / (1000 * 60 * 60);
          if (hoursDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      } else {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(天)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const daysDiff = (now - createTime) / (1000 * 60 * 60 * 24);
          if (daysDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      }
      return "未巡检";
    } else if (record.inspectionSubmitted) {
      return "已完成";
    } else {
      if (record.frequencyType == "DAILY") {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(小时)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const hoursDiff = (now - createTime) / (1000 * 60 * 60);
          if (hoursDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      } else {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(天)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const daysDiff = (now - createTime) / (1000 * 60 * 60 * 24);
          if (daysDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      }
      return "未巡检";
    }
  };
  // å¤šé€‰å˜æ›´
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
src/views/equipmentManagement/repair/Modal/MaintainModal.vue
@@ -32,6 +32,16 @@
          style="width: 100%"
        />
      </el-form-item>
      <el-form-item label="设备备件">
        <el-select v-model="form.sparePartsIds" :loading="loadingSparePartOptions" placeholder="请选择设备备件" multiple filterable>
          <el-option
              v-for="item in sparePartOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id"
          />
        </el-select>
      </el-form-item>
    </el-form>
  </FormDialog>
</template>
@@ -43,6 +53,7 @@
import useUserStore from "@/store/modules/user";
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import {getSparePartsOptions} from "@/api/equipmentManagement/spareParts.js";
defineOptions({
  name: "维修模态框",
@@ -61,7 +72,10 @@
  maintenanceResult: undefined, // ç»´ä¿®ç»“æžœ
  maintenanceTime: undefined, // ç»´ä¿®æ—¥æœŸ
  status: 0,
  sparePartsIds: undefined,
});
const sparePartOptions = ref([])
const loadingSparePartOptions = ref(true)
const setForm = (data) => {
  form.maintenanceName = data.maintenanceName ?? userStore.nickName;
@@ -71,12 +85,18 @@
      ? dayjs(data.maintenanceTime).format("YYYY-MM-DD HH:mm:ss")
      : dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.status = 1; // é»˜è®¤çŠ¶æ€ä¸ºå®Œç»“
  form.sparePartsIds = data.sparePartsIds;
};
const sendForm = async () => {
  loading.value = true;
  try {
    const { code } = await addMaintain({ id: repairId.value, ...form });
    const data = {
      id: repairId.value,
      ...form,
      sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
    }
    const { code } = await addMaintain(data);
    if (code == 200) {
      ElMessage.success("维修成功");
      emits("ok");
@@ -87,6 +107,17 @@
    loading.value = false;
  }
};
const fetchSparePartOptions = (deviceLedgerId) => {
  loadingSparePartOptions.value = true;
  getSparePartsOptions({ deviceLedgerId: deviceLedgerId }).then((res) => {
    if (res.code == 200) {
      sparePartOptions.value = res.data || [];
    }
  }).finally(() => {
    loadingSparePartOptions.value = false;
  })
}
const handleCancel = () => {
  resetForm();
@@ -103,6 +134,7 @@
  visible.value = true;
  await nextTick();
  setForm(row);
  fetchSparePartOptions(row.deviceLedgerId)
};
defineExpose({
src/views/equipmentManagement/spareParts/index.vue
@@ -36,7 +36,6 @@
            <el-tag type="success" size="small">{{ row.status }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="price" label="ä»·æ ¼" width="140"></el-table-column>
        <el-table-column prop="quantity" label="数量" width="140"></el-table-column>
        <el-table-column prop="description" label="描述"></el-table-column>
        <el-table-column label="操作" width="150" fixed="right" align="center">
@@ -111,16 +110,6 @@
        <el-form-item label="描述" prop="description">
          <el-input v-model="form.description"></el-input>
        </el-form-item>
        <el-form-item label="ä»·æ ¼" prop="price">
          <el-input-number
            v-model="form.price"
            placeholder="请输入价格"
            :min="0"
            :step="0.01"
            :precision="2"
            style="width: 100%"
          ></el-input-number>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
@@ -173,7 +162,6 @@
  status: '',
  description: '',
  deviceLedgerIds: [],
  price: null
});
// è¡¨å•验证规则
@@ -298,7 +286,6 @@
  form.status = '';
  form.description = '';
  form.deviceLedgerIds = [];
  form.price = null;
  operationType.value = 'add'
  dialogVisible.value = true;
};
src/views/equipmentManagement/upkeep/Form/DetailDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,219 @@
<template>
  <el-dialog v-model="dialogVisible"
             title="保养任务详情"
             width="600px"
             :close-on-click-modal="false"
             @close="handleClose">
    <el-form :model="formData"
             label-width="120px"
             class="detail-form">
      <el-form-item label="设备名称">
        <el-input v-model="formData.deviceName"
                  disabled />
      </el-form-item>
      <el-form-item label="规格型号">
        <el-input v-model="formData.deviceModel"
                  disabled />
      </el-form-item>
      <el-form-item label="计划保养日期">
        <el-input v-model="formData.maintenancePlanTime"
                  disabled />
      </el-form-item>
      <el-form-item label="录入人">
        <el-input v-model="formData.createUserName"
                  disabled />
      </el-form-item>
      <el-form-item label="实际保养人">
        <el-input v-model="formData.maintenanceActuallyName"
                  disabled />
      </el-form-item>
      <el-form-item label="实际保养日期">
        <el-input v-model="formData.maintenanceActuallyTime"
                  disabled />
      </el-form-item>
      <el-form-item label="保养结果">
        <el-input v-model="formData.maintenanceResult"
                  type="textarea"
                  :rows="3"
                  disabled />
      </el-form-item>
      <el-form-item label="状态">
        <el-tag v-if="formData.status === 2"
                type="danger">失败</el-tag>
        <el-tag v-else-if="formData.status === 1"
                type="success">完结</el-tag>
        <el-tag v-else-if="formData.status === 0"
                type="warning">待保养</el-tag>
        <span v-else>-</span>
      </el-form-item>
      <el-form-item label="设备备件">
        <span>{{formData.sparePartsNames}}</span>
      </el-form-item>
      <el-form-item label="图片列表">
        <div v-if="imageList.length > 0"
             class="image-list">
          <el-image v-for="(image, index) in imagesFile"
                    :key="index"
                    :src="image.url"
                    fit="cover"
                    class="image-item" />
        </div>
        <span v-else>-</span>
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleClose">关闭</el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script setup>
  import { ref, watch, computed } from "vue";
  import dayjs from "dayjs";
  const props = defineProps({
    visible: {
      type: Boolean,
      default: false,
    },
    row: {
      type: Object,
      default: () => ({}),
    },
  });
  const emit = defineEmits(["update:visible", "close"]);
  const dialogVisible = ref(false);
  const formData = ref({
    deviceName: "",
    deviceModel: "",
    maintenancePlanTime: "",
    createUserName: "",
    maintenanceActuallyName: "",
    maintenanceActuallyTime: "",
    maintenanceResult: "",
    status: "",
    sparePartsNames: "",
  });
  const imageList = ref([]);
  const sparePartsList = ref([]);
  // é¢„览图片列表
  const previewImageList = computed(() => {
    return imageList.value.map(image => image.url || image.fileUrl);
  });
  watch(
    () => props.visible,
    newVal => {
      dialogVisible.value = newVal;
    }
  );
  // ç›‘听 dialogVisible å˜åŒ–,通知父组件
  watch(
    () => dialogVisible.value,
    newVal => {
      emit("update:visible", newVal);
    }
  );
  watch(
    () => props.row,
    newRow => {
      if (newRow) {
        fillFormData(newRow);
      }
    },
    { deep: true }
  );
  const fillFormData = row => {
    formData.value = {
      deviceName: row.deviceName || "",
      deviceModel: row.deviceModel || "",
      maintenancePlanTime: row.maintenancePlanTime
        ? dayjs(row.maintenancePlanTime).format("YYYY-MM-DD")
        : "",
      createUserName: row.createUserName || "",
      maintenanceActuallyName: row.maintenanceActuallyName || "",
      maintenanceActuallyTime: row.maintenanceActuallyTime
        ? dayjs(row.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
        : "",
      maintenanceResult: row.maintenanceResult || "",
      status: row.status || 0,
      sparePartsNames: row.sparePartsNames || "",
    };
    // å¤„理图片列表
    if (row.imagesFile) {
      if (Array.isArray(row.imagesFile)) {
        imageList.value = row.imagesFile;
      } else if (typeof row.imagesFile === "string") {
        try {
          imageList.value = JSON.parse(row.imagesFile);
        } catch (error) {
          imageList.value = [];
        }
      } else {
        imageList.value = [];
      }
    } else {
      imageList.value = [];
    }
    console.log(imageList.value, "imageList");
    // å¤„理设备备件列表
    if (row.spareParts) {
      if (Array.isArray(row.spareParts)) {
        sparePartsList.value = row.spareParts;
      } else if (typeof row.spareParts === "string") {
        try {
          sparePartsList.value = JSON.parse(row.spareParts);
        } catch (error) {
          sparePartsList.value = [];
        }
      } else {
        sparePartsList.value = [];
      }
    } else {
      sparePartsList.value = [];
    }
  };
  const handleClose = () => {
    dialogVisible.value = false;
    emit("update:visible", false);
    emit("close");
  };
</script>
<style scoped>
  .detail-form {
    margin-top: 20px;
  }
  .dialog-footer {
    text-align: center;
  }
  .image-list {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 5px;
  }
  .image-item {
    width: 100px;
    height: 100px;
    cursor: pointer;
  }
  .el-table {
    margin-top: 5px;
  }
</style>
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -38,6 +38,16 @@
          placeholder="请输入保养结果"
          type="text" />
      </el-form-item>
      <el-form-item label="设备备件">
        <el-select v-model="form.sparePartsIds" :loading="loadingSparePartOptions" placeholder="请选择设备备件" multiple filterable>
          <el-option
              v-for="item in sparePartOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id"
          />
        </el-select>
      </el-form-item>
    </el-form>
  </FormDialog>
</template>
@@ -45,6 +55,7 @@
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
import { addMaintenance } from "@/api/equipmentManagement/upkeep";
import {getSparePartsOptions} from "@/api/equipmentManagement/spareParts.js";
import useFormData from "@/hooks/useFormData";
import dayjs from "dayjs";
import useUserStore from "@/store/modules/user";
@@ -67,7 +78,10 @@
  maintenanceActuallyTime: undefined, // å®žé™…保养日期
  maintenanceResult: undefined, // ä¿å…»ç»“æžœ
  status: 0, // ä¿å…»çŠ¶æ€
  sparePartsIds: undefined,
});
const sparePartOptions = ref([])
const loadingSparePartOptions = ref(true)
const setForm = (data) => {
  form.maintenanceActuallyName =
@@ -78,7 +92,19 @@
      : dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.maintenanceResult = data.maintenanceResult;
  form.status = 1; // é»˜è®¤çŠ¶æ€ä¸ºå®Œç»“
  form.sparePartsIds = data.sparePartsIds;
};
const fetchSparePartOptions = (deviceLedgerId) => {
  loadingSparePartOptions.value = true;
  getSparePartsOptions({ deviceLedgerId: deviceLedgerId }).then((res) => {
    if (res.code == 200) {
      sparePartOptions.value = res.data || [];
    }
  }).finally(() => {
    loadingSparePartOptions.value = false;
  })
}
/**
 * @desc ä¿å­˜ä¿å…»
@@ -86,7 +112,12 @@
const sendForm = async () => {
  loading.value = true;
  try {
    const { code } = await addMaintenance({ id: planId.value, ...form });
    const data = {
      id: planId.value,
      ...form,
      sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
    }
    const { code } = await addMaintenance(data);
    if (code == 200) {
      ElMessage.success("保养成功");
      emits("ok");
@@ -113,6 +144,7 @@
  visible.value = true;
  await nextTick();
  setForm(row);
  fetchSparePartOptions(row.deviceLedgerId)
};
defineExpose({
src/views/equipmentManagement/upkeep/index.vue
@@ -1,51 +1,58 @@
<template>
  <div class="app-container">
    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
    <el-tabs v-model="activeTab"
             @tab-change="handleTabChange">
      <!-- å®šæ—¶ä»»åŠ¡ç®¡ç†tab -->
      <el-tab-pane label="定时任务管理" name="scheduled">
      <el-tab-pane label="定时任务管理"
                   name="scheduled">
        <div class="search_form">
          <el-form :model="scheduledFilters" :inline="true">
          <el-form :model="scheduledFilters"
                   :inline="true">
            <el-form-item label="任务名称">
              <el-input
                  v-model="scheduledFilters.taskName"
              <el-input v-model="scheduledFilters.taskName"
                  style="width: 240px"
                  placeholder="请输入任务名称"
                  clearable
                  :prefix-icon="Search"
                  @change="getScheduledTableData"
              />
                        @change="getScheduledTableData" />
            </el-form-item>
            <el-form-item label="任务状态">
              <el-select v-model="scheduledFilters.status" placeholder="请选择任务状态" clearable style="width: 200px">
                <el-option label="启用" value="1" />
                <el-option label="停用" value="0" />
              <el-select v-model="scheduledFilters.status"
                         placeholder="请选择任务状态"
                         clearable
                         style="width: 200px">
                <el-option label="启用"
                           value="1" />
                <el-option label="停用"
                           value="0" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="getScheduledTableData">搜索</el-button>
              <el-button type="primary"
                         @click="getScheduledTableData">搜索</el-button>
              <el-button @click="resetScheduledFilters">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div class="table_list">
          <div class="actions">
            <el-text class="mx-1" size="large">定时任务管理</el-text>
            <el-text class="mx-1"
                     size="large">定时任务管理</el-text>
            <div>
              <el-button type="primary" icon="Plus" @click="addScheduledTask">
              <el-button type="primary"
                         icon="Plus"
                         @click="addScheduledTask">
                æ–°å¢žä»»åŠ¡
              </el-button>
              <el-button
                type="danger"
              <el-button type="danger"
                icon="Delete"
                :disabled="scheduledMultipleList.length <= 0"
                @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))"
              >
                         @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))">
                æ‰¹é‡åˆ é™¤
              </el-button>
            </div>
          </div>
          <PIMTable
            rowKey="id"
          <PIMTable rowKey="id"
            isSelection
            :column="scheduledColumns"
            :tableData="scheduledDataList"
@@ -55,102 +62,93 @@
              total: scheduledPagination.total,
            }"
            @selection-change="handleScheduledSelectionChange"
            @pagination="changeScheduledPage"
          >
                    @pagination="changeScheduledPage">
            <template #statusRef="{ row }">
              <el-tag v-if="row.status === 1" type="success">启用</el-tag>
              <el-tag v-if="row.status === 0" type="danger">停用</el-tag>
              <el-tag v-if="row.status === 1"
                      type="success">启用</el-tag>
              <el-tag v-if="row.status === 0"
                      type="danger">停用</el-tag>
            </template>
            <template #operation="{ row }">
              <el-button
                type="primary"
              <el-button type="primary"
                link
                @click="editScheduledTask(row)"
              >
                         @click="editScheduledTask(row)">
                ç¼–辑
              </el-button>
              <el-button
                type="danger"
              <el-button type="danger"
                link
                @click="delScheduledTaskByIds(row.id)"
              >
                         @click="delScheduledTaskByIds(row.id)">
                åˆ é™¤
              </el-button>
            </template>
          </PIMTable>
        </div>
      </el-tab-pane>
      <!-- ä»»åŠ¡è®°å½•tab(原设备保养页面) -->
      <el-tab-pane label="任务记录" name="record">
      <el-tab-pane label="任务记录"
                   name="record">
        <div class="search_form">
          <el-form :model="filters" :inline="true">
          <el-form :model="filters"
                   :inline="true">
            <el-form-item label="设备名称">
              <el-input
                  v-model="filters.deviceName"
              <el-input v-model="filters.deviceName"
                  style="width: 240px"
                  placeholder="请输入设备名称"
                  clearable
                  :prefix-icon="Search"
                  @change="getTableData"
              />
                        @change="getTableData" />
            </el-form-item>
            <el-form-item label="计划保养日期">
              <el-date-picker
                  v-model="filters.maintenancePlanTime"
              <el-date-picker v-model="filters.maintenancePlanTime"
                  type="date"
                  placeholder="请选择计划保养日期"
                  size="default"
                  @change="(date) => handleDateChange(date,2)"
              />
                              @change="(date) => handleDateChange(date,2)" />
            </el-form-item>
            <el-form-item label="实际保养日期">
              <el-date-picker
                  v-model="filters.maintenanceActuallyTime"
              <el-date-picker v-model="filters.maintenanceActuallyTime"
                  type="date"
                  placeholder="请选择实际保养日期"
                  size="default"
                  @change="(date) => handleDateChange(date,1)"
              />
                              @change="(date) => handleDateChange(date,1)" />
            </el-form-item>
            <el-form-item label="实际保养人">
              <el-input
                  v-model="filters.maintenanceActuallyName"
              <el-input v-model="filters.maintenanceActuallyName"
                  style="width: 240px"
                  placeholder="请输入实际保养人"
                  clearable
                  :prefix-icon="Search"
                  @change="getTableData"
              />
                        @change="getTableData" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="getTableData">搜索</el-button>
              <el-button type="primary"
                         @click="getTableData">搜索</el-button>
              <el-button @click="resetFilters">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div class="table_list">
          <div class="actions">
            <el-text class="mx-1" size="large">任务记录</el-text>
            <el-text class="mx-1"
                     size="large">任务记录</el-text>
            <div>
              <el-button type="success" icon="Van" @click="addPlan">
              <el-button type="success"
                         icon="Van"
                         @click="addPlan">
                æ–°å¢žè®¡åˆ’
              </el-button>
              <el-button @click="handleOut">
                å¯¼å‡º
              </el-button>
              <el-button
                type="danger"
              <el-button type="danger"
                icon="Delete"
                :disabled="multipleList.length <= 0 || hasFinishedStatus"
                @click="delRepairByIds(multipleList.map((item) => item.id))"
              >
                         @click="delRepairByIds(multipleList.map((item) => item.id))">
                æ‰¹é‡åˆ é™¤
              </el-button>
            </div>
          </div>
         <PIMTable
        rowKey="id"
          <PIMTable rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
@@ -160,15 +158,17 @@
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
                    @pagination="changePage">
        <template #maintenanceResultRef="{ row }">
          <div>{{ row.maintenanceResult || '-' }}</div>
        </template>
        <template #statusRef="{ row }">
          <el-tag v-if="row.status === 2" type="danger">失败</el-tag>
          <el-tag v-if="row.status === 1" type="success">完结</el-tag>
          <el-tag v-if="row.status === 0" type="warning">待保养</el-tag>
              <el-tag v-if="row.status === 2"
                      type="danger">失败</el-tag>
              <el-tag v-if="row.status === 1"
                      type="success">完结</el-tag>
              <el-tag v-if="row.status === 0"
                      type="warning">待保养</el-tag>
        </template>
        <template #operation="{ row }">
          <!-- è¿™ä¸ªåŠŸèƒ½è·Ÿæ–°å¢žä¿å…»åŠŸèƒ½ä¸€æ¨¡ä¸€æ ·ï¼Œæœ‰å•¥æ„ä¹‰ï¼Ÿ -->
@@ -179,47 +179,49 @@
          >
            æ–°å¢žä¿å…»
          </el-button> -->
          <el-button
            type="primary"
              <el-button type="primary"
            link
            :disabled="row.status === 1"
            @click="editPlan(row.id)"
          >
                         @click="editPlan(row.id)">
            ç¼–辑
          </el-button>
          <el-button
            type="success"
              <!-- <el-button type="success"
            link
            :disabled="row.status === 1"
            @click="addMaintain(row)"
          >
                         @click="addMaintain(row)">
            ä¿å…»
          </el-button>
          <el-button
            type="danger"
              </el-button> -->
              <el-button type="danger"
            link
            :disabled="row.status === 1"
            @click="delRepairByIds(row.id)"
          >
                         @click="delRepairByIds(row.id)">
            åˆ é™¤
          </el-button>
          <el-button
            type="primary"
              <el-button type="primary"
            link
            @click="openFileDialog(row)"
          >
            é™„ä»¶
                         @click="openFileDialog(row)">
                è¯¦æƒ…
          </el-button>
              <!-- <el-button type="primary"
                         link
                         @click="openAttachmentDialog(row)">
                é™„ä»¶
              </el-button> -->
        </template>
      </PIMTable>
        </div>
      </el-tab-pane>
    </el-tabs>
    <PlanModal ref="planModalRef" @ok="getTableData" />
        <MaintenanceModal ref="maintainModalRef" @ok="getTableData" />
        <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" />
    <FileListDialog
      ref="fileListDialogRef"
    <PlanModal ref="planModalRef"
               @ok="getTableData" />
    <MaintenanceModal ref="maintainModalRef"
                      @ok="getTableData" />
    <FormDia ref="formDiaRef"
             @closeDia="getScheduledTableData" />
    <DetailDialog ref="detailDialogRef"
                  v-model:visible="detailDialogVisible"
                  :row="currentDetailRow" />
    <FileListDialog ref="fileListDialogRef"
      v-model="fileDialogVisible"
      :show-upload-button="true"
      :show-delete-button="true"
@@ -231,71 +233,83 @@
</template>
<script setup>
import { ref, onMounted, reactive, getCurrentInstance, nextTick, computed } from 'vue'
import { Search } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import PlanModal from './Form/PlanModal.vue'
import MaintenanceModal from './Form/MaintenanceModal.vue'
import FormDia from './Form/formDia.vue'
import FileListDialog from '@/components/Dialog/FileListDialog.vue'
  import {
    ref,
    onMounted,
    reactive,
    getCurrentInstance,
    nextTick,
    computed,
  } from "vue";
  import { Search } from "@element-plus/icons-vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import PlanModal from "./Form/PlanModal.vue";
  import MaintenanceModal from "./Form/MaintenanceModal.vue";
  import FormDia from "./Form/formDia.vue";
  import DetailDialog from "./Form/DetailDialog.vue";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
import {
  getUpkeepPage,
  delUpkeep,
  deviceMaintenanceTaskList,
  deviceMaintenanceTaskDel,
} from '@/api/equipmentManagement/upkeep'
  } from "@/api/equipmentManagement/upkeep";
import {
  listMaintenanceTaskFiles,
  addMaintenanceTaskFile,
  delMaintenanceTaskFile,
} from '@/api/equipmentManagement/maintenanceTaskFile'
import dayjs from 'dayjs'
  } from "@/api/equipmentManagement/maintenanceTaskFile";
  import dayjs from "dayjs";
const { proxy } = getCurrentInstance()
  const { proxy } = getCurrentInstance();
// Tab相关
const activeTab = ref('scheduled')
  const activeTab = ref("scheduled");
// è®¡åˆ’弹窗控制器
const planModalRef = ref()
  const planModalRef = ref();
// ä¿å…»å¼¹çª—控制器
const maintainModalRef = ref()
  const maintainModalRef = ref();
// å®šæ—¶ä»»åŠ¡å¼¹çª—æŽ§åˆ¶å™¨
const formDiaRef = ref()
  const formDiaRef = ref();
  // è¯¦æƒ…弹窗
  const detailDialogRef = ref();
  const detailDialogVisible = ref(false);
  const currentDetailRow = ref(null);
// é™„件弹窗
const fileListDialogRef = ref(null)
const fileDialogVisible = ref(false)
const currentMaintenanceTaskId = ref(null)
  const fileListDialogRef = ref(null);
  const fileDialogVisible = ref(false);
  const currentMaintenanceTaskId = ref(null);
// ä»»åŠ¡è®°å½•tab(原设备保养页面)相关变量
const filters = reactive({
  deviceName: '',
  maintenancePlanTime: '',
  maintenanceActuallyTime: '',
  maintenanceActuallyName: '',
})
    deviceName: "",
    maintenancePlanTime: "",
    maintenanceActuallyTime: "",
    maintenanceActuallyName: "",
  });
const dataList = ref([])
  const dataList = ref([]);
const pagination = ref({
  currentPage: 1,
  pageSize: 10,
  total: 0,
})
const multipleList = ref([])
  });
  const multipleList = ref([]);
// å®šæ—¶ä»»åŠ¡ç®¡ç†tab相关变量
const scheduledFilters = reactive({
  taskName: '',
  status: '',
})
    taskName: "",
    status: "",
  });
const scheduledDataList = ref([])
  const scheduledDataList = ref([]);
const scheduledPagination = reactive({
  currentPage: 1,
  pageSize: 10,
  total: 0,
})
const scheduledMultipleList = ref([])
  });
  const scheduledMultipleList = ref([]);
// å®šæ—¶ä»»åŠ¡ç®¡ç†è¡¨æ ¼åˆ—é…ç½®
const scheduledColumns = ref([
@@ -309,33 +323,37 @@
        label: "频次",
        minWidth: 150,
        // PIMTable ä½¿ç”¨çš„æ˜¯ formatData,而不是 Element-Plus çš„ formatter
        formatData: (cell) => ({
      formatData: cell =>
        ({
            DAILY: "每日",
            WEEKLY: "每周",
            MONTHLY: "每月",
            QUARTERLY: "季度"
        }[cell] || "")
          QUARTERLY: "季度",
        }[cell] || ""),
    },
    {
        prop: "frequencyDetail",
        label: "开始日期与时间",
        minWidth: 150,
        // åŒæ ·æ”¹ç”¨ formatData,PIMTable å†…部会把单元格值传进来
        formatData: (cell) => {
            if (typeof cell !== 'string') return '';
      formatData: cell => {
        if (typeof cell !== "string") return "";
            let val = cell;
            const replacements = {
                MON: '周一',
                TUE: '周二',
                WED: '周三',
                THU: '周四',
                FRI: '周五',
                SAT: '周六',
                SUN: '周日'
          MON: "周一",
          TUE: "周二",
          WED: "周三",
          THU: "周四",
          FRI: "周五",
          SAT: "周六",
          SUN: "周日",
            };
            // ä½¿ç”¨æ­£åˆ™ä¸€æ¬¡æ€§æ›¿æ¢æ‰€æœ‰åŒ¹é…é¡¹
            return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]);
        }
        return val.replace(
          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
          match => replacements[match]
        );
      },
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "registrationDate", label: "登记日期", minWidth: 100 },
@@ -347,7 +365,7 @@
        align: "center",
        width: "200px",
    },
])
  ]);
// ä»»åŠ¡è®°å½•è¡¨æ ¼åˆ—é…ç½®ï¼ˆåŽŸè®¾å¤‡ä¿å…»è¡¨æ ¼åˆ—ï¼‰
const columns = ref([
@@ -365,7 +383,7 @@
        label: "计划保养日期",
        align: "center",
        prop: "maintenancePlanTime",
        formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
      formatData: cell => dayjs(cell).format("YYYY-MM-DD"),
    },
    {
        label: "录入人",
@@ -388,7 +406,7 @@
        label: "实际保养日期",
        align: "center",
        prop: "maintenanceActuallyTime",
        formatData: (cell) =>
      formatData: cell =>
            cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-",
    },
    {
@@ -413,16 +431,16 @@
        align: "center",
        width: "350px",
    },
])
  ]);
// Tab切换处理
const handleTabChange = (tabName) => {
  if (tabName === 'record') {
    getTableData()
  } else if (tabName === 'scheduled') {
    getScheduledTableData()
  const handleTabChange = tabName => {
    if (tabName === "record") {
      getTableData();
    } else if (tabName === "scheduled") {
      getScheduledTableData();
  }
}
  };
// å®šæ—¶ä»»åŠ¡ç®¡ç†ç›¸å…³æ–¹æ³•
const getScheduledTableData = async () => {
@@ -432,64 +450,64 @@
      size: scheduledPagination.pageSize,
      taskName: scheduledFilters.taskName || undefined,
      status: scheduledFilters.status || undefined,
    }
    const { code, data } = await deviceMaintenanceTaskList(params)
      };
      const { code, data } = await deviceMaintenanceTaskList(params);
    if (code === 200) {
      scheduledDataList.value = data?.records || []
      scheduledPagination.total = data?.total || 0
        scheduledDataList.value = data?.records || [];
        scheduledPagination.total = data?.total || 0;
    }
  } catch (error) {
    ElMessage.error('获取定时任务列表失败')
      ElMessage.error("获取定时任务列表失败");
  }
}
  };
const resetScheduledFilters = () => {
  scheduledFilters.taskName = ''
  scheduledFilters.status = ''
  getScheduledTableData()
}
    scheduledFilters.taskName = "";
    scheduledFilters.status = "";
    getScheduledTableData();
  };
const handleScheduledSelectionChange = (selection) => {
  scheduledMultipleList.value = selection
}
  const handleScheduledSelectionChange = selection => {
    scheduledMultipleList.value = selection;
  };
const changeScheduledPage = (page) => {
  scheduledPagination.currentPage = page.page
  scheduledPagination.pageSize = page.limit
  getScheduledTableData()
}
  const changeScheduledPage = page => {
    scheduledPagination.currentPage = page.page;
    scheduledPagination.pageSize = page.limit;
    getScheduledTableData();
  };
const addScheduledTask = () => {
  nextTick(() => {
        formDiaRef.value?.openDialog('add');
      formDiaRef.value?.openDialog("add");
    });
}
  };
const editScheduledTask = (row) => {
  const editScheduledTask = row => {
  if (row) {
        nextTick(() => {
            formDiaRef.value?.openDialog('edit', row);
        formDiaRef.value?.openDialog("edit", row);
        });
  }
}
  };
const delScheduledTaskByIds = async (ids) => {
  const delScheduledTaskByIds = async ids => {
  try {
    await ElMessageBox.confirm('确定删除选中的定时任务吗?', '提示', {
      type: 'warning',
    })
    const payload = Array.isArray(ids) ? ids : [ids]
    await deviceMaintenanceTaskDel(payload)
    ElMessage.success('删除定时任务成功')
    getScheduledTableData()
      await ElMessageBox.confirm("确定删除选中的定时任务吗?", "提示", {
        type: "warning",
      });
      const payload = Array.isArray(ids) ? ids : [ids];
      await deviceMaintenanceTaskDel(payload);
      ElMessage.success("删除定时任务成功");
      getScheduledTableData();
  } catch (error) {
    // ç”¨æˆ·å–消删除
  }
}
  };
const handleScheduledOut = () => {
  ElMessage.info('导出定时任务功能待实现')
}
    ElMessage.info("导出定时任务功能待实现");
  };
// ä»»åŠ¡è®°å½•ç›¸å…³æ–¹æ³•ï¼ˆåŽŸè®¾å¤‡ä¿å…»é¡µé¢æ–¹æ³•ï¼‰
const getTableData = async () => {
@@ -498,186 +516,197 @@
      current: pagination.value.currentPage,
      size: pagination.value.pageSize,
      deviceName: filters.deviceName || undefined,
      maintenancePlanTime: filters.maintenancePlanTime ? dayjs(filters.maintenancePlanTime).format('YYYY-MM-DD') : undefined,
      maintenanceActuallyTime: filters.maintenanceActuallyTime ? dayjs(filters.maintenanceActuallyTime).format('YYYY-MM-DD') : undefined,
        maintenancePlanTime: filters.maintenancePlanTime
          ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD")
          : undefined,
        maintenanceActuallyTime: filters.maintenanceActuallyTime
          ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD")
          : undefined,
      maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
    }
      };
    const { code, data } = await getUpkeepPage(params)
      const { code, data } = await getUpkeepPage(params);
    if (code === 200) {
      dataList.value = data.records
      pagination.value.total = data.total
        dataList.value = data.records;
        pagination.value.total = data.total;
    }
  } catch (error) {
    console.log(error);
  }
}
  };
const resetFilters = () => {
  filters.deviceName = ''
  filters.maintenancePlanTime = ''
  filters.maintenanceActuallyTime = ''
  filters.maintenanceActuallyName = ''
  getTableData()
}
    filters.deviceName = "";
    filters.maintenancePlanTime = "";
    filters.maintenanceActuallyTime = "";
    filters.maintenanceActuallyName = "";
    getTableData();
  };
const handleSelectionChange = (selection) => {
  multipleList.value = selection
}
  const handleSelectionChange = selection => {
    multipleList.value = selection;
  };
// æ£€æŸ¥é€‰ä¸­çš„记录中是否有完结状态的
const hasFinishedStatus = computed(() => {
  return multipleList.value.some(item => item.status === 1)
})
    return multipleList.value.some(item => item.status === 1);
  });
const changePage = (page) => {
  pagination.value.currentPage = page.page
  pagination.value.pageSize = page.limit
  getTableData()
}
  const changePage = page => {
    pagination.value.currentPage = page.page;
    pagination.value.pageSize = page.limit;
    getTableData();
  };
const addMaintain = (row) => {
  maintainModalRef.value.open(row.id, row)
}
  const addMaintain = row => {
    maintainModalRef.value.open(row.id, row);
  };
const addPlan = () => {
  planModalRef.value.openModal()
}
    planModalRef.value.openModal();
  };
const editPlan = (id) => {
  planModalRef.value.openEdit(id)
}
  const editPlan = id => {
    planModalRef.value.openEdit(id);
  };
const delRepairByIds = async (ids) => {
  const delRepairByIds = async ids => {
  // æ£€æŸ¥æ˜¯å¦æœ‰å®Œç»“状态的记录
  const hasFinished = multipleList.value.some(item => item.status === 1)
    const hasFinished = multipleList.value.some(item => item.status === 1);
  if (hasFinished) {
    ElMessage.warning('不能删除状态为完结的记录')
    return
      ElMessage.warning("不能删除状态为完结的记录");
      return;
  }
  
  try {
    await ElMessageBox.confirm('确认删除保养数据, æ­¤æ“ä½œä¸å¯é€†?', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    })
      await ElMessageBox.confirm("确认删除保养数据, æ­¤æ“ä½œä¸å¯é€†?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      });
    
    const { code } = await delUpkeep(ids)
      const { code } = await delUpkeep(ids);
    if (code === 200) {
      ElMessage.success('删除成功')
      getTableData()
        ElMessage.success("删除成功");
        getTableData();
    }
  } catch (error) {
    // ç”¨æˆ·å–消删除
  }
}
  };
const handleOut = () => {
  ElMessageBox.confirm('选中的内容将被导出,是否确认导出?', '导出', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
  })
    .then(() => {
      proxy.download('/device/maintenance/export', {}, '设备保养.xlsx')
        proxy.download("/device/maintenance/export", {}, "设备保养.xlsx");
    })
    .catch(() => {
      ElMessage.info('已取消')
    })
}
        ElMessage.info("已取消");
      });
  };
const handleDateChange = (date, type) => {
  if (type === 1) {
    filters.maintenanceActuallyTime = date ? dayjs(date).format('YYYY-MM-DD') : ''
      filters.maintenanceActuallyTime = date
        ? dayjs(date).format("YYYY-MM-DD")
        : "";
  } else {
    filters.maintenancePlanTime = date ? dayjs(date).format('YYYY-MM-DD') : ''
      filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
  }
  getTableData()
}
    getTableData();
  };
// é™„件相关方法
// æŸ¥è¯¢é™„件列表
const fetchMaintenanceTaskFiles = async (deviceMaintenanceId) => {
  const fetchMaintenanceTaskFiles = async deviceMaintenanceId => {
  try {
    const params = {
      current: 1,
      size: 100,
      deviceMaintenanceId,
      rulesRegulationsManagementId:deviceMaintenanceId
    }
    const res = await listMaintenanceTaskFiles(params)
    const records = res?.data?.records || []
        rulesRegulationsManagementId: deviceMaintenanceId,
      };
      const res = await listMaintenanceTaskFiles(params);
      const records = res?.data?.records || [];
    const mapped = records.map(item => ({
      id: item.id,
      name: item.fileName || item.name,
      url: item.fileUrl || item.url,
      raw: item,
    }))
    fileListDialogRef.value?.setList(mapped)
      }));
      fileListDialogRef.value?.setList(mapped);
  } catch (error) {
    ElMessage.error('获取附件列表失败')
      ElMessage.error("获取附件列表失败");
  }
}
  };
  // æ‰“开详情弹窗
  const openFileDialog = row => {
    currentDetailRow.value = row;
    detailDialogVisible.value = true;
  };
// æ‰“开附件弹窗
const openFileDialog = async (row) => {
  currentMaintenanceTaskId.value = row.id
  fileDialogVisible.value = true
  await fetchMaintenanceTaskFiles(row.id)
}
  const openAttachmentDialog = async row => {
    currentMaintenanceTaskId.value = row.id;
    fileDialogVisible.value = true;
    await fetchMaintenanceTaskFiles(row.id);
  };
// åˆ·æ–°é™„件列表
const refreshFileList = async () => {
  if (!currentMaintenanceTaskId.value) return
  await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value)
}
    if (!currentMaintenanceTaskId.value) return;
    await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value);
  };
// ä¸Šä¼ é™„ä»¶
const handleAttachmentUpload = async (filePayload) => {
  if (!currentMaintenanceTaskId.value) return
  const handleAttachmentUpload = async filePayload => {
    if (!currentMaintenanceTaskId.value) return;
  try {
    const payload = {
      name: filePayload?.fileName || filePayload?.name,
      url: filePayload?.fileUrl || filePayload?.url,
      deviceMaintenanceId: currentMaintenanceTaskId.value,
    }
    await addMaintenanceTaskFile(payload)
    ElMessage.success('文件上传成功')
    await refreshFileList()
      };
      await addMaintenanceTaskFile(payload);
      ElMessage.success("文件上传成功");
      await refreshFileList();
  } catch (error) {
    ElMessage.error('文件上传失败')
      ElMessage.error("文件上传失败");
  }
}
  };
// åˆ é™¤é™„ä»¶
const handleAttachmentDelete = async (row) => {
  if (!row?.id) return false
  const handleAttachmentDelete = async row => {
    if (!row?.id) return false;
  try {
    await ElMessageBox.confirm('确认删除该附件?', '提示', { type: 'warning' })
      await ElMessageBox.confirm("确认删除该附件?", "提示", { type: "warning" });
  } catch {
    return false
      return false;
  }
  try {
    await delMaintenanceTaskFile(row.id)
    ElMessage.success('删除成功')
    await refreshFileList()
    return true
      await delMaintenanceTaskFile(row.id);
      ElMessage.success("删除成功");
      await refreshFileList();
      return true;
  } catch (error) {
    ElMessage.error('删除失败')
    return false
      ElMessage.error("删除失败");
      return false;
  }
}
  };
onMounted(() => {
  // æ ¹æ®é»˜è®¤æ¿€æ´»çš„ Tab è°ƒç”¨å¯¹åº”的查询接口
  if (activeTab.value === 'scheduled') {
    getScheduledTableData()
    if (activeTab.value === "scheduled") {
      getScheduledTableData();
  } else {
    getTableData()
      getTableData();
  }
})
  });
</script>
<style lang="scss" scoped>
src/views/inventoryManagement/receiptManagement/Record.vue
@@ -83,6 +83,10 @@
            {{ getRecordType(scope.row.recordType) }}
          </template>
        </el-table-column>
        <el-table-column label="过磅日期"
                         prop="weighingDate"
                         v-if="type === '0'"
                         show-overflow-tooltip/>
      </el-table>
      <pagination v-show="total > 0"
                  :total="total"
src/views/inventoryManagement/stockManagement/New.vue
@@ -51,6 +51,30 @@
        >
          <el-input-number v-model="formState.warnNum" :step="1" :min="0" :max="formState.qualitity" style="width: 100%" />
        </el-form-item>
        <!-- productType === 0:原材料 -->
        <el-form-item
            v-if="type === 'qualified' && formState.productType === 0"
            label="过磅日期"
            prop="weighingDate"
        >
          <el-date-picker
              style="width: 100%"
              v-model="formState.weighingDate"
              value-format="YYYY-MM-DD HH:mm:ss"
              format="YYYY-MM-DD HH:mm:ss"
              type="datetime"
              placeholder="请选择过磅日期"
              clearable
          />
        </el-form-item>
        <el-form-item
            v-if="type === 'qualified' && formState.productType === 0"
            label="净重(吨)"
            prop="netWeight"
        >
          <el-input-number v-model="formState.netWeight" :step="0.01" :min="0" style="width: 100%" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="formState.remark" type="textarea" />
@@ -101,8 +125,11 @@
  productName: "",
  productModelName: "",
  unit: "",
  weighingDate: undefined,
  productType: undefined,
  qualitity: 0,
  warnNum: 0,
  netWeight: undefined,
  remark: '',
});
@@ -133,6 +160,8 @@
// äº§å“é€‰æ‹©å¤„理
const handleProductSelect = async (products) => {
  formState.value.weighingDate = undefined;
  formState.value.netWeight = undefined;
  if (products && products.length > 0) {
    const product = products[0];
    formState.value.productId = product.productId;
@@ -140,6 +169,7 @@
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    formState.value.productType = product.productType;
    showProductSelectDialog.value = false;
    // è§¦å‘表单验证更新
    proxy.$refs["formRef"]?.validateField('productModelId');
src/views/inventoryManagement/stockManagement/Qualified.vue
@@ -23,12 +23,14 @@
        :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)">
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column label="产品类型" prop="parentName" show-overflow-tooltip />
        <el-table-column label="产品大类" prop="productName" show-overflow-tooltip />
        <el-table-column label="规格型号" prop="model" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" show-overflow-tooltip />
        <el-table-column label="库存数量" prop="qualitity" show-overflow-tooltip />
        <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip />
        <el-table-column label="库存预警数量" prop="warnNum"  show-overflow-tooltip />
        <el-table-column label="净重(吨)" prop="netWeight"  show-overflow-tooltip />
        <el-table-column label="备注" prop="remark"  show-overflow-tooltip />
        <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" min-width="60" align="center">