huminmin
4 天以前 75435383608c681cb4158b22c166bc3a3cd33c96
Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro
已添加1个文件
已修改36个文件
818 ■■■■ 文件已修改
multiple/config.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/repair.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/sealManagement/index.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/components/formDia.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/index.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/formDia.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/index.vue 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/RepairModal.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/index.vue 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/PlanModal.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/formDia.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/index.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/index.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/PSIDataAnalysis/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/center-center.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/center-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/left-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/components/right-top.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionAnalysis/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
multiple/config.json
@@ -44,7 +44,7 @@
  },
  "BTYX": {
    "env": {
      "VITE_APP_TITLE": "河南帮太优选进出口有限公司",
      "VITE_APP_TITLE": "河南帮太优选食品有限公司",
      "VITE_BASE_API": "http://1.15.17.182:9056",
      "VITE_JAVA_API": "http://1.15.17.182:9057"
    },
src/api/equipmentManagement/repair.js
@@ -70,3 +70,16 @@
    data,
  });
};
/**
 * @desc éªŒæ”¶å®¡æ‰¹
 * @param {验收参数} data
 * @returns
 */
export const repairAcceptance = (data) => {
  return request({
    url: `/device/repair/acceptance`,
    method: "post",
    data,
  });
};
src/views/collaborativeApproval/sealManagement/index.vue
@@ -87,10 +87,18 @@
        </el-form-item>
        <el-form-item label="紧急程度" prop="urgency">
          <el-radio-group v-model="sealForm.urgency">
            <el-radio label="normal">普通</el-radio>
            <el-radio label="urgent">紧急</el-radio>
            <el-radio label="very-urgent">特急</el-radio>
            <el-radio value="normal">普通</el-radio>
            <el-radio value="urgent">紧急</el-radio>
            <el-radio value="very-urgent">特急</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="附件上传">
          <AttachmentUploadFile
            v-model:fileList="sealForm.storageBlobDTOs"
            :limit="10"
            :fileSize="50"
            buttonText="点击上传附件"
          />
        </el-form-item>
      </el-form>
    </FormDialog>
@@ -119,8 +127,27 @@
          </el-descriptions-item>
          <el-descriptions-item label="申请原因" :span="2">{{ currentSealDetail.reason }}</el-descriptions-item>
        </el-descriptions>
        <!-- é™„件列表 -->
        <div v-if="currentSealDetail.storageBlobVOList?.length || currentSealDetail.storageBlobDTOs?.length" class="attachment-section">
          <div class="attachment-title">附件列表:</div>
          <el-table :data="currentSealDetail.storageBlobVOList || currentSealDetail.storageBlobDTOs" border class="attachment-table">
            <el-table-column label="附件名称" show-overflow-tooltip>
              <template #default="scope">
                {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || '未命名文件' }}
              </template>
            </el-table-column>
            <el-table-column fixed="right" label="操作" width="150" align="center">
              <template #default="scope">
                <el-button link type="primary" size="small" @click="previewFile(scope.row)">预览</el-button>
                <el-button link type="primary" size="small" @click="downloadFile(scope.row)">下载</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </FormDialog>
    <!-- æ–‡ä»¶é¢„览组件 -->
    <FilePreview ref="filePreviewRef" />
  </div>
</template>
@@ -134,6 +161,9 @@
import useUserStore from '@/store/modules/user'
import FormDialog from '@/components/Dialog/FormDialog.vue'
import PIMTable from '@/components/PIMTable/PIMTable.vue'
import AttachmentUploadFile from '@/components/AttachmentUpload/file/index.vue'
import FilePreview from '@/components/filePreview/index.vue'
import download from '@/plugins/download.js'
// å“åº”式数据
// ç”¨å°ç”³è¯·ç›¸å…³
@@ -143,6 +173,7 @@
const tableLoading = ref(false)
const showSealDetailDialog = ref(false)
const currentSealDetail = ref(null)
const filePreviewRef = ref(null)
const sealFormRef = ref()
const userList = ref([])
const sealForm = reactive({
@@ -152,7 +183,8 @@
  reason: '',
  approveUserId: '',
  urgency: 'normal',
  status: 'pending'
  status: 'pending',
  storageBlobDTOs: []
})
const sealRules = {
@@ -281,7 +313,8 @@
        reason: '',
        approveUserId: '',
        urgency: 'normal',
        status: 'pending'
        status: 'pending',
        storageBlobDTOs: []
      })
      }
    }).catch(err => {
@@ -301,7 +334,8 @@
    reason: '',
    approveUserId: '',
    urgency: 'normal',
    status: 'pending'
    status: 'pending',
    storageBlobDTOs: []
  })
  // æ¸…除表单验证状态
  if (sealFormRef.value) {
@@ -318,6 +352,27 @@
const viewSealDetail = (row) => {
  currentSealDetail.value = row
  showSealDetailDialog.value = true
}
// é¢„览文件
const previewFile = (row) => {
  const url = row.previewURL || row.previewUrl || row.url
  if (url && filePreviewRef.value) {
    filePreviewRef.value.open(url)
  } else {
    ElMessage.warning('文件地址无效,无法预览')
  }
}
// ä¸‹è½½æ–‡ä»¶
const downloadFile = (row) => {
  const url = row.downloadURL || row.downloadUrl || row.url
  if (url) {
    const filename = row.originalFilename || row.name || row.fileName || 'download'
    download.byUrl(url, filename)
  } else {
    ElMessage.warning('文件地址无效,无法下载')
  }
}
// å®¡æ‰¹ç”¨å°ç”³è¯·
const approveSeal = (row) => {
@@ -421,4 +476,19 @@
.ml-10 {
  margin-left: 10px;
}
.attachment-section {
  margin-top: 20px;
}
.attachment-title {
  font-size: 14px;
  color: #606266;
  margin-bottom: 10px;
  font-weight: 500;
}
.attachment-table {
  border-radius: 4px;
}
</style>
src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -26,6 +26,21 @@
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="巡检项目" prop="inspectionProject">
              <el-input v-model="form.inspectionProject" placeholder="请输入巡检项目" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否启用" prop="isEnabled">
              <el-radio-group v-model="form.isEnabled">
                <el-radio :value="1">是</el-radio>
                <el-radio :value="0">否</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>
@@ -118,6 +133,8 @@
    taskName: undefined,
    inspector: '',
    inspectorIds: '',
    inspectionProject: '',
    isEnabled: 1,
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
@@ -245,6 +262,8 @@
    taskName: undefined,
    inspector: '',
    inspectorIds: '',
    inspectionProject: '',
    isEnabled: 1,
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
src/views/equipmentManagement/inspectionManagement/index.vue
@@ -70,6 +70,11 @@
                    class="no-data">--</span>
            </div>
          </template>
          <template #isEnabled="{ row }">
            <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'" size="small">
              {{ row.isEnabled == 1 ? '是' : '否' }}
            </el-tag>
          </template>
        </PIMTable>
      </div>
    </el-card>
@@ -126,8 +131,16 @@
  // åˆ—配置
  const columns = ref([
    { prop: "taskName", label: "巡检任务名称", minWidth: 160 },
    { prop: "inspectionProject", label: "巡检项目", minWidth: 150 },
    { prop: "remarks", label: "备注", minWidth: 150 },
    { prop: "inspector", label: "执行巡检人", minWidth: 150, slot: "inspector" },
    {
      prop: "isEnabled",
      label: "是否启用",
      minWidth: 100,
      dataType: "slot",
      slot: "isEnabled"
    },
    {
      prop: "frequencyType",
      label: "频次",
@@ -227,8 +240,10 @@
      operationsArr.value = ["edit"];
    } else if (value === "task") {
      const operationColumn = getOperationColumn(["viewFile"]);
      // å®šæ—¶ä»»åŠ¡è®°å½•ä¸å±•ç¤º"是否启用"列
      const taskColumns = columns.value.filter(col => col.prop !== "isEnabled");
      tableColumns.value = [
        ...columns.value,
        ...taskColumns,
        ...(operationColumn ? [operationColumn] : []),
      ];
      operationsArr.value = ["viewFile"];
src/views/equipmentManagement/measurementEquipment/components/formDia.vue
@@ -36,15 +36,6 @@
                </el-row>
                <el-row :gutter="30">
                    <el-col :span="12">
                        <el-form-item label="安装位置:" prop="instationLocation">
                            <el-input
                                v-model="form.instationLocation"
                                placeholder="请输入"
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="检定单位:" prop="unit">
              <el-input
                  v-model="form.unit"
@@ -53,17 +44,17 @@
              />
                        </el-form-item>
                    </el-col>
                </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="证书编号:" prop="model">
                    <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>
                </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="最新鉴定日期:" prop="mostDate">
              <el-date-picker
@@ -77,8 +68,6 @@
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="有效日期(天):" prop="valid">
              <el-input
@@ -91,15 +80,6 @@
              >
              <template #append>日</template>
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="检定周期:" prop="cycle">
              <el-input
                  v-model="form.cycle"
                  placeholder="请输入检定周期"
                  clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -184,10 +164,8 @@
    form: {
        code: "",
    name: "",
    instationLocation: "",
    mostDate:"",
        model: "",
    cycle:"",
        validDate: "",
        nextDate: "",
        userId: "",
@@ -203,9 +181,7 @@
        nextDate: [{required: true, message: "请选择", trigger: "change"}],
        userId: [{required: true, message: "请选择", trigger: "change"}],
        recordDate: [{required: true, message: "请选择", trigger: "change"}],
    instationLocation: [{required: true, message: "请输入", trigger: "blur"}],
    mostDate: [{required: true, message: "请选择", trigger: "change"}],
    cycle: [{required: true, message: "请选择", trigger: "blur"}],
    valid: [
      {required: true, message: "请输入", trigger: "blur"},
      {
src/views/equipmentManagement/measurementEquipment/index.vue
@@ -42,6 +42,7 @@
                :tableLoading="tableLoading"
                @pagination="pagination"
        :dbRowClick="dbRowClick"
        :rowClassName="rowClassName"
            ></PIMTable>
        </div>
        <form-dia ref="formDia" @close="handleQuery"></form-dia>
@@ -89,12 +90,6 @@
    align: "center",
  },
    {
        label: "安装位置",
        prop: "instationLocation",
        width: 150,
    align:"center"
    },
    {
        label: "检定单位",
        prop: "unit",
        width: 200,
@@ -130,12 +125,6 @@
        width: 130,
    align:"center"
    },
  {
    label: "检定周期(天)",
    prop: "cycle",
    width: 130,
    align:"center"
  },
  {
    label: "状态",
    prop: "status",
@@ -193,6 +182,31 @@
const dbRowClick = (row)=>{
  rowClickData.value?.openDialog(row)
}
// è¡Œæ ·å¼ï¼šå¿«åˆ°æœŸï¼ˆ7天内)或逾期标红
const rowClassName = ({ row }) => {
  console.log('rowClassName called:', row);
  // valid æ˜¯æœ‰æ•ˆå¤©æ•°ï¼ŒmostDate æ˜¯æœ€æ–°æ£€å®šæ—¥æœŸ
  if (row.valid && row.mostDate) {
    const mostDate = new Date(row.mostDate);
    // è®¡ç®—到期日期 = æ£€å®šæ—¥æœŸ + æœ‰æ•ˆå¤©æ•°
    const validDays = parseInt(row.valid) || 0;
    const expireDate = new Date(mostDate);
    expireDate.setDate(expireDate.getDate() + validDays);
    const now = new Date();
    const diffDays = Math.ceil((expireDate - now) / (1000 * 60 * 60 * 24));
    console.log('row:', row.code, 'validDays:', validDays, 'expireDate:', expireDate, 'diffDays:', diffDays);
    // 7天内到期或已逾期都标红
    if (diffDays <= 7) {
      console.log('return warning-row');
      return 'warning-row';
    }
  } else {
    console.log('row missing valid or mostDate:', row.valid, row.mostDate);
  }
  return '';
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
@@ -294,5 +308,13 @@
</script>
<style scoped>
:deep(.el-table .warning-row) {
  background-color: #fef0f0 !important;
}
:deep(.el-table .warning-row:hover > td) {
  background-color: #f9d5d5 !important;
}
:deep(.el-table .el-table__body tr.warning-row td) {
  background-color: #fef0f0 !important;
}
</style>
src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
<template>
  <FormDialog
    v-model="visible"
    title="验收审批"
    width="500px"
    @confirm="submitForm"
    @cancel="handleCancel"
    @close="handleCancel"
  >
    <el-form :model="form" :rules="rules" label-width="100px">
      <el-form-item label="验收人" prop="acceptanceName">
        <el-select
          v-model="form.acceptanceName"
          placeholder="请选择验收人"
          filterable
          style="width: 100%"
        >
          <el-option
            v-for="item in userList"
            :key="item.userId"
            :label="item.nickName"
            :value="item.nickName"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="验收时间" prop="acceptanceTime">
        <el-date-picker
          v-model="form.acceptanceTime"
          type="datetime"
          placeholder="请选择验收时间"
          format="YYYY-MM-DD HH:mm:ss"
          value-format="YYYY-MM-DD HH:mm:ss"
          style="width: 100%"
        />
      </el-form-item>
      <el-form-item label="验收备注" prop="acceptanceRemark">
        <el-input
          v-model="form.acceptanceRemark"
          type="textarea"
          :rows="3"
          placeholder="请输入验收备注"
        />
      </el-form-item>
    </el-form>
  </FormDialog>
</template>
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
import { ref, reactive } from "vue";
import { ElMessage } from "element-plus";
import { userListNoPageByTenantId } from "@/api/system/user.js";
import { repairAcceptance } from "@/api/equipmentManagement/repair";
import dayjs from "dayjs";
defineOptions({
  name: "验收审批弹窗",
});
const emits = defineEmits(["ok"]);
const visible = ref(false);
const loading = ref(false);
const repairId = ref(null);
const userList = ref([]);
const form = reactive({
  acceptanceName: undefined,
  acceptanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
  acceptanceRemark: undefined,
});
const rules = {
  acceptanceName: [
    { required: true, message: "请选择验收人", trigger: "change" },
  ],
  acceptanceTime: [
    { required: true, message: "请选择验收时间", trigger: "change" },
  ],
  acceptanceRemark: [
    { required: true, message: "请输入验收备注", trigger: "blur" },
  ],
};
// åŠ è½½ç”¨æˆ·åˆ—è¡¨
const loadUserList = async () => {
  const { data } = await userListNoPageByTenantId();
  userList.value = data;
};
// æ‰“开弹窗
const open = async (row) => {
  repairId.value = row.id;
  visible.value = true;
  // é‡ç½®è¡¨å•
  form.acceptanceName = undefined;
  form.acceptanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.acceptanceRemark = undefined;
  await loadUserList();
};
// æäº¤è¡¨å•
const submitForm = async () => {
  if (!form.acceptanceName) {
    ElMessage.warning("请选择验收人");
    return;
  }
  if (!form.acceptanceTime) {
    ElMessage.warning("请选择验收时间");
    return;
  }
  if (!form.acceptanceRemark) {
    ElMessage.warning("请输入验收备注");
    return;
  }
  loading.value = true;
  try {
    const { code } = await repairAcceptance({
      id: repairId.value,
      acceptanceName: form.acceptanceName,
      acceptanceTime: form.acceptanceTime,
      acceptanceRemark: form.acceptanceRemark,
    });
    if (code === 200) {
      ElMessage.success("验收通过");
      visible.value = false;
      emits("ok");
    }
  } finally {
    loading.value = false;
  }
};
const handleCancel = () => {
  visible.value = false;
};
defineExpose({
  open,
});
</script>
<style lang="scss" scoped></style>
src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -49,19 +49,44 @@
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="项目">
            <el-input v-model="form.machineryCategory" placeholder="请输入项目" />
          <el-form-item label="报修报修项目">
            <el-input v-model="form.machineryCategory" placeholder="请输入报修报修项目" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="12">
          <el-form-item label="维修人">
            <el-input v-model="form.maintenanceName" 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-select v-model="form.status" disabled>
              <el-option label="待维修" :value="0"></el-option>
              <el-option label="完结" :value="1"></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 v-if="id && form.status === 1">
        <el-col :span="12">
          <el-form-item label="验收人">
            <el-input v-model="form.acceptanceName" disabled />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="验收时间">
            <el-input v-model="form.acceptanceTime" disabled />
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="验收备注">
            <el-input v-model="form.acceptanceRemark" type="textarea" :rows="2" disabled />
          </el-form-item>
        </el-col>
      </el-row>
@@ -131,6 +156,7 @@
  status: 0, // æŠ¥ä¿®çŠ¶æ€
  machineryCategory: undefined,
  storageBlobDTOs: [],
  maintenanceName: undefined, // ç»´ä¿®äºº
});
const setDeviceModel = (deviceId) => {
@@ -148,6 +174,10 @@
  form.status = data.status;
  form.machineryCategory = data.machineryCategory;
  form.storageBlobDTOs = data.storageBlobVOs || [];
  form.maintenanceName = data.maintenanceName;
  form.acceptanceName = data.acceptanceName;
  form.acceptanceTime = data.acceptanceTime;
  form.acceptanceRemark = data.acceptanceRemark;
};
const sendForm = async () => {
src/views/equipmentManagement/repair/index.vue
@@ -100,13 +100,14 @@
        <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 === 3" type="info">待验收</el-tag>
          <el-tag v-if="row.status === 0" type="warning">待维修</el-tag>
        </template>
        <template #operation="{ row }">
          <el-button
            type="primary"
            link
            :disabled="row.status === 1"
            :disabled="row.status === 1 || row.status === 3"
            @click="editRepair(row.id)"
          >
            ç¼–辑
@@ -114,15 +115,23 @@
          <el-button
            type="success"
            link
            :disabled="row.status === 1"
            :disabled="row.status !== 0"
            @click="addMaintain(row)"
          >
            ç»´ä¿®
          </el-button>
          <el-button
            type="warning"
            link
            :disabled="row.status !== 3"
            @click="openAcceptance(row)"
          >
            éªŒæ”¶
          </el-button>
          <el-button
            type="danger"
            link
            :disabled="row.status === 1"
            :disabled="row.status === 1 || row.status === 3"
            @click="delRepairByIds(row.id)"
          >
            åˆ é™¤
@@ -139,6 +148,7 @@
    </div>
    <RepairModal ref="repairModalRef" @ok="getTableData"/>
    <MaintainModal ref="maintainModalRef" @ok="getTableData"/>
    <AcceptanceModal ref="acceptanceModalRef" @ok="getTableData"/>
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" :record-type="'device_repair'" :record-id="recordId"  />
  </div>
</template>
@@ -151,6 +161,7 @@
import {ElMessageBox, ElMessage} from "element-plus";
import dayjs from "dayjs";
import MaintainModal from "./Modal/MaintainModal.vue";
import AcceptanceModal from "./Modal/AcceptanceModal.vue";
const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
defineOptions({
@@ -162,6 +173,7 @@
// æ¨¡æ€æ¡†å®žä¾‹
const repairModalRef = ref();
const maintainModalRef = ref();
const acceptanceModalRef = ref();
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
@@ -197,7 +209,7 @@
        prop: "deviceModel",
      },
      {
        label: "项目",
        label: "报修项目",
        align: "center",
        prop: "machineryCategory",
      },
@@ -232,6 +244,17 @@
        align: "center",
        prop: "maintenanceTime",
        formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
      },
      {
        label: "验收人",
        align: "center",
        prop: "acceptanceName",
      },
      {
        label: "验收时间",
        align: "center",
        prop: "acceptanceTime",
        formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : ""),
      },
      {
        label: "状态",
@@ -301,6 +324,11 @@
  maintainModalRef.value.open(row.id, row);
};
// æ‰“开验收弹窗
const openAcceptance = (row) => {
  acceptanceModalRef.value.open(row);
};
const changePage = ({page, limit}) => {
  pagination.currentPage = page;
  pagination.pageSize = limit;
src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -32,10 +32,10 @@
          disabled
        />
      </el-form-item>
      <el-form-item label="项目">
      <el-form-item label="保养项目">
        <el-input
            v-model="form.machineryCategory"
            placeholder="请输入项目"
            placeholder="请输入保养项目"
        />
      </el-form-item>
      <el-form-item label="录入人">
@@ -61,6 +61,13 @@
          <el-option label="完结" :value="1"></el-option>
          <el-option label="失败" :value="2"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="保养人">
        <el-input
          v-model="form.maintenancePerson"
          placeholder="请输入保养人姓名"
          clearable
        />
      </el-form-item>
      <el-form-item label="计划保养日期">
        <el-date-picker
@@ -124,6 +131,7 @@
  status: 0, //保修状态
  machineryCategory: undefined,
  storageBlobDTOs: [],
  maintenancePerson: undefined, // ä¿å…»äºº
});
const setDeviceModel = (deviceId) => {
@@ -142,6 +150,7 @@
  form.createUser = Number(data.createUser);
  form.status = data.status;
  form.machineryCategory = data.machineryCategory;
  form.maintenancePerson = data.maintenancePerson;
  if (data.maintenancePlanTime) {
    form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
      "YYYY-MM-DD HH:mm:ss"
src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -67,10 +67,20 @@
            </el-row>
            <el-row>
                <el-col :span="12">
                    <el-form-item label="设备项目" prop="machineryCategory">
                    <el-form-item label="保养项目" prop="machineryCategory">
                        <el-input
                            v-model.trim="form.machineryCategory"
                            placeholder="请输入设备项目"
                            placeholder="请输入保养项目"
                            maxlength="100"
                            clearable
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="保养人" prop="maintenancePerson">
                        <el-input
                            v-model.trim="form.maintenancePerson"
                            placeholder="请输入保养人姓名"
                            maxlength="100"
                            clearable
                        />
@@ -173,13 +183,14 @@
        week: '',
        time: '',
        deviceModel: undefined, // è§„格型号
        registrationDate: ''
        registrationDate: '',
        maintenancePerson: '' // ä¿å…»äºº
    },
    rules: {
        taskId: [{ required: true, message: "请选择设备", trigger: "change" },],
        inspector: [{ required: true, message: "请选择录入人", trigger: "blur" },],
        registrationDate: [{ required: true, message: "请选择登记时间", trigger: "change" }],
        machineryCategory: [{ required: true, message: "请输入设备项目", trigger: "blur" }]
        machineryCategory: [{ required: true, message: "请输入保养项目", trigger: "blur" }]
    }
})
const { form, rules } = toRefs(data)
@@ -259,7 +270,8 @@
        week: '',
        time: '',
        deviceModel: undefined,
        registrationDate: ''
        registrationDate: '',
        maintenancePerson: ''
    }
}
src/views/equipmentManagement/upkeep/index.vue
@@ -300,7 +300,7 @@
      prop: "deviceModel",
    },
    {
      label: "设备项目",
      label: "保养项目",
      prop: "machineryCategory",
      minWidth: 120,
      formatData: cell => cell || "--",
@@ -342,6 +342,7 @@
        );
      },
    },
    { prop: "maintenancePerson", label: "保养人", minWidth: 100 },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "registrationDate", label: "登记日期", minWidth: 100 },
    {
@@ -378,7 +379,7 @@
      prop: "createUserName",
    },
    {
      label: "设备项目",
      label: "保养项目",
      align: "center",
      prop: "machineryCategory",
      formatData: cell => cell || "--",
src/views/personnelManagement/contractManagement/index.vue
@@ -23,6 +23,12 @@
        :total="page.total"></PIMTable>
    </div>
    <form-dia ref="formDia" @close="handleQuery"></form-dia>
    <renew-contract
        v-if="isShowRenewContractModal"
        v-model:visible="isShowRenewContractModal"
        :id="id"
        @completed="handleQuery"
    />
    <!-- åˆåŒå¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog
@@ -71,8 +77,9 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import { onMounted, ref } from "vue";
import { onMounted, ref, defineAsyncComponent } from "vue";
import FormDia from "@/views/personnelManagement/contractManagement/components/formDia.vue";
const RenewContract = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/RenewContract.vue"));
import { ElMessageBox } from "element-plus";
import { staffOnJobListPage } from "@/api/personnelManagement/staffOnJob.js";
import dayjs from "dayjs";
@@ -183,7 +190,7 @@
    label: "操作",
    align: "center",
    fixed: 'right',
    width: 120,
    width: 160,
    operation: [
      {
        name: "详情",
@@ -191,11 +198,22 @@
        clickFun: (row) => {
          openForm("edit", row);
        },
      },
      {
        name: "续签合同",
        type: "text",
        showHide: row => row.staffState === 1,
        clickFun: (row) => {
          isShowRenewContractModal.value = true;
          id.value = row.id;
        },
      }
    ],
  },
]);
const filesDia = ref()
const isShowRenewContractModal = ref(false);
const id = ref(0);
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
src/views/personnelManagement/employeeRecord/index.vue
@@ -52,16 +52,14 @@
          :tableLoading="tableLoading"
          @pagination="pagination"
          :total="page.total"
      ></PIMTable>
      >
        <template #positiveDate="{ row }">
          <span :class="getPositiveDateClass(row.positiveDate)">{{ row.positiveDate }}</span>
        </template>
      </PIMTable>
    </div>
    <show-form-dia ref="formDia" @close="handleQuery"></show-form-dia>
    <new-or-edit-form-dia ref="formDiaNewOrEditFormDia" @close="handleQuery"></new-or-edit-form-dia>
    <renew-contract
        v-if="isShowRenewContractModal"
        v-model:visible="isShowRenewContractModal"
        :id="id"
        @completed="handleQuery"
    />
    
    <!-- å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
@@ -107,7 +105,6 @@
const NewOrEditFormDia = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue"));
const ShowFormDia = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/Show.vue"));
const RenewContract = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/RenewContract.vue"));
const data = reactive({
  searchForm: {
@@ -119,8 +116,6 @@
  deptOptions: [],
});
const { searchForm, deptOptions } = toRefs(data);
const isShowRenewContractModal = ref(false);
const id = ref(0);
const tableColumn = ref([
  {
    label: "状态",
@@ -177,6 +172,13 @@
    width: 120,
  },
  {
    label: "转正日期",
    prop: "positiveDate",
    width: 120,
    dataType: "slot",
    slot: "positiveDate",
  },
  {
    label: "年龄",
    prop: "age",
  },
@@ -208,22 +210,6 @@
          openFormNewOrEditFormDia("edit", row);
        },
      },
      {
        name: "续签合同",
        type: "text",
        showHide: row => row.staffState === 1,
        clickFun: (row) => {
          isShowRenewContractModal.value = true;
          id.value = row.id;
        },
      },
      // {
      //   name: "详情",
      //   type: "text",
      //   clickFun: (row) => {
      //     openForm("edit", row);
      //   },
      // },
    ],
  },
]);
@@ -253,6 +239,22 @@
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/staff/staffOnJob/import"
})
// åˆ¤æ–­è½¬æ­£æ—¥æœŸæ˜¯å¦åœ¨7天内
const getPositiveDateClass = (positiveDate) => {
  if (!positiveDate) return '';
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const positive = new Date(positiveDate);
  positive.setHours(0, 0, 0, 0);
  const diffTime = positive - today;
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
  // 7天内转正(包括今天)显示警告色
  if (diffDays >= 0 && diffDays <= 7) {
    return 'positive-date-warning';
  }
  return '';
};
const fetchDeptOptions = () => {
    deptTreeSelect().then(response => {
@@ -402,4 +404,9 @@
.search_title2 {
  margin-left: 10px;
}
.positive-date-warning {
  color: #f56c6c;
  font-weight: bold;
}
</style>
src/views/procurementManagement/procurementLedger/index.vue
@@ -693,6 +693,7 @@
  const salesContractList = ref([]);
  const supplierList = ref([]);
  const tableLoading = ref(false);
  const recordId = ref();
  const fileListDialogVisible = ref(false);
  const page = reactive({
    current: 1,
src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
@@ -23,7 +23,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import * as echarts from 'echarts'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from './PanelHeader.vue'
@@ -151,6 +151,13 @@
  fetchData()
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
@@ -27,7 +27,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import { productTurnoverDays } from '@/api/viewIndex.js'
@@ -82,6 +82,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
@@ -24,7 +24,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import { salesPurchaseStorageProductCount } from '@/api/viewIndex.js'
const statItems = ref([])
@@ -52,6 +52,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
@@ -22,7 +22,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from './PanelHeader.vue'
import CarouselCards from './CarouselCards.vue'
@@ -205,6 +205,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
  initBackground()
src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
@@ -21,7 +21,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
import { productSalesAnalysis } from '@/api/viewIndex.js'
import PanelHeader from './PanelHeader.vue'
import CarouselCards from './CarouselCards.vue'
@@ -175,6 +175,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
  initBackground()
src/views/reportAnalysis/PSIDataAnalysis/index.vue
@@ -43,7 +43,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
import autofit from 'autofit.js'
import LeftBottom from './components/left-bottom.vue'
import CenterCenter from './components/center-center.vue'
@@ -65,6 +65,12 @@
// ç”¨æˆ·store
const userStore = useUserStore()
/** ä¸Ž dataDashboard å…±ç”¨æ³¨å…¥åï¼Œå­ç»„件(含复用的 right-top/right-bottom)每分钟刷新 */
const DASHBOARD_REFRESH_MS = 60 * 1000
const dataDashboardRefreshTick = ref(0)
provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
let dashboardPollTimer = null
// è®¡ç®—缩放比例
const calculateScale = () => {
@@ -140,9 +146,17 @@
  window.addEventListener('fullscreenchange', handleFullscreenChange)
  window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
  window.addEventListener('MSFullscreenChange', handleFullscreenChange)
  dashboardPollTimer = setInterval(() => {
    dataDashboardRefreshTick.value++
  }, DASHBOARD_REFRESH_MS)
})
onBeforeUnmount(() => {
  if (dashboardPollTimer) {
    clearInterval(dashboardPollTimer)
    dashboardPollTimer = null
  }
  window.removeEventListener('resize', handleResize)
  window.removeEventListener('fullscreenchange', handleFullscreenChange)
  window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
@@ -20,7 +20,7 @@
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted, computed, inject, watch } from 'vue'
import { deptStaffDistribution } from '@/api/viewIndex.js'
import PanelHeader from '../PanelHeader.vue'
import Echarts from '@/components/Echarts/echarts.vue'
@@ -148,6 +148,13 @@
  })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    getDeptStaffDistribution()
  })
}
onMounted(() => {
  getDeptStaffDistribution()
})
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
@@ -110,7 +110,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { ref, onMounted, onBeforeUnmount, nextTick, inject, watch } from 'vue'
import { homeTodos, summaryStatistics } from '@/api/viewIndex.js'
import { getLedgerPage } from '@/api/equipmentManagement/ledger.js'
import { getRepairPage } from '@/api/equipmentManagement/repair.js'
@@ -175,8 +175,23 @@
  })
}
const destroyTodoListScroll = () => {
  const todoListEl = refTodoList.value
  if (todoListEl) {
    if (todoListEl._animationFrame) {
      cancelAnimationFrame(todoListEl._animationFrame)
      todoListEl._animationFrame = null
    }
    if (todoListEl._pauseTimer) {
      clearInterval(todoListEl._pauseTimer)
      todoListEl._pauseTimer = null
    }
  }
}
// åˆå§‹åŒ–待办事项列表滚动功能
const initTodoListScroll = () => {
  destroyTodoListScroll()
  const todoListEl = refTodoList.value
  // å¼ºåˆ¶å¯ç”¨æ»šåŠ¨ï¼Œä¸æ£€æŸ¥ä»»ä½•æ¡ä»¶
  if (todoListEl) {
@@ -259,6 +274,7 @@
// å¾…办事项
const todoInfoS = () => {
  destroyTodoListScroll()
  homeTodos().then((res) => {
    todoList.value = res.data
    // åœ¨èŽ·å–åˆ°å¾…åŠžäº‹é¡¹æ•°æ®åŽï¼Œåˆå§‹åŒ–æ»šåŠ¨åŠŸèƒ½
@@ -268,25 +284,25 @@
  })
}
onMounted(() => {
const refreshCenterTopData = () => {
  getNum()
  getLedgerNum()
  todoInfoS()
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    refreshCenterTopData()
  })
}
onMounted(() => {
  refreshCenterTopData()
})
onBeforeUnmount(() => {
  // æ¸…理待办事项列表的动画和定时器
  const todoListEl = refTodoList.value
  if (todoListEl) {
    if (todoListEl._animationFrame) {
      cancelAnimationFrame(todoListEl._animationFrame)
      todoListEl._animationFrame = null
    }
    if (todoListEl._pauseTimer) {
      clearInterval(todoListEl._pauseTimer)
      todoListEl._pauseTimer = null
    }
  }
  destroyTodoListScroll()
})
</script>
src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
@@ -40,7 +40,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from '../PanelHeader.vue'
import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -192,6 +192,13 @@
  getCustomerRevenueAnalysis()
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    getCustomerRevenueAnalysis()
  })
}
onMounted(() => {
  fetchCustomerOptions()
})
src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
@@ -21,7 +21,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { ref, onMounted, onBeforeUnmount, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from '../PanelHeader.vue'
import { productCategoryDistribution } from '@/api/viewIndex.js'
@@ -207,6 +207,13 @@
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    loadData()
  })
}
onMounted(() => {
  loadData()
  initBackground()
src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
@@ -22,7 +22,7 @@
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted, computed, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from '../PanelHeader.vue'
import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -308,6 +308,13 @@
  fetchCustomerRanking()
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchCustomerRanking()
  })
}
onMounted(() => {
  fetchCustomerRanking()
})
src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
@@ -21,7 +21,7 @@
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted, computed, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from '../PanelHeader.vue'
import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -331,6 +331,13 @@
  fetchSupplierRanking()
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchSupplierRanking()
  })
}
onMounted(() => {
  fetchSupplierRanking()
})
src/views/reportAnalysis/dataDashboard/index.vue
@@ -44,7 +44,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
import autofit from 'autofit.js'
import LeftTop from './components/basic/left-top.vue'
import LeftBottom from './components/basic/left-bottom.vue'
@@ -65,6 +65,12 @@
// ç”¨æˆ·store
const userStore = useUserStore()
// å¤§å±æŽ¥å£è½®è¯¢é—´éš”
const DASHBOARD_REFRESH_MS = 60 * 1000
const dataDashboardRefreshTick = ref(0)
provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
let dashboardPollTimer = null
// è®¡ç®—缩放比例
const calculateScale = () => {
@@ -140,9 +146,17 @@
  window.addEventListener('fullscreenchange', handleFullscreenChange)
  window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
  window.addEventListener('MSFullscreenChange', handleFullscreenChange)
  dashboardPollTimer = setInterval(() => {
    dataDashboardRefreshTick.value++
  }, DASHBOARD_REFRESH_MS)
})
onBeforeUnmount(() => {
  if (dashboardPollTimer) {
    clearInterval(dashboardPollTimer)
    dashboardPollTimer = null
  }
  window.removeEventListener('resize', handleResize)
  window.removeEventListener('fullscreenchange', handleFullscreenChange)
  window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
@@ -51,7 +51,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { ref, onMounted, onBeforeUnmount, nextTick, inject, watch } from 'vue'
import { getProgressStatistics } from '@/api/viewIndex.js'
import PanelHeader from './PanelHeader.vue'
import CarouselCards from './CarouselCards.vue'
@@ -132,17 +132,22 @@
  }, 150)
}
const initProgressTableScroll = () => {
  const tableContainer = progressTableRef.value
  if (!tableContainer) return
const stopProgressTableScroll = () => {
  if (progressTableScrollTimer.value) {
    cancelAnimationFrame(progressTableScrollTimer.value)
    progressTableScrollTimer.value = null
  }
  if (tableContainer._pauseTimer) {
  const tableContainer = progressTableRef.value
  if (tableContainer?._pauseTimer) {
    clearInterval(tableContainer._pauseTimer)
    tableContainer._pauseTimer = null
  }
}
const initProgressTableScroll = () => {
  const tableContainer = progressTableRef.value
  if (!tableContainer) return
  stopProgressTableScroll()
  const tbody = tableContainer.querySelector('tbody')
  if (!tbody) return
  const originalCount = progressTableData.value.length
@@ -198,6 +203,7 @@
const progressStatisticsInfo = () => {
  getProgressStatistics()
    .then((res) => {
      stopProgressTableScroll()
      if (!res || !res.data) return
      const obj = {
        totalOrderCount: res.data.totalOrderCount || 0,
@@ -224,14 +230,19 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    progressStatisticsInfo()
  })
}
onMounted(() => {
  progressStatisticsInfo()
})
onBeforeUnmount(() => {
  if (progressTableScrollTimer.value) {
    cancelAnimationFrame(progressTableScrollTimer.value)
  }
  stopProgressTableScroll()
  if (tableScrollTimeout.value) clearTimeout(tableScrollTimeout.value)
  const tableContainer = progressTableRef.value
  if (tableContainer?._pauseTimer) {
src/views/reportAnalysis/productionAnalysis/components/center-center.vue
@@ -27,7 +27,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import * as echarts from 'echarts'
import Echarts from '@/components/Echarts/echarts.vue'
import { inputOutputAnalysis } from '@/api/viewIndex.js'
@@ -146,6 +146,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/productionAnalysis/components/center-top.vue
@@ -24,7 +24,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import { orderCount } from '@/api/viewIndex.js'
const statItems = ref([])
@@ -52,6 +52,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
@@ -22,7 +22,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from './PanelHeader.vue'
import CarouselCards from './CarouselCards.vue'
@@ -143,6 +143,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    workInProcessTurnoverInfo()
  })
}
onMounted(() => {
  workInProcessTurnoverInfo()
})
src/views/reportAnalysis/productionAnalysis/components/left-top.vue
@@ -23,7 +23,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
import { processOutputAnalysis } from '@/api/viewIndex.js'
import PanelHeader from './PanelHeader.vue'
import Echarts from '@/components/Echarts/echarts.vue'
@@ -170,6 +170,13 @@
  fetchData()
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
  initBackground()
src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
@@ -22,7 +22,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import { productionAccountingAnalysis } from '@/api/viewIndex.js'
import PanelHeader from './PanelHeader.vue'
import DateTypeSwitch from './DateTypeSwitch.vue'
@@ -157,6 +157,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/productionAnalysis/components/right-top.vue
@@ -22,7 +22,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, inject, watch } from 'vue'
import { workOrderEfficiencyAnalysis } from '@/api/viewIndex.js'
import PanelHeader from './PanelHeader.vue'
import Echarts from '@/components/Echarts/echarts.vue'
@@ -152,6 +152,13 @@
    })
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    fetchData()
  })
}
onMounted(() => {
  fetchData()
})
src/views/reportAnalysis/productionAnalysis/index.vue
@@ -44,7 +44,7 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
import autofit from 'autofit.js'
import LeftBottom from './components/left-bottom.vue'
import CenterCenter from './components/center-center.vue'
@@ -66,6 +66,12 @@
// ç”¨æˆ·store
const userStore = useUserStore()
/** ä¸Žå…¶å®ƒé©¾é©¶èˆ±å…±ç”¨æ³¨å…¥åï¼Œå­ç»„件每分钟刷新接口数据 */
const DASHBOARD_REFRESH_MS = 60 * 1000
const dataDashboardRefreshTick = ref(0)
provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
let dashboardPollTimer = null
// è®¡ç®—缩放比例
const calculateScale = () => {
@@ -141,9 +147,17 @@
  window.addEventListener('fullscreenchange', handleFullscreenChange)
  window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
  window.addEventListener('MSFullscreenChange', handleFullscreenChange)
  dashboardPollTimer = setInterval(() => {
    dataDashboardRefreshTick.value++
  }, DASHBOARD_REFRESH_MS)
})
onBeforeUnmount(() => {
  if (dashboardPollTimer) {
    clearInterval(dashboardPollTimer)
    dashboardPollTimer = null
  }
  window.removeEventListener('resize', handleResize)
  window.removeEventListener('fullscreenchange', handleFullscreenChange)
  window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)