From b58f53769f004fb0ba6b5aedf55ef602850c7c97 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期日, 20 九月 2026 15:46:05 +0800
Subject: [PATCH] 天津豹鸣app 1.部署修改
---
src/pages/projectManagement/project/progress.vue | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 326 insertions(+), 0 deletions(-)
diff --git a/src/pages/projectManagement/project/progress.vue b/src/pages/projectManagement/project/progress.vue
new file mode 100644
index 0000000..6931be4
--- /dev/null
+++ b/src/pages/projectManagement/project/progress.vue
@@ -0,0 +1,326 @@
+<!--
+ 杩涘害姹囨姤锛堚啋 POST /projectManagement/info/saveStage锛�
+
+ 瀛楁浠ョ鐞嗙 projectDetail.vue 鐨� handleProgressSubmitted 缁勮鍑虹殑璇锋眰浣撲负鍑嗐��
+ 绠$悊绔� ProgressReportDialog 閲岃繕鏈夈�屼笂娆¤繘搴� / 璐熻矗浜� / 閮ㄩ棬銆嶄笁涓緭鍏ユ锛屼絾瀹冧滑
+ 骞朵笉鍦ㄨ姹備綋閲岋紙璐熻矗浜哄彇鐨勬槸褰撳墠鐧诲綍浜猴紝涓嶆槸琛ㄥ崟鍊硷級锛屾墍浠ヨ繖閲屼笉鍋氬彲缂栬緫鎺т欢锛�
+ 銆屼笂娆¤繘搴︺�嶇敱宸叉湁姹囨姤璁板綍鎺ㄧ畻鍚庡彧璇诲睍绀猴紝銆岃礋璐d汉銆嶆樉绀哄皢琚褰曠殑褰撳墠鐧诲綍浜猴紝
+ 閬垮厤鍑虹幇濉簡涓嶇敓鏁堢殑瀛楁銆�
+-->
+<template>
+ <view class="project-progress">
+ <PageHeader title="杩涘害姹囨姤"
+ @back="goBack" />
+
+ <view v-if="projectName"
+ class="project-banner">
+ <text class="banner-label">椤圭洰鍚嶇О</text>
+ <text class="banner-value">{{ projectName }}</text>
+ </view>
+
+ <view class="form-container">
+ <up-form ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="120"
+ input-align="right"
+ error-message-align="right">
+ <u-cell-group title="闃舵淇℃伅"
+ class="form-section">
+ <up-form-item label="椤圭洰闃舵"
+ prop="planNodeId"
+ required>
+ <FormPicker v-model="form.planNodeId"
+ type="select"
+ title="閫夋嫨椤圭洰闃舵"
+ :options="stageOptions"
+ placeholder="璇烽�夋嫨椤圭洰闃舵" />
+ </up-form-item>
+ <up-form-item label="璁″垝寮�濮嬫椂闂�"
+ prop="planStartTime"
+ required>
+ <FormPicker v-model="form.planStartTime"
+ type="date"
+ placeholder="璇烽�夋嫨璁″垝寮�濮嬫椂闂�" />
+ </up-form-item>
+ <up-form-item label="璁″垝瀹屽伐鏃堕棿"
+ prop="planEndTime"
+ required>
+ <FormPicker v-model="form.planEndTime"
+ type="date"
+ placeholder="璇烽�夋嫨璁″垝瀹屽伐鏃堕棿" />
+ </up-form-item>
+ <up-form-item label="瀹為檯寮�宸ユ棩鏈�"
+ prop="actualStartTime">
+ <FormPicker v-model="form.actualStartTime"
+ type="date"
+ placeholder="璇烽�夋嫨瀹為檯寮�宸ユ棩鏈�" />
+ </up-form-item>
+ </u-cell-group>
+
+ <u-cell-group title="杩涘害鎯呭喌"
+ class="form-section">
+ <up-form-item label="鏈杩涘害鏃ユ湡"
+ prop="reportDate"
+ required>
+ <FormPicker v-model="form.reportDate"
+ type="date"
+ placeholder="璇烽�夋嫨鏈杩涘害鏃ユ湡" />
+ </up-form-item>
+ <up-form-item label="涓婃杩涘害(%)">
+ <up-input :model-value="String(lastProgress)"
+ disabled />
+ </up-form-item>
+ <up-form-item label="瀹屾垚杩涘害(%)"
+ prop="completionProgress"
+ required>
+ <view class="progress-input">
+ <up-input v-model="form.completionProgress"
+ type="number"
+ placeholder="璇疯緭鍏ュ畬鎴愯繘搴�" />
+ <up-button type="primary"
+ size="small"
+ text="瀹屾垚"
+ @click="markDone" />
+ </view>
+ </up-form-item>
+ <up-form-item label="绱杩涘害(%)"
+ prop="totalProgress">
+ <up-input v-model="form.totalProgress"
+ type="number"
+ placeholder="鐣欑┖鍒欏彇瀹屾垚杩涘害" />
+ </up-form-item>
+ <up-form-item label="瀹為檯瀹屽伐鏃ユ湡"
+ prop="actualEndTime">
+ <FormPicker v-model="form.actualEndTime"
+ type="date"
+ placeholder="璇烽�夋嫨瀹為檯瀹屽伐鏃ユ湡" />
+ </up-form-item>
+ </u-cell-group>
+
+ <u-cell-group title="姹囨姤淇℃伅"
+ class="form-section">
+ <up-form-item label="璐熻矗浜�">
+ <up-input :model-value="leaderName || '褰撳墠鐧诲綍浜�'"
+ disabled />
+ </up-form-item>
+ <up-form-item label="澶囨敞"
+ prop="remark">
+ <up-textarea v-model="form.remark"
+ placeholder="璇疯緭鍏ュ娉�"
+ :maxlength="200"
+ count
+ auto-height />
+ </up-form-item>
+ <view class="upload-block">
+ <CommonUpload v-model="attachmentFiles"
+ accept="all" />
+ </view>
+ </u-cell-group>
+ </up-form>
+ </view>
+
+ <FooterButtons :loading="loading"
+ confirm-text="鎻愪氦姹囨姤"
+ @cancel="goBack"
+ @confirm="handleSubmit" />
+ </view>
+</template>
+
+<script setup>
+ import { computed, ref } from "vue";
+ import { onLoad } from "@dcloudio/uni-app";
+ import PageHeader from "@/components/PageHeader.vue";
+ import FooterButtons from "@/components/FooterButtons.vue";
+ import FormPicker from "@/components/FormPicker.vue";
+ import CommonUpload from "@/components/CommonUpload.vue";
+ import useUserStore from "@/store/modules/user";
+ import { getProject, saveStage } from "@/api/projectManagement/project";
+ import {
+ buildStagePayload,
+ defaultPlanNodeId,
+ fetchPlanNodeList,
+ fetchProjectStages,
+ planNodeOptions,
+ } from "./_utils/stage";
+
+ const userStore = useUserStore();
+
+ const formRef = ref();
+ const loading = ref(false);
+ const projectId = ref("");
+ const info = ref({});
+ const projectName = ref("");
+ const planNodes = ref([]);
+ const lastProgress = ref(0);
+ const attachmentFiles = ref([]);
+
+ const leaderName = computed(() => userStore.nickName || "");
+
+ const stageOptions = computed(() => planNodeOptions(planNodes.value));
+
+ const form = ref({
+ planNodeId: "",
+ planStartTime: "",
+ planEndTime: "",
+ actualStartTime: "",
+ actualEndTime: "",
+ reportDate: "",
+ completionProgress: "",
+ totalProgress: "",
+ remark: "",
+ });
+
+ const rules = {
+ planNodeId: [{ required: true, message: "璇烽�夋嫨椤圭洰闃舵", trigger: "change" }],
+ planStartTime: [
+ { required: true, message: "璇烽�夋嫨璁″垝寮�濮嬫椂闂�", trigger: "change" },
+ ],
+ planEndTime: [
+ { required: true, message: "璇烽�夋嫨璁″垝瀹屽伐鏃堕棿", trigger: "change" },
+ ],
+ reportDate: [
+ { required: true, message: "璇烽�夋嫨鏈杩涘害鏃ユ湡", trigger: "change" },
+ ],
+ completionProgress: [
+ { required: true, message: "璇疯緭鍏ュ畬鎴愯繘搴�", trigger: "blur" },
+ ],
+ };
+
+ const goBack = () => uni.navigateBack();
+
+ // 鍚庣涓嶆帴鏀躲�屼笂娆¤繘搴︺�嶏紝鐢卞凡姹囨姤璁板綍閲岀殑鏈�澶� progress 鎺ㄧ畻锛屽彧浣滃~鍐欏弬鑰�
+ const deriveLastProgress = stages =>
+ (Array.isArray(stages) ? stages : []).reduce((max, row) => {
+ const value = Number(row?.progress ?? 0) || 0;
+ return value > max ? value : max;
+ }, 0);
+
+ const markDone = () => {
+ form.value.completionProgress = "100";
+ form.value.totalProgress = "100";
+ if (!form.value.actualEndTime) form.value.actualEndTime = form.value.reportDate;
+ };
+
+ const loadDetail = async () => {
+ try {
+ const res = await getProject(projectId.value);
+ const raw = res?.data?.data ?? res?.data ?? res;
+ info.value = raw?.info || {};
+ projectName.value = info.value.title || "";
+
+ const [nodes, stages] = await Promise.all([
+ fetchPlanNodeList(info.value.projectManagementPlanId),
+ fetchProjectStages(projectId.value),
+ ]);
+ planNodes.value = nodes;
+ lastProgress.value = deriveLastProgress(stages);
+
+ form.value.planNodeId = defaultPlanNodeId(info.value.stage, nodes);
+ form.value.planStartTime = info.value.planStartTime || "";
+ form.value.planEndTime = info.value.planEndTime || "";
+ form.value.actualStartTime = info.value.actualStartTime || "";
+ form.value.actualEndTime = info.value.actualEndTime || "";
+ // 鏈夊巻鍙叉眹鎶ユ墠棰勫~绱杩涘害锛涙病鏈夊垯鐣欑┖锛屾彁浜ゆ椂閫�鍥炪�屽畬鎴愯繘搴︺��
+ form.value.totalProgress = lastProgress.value
+ ? String(lastProgress.value)
+ : "";
+ } catch (error) {
+ uni.showToast({ title: "鑾峰彇椤圭洰璇︽儏澶辫触", icon: "none" });
+ }
+ };
+
+ const handleSubmit = async () => {
+ const valid = await formRef.value.validate().catch(() => false);
+ if (!valid) return;
+
+ loading.value = true;
+ saveStage(
+ buildStagePayload({
+ projectId: projectId.value,
+ projectInfo: info.value,
+ planNodes: planNodes.value,
+ form: form.value,
+ attachments: attachmentFiles.value,
+ leaderId: userStore.id,
+ leaderName: userStore.nickName,
+ })
+ )
+ .then(() => {
+ uni.showToast({ title: "姹囨姤鎴愬姛", icon: "success" });
+ setTimeout(() => uni.navigateBack(), 300);
+ })
+ .catch(() => {
+ uni.showToast({ title: "姹囨姤澶辫触", icon: "none" });
+ })
+ .finally(() => {
+ loading.value = false;
+ });
+ };
+
+ onLoad(options => {
+ projectId.value = options?.id || "";
+ if (projectId.value) loadDetail();
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "@/static/scss/form-common.scss";
+
+ .project-progress {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 100px;
+ }
+
+ .project-banner {
+ margin: 12px 12px 0;
+ padding: 14px 16px;
+ border-radius: 12px;
+ background: #ffffff;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ .banner-label {
+ font-size: 13px;
+ color: #909399;
+ }
+
+ .banner-value {
+ font-size: 16px;
+ font-weight: 600;
+ color: #22324d;
+ }
+
+ .form-container {
+ padding: 12px 12px 0;
+ }
+
+ .form-section {
+ margin-bottom: 12px;
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow: 0 2px 10px rgba(15, 35, 95, 0.05);
+ }
+
+ .progress-input {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+ }
+
+ .upload-block {
+ padding: 12px;
+ }
+
+ :deep(.u-cell-group__title) {
+ padding: 14px 18px 10px !important;
+ font-size: 15px !important;
+ font-weight: 600 !important;
+ color: #22324d !important;
+ background: #f8fbff !important;
+ }
+</style>
--
Gitblit v1.9.3