From 8a22c10dd6a1a635e44b97056efb6f5627b395e4 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 21 一月 2026 10:21:31 +0800
Subject: [PATCH] 会议看板

---
 src/pages/cooperativeOffice/collaborativeApproval/detail.vue | 1366 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 880 insertions(+), 486 deletions(-)

diff --git a/src/pages/cooperativeOffice/collaborativeApproval/detail.vue b/src/pages/cooperativeOffice/collaborativeApproval/detail.vue
index 362b237..dc7a869 100644
--- a/src/pages/cooperativeOffice/collaborativeApproval/detail.vue
+++ b/src/pages/cooperativeOffice/collaborativeApproval/detail.vue
@@ -1,535 +1,929 @@
 <template>
   <view class="account-detail">
-    <!-- 椤堕儴鏍囬鏍� -->
-    <view class="header">
-      <up-icon name="arrow-left" size="20" color="#333" @click="goBack" />
-      <text class="title">瀹℃壒娴佺▼</text>
-    </view>
-
+    <PageHeader title="瀹℃壒娴佺▼"
+                @back="goBack" />
     <!-- 琛ㄥ崟鍖哄煙 -->
-    <view class="form-section">
-      <van-form ref="formRef" @submit="submitForm" :rules="rules" input-align="right">
-        <van-cell-group inset style="height:auto">
-          <van-field
-            v-model="taxPrice"
-            name="taxPrice"
-            label="濮撳悕"
-            placeholder="璇疯緭鍏ュ鍚�"
-            :rules="[{ required: true, message: '濮撳悕涓嶈兘涓虹┖' }]"
-            required
-            readonly
-          />
-          <van-field
-            v-model="result"
-            readonly
-            name="picker"
-            label="鐢宠閮ㄩ棬"
-            placeholder="璇烽�夋嫨鐢宠閮ㄩ棬"
-            :rules="[{ required: true, message: '璇烽�夋嫨鐢宠閮ㄩ棬' }]"
-            @click="showPicker = true"
-            required
-          />
-          <van-popup
-            v-model:show="showPicker"
-            destroy-on-close
-            position="bottom"
-          >
-            <van-picker
-              :columns="columns"
-              :model-value="pickerValue"
-              @confirm="onConfirm"
-              @cancel="showPicker = false"
-            />
-          </van-popup>
-          <van-field
-            v-model="message"
-            name="message"
-            rows="1"
-            autosize
-            label="鐢宠浜嬬敱"
-            type="textarea"
-            placeholder="璇疯緭鍏ョ敵璇蜂簨鐢�"
-            height="100"
-            :rules="[{ required: true, message: '鐢宠浜嬬敱涓嶈兘涓虹┖' }]"
-            required
-          />
-        </van-cell-group>
-      </van-form>
-    </view>
+    <u-form ref="formRef"
+            @submit="submitForm"
+            :rules="rules"
+            :model="form"
+            label-width="140rpx">
+      <u-form-item prop="approveReason"
+                   label="娴佺▼缂栧彿">
+        <u-input v-model="form.approveId"
+                 disabled
+                 placeholder="鑷姩缂栧彿" />
+      </u-form-item>
+      <u-form-item prop="approveReason"
+                   :label="approveType === 5 ? '閲囪喘浜嬬敱' : '鐢宠浜嬬敱'"
+                   required>
+        <u-input v-model="form.approveReason"
+                 type="textarea"
+                 rows="2"
+                 auto-height
+                 maxlength="200"
+                 :placeholder="approveType === 5 ? '璇疯緭鍏ラ噰璐簨鐢�' : '璇疯緭鍏ョ敵璇蜂簨鐢�'"
+                 show-word-limit />
+      </u-form-item>
+      <u-form-item prop="approveDeptName"
+                   label="鐢宠閮ㄩ棬"
+                   required>
+        <u-input v-model="form.approveDeptName"
+                 placeholder="璇烽�夋嫨鐢宠閮ㄩ棬" />
+        <!-- <u-input v-model="form.approveDeptName"
+                 readonly
+                 placeholder="璇烽�夋嫨鐢宠閮ㄩ棬"
+                 @click="showPicker = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showPicker = true"></up-icon>
+        </template> -->
+      </u-form-item>
+      <u-form-item prop="approveUser"
+                   label="鐢宠浜�"
+                   required>
+        <u-input v-model="form.approveUserName"
+                 placeholder="璇疯緭鍏ョ敵璇蜂汉"
+                 readonly />
+      </u-form-item>
+      <u-form-item prop="approveTime"
+                   label="鐢宠鏃ユ湡"
+                   required>
+        <u-input v-model="form.approveTime"
+                 readonly
+                 placeholder="璇烽�夋嫨"
+                 @click="showDatePicker" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showDatePicker"></up-icon>
+        </template>
+      </u-form-item>
+      <!-- approveType=2 璇峰亣鐩稿叧瀛楁 -->
+      <template v-if="approveType === 2">
+        <u-form-item prop="startDate"
+                     label="寮�濮嬫椂闂�"
+                     required>
+          <u-input v-model="form.startDate"
+                   readonly
+                   placeholder="璇峰亣寮�濮嬫椂闂�"
+                   @click="showStartDatePicker" />
+          <template #right>
+            <up-icon name="arrow-right"
+                     @click="showStartDatePicker"></up-icon>
+          </template>
+        </u-form-item>
+        <u-form-item prop="endDate"
+                     label="缁撴潫鏃堕棿"
+                     required>
+          <u-input v-model="form.endDate"
+                   readonly
+                   placeholder="璇峰亣缁撴潫鏃堕棿"
+                   @click="showEndDatePicker" />
+          <template #right>
+            <up-icon name="arrow-right"
+                     @click="showEndDatePicker"></up-icon>
+          </template>
+        </u-form-item>
+      </template>
+      <!-- approveType=3 鍑哄樊鐩稿叧瀛楁 -->
+      <u-form-item v-if="approveType === 3"
+                   prop="location"
+                   label="鍑哄樊鍦扮偣"
+                   required>
+        <u-input v-model="form.location"
+                 placeholder="璇疯緭鍏ュ嚭宸湴鐐�"
+                 clearable />
+      </u-form-item>
+      <!-- approveType=4 鎶ラ攢鐩稿叧瀛楁 -->
+      <u-form-item v-if="approveType === 4"
+                   prop="price"
+                   label="鎶ラ攢閲戦"
+                   required>
+        <u-input v-model="form.price"
+                 type="number"
+                 placeholder="璇疯緭鍏ユ姤閿�閲戦"
+                 clearable />
+      </u-form-item>
+    </u-form>
+    <!-- 閫夋嫨鍣ㄥ脊绐� -->
+    <up-action-sheet :show="showPicker"
+                     :actions="productOptions"
+                     title="閫夋嫨閮ㄩ棬"
+                     @select="onConfirm"
+                     @close="showPicker = false" />
+    <!-- 鏃ユ湡閫夋嫨鍣� -->
+    <up-popup :show="showDate"
+              mode="bottom"
+              @close="showDate = false">
+      <up-datetime-picker :show="true"
+                          v-model="currentDate"
+                          @confirm="onDateConfirm"
+                          @cancel="showDate = false"
+                          mode="date" />
+    </up-popup>
+    <!-- 璇峰亣寮�濮嬫椂闂撮�夋嫨鍣� -->
+    <up-popup :show="showStartDate"
+              mode="bottom"
+              @close="showStartDate = false">
+      <up-datetime-picker :show="true"
+                          v-model="startDateValue"
+                          @confirm="onStartDateConfirm"
+                          @cancel="showStartDate = false"
+                          mode="date" />
+    </up-popup>
+    <!-- 璇峰亣缁撴潫鏃堕棿閫夋嫨鍣� -->
+    <up-popup :show="showEndDate"
+              mode="bottom"
+              @close="showEndDate = false">
+      <up-datetime-picker :show="true"
+                          v-model="endDateValue"
+                          @confirm="onEndDateConfirm"
+                          @cancel="showEndDate = false"
+                          mode="date" />
+    </up-popup>
     <!-- 瀹℃牳娴佺▼鍖哄煙 -->
     <view class="approval-process">
       <view class="approval-header">
         <text class="approval-title">瀹℃牳娴佺▼</text>
-        <text class="approval-desc">宸茬敱绠$悊鍛橀璁句笉鍙慨鏀�</text>
+        <text class="approval-desc">姣忎釜姝ラ鍙兘閫夋嫨涓�涓鎵逛汉</text>
       </view>
-
       <view class="approval-steps">
-        <view v-for="(step, stepIndex) in approvalSteps" :key="stepIndex" class="approval-step">
+        <view v-for="(step, stepIndex) in approverNodes"
+              :key="stepIndex"
+              class="approval-step">
+          <view class="step-dot"></view>
           <view class="step-title">
             <text>瀹℃壒浜�</text>
           </view>
-          <view class="approvers-container">
-            <view v-for="(approver, approverIndex) in step.approvers" :key="approverIndex" class="approver-item">
-              <view class="approver-avatar"></view>
-              <text class="approver-name">{{ approver.name }}</text>
-              <view class="delete-approver-btn" @click="removeApprover(stepIndex, approverIndex)">脳</view>
+          <view class="approver-container">
+            <view v-if="step.nickName"
+                  class="approver-item">
+              <view class="approver-avatar">
+                <text class="avatar-text">{{ step.nickName.charAt(0) }}</text>
+                <view class="status-dot"></view>
+              </view>
+              <view class="approver-info">
+                <text class="approver-name">{{ step.nickName }}</text>
+              </view>
+              <view class="delete-approver-btn"
+                    @click="removeApprover(stepIndex)">脳</view>
             </view>
-            <view class="add-approver-btn" @click="addApprover(stepIndex)">+
+            <view v-else
+                  class="add-approver-btn"
+                  @click="addApprover(stepIndex)">
+              <view class="add-circle">+</view>
+              <text class="add-label">閫夋嫨瀹℃壒浜�</text>
             </view>
           </view>
-          <view class="step-line" v-if="stepIndex < approvalSteps.length - 1"></view>
-          <view class="delete-step-btn" @click="removeApprovalStep(stepIndex)">鍒犻櫎鑺傜偣</view>
+          <view class="step-line"
+                v-if="stepIndex < approverNodes.length - 1"></view>
+          <view class="delete-step-btn"
+                v-if="approverNodes.length > 1"
+                @click="removeApprovalStep(stepIndex)">鍒犻櫎鑺傜偣</view>
         </view>
       </view>
-
-      <view class="add-step-btn" @click="addApprovalStep">
-        <text>鏂板鑺傜偣瀹℃牳浜�</text>
+      <view class="add-step-btn">
+        <u-button icon="plus"
+                  plain
+                  type="primary"
+                  style="width: 100%"
+                  @click="addApprovalStep">鏂板鑺傜偣</u-button>
       </view>
     </view>
-
     <!-- 搴曢儴鎸夐挳 -->
     <view class="footer-btns">
-      <van-button class="cancel-btn" @click="goBack">鍙栨秷</van-button>
-      <van-button class="save-btn" @click="submitForm">淇濆瓨</van-button>
+      <u-button class="cancel-btn"
+                @click="goBack">鍙栨秷</u-button>
+      <u-button class="save-btn"
+                @click="submitForm">淇濆瓨</u-button>
     </view>
   </view>
 </template>
 
-<script>
-import { ref, onMounted } from "vue";
-
-export default {
-  setup() {
-    const rules = ref({
-
-  taxPrice: {
-    rules: [{ required: true, errorMessage: '濮撳悕涓嶈兘涓虹┖' }]
-  },
-  result: {
-    rules: [{ required: true, errorMessage: '璇烽�夋嫨鐢宠閮ㄩ棬' }]
-  },
-  message: {
-    rules: [{ required: true, errorMessage: '鐢宠浜嬬敱涓嶈兘涓虹┖' }]
-  },
-});
-    const result = ref("");
-    const pickerValue = ref([]);
-    const showPicker = ref(false);
-    const columns = ref([]);
-    onMounted(async () => {
-      try {
-        // 鏇挎崲涓哄疄闄呮帴鍙e湴鍧�
-        // const response = await axios.get('/api/getDepartments');
-        columns.value = [
-          {
-            text: "鏉窞",
-            value: "Hangzhou",
-          },
-          {
-            text: "瀹佹尝",
-            value: "Ningbo",
-          },
-          {
-            text: "娓╁窞",
-            value: "Wenzhou",
-          },
-          {
-            text: "缁嶅叴",
-            value: "Shaoxing",
-          },
-          {
-            text: "婀栧窞",
-            value: "Huzhou",
-          },
-        ];
-      } catch (error) {
-        console.error("鑾峰彇閮ㄩ棬鏁版嵁澶辫触:", error);
-      }
+<script setup>
+  import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
+  import PageHeader from "@/components/PageHeader.vue";
+  import useUserStore from "@/store/modules/user";
+  import { formatDateToYMD } from "@/utils/ruoyi";
+  import {
+    getDept,
+    approveProcessGetInfo,
+    approveProcessAdd,
+    approveProcessUpdate,
+  } from "@/api/collaborativeApproval/approvalProcess";
+  const showToast = message => {
+    uni.showToast({
+      title: message,
+      icon: "none",
     });
-    const onConfirm = ({ selectedValues, selectedOptions }) => {
-      result.value = selectedOptions[0]?.text;
-      pickerValue.value = selectedValues;
-      showPicker.value = false;
-    };
-    const taxPrice = ref("");
-    const contractAmount = ref("");
-    const approvalSteps = ref([
-      { approvers: [{ name: '鍗㈠皬鏁�' }, { name: '鍗㈠皬鏁�' }] },
-      { approvers: [{ name: '鍗㈠皬鏁�' }] },
-      { approvers: [{ name: '鍗㈠皬鏁�' }] },
-      { approvers: [{ name: '鍗㈠皬鏁�' }] }
-    ]);
+  };
+  import { userListNoPageByTenantId } from "@/api/system/user";
 
-    const goBack = () => {
-    	uni.navigateBack();
-    };
+  const data = reactive({
+    form: {
+      approveTime: "",
+      approveId: "",
+      approveUser: "",
+      approveUserName: "",
+      approveDeptName: "",
+      approveDeptId: "",
+      approveReason: "",
+      checkResult: "",
+      tempFileIds: [],
+      approverList: [], // 鏂板瀛楁锛屽瓨鍌ㄦ墍鏈夎妭鐐圭殑瀹℃壒浜篿d
+      startDate: "",
+      endDate: "",
+      location: "",
+      price: "",
+    },
+    rules: {
+      approveTime: [{ required: false, message: "璇疯緭鍏�", trigger: "change" }],
+      approveId: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+      approveDeptId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      approveReason: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      checkResult: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+      startDate: [
+        { required: false, message: "璇烽�夋嫨寮�濮嬫椂闂�", trigger: "change" },
+      ],
+      endDate: [
+        { required: false, message: "璇烽�夋嫨缁撴潫鏃堕棿", trigger: "change" },
+      ],
+      location: [{ required: false, message: "璇疯緭鍏ュ嚭宸湴鐐�", trigger: "blur" }],
+      price: [{ required: false, message: "璇疯緭鍏ユ姤閿�閲戦", trigger: "blur" }],
+    },
+  });
+  const { form, rules } = toRefs(data);
+  const result = ref("");
+  const showPicker = ref(false);
+  const productOptions = ref([]);
+  const operationType = ref("");
+  const currentApproveStatus = ref("");
+  const approverNodes = ref([]);
+  const userList = ref([]);
+  const formRef = ref(null);
+  const message = ref("");
+  const showDate = ref(false);
+  const currentDate = ref(Date.now());
+  const showStartDate = ref(false);
+  const startDateValue = ref(Date.now());
+  const showEndDate = ref(false);
+  const endDateValue = ref(Date.now());
+  const userStore = useUserStore();
+  const approveType = ref(0);
 
-    const formRef = ref(null);
-
-    const submitForm = () => {
-      formRef.value.validate().then(() => {
-        // 琛ㄥ崟鏍¢獙閫氳繃锛屽彲浠ユ彁浜ゆ暟鎹�
-        console.log("琛ㄥ崟鏁版嵁:", {
-          taxPrice: taxPrice.value,
-          department: result.value,
-          message: message.value,
-          approvalSteps: approvalSteps.value
-        });
-
-        uni.showToast({
-          title: "淇濆瓨鎴愬姛",
-          icon: "success",
-        });
-      }).catch((error) => {
-        console.error("琛ㄥ崟鏍¢獙澶辫触:", error);
-        // 鏄剧ず鍏蜂綋鐨勯敊璇俊鎭�
-        if (error.length > 0) {
-          const firstError = error[0];
-          uni.showToast({
-            title: firstError.message || '琛ㄥ崟鏍¢獙澶辫触',
-            icon: 'none'
-          });
-        } else {
-          uni.showToast({
-            title: '琛ㄥ崟鏍¢獙澶辫触锛岃妫�鏌ュ繀濉」',
-            icon: 'none'
-          });
-        }
+  const getProductOptions = () => {
+    getDept().then(res => {
+      productOptions.value = res.data.map(item => ({
+        value: item.deptId,
+        name: item.deptName,
+      }));
+    });
+  };
+  const fileList = ref([]);
+  let nextApproverId = 2;
+  const getCurrentinfo = () => {
+    userStore.getInfo().then(res => {
+      form.value.approveDeptId = res.user.tenantId;
+      console.log(res.user.tenantId, "res.user.tenantId");
+    });
+  };
+  onMounted(async () => {
+    try {
+      getProductOptions();
+      userListNoPageByTenantId().then(res => {
+        userList.value = res.data;
       });
-    };
+      form.value.approveUser = userStore.id;
+      form.value.approveUserName = userStore.nickName;
+      form.value.approveTime = getCurrentDate();
+      getCurrentinfo();
+      // 浠庢湰鍦板瓨鍌ㄨ幏鍙栧弬鏁�
+      operationType.value = uni.getStorageSync("operationType") || "add";
+      approveType.value = uni.getStorageSync("approveType") || 0;
 
-    const message = ref("");
+      // 濡傛灉鏄紪杈戞ā寮忥紝浠庢湰鍦板瓨鍌ㄨ幏鍙栨暟鎹�
+      if (operationType.value === "edit") {
+        const storedData = uni.getStorageSync("invoiceLedgerEditRow");
+        if (storedData) {
+          const row = JSON.parse(storedData);
+          fileList.value = row.commonFileList || [];
+          form.value.tempFileIds = fileList.value.map(file => file.id);
+          currentApproveStatus.value = row.approveStatus;
 
-    const addApprover = (stepIndex) => {
-      // 鍦ㄦ寚瀹氬鎵规楠ゆ坊鍔犳柊鐨勫鎵逛汉
-      approvalSteps.value[stepIndex].approvers.push({ name: '鍗㈠皬鏁�' });
-    };
-
-    const addApprovalStep = () => {
-      // 娣诲姞鏂扮殑瀹℃壒姝ラ
-      approvalSteps.value.push({ approvers: [{ name: '鍗㈠皬鏁�' }] });
-    };
-
-    const removeApprover = (stepIndex, approverIndex) => {
-      // 纭繚姣忎釜姝ラ鑷冲皯淇濈暀涓�涓鎵逛汉
-      if (approvalSteps.value[stepIndex].approvers.length > 1) {
-        approvalSteps.value[stepIndex].approvers.splice(approverIndex, 1);
+          approveProcessGetInfo({ id: row.approveId, approveReason: "1" }).then(
+            res => {
+              form.value = { ...res.data };
+              // 鍙嶆樉瀹℃壒浜�
+              if (res.data && res.data.approveUserIds) {
+                const userIds = res.data.approveUserIds.split(",");
+                approverNodes.value = userIds.map((userId, idx) => {
+                  const userIdNum = parseInt(userId.trim());
+                  // 浠巙serList涓壘鍒板搴旂殑鐢ㄦ埛淇℃伅
+                  const userInfo = userList.value.find(
+                    user => user.userId === userIdNum
+                  );
+                  return {
+                    id: idx + 1,
+                    userId: userIdNum,
+                    nickName: userInfo ? userInfo.nickName : null,
+                  };
+                });
+                nextApproverId = userIds.length + 1;
+              } else {
+                // 鏂板妯″紡锛屽垵濮嬪寲涓�涓┖鐨勫鎵硅妭鐐�
+                approverNodes.value = [{ id: 1, userId: null, nickName: null }];
+                nextApproverId = 2;
+              }
+            }
+          );
+        }
       } else {
-        uni.showToast({
-          title: '姣忎釜姝ラ鑷冲皯闇�瑕佷竴涓鎵逛汉',
-          icon: 'none'
-        });
+        // 鏂板妯″紡锛屽垵濮嬪寲涓�涓┖鐨勫鎵硅妭鐐�
+        approverNodes.value = [{ id: 1, userId: null }];
       }
-    };
 
-    const removeApprovalStep = (stepIndex) => {
-      // 纭繚鑷冲皯淇濈暀涓�涓鎵规楠�
-      if (approvalSteps.value.length > 1) {
-        approvalSteps.value.splice(stepIndex, 1);
-      } else {
+      // 鐩戝惉鑱旂郴浜洪�夋嫨浜嬩欢
+      uni.$on("selectContact", handleSelectContact);
+    } catch (error) {
+      console.error("鑾峰彇閮ㄩ棬鏁版嵁澶辫触:", error);
+    }
+  });
+
+  onUnmounted(() => {
+    // 绉婚櫎浜嬩欢鐩戝惉
+    uni.$off("selectContact", handleSelectContact);
+  });
+
+  const onConfirm = item => {
+    // 璁剧疆閫変腑鐨勯儴闂�
+    form.value.approveDeptName = item.name;
+    // 纭繚璁剧疆鐨勬槸瀛楃涓茬被鍨嬬殑閮ㄩ棬ID
+    form.value.approveDeptId = String(item.value || "");
+    console.log("閮ㄩ棬閫夋嫨鍚庣殑鍊�:", {
+      approveDeptId: form.value.approveDeptId,
+      approveDeptName: form.value.approveDeptName,
+    });
+    showPicker.value = false;
+  };
+
+  const goBack = () => {
+    // 娓呴櫎鏈湴瀛樺偍鐨勬暟鎹�
+    uni.removeStorageSync("operationType");
+    uni.removeStorageSync("invoiceLedgerEditRow");
+    uni.removeStorageSync("approveType");
+    uni.navigateBack();
+  };
+
+  const submitForm = () => {
+    // 妫�鏌ユ瘡涓鎵规楠ゆ槸鍚﹂兘鏈夊鎵逛汉
+    const hasEmptyStep = approverNodes.value.some(step => !step.nickName);
+    if (hasEmptyStep) {
+      showToast("璇蜂负姣忎釜瀹℃壒姝ラ閫夋嫨瀹℃壒浜�");
+      return;
+    }
+
+    // 鎵嬪姩妫�鏌ュ繀濉瓧娈碉紝闃叉鍥犳暟鎹被鍨嬮棶棰樺鑷寸殑鏍¢獙澶辫触
+    if (!form.value.approveReason || !form.value.approveReason.trim()) {
+      showToast("璇疯緭鍏ョ敵璇蜂簨鐢�");
+      return;
+    }
+
+    if (
+      !form.value.approveDeptId ||
+      String(form.value.approveDeptId).trim() === ""
+    ) {
+      showToast("璇烽�夋嫨鐢宠閮ㄩ棬");
+      return;
+    }
+
+    if (!form.value.approveTime) {
+      showToast("璇烽�夋嫨鐢宠鏃ユ湡");
+      return;
+    }
+
+    formRef.value
+      .validate()
+      .then(valid => {
+        if (valid) {
+          // 琛ㄥ崟鏍¢獙閫氳繃锛屽彲浠ユ彁浜ゆ暟鎹�
+          // 鏀堕泦鎵�鏈夎妭鐐圭殑瀹℃壒浜篿d
+          console.log("approverNodes---", approverNodes.value);
+          form.value.approveUserIds = approverNodes.value
+            .map(node => node.userId)
+            .join(",");
+          form.value.approveType = approveType.value;
+          form.value.approveDeptId = Number(form.value.approveDeptId);
+          // const submitForm = {
+          //   approveDeptId: form.value.approveDeptId,
+          //   approveDeptName: form.value.approveDeptName,
+          //   approveReason: form.value.approveReason,
+          //   approveTime: form.value.approveTime,
+          //   approveType: form.value.approveType,
+          //   approveUser: form.value.approveUser,
+          //   approveUserIds: form.value.approveUserIds,
+          //   endDate: form.value.endDate,
+          //   startDate: form.value.startDate,
+          // };
+          // console.log("form.value---", form.value);
+          // console.log("submitForm", submitForm);
+
+          if (operationType.value === "add" || currentApproveStatus.value == 3) {
+            approveProcessAdd(form.value).then(res => {
+              showToast("鎻愪氦鎴愬姛");
+              goBack();
+            });
+          } else {
+            approveProcessUpdate(form.value).then(res => {
+              showToast("鎻愪氦鎴愬姛");
+              goBack();
+            });
+          }
+        }
+      })
+      .catch(error => {
+        console.error("琛ㄥ崟鏍¢獙澶辫触:", error);
+        // 灏濊瘯鑾峰彇鍏蜂綋鐨勯敊璇瓧娈�
+        if (error && error.errors) {
+          const firstError = error.errors[0];
+          if (firstError) {
+            uni.showToast({
+              title: firstError.message || "琛ㄥ崟鏍¢獙澶辫触锛岃妫�鏌ュ繀濉」",
+              icon: "none",
+            });
+            return;
+          }
+        }
+        // 鏄剧ず閫氱敤閿欒淇℃伅
         uni.showToast({
-          title: '鑷冲皯闇�瑕佷竴涓鎵规楠�',
-          icon: 'none'
+          title: "琛ㄥ崟鏍¢獙澶辫触锛岃妫�鏌ュ繀濉」",
+          icon: "none",
         });
-      }
-    };
+      });
+  };
 
-    return {
-      rules,
-      removeApprovalStep,
-    removeApprover,
-      result,
-      pickerValue,
-      columns,
-      onConfirm,
-      showPicker,
-      taxPrice,
-      contractAmount,
-      goBack,
-      submitForm,
-      approvalSteps,
-      addApprover,
-      addApprovalStep,
-      formRef,
-      message
-    };
-  },
-};
+  // 澶勭悊鑱旂郴浜洪�夋嫨缁撴灉
+  const handleSelectContact = data => {
+    const { stepIndex, contact } = data;
+    // 灏嗛�変腑鐨勮仈绯讳汉璁剧疆涓哄搴斿鎵规楠ょ殑瀹℃壒浜�
+    approverNodes.value[stepIndex].userId = contact.userId;
+    approverNodes.value[stepIndex].nickName = contact.nickName;
+  };
+
+  const addApprover = stepIndex => {
+    // 璺宠浆鍒拌仈绯讳汉閫夋嫨椤甸潰
+    uni.setStorageSync("stepIndex", stepIndex);
+    uni.navigateTo({
+      url: "/pages/cooperativeOffice/collaborativeApproval/contactSelect",
+    });
+  };
+
+  const addApprovalStep = () => {
+    // 娣诲姞鏂扮殑瀹℃壒姝ラ
+    approverNodes.value.push({ userId: null, nickName: null });
+  };
+
+  const removeApprover = stepIndex => {
+    // 绉婚櫎瀹℃壒浜�
+    approverNodes.value[stepIndex].userId = null;
+    approverNodes.value[stepIndex].nickName = null;
+  };
+
+  const removeApprovalStep = stepIndex => {
+    // 纭繚鑷冲皯淇濈暀涓�涓鎵规楠�
+    if (approverNodes.value.length > 1) {
+      approverNodes.value.splice(stepIndex, 1);
+    } else {
+      uni.showToast({
+        title: "鑷冲皯闇�瑕佷竴涓鎵规楠�",
+        icon: "none",
+      });
+    }
+  };
+  // 鏄剧ず鏃ユ湡閫夋嫨鍣�
+  const showDatePicker = () => {
+    showDate.value = true;
+  };
+
+  // 纭鏃ユ湡閫夋嫨
+  const onDateConfirm = e => {
+    form.value.approveTime = formatDateToYMD(e.value);
+    currentDate.value = formatDateToYMD(e.value);
+    showDate.value = false;
+  };
+
+  // 鏄剧ず璇峰亣寮�濮嬫椂闂撮�夋嫨鍣�
+  const showStartDatePicker = () => {
+    showStartDate.value = true;
+  };
+
+  // 纭璇峰亣寮�濮嬫椂闂撮�夋嫨
+  const onStartDateConfirm = e => {
+    form.value.startDate = formatDateToYMD(e.value);
+    showStartDate.value = false;
+  };
+
+  const showEndDatePicker = () => {
+    showEndDate.value = true;
+  };
+
+  // 纭璇峰亣缁撴潫鏃堕棿閫夋嫨
+  const onEndDateConfirm = e => {
+    form.value.endDate = formatDateToYMD(e.value);
+    showEndDate.value = false;
+  };
+
+  // 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+  function getCurrentDate() {
+    const today = new Date();
+    const year = today.getFullYear();
+    const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
+    const day = String(today.getDate()).padStart(2, "0");
+    return `${year}-${month}-${day}`;
+  }
 </script>
 
 <style scoped lang="scss">
-.account-detail {
-  min-height: 100vh;
-  background: #f8f9fa;
-  padding-bottom: 80px;
-}
+  @import "@/static/scss/form-common.scss";
 
-.header {
-  display: flex;
-  align-items: center;
-  background: #fff;
-  padding: 16px 20px;
-  border-bottom: 1px solid #f0f0f0;
-  position: sticky;
-  top: 0;
-  z-index: 100;
-}
-
-.title {
-  flex: 1;
-  text-align: center;
-  font-size: 18px;
-  font-weight: 600;
-  color: #333;
-}
-
-.form-section {
-  margin-top: 16px;
-}
-
-.van-field {
-  height: 56px;
-  line-height: 36px;
-}
-
-.product-section {
-  background: #fff;
-  margin: 16px;
-  border-radius: 16px;
-  padding: 20px 16px 8px 16px;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
-}
-
-.section-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: 12px;
-}
-
-.section-title {
-  font-size: 16px;
-  font-weight: 600;
-  color: #333;
-}
-
-.add-btn {
-  background: #2979ff;
-  color: #fff;
-  border-radius: 8px;
-  padding: 4px 16px;
-  font-size: 14px;
-}
-
-.product-card {
-  background: #f8f9fa;
-  border-radius: 12px;
-  padding: 12px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(41, 121, 255, 0.06);
-  position: relative;
-}
-
-.product-row {
-  display: flex;
-  align-items: center;
-  margin-bottom: 8px;
-}
-
-.product-label {
-  min-width: 60px;
-  color: #888;
-  font-size: 13px;
-}
-
-.del-row {
-  justify-content: flex-end;
-}
-
-.del-btn {
-  background: #ff4d4f;
-  color: #fff;
-  border-radius: 8px;
-  padding: 4px 16px;
-  font-size: 13px;
-  margin-top: 4px;
-}
-
-.approval-process {
-  background: #fff;
-  margin: 16px;
-  border-radius: 16px;
-  padding: 16px;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
-}
-
-.approval-header {
-  margin-bottom: 16px;
-}
-
-.approval-title {
-  font-size: 16px;
-  font-weight: 600;
-  color: #333;
-  display: block;
-  margin-bottom: 4px;
-}
-
-.approval-desc {
-  font-size: 12px;
-  color: #999;
-}
-
-.approval-steps {
-  padding-left: 16px;
-  position: relative;
-}
-
-.approval-step {
-  position: relative;
-  margin-bottom: 20px;
-}
-
-.step-title {
-  margin-bottom: 12px;
-}
-
-.step-title text {
-  font-size: 14px;
-  color: #666;
-  background: #f0f0f0;
-  padding: 2px 8px;
-  border-radius: 4px;
-}
-
-.approvers-container {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 12px;
-  margin-bottom: 8px;
-}
-
-.approver-item {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  width: 60px;
-}
-
-.approver-avatar {
-  width: 40px;
-  height: 40px;
-  background: #e6f7ff;
-  border-radius: 50%;
-  margin-bottom: 4px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.approver-avatar::after {
-  content: '馃懁';
-  font-size: 20px;
-}
-
-.approver-name {
-  font-size: 12px;
-  color: #333;
-  text-align: center;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  margin-bottom: 2px;
-}
-
-.delete-approver-btn {
-  font-size: 12px;
-  color: #ff4d4f;
-  background: rgba(255, 77, 79, 0.1);
-  width: 16px;
-  height: 16px;
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-top: 2px;
-}
-
-.delete-step-btn {
-  margin-top: 8px;
-  color: #ff4d4f;
-  font-size: 12px;
-  background: rgba(255, 77, 79, 0.1);
-  padding: 2px 8px;
-  border-radius: 4px;
-  display: inline-block;
+  .approval-process {
+    background: #fff;
+    margin: 16px;
+    border-radius: 16px;
+    padding: 16px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
   }
 
-.add-approver-btn {
-  width: 40px;
-  height: 40px;
-  border: 1px dashed #ccc;
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 20px;
-  color: #999;
-  margin-top: 8px;
-}
+  .approval-header {
+    margin-bottom: 16px;
+  }
 
-.step-line {
-  position: absolute;
-  left: 20px;
-  top: 100%;
-  width: 1px;
-  height: 30px;
-  background: #e0e0e0;
-}
+  .approval-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+    display: block;
+    margin-bottom: 4px;
+  }
 
-.add-step-btn {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-top: 16px;
-  color: #006cfb;
-  font-size: 14px;
-  padding: 8px 0;
-  border: 1px dashed #006cfb;
-  border-radius: 8px;
-}
+  .approval-desc {
+    font-size: 12px;
+    color: #999;
+  }
 
-.footer-btns {
-  position: fixed;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: #fff;
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  padding: 12px 0;
-  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
-  z-index: 1000;
-}
+  /* 鏍峰紡澧炲己涓衡�滅畝娲佸皬鍦嗗湀椋庢牸鈥� */
+  .approval-steps {
+    padding-left: 22px;
+    position: relative;
 
-.cancel-btn {
-  font-weight: 400;
-  font-size: 16px;
-  color: #ffffff;
-  width: 102px;
-  background: #c7c9cc;
-  box-shadow: 0px 4px 10px 0px rgba(3, 88, 185, 0.2);
-  border-radius: 40px 40px 40px 40px;
-}
+    &::before {
+      content: "";
+      position: absolute;
+      left: 11px;
+      top: 40px;
+      bottom: 40px;
+      width: 2px;
+      background: linear-gradient(
+        to bottom,
+        #e6f7ff 0%,
+        #bae7ff 50%,
+        #91d5ff 100%
+      );
+      border-radius: 1px;
+    }
+  }
 
-.save-btn {
-  font-weight: 400;
-  font-size: 16px;
-  color: #ffffff;
-  width: 224px;
-  background: linear-gradient(140deg, #00baff 0%, #006cfb 100%);
-  box-shadow: 0px 4px 10px 0px rgba(3, 88, 185, 0.2);
-  border-radius: 40px 40px 40px 40px;
-}
+  .approval-step {
+    position: relative;
+    margin-bottom: 24px;
+
+    &::before {
+      content: "";
+      position: absolute;
+      left: -18px;
+      top: 14px; // 浠� 8px 璋冩暣涓� 14px锛屼笌鏂囧瓧涓績瀵归綈
+      width: 12px;
+      height: 12px;
+      background: #fff;
+      border: 3px solid #006cfb;
+      border-radius: 50%;
+      z-index: 2;
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    }
+  }
+
+  .step-title {
+    top: 12px;
+    margin-bottom: 12px;
+    position: relative;
+    margin-left: 6px;
+  }
+
+  .step-title text {
+    font-size: 14px;
+    color: #666;
+    background: #f0f0f0;
+    padding: 4px 12px;
+    border-radius: 12px;
+    position: relative;
+    line-height: 1.4; // 纭繚鏂囧瓧琛岄珮涓�鑷�
+  }
+
+  .approver-item {
+    display: flex;
+    align-items: center;
+    background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
+    border-radius: 16px;
+    padding: 16px;
+    gap: 12px;
+    position: relative;
+    border: 1px solid #e6f7ff;
+    box-shadow: 0 4px 12px rgba(0, 108, 251, 0.08);
+    transition: all 0.3s ease;
+  }
+
+  .approver-avatar {
+    width: 48px;
+    height: 48px;
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: relative;
+    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
+  }
+
+  .avatar-text {
+    color: #fff;
+    font-size: 18px;
+    font-weight: 600;
+    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+  }
+
+  .approver-info {
+    flex: 1;
+    position: relative;
+  }
+
+  .approver-name {
+    display: block;
+    font-size: 16px;
+    color: #333;
+    font-weight: 500;
+    position: relative;
+  }
+
+  .approver-dept {
+    font-size: 12px;
+    color: #999;
+    background: rgba(0, 108, 251, 0.05);
+    padding: 2px 8px;
+    border-radius: 8px;
+    display: inline-block;
+    position: relative;
+
+    &::before {
+      content: "";
+      position: absolute;
+      left: 4px;
+      top: 50%;
+      transform: translateY(-50%);
+      width: 2px;
+      height: 2px;
+      background: #006cfb;
+      border-radius: 50%;
+    }
+  }
+
+  .delete-approver-btn {
+    font-size: 16px;
+    color: #ff4d4f;
+    background: linear-gradient(
+      135deg,
+      rgba(255, 77, 79, 0.1) 0%,
+      rgba(255, 77, 79, 0.05) 100%
+    );
+    width: 28px;
+    height: 28px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.3s ease;
+    position: relative;
+  }
+
+  .add-approver-btn {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: linear-gradient(135deg, #f0f8ff 0%, #e6f7ff 100%);
+    border: 2px dashed #006cfb;
+    border-radius: 16px;
+    padding: 20px;
+    color: #006cfb;
+    font-size: 14px;
+    position: relative;
+    transition: all 0.3s ease;
+
+    &::before {
+      content: "";
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+      width: 32px;
+      height: 32px;
+      border: 2px solid #006cfb;
+      border-radius: 50%;
+      opacity: 0;
+      transition: all 0.3s ease;
+    }
+  }
+
+  .delete-step-btn {
+    color: #ff4d4f;
+    font-size: 12px;
+    background: linear-gradient(
+      135deg,
+      rgba(255, 77, 79, 0.1) 0%,
+      rgba(255, 77, 79, 0.05) 100%
+    );
+    padding: 6px 12px;
+    border-radius: 12px;
+    display: inline-block;
+    position: relative;
+    transition: all 0.3s ease;
+
+    &::before {
+      content: "";
+      position: absolute;
+      left: 6px;
+      top: 50%;
+      transform: translateY(-50%);
+      width: 4px;
+      height: 4px;
+      background: #ff4d4f;
+      border-radius: 50%;
+    }
+  }
+
+  .step-line {
+    display: none; // 闅愯棌鍘熸潵鐨勭嚎鏉★紝浣跨敤浼厓绱犱唬鏇�
+  }
+
+  .add-step-btn {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+  .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-weight: 400;
+    font-size: 1rem;
+    color: #ffffff;
+    width: 6.375rem;
+    background: #c7c9cc;
+    box-shadow: 0 0.25rem 0.625rem 0 rgba(3, 88, 185, 0.2);
+    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
+  }
+
+  .save-btn {
+    font-weight: 400;
+    font-size: 1rem;
+    color: #ffffff;
+    width: 14rem;
+    background: linear-gradient(140deg, #00baff 0%, #006cfb 100%);
+    box-shadow: 0 0.25rem 0.625rem 0 rgba(3, 88, 185, 0.2);
+    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
+  }
+
+  // 鍔ㄧ敾瀹氫箟
+  @keyframes pulse {
+    0% {
+      transform: scale(1);
+      opacity: 1;
+    }
+    50% {
+      transform: scale(1.2);
+      opacity: 0.7;
+    }
+    100% {
+      transform: scale(1);
+      opacity: 1;
+    }
+  }
+
+  @keyframes rotate {
+    0% {
+      transform: rotate(0deg);
+    }
+    100% {
+      transform: rotate(360deg);
+    }
+  }
+
+  @keyframes ripple {
+    0% {
+      transform: translate(-50%, -50%) scale(0.8);
+      opacity: 1;
+    }
+    100% {
+      transform: translate(-50%, -50%) scale(1.6);
+      opacity: 0;
+    }
+  }
+
+  /* 濡傛灉宸叉湁 .step-line锛岃繖閲屾洿绮惧噯瀹氫綅鍒板乏渚т笌灏忓渾鐐瑰榻� */
+  .step-line {
+    position: absolute;
+    left: 4px;
+    top: 48px;
+    width: 2px;
+    height: calc(100% - 48px);
+    background: #e5e7eb;
+  }
+
+  .approver-container {
+    display: flex;
+    align-items: center;
+    background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
+    border-radius: 16px;
+    gap: 12px;
+    padding: 10px 0;
+    background: transparent;
+    border: none;
+    box-shadow: none;
+  }
+
+  .approver-item {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    padding: 8px 10px;
+    background: transparent;
+    border: none;
+    box-shadow: none;
+    border-radius: 0;
+  }
+
+  .approver-avatar {
+    position: relative;
+    width: 40px;
+    height: 40px;
+    border-radius: 50%;
+    background: #f3f4f6;
+    border: 2px solid #e5e7eb;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    animation: none; /* 绂佺敤鏃嬭浆绛夊姩鐢伙紝鍥炲綊绠�娲� */
+  }
+
+  .avatar-text {
+    font-size: 14px;
+    color: #374151;
+    font-weight: 600;
+  }
+
+  .add-approver-btn {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    background: transparent;
+    border: none;
+    box-shadow: none;
+    padding: 0;
+  }
+
+  .add-approver-btn .add-circle {
+    width: 40px;
+    height: 40px;
+    border: 2px dashed #a0aec0;
+    border-radius: 50%;
+    color: #6b7280;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 22px;
+    line-height: 1;
+  }
+
+  .add-approver-btn .add-label {
+    color: #3b82f6;
+    font-size: 14px;
+  }
 </style>
\ No newline at end of file

--
Gitblit v1.9.3