zhangwencui
13 小时以前 b973bcee308e99b5fd8a69640f11069e810346f4
采购台账重构
已修改3个文件
1424 ■■■■ 文件已修改
src/api/procurementManagement/procurementLedger.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/procurementLedger/detail.vue 1291 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/procurementLedger/index.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/procurementLedger.js
@@ -72,3 +72,10 @@
    method: "get",
  });
}
export function approveProcessGetInfo(query) {
    return request({
        url: '/approveProcess/get',
        method: 'get',
        params: query,
    })
}
src/pages/procurementManagement/procurementLedger/detail.vue
@@ -1,128 +1,184 @@
<template>
  <view class="account-detail">
    <!-- 使用通用页面头部组件 -->
        <PageHeader title="台账详情" @back="goBack" />
    <PageHeader title="台账详情"
                @back="goBack" />
         <!-- 表单区域 -->
        <up-form @submit="onSubmit" label-width="110" ref="formRef" :rules="rules" :model="form">
                <up-form-item label="采购合同号" prop="purchaseContractNumber">
                    <up-input v-model="form.purchaseContractNumber" placeholder="自动生成" disabled />
    <up-form @submit="onSubmit"
             label-width="110"
             ref="formRef"
             :rules="rules"
             :model="form">
      <up-form-item label="采购合同号"
                    prop="purchaseContractNumber">
        <up-input v-model="form.purchaseContractNumber"
                  placeholder="自动生成"
                  disabled />
                </up-form-item>
                <up-form-item
                    label="销售合同号"
      <up-form-item label="销售合同号"
                    prop="salesContractNo"
                    required
                    @click="showPicker = true"
                >
                    <up-input
                        v-model="form.salesContractNo"
                    @click="showPicker = true">
        <up-input v-model="form.salesContractNo"
                        readonly=""
                        @click="showPicker = true"
                        placeholder="点击选择销售合同号"
                    />
                  placeholder="点击选择销售合同号" />
                    <template #right>
                        <up-icon
                            name="arrow-right"
                            @click="showPicker = true"
                        ></up-icon>
          <up-icon name="arrow-right"
                   @click="showPicker = true"></up-icon>
                    </template>
                </up-form-item>
                <up-form-item
                    label="供应商名称"
      <up-form-item label="供应商名称"
                    prop="supplierName"
                    required
                    @click="showCustomerPicker = true"
                >
                    <up-input
                        v-model="form.supplierName"
                    @click="showCustomerPicker = true">
        <up-input v-model="form.supplierName"
                        readonly=""
                        @click="showCustomerPicker = true"
                        placeholder="点击选择供应商"
                    />
                  placeholder="点击选择供应商" />
                    <template #right>
                        <up-icon
                            name="arrow-right"
                            @click="showCustomerPicker = true"
                        ></up-icon>
          <up-icon name="arrow-right"
                   @click="showCustomerPicker = true"></up-icon>
                    </template>
                </up-form-item>
                <up-form-item label="项目名称" prop="projectName" required >
                    <up-input
                        v-model="form.projectName"
                        placeholder="请输入项目名称"
                    />
      <up-form-item label="项目名称"
                    prop="projectName"
                    required>
        <up-input v-model="form.projectName"
                  placeholder="请输入项目名称" />
                </up-form-item>
                <up-form-item label="付款方式" prop="paymentMethod" >
                    <up-input v-model="form.paymentMethod" placeholder="请输入付款方式" />
      <up-form-item label="付款方式"
                    prop="paymentMethod">
        <up-input v-model="form.paymentMethod"
                  placeholder="请输入付款方式" />
                </up-form-item>
                <up-form-item label="录入人" prop="recorderName" >
                    <up-input v-model="form.recorderName" placeholder="请输入" disabled />
      <up-form-item label="签订日期"
                    required
                    prop="executionDate">
        <up-input v-model="form.executionDate"
                  placeholder="请选择"
                  readonly="" />
        <template #right>
          <up-icon name="arrow-right"
                   @click="showTimePicker = true"></up-icon>
        </template>
                </up-form-item>
                <up-form-item label="录入日期" prop="entryDate" >
                    <up-input v-model="form.entryDate" placeholder="请输入" disabled />
      <up-form-item label="录入人"
                    prop="recorderName">
        <up-input v-model="form.recorderName"
                  placeholder="请输入"
                  disabled />
                </up-form-item>
      <up-form-item label="录入日期"
                    prop="entryDate">
        <up-input v-model="form.entryDate"
                  placeholder="请输入"
                  disabled />
      </up-form-item>
      <view class="approval-process">
        <view class="approval-header">
          <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 class="step-dot"></view>
            <view class="step-title">
              <text>审批人</text>
            </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 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>
        </view>
        <view class="add-step-btn">
          <u-button icon="plus"
                    plain
                    type="primary"
                    style="width: 100%"
                    @click="addApprovalStep">新增节点</u-button>
        </view>
      </view>
      <up-popup :show="showTimePicker"
                mode="bottom"
                @close="showTimePicker = false">
        <up-datetime-picker :show="true"
                            v-model="currentDate"
                            @confirm="onDateConfirm"
                            @cancel="showTimePicker = false"
                            mode="date" />
      </up-popup>
                <!-- 销售合同号选择 -->
                <up-action-sheet
                    :show="showPicker"
      <up-action-sheet :show="showPicker"
                    :actions="salesContractActionList"
                    title="选择销售合同号"
                    @select="onSalesmanSelect"
                    @close="showPicker = false"
                />
                       @close="showPicker = false" />
                <!-- 供应商选择 -->
                <up-action-sheet
                    :show="showCustomerPicker"
      <up-action-sheet :show="showCustomerPicker"
                    :actions="supplierActionList"
                    title="选择供应商"
                    @select="onCustomerSelect"
                    @close="showCustomerPicker = false"
                />
                       @close="showCustomerPicker = false" />
                <!-- 产品大类选择器 -->
                <up-popup :show="showCategoryPicker" mode="bottom">
      <up-popup :show="showCategoryPicker"
                mode="bottom">
                    <!-- 头部按钮区域 -->
                    <view class="popup-header">
                        <view @click="showCategoryPicker = false" class="cancelButton">取消</view>
                        <view @click="confirmCategorySelection" class="confirmButton">确定</view>
          <view @click="showCategoryPicker = false"
                class="cancelButton">取消</view>
          <view @click="confirmCategorySelection"
                class="confirmButton">确定</view>
                    </view>
                    <u-tree
                        :data="productOptions"
        <u-tree :data="productOptions"
                        :props="defaultProps"
                        show-checkbox
                        default-expand-all
                        check-strictly
                        @check-change="onCategoryConfirm"
                    />
                @check-change="onCategoryConfirm" />
                </up-popup>
                <!-- 规格型号选择器 -->
                <up-action-sheet
                    :show="showSpecificationPicker"
      <up-action-sheet :show="showSpecificationPicker"
                    :actions="specificationActionList"
                    title="选择规格型号"
                    @select="onSpecificationSelect"
                    @close="showSpecificationPicker = false"
                />
                       @close="showSpecificationPicker = false" />
                <!-- 税率选择器 -->
                <up-action-sheet
                    :show="showTaxRatePicker"
      <up-action-sheet :show="showTaxRatePicker"
                    :actions="taxRateActionList"
                    title="选择税率"
                    @select="onTaxRateSelect"
                    @close="showTaxRatePicker = false"
                />
                       @close="showTaxRatePicker = false" />
                <!-- 发票类型选择器 -->
                <up-action-sheet
                    :show="showInvoiceTypePicker"
      <up-action-sheet :show="showInvoiceTypePicker"
                    :actions="invoiceTypeActionList"
                    title="选择发票类型"
                    @select="onInvoiceTypeSelect"
                    @close="showInvoiceTypePicker = false"
                />
                       @close="showInvoiceTypePicker = false" />
                <!-- 产品信息 -->
                <view class="product-section">
                    <view class="section-header">
@@ -130,254 +186,240 @@
                        <text class="section-title">产品信息</text>
                        </view>
                        <view>
                            <up-button type="primary" size="small" @click="addProduct" class="add-btn" v-if="operationType !== 'view'">
            <up-button type="primary"
                       size="small"
                       @click="addProduct"
                       class="add-btn"
                       v-if="operationType !== 'view'">
                            新增
                        </up-button>
                        </view>
                    </view>
                    <view class="product-card" v-for="(product, idx) in productData" :key="idx">
        <view class="product-card"
              v-for="(product, idx) in productData"
              :key="idx">
                        <!-- 产品类 -->
                        <view class="product-header">
                            <view class="product-title">
                                <up-icon name="file-text" size="16" color="#2979ff"></up-icon>
              <up-icon name="file-text"
                       size="16"
                       color="#2979ff"></up-icon>
                                <text class="product-productCategory">产品 {{ idx + 1 }}</text>
                            </view>
                            <!-- 操作按钮 -->
                            <view class="product-actions" v-if="operationType !== 'view'">
                                <up-button type="error" size="mini" @click="removeProduct(idx)" class="del-btn">
            <view class="product-actions"
                  v-if="operationType !== 'view'">
              <up-button type="error"
                         size="mini"
                         @click="removeProduct(idx)"
                         class="del-btn">
                                    删除
                                </up-button>
                            </view>
                        </view>
                        <!-- 产品信息表单 -->
                        <view class="product-form">
                            <!-- 产品大类 -->
                            <up-form-item
                                label="产品大类"
            <up-form-item label="产品大类"
                                prop="productCategory"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.productCategory"
                          :rules="productRules">
              <up-input v-model="product.productCategory"
                                    readonly
                                    placeholder="请选择"
                                    @click="openCategoryPicker(idx)"
                                />
                        @click="openCategoryPicker(idx)" />
                                <template #right>
                                    <up-icon
                                        name="arrow-right"
                                        @click="showCategoryPicker = true"
                                    ></up-icon>
                <up-icon name="arrow-right"
                         @click="showCategoryPicker = true"></up-icon>
                                </template>
                            </up-form-item>
                            <!-- 规格型号 -->
                            <up-form-item
                                label="规格型号"
            <up-form-item label="规格型号"
                                prop="specificationModel"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.specificationModel"
                          :rules="productRules">
              <up-input v-model="product.specificationModel"
                                    readonly
                                    placeholder="请选择"
                                    @click="openSpecificationPicker(idx)"
                                />
                        @click="openSpecificationPicker(idx)" />
                                <template #right>
                                    <up-icon
                                        name="arrow-right"
                                        @click="showSpecificationPicker = true"
                                    ></up-icon>
                <up-icon name="arrow-right"
                         @click="showSpecificationPicker = true"></up-icon>
                                </template>
                            </up-form-item>
                            <!-- 单位 -->
                            <up-form-item
                                label="单位"
            <up-form-item label="单位"
                                prop="unit"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.unit"
                                    placeholder="请输入"
                                />
                          :rules="productRules">
              <up-input v-model="product.unit"
                        placeholder="请输入" />
                            </up-form-item>
                            <!-- 税率 -->
                            <up-form-item
                                label="税率(%)"
            <up-form-item label="税率(%)"
                                prop="taxRate"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.taxRate"
                          :rules="productRules">
              <up-input v-model="product.taxRate"
                                    readonly
                                    placeholder="请选择"
                                    @click="openTaxRatePicker(idx)"
                                />
                        @click="openTaxRatePicker(idx)" />
                                <template #right>
                                    <up-icon
                                        name="arrow-right"
                                        @click="showTaxRatePicker = true"
                                    ></up-icon>
                <up-icon name="arrow-right"
                         @click="showTaxRatePicker = true"></up-icon>
                                </template>
                            </up-form-item>
                            <!-- 含税单价 -->
                            <up-form-item
                                label="含税单价(元)"
            <up-form-item label="含税单价(元)"
                                prop="taxInclusiveUnitPrice"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.taxInclusiveUnitPrice"
                          :rules="productRules">
              <up-input v-model="product.taxInclusiveUnitPrice"
                                    type="number"
                                    placeholder="请输入"
                                    @blur="formatTaxPrice(idx)"
                                />
                        @blur="formatTaxPrice(idx)" />
                            </up-form-item>
                            <!-- 数量 -->
                            <up-form-item
                                label="数量"
            <up-form-item label="数量"
                                prop="quantity"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.quantity"
                          :rules="productRules">
              <up-input v-model="product.quantity"
                                    type="number"
                                    placeholder="请输入"
                                    @blur="formatAmount(idx)"
                                />
                        @blur="formatAmount(idx)" />
                            </up-form-item>
                            <!-- 含税总价 -->
                            <up-form-item
                                label="含税总价(元)"
            <up-form-item label="含税总价(元)"
                                prop="taxInclusiveTotalPrice"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.taxInclusiveTotalPrice"
                          :rules="productRules">
              <up-input v-model="product.taxInclusiveTotalPrice"
                                    type="number"
                                    placeholder="请输入"
                                    @blur="formatTaxTotal(idx)"
                                />
                        @blur="formatTaxTotal(idx)" />
                            </up-form-item>
                            <!-- 不含税总价 -->
                            <up-form-item
                                label="不含税总价(元)"
            <up-form-item label="不含税总价(元)"
                                prop="taxExclusiveTotalPrice"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.taxExclusiveTotalPrice"
                          :rules="productRules">
              <up-input v-model="product.taxExclusiveTotalPrice"
                                    type="number"
                                    placeholder="请输入"
                                    @blur="formatNoTaxTotal(idx)"
                                />
                        @blur="formatNoTaxTotal(idx)" />
                            </up-form-item>
                            <!-- 发票类型 -->
                            <up-form-item
                                label="发票类型"
            <up-form-item label="发票类型"
                                prop="invoiceType"
                                required
                                :rules="productRules"
                            >
                                <up-input
                                    v-model="product.invoiceType"
                          :rules="productRules">
              <up-input v-model="product.invoiceType"
                                    readonly
                                    placeholder="请选择"
                                    @click="openInvoiceTypePicker(idx)"
                                />
                        @click="openInvoiceTypePicker(idx)" />
                                <template #right>
                                    <up-icon
                                        name="arrow-right"
                                        @click="showInvoiceTypePicker = true"
                                    ></up-icon>
                <up-icon name="arrow-right"
                         @click="showInvoiceTypePicker = true"></up-icon>
                                </template>
            </up-form-item>
            <!-- 库存预警数量 -->
            <up-form-item label="库存预警数量"
                          prop="warnNum"
                          required
                          :rules="productRules">
              <up-input v-model="product.warnNum"
                        type="number"
                        placeholder="请输入" />
            </up-form-item>
            <up-form-item label="是否质检"
                          prop="invoiceType"
                          required
                          :rules="productRules">
              <u-radio-group v-model="product.isChecked"
                             placement="row"
                             @change="groupChange">
                <u-radio :customStyle="{marginRight: '40rpx'}"
                         label="是"
                         :name="true">
                </u-radio>
                <u-radio label="否"
                         :name="false">
                </u-radio>
              </u-radio-group>
                            </up-form-item>
                        </view>
                    </view>
                </view>
                <!-- 使用公共底部按钮组件 -->
                <FooterButtons
                    :show="operationType !== 'view'"
      <FooterButtons :show="operationType !== 'view'"
                    cancelText="取消"
                    confirmText="保存"
                    @cancel="goBack"
                    @confirm="onSubmit"
                />
                     @confirm="onSubmit" />
        </up-form>
  </view>
</template>
<script setup>
import {onMounted, ref, computed} from 'vue';
  import { onMounted, ref, computed } from "vue";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useUserStore from "@/store/modules/user";
import {calculateTaxExclusiveTotalPrice} from "@/utils/summarizeTable";
import {formatDateToYMD} from '@/utils/ruoyi'
  import { formatDateToYMD } from "@/utils/ruoyi";
import {
    addOrEditPurchase, createPurchaseNo,
    addOrEditPurchase,
    createPurchaseNo,
    getOptions,
    getPurchaseById,
    getSalesNo
    getSalesNo,
    approveProcessGetInfo,
} from "@/api/procurementManagement/procurementLedger";
import PageHeader from '@/components/PageHeader.vue';
import FooterButtons from '@/components/FooterButtons.vue';
  import PageHeader from "@/components/PageHeader.vue";
  import FooterButtons from "@/components/FooterButtons.vue";
  import { userListNoPageByTenantId } from "@/api/system/user";
// 获取页面参数
const operationType = ref('');
  const operationType = ref("");
const editData = ref(null);
const formRef = ref(null);
const userStore = useUserStore()
  const userStore = useUserStore();
const form = ref({
    id: '',
  salesContractNo: '',
    purchaseContractNumber: '',
    supplierId: '',
    supplierName: '',
    projectName: '',
  paymentMethod: '',
    recorderId: '',
    recorderName: '',
    entryDate: '',
    id: "",
    salesContractNo: "",
    purchaseContractNumber: "",
    supplierId: "",
    supplierName: "",
    projectName: "",
    paymentMethod: "",
    recorderId: "",
    recorderName: "",
    entryDate: "",
    approveUserIds: "",
    executionDate: "",
});
  const showTimePicker = ref(false);
const showPicker = ref(false);
const showCustomerPicker = ref(false);
const salesContractList = ref([]);
const supplierList = ref([]);
const productData = ref([]);
  const currentDate = ref(Date.now());
// 计算销售合同号选择列表
const salesContractActionList = computed(() => {
    return salesContractList.value.map(item => ({
        name: item.text,
        value: item.value
    }))
})
      value: item.value,
    }));
  });
// 计算供应商选择列表
const supplierActionList = computed(() => {
    return supplierList.value.map(item => ({
        name: item.text,
        value: item.value
    }))
})
      value: item.value,
    }));
  });
// 选择器相关变量
const showCategoryPicker = ref(false);
@@ -390,21 +432,21 @@
const productOptions = ref([]);
const selectedCategoryNode = ref(null);
const defaultProps = ref({
    children: 'children',
    label: 'label',
    nodeKey: 'id'
    children: "children",
    label: "label",
    nodeKey: "id",
});
const modelOptions = ref([]);
const taxRateOptions = ref([
  { text: '1', value: '1' },
  { text: '6', value: '6' },
  { text: '13', value: '13' },
    { text: "1", value: "1" },
    { text: "6", value: "6" },
    { text: "13", value: "13" },
]);
const invoiceTypeOptions = ref([
  { text: '增普票', value: '增普票' },
  { text: '增专票', value: '增专票' },
    { text: "增普票", value: "增普票" },
    { text: "增专票", value: "增专票" },
]);
// 计算规格型号选择列表
@@ -412,143 +454,154 @@
    return modelOptions.value.map(model => ({
        name: model.text,
        value: model.value,
        unit: model.unit
    }))
})
      unit: model.unit,
    }));
  });
// 计算税率选择列表
const taxRateActionList = computed(() => {
    return taxRateOptions.value.map(rate => ({
        name: rate.text,
        value: rate.value
    }))
})
      value: rate.value,
    }));
  });
// 计算发票类型选择列表
const invoiceTypeActionList = computed(() => {
    return invoiceTypeOptions.value.map(type => ({
        name: type.text,
        value: type.value
    }))
})
      value: type.value,
    }));
  });
// 表单校验规则
const rules = {
    salesContractNo: [
        { required: true, message: '请选择销售合同号', trigger: 'blur' }
      { required: true, message: "请选择销售合同号", trigger: "blur" },
    ],
    supplierName: [
        { required: true, message: '请选择供应商名称', trigger: 'blur' }
      { required: true, message: "请选择供应商名称", trigger: "blur" },
    ],
    projectName: [
        { required: true, message: '请输入项目名称', trigger: 'blur' }
    ]
    projectName: [{ required: true, message: "请输入项目名称", trigger: "blur" }],
    executionDate: [
      { required: true, message: "请选择签订日期", trigger: "blur" },
    ],
};
// 产品信息校验规则
const productRules = {
    productCategory: [
        { required: true, message: '请选择产品大类', trigger: 'blur' }
      { required: true, message: "请选择产品大类", trigger: "blur" },
    ],
    specificationModel: [
        { required: true, message: '请选择规格型号', trigger: 'blur' }
      { required: true, message: "请选择规格型号", trigger: "blur" },
    ],
    unit: [
        { required: true, message: '请输入单位', trigger: 'blur' }
    ],
    taxRate: [
        { required: true, message: '请选择税率', trigger: 'blur' }
    ],
    unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
    taxRate: [{ required: true, message: "请选择税率", trigger: "blur" }],
    taxInclusiveUnitPrice: [
        { required: true, message: '请输入含税单价', trigger: 'blur' },
        { type: 'number', min: 0, message: '含税单价必须大于0', trigger: 'blur' }
      { required: true, message: "请输入含税单价", trigger: "blur" },
      { type: "number", min: 0, message: "含税单价必须大于0", trigger: "blur" },
    ],
    quantity: [
        { required: true, message: '请输入数量', trigger: 'blur' },
        { type: 'number', min: 0, message: '数量必须大于0', trigger: 'blur' }
      { required: true, message: "请输入数量", trigger: "blur" },
      { type: "number", min: 0, message: "数量必须大于0", trigger: "blur" },
    ],
    taxInclusiveTotalPrice: [
        { required: true, message: '请输入含税总价', trigger: 'blur' },
        { type: 'number', min: 0, message: '含税总价必须大于0', trigger: 'blur' }
      { required: true, message: "请输入含税总价", trigger: "blur" },
      { type: "number", min: 0, message: "含税总价必须大于0", trigger: "blur" },
    ],
    taxExclusiveTotalPrice: [
        { required: true, message: '请输入不含税总价', trigger: 'blur' },
        { type: 'number', min: 0, message: '不含税总价必须大于0', trigger: 'blur' }
      { required: true, message: "请输入不含税总价", trigger: "blur" },
      { type: "number", min: 0, message: "不含税总价必须大于0", trigger: "blur" },
    ],
    invoiceType: [
        { required: true, message: '请选择发票类型', trigger: 'blur' }
    ]
    invoiceType: [{ required: true, message: "请选择发票类型", trigger: "blur" }],
    warnNum: [
      { required: true, message: "请输入库存预警数量", trigger: "blur" },
      {
        type: "number",
        min: 0,
        message: "库存预警数量必须大于0",
        trigger: "blur",
      },
    ],
};
const addProduct = () => {
    if (productData.value === null) {
        productData.value = []
      productData.value = [];
    }
    productData.value.push({
    productCategory: '',
    specificationModel: '',
        productModelId: '',
    unit: '',
    taxRate: '',
    taxInclusiveUnitPrice: '',
    quantity: '',
    taxInclusiveTotalPrice: '',
    taxExclusiveTotalPrice: '',
    invoiceType: ''
      productCategory: "",
      specificationModel: "",
      productModelId: "",
      unit: "",
      taxRate: "",
      taxInclusiveUnitPrice: "",
      quantity: "",
      taxInclusiveTotalPrice: "",
      taxExclusiveTotalPrice: "",
      invoiceType: "",
      isChecked: false,
      warnNum: "",
  });
};
// 销售合同号选择事件
const onSalesmanSelect = (item) => {
    form.value.salesContractNo = item.name
  const onSalesmanSelect = item => {
    form.value.salesContractNo = item.name;
    // 查找对应的id
    const selectedItem = salesContractList.value.find(contract => contract.text === item.name);
    const selectedItem = salesContractList.value.find(
      contract => contract.text === item.name
    );
    if (selectedItem) {
        form.value.salesLedgerId = selectedItem.value;
    }
    showPicker.value = false;
}
  };
// 供应商选择事件
const onCustomerSelect = (item) => {
    form.value.supplierName = item.name
  const onCustomerSelect = item => {
    form.value.supplierName = item.name;
    // 查找对应的id
    const selectedItem = supplierList.value.find(supplier => supplier.text === item.name);
    const selectedItem = supplierList.value.find(
      supplier => supplier.text === item.name
    );
    if (selectedItem) {
        form.value.supplierId = selectedItem.value;
    }
    showCustomerPicker.value = false;
}
  };
const removeProduct = (idx) => {
  const removeProduct = idx => {
    productData.value.splice(idx, 1);
};
// 显示选择器
const openCategoryPicker = (idx) => {
  const openCategoryPicker = idx => {
  currentProductIndex.value = idx;
  showCategoryPicker.value = true;
};
const openSpecificationPicker = (idx) => {
  const openSpecificationPicker = idx => {
  currentProductIndex.value = idx;
  showSpecificationPicker.value = true;
};
const openTaxRatePicker = (idx) => {
  const openTaxRatePicker = idx => {
  currentProductIndex.value = idx;
  showTaxRatePicker.value = true;
};
const openInvoiceTypePicker = (idx) => {
  const openInvoiceTypePicker = idx => {
  currentProductIndex.value = idx;
  showInvoiceTypePicker.value = true;
};
// 选择器确认事件
const onCategoryConfirm = (node) => {
  const onCategoryConfirm = node => {
    // 获取选中的节点信息
    console.log('selected node---', node);
    console.log("selected node---", node);
    // 存储选中的节点,用于确认时获取数据
    selectedCategoryNode.value = node;
};
@@ -557,20 +610,21 @@
const confirmCategorySelection = () => {
    if (selectedCategoryNode.value) {
        // 设置选中的产品大类
        productData.value[currentProductIndex.value].productCategory = selectedCategoryNode.value.label;
        const id = selectedCategoryNode.value.id
      productData.value[currentProductIndex.value].productCategory =
        selectedCategoryNode.value.label;
      const id = selectedCategoryNode.value.id;
        // 重置选中的节点
        selectedCategoryNode.value = null;
        productData.value[currentProductIndex.value].specificationModel = ''
        productData.value[currentProductIndex.value].productModelId = ''
        getModels(id)
      productData.value[currentProductIndex.value].specificationModel = "";
      productData.value[currentProductIndex.value].productModelId = "";
      getModels(id);
    }
    showCategoryPicker.value = false;
};
// 获取规格型号
const getModels = (value) => {
    modelList({ id: value }).then((res) => {
  const getModels = value => {
    modelList({ id: value }).then(res => {
        modelOptions.value = res.map(user => ({
            text: user.model,
            value: user.id,
@@ -580,34 +634,36 @@
};
// 规格型号选择事件
const onSpecificationSelect = (item) => {
    productData.value[currentProductIndex.value].specificationModel = item.name
    productData.value[currentProductIndex.value].productModelId = item.value
    productData.value[currentProductIndex.value].unit = item.unit
  const onSpecificationSelect = item => {
    productData.value[currentProductIndex.value].specificationModel = item.name;
    productData.value[currentProductIndex.value].productModelId = item.value;
    productData.value[currentProductIndex.value].unit = item.unit;
    showSpecificationPicker.value = false;
};
// 税率选择事件
const onTaxRateSelect = (item) => {
    productData.value[currentProductIndex.value].taxRate = item.value
  const onTaxRateSelect = item => {
    productData.value[currentProductIndex.value].taxRate = item.value;
    showTaxRatePicker.value = false;
    // 重新计算不含税总价
    const inclusiveTotalPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveTotalPrice)
    const taxRate = parseFloat(item.value)
    const inclusiveTotalPrice = parseFloat(
      productData.value[currentProductIndex.value].taxInclusiveTotalPrice
    );
    const taxRate = parseFloat(item.value);
    if (inclusiveTotalPrice && taxRate) {
        productData.value[currentProductIndex.value].taxExclusiveTotalPrice = 
            calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate)
        calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
    }
};
// 发票类型选择事件
const onInvoiceTypeSelect = (item) => {
    productData.value[currentProductIndex.value].invoiceType = item.name
  const onInvoiceTypeSelect = item => {
    productData.value[currentProductIndex.value].invoiceType = item.name;
    showInvoiceTypePicker.value = false;
};
// 格式化函数 - 固定两位小数
const formatTaxPrice = (idx) => {
  const formatTaxPrice = idx => {
  if (productData.value[idx].taxInclusiveUnitPrice) {
    const value = parseFloat(productData.value[idx].taxInclusiveUnitPrice);
    if (!isNaN(value)) {
@@ -616,19 +672,25 @@
  }
    if (!productData.value[currentProductIndex.value].taxRate) {
        uni.showToast({
            title: '请先选择税率',
            icon: 'none'
        title: "请先选择税率",
        icon: "none",
        });
        return;
    }
    const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
    const unitPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveUnitPrice);
    const quantity = parseFloat(
      productData.value[currentProductIndex.value].quantity
    );
    const unitPrice = parseFloat(
      productData.value[currentProductIndex.value].taxInclusiveUnitPrice
    );
    
    if (!quantity || quantity <= 0 || !unitPrice) {
        return;
    }
    // 计算含税总价
    productData.value[currentProductIndex.value].taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
    productData.value[currentProductIndex.value].taxInclusiveTotalPrice = (
      unitPrice * quantity
    ).toFixed(2);
    
    // 如果有税率,计算不含税总价
    if (productData.value[currentProductIndex.value].taxRate) {
@@ -641,7 +703,7 @@
};
// 数量输入框失焦
const formatAmount = (idx) => {
  const formatAmount = idx => {
  if (productData.value[idx].quantity) {
    const value = parseFloat(productData.value[idx].quantity);
    if (!isNaN(value)) {
@@ -650,19 +712,25 @@
  }
    if (!productData.value[currentProductIndex.value].taxRate) {
        uni.showToast({
            title: '请先选择税率',
            icon: 'none'
        title: "请先选择税率",
        icon: "none",
        });
        return;
    }
    const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
    const unitPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveUnitPrice);
    const quantity = parseFloat(
      productData.value[currentProductIndex.value].quantity
    );
    const unitPrice = parseFloat(
      productData.value[currentProductIndex.value].taxInclusiveUnitPrice
    );
    
    if (!quantity || quantity <= 0 || !unitPrice) {
        return;
    }
    // 计算含税总价
    productData.value[currentProductIndex.value].taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
    productData.value[currentProductIndex.value].taxInclusiveTotalPrice = (
      unitPrice * quantity
    ).toFixed(2);
    // 如果有税率,计算不含税总价
    if (productData.value[currentProductIndex.value].taxRate) {
        productData.value[currentProductIndex.value].taxExclusiveTotalPrice = 
@@ -674,21 +742,27 @@
};
// 含税总价失焦,根据含税总价计算含税单价和数量
const formatTaxTotal = (idx) => {
  const formatTaxTotal = idx => {
  if (productData.value[idx].taxInclusiveTotalPrice) {
    const value = parseFloat(productData.value[idx].taxInclusiveTotalPrice);
    if (!isNaN(value)) {
            productData.value[idx].taxInclusiveTotalPrice = value.toFixed(2);
    }
  }
    const totalPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveTotalPrice);
    const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
    const totalPrice = parseFloat(
      productData.value[currentProductIndex.value].taxInclusiveTotalPrice
    );
    const quantity = parseFloat(
      productData.value[currentProductIndex.value].quantity
    );
    
    if (!totalPrice || !quantity || quantity <= 0) {
        return;
    }
    // 计算含税单价 = 含税总价 / 数量
    productData.value[currentProductIndex.value].taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
    productData.value[currentProductIndex.value].taxInclusiveUnitPrice = (
      totalPrice / quantity
    ).toFixed(2);
    // 如果有税率,计算不含税总价
    if (productData.value[currentProductIndex.value].taxRate) {
        productData.value[currentProductIndex.value].taxExclusiveTotalPrice = 
@@ -700,7 +774,7 @@
};
// 不含税总价失焦, 根据不含税总价计算含税单价和数量
const formatNoTaxTotal = (idx) => {
  const formatNoTaxTotal = idx => {
  if (productData.value[idx].taxExclusiveTotalPrice) {
    const value = parseFloat(productData.value[idx].taxExclusiveTotalPrice);
    if (!isNaN(value)) {
@@ -709,47 +783,74 @@
  }
    if (!productData.value[currentProductIndex.value].taxRate) {
        uni.showToast({
            title: '请先选择税率',
            icon: 'none'
        title: "请先选择税率",
        icon: "none",
        });
        return;
    }
    const exclusiveTotalPrice = parseFloat(productData.value[currentProductIndex.value].taxExclusiveTotalPrice);
    const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
    const taxRate = parseFloat(productData.value[currentProductIndex.value].taxRate);
    const exclusiveTotalPrice = parseFloat(
      productData.value[currentProductIndex.value].taxExclusiveTotalPrice
    );
    const quantity = parseFloat(
      productData.value[currentProductIndex.value].quantity
    );
    const taxRate = parseFloat(
      productData.value[currentProductIndex.value].taxRate
    );
    if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
        return;
    }
    // 先计算含税总价 = 不含税总价 / (1 - 税率/100)
    const taxRateDecimal = taxRate / 100;
    const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
    productData.value[currentProductIndex.value].taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
    productData.value[currentProductIndex.value].taxInclusiveTotalPrice =
      inclusiveTotalPrice.toFixed(2);
    // 计算含税单价 = 含税总价 / 数量
    productData.value[currentProductIndex.value].taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
    productData.value[currentProductIndex.value].taxInclusiveUnitPrice = (
      inclusiveTotalPrice / quantity
    ).toFixed(2);
};
const goBack = () => {
    // 清理本地存储的数据
    uni.removeStorageSync('operationType');
    uni.removeStorageSync('editData');
    uni.removeStorageSync("operationType");
    uni.removeStorageSync("editData");
    uni.navigateBack();
};
const onSubmit = () => {
    const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
    if (hasEmptyApprover) {
      uni.showToast({
        title: "请为所有审批节点选择审批人!",
        icon: "none",
      });
      return;
    }
    const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
    if (productData.value !== null && productData.value.length > 0) {
        form.value.productData = JSON.parse(JSON.stringify(productData.value));
    } else {
        uni.showToast({
            title: '请添加产品信息',
            icon: 'none'
        title: "请添加产品信息",
        icon: "none",
        });
        return
      return;
    }
    // 如果salesLedgerId为空,则不传递salesContractNo
    if (!form.value.salesLedgerId) {
      form.value.salesContractNo = "";
    }
    if (operationType.value == "add") {
      delete form.value.id;
    }
    form.value.approveUserIds = approveUserIds;
    form.value.type = 2;
    addOrEditPurchase(form.value).then((res) => {
    addOrEditPurchase(form.value).then(res => {
        uni.showToast({
            title: '提交成功',
            icon: 'success',
        title: "提交成功",
        icon: "success",
        });
        goBack();
    });
@@ -759,54 +860,83 @@
    form.value.recorderId = userStore.id;
    form.value.recorderName = userStore.nickName;
    // 设置当天日期
    const today = new Date()
    const year = today.getFullYear()
    const month = String(today.getMonth() + 1).padStart(2, '0')
    const day = String(today.getDate()).padStart(2, '0')
    form.value.entryDate = `${year}-${month}-${day}`
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    const day = String(today.getDate()).padStart(2, "0");
    form.value.entryDate = `${year}-${month}-${day}`;
  };
  // 确认日期选择
  const onDateConfirm = e => {
    form.value.executionDate = formatDateToYMD(e.value);
    currentDate.value = e.value;
    showTimePicker.value = false;
};
// 填充表单数据(编辑模式)
const fillFormData = () => {
  if (!editData.value) return;
    getPurchaseById({ id: editData.value.id, type: 2 }).then((res) => {
    getPurchaseById({ id: editData.value.id, type: 2 }).then(res => {
        productData.value = res.productData;
      if (res && res.approveUserIds) {
        const userIds = res.approveUserIds.split(",");
        approverNodes.value = userIds.map((userId, idx) => {
          const userIdNum = parseInt(userId.trim());
          // 从userList中找到对应的用户信息
          console.log(userList.value, "userList.value");
          const userInfo = userList.value.find(user => user.userId === userIdNum);
          return {
            id: idx + 1,
            userId: userIdNum,
            nickName: userInfo ? userInfo.nickName : null,
          };
    });
    console.log(editData.value)
        nextApproverId = userIds.length + 1;
      } else {
        // 新增模式,初始化一个空的审批节点
        approverNodes.value = [{ id: 1, userId: null, nickName: null }];
        nextApproverId = 2;
      }
    });
    console.log(editData.value);
  // 填充基本信息
  form.value.salesContractNo = editData.value.salesContractNo || '';
  form.value.supplierName = editData.value.supplierName || '';
  form.value.projectName = editData.value.projectName || '';
  form.value.paymentMethod = editData.value.paymentMethod || '';
  form.value.salesLedgerId = editData.value.salesLedgerId || '';
  form.value.recorderId = editData.value.recorderId || '';
  form.value.recorderName = editData.value.recorderName || '';
  form.value.entryDate = editData.value.entryDate || '';
  form.value.id = editData.value.id || '';
  form.value.supplierId = editData.value.supplierId || '';
    form.value.purchaseContractNumber =
      editData.value.purchaseContractNumber || "";
    form.value.salesContractNo = editData.value.salesContractNo || "";
    form.value.supplierName = editData.value.supplierName || "";
    form.value.projectName = editData.value.projectName || "";
    form.value.paymentMethod = editData.value.paymentMethod || "";
    form.value.salesLedgerId = editData.value.salesLedgerId || "";
    form.value.recorderId = editData.value.recorderId || "";
    form.value.recorderName = editData.value.recorderName || "";
    form.value.entryDate = editData.value.entryDate || "";
    form.value.id = editData.value.id || "";
    form.value.supplierId = editData.value.supplierId || "";
    form.value.executionDate = editData.value.executionDate || "";
};
const getSalesNoList = () => {
    getSalesNo().then((res) => {
    getSalesNo().then(res => {
        // 将用户数据组装成 picker 需要的格式
        salesContractList.value = res.map(user => ({
            text: user.salesContractNo,
            value: user.id
        value: user.id,
        }));
    })
    });
};
const getOptionsLIst = () => {
    getOptions().then((res) => {
    getOptions().then(res => {
        // 将用户数据组装成 picker 需要的格式
        supplierList.value = res.data.map(item => ({
            text: item.supplierName,
            value: item.id
        value: item.id,
        }));
    })
    });
};
const convertIdToValue = (data) => {
  const convertIdToValue = data => {
    // 如果传入的不是数组,则返回空数组
    if (!Array.isArray(data)) {
        return [];
@@ -819,7 +949,11 @@
            id: item.id,       // 保留 id
        };
        // 如果存在 children 数组,则递归处理
        if (item.children && Array.isArray(item.children) && item.children.length > 0) {
      if (
        item.children &&
        Array.isArray(item.children) &&
        item.children.length > 0
      ) {
            mappedItem.children = convertIdToValue(item.children);
        }
        return mappedItem;
@@ -828,48 +962,481 @@
// 获取产品大类tree数据
const getProductOptions = () => {
    productTreeList().then((res) => {
    productTreeList().then(res => {
        productOptions.value = convertIdToValue(res);
    });
};
  const approverNodes = ref([]);
  let nextApproverId = 2;
  const userList = ref([]);
onMounted(() => {
    // 获取页面参数
    operationType.value = uni.getStorageSync('operationType') || '';
    operationType.value = uni.getStorageSync("operationType") || "";
    userListNoPageByTenantId().then(res => {
      userList.value = res.data;
    });
    // 获取销售合同号列表
    getSalesNoList()
    getSalesNoList();
    // 获取供应商列表
    getOptionsLIst()
    getOptionsLIst();
    // 获取产品大类tree数据
    getProductOptions()
    getProductOptions();
    // 赋值默认信息
    if (operationType.value === 'add') {
        setUserInfo()
        createPurchaseNo().then((res) => {
    if (operationType.value === "add") {
      setUserInfo();
      createPurchaseNo().then(res => {
            form.value.purchaseContractNumber = res.data;
        });
    }
    
    // 监听联系人选择事件
    uni.$on("selectContact", handleSelectContact);
    // 获取编辑数据并填充表单
    const editDataStr = uni.getStorageSync('editData');
    const editDataStr = uni.getStorageSync("editData");
    if (editDataStr) {
        try {
            editData.value = JSON.parse(editDataStr);
            // 如果是编辑模式,等待数据加载完成后填充表单数据
            if (operationType.value !== 'add' && editData.value) {
        if (operationType.value !== "add" && editData.value) {
                // 使用 nextTick 确保数据加载完成后再填充
                setTimeout(() => {
                    fillFormData();
                }, 100);
            }
        } catch (error) {
            console.error('解析编辑数据失败:', error);
        console.error("解析编辑数据失败:", error);
        }
    } else {
      approverNodes.value = [{ id: 1, userId: null }];
    }
});
  // 处理联系人选择结果
  const handleSelectContact = data => {
    const { stepIndex, contact } = data;
    // 将选中的联系人设置为对应审批步骤的审批人
    console.log(contact);
    console.log(stepIndex, "stepIndex");
    console.log(approverNodes.value[stepIndex], "审批人");
    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 });
    console.log(approverNodes.value, "approverNodes.value");
  };
  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",
      });
    }
  };
</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;
      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>
src/pages/procurementManagement/procurementLedger/index.vue
@@ -1,43 +1,49 @@
<template>
    <view class="sales-account">
        <!-- 使用通用页面头部组件 -->
        <PageHeader title="采购台账" @back="goBack" />
    <PageHeader title="采购台账"
                @back="goBack" />
        <!-- 搜索和筛选区域 -->
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <up-input
                        class="search-text"
          <up-input class="search-text"
                        placeholder="请输入采购合同号搜索"
                        v-model="purchaseContractNumber"
                        @change="getList"
                        clearable
                    />
                    clearable />
                </view>
                <view class="filter-button" @click="getList">
                    <up-icon name="search" size="24" color="#999"></up-icon>
        <view class="filter-button"
              @click="getList">
          <up-icon name="search"
                   size="24"
                   color="#999"></up-icon>
                </view>
            </view>
        </view>
        <!-- 采购台账瀑布流 -->
        <view class="ledger-list" v-if="ledgerList.length > 0">
            <view v-for="(item, index) in ledgerList" :key="index">
                <view class="ledger-item" @click="handleInfo('edit', item)">
    <view class="ledger-list"
          v-if="ledgerList.length > 0">
      <view v-for="(item, index) in ledgerList"
            :key="index">
        <view class="ledger-item"
              @click="handleInfo('edit', item)">
                    <view class="item-header">
                        <view class="item-left">
                            <view class="document-icon">
                                <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
                <up-icon name="file-text"
                         size="16"
                         color="#ffffff"></up-icon>
                            </view>
                            <text class="item-id">{{ item.purchaseContractNumber }}</text>
                        </view>
                        <!--                            <view class="item-tag">-->
                        <!--                                <text class="tag-text">{{ item.recorder }}</text>-->
                        <!--                            </view>-->
            <view class="item-tag">
              <u-tag :type="getApprovalStatusType(item.approvalStatus)">
                {{ approvalStatusText[item.approvalStatus] || '未知状态' }}
              </u-tag>
            </view>
                    </view>
                    <up-divider></up-divider>
                    <view class="item-details">
                        <view class="detail-row">
                            <text class="detail-label">销售合同号</text>
@@ -74,27 +80,45 @@
                </view>
            </view>
        </view>
        <view v-else class="no-data">
    <view v-else
          class="no-data">
            <text>暂无采购台账数据</text>
        </view>
        <!-- 浮动操作按钮 -->
        <view class="fab-button" @click="handleInfo('add')">
            <up-icon name="plus" size="24" color="#ffffff"></up-icon>
    <view class="fab-button"
          @click="handleInfo('add')">
      <up-icon name="plus"
               size="24"
               color="#ffffff"></up-icon>
        </view>
    </view>
</template>
<script setup>
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
  import { ref } from "vue";
  import { onShow } from "@dcloudio/uni-app";
import useUserStore from "@/store/modules/user";
import PageHeader from "@/components/PageHeader.vue";
import {purchaseListPage} from "@/api/procurementManagement/procurementLedger";
const userStore = useUserStore()
  const userStore = useUserStore();
  const approvalStatusText = {
    1: "待审核",
    2: "审批中",
    3: "审批通过",
    4: "审批失败",
  };
  // 获取审批状态标签类型
  const getApprovalStatusType = status => {
    const typeMap = {
      1: "info", // 待审核 - 灰色
      2: "warning", // 审批中 - 橙色
      3: "success", // 审批通过 - 绿色
      4: "error", // 审批失败 - 红色
    };
    return typeMap[status] || "";
  };
// 搜索关键词
const purchaseContractNumber = ref('');
  const purchaseContractNumber = ref("");
// 采购台账数据
const ledgerList = ref([]);
@@ -105,24 +129,29 @@
};
// 查询列表
const getList = () => {
    showLoadingToast('加载中...')
    showLoadingToast("加载中...");
    const page = {
        current: -1,
        size: -1
    }
    purchaseListPage({...page, purchaseContractNumber: purchaseContractNumber.value}).then((res) => {
      size: -1,
    };
    purchaseListPage({
      ...page,
      purchaseContractNumber: purchaseContractNumber.value,
    })
      .then(res => {
        ledgerList.value = res.data.records;
        closeToast()
    }).catch(() => {
        closeToast()
        closeToast();
      })
      .catch(() => {
        closeToast();
    });
};
// 显示加载提示
const showLoadingToast = (message) => {
  const showLoadingToast = message => {
    uni.showLoading({
        title: message,
        mask: true
      mask: true,
    });
};
@@ -135,15 +164,15 @@
const handleInfo = (type, row) => {
  try {
    // 设置操作类型
    uni.setStorageSync('operationType', type);
      uni.setStorageSync("operationType", type);
    
    // 如果是查看或编辑操作
    if (type !== 'add') {
      if (type !== "add") {
      // 验证行数据是否存在
      if (!row) {
        uni.showToast({
          title: '数据不存在',
          icon: 'error'
            title: "数据不存在",
            icon: "error",
        });
        return;
      }
@@ -151,31 +180,30 @@
      // 检查权限:只有录入人才能编辑
      if (row.recorderName != userStore.nickName) {
        // 非录入人跳转到只读详情页面
        uni.setStorageSync('editData', JSON.stringify(row));
          uni.setStorageSync("editData", JSON.stringify(row));
        uni.navigateTo({
          url: '/pages/procurementManagement/procurementLedger/view'
            url: "/pages/procurementManagement/procurementLedger/view",
        });
        return;
      }
      
      // 录入人编辑:存储数据并跳转到编辑页面
      uni.setStorageSync('editData', JSON.stringify(row));
        uni.setStorageSync("editData", JSON.stringify(row));
      uni.navigateTo({
        url: '/pages/procurementManagement/procurementLedger/detail'
          url: "/pages/procurementManagement/procurementLedger/detail",
      });
      return;
    }
    
    // 新增操作:直接跳转到编辑页面
    uni.navigateTo({
      url: '/pages/procurementManagement/procurementLedger/detail'
        url: "/pages/procurementManagement/procurementLedger/detail",
    });
  } catch (error) {
    console.error('处理台账信息操作失败:', error);
      console.error("处理台账信息操作失败:", error);
    uni.showToast({
      title: '操作失败,请重试',
      icon: 'error'
        title: "操作失败,请重试",
        icon: "error",
    });
  }
};
@@ -187,7 +215,7 @@
</script>
<style scoped lang="scss">
@import '@/styles/procurement-common.scss';
  @import "@/styles/procurement-common.scss";
// 采购台账特有样式(如有需要可在此添加)
</style>