zhangwencui
2026-01-15 ae56bfe58933e4ffbbed0fe4df2586637cd5c56d
重构协同办公-协同审批相关页面
已添加3个文件
已修改3个文件
1661 ■■■■■ 文件已修改
src/pages.json 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/detail.vue 1538 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/index5.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/index6.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/index7.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json
@@ -268,6 +268,34 @@
      }
    },
    {
      "path": "pages/cooperativeOffice/collaborativeApproval/index4",
      "style": {
        "navigationBarTitleText": "报销管理",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/cooperativeOffice/collaborativeApproval/index5",
      "style": {
        "navigationBarTitleText": "采购管理",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/cooperativeOffice/collaborativeApproval/index6",
      "style": {
        "navigationBarTitleText": "报价管理",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/cooperativeOffice/collaborativeApproval/index7",
      "style": {
        "navigationBarTitleText": "出库管理",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/cooperativeOffice/collaborativeApproval/index",
      "style": {
        "navigationBarTitleText": "审批管理",
@@ -419,8 +447,8 @@
      "style": {
        "navigationBarTitleText": "巡检上传",
        "navigationStyle": "custom",
                "enablePullDownRefresh": true,
                "backgroundColor": "#f8f8f8"
        "enablePullDownRefresh": true,
        "backgroundColor": "#f8f8f8"
      }
    },
    {
@@ -709,4 +737,4 @@
    "navigationBarTitleText": "RuoYi",
    "navigationBarBackgroundColor": "#FFFFFF"
  }
}
}
src/pages/cooperativeOffice/collaborativeApproval/detail.vue
@@ -1,130 +1,133 @@
<template>
  <view class="account-detail">
    <PageHeader title="审批流程" @back="goBack" />
    <PageHeader title="审批流程"
                @back="goBack" />
    <!-- è¡¨å•区域 -->
    <u-form ref="formRef" @submit="submitForm" :rules="rules" :model="form" label-width="140rpx">
      <u-form-item prop="approveReason" label="申请事由" required>
        <u-input
          v-model="form.approveReason"
          type="textarea"
          rows="2"
          auto-height
          maxlength="200"
          placeholder="请输入申请事由"
          show-word-limit
        />
    <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="approveDeptName" label="申请部门" required>
        <u-input
          v-model="form.approveDeptName"
          readonly
          placeholder="请选择申请部门"
          @click="showPicker = true"
        />
      <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>
          <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 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"
        />
      <u-form-item prop="approveTime"
                   label="申请日期"
                   required>
        <u-input v-model="form.approveTime"
                 readonly
                 placeholder="请选择"
                 @click="showDatePicker" />
      </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"
          />
        <u-form-item prop="startDate"
                     label="请假开始时间"
                     required>
          <u-input v-model="form.startDate"
                   readonly
                   placeholder="请选择开始时间"
                   @click="showStartDatePicker" />
        </u-form-item>
        <u-form-item prop="endDate" label="请假结束时间" required>
          <u-input
            v-model="form.endDate"
            readonly
            placeholder="请选择结束时间"
            @click="showEndDatePicker"
          />
        <u-form-item prop="endDate"
                     label="请假结束时间"
                     required>
          <u-input v-model="form.endDate"
                   readonly
                   placeholder="请选择结束时间"
                   @click="showEndDatePicker" />
        </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 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 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-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 :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 :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 :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">
@@ -132,15 +135,17 @@
        <text class="approval-title">审核流程</text>
        <text class="approval-desc">每个步骤只能选择一个审批人</text>
      </view>
      <view class="approval-steps">
        <view v-for="(step, stepIndex) in approverNodes" :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="approver-container">
            <view v-if="step.nickName" class="approver-item">
            <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>
@@ -148,702 +153,751 @@
              <view class="approver-info">
                <text class="approver-name">{{ step.nickName }}</text>
              </view>
              <view class="delete-approver-btn" @click="removeApprover(stepIndex)">×</view>
              <view class="delete-approver-btn"
                    @click="removeApprover(stepIndex)">×</view>
            </view>
            <view v-else 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 < approverNodes.length - 1"></view>
          <view class="delete-step-btn" v-if="approverNodes.length > 1" @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">
            <u-button icon="plus" plain type="primary" style="width: 100%" @click="addApprovalStep">新增节点</u-button>
        <u-button icon="plus"
                  plain
                  type="primary"
                  style="width: 100%"
                  @click="addApprovalStep">新增节点</u-button>
      </view>
    </view>
    <!-- åº•部按钮 -->
    <view class="footer-btns">
      <u-button class="cancel-btn" @click="goBack">取消</u-button>
      <u-button class="save-btn" @click="submitForm">保存</u-button>
      <u-button class="cancel-btn"
                @click="goBack">取消</u-button>
      <u-button class="save-btn"
                @click="submitForm">保存</u-button>
    </view>
  </view>
</template>
<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'
    })
}
import {userListNoPageByTenantId} from "@/api/system/user";
  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",
    });
  };
  import { userListNoPageByTenantId } from "@/api/system/user";
const data = reactive({
    form: {
        approveTime: "",
        approveId: "",
        approveUser: "",
        approveUserName: "",
        approveDeptName: "",
        approveDeptId: "",
        approveReason: "",
        checkResult: "",
        tempFileIds: [],
        approverList: [], // æ–°å¢žå­—段,存储所有节点的审批人id
        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 getProductOptions = () => {
    getDept().then((res) => {
        productOptions.value = res.data.map(item => ({
            value: item.deptId,
            name: item.deptName
        }))
    });
};
const fileList = ref([]);
let nextApproverId = 2;
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();
        // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å–å‚æ•°
        operationType.value = uni.getStorageSync('operationType') || 'add';
        approveType.value = uni.getStorageSync('approveType') || 0;
        // å¦‚果是编辑模式,从本地存储获取数据
        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;
                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());
                            // ä»ŽuserList中找到对应的用户信息
                            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 {
            // æ–°å¢žæ¨¡å¼ï¼Œåˆå§‹åŒ–一个空的审批节点
            approverNodes.value = [{ id: 1, userId: null }];
        }
    // ç›‘听联系人选择事件
    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
  const data = reactive({
    form: {
      approveTime: "",
      approveId: "",
      approveUser: "",
      approveUserName: "",
      approveDeptName: "",
      approveDeptId: "",
      approveReason: "",
      checkResult: "",
      tempFileIds: [],
      approverList: [], // æ–°å¢žå­—段,存储所有节点的审批人id
      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" }],
    },
  });
  showPicker.value = false;
};
  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 goBack = () => {
    // æ¸…除本地存储的数据
  uni.removeStorageSync('operationType');
    uni.removeStorageSync('invoiceLedgerEditRow');
    uni.removeStorageSync('approveType');
  uni.navigateBack();
};
  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 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) {
      // è¡¨å•校验通过,可以提交数据
      // æ”¶é›†æ‰€æœ‰èŠ‚ç‚¹çš„å®¡æ‰¹äººid
      console.log('approverNodes---', approverNodes.value)
      form.value.approveUserIds = approverNodes.value.map(node => node.userId).join(',')
      form.value.approveType = approveType.value
      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;
      // å¦‚果是编辑模式,从本地存储获取数据
      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;
          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());
                  // ä»ŽuserList中找到对应的用户信息
                  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 {
        // æ–°å¢žæ¨¡å¼ï¼Œåˆå§‹åŒ–一个空的审批节点
        approverNodes.value = [{ id: 1, userId: null }];
      }
      // ç›‘听联系人选择事件
      uni.$on("selectContact", handleSelectContact);
    } catch (error) {
      console.error("获取部门数据失败:", error);
    }
    // æ˜¾ç¤ºé€šç”¨é”™è¯¯ä¿¡æ¯
    uni.showToast({
      title: '表单校验失败,请检查必填项',
      icon: 'none'
    });
  });
};
// å¤„理联系人选择结果
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"
  onUnmounted(() => {
    // ç§»é™¤äº‹ä»¶ç›‘听
    uni.$off("selectContact", handleSelectContact);
  });
};
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 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) {
          // è¡¨å•校验通过,可以提交数据
          // æ”¶é›†æ‰€æœ‰èŠ‚ç‚¹çš„å®¡æ‰¹äººid
          console.log("approverNodes---", approverNodes.value);
          form.value.approveUserIds = approverNodes.value
            .map(node => node.userId)
            .join(",");
          form.value.approveType = approveType.value;
          console.log("form.value---", form.value);
          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",
        });
      });
  };
  // å¤„理联系人选择结果
  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}`;
  }
};
// æ˜¾ç¤ºæ—¥æœŸé€‰æ‹©å™¨
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">
@import '@/static/scss/form-common.scss';
  @import "@/static/scss/form-common.scss";
.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: 22px;
  position: relative;
  &::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;
  }
}
.approval-step {
  position: relative;
  margin-bottom: 24px;
  &::before {
    content: '';
    position: absolute;
    left: -18px;
    top: 14px; // ä»Ž 8px è°ƒæ•´ä¸º 14px,与文字中心对齐
    width: 12px;
    height: 12px;
  .approval-process {
    background: #fff;
    border: 3px solid #006cfb;
    border-radius: 50%;
    z-index: 2;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    margin: 16px;
    border-radius: 16px;
    padding: 16px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  }
}
.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%;
  .approval-header {
    margin-bottom: 16px;
  }
}
.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;
}
  .approval-title {
    font-size: 16px;
    font-weight: 600;
    color: #333;
    display: block;
    margin-bottom: 4px;
  }
.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;
  .approval-desc {
    font-size: 12px;
    color: #999;
  }
  /* æ ·å¼å¢žå¼ºä¸ºâ€œç®€æ´å°åœ†åœˆé£Žæ ¼â€ */
  .approval-steps {
    padding-left: 22px;
    position: relative;
    &::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;
    }
  }
  .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;
  }
}
.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;
  .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);
  }
}
.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;
  .avatar-text {
    color: #fff;
    font-size: 18px;
    font-weight: 600;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  }
  50% {
    transform: scale(1.2);
    opacity: 0.7;
  .approver-info {
    flex: 1;
    position: relative;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  .approver-name {
    display: block;
    font-size: 16px;
    color: #333;
    font-weight: 500;
    position: relative;
  }
}
@keyframes rotate {
  0% {
    transform: rotate(0deg);
  .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%;
    }
  }
  100% {
    transform: rotate(360deg);
  .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;
  }
}
@keyframes ripple {
  0% {
    transform: translate(-50%, -50%) scale(0.8);
    opacity: 1;
  .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;
    }
  }
  100% {
    transform: translate(-50%, -50%) scale(1.6);
    opacity: 0;
  .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,这里更精准定位到左侧与小圆点对齐 */
.step-line {
  position: absolute;
  left: 4px;
  top: 48px;
  width: 2px;
  height: calc(100% - 48px);
  background: #E5E7EB;
}
  .step-line {
    display: none; // éšè—åŽŸæ¥çš„çº¿æ¡ï¼Œä½¿ç”¨ä¼ªå…ƒç´ ä»£æ›¿
  }
.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;
}
  .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;
  }
.approver-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
}
  .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;
  }
.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; /* ç¦ç”¨æ—‹è½¬ç­‰åŠ¨ç”»ï¼Œå›žå½’ç®€æ´ */
}
  .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;
  }
.avatar-text {
  font-size: 14px;
  color: #374151;
  font-weight: 600;
}
  // åŠ¨ç”»å®šä¹‰
  @keyframes pulse {
    0% {
      transform: scale(1);
      opacity: 1;
    }
    50% {
      transform: scale(1.2);
      opacity: 0.7;
    }
    100% {
      transform: scale(1);
      opacity: 1;
    }
  }
.add-approver-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
}
  @keyframes rotate {
    0% {
      transform: rotate(0deg);
    }
    100% {
      transform: rotate(360deg);
    }
  }
.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;
}
  @keyframes ripple {
    0% {
      transform: translate(-50%, -50%) scale(0.8);
      opacity: 1;
    }
    100% {
      transform: translate(-50%, -50%) scale(1.6);
      opacity: 0;
    }
  }
.add-approver-btn .add-label {
  color: #3B82F6;
  font-size: 14px;
}
  /* å¦‚果已有 .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>
src/pages/cooperativeOffice/collaborativeApproval/index5.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
<template>
  <view class="container">
    <!-- å¼•å…¥index.vue组件并传递参数 -->
    <ApprovalProcessIndex :approveType="5" />
  </view>
</template>
<script setup>
  import ApprovalProcessIndex from "./index.vue";
</script>
<style scoped>
  .container {
    width: 100%;
    height: 100%;
  }
</style>
src/pages/cooperativeOffice/collaborativeApproval/index6.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
<template>
  <view class="container">
    <!-- å¼•å…¥index.vue组件并传递参数 -->
    <ApprovalProcessIndex :approveType="6" />
  </view>
</template>
<script setup>
  import ApprovalProcessIndex from "./index.vue";
</script>
<style scoped>
  .container {
    width: 100%;
    height: 100%;
  }
</style>
src/pages/cooperativeOffice/collaborativeApproval/index7.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
<template>
  <view class="container">
    <!-- å¼•å…¥index.vue组件并传递参数 -->
    <ApprovalProcessIndex :approveType="7" />
  </view>
</template>
<script setup>
  import ApprovalProcessIndex from "./index.vue";
</script>
<style scoped>
  .container {
    width: 100%;
    height: 100%;
  }
</style>
src/pages/index.vue
@@ -287,6 +287,22 @@
      label: "出差管理",
    },
    {
      icon: "/static/images/icon/chuchaiguanli@2x.png",
      label: "报销管理",
    },
    {
      icon: "/static/images/icon/chuchaiguanli@2x.png",
      label: "采购管理",
    },
    {
      icon: "/static/images/icon/chuchaiguanli@2x.png",
      label: "报价管理",
    },
    {
      icon: "/static/images/icon/chuchaiguanli@2x.png",
      label: "出库管理",
    },
    {
      icon: "/static/images/icon/xietongshenpi@2x.png",
      label: "协同审批",
    },
@@ -457,6 +473,26 @@
      case "出差管理":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index3",
        });
        break;
      case "报销管理":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index4",
        });
        break;
      case "采购管理":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index5",
        });
        break;
      case "报价管理":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index6",
        });
        break;
      case "出库管理":
        uni.navigateTo({
          url: "/pages/cooperativeOffice/collaborativeApproval/index7",
        });
        break;
      case "协同审批":
@@ -702,7 +738,7 @@
        });
      })
      .catch(error => {
        modal.msgError("获取公告数量:", error);
        // modal.msgError("获取公告数量:", error);
      });
  };