zouyu
3 天以前 e76403a881cbad2a4788c5a90e1318b1feb1b5ef
Merge branch 'dev_tide_sbjkxt' into dev_tide_sbjkxt_xindao

# Conflicts:
# src/utils/auth.js
已添加18个文件
已修改2个文件
已删除3个文件
4658 ■■■■■ 文件已修改
src/api/equipmentManagement/calibration.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/auth.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/calibration/index.vue 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/device/DeviceManagement.vue 513 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/device/Form.vue 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/device/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/device/index.vue 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/FaultDiagnosis.vue 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/Form/MaintainForm.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/Form/RepairForm.vue 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/Modal/MaintainModal.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/Modal/RepairModal.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/index.vue 327 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/Form/MaintenanceForm.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/Form/PlanForm.vue 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/MaintenanceManagement.vue 526 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/Modal/MaintenanceModal.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/Modal/PlanModal.vue 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/index.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/measurementEquipment/components/calibrationDia.vue 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/measurementEquipment/components/formDia.vue 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/measurementEquipment/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/measurementEquipment/index.vue 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/calibration.js
@@ -24,4 +24,13 @@
    method: "post",
    data: query,
  });
}
// åˆ é™¤è®°å½•
export function ledgerRecordDelete(ids) {
    return request({
        url: "/measuringInstrumentLedgerRecord/delete",
        method: "delete",
        data: ids,
    });
}
src/utils/auth.js
@@ -3,17 +3,17 @@
const TokenKey = 'Admin-Token'
export function getToken() {
    // return Cookies.get(TokenKey)
  // return Cookies.get(TokenKey)
    return sessionStorage.getItem(TokenKey)
}
export function setToken(token) {
    // return Cookies.set(TokenKey, token)
  // return Cookies.set(TokenKey, token)
    return sessionStorage.setItem(TokenKey, token)
}
export function removeToken() {
    // return Cookies.remove(TokenKey)
  // return Cookies.remove(TokenKey)
    return sessionStorage.removeItem(TokenKey)
}
src/views/calibration/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,246 @@
<template>
    <div class="app-container">
        <div class="search_form">
            <div>
                <span class="search_title">检定日期:</span>
                <el-date-picker
                    v-model="searchForm.recordDate"
                    value-format="YYYY-MM-DD"
                    format="YYYY-MM-DD"
                    type="date"
                    placeholder="请选择"
                    clearable
                    style="width: 160px"
                    @change="handleQuery"
                />
                <span class="search_title ml10">录入日期:</span>
                <el-date-picker
                    v-model="searchForm.entryDate"
                    value-format="YYYY-MM-DD"
                    format="YYYY-MM-DD"
                    type="date"
                    placeholder="请选择"
                    clearable
                    style="width: 160px"
                    @change="handleQuery"
                />
                <span class="search_title ml10">计量器具编号:</span>
                <el-input v-model="searchForm.code" placeholder="请输入编号" clearable style="width: 240px" @change="handleQuery"/>
<!--                <span class="search_title ml10">状态:</span>-->
<!--                <el-select v-model="searchForm.status" placeholder="请选择状态" @change="handleQuery" style="width: 160px" clearable>-->
<!--                    <el-option label="有效" :value="1"></el-option>-->
<!--                    <el-option label="逾期" :value="2"></el-option>-->
<!--                </el-select>-->
                <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
                >搜索</el-button
                >
            </div>
            <div>
                <el-button @click="handleOut">导出</el-button>
            </div>
        </div>
        <div class="table_list">
            <PIMTable
                rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                @selection-change="handleSelectionChange"
                :tableLoading="tableLoading"
                @pagination="pagination"
            ></PIMTable>
        </div>
        <calibration-dia ref="calibrationDia" @close="handleQuery"></calibration-dia>
    </div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import {ElMessageBox, ElMessage} from "element-plus";
import useUserStore from "../../store/modules/user.js";
import CalibrationDia from "../../views/measurementEquipment/components/calibrationDia.vue";
import {ledgerRecordListPage, ledgerRecordDelete} from "../../api/equipmentManagement/calibration.js";
const { proxy } = getCurrentInstance();
const userStore = useUserStore()
const data = reactive({
    searchForm: {
        recordDate: "",
        code: "",
        entryDate: "",
    },
});
const { searchForm } = toRefs(data);
const tableColumn = ref([
    // {
    //     label: "状态",
    //     prop: "status",
    //     dataType: "tag",
    //     formatData: (params) => {
    //         if (params == 1) {
    //             return "有效";
    //         } else if (params == 2) {
    //             return "逾期";
    //         } else {
    //             return null;
    //         }
    //     },
    //     formatType: (params) => {
    //         if (params == 1) {
    //             return "success";
    //         } else if (params == 2) {
    //             return "danger";
    //         } else {
    //             return null;
    //         }
    //     },
    // },
    {
        label: "检定日期",
        prop: "recordDate",
        width: 130,
    },
    {
        label: "计量器具编号",
        prop: "code",
        width: 150,
    },
    {
        label: "计量器具名称",
        prop: "name",
        width: 200,
    },
    {
        label: "规格型号",
        prop: "model",
        width:200
    },
    {
        label: "有效期",
        prop: "valid",
        width: 100,
    },
    {
        label: "录入人",
        prop: "userName",
    },
    {
        label: "录入日期",
        prop: "entryDate",
        width: 130,
    },
    {
        dataType: "action",
        label: "操作",
        width: 100,
        align: "center",
        fixed: 'right',
        operation: [
            {
                name: "编辑",
                type: "text",
                clickFun: (row) => {
                    openCalibrationDia("edit", row);
                },
            },
            {
                name: "删除",
                type: "text",
                style: {
                    color: "#F56C6C"
                },
                clickFun: (row) => {
                    handleDelete(row);
                },
            },
        ],
    },
]);
const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({
    current: 1,
    size: 100,
    total: 0,
});
const selectedRows = ref([]);
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
    selectedRows.value = selection;
};
const calibrationDia = ref()
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    page.current = 1;
    getList();
};
const pagination = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
const getList = () => {
    tableLoading.value = true;
    ledgerRecordListPage({ ...searchForm.value, ...page }).then((res) => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
    }).catch((err) => {
        tableLoading.value = false;
    })
};
// æ‰“开检定校准弹框
const openCalibrationDia = (type, row) => {
    nextTick(() => {
        calibrationDia.value?.openDialog(type, row)
    })
}
// åˆ é™¤è®°å½•
const handleDelete = (row) => {
    ElMessageBox.confirm(`确认删除计量器具编号为"${row.code}"的检定记录吗?`, "删除确认", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            ledgerRecordDelete([row.id]).then(() => {
                ElMessage.success("删除成功");
                getList();
            }).catch(() => {
                ElMessage.error("删除失败");
            });
        })
        .catch(() => {
            proxy.$modal.msg("已取消删除");
        });
};
// å¯¼å‡º
const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/measuringInstrumentLedgerRecord/export", {}, "检定校准记录.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
onMounted(() => {
    getList();
});
</script>
<style scoped>
</style>
src/views/device/DeviceManagement.vue
ÎļþÒÑɾ³ý
src/views/device/Form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,239 @@
<template>
  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="设备名称" prop="deviceName">
          <el-input v-model="form.deviceName" placeholder="请输入设备名称" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="规格型号" prop="deviceModel">
          <el-input v-model="form.deviceModel" placeholder="请输入规格型号" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="设备品牌" prop="deviceBrand">
          <el-input v-model="form.deviceBrand" placeholder="请输入设备品牌" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="供应商" prop="supplierName">
          <el-input v-model="form.supplierName" placeholder="请输入供应商" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="存放位置" prop="storageLocation">
          <el-input v-model="form.storageLocation" placeholder="请输入存放位置" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="单位" prop="unit">
          <el-input v-model="form.unit" placeholder="请输入单位" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="启用折旧" prop="enableDepreciation">
          <el-switch v-model="form.enableDepreciation" :active-value="true" :inactive-value="false" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="数量" prop="number">
          <el-input-number :min="1" style="width: 100%"
            v-model="form.number"
                                                     disabled
            placeholder="请输入数量"
            @change="mathNum"
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="含税单价" prop="taxIncludingPriceUnit">
          <el-input-number :step="0.01" :min="0" style="width: 100%"
            v-model="form.taxIncludingPriceUnit"
            placeholder="请输入含税单价"
            maxlength="10"
            @change="mathNum"
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="含税总价" prop="taxIncludingPriceTotal">
          <el-input
            v-model="form.taxIncludingPriceTotal"
            placeholder="自动生成"
            type="number"
            disabled
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="税率(%)" prop="taxRate">
          <!-- <el-input
            v-model="form.taxRate"
            placeholder="请输入税率"
            type="number"
          >
            <template #append> % </template>
          </el-input> -->
          <el-select
            v-model="form.taxRate"
            placeholder="请选择"
            clearable
            @change="mathNum"
          >
            <el-option label="1" :value="1" />
            <el-option label="6" :value="6" />
            <el-option label="13" :value="13" />
          </el-select>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="不含税总价" prop="unTaxIncludingPriceTotal">
          <el-input
            v-model="form.unTaxIncludingPriceTotal"
            placeholder="自动生成"
            type="number"
            disabled
          />
        </el-form-item>
      </el-col>
      <!-- <el-col :span="12">
        <el-form-item label="录入人" prop="createUser">
          <el-input v-model="form.createUser" placeholder="请输入录入人" />
        </el-form-item>
      </el-col> -->
      <el-col :span="12">
        <el-form-item label="录入日期" prop="createTime">
          <el-date-picker
            style="width: 100%"
            v-model="form.createTime"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD HH:mm:ss"
            type="date"
            placeholder="请选择录入日期"
            clearable
          />
        </el-form-item>
      </el-col>
            <el-col :span="12">
                <el-form-item label="预计运行时间" prop="planRuntimeTime">
                    <el-date-picker
                        style="width: 100%"
                        v-model="form.planRuntimeTime"
                        format="YYYY-MM-DD"
                        value-format="YYYY-MM-DD"
                        type="date"
                        placeholder="请选择录入日期"
                        clearable
                    />
                </el-form-item>
            </el-col>
    </el-row>
  </el-form>
</template>
<script setup>
import useFormData from "../../hooks/useFormData";
// import useUserStore from "@/store/modules/user";
import { getLedgerById } from "../../api/equipmentManagement/ledger";
import dayjs from "dayjs";
import {
  calculateTaxIncludeTotalPrice,
  calculateTaxExclusiveTotalPrice,
} from "../../utils/summarizeTable";
import { ElMessage } from "element-plus";
import {ref} from "vue";
defineOptions({
  name: "设备台账表单",
});
const formRef = ref(null);
const operationType = ref('');
const formRules = {
    deviceName: [{ required: true, trigger: "blur", message: "请输入" }],
    deviceModel: [{ required: true, trigger: "blur", message: "请输入" }],
    supplierName: [{ required: true, trigger: "blur", message: "请输入" }],
    unit: [{ required: true, trigger: "blur", message: "请输入" }],
    number: [{ required: true, trigger: "blur", message: "请输入" }],
    taxIncludingPriceUnit: [{ required: true, trigger: "blur", message: "请输入" }],
    taxRate: [{ required: true, trigger: "change", message: "请输入" }],
    planRuntimeTime: [{ required: true, trigger: "change", message: "请选择" }],
}
const { form, resetForm } = useFormData({
  deviceName: undefined, // è®¾å¤‡åç§°
  deviceModel: undefined, // è§„格型号
  deviceBrand: undefined, // è®¾å¤‡å“ç‰Œ
  supplierName: undefined, // ä¾›åº”商
  storageLocation: undefined, // å­˜æ”¾ä½ç½®
  enableDepreciation: false, // æ˜¯å¦å¯ç”¨æŠ˜æ—§
  unit: undefined, // å•位
  number: 1, // æ•°é‡
  taxIncludingPriceUnit: undefined, // å«ç¨Žå•ä»·
  taxIncludingPriceTotal: undefined, // å«ç¨Žæ€»ä»·
  taxRate: undefined, // ç¨Žçއ
  unTaxIncludingPriceTotal: undefined, // ä¸å«ç¨Žæ€»ä»·
  // createUser: useUserStore().nickName, // å½•入人
  createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // å½•入日期
    planRuntimeTime: dayjs().format("YYYY-MM-DD"), // å½•入日期
});
const loadForm = async (id) => {
    if (id) {
        operationType.value = 'edit'
    }
  const { code, data } = await getLedgerById(id);
  if (code == 200) {
    form.deviceName = data.deviceName;
    form.deviceModel = data.deviceModel;
    form.deviceBrand = data.deviceBrand;
    form.supplierName = data.supplierName;
    form.storageLocation = data.storageLocation;
    form.enableDepreciation = data.enableDepreciation;
    form.unit = data.unit;
    form.number = 1;
    form.taxIncludingPriceUnit = data.taxIncludingPriceUnit;
    form.taxIncludingPriceTotal = data.taxIncludingPriceTotal;
    form.taxRate = data.taxRate;
    form.unTaxIncludingPriceTotal = data.unTaxIncludingPriceTotal;
    form.createTime = data.createTime;
  }
};
const mathNum = () => {
  if (!form.taxIncludingPriceUnit) {
    ElMessage.error("请输入单价");
    return;
  }
  form.taxIncludingPriceTotal = calculateTaxIncludeTotalPrice(
    form.taxIncludingPriceUnit,
    form.number
  );
  if (form.taxRate) {
    form.unTaxIncludingPriceTotal = calculateTaxExclusiveTotalPrice(
      form.taxIncludingPriceTotal,
      form.taxRate
    );
  }
};
// æ¸…除表单校验状态
const clearValidate = () => {
  formRef.value?.clearValidate();
};
// é‡ç½®è¡¨å•数据和校验状态
const resetFormAndValidate = () => {
  resetForm();
  clearValidate();
};
defineExpose({
  form,
  loadForm,
  resetForm,
  clearValidate,
  resetFormAndValidate,
    formRef,
});
</script>
src/views/device/Modal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<template>
  <el-dialog :title="modalOptions.title" v-model="visible" @close="close">
    <Form ref="formRef"></Form>
    <template #footer>
            <el-button type="primary" @click="sendForm" :loading="loading">
                {{ modalOptions.confirmText }}
            </el-button>
      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { useModal } from "../../hooks/useModal";
import { addLedger, editLedger } from "../../api/equipmentManagement/ledger";
import Form from "./Form.vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance()
defineOptions({
  name: "设备台账新增编辑",
});
const emits = defineEmits(["success"]);
const formRef = ref();
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "设备台账" });
const sendForm = () => {
    proxy.$refs.formRef.$refs.formRef.validate(async valid => {
        if (valid) {
            const {code} = id.value
                ? await editLedger({id: id.value, ...formRef.value.form})
                : await addLedger(formRef.value.form);
            if (code == 200) {
                emits("success");
                ElMessage({message: "操作成功", type: "success"});
                close();
            } else {
                loading.value = false;
            }
        }
    })
};
const close = () => {
    formRef.value.resetFormAndValidate();
  closeModal();
};
const loadForm = async (id) => {
  openModal(id);
  await nextTick();
  formRef.value.loadForm(id);
};
defineExpose({
  openModal,
  loadForm,
});
</script>
src/views/device/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,322 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="设备名称">
        <el-input
          v-model="filters.deviceName"
          style="width: 240px"
          placeholder="请输入设备名称"
          clearable
          :prefix-icon="Search"
          @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="规格型号">
        <el-input
            v-model="filters.deviceModel"
            style="width: 240px"
            placeholder="请输入规格型号"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="供应商">
        <el-input
            v-model="filters.supplierName"
            style="width: 240px"
            placeholder="请输入供应商"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="单位">
        <el-input
            v-model="filters.unit"
            style="width: 240px"
            placeholder="请输入单位"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="录入日期:">
        <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                        placeholder="请选择" clearable @change="changeDaterange" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData">搜索</el-button>
        <el-button @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <div></div>
        <div>
          <el-button type="primary" @click="add" icon="Plus"> æ–°å¢ž </el-button>
          <el-button @click="handleOut" icon="download">导出</el-button>
          <el-button
            type="danger"
            icon="Delete"
            :disabled="multipleList.length <= 0"
            @click="deleteRow(multipleList.map((item) => item.id))"
          >
            æ‰¹é‡åˆ é™¤
          </el-button>
        </div>
      </div>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
      </PIMTable>
    </div>
    <Modal ref="modalRef" @success="getTableData"></Modal>
    <el-dialog v-model="qrDialogVisible" title="二维码" width="300px">
      <div style="text-align:center;">
        <img :src="qrCodeUrl" alt="二维码" style="width:200px;height:200px;" />
        <div style="margin:10px 0;">
          <el-button type="primary" @click="downloadQRCode">下载二维码图片</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script setup>
import { usePaginationApi } from "../../hooks/usePaginationApi";
// import { Search } from "@element-plus/icons-vue";
import { getLedgerPage, delLedger } from "../../api/equipmentManagement/ledger";
import { onMounted, getCurrentInstance } from "vue";
import Modal from "./Modal.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import dayjs from "dayjs";
import QRCode from "qrcode";
import { ref } from "vue";
defineOptions({
  name: "设备台账",
});
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
const { proxy } = getCurrentInstance();
const modalRef = ref();
const qrDialogVisible = ref(false);
const qrCodeUrl = ref("");
const qrRowData = ref(null);
const {
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
} = usePaginationApi(
  getLedgerPage,
  {
    deviceName: undefined,
    deviceModel: undefined,
    supplierName: undefined,
    unit: undefined,
    entryDateStart: undefined,
    entryDateEnd: undefined,
  },
  [
    {
      label: "设备名称",
      align: "center",
      prop: "deviceName",
    },
    {
      label: "规格型号",
      align: "center",
      prop: "deviceModel",
    },
    {
      label: "设备品牌",
      align: "center",
      prop: "deviceBrand",
    },
    {
      label: "供应商",
      align: "center",
      prop: "supplierName",
    },
    {
      label: "单位",
      align: "center",
      prop: "unit",
    },
    {
      label: "存放位置",
      align: "center",
      prop: "storageLocation",
    },
    {
      label: "数量",
      align: "center",
      prop: "number",
    },
    {
      label: "含税单价",
      align: "center",
      prop: "taxIncludingPriceUnit",
    },
    {
      label: "含税总价",
      align: "center",
      prop: "taxIncludingPriceTotal",
    },
    {
      label: "税率",
      align: "center",
      prop: "taxRate",
    },
    {
      label: "不含税总价",
      align: "center",
      prop: "unTaxIncludingPriceTotal",
    },
    {
      label: "启用折旧",
      align: "center",
      prop: "enableDepreciation",
      formatData: (v) => (v ? "是" : "否"),
    },
    {
      label: "录入人",
      align: "center",
      prop: "createUser",
    },
    {
      label: "录入日期",
      align: "center",
      prop: "createTime",
    },
        {
            dataType: "action",
            label: "操作",
            align: "center",
            fixed: 'right',
            width: 150,
            operation: [
                {
                    name: "编辑",
                    type: "text",
                    clickFun: (row) => {
                        edit(row.id)
                    },
                },
                {
                    name: "生成二维码",
                    type: "text",
                    clickFun: (row) => {
                        showQRCode(row)
                    },
                },
            ],
        },
  ]
);
// å¤šé€‰åŽåšä»€ä¹ˆ
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
const add = () => {
  modalRef.value.openModal();
};
const edit = (id) => {
  modalRef.value.loadForm(id);
};
const changePage = ({ page, limit }) => {
  pagination.currentPage = page;
    pagination.pageSize = limit;
  onCurrentChange(page);
};
const deleteRow = (id) => {
  ElMessageBox.confirm("此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(async () => {
    const { code } = await delLedger(id);
    if (code == 200) {
      ElMessage({
        type: "success",
        message: "删除成功",
      });
      getTableData();
    }
  });
};
const changeDaterange = (value) => {
  if (value) {
    filters.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
    filters.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
  } else {
    filters.entryDateStart = undefined;
    filters.entryDateEnd = undefined;
  }
  getTableData();
};
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download(`/device/ledger/export`, {}, "设备台账档案.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
const showQRCode = async (row) => {
  // ç›´æŽ¥ä½¿ç”¨URL,不要用JSON.stringify包装
  const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id;
  qrCodeUrl.value = await QRCode.toDataURL(qrContent);
  qrRowData.value = row;
  qrDialogVisible.value = true;
};
const downloadQRCode = () => {
  const a = document.createElement("a");
  a.href = qrCodeUrl.value;
  a.download = `${qrRowData.value.deviceName || "二维码"}.png`;
  a.click();
};
onMounted(() => {
  getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
</style>
src/views/diagnosis/FaultDiagnosis.vue
ÎļþÒÑɾ³ý
src/views/diagnosis/Form/MaintainForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
<template>
  <el-form :model="form" label-width="80px">
    <el-form-item label="维修人">
      <el-input v-model="form.maintenanceName" placeholder="请输入维修人" />
    </el-form-item>
    <el-form-item label="维修结果">
      <el-input v-model="form.maintenanceResult" placeholder="请输入维修结果" />
    </el-form-item>
    <el-form-item label="故障状态">
      <el-select v-model="form.status">
        <el-option label="待故障" :value="0"></el-option>
        <el-option label="完结" :value="1"></el-option>
        <el-option label="失败" :value="2"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="维修日期">
      <el-date-picker
        v-model="form.maintenanceTime"
        placeholder="请选择维修日期"
        format="YYYY-MM-DD HH:mm:ss"
        value-format="YYYY-MM-DD HH:mm:ss"
        type="datetime"
        clearable
        style="width: 100%"
      />
    </el-form-item>
  </el-form>
</template>
<script setup>
import useFormData from "../../../hooks/useFormData";
import useUserStore from "../../../store/modules/user";
import dayjs from "dayjs";
defineOptions({
  name: "设备维修表单",
});
const userStore = useUserStore();
const { form, resetForm } = useFormData({
  maintenanceName: undefined, // ç»´ä¿®åç§°
  maintenanceResult: undefined, // ç»´ä¿®ç»“æžœ
  maintenanceTime: undefined, // ç»´ä¿®æ—¥æœŸ
  status: 0,
});
const setForm = (data) => {
  form.maintenanceName = data.maintenanceName ?? userStore.nickName;
  form.maintenanceResult = data.maintenanceResult;
  form.maintenanceTime =
    dayjs(data.maintenanceTime).format("YYYY-MM-DD HH:mm:ss") ??
    dayjs().format("YYYY-MM-DD HH:mm:ss");
};
const getForm = () => {
  return form;
};
defineExpose({
  getForm,
  setForm,
  resetForm,
});
</script>
<style lang="scss" scoped></style>
src/views/diagnosis/Form/RepairForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,130 @@
<template>
  <el-form :model="form" label-width="100px">
    <el-row>
      <el-col :span="12">
        <el-form-item label="设备名称">
          <el-select v-model="form.deviceLedgerId" @change="setDeviceModel">
            <el-option
              v-for="(item, index) in deviceOptions"
              :key="index"
              :label="item.deviceName"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="规格型号">
          <el-input
            v-model="form.deviceModel"
            placeholder="请输入规格型号"
            disabled
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="故障日期">
          <el-date-picker
            v-model="form.repairTime"
            placeholder="请选择故障日期"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD"
            type="date"
            clearable
            style="width: 100%"
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="上报人">
          <el-input v-model="form.repairName" placeholder="请输入上报人" />
        </el-form-item>
      </el-col>
    </el-row>
    <el-row v-if="id">
      <el-col :span="12">
        <el-form-item label="故障状态">
          <el-select v-model="form.status">
            <el-option label="待维修" :value="0"></el-option>
            <el-option label="完结" :value="1"></el-option>
            <el-option label="失败" :value="2"></el-option>
          </el-select>
        </el-form-item>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="24">
        <el-form-item label="故障现象">
          <el-input
            v-model="form.remark"
            :rows="2"
            type="textarea"
            placeholder="请输入故障现象"
          />
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>
<script setup>
import useFormData from "../../../hooks/useFormData";
import { getDeviceLedger } from "../../../api/equipmentManagement/ledger";
import useUserStore from "../../../store/modules/user";
const { id } = defineProps(["id"])
defineOptions({
  name: "设备故障表单",
});
const userStore = useUserStore();
const deviceOptions = ref([]);
const loadDeviceName = async () => {
  const { data } = await getDeviceLedger();
  deviceOptions.value = data;
};
const { form, resetForm } = useFormData({
  deviceLedgerId: undefined, // è®¾å¤‡Id
  deviceName: undefined, // è®¾å¤‡åç§°
  deviceModel: undefined, // è§„格型号
  repairTime: undefined, // æ•…障日期
  repairName: userStore.nickName, // æ•…障人
  remark: undefined, // æ•…障现象
  status: 0, // æ•…障状态
});
const setDeviceModel = (id) => {
  const option = deviceOptions.value.find((item) => item.id === id);
  form.deviceModel = option.deviceModel;
};
const getForm = () => {
  return form;
};
const setForm = (data) => {
  form.deviceLedgerId = data.deviceLedgerId;
  form.deviceName = data.deviceName;
  form.deviceModel = data.deviceModel;
  form.repairTime = data.repairTime;
  form.repairName = data.repairName;
  form.remark = data.remark;
  form.status = data.status;
};
// onMounted(() => {
//   loadDeviceName();
// });
defineExpose({
  loadDeviceName,
  resetForm,
  getForm,
  setForm,
});
</script>
<style lang="scss" scoped></style>
src/views/diagnosis/Modal/MaintainModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
<template>
  <el-dialog v-model="visible" :title="modalOptions.title" direction="ltr">
    <MaintainForm ref="maintainFormRef" />
    <template #footer>
            <el-button type="primary" @click="sendForm" :loading="loading">
                {{ modalOptions.confirmText }}
            </el-button>
      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { useModal } from "../../../hooks/useModal";
import MaintainForm from "../Form/MaintainForm.vue";
import { addMaintain } from "../../../api/equipmentManagement/repair";
defineOptions({
  name: "维修模态框",
});
const maintainFormRef = ref();
const emits = defineEmits(["ok"]);
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "设备维修" });
const sendForm = async () => {
  loading.value = true;
  const form = await maintainFormRef.value.getForm();
  const { code } = await addMaintain({ id: id.value, ...form });
  if (code == 200) {
    emits("ok");
    maintainFormRef.value.resetForm();
    closeModal();
  }
  loading.value = false;
};
const open = async (id, row) => {
  openModal(id);
  await nextTick();
  maintainFormRef.value.setForm(row);
};
defineExpose({
  open,
});
</script>
<style lang="scss" scoped></style>
src/views/diagnosis/Modal/RepairModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
<template>
  <el-dialog v-model="visible" :title="modalOptions.title" @close="close">
    <RepairForm ref="repairFormRef" :id="id" />
    <template #footer>
            <el-button type="primary" @click="sendForm" :loading="loading">
                {{ modalOptions.confirmText }}
            </el-button>
      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { useModal } from "../../../hooks/useModal";
import RepairForm from "../Form/RepairForm.vue";
import {
  addRepair,
  editRepair,
  getRepairById,
} from "../../../api/equipmentManagement/repair";
import { ElMessage } from "element-plus";
defineOptions({
  name: "设备故障弹窗",
});
const emits = defineEmits(["ok"]);
const repairFormRef = ref();
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "设备故障" });
const sendForm = async () => {
  loading.value = true;
  const form = await repairFormRef.value.getForm();
  const { code } = id.value
    ? await editRepair({ id: unref(id), ...form })
    : await addRepair(form);
  if (code == 200) {
    ElMessage.success(`${id ? "编辑" : "新增"}故障成功`);
    closeModal();
    emits("ok");
  }
  loading.value = false;
};
const openAdd = async () => {
  openModal();
  await nextTick();
  await repairFormRef.value.loadDeviceName();
};
const openEdit = async (id) => {
  const { data } = await getRepairById(id);
  openModal(id);
  await nextTick();
  await repairFormRef.value.loadDeviceName();
  await repairFormRef.value.setForm(data);
};
const close = () => {
  repairFormRef.value.resetForm();
  closeModal();
};
defineExpose({
  openAdd,
  openEdit,
});
</script>
src/views/diagnosis/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,327 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="设备名称">
        <el-input
            v-model="filters.deviceName"
            style="width: 240px"
            placeholder="请输入设备名称"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="规格型号">
        <el-input
            v-model="filters.deviceModel"
            style="width: 240px"
            placeholder="请选择规格型号"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="故障现象">
        <el-input
            v-model="filters.remark"
            style="width: 240px"
            placeholder="请输入故障现象"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="维修人">
        <el-input
            v-model="filters.maintenanceName"
            style="width: 240px"
            placeholder="请输入维修人"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="故障日期">
        <el-date-picker
            v-model="filters.repairTimeStr"
            type="date"
            placeholder="请选择故障日期"
            size="default"
            @change="(date) => handleDateChange(date,2)"
        />
      </el-form-item>
      <el-form-item label="维修日期">
        <el-date-picker
            v-model="filters.maintenanceTimeStr"
            type="date"
            placeholder="请选择维修日期"
            size="default"
            @change="(date) => handleDateChange(date,1)"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData">搜索</el-button>
        <el-button @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <el-text class="mx-1" size="large">设备故障</el-text>
        <div>
          <el-button
            type="primary"
            icon="Plus"
            :disabled="multipleList.length !== 1"
            @click="addMaintain"
          >
            æ–°å¢žç»´ä¿®
          </el-button>
          <el-button type="success" icon="Van" @click="addRepair">
            æ–°å¢žæ•…éšœ
          </el-button>
          <el-button @click="handleOut">
            å¯¼å‡º
          </el-button>
          <el-button
            type="danger"
            icon="Delete"
            :disabled="multipleList.length <= 0"
            @click="delRepairByIds(multipleList.map((item) => item.id))"
          >
            æ‰¹é‡åˆ é™¤
          </el-button>
        </div>
      </div>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
        <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>
        </template>
        <template #operation="{ row }">
          <el-button
            type="primary"
            text
            icon="editPen"
            @click="editRepair(row.id)"
          >
            ç¼–辑
          </el-button>
          <el-button
            type="danger"
            text
            icon="delete"
            @click="delRepairByIds(row.id)"
          >
            åˆ é™¤
          </el-button>
        </template>
      </PIMTable>
    </div>
    <RepairModal ref="repairModalRef" @ok="getTableData" />
    <MaintainModal ref="maintainModalRef" @ok="getTableData" />
  </div>
</template>
<script setup>
import { usePaginationApi } from "../../hooks/usePaginationApi";
import { getRepairPage, delRepair } from "../../api/equipmentManagement/repair";
import { onMounted, getCurrentInstance } from "vue";
import RepairModal from "./Modal/RepairModal.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import dayjs from "dayjs";
import MaintainModal from "./Modal/MaintainModal.vue";
defineOptions({
  name: "设备故障",
});
const { proxy } = getCurrentInstance();
// æ¨¡æ€æ¡†å®žä¾‹
const repairModalRef = ref();
const maintainModalRef = ref();
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
// è¡¨æ ¼é’©å­
const {
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
} = usePaginationApi(
  getRepairPage,
  {
    deviceName: undefined,
    deviceModel: undefined,
    remark: undefined,
    maintenanceName: undefined,
    repairTimeStr: undefined,
    maintenanceTimeStr: undefined,
  },
  [
    {
      label: "设备名称",
      align: "center",
      prop: "deviceName",
    },
    {
      label: "规格型号",
      align: "center",
      prop: "deviceModel",
    },
    {
      label: "故障日期",
      align: "center",
      prop: "repairTime",
      formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
    },
    {
      label: "上报人",
      align: "center",
      prop: "repairName",
    },
    {
      label: "故障现象",
      align: "center",
      prop: "remark",
    },
    {
      label: "维修人",
      align: "center",
      prop: "maintenanceName",
    },
    {
      label: "维修结果",
      align: "center",
      prop: "maintenanceResult",
    },
    {
      label: "维修日期",
      align: "center",
      prop: "maintenanceTime",
      formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
    },
    {
      label: "状态",
      align: "center",
      prop: "status",
      dataType: "slot",
      slot: "statusRef",
    },
    {
      fixed: "right",
      label: "操作",
      dataType: "slot",
      slot: "operation",
      align: "center",
      width: "200px",
    },
  ]
);
// type === 1 ç»´ä¿® 2故障间
const handleDateChange = (value,type) => {
  filters.maintenanceTimeStr = null
  filters.c = null
  if(type === 1){
    if (value) {
      filters.maintenanceTimeStr = dayjs(value).format("YYYY-MM-DD");
    }
  }else{
    if (value) {
      filters.repairTimeStr = dayjs(value).format("YYYY-MM-DD");
    }
  }
  getTableData();
};
// å¤šé€‰åŽåšä»€ä¹ˆ
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
// æ–°å¢žæ•…éšœ
const addRepair = () => {
  repairModalRef.value.openAdd();
};
// ç¼–辑故障
const editRepair = (id) => {
  repairModalRef.value.openEdit(id);
};
// æ–°å¢žç»´ä¿®
const addMaintain = () => {
  const row = multipleList.value[0];
  maintainModalRef.value.open(row.id, row);
};
const changePage = ({ page, limit }) => {
    pagination.currentPage = page;
    pagination.pageSize = limit;
    onCurrentChange(page);
};
// å•行删除
const delRepairByIds = async (ids) => {
  ElMessageBox.confirm("确认删除故障数据, æ­¤æ“ä½œä¸å¯é€†?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(async () => {
    const { code } = await delRepair(ids);
    if (code === 200) {
      ElMessage.success("删除成功");
      getTableData();
    }
  });
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/device/repair/export", {}, "设备故障.xlsx");
    })
    .catch(() => {
      ElMessage.info("已取消");
    });
};
onMounted(() => {
  getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
</style>
src/views/maintenance/Form/MaintenanceForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
<template>
  <el-form :model="form" label-width="100px">
    <el-form-item label="实际保养人">
      <el-input
        v-model="form.maintenanceActuallyName"
        placeholder="请输入实际保养人"
      ></el-input>
    </el-form-item>
    <el-form-item label="实际保养日期">
      <el-date-picker
        v-model="form.maintenanceActuallyTime"
        placeholder="请选择实际保养日期"
        format="YYYY-MM-DD HH:mm:ss"
        value-format="YYYY-MM-DD HH:mm:ss"
        type="datetime"
        clearable
        style="width: 100%"
      />
    </el-form-item>
    <el-form-item label="保养状态">
      <el-select v-model="form.status">
        <el-option label="待保养" :value="0"></el-option>
        <el-option label="完结" :value="1"></el-option>
        <el-option label="失败" :value="2"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="保养结果">
      <!-- <el-select v-model="form.maintenanceResult" placeholder="请选择保养结果">
        <el-option label="完好" :value="1"></el-option>
        <el-option label="ç»´ä¿®" :value="0"></el-option>
      </el-select> -->
      <el-input
        v-model="form.maintenanceResult"
        placeholder="请输入保养结果"
        type="text" />
    </el-form-item>
  </el-form>
</template>
<script setup>
import useFormData from "../../../hooks/useFormData";
import dayjs from "dayjs";
import useUserStore from "../../../store/modules/user";
defineOptions({
  name: "保养表单",
});
const userStore = useUserStore();
const { form, resetForm } = useFormData({
  maintenanceActuallyName: undefined, // å®žé™…保养人
  maintenanceActuallyTime: undefined, // å®žé™…保养日期
  maintenanceResult: undefined, // ä¿å…»ç»“æžœ
  status: 0, // ä¿å…»çŠ¶æ€
});
const setForm = (data) => {
  form.maintenanceActuallyName =
    data.maintenanceActuallyName ?? userStore.nickName;
  form.maintenanceActuallyTime =
    dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss") ??
    dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.maintenanceResult = data.maintenanceResult;
};
const getForm = () => {
  return form;
};
defineExpose({
  getForm,
  setForm,
  resetForm,
});
</script>
<style lang="scss" scoped></style>
src/views/maintenance/Form/PlanForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,137 @@
<template>
  <el-form :model="form" label-width="100px">
    <el-form-item label="设备名称">
      <el-select
        v-model="form.deviceLedgerId"
        @change="setDeviceModel"
        placeholder="请选择设备"
        filterable
        default-first-option
        :reserve-keyword="false"
      >
        <el-option
          v-for="(item, index) in deviceOptions"
          :key="index"
          :label="item.deviceName"
          :value="item.id"
        ></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="规格型号">
      <el-input
        v-model="form.deviceModel"
        placeholder="请输入规格型号"
        disabled
      />
    </el-form-item>
    <el-form-item label="录入人">
      <el-select
        v-model="form.createUser"
        placeholder="请选择"
        filterable
        default-first-option
        :reserve-keyword="false"
        clearable
      >
        <el-option
          v-for="item in userList"
          :key="item.userId"
          :label="item.userName"
          :value="item.userId"
        />
      </el-select>
    </el-form-item>
    <el-form-item v-if="id" label="保修状态">
      <el-select v-model="form.status">
        <el-option label="待保修" :value="0"></el-option>
        <el-option label="完结" :value="1"></el-option>
        <el-option label="失败" :value="2"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="计划保养日期">
      <el-date-picker
        style="width: 100%"
        v-model="form.maintenancePlanTime"
        format="YYYY-MM-DD"
        value-format="YYYY-MM-DD HH:mm:ss"
        type="date"
        placeholder="请选择计划保养日期日期"
        clearable
      />
    </el-form-item>
  </el-form>
</template>
<script setup>
import useFormData from "../../../hooks/useFormData";
import { getDeviceLedger } from "../../../api/equipmentManagement/ledger";
import { onMounted } from "vue";
import dayjs from "dayjs";
import { userListNoPage } from "../../../api/system/user.js";
defineOptions({
  name: "计划表单",
});
const deviceOptions = ref([]);
const loadDeviceName = async () => {
  const { data } = await getDeviceLedger();
  deviceOptions.value = data;
};
const { id } = defineProps(['id']);
const { form, resetForm } = useFormData({
  deviceLedgerId: undefined, // è®¾å¤‡Id
  deviceName: undefined, // è®¾å¤‡åç§°
  deviceModel: undefined, // è§„格型号
  maintenancePlanTime: undefined, // è®¡åˆ’保养日期
  createUser: undefined, // å½•入人
  status: 0, //保修状态
});
const setDeviceModel = (id) => {
  const option = deviceOptions.value.find((item) => item.id === id);
  form.deviceModel = option.deviceModel;
};
const getForm = () => {
  return form;
};
/**
 * @desc è®¾ç½®è¡¨å•内容
 * @param data è®¾å¤‡ä¿¡æ¯
 */
const setForm = (data) => {
  form.deviceLedgerId = data.deviceLedgerId;
  form.deviceName = data.deviceName;
  form.deviceModel = data.deviceModel;
  form.createUser = Number(data.createUser);
  form.status = data.status;
  form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
    "YYYY-MM-DD HH:mm:ss"
  );
};
// ç”¨æˆ·åˆ—表
const userList = ref([]);
const loadForm = () => {};
onMounted(() => {
  loadDeviceName();
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
});
defineExpose({
  loadForm,
  resetForm,
  getForm,
  setForm,
});
</script>
<style lang="scss" scoped></style>
src/views/maintenance/MaintenanceManagement.vue
ÎļþÒÑɾ³ý
src/views/maintenance/Modal/MaintenanceModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
<template>
  <el-dialog v-model="visible" :title="modalOptions.title" direction="ltr">
    <MaintenanceForm ref="maintenanceFormRef" />
    <template #footer>
            <el-button type="primary" @click="sendForm" :loading="loading">
                {{ modalOptions.confirmText }}
            </el-button>
      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import MaintenanceForm from "../Form/MaintenanceForm.vue";
import { useModal } from "../../../hooks/useModal";
import { addMaintenance } from "../../../api/equipmentManagement/upkeep";
defineOptions({
  name: "保养模态框",
});
const maintenanceFormRef = ref();
const emits = defineEmits(["ok"]);
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "设备保养" });
/**
 * @desc ä¿å­˜ä¿å…»
 */
const sendForm = async () => {
  loading.value = true;
  const form = await maintenanceFormRef.value.getForm();
  const { code } = await addMaintenance({ id: id.value, ...form });
  if (code == 200) {
    emits("ok");
    maintenanceFormRef.value.resetForm();
    closeModal();
  }
  loading.value = false;
};
const open = async (id, row) => {
  openModal(id);
  await nextTick();
  maintenanceFormRef.value.setForm(row);
};
defineExpose({
  open,
});
</script>
<style lang="scss" scoped></style>
src/views/maintenance/Modal/PlanModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
<template>
  <el-dialog
    v-model="visible"
    :title="modalOptions.title"
    width="30%"
    @close="close"
  >
    <PlanForm ref="planFormRef" :id="id"></PlanForm>
    <template #footer>
            <el-button type="primary" @click="sendForm" :loading="loading">
                {{ modalOptions.confirmText }}
            </el-button>
      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { useModal } from "../../../hooks/useModal";
import PlanForm from "../Form/PlanForm";
import {
  addUpkeep,
  editUpkeep,
  getUpkeepById,
} from "../../../api/equipmentManagement/upkeep";
import { ElMessage } from "element-plus";
defineOptions({
  name: "设备保养新增计划",
});
const emits = defineEmits(["ok"]);
const planFormRef = ref();
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "设备保养计划" });
const openEdit = async (id) => {
  const { data } = await getUpkeepById(id);
  openModal(id);
  await nextTick();
  await planFormRef.value.setForm(data);
};
const sendForm = async () => {
  loading.value = true;
  const form = await planFormRef.value.getForm();
  const { code } = id.value
    ? await editUpkeep({ id: unref(id), ...form })
    : await addUpkeep(form);
  if (code == 200) {
    ElMessage.success(`${id ? "编辑" : "新增"}计划成功`);
    closeModal();
    emits("ok");
  }
  loading.value = false;
};
const close = () => {
  planFormRef.value.resetForm();
  closeModal();
};
defineExpose({
  openModal,
  openEdit,
});
</script>
<style lang="scss" scoped></style>
src/views/maintenance/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,315 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="设备名称">
        <el-input
            v-model="filters.deviceName"
            style="width: 240px"
            placeholder="请输入设备名称"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="计划保养日期">
        <el-date-picker
            v-model="filters.maintenancePlanTime"
            type="date"
            placeholder="请选择计划保养日期"
            size="default"
            @change="(date) => handleDateChange(date,2)"
        />
      </el-form-item>
      <el-form-item label="实际保养日期">
        <el-date-picker
            v-model="filters.maintenanceActuallyTime"
            type="date"
            placeholder="请选择实际保养日期"
            size="default"
            @change="(date) => handleDateChange(date,1)"
        />
      </el-form-item>
      <el-form-item label="实际保养人">
        <el-input
            v-model="filters.maintenanceActuallyName"
            style="width: 240px"
            placeholder="请输入实际保养人"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData">搜索</el-button>
        <el-button @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <el-text class="mx-1" size="large">设备保养</el-text>
        <div>
          <el-button
            type="primary"
            icon="Plus"
            :disabled="multipleList.length !== 1"
            @click="addMaintain"
          >
            æ–°å¢žä¿å…»
          </el-button>
          <el-button type="success" icon="Van" @click="addPlan">
            æ–°å¢žè®¡åˆ’
          </el-button>
          <el-button @click="handleOut">
            å¯¼å‡º
          </el-button>
          <el-button
            type="danger"
            icon="Delete"
            :disabled="multipleList.length <= 0"
            @click="delRepairByIds(multipleList.map((item) => item.id))"
          >
            æ‰¹é‡åˆ é™¤
          </el-button>
        </div>
      </div>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
        <template #maintenanceResultRef="{ row }">
          <div>{{ row.maintenanceResult || '-' }}</div>
          <!-- <el-tag v-if="row.maintenanceResult === 1" type="success">
            å®Œå¥½
          </el-tag>
          <el-tag v-if="row.maintenanceResult === 0" type="danger">
            ç»´ä¿®
          </el-tag> -->
        </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>
        </template>
        <template #operation="{ row }">
          <el-button
            type="primary"
            text
            icon="editPen"
            @click="editPlan(row.id)"
          >
            ç¼–辑
          </el-button>
          <el-button
            type="danger"
            text
            icon="delete"
            @click="delRepairByIds(row.id)"
          >
            åˆ é™¤
          </el-button>
        </template>
      </PIMTable>
    </div>
    <PlanModal ref="planModalRef" @ok="getTableData" />
    <MaintenanceModal ref="maintainModalRef" @ok="getTableData" />
  </div>
</template>
<script setup>
import { usePaginationApi } from "../../hooks/usePaginationApi";
import { getUpkeepPage, delUpkeep } from "../../api/equipmentManagement/upkeep";
import { onMounted, getCurrentInstance } from "vue";
import PlanModal from "./Modal/PlanModal.vue";
import MaintenanceModal from "./Modal/MaintenanceModal.vue";
import dayjs from "dayjs";
import { ElMessageBox, ElMessage } from "element-plus";
defineOptions({
  name: "设备保养",
});
const { proxy } = getCurrentInstance();
// è®¡åˆ’弹窗控制器
const planModalRef = ref();
// ä¿å…»å¼¹çª—控制器
const maintainModalRef = ref();
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
// å¤šé€‰åŽåšä»€ä¹ˆ
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
// è¡¨æ ¼é’©å­
const {
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
} = usePaginationApi(getUpkeepPage, {
  deviceName: undefined,
  maintenancePlanTime: undefined,
  maintenanceActuallyTime: undefined,
  maintenanceActuallyName: undefined,
}, [
  {
    label: "设备名称",
    align: "center",
    prop: "deviceName",
  },
  {
    label: "规格型号",
    align: "center",
    prop: "deviceModel",
  },
  {
    label: "计划保养日期",
    align: "center",
    prop: "maintenancePlanTime",
    formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
  },
  {
    label: "录入人",
    align: "center",
    prop: "createUserName",
  },
  // {
  //   label: "录入日期",
  //   align: "center",
  //   prop: "createTime",
  //   formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
  //   width: 200,
  // },
  {
    label: "实际保养人",
    align: "center",
    prop: "maintenanceActuallyName",
  },
  {
    label: "实际保养日期",
    align: "center",
    prop: "maintenanceActuallyTime",
    formatData: (cell) =>
      cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-",
  },
  {
    label: "保养结果",
    align: "center",
    prop: "maintenanceResult",
    dataType: "slot",
    slot: "maintenanceResultRef",
  },
  {
    label: "状态",
    align: "center",
    prop: "status",
    dataType: "slot",
    slot: "statusRef",
  },
  {
    fixed: "right",
    label: "操作",
    dataType: "slot",
    slot: "operation",
    align: "center",
    width: "200px",
  },
]);
// type == 1实际保养时间 2计划保养时间
const handleDateChange = (value,type) => {
  filters.maintenanceActuallyTimeReq = null
  filters.maintenancePlanTimeReq = null
  if(type === 1){
    if (value) {
      filters.maintenanceActuallyTimeReq = dayjs(value).format("YYYY-MM-DD");
    }
  }else{
    if (value) {
      filters.maintenancePlanTimeReq = dayjs(value).format("YYYY-MM-DD");
    }
  }
  getTableData();
};
// æ–°å¢žä¿å…»
const addMaintain = () => {
  const row = multipleList.value[0];
  maintainModalRef.value.open(row.id, row);
};
// æ–°å¢žè®¡åˆ’
const addPlan = () => {
  planModalRef.value.openModal();
};
// ç¼–辑计划
const editPlan = (id) => {
  planModalRef.value.openEdit(id);
};
const changePage = ({ page, limit }) => {
    pagination.currentPage = page;
    pagination.pageSize = limit;
    onCurrentChange(page);
};
// å•行删除
const delRepairByIds = async (ids) => {
  ElMessageBox.confirm("确认删除报修数据, æ­¤æ“ä½œä¸å¯é€†?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(async () => {
    const { code } = await delUpkeep(ids);
    if (code === 200) {
      ElMessage.success("删除成功");
      getTableData();
    }
  });
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/device/maintenance/export", {}, "设备保养.xlsx");
    })
    .catch(() => {
      ElMessage.info("已取消");
    });
};
onMounted(() => {
  getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
</style>
src/views/measurementEquipment/components/calibrationDia.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,268 @@
<template>
    <div>
        <el-dialog
            v-model="dialogFormVisible"
            title="计量器具"
            width="50%"
            @close="closeDia"
        >
            <el-form
                :model="form"
                label-width="140px"
                label-position="top"
                :rules="rules"
                ref="formRef"
            >
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="计量器具编号:" prop="customerName">
                            <el-input
                                v-model="form.code"
                                placeholder="请输入"
                                clearable
                                disabled
                            />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="计量器具名称:" prop="proDesc">
                            <el-input
                                v-model="form.name"
                                placeholder="请输入"
                                clearable
                                disabled
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="检定日期:" prop="recordDate">
                            <el-date-picker
                                style="width: 100%"
                                v-model="form.recordDate"
                                value-format="YYYY-MM-DD"
                                format="YYYY-MM-DD"
                                type="date"
                                placeholder="请选择"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="有效期:" prop="valid">
                            <el-input
                                v-model="form.valid"
                                placeholder="请输入"
                                clearable
                            >
                                <template #append>日</template>
                            </el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="录入人:" prop="userId">
                            <el-select
                                v-model="form.userId"
                                placeholder="请选择"
                filterable
                default-first-option
                :reserve-keyword="false"
                                clearable
                            >
                                <el-option
                                    v-for="item in userList"
                                    :key="item.userId"
                                    :label="item.nickName"
                                    :value="item.userId"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="录入日期:" prop="entryDate">
                            <el-date-picker
                                style="width: 100%"
                                v-model="form.entryDate"
                                value-format="YYYY-MM-DD"
                                format="YYYY-MM-DD"
                                type="date"
                                placeholder="请选择"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
<!--                <el-row :gutter="30">-->
<!--                    <el-col :span="24">-->
<!--                        <el-form-item label="附件材料:" prop="remark">-->
<!--                            <el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload-->
<!--                                                 :headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"-->
<!--                                                 :on-success="handleUploadSuccess" :on-remove="handleRemove">-->
<!--                                <el-button type="primary" v-if="operationType !== 'view'">上传</el-button>-->
<!--                                <template #tip v-if="operationType !== 'view'">-->
<!--                                    <div class="el-upload__tip">-->
<!--                                        æ–‡ä»¶æ ¼å¼æ”¯æŒ-->
<!--                                        doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z-->
<!--                                    </div>-->
<!--                                </template>-->
<!--                            </el-upload>-->
<!--                        </el-form-item>-->
<!--                    </el-col>-->
<!--                </el-row>-->
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">确认</el-button>
                    <el-button @click="closeDia">取消</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
<script setup>
import {ref} from "vue";
import useUserStore from "../../../store/modules/user.js";
import {userListNoPageByTenantId} from "../../../api/system/user.js";
import {afterSalesServiceAdd, afterSalesServiceUpdate} from "@/api/customerService/index.js";
import {getToken} from "../../../utils/auth.js";
import {ledgerRecordUpdate, ledgerRecordVerifying} from "../../../api/equipmentManagement/calibration.js";
import {delLedgerFile} from "../../../api/salesManagement/salesLedger.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
const dialogFormVisible = ref(false);
const operationType = ref('')
const userStore = useUserStore();
const data = reactive({
    form: {
        code: "",
        name: "",
        valid: "",
        recordDate: "",
        userId: "",
        entryDate: "",
    tempFileIds: []
    },
    rules: {
        code: [{required: true, message: "请输入", trigger: "blur"}],
        name: [{required: true, message: "请输入", trigger: "blur"}],
        valid: [{required: true, message: "请输入", trigger: "blur"}],
        recordDate: [{required: true, message: "请选择", trigger: "change"}],
        userId: [{required: true, message: "请选择", trigger: "change"}],
        entryDate: [{required: true, message: "请选择", trigger: "change"}],
    }
})
const { form, rules } = toRefs(data);
const userList = ref([])
const fileList = ref([]);
const upload = reactive({
    // ä¸Šä¼ çš„地址
    url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
    // è®¾ç½®ä¸Šä¼ çš„请求头部
    headers: { Authorization: "Bearer " + getToken() },
});
// æ‰“开弹框
const openDialog = (type, row) => {
  console.log(row)
    operationType.value = type;
    dialogFormVisible.value = true;
    userListNoPageByTenantId().then((res) => {
        userList.value = res.data;
    });
  fileList.value = []
    if(type !== "add"){
      form.value.tempFileIds = [];
  }
    if (type === "edit") {
        form.value.valid = row.valid;
        form.value.recordDate = row.recordDate;
    fileList.value = row.commonFiles;
    }
    if(type === "add"){
    fileList.value = row.commonFiles;
  }
    form.value.id = row.id;
    form.value.code = row.code;
    form.value.name = row.name;
    form.value.userId = userStore.id;
    form.value.entryDate = getCurrentDate();
}
// ä¸Šä¼ å‰æ ¡æ£€
function handleBeforeUpload(file) {
    proxy.$modal.loading("正在上传文件,请稍候...");
    return true;
}
// ä¸Šä¼ å¤±è´¥
function handleUploadError(err) {
    proxy.$modal.msgError("上传文件失败");
    proxy.$modal.closeLoading();
}
// ä¸Šä¼ æˆåŠŸå›žè°ƒ
function handleUploadSuccess(res, file, uploadFiles) {
    proxy.$modal.closeLoading();
    if (res.code === 200) {
        file.tempId = res.data.tempId;
        form.value.tempFileIds.push(file.tempId);
        proxy.$modal.msgSuccess("上传成功");
    } else {
        proxy.$modal.msgError(res.msg);
        proxy.$refs.fileUpload.handleRemove(file);
    }
}
// ç§»é™¤æ–‡ä»¶
function handleRemove(file) {
    if (operationType.value === "edit") {
        let ids = [];
        ids.push(file.id);
        delLedgerFile(ids).then((res) => {
            proxy.$modal.msgSuccess("删除成功");
        });
    }
}
const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
        if (valid) {
            if (operationType.value === "verifying") {
                ledgerRecordVerifying(form.value).then(response => {
                    proxy.$modal.msgSuccess("检定校准成功")
                    closeDia()
                })
            } else {
                ledgerRecordUpdate(form.value).then(response => {
                    proxy.$modal.msgSuccess("修改成功")
                    closeDia()
                })
            }
        }
    })
}
// å…³é—­å¼¹æ¡†
const closeDia = () => {
    proxy.resetForm("formRef");
    dialogFormVisible.value = false;
    emit('close')
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
    const day = String(today.getDate()).padStart(2, "0");
    return `${year}-${month}-${day}`;
}
defineExpose({
    openDialog,
});
</script>
<style scoped>
</style>
src/views/measurementEquipment/components/formDia.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,254 @@
<template>
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        title="计量器具"
        width="50%"
        @close="closeDia"
    >
            <el-form
                :model="form"
                label-width="140px"
                label-position="top"
                :rules="rules"
                ref="formRef"
            >
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="计量器具编号:" prop="code">
                            <el-input
                                v-model="form.code"
                                placeholder="请输入"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="计量器具名称:" prop="name">
                            <el-input
                                v-model="form.name"
                                placeholder="请输入"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="规格型号:" prop="model">
                            <el-input
                                v-model="form.model"
                                placeholder="请输入"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="预计下次检定日期:" prop="nextDate">
                            <el-date-picker
                                style="width: 100%"
                                v-model="form.nextDate"
                                value-format="YYYY-MM-DD"
                                format="YYYY-MM-DD"
                                type="date"
                                placeholder="请选择"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="录入人:" prop="userId">
                            <el-select
                                v-model="form.userId"
                                placeholder="请选择"
                                clearable
                filterable
                default-first-option
                :reserve-keyword="false"
                            >
                                <el-option
                                    v-for="item in userList"
                                    :key="item.userId"
                                    :label="item.nickName"
                                    :value="item.userId"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="录入日期:" prop="recordDate">
                            <el-date-picker
                                style="width: 100%"
                                v-model="form.recordDate"
                                value-format="YYYY-MM-DD"
                                format="YYYY-MM-DD"
                                type="date"
                                placeholder="请选择"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
<!--                <el-row :gutter="30">-->
<!--                    <el-col :span="24">-->
<!--                        <el-form-item label="附件材料:" prop="remark">-->
<!--                            <el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload-->
<!--                                                 :headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"-->
<!--                                                 :on-success="handleUploadSuccess" :on-remove="handleRemove">-->
<!--                                <el-button type="primary" v-if="operationType !== 'view'">上传</el-button>-->
<!--                                <template #tip v-if="operationType !== 'view'">-->
<!--                                    <div class="el-upload__tip">-->
<!--                                        æ–‡ä»¶æ ¼å¼æ”¯æŒ-->
<!--                                        doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z-->
<!--                                    </div>-->
<!--                                </template>-->
<!--                            </el-upload>-->
<!--                        </el-form-item>-->
<!--                    </el-col>-->
<!--                </el-row>-->
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submitForm">确认</el-button>
                    <el-button @click="closeDia">取消</el-button>
                </div>
            </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {ref} from "vue";
import useUserStore from "../../../store/modules/user.js";
import {userListNoPageByTenantId} from "../../../api/system/user.js";
import {afterSalesServiceAdd, afterSalesServiceUpdate} from "@/api/customerService/index.js";
import {getToken} from "../../../utils/auth.js";
import {measuringInstrumentAdd, measuringInstrumentUpdate} from "../../../api/equipmentManagement/measurementEquipment.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
const dialogFormVisible = ref(false);
const operationType = ref('')
const userStore = useUserStore();
const data = reactive({
    form: {
        code: "",
        name: "",
        model: "",
        validDate: "",
        nextDate: "",
        userId: "",
        recordDate: "",
    tempFileIds: []
    },
    rules: {
        code: [{required: true, message: "请输入", trigger: "blur"}],
        name: [{required: true, message: "请输入", trigger: "blur"}],
        model: [{required: true, message: "请输入", trigger: "blur"}],
        validDate: [{required: true, message: "请输入", trigger: "blur"}],
        nextDate: [{required: true, message: "请选择", trigger: "change"}],
        userId: [{required: true, message: "请选择", trigger: "change"}],
        recordDate: [{required: true, message: "请选择", trigger: "change"}],
    }
})
const { form, rules } = toRefs(data);
const userList = ref([])
const fileList = ref([]);
const upload = reactive({
    // ä¸Šä¼ çš„地址
    url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
    // è®¾ç½®ä¸Šä¼ çš„请求头部
    headers: { Authorization: "Bearer " + getToken() },
});
// æ‰“开弹框
const openDialog = (type, row) => {
  operationType.value = type;
  dialogFormVisible.value = true;
    fileList.value = []
    form.value.userId = userStore.id;
    form.value.recordDate = getCurrentDate();
    userListNoPageByTenantId().then((res) => {
        userList.value = res.data;
    });
    if (type === "edit") {
        form.value = {...row}
    }
}
// ä¸Šä¼ å‰æ ¡æ£€
function handleBeforeUpload(file) {
    proxy.$modal.loading("正在上传文件,请稍候...");
    return true;
}
// ä¸Šä¼ å¤±è´¥
function handleUploadError(err) {
    proxy.$modal.msgError("上传文件失败");
    proxy.$modal.closeLoading();
}
// ä¸Šä¼ æˆåŠŸå›žè°ƒ
function handleUploadSuccess(res, file, uploadFiles) {
    proxy.$modal.closeLoading();
    if (res.code === 200) {
        file.tempId = res.data.tempId;
    form.value.tempFileIds.push(res.data.tempId)
        proxy.$modal.msgSuccess("上传成功");
    } else {
        proxy.$modal.msgError(res.msg);
        proxy.$refs.fileUpload.handleRemove(file);
    }
}
// ç§»é™¤æ–‡ä»¶
function handleRemove(file) {
    if (operationType.value === "edit") {
        let ids = [];
        ids.push(file.id);
        delLedgerFile(ids).then((res) => {
            proxy.$modal.msgSuccess("删除成功");
        });
    }
}
const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
        if (valid) {
            if (operationType.value === "add") {
                measuringInstrumentAdd(form.value).then(response => {
                    proxy.$modal.msgSuccess("新增成功")
          form.value.tempFileIds = []
                    closeDia()
                })
            } else {
                measuringInstrumentUpdate(form.value).then(response => {
                    proxy.$modal.msgSuccess("修改成功")
          form.value.tempFileIds = []
                    closeDia()
                })
            }
        }
    })
}
// å…³é—­å¼¹æ¡†
const closeDia = () => {
    proxy.resetForm("formRef");
  dialogFormVisible.value = false;
  emit('close')
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
    const day = String(today.getDate()).padStart(2, "0");
    return `${year}-${month}-${day}`;
}
defineExpose({
  openDialog,
});
</script>
<style scoped>
</style>
src/views/measurementEquipment/filesDia.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
<template>
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        title="上传附件"
        width="50%"
        @close="closeDia"
    >
      <div style="margin-bottom: 10px;text-align: right">
        <el-upload
            v-model:file-list="fileList"
            class="upload-demo"
            :action="uploadUrl"
            :on-success="handleUploadSuccess"
            :on-error="handleUploadError"
            name="file"
            :show-file-list="false"
            :headers="headers"
            style="display: inline;margin-right: 10px"
        >
          <el-button type="primary">上传附件</el-button>
        </el-upload>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
      <PIMTable
          rowKey="id"
          :column="tableColumn"
          :tableData="tableData"
          :tableLoading="tableLoading"
          :isSelection="true"
          @selection-change="handleSelectionChange"
          height="500"
      >
      </PIMTable>
            <pagination
                style="margin: 10px 0"
                v-show="total > 0"
                @pagination="paginationSearch"
                :total="total"
                :page="page.current"
                :limit="page.size"
            />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="closeDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <filePreview ref="filePreviewRef" />
  </div>
</template>
<script setup>
import {ref} from "vue";
import {ElMessageBox} from "element-plus";
import {getToken} from "../../utils/auth.js";
import filePreview from '../../components/filePreview/index.vue'
import {
  fileAdd,
  fileDel,
  fileListPage
} from "../../api/financialManagement/revenueManagement.js";
import Pagination from "../../components/PIMTable/Pagination.vue";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
const dialogFormVisible = ref(false);
const currentId = ref('')
const selectedRows = ref([]);
const filePreviewRef = ref()
const tableColumn = ref([
  {
    label: "文件名称",
    prop: "name",
  },
  {
    dataType: "action",
    label: "操作",
    align: "center",
    operation: [
      {
        name: "下载",
        type: "text",
        clickFun: (row) => {
          downLoadFile(row);
        },
      },
      {
        name: "预览",
        type: "text",
        clickFun: (row) => {
          lookFile(row);
        },
      }
    ],
  },
]);
const page = reactive({
    current: 1,
    size: 100,
});
const total = ref(0);
const tableData = ref([]);
const fileList = ref([]);
const tableLoading = ref(false);
const accountType = ref('')
const headers = ref({
  Authorization: "Bearer " + getToken(),
});
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // ä¸Šä¼ çš„图片服务器地址
// æ‰“开弹框
const openDialog = (row,type) => {
  accountType.value = type;
  dialogFormVisible.value = true;
  currentId.value = row.id;
  getList()
}
const paginationSearch = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
const getList = () => {
  fileListPage({accountId: currentId.value,accountType:accountType.value, ...page}).then(res => {
    tableData.value = res.data.records;
        total.value = res.data.total;
  })
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  dialogFormVisible.value = false;
  emit('close')
};
// ä¸Šä¼ æˆåŠŸå¤„ç†
function handleUploadSuccess(res, file) {
  // å¦‚果上传成功
  if (res.code == 200) {
    const fileRow = {}
    fileRow.name = res.data.originalName
    fileRow.url = res.data.tempPath
    uploadFile(fileRow)
  } else {
    proxy.$modal.msgError("文件上传失败");
  }
}
function uploadFile(file) {
  file.accountId = currentId.value;
  file.accountType = accountType.value;
  fileAdd(file).then(res => {
    proxy.$modal.msgSuccess("文件上传成功");
    getList()
  })
}
// ä¸Šä¼ å¤±è´¥å¤„理
function handleUploadError() {
  proxy.$modal.msgError("文件上传失败");
}
// ä¸‹è½½é™„ä»¶
const downLoadFile = (row) => {
  proxy.$download.name(row.url);
}
// åˆ é™¤
const handleDelete = () => {
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    fileDel(ids).then((res) => {
      proxy.$modal.msgSuccess("删除成功");
      getList();
    });
  }).catch(() => {
    proxy.$modal.msg("已取消");
  });
};
// é¢„览附件
const lookFile = (row) => {
  filePreviewRef.value.open(row.url)
}
defineExpose({
  openDialog,
});
</script>
<style scoped>
</style>
src/views/measurementEquipment/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,270 @@
<template>
    <div class="app-container">
        <div class="search_form">
            <div>
                <span class="search_title">录入日期:</span>
                <el-date-picker
                    v-model="searchForm.recordDate"
                    value-format="YYYY-MM-DD"
                    format="YYYY-MM-DD"
                    type="date"
                    placeholder="请选择"
                    clearable
                    style="width: 160px"
                    @change="handleQuery"
                />
                <span class="search_title ml10">计量器具编号:</span>
                <el-input v-model="searchForm.code" placeholder="请输入编号" clearable style="width: 240px" @change="handleQuery"/>
                <span class="search_title ml10">状态:</span>
                <el-select v-model="searchForm.status" placeholder="请选择状态" @change="handleQuery" style="width: 160px" clearable>
                    <el-option label="有效" :value="1"></el-option>
                    <el-option label="逾期" :value="2"></el-option>
                </el-select>
                <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
                >搜索</el-button
                >
            </div>
            <div>
                <el-button type="primary" @click="openForm('add')">新增计量器具</el-button>
                <el-button type="danger" plain @click="handleDelete">删除</el-button>
                <el-button @click="handleOut">导出</el-button>
            </div>
        </div>
        <div class="table_list">
            <PIMTable
                rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                @selection-change="handleSelectionChange"
                :tableLoading="tableLoading"
                @pagination="pagination"
            ></PIMTable>
        </div>
        <form-dia ref="formDia" @close="handleQuery"></form-dia>
        <calibration-dia ref="calibrationDia" @close="handleQuery"></calibration-dia>
    <files-dia ref="filesDia"></files-dia>
    </div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import FormDia from "../measurementEquipment/components/formDia.vue";
import {ElMessageBox} from "element-plus";
import useUserStore from "../../store/modules/user.js";
import CalibrationDia from "../measurementEquipment/components/calibrationDia.vue";
import {
    measuringInstrumentDelete,
    measuringInstrumentListPage
} from "../../api/equipmentManagement/measurementEquipment.js";
import FilesDia from "./filesDia.vue";
const { proxy } = getCurrentInstance();
const userStore = useUserStore()
const data = reactive({
    searchForm: {
        recordDate: "",
        code: "",
        status: "",
    },
});
const { searchForm } = toRefs(data);
const tableColumn = ref([
    {
        label: "状态",
        prop: "status",
        dataType: "tag",
        formatData: (params) => {
            if (params == 1) {
                return "有效";
            } else if (params == 2) {
                return "逾期";
            } else {
                return null;
            }
        },
        formatType: (params) => {
            if (params == 1) {
                return "success";
            } else if (params == 2) {
                return "danger";
            } else {
                return null;
            }
        },
    },
    {
        label: "最近一次检定日期",
        prop: "mostDate",
        width: 130,
    },
    {
        label: "计量器具编号",
        prop: "code",
        width: 150,
    },
    {
        label: "计量器具名称",
        prop: "name",
        width: 200,
    },
    {
        label: "规格型号",
        prop: "model",
        width:200
    },
    {
        label: "有效期",
        prop: "valid",
        width: 130,
    },
    {
        label: "预计下次检定日期",
        prop: "nextDate",
        width: 130,
    },
    {
        label: "录入人",
        prop: "userName",
    },
    {
        label: "录入日期",
        prop: "recordDate",
        width: 130,
    },
    {
        dataType: "action",
        label: "操作",
        align: "center",
        width: '130',
        fixed: 'right',
        operation: [
            {
                name: "检定校准",
                type: "text",
                clickFun: (row) => {
                    openCalibrationDia("verifying", row);
                },
            },
            // {
            //     name: "附件",
            //     type: "text",
            //     clickFun: (row) => {
      //     openFilesFormDia(row);
            //     },
            // },
        ],
    },
]);
const tableData = ref([]);
const tableLoading = ref(false);
const filesDia = ref()
const page = reactive({
    current: 1,
    size: 100,
    total: 0,
});
const selectedRows = ref([]);
// æ‰“开附件弹框
const openFilesFormDia = (row) => {
  console.log(row)
  nextTick(() => {
    filesDia.value?.openDialog( row,'计量器具台账')
  })
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
    selectedRows.value = selection;
};
const formDia = ref()
const calibrationDia = ref()
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
    page.current = 1;
    getList();
};
const pagination = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
const getList = () => {
    tableLoading.value = true;
    measuringInstrumentListPage({ ...searchForm.value, ...page }).then((res) => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
    }).catch((err) => {
        tableLoading.value = false;
    })
};
// æ‰“开弹框
const openForm = (type, row) => {
    nextTick(() => {
        formDia.value?.openDialog(type, row)
    })
};
// æ‰“开检定校准弹框
const openCalibrationDia = (type, row) => {
    nextTick(() => {
        calibrationDia.value?.openDialog(type, row)
    })
}
const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
        ids = selectedRows.value.map((item) => item.id);
    } else {
        proxy.$modal.msgWarning("请选择数据");
        return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            tableLoading.value = true;
            measuringInstrumentDelete(ids)
                .then((res) => {
                    proxy.$modal.msgSuccess("删除成功");
                    getList();
                })
                .finally(() => {
                    tableLoading.value = false;
                });
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
// å¯¼å‡º
const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/measuringInstrumentLedger/export", {}, "计量器具台账.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
onMounted(() => {
    getList();
});
</script>
<style scoped>
</style>