From 633568cff8a45c9f92aec1ec5edb5a09a3b0d8a4 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期六, 14 三月 2026 13:26:38 +0800
Subject: [PATCH] fix: 隐患地点需要拍照而不是文字描述,需要可预览。

---
 src/pages/equipmentManagement/upkeepTask/components/formDia.vue |  659 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 659 insertions(+), 0 deletions(-)

diff --git a/src/pages/equipmentManagement/upkeepTask/components/formDia.vue b/src/pages/equipmentManagement/upkeepTask/components/formDia.vue
new file mode 100644
index 0000000..15fe952
--- /dev/null
+++ b/src/pages/equipmentManagement/upkeepTask/components/formDia.vue
@@ -0,0 +1,659 @@
+<template>
+  <u-popup :show="dialogVisitable"
+           mode="center"
+           :round="12"
+           :zIndex="900"
+           @close="cancel">
+    <view class="popup-content">
+      <view class="popup-title">{{ operationType === "add" ? "鏂板淇濆吇浠诲姟" : "缂栬緫淇濆吇浠诲姟" }}</view>
+      <view class="form-body">
+        <view class="form-item">
+          <text class="label">浠诲姟鍚嶇О</text>
+          <up-input v-model="form.taskName"
+                    placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
+                    border="none"
+                    customStyle="background: #f7f8fa; padding: 0 20rpx; min-height: 72rpx; border-radius: 12rpx;" />
+        </view>
+        <view class="form-item">
+          <text class="label">璁惧</text>
+          <view class="picker-value inspector-picker"
+                @click="openDevicePopup">
+            <text>{{ deviceNamesText || "璇烽�夋嫨璁惧" }}</text>
+            <u-icon name="arrow-right"
+                    size="14"
+                    color="#999" />
+          </view>
+          <view class="inspector-tags"
+                v-if="form.deviceIds?.length">
+            <view v-for="id in form.deviceIds"
+                  :key="id"
+                  class="inspector-tag"
+                  @click="toggleDevice(id)">
+              <text>{{ getDeviceName(id) }}</text>
+              <u-icon name="close"
+                      size="11"
+                      color="#1677ff" />
+            </view>
+          </view>
+        </view>
+        <view class="form-item">
+          <text class="label">褰曞叆浜�</text>
+          <picker mode="selector"
+                  :range="userList"
+                  range-key="nickName"
+                  :value="inspectorIndex"
+                  @change="onInspectorChange">
+            <view class="picker-value">{{ form.registrant || "璇烽�夋嫨褰曞叆浜�" }}</view>
+          </picker>
+        </view>
+        <view class="form-item">
+          <text class="label">鐧昏鏃堕棿</text>
+          <picker mode="date"
+                  :value="form.registrationDate || todayStr"
+                  @change="onRegistrationDateChange">
+            <view class="picker-value">{{ form.registrationDate || "璇烽�夋嫨鐧昏鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item">
+          <text class="label">浠诲姟棰戠巼</text>
+          <picker mode="selector"
+                  :range="frequencyOptions"
+                  range-key="label"
+                  :value="frequencyIndex"
+                  @change="onFrequencyChange">
+            <view class="picker-value">{{ currentFrequencyLabel || "璇烽�夋嫨浠诲姟棰戠巼" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'DAILY'">
+          <text class="label">鏃堕棿</text>
+          <picker mode="time"
+                  :value="form.frequencyDetail || '08:00'"
+                  @change="onDailyTimeChange">
+            <view class="picker-value">{{ form.frequencyDetail || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'WEEKLY'">
+          <text class="label">姣忓懆鏃ユ湡</text>
+          <picker mode="selector"
+                  :range="weekOptions"
+                  range-key="label"
+                  :value="weekIndex"
+                  @change="onWeekChange">
+            <view class="picker-value">{{ currentWeekLabel || "璇烽�夋嫨鏄熸湡" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'WEEKLY'">
+          <text class="label">姣忓懆鏃堕棿</text>
+          <picker mode="time"
+                  :value="form.time || '08:00'"
+                  @change="onWeekTimeChange">
+            <view class="picker-value">{{ form.time || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'MONTHLY'">
+          <text class="label">姣忔湀鏃ユ湡涓庢椂闂�</text>
+          <picker mode="date"
+                  fields="day"
+                  :value="monthlyDate"
+                  @change="onMonthlyDateChange">
+            <view class="picker-value">{{ monthlyDate || "璇烽�夋嫨鏃ユ湡" }}</view>
+          </picker>
+          <picker mode="time"
+                  :value="monthlyTime"
+                  @change="onMonthlyTimeChange">
+            <view class="picker-value">{{ monthlyTime || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'QUARTERLY'">
+          <text class="label">瀛e害鏃ユ湡涓庢椂闂�</text>
+          <picker mode="date"
+                  :value="quarterlyDate"
+                  @change="onQuarterlyDateChange">
+            <view class="picker-value">{{ quarterlyDate || "璇烽�夋嫨鏃ユ湡" }}</view>
+          </picker>
+          <picker mode="time"
+                  :value="quarterlyTime"
+                  @change="onQuarterlyTimeChange">
+            <view class="picker-value">{{ quarterlyTime || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item">
+          <text class="label">澶囨敞</text>
+          <u-textarea v-model="form.remarks"
+                      placeholder="璇疯緭鍏ュ娉�"
+                      :height="80"
+                      count />
+        </view>
+      </view>
+      <view class="popup-footer">
+        <u-button @click="cancel">鍙栨秷</u-button>
+        <u-button type="primary"
+                  @click="submitForm">淇濆瓨</u-button>
+      </view>
+    </view>
+  </u-popup>
+  <u-popup :show="showDevicePopup"
+           mode="bottom"
+           :round="16"
+           :zIndex="1100"
+           @close="closeDevicePopup">
+    <view class="inspector-popup">
+      <view class="inspector-header">
+        <text class="inspector-title">閫夋嫨璁惧</text>
+      </view>
+      <scroll-view scroll-y
+                   class="inspector-list">
+        <view v-for="item in deviceOptions"
+              :key="item.id"
+              class="inspector-row"
+              @click="toggleDevice(item.id)">
+          <text class="inspector-name">{{ item.deviceName }}</text>
+          <u-icon v-if="(form.deviceIds || []).includes(item.id)"
+                  name="checkmark-circle-fill"
+                  color="#1677ff"
+                  size="20" />
+          <u-icon v-else
+                  name=""
+                  color="#d5d8de"
+                  size="20" />
+        </view>
+      </scroll-view>
+      <view class="inspector-footer">
+        <u-button @click="closeDevicePopup">纭畾</u-button>
+      </view>
+    </view>
+  </u-popup>
+</template>
+
+<script setup>
+  import { computed, reactive, ref } from "vue";
+  import useUserStore from "@/store/modules/user";
+  import {
+    deviceMaintenanceTaskAdd,
+    deviceMaintenanceTaskEdit,
+  } from "@/api/equipmentManagement/upkeep.js";
+  import { userListNoPageByTenantId } from "@/api/system/user.js";
+  import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js";
+
+  const emit = defineEmits(["closeDia"]);
+  const userStore = useUserStore();
+  const dialogVisitable = ref(false);
+  const operationType = ref("add");
+  const deviceOptions = ref([]);
+  const userList = ref([]);
+  const showDevicePopup = ref(false);
+
+  const todayStr = ref("");
+  try {
+    const d = new Date();
+    todayStr.value = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
+  } catch (e) {}
+
+  const defaultForm = () => ({
+    id: undefined,
+    taskName: "",
+    deviceIds: [],
+    registrantId: undefined,
+    registrant: "",
+    registrationDate: "",
+    remarks: "",
+    frequencyType: "",
+    frequencyDetail: "",
+    week: "",
+    time: "",
+  });
+
+  const form = reactive(defaultForm());
+
+  const frequencyOptions = [
+    { label: "姣忔棩", value: "DAILY" },
+    { label: "姣忓懆", value: "WEEKLY" },
+    { label: "姣忔湀", value: "MONTHLY" },
+    { label: "瀛e害", value: "QUARTERLY" },
+  ];
+
+  const weekOptions = [
+    { label: "鍛ㄤ竴", value: "MON" },
+    { label: "鍛ㄤ簩", value: "TUE" },
+    { label: "鍛ㄤ笁", value: "WED" },
+    { label: "鍛ㄥ洓", value: "THU" },
+    { label: "鍛ㄤ簲", value: "FRI" },
+    { label: "鍛ㄥ叚", value: "SAT" },
+    { label: "鍛ㄦ棩", value: "SUN" },
+  ];
+
+  const monthlyDate = ref("");
+  const monthlyTime = ref("");
+  const quarterlyDate = ref("");
+  const quarterlyTime = ref("");
+
+  const frequencyIndex = computed(() => {
+    const index = frequencyOptions.findIndex(item => item.value === form.frequencyType);
+    return index >= 0 ? index : 0;
+  });
+
+  const weekIndex = computed(() => {
+    const index = weekOptions.findIndex(item => item.value === form.week);
+    return index >= 0 ? index : 0;
+  });
+
+  const currentFrequencyLabel = computed(() => {
+    return frequencyOptions.find(item => item.value === form.frequencyType)?.label || "";
+  });
+
+  const currentWeekLabel = computed(() => {
+    return weekOptions.find(item => item.value === form.week)?.label || "";
+  });
+
+  const inspectorIndex = computed(() => {
+    const index = userList.value.findIndex(item => String(item.userId) === String(form.registrantId));
+    return index >= 0 ? index : 0;
+  });
+
+  const deviceNamesText = computed(() => {
+    if (!form.deviceIds?.length) return "";
+    return form.deviceIds
+      .map(id => getDeviceName(id))
+      .filter(Boolean)
+      .join("銆�");
+  });
+
+  function getDeviceName(id) {
+    const d = deviceOptions.value.find(item => String(item.id) === String(id));
+    return d?.deviceName || "";
+  }
+
+  const resetForm = () => {
+    Object.assign(form, defaultForm());
+    monthlyDate.value = "";
+    monthlyTime.value = "";
+    quarterlyDate.value = "";
+    quarterlyTime.value = "";
+    showDevicePopup.value = false;
+  };
+
+  const normalizeIdList = val => {
+    if (!val) return [];
+    if (Array.isArray(val)) return val.map(v => (Number.isNaN(Number(v)) ? v : Number(v)));
+    if (typeof val === "string") {
+      const s = val.trim();
+      if (s.startsWith("[") && s.endsWith("]")) {
+        try {
+          const arr = JSON.parse(s);
+          return Array.isArray(arr) ? arr : [];
+        } catch {
+          return [];
+        }
+      }
+      return s.split(",").map(v => v.trim()).filter(Boolean).map(v => (Number.isNaN(Number(v)) ? v : Number(v)));
+    }
+    return [];
+  };
+
+  const parseWeeklyDetail = detail => {
+    if (!detail || typeof detail !== "string" || !detail.includes(",")) return;
+    const [week, time] = detail.split(",");
+    form.week = week || "";
+    form.time = time || "";
+  };
+
+  const parseMonthlyDetail = detail => {
+    if (!detail || typeof detail !== "string" || !detail.includes(",")) return;
+    const [day, time] = detail.split(",");
+    if (day) {
+      const y = new Date().getFullYear();
+      const m = new Date().getMonth() + 1;
+      monthlyDate.value = `${y}-${String(m).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
+    }
+    if (time) monthlyTime.value = time;
+  };
+
+  const parseQuarterlyDetail = detail => {
+    if (!detail || typeof detail !== "string") return;
+    const parts = detail.split(",");
+    if (parts.length >= 3) {
+      const [mm, dd, time] = parts;
+      const y = new Date().getFullYear();
+      quarterlyDate.value = `${y}-${String(mm).padStart(2, "0")}-${String(dd).padStart(2, "0")}`;
+      quarterlyTime.value = time || "";
+    }
+  };
+
+  const openDialog = async (type, row) => {
+    operationType.value = type;
+    dialogVisitable.value = true;
+    resetForm();
+    try {
+      const [userRes, deviceRes] = await Promise.all([
+        userListNoPageByTenantId(),
+        getDeviceLedger(),
+      ]);
+      userList.value = userRes?.data || [];
+      deviceOptions.value = deviceRes?.data || [];
+      if (type === "edit" && row) {
+        Object.assign(form, {
+          ...defaultForm(),
+          ...row,
+          deviceIds: normalizeIdList(row.deviceIds ?? row.taskIds ?? row.deviceIds),
+        });
+        if (!form.registrationDate && row.registrationDate) form.registrationDate = row.registrationDate;
+        if (row.registrantId) form.registrantId = row.registrantId;
+        if (row.registrant) form.registrant = row.registrant;
+        if (form.frequencyType === "WEEKLY") parseWeeklyDetail(form.frequencyDetail);
+        if (form.frequencyType === "MONTHLY") parseMonthlyDetail(form.frequencyDetail);
+        if (form.frequencyType === "QUARTERLY") parseQuarterlyDetail(form.frequencyDetail);
+      } else {
+        form.registrationDate = todayStr.value;
+        const userInfo = await userStore.getInfo();
+        if (userInfo?.user?.userId) {
+          form.registrantId = userInfo.user.userId;
+          form.registrant = userInfo.user.nickName || userInfo.user.userName || "";
+        }
+      }
+    } catch (error) {
+      uni.showToast({
+        title: "鍒濆鍖栧け璐�",
+        icon: "none",
+      });
+    }
+  };
+
+  const openDevicePopup = () => {
+    showDevicePopup.value = true;
+  };
+
+  const closeDevicePopup = () => {
+    showDevicePopup.value = false;
+  };
+
+  const toggleDevice = id => {
+    const ids = form.deviceIds || [];
+    if (ids.includes(id)) {
+      form.deviceIds = ids.filter(i => i !== id);
+    } else {
+      form.deviceIds = [...ids, id];
+    }
+  };
+
+  const onInspectorChange = e => {
+    const index = Number(e?.detail?.value ?? 0);
+    const user = userList.value[index];
+    if (user) {
+      form.registrantId = user.userId;
+      form.registrant = user.nickName || "";
+    }
+  };
+
+  const onRegistrationDateChange = e => {
+    form.registrationDate = e?.detail?.value || "";
+  };
+
+  const onFrequencyChange = e => {
+    const index = Number(e?.detail?.value ?? 0);
+    const selected = frequencyOptions[index];
+    form.frequencyType = selected?.value || "";
+    form.frequencyDetail = "";
+    form.week = "";
+    form.time = "";
+    monthlyDate.value = "";
+    monthlyTime.value = "";
+    quarterlyDate.value = "";
+    quarterlyTime.value = "";
+  };
+
+  const onDailyTimeChange = e => {
+    form.frequencyDetail = e?.detail?.value || "";
+  };
+
+  const onWeekChange = e => {
+    const index = Number(e?.detail?.value ?? 0);
+    const selected = weekOptions[index];
+    form.week = selected?.value || "";
+  };
+
+  const onWeekTimeChange = e => {
+    form.time = e?.detail?.value || "";
+  };
+
+  const onMonthlyDateChange = e => {
+    monthlyDate.value = e?.detail?.value || "";
+  };
+
+  const onMonthlyTimeChange = e => {
+    monthlyTime.value = e?.detail?.value || "";
+  };
+
+  const onQuarterlyDateChange = e => {
+    quarterlyDate.value = e?.detail?.value || "";
+  };
+
+  const onQuarterlyTimeChange = e => {
+    quarterlyTime.value = e?.detail?.value || "";
+  };
+
+  const validateForm = () => {
+    if (!form.taskName?.trim()) {
+      uni.showToast({ title: "璇疯緭鍏ヤ换鍔″悕绉�", icon: "none" });
+      return false;
+    }
+    if (!form.deviceIds?.length) {
+      uni.showToast({ title: "璇烽�夋嫨璁惧", icon: "none" });
+      return false;
+    }
+    if (!form.registrantId && !form.registrant) {
+      uni.showToast({ title: "璇烽�夋嫨褰曞叆浜�", icon: "none" });
+      return false;
+    }
+    if (!form.registrationDate) {
+      uni.showToast({ title: "璇烽�夋嫨鐧昏鏃堕棿", icon: "none" });
+      return false;
+    }
+    if (!form.frequencyType) {
+      uni.showToast({ title: "璇烽�夋嫨浠诲姟棰戠巼", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "DAILY" && !form.frequencyDetail) {
+      uni.showToast({ title: "璇烽�夋嫨鏃堕棿", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "WEEKLY" && (!form.week || !form.time)) {
+      uni.showToast({ title: "璇烽�夋嫨姣忓懆鏃ユ湡鍜屾椂闂�", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "MONTHLY" && (!monthlyDate.value || !monthlyTime.value)) {
+      uni.showToast({ title: "璇烽�夋嫨姣忔湀鏃ユ湡鍜屾椂闂�", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "QUARTERLY" && (!quarterlyDate.value || !quarterlyTime.value)) {
+      uni.showToast({ title: "璇烽�夋嫨瀛e害鏃ユ湡鍜屾椂闂�", icon: "none" });
+      return false;
+    }
+    return true;
+  };
+
+  const buildFrequencyDetail = () => {
+    if (form.frequencyType === "WEEKLY") return `${form.week},${form.time}`;
+    if (form.frequencyType === "MONTHLY") {
+      const day = monthlyDate.value.split("-")[2] || "";
+      return `${day},${monthlyTime.value}`;
+    }
+    if (form.frequencyType === "QUARTERLY") {
+      const [y, m, d] = (quarterlyDate.value || "").split("-");
+      return `${m},${d},${quarterlyTime.value}`;
+    }
+    return form.frequencyDetail || "";
+  };
+
+  const submitForm = async () => {
+    if (!validateForm()) return;
+    try {
+      const payload = {
+        id: form.id,
+        taskName: form.taskName.trim(),
+        deviceIds: JSON.stringify(form.deviceIds || []),
+        registrantId: form.registrantId,
+        registrant: form.registrant,
+        registrationDate: form.registrationDate,
+        frequencyType: form.frequencyType,
+        frequencyDetail: buildFrequencyDetail(),
+        remarks: form.remarks || "",
+        status: "0",
+        active: true,
+        deleted: 0,
+      };
+      if (operationType.value === "edit" && form.id) {
+        await deviceMaintenanceTaskEdit(payload);
+      } else {
+        delete payload.id;
+        await deviceMaintenanceTaskAdd(payload);
+      }
+      uni.showToast({
+        title: "鎻愪氦鎴愬姛",
+        icon: "success",
+      });
+      cancel();
+    } catch (error) {
+      uni.showToast({
+        title: "鎻愪氦澶辫触锛岃閲嶈瘯",
+        icon: "none",
+      });
+    }
+  };
+
+  const cancel = () => {
+    dialogVisitable.value = false;
+    resetForm();
+    emit("closeDia");
+  };
+
+  defineExpose({ openDialog });
+</script>
+
+<style scoped lang="scss">
+  :deep(.uni-picker-container) {
+    z-index: 1200 !important;
+  }
+
+  .popup-content {
+    width: 88vw;
+    max-height: 80vh;
+    background: #fff;
+    border-radius: 20rpx;
+    overflow: hidden;
+  }
+
+  .popup-title {
+    text-align: center;
+    font-size: 32rpx;
+    color: #1f1f1f;
+    font-weight: 600;
+    padding: 24rpx 20rpx;
+    border-bottom: 1rpx solid #f0f0f0;
+  }
+
+  .form-body {
+    padding: 24rpx;
+    max-height: 56vh;
+    overflow-y: auto;
+  }
+
+  .form-item {
+    margin-bottom: 20rpx;
+  }
+
+  .label {
+    display: block;
+    margin-bottom: 10rpx;
+    font-size: 24rpx;
+    color: #666;
+  }
+
+  .picker-value {
+    min-height: 72rpx;
+    background: #f7f8fa;
+    border-radius: 12rpx;
+    padding: 0 20rpx;
+    display: flex;
+    align-items: center;
+    color: #333;
+    font-size: 26rpx;
+  }
+
+  .inspector-picker {
+    justify-content: space-between;
+  }
+
+  .inspector-tags {
+    display: flex;
+    flex-wrap: wrap;
+    margin-top: 10rpx;
+    gap: 10rpx;
+  }
+
+  .inspector-tag {
+    display: flex;
+    align-items: center;
+    gap: 8rpx;
+    background: #edf3ff;
+    color: #1677ff;
+    font-size: 22rpx;
+    border-radius: 999rpx;
+    padding: 6rpx 14rpx;
+  }
+
+  .popup-footer {
+    display: flex;
+    gap: 16rpx;
+    padding: 20rpx 24rpx 24rpx;
+    border-top: 1rpx solid #f0f0f0;
+  }
+
+  .inspector-popup {
+    background: #fff;
+    border-radius: 24rpx 24rpx 0 0;
+    overflow: hidden;
+    max-height: 70vh;
+    padding-bottom: env(safe-area-inset-bottom);
+  }
+
+  .inspector-header {
+    padding: 24rpx;
+    text-align: center;
+    border-bottom: 1rpx solid #f0f0f0;
+  }
+
+  .inspector-title {
+    color: #1f1f1f;
+    font-size: 30rpx;
+    font-weight: 600;
+  }
+
+  .inspector-list {
+    max-height: 46vh;
+    padding: 0 24rpx;
+  }
+
+  .inspector-row {
+    min-height: 82rpx;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    border-bottom: 1rpx solid #f5f5f5;
+  }
+
+  .inspector-name {
+    font-size: 26rpx;
+    color: #333;
+  }
+
+  .inspector-footer {
+    display: flex;
+    gap: 16rpx;
+    padding: 20rpx 24rpx 24rpx;
+  }
+</style>

--
Gitblit v1.9.3