From 166ff56efefe6682a9d840fe0f1fa6e456833556 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期五, 04 九月 2026 18:34:23 +0800
Subject: [PATCH] fix: 时效模块原型
---
src/pages/timely/index.vue | 1008 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 928 insertions(+), 80 deletions(-)
diff --git a/src/pages/timely/index.vue b/src/pages/timely/index.vue
index ab55d7b..3063f91 100644
--- a/src/pages/timely/index.vue
+++ b/src/pages/timely/index.vue
@@ -1,108 +1,956 @@
<template>
- <view class="list_box">
- <z-paging ref="pagingRef" v-model="cardList" :fixed="false" :auto-show-back-to-top="true">
+ <view class="timely-page">
+ <z-paging
+ ref="pagingRef"
+ v-model="taskList"
+ :fixed="false"
+ :auto-show-back-to-top="true"
+ @query="queryTaskList"
+ >
<template #top>
- <CardTitle title="鏃舵晥鎶ュ伐" :hideAction="false">
- <template #action>
- <wd-button type="icon" icon="scan" color="#0D867F" @click="openScan"></wd-button>
- </template>
- </CardTitle>
- </template>
- <MonofilCard v-for="(item, index) in cardList" :key="index" :data="item" />
- <template #bottom>
- <view class="flex justify-center items-center">
- <wd-button block @click="save">
- <text class="text-[#fff]">淇濆瓨</text>
- </wd-button>
+ <view class="page-top">
+ <CardTitle title="鏃舵晥浠诲姟鍙拌处" :hideAction="false">
+ <template #action>
+ <wd-tag type="warning" size="small">Mock</wd-tag>
+ <wd-button size="small" icon="add" @click="openCreatePopup">鏂板浠诲姟</wd-button>
+ </template>
+ </CardTitle>
+
+ <view class="date-filter-card">
+ <view class="date-filter-heading">
+ <view class="date-filter-title">
+ <view class="date-filter-icon">
+ <wd-icon name="calendar" size="18px" color="#078568" />
+ </view>
+ <view>
+ <view class="date-filter-name">閫夋嫨鏃ユ湡</view>
+ <view class="date-filter-tip">鎸変换鍔″彂璧锋棩鏈熸煡璇�</view>
+ </view>
+ </view>
+ <text v-if="hasDateFilter" class="date-filter-clear" @click="resetFilters">娓呴櫎</text>
+ </view>
+ <view class="date-filter-fields">
+ <view class="date-filter-field">
+ <wd-datetime-picker v-model="filters.startTimestamp" type="date">
+ <view class="date-picker-trigger">
+ <text class="date-picker-label">寮�濮嬫棩鏈�</text>
+ <view class="date-picker-value">
+ <text :class="{ 'is-placeholder': !filters.startTimestamp }">
+ {{
+ filters.startTimestamp
+ ? formatDateOnly(Number(filters.startTimestamp))
+ : "璇烽�夋嫨"
+ }}
+ </text>
+ <wd-icon name="arrow-right" size="13px" color="#aebbb7" />
+ </view>
+ </view>
+ </wd-datetime-picker>
+ </view>
+ <view class="date-filter-separator">鑷�</view>
+ <view class="date-filter-field">
+ <wd-datetime-picker v-model="filters.endTimestamp" type="date">
+ <view class="date-picker-trigger">
+ <text class="date-picker-label">缁撴潫鏃ユ湡</text>
+ <view class="date-picker-value">
+ <text :class="{ 'is-placeholder': !filters.endTimestamp }">
+ {{
+ filters.endTimestamp
+ ? formatDateOnly(Number(filters.endTimestamp))
+ : "璇烽�夋嫨"
+ }}
+ </text>
+ <wd-icon name="arrow-right" size="13px" color="#aebbb7" />
+ </view>
+ </view>
+ </wd-datetime-picker>
+ </view>
+ </view>
+ <view class="date-filter-actions">
+ <wd-button size="small" type="info" plain @click="resetFilters">閲嶇疆</wd-button>
+ <wd-button size="small" icon="search" @click="applyFilters">鏌ヨ浠诲姟</wd-button>
+ </view>
+ </view>
</view>
</template>
+
+ <view class="task-list">
+ <wd-card v-for="task in taskList" :key="task.id" custom-class="task-card">
+ <template #title>
+ <view class="card-title" @click="openDetail(task)">
+ <view class="title-main">
+ <text class="task-code">{{ task.taskCode || `浠诲姟-${task.id}` }}</text>
+ <wd-tag
+ size="small"
+ :type="
+ normalizeMaterialType(task.materialType) === '鍗曚笣' ? 'primary' : 'success'
+ "
+ >
+ {{ normalizeMaterialType(task.materialType) }}
+ </wd-tag>
+ </view>
+ <wd-tag size="small" :type="getStatusType(task)">
+ {{ getStatusLabel(task) }}
+ </wd-tag>
+ </view>
+ </template>
+
+ <view @click="openDetail(task)">
+ <view class="info-grid">
+ <view class="info-item">
+ <text class="info-label">鍙戣捣浠诲姟浜�</text>
+ <text>{{ getInitiator(task) }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">宸℃鍛�</text>
+ <text>{{ getInspector(task) }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">璁惧畾娓╁害</text>
+ <text>{{ getTemperature(task) }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鏃舵晥鏃堕暱</text>
+ <text>{{ getDuration(task) }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">璁惧畾鏈哄彴</text>
+ <text>{{ task.machineName || task.machine || "-" }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鏃舵晥浠舵暟</text>
+ <text>{{ task.itemCount ?? task.count ?? task.detailCount ?? 0 }} 浠�</text>
+ </view>
+ </view>
+ <view class="time-row">
+ <text class="info-label">鍙戣捣鏃堕棿</text>
+ <text>{{ task.initiateTime || task.startTime || task.createTime || "-" }}</text>
+ </view>
+ <view v-if="task.furnaceInTime || task.inTime" class="time-row">
+ <text class="info-label">杩涚倝鏃堕棿</text>
+ <text>{{ task.furnaceInTime || task.inTime }}</text>
+ </view>
+ <view v-if="task.furnaceOutTime || task.outTime" class="time-row">
+ <text class="info-label">鍑虹倝鏃堕棿</text>
+ <text>{{ task.furnaceOutTime || task.outTime }}</text>
+ </view>
+ </view>
+
+ <template #footer>
+ <view class="task-actions">
+ <wd-button size="small" plain @click="openDetail(task)">鏄庣粏</wd-button>
+ <wd-button
+ v-if="isWaiting(task)"
+ size="small"
+ plain
+ type="warning"
+ @click="openEditPopup(task)"
+ >
+ 缂栬緫
+ </wd-button>
+ <wd-button v-if="isWaiting(task)" size="small" plain @click="startTask(task)">
+ 寮�濮嬫椂鏁�
+ </wd-button>
+ <wd-button
+ v-if="isWaiting(task)"
+ size="small"
+ plain
+ type="error"
+ @click="deleteTask(task)"
+ >
+ 鍒犻櫎
+ </wd-button>
+ <wd-button
+ v-if="isRunning(task)"
+ size="small"
+ plain
+ type="error"
+ @click="endTask(task)"
+ >
+ 缁撴潫鏃舵晥
+ </wd-button>
+ <wd-button
+ v-if="!isWaiting(task)"
+ size="small"
+ plain
+ type="success"
+ @click="openInspection(task)"
+ >
+ 宸℃璁板綍
+ </wd-button>
+ </view>
+ </template>
+ </wd-card>
+ </view>
</z-paging>
- <Scan ref="scanRef" emitName="scanTime" />
+
+ <wd-popup
+ v-model="taskPopupVisible"
+ position="bottom"
+ :z-index="30"
+ :close-on-click-modal="false"
+ custom-style="height: 88vh; border-radius: 24rpx 24rpx 0 0;"
+ >
+ <view class="popup-layout">
+ <view class="popup-header">
+ <text class="popup-title">{{ editingTaskId ? "缂栬緫鏃舵晥浠诲姟" : "鏂板鏃舵晥浠诲姟" }}</text>
+ <wd-icon name="close" size="20px" @click="taskPopupVisible = false" />
+ </view>
+ <scroll-view class="popup-body" scroll-y>
+ <wd-form ref="taskFormRef" :model="taskForm">
+ <wd-cell-group border>
+ <wd-picker
+ v-model="taskForm.materialType"
+ :columns="materialTypeOptions"
+ label="浠诲姟绫诲瀷"
+ required
+ :z-index="40"
+ />
+ <wd-picker
+ v-model="taskForm.initiatorName"
+ :columns="userOptions"
+ label="鍙戣捣浠诲姟浜�"
+ placeholder="璇烽�夋嫨"
+ required
+ :loading="optionsLoading"
+ :z-index="40"
+ />
+ <wd-datetime-picker
+ v-model="taskForm.initiateTimestamp"
+ label="鍙戣捣鏃堕棿"
+ type="datetime"
+ required
+ use-second
+ :z-index="40"
+ />
+ <wd-picker
+ v-model="taskForm.inspectorName"
+ :columns="userOptions"
+ label="宸℃鍛�"
+ placeholder="璇烽�夋嫨"
+ required
+ :loading="optionsLoading"
+ :z-index="40"
+ />
+ <wd-input
+ v-model="taskForm.setTemperature"
+ label="璁惧畾娓╁害(鈩�)"
+ type="digit"
+ required
+ placeholder="璇疯緭鍏�"
+ />
+ <wd-cell title="鏃舵晥鏃堕暱(灏忔椂)" required />
+ <view class="duration-row">
+ <wd-input
+ v-model="taskForm.durationRise"
+ type="digit"
+ placeholder="鍗囨俯"
+ no-border
+ />
+ <text>+</text>
+ <wd-input
+ v-model="taskForm.durationHold"
+ type="digit"
+ placeholder="淇濇俯"
+ no-border
+ />
+ <text>+</text>
+ <wd-input
+ v-model="taskForm.durationSoak"
+ type="digit"
+ placeholder="鐒栫倝"
+ no-border
+ />
+ </view>
+ <wd-picker
+ v-model="taskForm.machineName"
+ :columns="machineOptions"
+ label="璁惧畾鏈哄彴"
+ placeholder="璇烽�夋嫨鏃舵晥鏈哄彴"
+ required
+ :loading="optionsLoading"
+ :z-index="40"
+ />
+ </wd-cell-group>
+ </wd-form>
+ </scroll-view>
+ <view class="popup-footer">
+ <wd-button type="info" plain @click="taskPopupVisible = false">鍙栨秷</wd-button>
+ <wd-button :loading="taskSubmitting" @click="submitTask">
+ {{ editingTaskId ? "淇濆瓨淇敼" : "纭畾鏂板" }}
+ </wd-button>
+ </view>
+ </view>
+ </wd-popup>
+
<wd-toast />
</view>
</template>
<script setup lang="ts">
+import { onShow } from "@dcloudio/uni-app";
+import { useToast } from "wot-design-uni";
+import type { TagType } from "wot-design-uni/components/wd-tag/types";
import CardTitle from "@/components/card-title/index.vue";
import zPaging from "@/components/z-paging/z-paging.vue";
-import Scan from "@/components/scan/index.vue";
-import MonofilCard from "../production/twist/components/MonofilCard.vue";
-import TwistApi from "@/api/product/twist";
-import { useToast } from "wot-design-uni";
+import TimeSensitiveTaskApi, {
+ type TimelinessMaterialType,
+ type TimeSensitiveTaskForm,
+} from "@/api/timeSensitiveTask";
+import { useUserStore } from "@/store/modules/user";
-const pagingRef = ref();
-const scanRef = ref();
const toast = useToast();
-const cardList = ref<any>([]);
+const userStore = useUserStore();
+const pagingRef = ref();
+const taskFormRef = ref();
+const taskList = ref<any[]>([]);
+const taskPopupVisible = ref(false);
+const taskSubmitting = ref(false);
+const optionsLoading = ref(false);
+const editingTaskId = ref<number | string | undefined>();
+const pageReady = ref(false);
-const getScanCode = async (code: any) => {
- console.log("鏃舵晥鎵爜鍥炶皟:", code);
- console.log("json:", JSON.parse(code.code));
- console.log("id:=============", JSON.parse(code.code).id);
- const { data } = await TwistApi.getScarn({
- outPutId: JSON.parse(code.code).id,
- });
- console.log("=======璇锋眰========", data);
- const exists = cardList.value.some(
- (item: any) => item.monofilamentNumber === data.monofilamentNumber
- );
- if (!exists) {
- const { id, outPutId, wireId, oneLength, ...rest } = data;
- console.log("sb", {
- outputId: id,
- amount: oneLength,
- ongLength: oneLength,
- ...rest,
- });
- cardList.value.push({
- outputId: id,
- amount: oneLength,
- ongLength: oneLength,
- ...rest,
- });
- pagingRef.value.complete(cardList.value);
- } else {
- toast.error("璇ュ崟涓濆凡棰嗙敤锛岃鍕块噸澶嶆壂鐮�");
- }
-};
-const save = async () => {
- const { code } = await TwistApi.saveAge(cardList.value);
- if (code == 200) {
- toast.success("淇濆瓨鎴愬姛");
- pagingRef.value.refresh();
- } else {
- toast.error("淇濆瓨澶辫触");
- }
-};
+const materialTypeOptions = [
+ { label: "鍗曚笣", value: "鍗曚笣" },
+ { label: "缁炵嚎", value: "缁炵嚎" },
+];
-const openScan = () => {
- scanRef.value.triggerScan();
-};
+const statusOptions = [
+ { label: "寰呭紑濮�", value: 0 },
+ { label: "鏃舵晥涓�", value: 1 },
+ { label: "鏃舵晥缁撴潫", value: 2 },
+];
-// 纭繚鍏堢Щ闄ゅ啀娣诲姞鐩戝惉
-const setupScanListener = () => {
- uni.$off("scanTime", getScanCode); // 鍏堢Щ闄ゆ棫鐨�
- uni.$on("scanTime", getScanCode); // 鍐嶆坊鍔犳柊鐨�
-};
+const filters = reactive({
+ startTimestamp: "" as "" | number,
+ endTimestamp: "" as "" | number,
+});
+const hasDateFilter = computed(() => Boolean(filters.startTimestamp || filters.endTimestamp));
-onMounted(() => {
- setupScanListener();
- console.log("椤甸潰鏄剧ず - 鎵爜鐩戝惉宸茶缃�");
+const taskForm = reactive({
+ materialType: "鍗曚笣" as TimelinessMaterialType,
+ initiatorName: "",
+ initiateTimestamp: Date.now() as number,
+ setTemperature: "" as string | number,
+ durationRise: 2 as string | number,
+ durationHold: "" as string | number,
+ durationSoak: "" as string | number,
+ machineName: "",
+ inspectorName: "",
});
-onUnmounted(() => {
- // 寮�鍚箍鎾洃鍚簨浠�
- uni.$off("scanTime", getScanCode);
- console.log("椤甸潰鍗歌浇 - 鎵爜鐩戝惉宸茬Щ闄�");
+const userOptions = ref<Array<{ label: string; value: string }>>([]);
+const machineOptions = ref<Array<{ label: string; value: string }>>([]);
+
+function pad(value: number) {
+ return String(value).padStart(2, "0");
+}
+
+function formatDateTime(value: number | Date) {
+ const date = value instanceof Date ? value : new Date(value);
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(
+ date.getHours()
+ )}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
+}
+
+function formatDate(value: number, endOfDay = false) {
+ const date = new Date(value);
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${
+ endOfDay ? "23:59:59" : "00:00:00"
+ }`;
+}
+
+function formatDateOnly(value: number) {
+ return formatDate(value).slice(0, 10);
+}
+
+function parseDateTime(value: unknown) {
+ if (!value) return Date.now();
+ const timestamp = new Date(String(value).replace(/-/g, "/")).getTime();
+ return Number.isFinite(timestamp) ? timestamp : Date.now();
+}
+
+function normalizeStatus(task: any) {
+ const key = String(task?.taskStatus ?? task?.timelinessStatus ?? task?.status ?? "")
+ .trim()
+ .toUpperCase();
+ if (["0", "WAITING", "PENDING", "寰呭紑濮�", "寰呮椂鏁�"].includes(key)) return 0;
+ if (["1", "RUNNING", "PROCESSING", "鏃舵晥涓�"].includes(key)) return 1;
+ if (["2", "FINISHED", "COMPLETED", "鏃舵晥缁撴潫"].includes(key)) return 2;
+ return Number(key);
+}
+
+function normalizeMaterialType(value: unknown): TimelinessMaterialType {
+ const text = String(value ?? "");
+ return text.includes("缁�") || text === "鎴愬搧" ? "缁炵嚎" : "鍗曚笣";
+}
+
+function isWaiting(task: any) {
+ return normalizeStatus(task) === 0;
+}
+
+function isRunning(task: any) {
+ return normalizeStatus(task) === 1;
+}
+
+function getStatusLabel(task: any) {
+ return statusOptions.find((item) => item.value === normalizeStatus(task))?.label || "鏈煡";
+}
+
+function getStatusType(task: any): TagType {
+ const status = normalizeStatus(task);
+ if (status === 0) return "warning";
+ if (status === 1) return "primary";
+ if (status === 2) return "success";
+ return "default";
+}
+
+function getInitiator(task: any) {
+ return task.initiatorName || task.userName || task.createUserName || "-";
+}
+
+function getInspector(task: any) {
+ return task.inspectorName || task.routingInspectionUser || "-";
+}
+
+function getTemperature(task: any) {
+ const value = task.setTemperature ?? task.temperature;
+ return value === undefined || value === "" ? "-" : `${value}鈩僠;
+}
+
+function getDuration(task: any) {
+ const value = task.agingDuration ?? task.duration;
+ return value === undefined || value === "" ? "-" : `${value} 灏忔椂`;
+}
+
+async function queryTaskList(pageNo: number, pageSize: number) {
+ try {
+ const { data } = await TimeSensitiveTaskApi.queryPage({
+ current: pageNo,
+ size: pageSize,
+ startTime: filters.startTimestamp ? formatDate(Number(filters.startTimestamp)) : undefined,
+ endTime: filters.endTimestamp ? formatDate(Number(filters.endTimestamp), true) : undefined,
+ });
+ pagingRef.value?.complete(data?.records || []);
+ } catch (error: any) {
+ pagingRef.value?.complete(false);
+ toast.error(error?.message || "鑾峰彇鏃舵晥浠诲姟澶辫触");
+ } finally {
+ pageReady.value = true;
+ }
+}
+
+function applyFilters() {
+ if (
+ filters.startTimestamp &&
+ filters.endTimestamp &&
+ Number(filters.startTimestamp) > Number(filters.endTimestamp)
+ ) {
+ toast.error("寮�濮嬫棩鏈熶笉鑳芥櫄浜庣粨鏉熸棩鏈�");
+ return;
+ }
+ pagingRef.value?.reload();
+}
+
+function resetFilters() {
+ Object.assign(filters, {
+ startTimestamp: "",
+ endTimestamp: "",
+ });
+ applyFilters();
+}
+
+function getCurrentPerson() {
+ const user = userStore.userInfo as any;
+ return user?.nickName || user?.nickname || user?.userName || user?.username || "";
+}
+
+function getPersonName(item: any) {
+ return String(item?.nickName || item?.nickname || item?.userName || item?.username || "");
+}
+
+function getMachineName(item: any) {
+ return String(item?.deviceModel || item?.device_model || item?.deviceName || item?.name || "");
+}
+
+async function loadOptions() {
+ if (userOptions.value.length && machineOptions.value.length) return;
+ optionsLoading.value = true;
+ try {
+ const [usersResult, machinesResult] = await Promise.all([
+ TimeSensitiveTaskApi.getUsers(),
+ TimeSensitiveTaskApi.getMachines(),
+ ]);
+ userOptions.value = (usersResult.data || [])
+ .map((item: any) => getPersonName(item))
+ .filter(Boolean)
+ .map((name: string) => ({ label: name, value: name }));
+ machineOptions.value = (machinesResult.data || [])
+ .map((item: any) => getMachineName(item))
+ .filter(Boolean)
+ .map((name: string) => ({ label: name, value: name }));
+ } catch (error: any) {
+ toast.error(error?.message || "鑾峰彇浜哄憳鎴栨椂鏁堟満鍙板け璐�");
+ } finally {
+ optionsLoading.value = false;
+ }
+}
+
+function resetTaskForm() {
+ const currentPerson = getCurrentPerson();
+ Object.assign(taskForm, {
+ materialType: "鍗曚笣",
+ initiatorName: currentPerson,
+ initiateTimestamp: Date.now(),
+ setTemperature: "",
+ durationRise: 2,
+ durationHold: "",
+ durationSoak: "",
+ machineName: "",
+ inspectorName: currentPerson,
+ });
+}
+
+function parseDuration(value: unknown) {
+ const parts = String(value ?? "")
+ .replace(/灏忔椂/g, "")
+ .split("+")
+ .map((item) => Number(item.trim()));
+ if (parts.length >= 3 && parts.every(Number.isFinite)) return parts;
+ return [2, Number.isFinite(parts[0]) ? parts[0] : "", ""];
+}
+
+async function openCreatePopup() {
+ editingTaskId.value = undefined;
+ resetTaskForm();
+ taskPopupVisible.value = true;
+ await loadOptions();
+}
+
+async function openEditPopup(task: any) {
+ if (!isWaiting(task)) return;
+ try {
+ const { data } = await TimeSensitiveTaskApi.getDetail(task.id);
+ const detail = { ...task, ...(data || {}) };
+ const duration = parseDuration(detail.agingDuration ?? detail.duration);
+ editingTaskId.value = detail.id;
+ Object.assign(taskForm, {
+ materialType: normalizeMaterialType(detail.materialType),
+ initiatorName: getInitiator(detail) === "-" ? "" : getInitiator(detail),
+ initiateTimestamp: parseDateTime(
+ detail.initiateTime || detail.startTime || detail.createTime
+ ),
+ setTemperature: detail.setTemperature ?? detail.temperature ?? "",
+ durationRise: duration[0],
+ durationHold: duration[1],
+ durationSoak: duration[2],
+ machineName: detail.machineName || detail.machine || "",
+ inspectorName: getInspector(detail) === "-" ? "" : getInspector(detail),
+ });
+ taskPopupVisible.value = true;
+ await loadOptions();
+ } catch (error: any) {
+ toast.error(error?.message || "鑾峰彇鏃舵晥浠诲姟璇︽儏澶辫触");
+ }
+}
+
+function buildTaskPayload(): TimeSensitiveTaskForm | null {
+ if (!taskForm.materialType) return (toast.error("璇烽�夋嫨浠诲姟绫诲瀷"), null);
+ if (!taskForm.initiatorName) return (toast.error("璇烽�夋嫨鍙戣捣浠诲姟浜�"), null);
+ if (!taskForm.initiateTimestamp) return (toast.error("璇烽�夋嫨鍙戣捣鏃堕棿"), null);
+ if (taskForm.setTemperature === "") return (toast.error("璇疯緭鍏ヨ瀹氭俯搴�"), null);
+ if (taskForm.durationHold === "") return (toast.error("璇疯緭鍏ヤ繚娓╂椂闀�"), null);
+ if (!taskForm.machineName) return (toast.error("璇烽�夋嫨璁惧畾鏈哄彴"), null);
+ if (!taskForm.inspectorName) return (toast.error("璇烽�夋嫨宸℃鍛�"), null);
+
+ return {
+ materialType: taskForm.materialType,
+ initiatorName: taskForm.initiatorName,
+ initiateTime: formatDateTime(Number(taskForm.initiateTimestamp)),
+ setTemperature: taskForm.setTemperature,
+ agingDuration: `${taskForm.durationRise || 0}+${taskForm.durationHold || 0}+${
+ taskForm.durationSoak || 0
+ }`,
+ machineName: taskForm.machineName,
+ inspectorName: taskForm.inspectorName,
+ };
+}
+
+async function submitTask() {
+ const payload = buildTaskPayload();
+ if (!payload || taskSubmitting.value) return;
+ taskSubmitting.value = true;
+ try {
+ const result = editingTaskId.value
+ ? await TimeSensitiveTaskApi.update({ id: editingTaskId.value, ...payload })
+ : await TimeSensitiveTaskApi.create(payload);
+ taskPopupVisible.value = false;
+ toast.success(editingTaskId.value ? "鏃舵晥浠诲姟淇敼鎴愬姛" : "鏂板鎴愬姛锛岃娣诲姞鏃舵晥鏄庣粏");
+ pagingRef.value?.reload();
+ if (!editingTaskId.value) {
+ const resultData = result.data;
+ const newId =
+ resultData && typeof resultData === "object"
+ ? resultData.id || resultData.taskId
+ : resultData;
+ if (newId) {
+ setTimeout(() => {
+ uni.navigateTo({ url: `/pages/timely/detail?id=${newId}` });
+ }, 500);
+ }
+ }
+ } catch (error: any) {
+ toast.error(error?.message || `${editingTaskId.value ? "淇敼" : "鏂板"}鏃舵晥浠诲姟澶辫触`);
+ } finally {
+ taskSubmitting.value = false;
+ }
+}
+
+function showConfirm(title: string, content: string, confirmText = "纭畾") {
+ return new Promise<boolean>((resolve) => {
+ uni.showModal({
+ title,
+ content,
+ confirmText,
+ success: (result) => resolve(Boolean(result.confirm)),
+ fail: () => resolve(false),
+ });
+ });
+}
+
+async function deleteTask(task: any) {
+ if (!isWaiting(task)) return toast.error("鍙湁寰呭紑濮嬬殑浠诲姟鍙互鍒犻櫎");
+ const confirmed = await showConfirm(
+ "鍒犻櫎浠诲姟",
+ `纭畾鍒犻櫎鏃舵晥浠诲姟鈥�${task.taskCode || task.id}鈥濆悧锛熶换鍔℃槑缁嗕篃浼氫竴骞跺垹闄ゃ�俙,
+ "鍒犻櫎"
+ );
+ if (!confirmed) return;
+ try {
+ await TimeSensitiveTaskApi.delete(task.id);
+ toast.success("鏃舵晥浠诲姟鍒犻櫎鎴愬姛");
+ pagingRef.value?.reload();
+ } catch (error: any) {
+ toast.error(error?.message || "鍒犻櫎鏃舵晥浠诲姟澶辫触");
+ }
+}
+
+async function startTask(task: any) {
+ if (!isWaiting(task)) return;
+ try {
+ const [detailResult, itemsResult] = await Promise.all([
+ TimeSensitiveTaskApi.getDetail(task.id),
+ TimeSensitiveTaskApi.getItems(task.id),
+ ]);
+ const detail = { ...task, ...(detailResult.data || {}) };
+ const items = Array.isArray(itemsResult.data)
+ ? itemsResult.data
+ : (itemsResult.data as any)?.records || [];
+ const payload = {
+ id: task.id,
+ materialType: normalizeMaterialType(detail.materialType),
+ initiatorName: getInitiator(detail) === "-" ? "" : getInitiator(detail),
+ initiateTime: detail.initiateTime || detail.startTime || detail.createTime || "",
+ setTemperature: detail.setTemperature ?? detail.temperature ?? "",
+ agingDuration: detail.agingDuration ?? detail.duration ?? "",
+ machineName: detail.machineName || detail.machine || "",
+ furnaceInTime: detail.furnaceInTime || formatDateTime(new Date()),
+ inspectorName: getInspector(detail) === "-" ? "" : getInspector(detail),
+ };
+ if (
+ Object.values(payload).some(
+ (value) => value === undefined || value === null || String(value) === ""
+ )
+ ) {
+ return toast.error("浠诲姟鍩虹淇℃伅涓嶅畬鏁达紝璇峰厛缂栬緫瀹屽杽");
+ }
+ if (!items.length) return toast.error("褰撳墠浠诲姟娌℃湁鏃舵晥鏄庣粏锛屼笉鑳藉紑濮嬫椂鏁�");
+ const confirmed = await showConfirm(
+ "寮�濮嬫椂鏁�",
+ `浠诲姟锛�${task.taskCode || task.id}\n鏄庣粏锛�${items.length}浠禱n鏈哄彴锛�${payload.machineName}\n纭寮�濮嬫椂鏁堝悧锛焋,
+ "寮�濮�"
+ );
+ if (!confirmed) return;
+ await TimeSensitiveTaskApi.start(payload);
+ toast.success("鏃舵晥宸插紑濮�");
+ pagingRef.value?.reload();
+ } catch (error: any) {
+ toast.error(error?.message || "寮�濮嬫椂鏁堝け璐�");
+ }
+}
+
+function parseCanEnd(data: any) {
+ if (typeof data === "boolean") return data;
+ return Boolean(data?.canEnd ?? data?.reachedDuration);
+}
+
+async function endTask(task: any) {
+ if (!isRunning(task)) return;
+ try {
+ const { data } = await TimeSensitiveTaskApi.checkEnd(task.id);
+ const canEnd = parseCanEnd(data);
+ const durationText =
+ data?.elapsedMinutes != null && data?.requiredMinutes != null
+ ? `褰撳墠宸叉椂鏁� ${data.elapsedMinutes} 鍒嗛挓锛岃瀹氭椂闀� ${data.requiredMinutes} 鍒嗛挓銆俙
+ : "褰撳墠灏氭湭杈惧埌璁惧畾鏃舵晥鏃堕暱銆�";
+ const confirmed = await showConfirm(
+ canEnd ? "缁撴潫鏃舵晥" : "鏃堕暱鏈揪鍒�",
+ canEnd
+ ? "宸茶揪鍒拌瀹氭椂鏁堟椂闀匡紝纭畾缁撴潫鏃舵晥鍚楋紵"
+ : `${data?.message || durationText}鏄惁浠嶈缁撴潫鏃舵晥锛焋,
+ canEnd ? "缁撴潫" : "浠嶇劧缁撴潫"
+ );
+ if (!confirmed) return;
+ await TimeSensitiveTaskApi.end({ id: task.id, forceEnd: !canEnd });
+ toast.success("鏃舵晥宸茬粨鏉�");
+ pagingRef.value?.reload();
+ } catch (error: any) {
+ toast.error(error?.message || "缁撴潫鏃舵晥澶辫触");
+ }
+}
+
+function openDetail(task: any) {
+ uni.navigateTo({ url: `/pages/timely/detail?id=${task.id}` });
+}
+
+function openInspection(task: any) {
+ const inspectionId = task.timelinessInspectionId || task.inspectionId || task.id;
+ const readonly = normalizeStatus(task) === 2 ? 1 : 0;
+ uni.navigateTo({
+ url: `/pages/timely/inspection?id=${inspectionId}&readonly=${readonly}`,
+ });
+}
+
+onShow(() => {
+ if (pageReady.value) pagingRef.value?.reload();
});
</script>
<style lang="scss" scoped>
-.list_box {
- height: calc(100vh - 100px);
+.timely-page {
+ height: calc(100vh - 50px);
background: #f3f9f8;
}
-:deep(.wd-button__content) {
- color: #0d867f;
+
+.page-top {
+ background: #ffffff;
+}
+
+.date-filter-card {
+ padding: 12px;
+ margin: 0 10px 10px;
+ background: linear-gradient(135deg, #f3fbf8 0%, #ffffff 72%);
+ border: 1px solid rgba(7, 133, 104, 0.12);
+ border-radius: 12px;
+ box-shadow: 0 4px 14px rgba(19, 94, 78, 0.06);
+}
+
+.date-filter-heading,
+.date-filter-title,
+.date-filter-fields,
+.date-filter-actions,
+.popup-footer,
+.task-actions {
+ display: flex;
+ align-items: center;
+}
+
+.date-filter-heading {
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
+
+.date-filter-title {
+ gap: 8px;
+}
+
+.date-filter-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ background: rgba(7, 133, 104, 0.1);
+ border-radius: 9px;
+}
+
+.date-filter-name {
+ font-size: 14px;
+ font-weight: 600;
+ color: #243832;
+}
+
+.date-filter-tip {
+ margin-top: 2px;
+ font-size: 11px;
+ color: #91a09c;
+}
+
+.date-filter-clear {
+ padding: 5px 0 5px 10px;
+ font-size: 12px;
+ color: #078568;
+}
+
+.date-filter-fields {
+ gap: 7px;
+}
+
+.date-filter-field {
+ flex: 1;
+ min-width: 0;
+ background: #ffffff;
+ border: 1px solid #e5efec;
+ border-radius: 8px;
+}
+
+.date-picker-trigger {
+ padding: 9px 10px;
+}
+
+.date-picker-label {
+ display: block;
+ margin-bottom: 5px;
+ font-size: 11px;
+ color: #8c9b97;
+}
+
+.date-picker-value {
+ display: flex;
+ gap: 4px;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 13px;
+ font-weight: 500;
+ color: #2b3c37;
+}
+
+.is-placeholder {
+ font-weight: 400;
+ color: #b7c1be;
+}
+
+.date-filter-separator {
+ flex: none;
+ font-size: 12px;
+ color: #8c9b97;
+}
+
+.date-filter-actions {
+ gap: 8px;
+ justify-content: flex-end;
+ margin-top: 10px;
+}
+
+.popup-footer,
+.task-actions {
+ flex-wrap: wrap;
+ gap: 8px;
+ justify-content: flex-end;
+}
+
+.task-list {
+ padding: 10px 10px 24px;
+}
+
+:deep(.task-card) {
+ margin: 0 0 10px;
+}
+
+.card-title,
+.title-main {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.title-main {
+ min-width: 0;
+ justify-content: flex-start;
+}
+
+.task-code {
+ overflow: hidden;
+ font-weight: 600;
+ color: #222222;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.info-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 10px 16px;
+}
+
+.info-item,
+.time-row {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+ min-width: 0;
+ font-size: 13px;
+ color: #333333;
+}
+
+.time-row {
+ flex-direction: row;
+ justify-content: space-between;
+ padding-top: 10px;
+ margin-top: 10px;
+ border-top: 1px solid #f2f2f2;
+}
+
+.info-label {
+ font-size: 12px;
+ color: #999999;
+}
+
+.popup-layout {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background: #f7f8fa;
+}
+
+.popup-header {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px;
+ background: #ffffff;
+ border-bottom: 1px solid #eeeeee;
+}
+
+.popup-title {
+ font-size: 17px;
+ font-weight: 600;
+}
+
+.popup-body {
+ flex: 1;
+ height: 0;
+}
+
+.popup-footer {
+ flex-shrink: 0;
+ padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
+ background: #ffffff;
+ border-top: 1px solid #eeeeee;
+}
+
+.duration-row {
+ display: grid;
+ grid-template-columns: 1fr auto 1fr auto 1fr;
+ gap: 4px;
+ align-items: center;
+ padding: 0 12px 10px;
+ background: #ffffff;
+}
+
+.duration-row :deep(.wd-input) {
+ padding: 0;
}
</style>
--
Gitblit v1.9.3