From d5048a33e4760d414115a5e25645d30b41d24198 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期六, 29 八月 2026 18:06:07 +0800
Subject: [PATCH] fix(wls): 修复多个组件中的类型安全和数据验证问题
---
src/views/mes/pro/feedback/modules/wait-countdown.vue | 137 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 137 insertions(+), 0 deletions(-)
diff --git a/src/views/mes/pro/feedback/modules/wait-countdown.vue b/src/views/mes/pro/feedback/modules/wait-countdown.vue
new file mode 100644
index 0000000..760b8de
--- /dev/null
+++ b/src/views/mes/pro/feedback/modules/wait-countdown.vue
@@ -0,0 +1,137 @@
+<script lang="ts" setup>
+import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
+
+import dayjs from 'dayjs';
+
+import { Button, message } from 'ant-design-vue';
+
+import { startWaitCountdown } from '#/api/mes/pro/task';
+
+defineOptions({ name: 'WaitCountdown' });
+
+interface Props {
+ taskId?: number;
+ /** 绛夊緟鏃堕暱锛堝皬鏃讹級锛�>0 鎵嶅睍绀哄�掕鏃� */
+ waitDuration?: number;
+ /** 鍊掕鏃跺紑濮嬫椂闂达紙yyyy-MM-dd HH:mm:ss锛� */
+ waitStartTime?: string;
+ /** 鍙妯″紡锛堣鎯�/瀹℃壒锛変笅涓嶅睍绀哄紑濮嬫寜閽� */
+ disabled?: boolean;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+ taskId: undefined,
+ waitDuration: undefined,
+ waitStartTime: undefined,
+ disabled: false,
+});
+
+const starting = ref(false);
+const startTime = ref<string | undefined>(props.waitStartTime);
+const now = ref(Date.now());
+let timer: ReturnType<typeof setInterval> | undefined;
+
+const showCountdown = computed(
+ () => !!props.waitDuration && props.waitDuration > 0,
+);
+
+const endTime = computed(() => {
+ if (!startTime.value || !showCountdown.value) {
+ return undefined;
+ }
+ return dayjs(startTime.value, 'YYYY-MM-DD HH:mm:ss').valueOf() +
+ props.waitDuration! * 3600 * 1000;
+});
+
+const remainingMs = computed(() => {
+ if (!endTime.value) {
+ return 0;
+ }
+ return Math.max(0, endTime.value - now.value);
+});
+
+const counting = computed(() => remainingMs.value > 0);
+
+const remainingText = computed(() => {
+ const totalSeconds = Math.ceil(remainingMs.value / 1000);
+ const hours = Math.floor(totalSeconds / 3600);
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
+ const seconds = totalSeconds % 60;
+ const pad = (n: number) => String(n).padStart(2, '0');
+ if (hours > 0) {
+ return `鍓╀綑 ${hours} 灏忔椂 ${pad(minutes)} 鍒� ${pad(seconds)} 绉抈;
+ }
+ return `鍓╀綑 ${pad(minutes)} 鍒� ${pad(seconds)} 绉抈;
+});
+
+function startTimer() {
+ if (timer) {
+ clearInterval(timer);
+ }
+ timer = setInterval(() => {
+ now.value = Date.now();
+ if (remainingMs.value <= 0) {
+ clearInterval(timer);
+ timer = undefined;
+ }
+ }, 1000);
+}
+
+watch(
+ () => props.waitStartTime,
+ (value) => {
+ startTime.value = value;
+ if (value) {
+ now.value = Date.now();
+ startTimer();
+ }
+ },
+);
+
+onMounted(() => {
+ if (startTime.value) {
+ startTimer();
+ }
+});
+
+onBeforeUnmount(() => {
+ if (timer) {
+ clearInterval(timer);
+ timer = undefined;
+ }
+});
+
+async function handleStart() {
+ if (!props.taskId) {
+ message.warning('璇峰厛閫夋嫨浠诲姟');
+ return;
+ }
+ starting.value = true;
+ try {
+ const time = await startWaitCountdown(props.taskId);
+ startTime.value = time;
+ now.value = Date.now();
+ startTimer();
+ message.success('鍊掕鏃跺凡寮�濮�');
+ } finally {
+ starting.value = false;
+ }
+}
+</script>
+
+<template>
+ <div v-if="showCountdown" class="flex items-center gap-2">
+ <Button
+ v-if="!startTime && !disabled"
+ type="primary"
+ :loading="starting"
+ @click="handleStart"
+ >
+ 寮�濮嬪�掕鏃�
+ </Button>
+ <span v-if="startTime" class="text-sm">
+ <span v-if="counting" class="text-orange-500">{{ remainingText }}</span>
+ <span v-else class="text-green-600">鍊掕鏃跺凡缁撴潫锛屽彲鎶ュ伐</span>
+ </span>
+ </div>
+</template>
--
Gitblit v1.9.3