周宾
2025-12-17 ad1130e4bd03661df016dc3fd4bf8b60ce8b1ca2
src/pages/cooperativeOffice/collaborativeApproval/detail.vue
@@ -3,75 +3,129 @@
    <PageHeader title="审批流程" @back="goBack" />
    <!-- 表单区域 -->
    <view class="form-section">
      <van-form ref="formRef" @submit="submitForm" :rules="rules" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center">
            <van-cell-group style="margin-bottom: 16px;">
               <van-field
                  v-model="form.approveReason"
                  name="approveReason"
                  rows="2"
                  autosize
                  label="申请事由"
                  type="textarea"
                  maxlength="200"
                  :rules="[{ required: true, message: '申请事由不能为空' }]"
                  placeholder="请输入申请事由"
                  show-word-limit
                  required
               />
            </van-cell-group>
            <van-cell-group>
               <van-field
                  v-model="form.approveDeptName"
                  readonly
                  name="picker"
                  label="申请部门"
                  placeholder="请选择申请部门"
                  :rules="[{ required: true, message: '请选择申请部门' }]"
    <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-item>
      <u-form-item prop="approveDeptName" label="申请部门" required>
        <u-input
          v-model="form.approveDeptName"
          readonly
          placeholder="请选择申请部门"
          @click="showPicker = true"
        />
        <template #right>
               <up-icon
                  name="arrow-right"
                  @click="showPicker = true"
                  required
               />
          <van-field
            v-model="form.approveUserName"
            name="taxPrice"
            label="申请人"
            placeholder="请输入申请人"
            :rules="[{ required: true, message: '申请人不能为空' }]"
            required
               ></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"
        />
      </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"
          />
          <van-popup
            v-model:show="showPicker"
            position="bottom"
          >
            <van-picker
              :columns="productOptions"
              :model-value="pickerValue"
              @confirm="onConfirm"
              @cancel="showPicker = false"
            />
          </van-popup>
               <van-field
                  v-model="form.approveTime"
                  label="申请日期"
                  placeholder="请选择"
                  readonly
                  required
                  @click="showDatePicker"
                  :rules="[{ required: true, message: '请选择来款日期' }]"
               />
               <!-- 日期选择器 -->
               <van-popup v-model:show="showDate" position="bottom">
                  <van-date-picker
                     v-model="currentDate"
                     title="选择日期"
                     @confirm="onDateConfirm"
                     @cancel="showDate = false"
                  />
               </van-popup>
        </van-cell-group>
      </van-form>
    </view>
        </u-form-item>
        <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>
      <!-- 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">
@@ -107,14 +161,14 @@
      </view>
      <view class="add-step-btn">
            <van-button icon="plus" plain type="primary" style="width: 100%" @click="addApprovalStep">新增节点</van-button>
         <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>
@@ -123,8 +177,14 @@
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";
import { showToast } from 'vant'
const showToast = (message) => {
   uni.showToast({
      title: message,
      icon: 'none'
   })
}
import {userListNoPageByTenantId} from "@/api/system/user";
const data = reactive({
@@ -138,20 +198,26 @@
      approveReason: "",
      checkResult: "",
      tempFileIds: [],
      approverList: [] // 新增字段,存储所有节点的审批人id
      approverList: [], // 新增字段,存储所有节点的审批人id
      startDate: "",
      endDate: "",
      location: "",
      price: ""
   },
   rules: {
      approveTime: [{ required: false, message: "请输入", trigger: "change" },],
      approveId: [{ required: false, message: "请输入", trigger: "blur" }],
      approveUser: [{ 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 pickerValue = ref([]);
const showPicker = ref(false);
const productOptions = ref([]);
const operationType = ref("");
@@ -161,14 +227,19 @@
const formRef = ref(null);
const message = ref("");
const showDate = ref(false)
const currentDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()])
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,
         text: item.deptName
         name: item.deptName
      }))
   });
};
@@ -185,11 +256,9 @@
      form.value.approveUserName = userStore.nickName
      form.value.approveTime = getCurrentDate();
      
      // 获取URL参数
      const pages = getCurrentPages();
      const currentPage = pages[pages.length - 1];
      const options = currentPage && currentPage.options ? currentPage.options : {};
      operationType.value = options.operationType || 'add';
      // 从本地存储获取参数
      operationType.value = uni.getStorageSync('operationType') || 'add';
      approveType.value = uni.getStorageSync('approveType') || 0;
      
      // 如果是编辑模式,从本地存储获取数据
      if (operationType.value === 'edit') {
@@ -240,16 +309,23 @@
  uni.$off('selectContact', handleSelectContact);
});
const onConfirm = ({ selectedValues, selectedOptions }) => {
  form.value.approveDeptName = selectedOptions[0]?.text;
  form.value.approveDeptId = selectedOptions[0]?.value;
  pickerValue.value = selectedValues;
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();
};
@@ -261,38 +337,59 @@
    return;
  }
  
  formRef.value.validate().then(() => {
    // 表单校验通过,可以提交数据
      // 收集所有节点的审批人id
      console.log('approverNodes---', approverNodes.value)
      form.value.approveUserIds = approverNodes.value.map(node => node.userId).join(',')
      form.value.approveType = 0
      if (operationType.value === "add" || currentApproveStatus.value == 3) {
         approveProcessAdd(form.value).then(res => {
            showToast("提交成功");
            goBack()
         })
      } else {
         approveProcessUpdate(form.value).then(res => {
            showToast("提交成功");
            goBack()
         })
      }
  // 手动检查必填字段,防止因数据类型问题导致的校验失败
  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.length > 0) {
      const firstError = error[0];
      uni.showToast({
        title: firstError.message || '表单校验失败',
        icon: 'none'
      });
    } else {
      uni.showToast({
        title: '表单校验失败,请检查必填项',
        icon: 'none'
      });
    // 尝试获取具体的错误字段
    if (error && error.errors) {
      const firstError = error.errors[0];
      if (firstError) {
        uni.showToast({
          title: firstError.message || '表单校验失败,请检查必填项',
          icon: 'none'
        });
        return;
      }
    }
    // 显示通用错误信息
    uni.showToast({
      title: '表单校验失败,请检查必填项',
      icon: 'none'
    });
  });
};
@@ -306,8 +403,9 @@
const addApprover = (stepIndex) => {
  // 跳转到联系人选择页面
  uni.setStorageSync('stepIndex', stepIndex);
  uni.navigateTo({
    url: `/pages/cooperativeOffice/collaborativeApproval/contactSelect?stepIndex=${stepIndex}`
    url: "/pages/cooperativeOffice/collaborativeApproval/contactSelect"
  });
};
@@ -339,11 +437,33 @@
}
// 确认日期选择
const onDateConfirm = ({ selectedValues }) => {
   form.value.approveTime = selectedValues.join('-')
   currentDate.value = selectedValues
   showDate.value = false
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();
@@ -352,37 +472,11 @@
   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;
}
.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;
}
@import '@/static/scss/form-common.scss';
.approval-process {
  background: #fff;