From 7235cbde16ad4ac19f19d9a9a96e12d71a23ebce Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期六, 16 五月 2026 13:42:00 +0800
Subject: [PATCH] 优化报修表单,新增验收人字段,调整状态管理,提升报修详情展示效果。
---
src/pages/equipmentManagement/repair/detail.vue | 362 ++++++++++++++++++++++++++++++++
src/pages/equipmentManagement/repair/acceptance.vue | 259 +++++++++++++++++++++++
2 files changed, 621 insertions(+), 0 deletions(-)
diff --git a/src/pages/equipmentManagement/repair/acceptance.vue b/src/pages/equipmentManagement/repair/acceptance.vue
new file mode 100644
index 0000000..0c24129
--- /dev/null
+++ b/src/pages/equipmentManagement/repair/acceptance.vue
@@ -0,0 +1,259 @@
+<template>
+ <view class="repair-acceptance">
+ <PageHeader title="璁惧鎶ヤ慨楠屾敹"
+ @back="goBack" />
+ <view class="section"
+ v-if="detail">
+ <view class="section-title">鎶ヤ慨淇℃伅</view>
+ <view class="info-item">
+ <text class="info-label">璁惧鍚嶇О</text>
+ <text class="info-value">{{ detail.deviceName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">楠屾敹浜�</text>
+ <text class="info-value">{{ detail.acceptanceName || '-' }}</text>
+ </view>
+ </view>
+ <u-form ref="formRef"
+ :model="form"
+ label-width="110">
+ <u-cell-group title="楠屾敹淇℃伅">
+ <u-form-item label="楠屾敹浜�"
+ border-bottom>
+ <u-input v-model="form.acceptanceName"
+ disabled
+ placeholder="楠屾敹浜�" />
+ </u-form-item>
+ <u-form-item label="楠屾敹鏃堕棿"
+ required
+ border-bottom>
+ <u-input v-model="form.acceptanceTime"
+ placeholder="璇烽�夋嫨楠屾敹鏃堕棿"
+ readonly
+ @click="showDatePicker = true" />
+ <template #right>
+ <u-icon name="arrow-right"
+ @click="showDatePicker = true" />
+ </template>
+ </u-form-item>
+ <u-form-item label="楠屾敹澶囨敞"
+ required
+ border-bottom>
+ <u-textarea v-model="form.acceptanceRemark"
+ placeholder="璇疯緭鍏ラ獙鏀跺娉�"
+ :maxlength="200"
+ count
+ :autoHeight="true" />
+ </u-form-item>
+ </u-cell-group>
+ <view class="footer-btns">
+ <u-button class="cancel-btn"
+ @click="goBack">鍙栨秷</u-button>
+ <u-button class="save-btn"
+ type="primary"
+ :loading="loading"
+ @click="submitAcceptance">纭楠屾敹</u-button>
+ </view>
+ </u-form>
+ <up-datetime-picker :show="showDatePicker"
+ v-model="pickerDateValue"
+ mode="datetime"
+ @confirm="onDateConfirm"
+ @cancel="showDatePicker = false" />
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted } from "vue";
+ import { onLoad } from "@dcloudio/uni-app";
+ import PageHeader from "@/components/PageHeader.vue";
+ import useUserStore from "@/store/modules/user";
+ import { getRepairById, acceptRepair } from "@/api/equipmentManagement/repair";
+ import dayjs from "dayjs";
+
+ defineOptions({ name: "璁惧鎶ヤ慨楠屾敹" });
+
+ const userStore = useUserStore();
+ const repairId = ref("");
+ const detail = ref(null);
+ const loading = ref(false);
+ const showDatePicker = ref(false);
+ const pickerDateValue = ref(Date.now());
+
+ const form = ref({
+ id: "",
+ acceptanceName: "",
+ acceptanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ acceptanceRemark: "",
+ });
+
+ const showToast = message => {
+ uni.showToast({ title: message, icon: "none" });
+ };
+
+ const getCurrentUserName = () =>
+ (userStore.nickName || userStore.name || "").trim();
+
+ const canAccept = acceptanceName => {
+ const current = getCurrentUserName();
+ const target = (acceptanceName || "").trim();
+ return current && target && current === target;
+ };
+
+ const loadDetail = async () => {
+ if (!repairId.value) {
+ showToast("鍙傛暟閿欒");
+ return;
+ }
+ try {
+ uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+ const { code, data } = await getRepairById(repairId.value);
+ if (code !== 200) {
+ showToast("鑾峰彇璇︽儏澶辫触");
+ return;
+ }
+ detail.value = data;
+ if (Number(data.status) !== 3) {
+ showToast("褰撳墠鐘舵�佷笉鍙獙鏀�");
+ setTimeout(() => goBack(), 1500);
+ return;
+ }
+ if (!canAccept(data.acceptanceName)) {
+ showToast("浠呮寚瀹氶獙鏀朵汉鍙繘琛岄獙鏀�");
+ setTimeout(() => goBack(), 1500);
+ return;
+ }
+ form.value.id = data.id;
+ form.value.acceptanceName = data.acceptanceName || "";
+ form.value.acceptanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
+ } catch (e) {
+ showToast("鑾峰彇璇︽儏澶辫触");
+ } finally {
+ uni.hideLoading();
+ }
+ };
+
+ const onDateConfirm = e => {
+ form.value.acceptanceTime = dayjs(e.value).format("YYYY-MM-DD HH:mm:ss");
+ pickerDateValue.value = e.value;
+ showDatePicker.value = false;
+ };
+
+ const submitAcceptance = async () => {
+ if (!form.value.acceptanceTime?.trim()) {
+ showToast("璇烽�夋嫨楠屾敹鏃堕棿");
+ return;
+ }
+ if (!form.value.acceptanceRemark?.trim()) {
+ showToast("璇疯緭鍏ラ獙鏀跺娉�");
+ return;
+ }
+ try {
+ loading.value = true;
+ const { code, msg } = await acceptRepair({
+ id: form.value.id,
+ acceptanceTime: form.value.acceptanceTime,
+ acceptanceRemark: form.value.acceptanceRemark.trim(),
+ });
+ if (code === 200) {
+ showToast("楠屾敹鎴愬姛");
+ setTimeout(() => goBack(), 1500);
+ } else {
+ showToast(msg || "楠屾敹澶辫触");
+ loading.value = false;
+ }
+ } catch (e) {
+ loading.value = false;
+ showToast("楠屾敹澶辫触");
+ }
+ };
+
+ const goBack = () => {
+ uni.removeStorageSync("repairId");
+ uni.navigateBack();
+ };
+
+ onLoad(options => {
+ repairId.value = options?.id || uni.getStorageSync("repairId") || "";
+ form.value.id = repairId.value;
+ });
+
+ onMounted(() => {
+ loadDetail();
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "@/static/scss/form-common.scss";
+
+ .repair-acceptance {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 5rem;
+ }
+
+ .section {
+ margin: 12px 16px;
+ background: #fff;
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+ }
+
+ .section-title {
+ padding: 14px 16px;
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .info-item {
+ display: flex;
+ padding: 12px 16px;
+ border-bottom: 1px solid #f8f8f8;
+ }
+
+ .info-label {
+ width: 90px;
+ font-size: 14px;
+ color: #606266;
+ }
+
+ .info-value {
+ flex: 1;
+ font-size: 14px;
+ color: #303133;
+ text-align: right;
+ }
+
+ .footer-btns {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: #fff;
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ padding: 0.75rem 0;
+ box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05);
+ z-index: 1000;
+ }
+
+ .cancel-btn {
+ font-size: 1rem;
+ color: #ffffff;
+ width: 6.375rem;
+ background: #c7c9cc;
+ border-radius: 2.5rem;
+ }
+
+ .save-btn {
+ font-size: 1rem;
+ color: #ffffff;
+ width: 14rem;
+ background: linear-gradient(140deg, #00baff 0%, #006cfb 100%);
+ border-radius: 2.5rem;
+ }
+</style>
diff --git a/src/pages/equipmentManagement/repair/detail.vue b/src/pages/equipmentManagement/repair/detail.vue
new file mode 100644
index 0000000..8e62232
--- /dev/null
+++ b/src/pages/equipmentManagement/repair/detail.vue
@@ -0,0 +1,362 @@
+<template>
+ <view class="repair-detail">
+ <PageHeader title="璁惧鎶ヤ慨璇︽儏"
+ @back="goBack" />
+ <view v-if="detail"
+ class="detail-content">
+ <!-- 1. 鎶ヤ慨鐧昏 -->
+ <view class="section">
+ <view class="section-title">
+ <text class="section-num">1</text>
+ <text>鎶ヤ慨鐧昏</text>
+ </view>
+ <view class="info-grid">
+ <view class="info-item">
+ <text class="info-label">璁惧鍚嶇О</text>
+ <text class="info-value">{{ detail.deviceName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">瑙勬牸鍨嬪彿</text>
+ <text class="info-value">{{ detail.deviceModel || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鎶ヤ慨鏃ユ湡</text>
+ <text class="info-value">{{ formatDate(detail.repairTime) || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鎶ヤ慨浜�</text>
+ <text class="info-value">{{ detail.repairName || detail.maintenanceName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">楠屾敹浜�</text>
+ <text class="info-value">{{ detail.acceptanceName || '-' }}</text>
+ </view>
+ <view class="info-item"
+ v-if="Number(detail.status) !== 0">
+ <text class="info-label">缁翠慨浜�</text>
+ <text class="info-value">{{ detail.maintenancePerson || detail.maintenanceName || '-' }}</text>
+ </view>
+ <view class="info-item full">
+ <text class="info-label">鏁呴殰鐜拌薄</text>
+ <text class="info-value">{{ detail.remark || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">褰撳墠鐘舵��</text>
+ <view class="info-value">
+ <u-tag :type="getStatusTagType(detail.status)"
+ size="small">{{ getStatusText(detail.status) }}</u-tag>
+ </view>
+ </view>
+ </view>
+ <view class="image-section">
+ <text class="image-title">璁惧闂鍥剧墖</text>
+ <view v-if="repairImageList.length"
+ class="image-list">
+ <image v-for="(file, index) in repairImageList"
+ :key="file.id || index"
+ :src="getFileAccessUrl(file)"
+ mode="aspectFill"
+ class="repair-image"
+ @click="previewImage(index)" />
+ </view>
+ <view v-else
+ class="no-image">
+ <up-icon name="photo"
+ size="40"
+ color="#c0c4cc" />
+ <text>鏆傛棤璁惧闂鍥剧墖</text>
+ </view>
+ </view>
+ </view>
+ <!-- 2. 缁翠慨澶勭悊 -->
+ <view class="section"
+ v-if="showMaintenanceSection">
+ <view class="section-title">
+ <text class="section-num">2</text>
+ <text>缁翠慨澶勭悊</text>
+ </view>
+ <view class="info-grid">
+ <view class="info-item">
+ <text class="info-label">缁翠慨浜�</text>
+ <text class="info-value">{{ detail.maintenancePerson || detail.maintenanceName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">缁翠慨鏃堕棿</text>
+ <text class="info-value">{{ formatDateTime(detail.maintenanceTime) || '-' }}</text>
+ </view>
+ <view class="info-item full">
+ <text class="info-label">缁翠慨缁撴灉</text>
+ <text class="info-value">{{ detail.maintenanceResult || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ <!-- 3. 楠屾敹 -->
+ <view class="section"
+ v-if="showAcceptanceSection">
+ <view class="section-title">
+ <text class="section-num">3</text>
+ <text>楠屾敹</text>
+ </view>
+ <view class="info-grid">
+ <view class="info-item">
+ <text class="info-label">楠屾敹浜�</text>
+ <text class="info-value">{{ detail.acceptanceName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">楠屾敹鏃堕棿</text>
+ <text class="info-value">{{ formatDateTime(detail.acceptanceTime) || '-' }}</text>
+ </view>
+ <view class="info-item full">
+ <text class="info-label">楠屾敹澶囨敞</text>
+ <text class="info-value">{{ detail.acceptanceRemark || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ </view>
+ <view v-else
+ class="loading-wrap">
+ <text>鍔犺浇涓�...</text>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, computed, onMounted } from "vue";
+ import { onLoad } from "@dcloudio/uni-app";
+ import PageHeader from "@/components/PageHeader.vue";
+ import config from "@/config";
+ import {
+ getRepairById,
+ getRepairFileList,
+ } from "@/api/equipmentManagement/repair";
+ import dayjs from "dayjs";
+
+ defineOptions({ name: "璁惧鎶ヤ慨璇︽儏" });
+
+ const repairId = ref("");
+ const detail = ref(null);
+ const repairImageList = ref([]);
+
+ const STATUS_MAP = {
+ 0: "寰呯淮淇�",
+ 3: "寰呴獙鏀�",
+ 1: "瀹屾垚",
+ 2: "缁翠慨澶辫触",
+ };
+
+ const getStatusText = status => STATUS_MAP[Number(status)] || "-";
+
+ const getStatusTagType = status => {
+ const map = { 0: "error", 3: "warning", 1: "success", 2: "error" };
+ return map[Number(status)] || "info";
+ };
+
+ const showMaintenanceSection = computed(() => Number(detail.value?.status) !== 0);
+
+ const showAcceptanceSection = computed(() => Number(detail.value?.status) === 1);
+
+ const formatDate = dateStr => {
+ if (!dateStr) return "";
+ return dayjs(dateStr).format("YYYY-MM-DD");
+ };
+
+ const formatDateTime = dateStr => {
+ if (!dateStr) return "";
+ return dayjs(dateStr).format("YYYY-MM-DD HH:mm:ss");
+ };
+
+ const normalizeFileUrl = (rawUrl = "") => {
+ let fileUrl = rawUrl || "";
+ const javaApi = config.baseUrl;
+ const localPrefixes = ["wxfile://", "file://", "content://", "blob:", "data:"];
+
+ if (localPrefixes.some(prefix => fileUrl.startsWith(prefix))) {
+ return fileUrl;
+ }
+
+ if (fileUrl && fileUrl.indexOf("\\") > -1) {
+ const lowerPath = fileUrl.toLowerCase();
+ const uploadPathIndex = lowerPath.indexOf("uploadpath");
+ if (uploadPathIndex > -1) {
+ fileUrl = fileUrl.substring(uploadPathIndex).replace(/\\/g, "/");
+ } else {
+ fileUrl = fileUrl.replace(/\\/g, "/");
+ }
+ }
+ fileUrl = fileUrl.replace(/^\/?uploadPath/, "/profile");
+
+ if (fileUrl && !fileUrl.startsWith("http")) {
+ if (!fileUrl.startsWith("/")) fileUrl = "/" + fileUrl;
+ fileUrl = javaApi + fileUrl;
+ }
+ return fileUrl;
+ };
+
+ const getFileAccessUrl = (file = {}) => {
+ if (file?.link) {
+ if (String(file.link).startsWith("http")) return file.link;
+ return normalizeFileUrl(file.link);
+ }
+ return normalizeFileUrl(file?.url || "");
+ };
+
+ const previewImage = index => {
+ const urls = repairImageList.value
+ .map(item => getFileAccessUrl(item))
+ .filter(Boolean);
+ if (!urls.length) return;
+ uni.previewImage({ urls, current: urls[index] || urls[0] });
+ };
+
+ const loadDetail = async () => {
+ if (!repairId.value) return;
+ try {
+ uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+ const { code, data } = await getRepairById(repairId.value);
+ if (code === 200) {
+ detail.value = data;
+ } else {
+ uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "none" });
+ }
+ const fileRes = await getRepairFileList(repairId.value);
+ if (fileRes?.code === 200) {
+ repairImageList.value = Array.isArray(fileRes.data) ? fileRes.data : [];
+ }
+ } catch (e) {
+ uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "none" });
+ } finally {
+ uni.hideLoading();
+ }
+ };
+
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ onLoad(options => {
+ repairId.value = options?.id || uni.getStorageSync("repairId") || "";
+ });
+
+ onMounted(() => {
+ loadDetail();
+ });
+</script>
+
+<style scoped lang="scss">
+ .repair-detail {
+ min-height: 100vh;
+ background: #f5f6f8;
+ padding-bottom: 24px;
+ }
+
+ .detail-content {
+ padding: 12px 16px;
+ }
+
+ .section {
+ background: #fff;
+ border-radius: 12px;
+ margin-bottom: 16px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+ }
+
+ .section-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 14px 16px;
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .section-num {
+ width: 22px;
+ height: 22px;
+ line-height: 22px;
+ text-align: center;
+ border-radius: 50%;
+ background: #2c7be5;
+ color: #fff;
+ font-size: 12px;
+ font-weight: 600;
+ }
+
+ .info-grid {
+ padding: 8px 16px 12px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .info-item {
+ width: 50%;
+ padding: 10px 8px 10px 0;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+
+ &.full {
+ width: 100%;
+ }
+ }
+
+ .info-label {
+ font-size: 13px;
+ color: #909399;
+ }
+
+ .info-value {
+ font-size: 14px;
+ color: #303133;
+ word-break: break-all;
+ }
+
+ .image-section {
+ padding: 0 16px 16px;
+ border-top: 1px solid #f5f5f5;
+ margin-top: 4px;
+ padding-top: 12px;
+ }
+
+ .image-title {
+ font-size: 13px;
+ color: #909399;
+ display: block;
+ margin-bottom: 10px;
+ }
+
+ .image-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ }
+
+ .repair-image {
+ width: 80px;
+ height: 80px;
+ border-radius: 6px;
+ background: #f5f5f5;
+ }
+
+ .no-image {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ color: #c0c4cc;
+ font-size: 13px;
+ gap: 8px;
+ background: #fafafa;
+ border-radius: 8px;
+ }
+
+ .loading-wrap {
+ padding: 40px;
+ text-align: center;
+ color: #909399;
+ }
+</style>
--
Gitblit v1.9.3