Selaa lähdekoodia

修改供应商bug

hurx 1 päivä sitten
vanhempi
sitoutus
07694d5ed0

+ 30 - 231
src/views/customer/info/components/BasicInfoTab.vue

@@ -124,12 +124,12 @@
         <el-row :gutter="12" class="form-row">
           <el-col :span="8">
             <el-form-item label="传真:">
-              <el-input v-model="localDetailData.fax" placeholder="请输入传真" @blur="onFaxBlur" :disabled="isViewMode" />
+              <el-input v-model="localDetailData.fax" placeholder="请输入传真" :disabled="isViewMode" />
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item label="企业邮箱:">
-              <el-input v-model="localDetailData.mailbox" placeholder="请输入企业邮箱" :disabled="isViewMode" />
+            <el-form-item label="企业邮箱:" :error="mailboxError">
+              <el-input v-model="localDetailData.mailbox" placeholder="请输入企业邮箱" @blur="onMailboxBlur" :disabled="isViewMode" />
             </el-form-item>
           </el-col>
           <!-- <el-col :span="8">
@@ -251,7 +251,7 @@
         <el-col :span="24">
           <div class="form-item">
             <span class="label">工商地址:</span>
-            <el-input v-model="businessInfo.businessAddress" placeholder="工商地址" style="width: 70%" :disabled="isViewMode" />
+            <el-input v-model="businessInfo.businessAddress" placeholder="工商地址" style="width: 70%" :disabled="true" />
           </div>
         </el-col>
       </el-row>
@@ -288,86 +288,12 @@
         <el-col :span="8" />
       </el-row>
     </div>
-
-    <div class="section-title">ERP供应商信息</div>
-    <el-form :model="erpSupplierInfoForm" label-width="120px" class="detail-form">
-      <el-row :gutter="12" class="form-row">
-        <el-col :span="8">
-          <el-form-item label="采购人员:">
-            <el-select v-model="erpSupplierInfoForm.purchaseId" placeholder="请选择采购人员" class="w-full" filterable :disabled="isViewMode">
-              <el-option v-for="item in erpStaffList" :key="item.staffId" :label="`${item.staffCode} , ${item.staffName}`" :value="item.staffId" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="采购开票类型:">
-            <el-select
-              v-model="erpSupplierInfoForm.purchaseInvoiceNo"
-              placeholder="采购开票类型"
-              class="w-full"
-              filterable
-              :disabled="isViewMode"
-              @change="handInvoiceChange"
-            >
-              <el-option v-for="item in purchaseInvoice" :key="item.value" :label="item.label" :value="item.value" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="单价含税:">
-            <el-select v-model="erpSupplierInfoForm.unitPrice" placeholder="单价含税" class="w-full" filterable :disabled="isViewMode">
-              <el-option v-for="item in unitPriceArr" :key="item.value" :label="item.label" :value="item.value" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row :gutter="12" class="form-row">
-        <el-col :span="8">
-          <el-form-item label="税码:">
-            <el-select v-model="erpSupplierInfoForm.rateId" placeholder="税码" class="w-full" filterable :disabled="isViewMode">
-              <el-option v-for="item in taxrateList" :key="item.id" :label="item.taxrateNo" :value="item.id" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="交易币别:">
-            <el-select v-model="erpSupplierInfoForm.dealCurrencyId" placeholder="请选择交易币别" class="w-full" filterable :disabled="isViewMode">
-              <el-option v-for="item in currencyList" :key="item.id" :label="item.currencyName" :value="item.id" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="账款归属:">
-            <el-input v-model="localDetailData.supplierNo" disabled />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row :gutter="12" class="form-row">
-        <el-col :span="8">
-          <el-form-item label="付款条件:">
-            <el-select v-model="erpSupplierInfoForm.settlementMethod" placeholder="请选择付款条件" class="w-full" filterable :disabled="isViewMode">
-              <el-option v-for="dict in payment_clause" :key="dict.value" :label="dict.label" :value="dict.value" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
   </div>
 </template>
 
 <script setup lang="ts">
 import ImageUpload from '@/components/ImageUpload/index.vue';
 import { ElMessage } from 'element-plus';
-import { listErpSupplierInfo, getErpSupplierInfo } from '@/api/supplier/erpSupplierInfo';
-import { ErpSupplierInfoForm } from '@/api/supplier/erpSupplierInfo/types';
-import { listErpStaff } from '@/api/erpData/erpStaff';
-import { ErpStaffVO } from '@/api/erpData/erpStaff/types';
-import { listComCurrency } from '@/api/company/comCurrency';
-import { listTaxrate } from '@/api/company/taxrate';
-import { ComCurrencyVO } from '@/api/company/comCurrency/types';
-
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { payment_clause } = toRefs<any>(proxy?.useDict('payment_clause'));
 
 const props = defineProps<{
   detailData: any;
@@ -388,26 +314,8 @@ const props = defineProps<{
   formatDate: (date: any) => string;
 }>();
 
-// erp供应商信息
-const erpSupplierInfoForm = reactive<ErpSupplierInfoForm>({
-  id: undefined,
-  supplierId: undefined,
-  purchaseId: undefined,
-  belongingDepartmentId: undefined,
-  status: undefined,
-  remark: undefined,
-  unitPrice: 'True',
-  dealCurrencyId: undefined,
-  accountBelong: undefined,
-  rateId: undefined,
-  purchaseInvoiceId: undefined,
-  purchaseInvoiceNo: undefined,
-  purchaseInvoice: undefined,
-  settlementMethod: undefined
-});
-
 const emit = defineEmits<{
-  (e: 'save', erpSupplierInfo: ErpSupplierInfoForm): void;
+  (e: 'save'): void;
   (e: 'getBusinessInfo'): void;
   (e: 'officeRegionChange', value: string[]): void;
   (e: 'update:selectedOfficeRegion', value: string[]): void;
@@ -417,8 +325,6 @@ const emit = defineEmits<{
   (e: 'update:detailData', value: any): void;
 }>();
 
-const erpStaffList = ref<ErpStaffVO[]>([]);
-
 const localDetailData = computed({
   get: () => props.detailData,
   set: (value) => emit('update:detailData', value)
@@ -429,25 +335,6 @@ const selectedOfficeRegionProxy = computed({
   set: (value) => emit('update:selectedOfficeRegion', value)
 });
 
-const unitPriceArr = ref([
-  { label: '含税', value: 'True' },
-  { label: '不含税', value: 'False' }
-]);
-
-const purchaseInvoice = ref([
-  { label: '优易达专票', value: '0001' },
-  { label: '江西优易云普票', value: '0016' },
-  { label: '江西优易云专票', value: '0006' },
-  { label: '无票', value: '0017' },
-  { label: '新天利泰专票', value: '0003' },
-  { label: '优易达(长沙)-普票', value: '0019' },
-  { label: '优易达(长沙)-专票', value: '0018' },
-  { label: '优易达普票', value: '0010' },
-  { label: '优易智采(江西)-专票', value: '0020' }
-]);
-const taxrateList = ref<any[]>([]);
-const currencyList = ref<ComCurrencyVO[]>([]);
-
 const onOfficeRegionChange = (val: unknown) => {
   emit('officeRegionChange', (val || []) as string[]);
 };
@@ -455,6 +342,8 @@ const onOfficeRegionChange = (val: unknown) => {
 const fixedPhoneError = ref('');
 const fixedPhoneReg = /^(\d{3,4}-?)?\d{7,8}(-\d{1,6})?$/;
 const postCodeError = ref('');
+const mailboxError = ref('');
+const mailboxReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
 
 const validateFixedPhone = (val: unknown) => {
   const v = String(val ?? '').trim();
@@ -470,6 +359,13 @@ const validatePostCode = (val: unknown) => {
   return '';
 };
 
+const validateMailbox = (val: unknown) => {
+  const v = String(val ?? '').trim();
+  if (!v) return '';
+  if (!mailboxReg.test(v)) return '请输入正确的邮箱格式';
+  return '';
+};
+
 const validateFax = (val: unknown) => {
   const v = String(val ?? '').trim();
   if (!v) return '';
@@ -493,45 +389,13 @@ watch(
   { immediate: true }
 );
 
-const handInvoiceChange = (invoiceNo: any) => {
-  const invoice = purchaseInvoice.value.find((invoice) => invoice.value === invoiceNo);
-  erpSupplierInfoForm.purchaseInvoice = invoice?.label;
-};
-
-// 加载税码列表
-const loadTaxrateList = async () => {
-  try {
-    const res = await listTaxrate({
-      isShow: '0',
-      pageNum: 1,
-      pageSize: 1000
-    });
-    taxrateList.value = res.rows || [];
-    // 默认选择第一个
-    if (!erpSupplierInfoForm.rateId && taxrateList.value.length > 0) {
-      erpSupplierInfoForm.rateId = taxrateList.value[0].id;
-    }
-  } catch (error) {}
-};
-
-// 加载币种列表
-const loadCurrencyList = async () => {
-  try {
-    const res = await listComCurrency({
-      isShow: '0',
-      pageNum: 1,
-      pageSize: 1000
-    });
-    currencyList.value = res.rows || [];
-    // 默认选择第一个
-    if (!erpSupplierInfoForm.dealCurrencyId && currencyList.value.length > 0) {
-      erpSupplierInfoForm.dealCurrencyId = currencyList.value[0].id;
-    }
-  } catch (error) {
-    console.error('加载币种列表失败:', error);
-    currencyList.value = [];
-  }
-};
+watch(
+  () => props.detailData?.mailbox,
+  (v) => {
+    mailboxError.value = validateMailbox(v);
+  },
+  { immediate: true }
+);
 
 const onFixedPhoneBlur = () => {
   fixedPhoneError.value = validateFixedPhone(props.detailData?.fixedPhone);
@@ -541,21 +405,15 @@ const onPostCodeBlur = () => {
   postCodeError.value = validatePostCode(props.detailData?.postCode);
 };
 
-// 加载员工列表
-const loadErpStaffList = async () => {
-  try {
-    const query: any = {};
-    const res = await listErpStaff(query);
-    erpStaffList.value = res.rows || [];
-  } catch (error) {
-    console.error('加载员工列表失败:', error);
-  }
-};
 const onFaxBlur = () => {
   const err = validateFax(props.detailData?.fax);
   if (err) ElMessage.warning(err);
 };
 
+const onMailboxBlur = () => {
+  mailboxError.value = validateMailbox(props.detailData?.mailbox);
+};
+
 const onSaveClick = () => {
   const err = validateFixedPhone(props.detailData?.fixedPhone);
   fixedPhoneError.value = err;
@@ -576,75 +434,16 @@ const onSaveClick = () => {
     ElMessage.warning(faxErr);
     return;
   }
-  emit('save', erpSupplierInfoForm);
-};
 
-// 加载ERP供应商信息
-const loadErpSupplierInfo = async (supplierId: string | number) => {
-  if (!supplierId) {
-    console.log('supplierId为空,跳过查询');
+  const mailboxErr = validateMailbox(props.detailData?.mailbox);
+  mailboxError.value = mailboxErr;
+  if (mailboxErr) {
+    ElMessage.warning(mailboxErr);
     return;
   }
 
-  try {
-    const res = await listErpSupplierInfo({ supplierId, pageNum: 1, pageSize: 1 });
-    console.log('ERP供应商信息查询结果:', res);
-
-    if (res.rows && res.rows.length > 0) {
-      const data = res.rows[0];
-      Object.assign(erpSupplierInfoForm, {
-        id: data.id,
-        supplierId: data.supplierId,
-        purchaseId: data.purchaseId,
-        belongingDepartmentId: data.belongingDepartmentId,
-        status: data.status,
-        remark: data.remark,
-        unitPrice: data.unitPrice || 'True',
-        dealCurrencyId: data.dealCurrencyId,
-        accountBelong: data.accountBelong,
-        rateId: data.rateId,
-        purchaseInvoiceId: data.purchaseInvoiceId,
-        purchaseInvoiceNo: data.purchaseInvoiceNo,
-        purchaseInvoice: data.purchaseInvoice,
-        settlementMethod: data.settlementMethod
-      });
-      console.log('ERP供应商信息已回显:', erpSupplierInfoForm);
-    } else {
-      console.log('未查询到ERP供应商信息');
-    }
-  } catch (error) {
-    console.error('加载ERP供应商信息失败:', error);
-  }
+  emit('save');
 };
-
-watch(
-  () => props.detailData?.supplierId,
-  (newId) => {
-    console.log('detailData变化:', props.detailData);
-    console.log('detailData.id变化:', newId);
-    if (newId) {
-      loadErpSupplierInfo(newId);
-    }
-  },
-  { immediate: true }
-);
-
-// 监听付款条件字典加载完成后默认选择第一个
-watch(
-  () => payment_clause.value,
-  (val) => {
-    if (!erpSupplierInfoForm.settlementMethod && val && val.length > 0) {
-      erpSupplierInfoForm.settlementMethod = val[0].value;
-    }
-  },
-  { immediate: true }
-);
-
-onMounted(() => {
-  loadErpStaffList();
-  loadTaxrateList();
-  loadCurrencyList();
-});
 </script>
 
 <style scoped>

+ 6 - 6
src/views/customer/info/components/ContractTab.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="tab-content">
     <div class="info-section">
-      <el-form :model="contractSearchParams" label-width="70px" style="margin-bottom: 20px;">
+      <el-form :model="contractSearchParams" label-width="70px" style="margin-bottom: 20px">
         <el-row :gutter="16">
           <el-col :span="6">
             <el-form-item label="合同编号">
@@ -15,14 +15,14 @@
           </el-col>
           <el-col :span="6">
             <el-form-item label="合同类型">
-              <el-select v-model="contractSearchParams.contractType" placeholder="请选择" clearable filterable style="width: 100%;">
+              <el-select v-model="contractSearchParams.contractType" placeholder="请选择" clearable filterable style="width: 100%">
                 <el-option v-for="item in contractTypeDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="开始时间">
-              <el-date-picker v-model="contractSearchParams.contractStartTime" type="date" placeholder="请选择" style="width: 100%;" />
+              <el-date-picker v-model="contractSearchParams.contractStartTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -30,12 +30,12 @@
         <el-row :gutter="16">
           <el-col :span="6">
             <el-form-item label="结束时间">
-              <el-date-picker v-model="contractSearchParams.contractEndTime" type="date" placeholder="请选择" style="width: 100%;" />
+              <el-date-picker v-model="contractSearchParams.contractEndTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="合同状态">
-              <el-select v-model="contractSearchParams.contractStatus" placeholder="请选择" clearable filterable style="width: 100%;">
+              <el-select v-model="contractSearchParams.contractStatus" placeholder="请选择" clearable filterable style="width: 100%">
                 <el-option v-for="item in contractStatusDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
@@ -99,7 +99,7 @@
         </el-table-column>
       </el-table>
 
-      <div style="margin-top: 20px; display: flex; justify-content: flex-end;">
+      <div style="margin-top: 20px; display: flex; justify-content: flex-end">
         <el-pagination
           v-model:current-page="contractPagination.pageNum"
           v-model:page-size="contractPagination.pageSize"

+ 370 - 0
src/views/customer/info/components/ErpSupplierInfoTab.vue

@@ -0,0 +1,370 @@
+<template>
+  <div class="tab-content">
+    <div class="info-section">
+      <div class="section-title-row">
+        <div class="section-title-left">
+          <span class="section-title-text">ERP供应商信息</span>
+        </div>
+        <el-button v-if="!isViewMode" type="primary" icon="Document" @click="onSaveClick">保存</el-button>
+      </div>
+
+      <el-form ref="erpFormRef" :model="erpForm" :rules="erpFormRules" label-width="120px" class="detail-form">
+        <el-row :gutter="12" class="form-row">
+          <el-col :span="8">
+            <el-form-item label="采购人员:" prop="purchaseId">
+              <el-select v-model="erpForm.purchaseId" placeholder="请选择采购人员" class="w-full" filterable :disabled="isViewMode">
+                <el-option v-for="item in erpStaffList" :key="item.staffId" :label="`${item.staffCode} , ${item.staffName}`" :value="item.staffId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="采购开票类型:" prop="purchaseInvoiceNo">
+              <el-select
+                v-model="erpForm.purchaseInvoiceNo"
+                placeholder="采购开票类型"
+                class="w-full"
+                filterable
+                :disabled="isViewMode"
+                @change="handInvoiceChange"
+              >
+                <el-option v-for="item in purchaseInvoice" :key="item.value" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="单价含税:">
+              <el-select v-model="erpForm.unitPrice" placeholder="单价含税" class="w-full" filterable disabled>
+                <el-option v-for="item in unitPriceArr" :key="item.value" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="12" class="form-row">
+          <el-col :span="8">
+            <el-form-item label="税码:">
+              <el-select v-model="erpForm.rateId" placeholder="税码" class="w-full" filterable disabled>
+                <el-option v-for="item in taxrateList" :key="item.id" :label="item.taxrateNo" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="交易币别:">
+              <el-select v-model="erpForm.dealCurrencyId" placeholder="请选择交易币别" class="w-full" filterable disabled>
+                <el-option v-for="item in currencyList" :key="item.id" :label="item.currencyName" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="账款归属:">
+              <el-input :model-value="supplierNo" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="12" class="form-row">
+          <el-col :span="8">
+            <el-form-item label="付款条件:">
+              <el-select v-model="erpForm.settlementMethod" placeholder="请选择付款条件" class="w-full" filterable disabled>
+                <el-option v-for="dict in payment_clause" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
+import { listErpSupplierInfo, addErpSupplierInfo, updateErpSupplierInfo } from '@/api/supplier/erpSupplierInfo';
+import type { ErpSupplierInfoForm } from '@/api/supplier/erpSupplierInfo/types';
+import { listErpStaff } from '@/api/erpData/erpStaff';
+import type { ErpStaffVO } from '@/api/erpData/erpStaff/types';
+import { listComCurrency } from '@/api/company/comCurrency';
+import { listTaxrate } from '@/api/company/taxrate';
+import type { ComCurrencyVO } from '@/api/company/comCurrency/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { payment_clause } = toRefs<any>(proxy?.useDict('payment_clause'));
+
+const props = defineProps<{
+  supplierId?: string | number;
+  supplierNo?: string;
+  isViewMode: boolean;
+}>();
+
+const emit = defineEmits<{
+  (e: 'saved'): void;
+}>();
+
+const erpFormRef = ref<FormInstance>();
+const erpStaffList = ref<ErpStaffVO[]>([]);
+const taxrateList = ref<any[]>([]);
+const currencyList = ref<ComCurrencyVO[]>([]);
+
+const erpForm = reactive<ErpSupplierInfoForm>({
+  id: undefined,
+  supplierId: undefined,
+  purchaseId: undefined,
+  belongingDepartmentId: undefined,
+  status: undefined,
+  remark: undefined,
+  unitPrice: 'True',
+  dealCurrencyId: undefined,
+  accountBelong: undefined,
+  rateId: undefined,
+  purchaseInvoiceId: undefined,
+  purchaseInvoiceNo: undefined,
+  purchaseInvoice: undefined,
+  settlementMethod: undefined
+});
+
+const erpFormRules: FormRules = {
+  purchaseId: [{ required: true, message: '请选择采购人员', trigger: 'change' }],
+  purchaseInvoiceNo: [{ required: true, message: '请选择采购开票类型', trigger: 'change' }]
+};
+
+const unitPriceArr = ref([
+  { label: '含税', value: 'True' },
+  { label: '不含税', value: 'False' }
+]);
+
+const purchaseInvoice = ref([
+  { label: '优易达专票', value: '0001' },
+  { label: '江西优易云普票', value: '0016' },
+  { label: '江西优易云专票', value: '0006' },
+  { label: '无票', value: '0017' },
+  { label: '新天利泰专票', value: '0003' },
+  { label: '优易达(长沙)-普票', value: '0019' },
+  { label: '优易达(长沙)-专票', value: '0018' },
+  { label: '优易达普票', value: '0010' },
+  { label: '优易智采(江西)-专票', value: '0020' }
+]);
+
+const handInvoiceChange = (invoiceNo: any) => {
+  const invoice = purchaseInvoice.value.find((item) => item.value === invoiceNo);
+  erpForm.purchaseInvoice = invoice?.label;
+};
+
+// 加载税码列表并设默认值
+const loadTaxrateList = async () => {
+  try {
+    const res = await listTaxrate({
+      isShow: '0',
+      pageNum: 1,
+      pageSize: 1000
+    });
+    taxrateList.value = res.rows || [];
+    if (!erpForm.rateId && taxrateList.value.length > 0) {
+      erpForm.rateId = taxrateList.value[0].id;
+    }
+  } catch (error) {}
+};
+
+// 加载币种列表并设默认值
+const loadCurrencyList = async () => {
+  try {
+    const res = await listComCurrency({
+      isShow: '0',
+      pageNum: 1,
+      pageSize: 1000
+    });
+    currencyList.value = res.rows || [];
+    if (!erpForm.dealCurrencyId && currencyList.value.length > 0) {
+      erpForm.dealCurrencyId = currencyList.value[0].id;
+    }
+  } catch (error) {
+    console.error('加载币种列表失败:', error);
+    currencyList.value = [];
+  }
+};
+
+// 加载员工列表
+const loadErpStaffList = async () => {
+  try {
+    const res = await listErpStaff();
+    erpStaffList.value = res.rows || [];
+  } catch (error) {
+    console.error('加载员工列表失败:', error);
+  }
+};
+
+// 加载已有ERP供应商信息
+const loadErpSupplierInfo = async () => {
+  if (!props.supplierId) return;
+
+  try {
+    const res = await listErpSupplierInfo({ supplierId: props.supplierId, pageNum: 1, pageSize: 1 });
+    if (res.rows && res.rows.length > 0) {
+      const data = res.rows[0];
+      Object.assign(erpForm, {
+        id: data.id,
+        supplierId: data.supplierId,
+        purchaseId: data.purchaseId,
+        belongingDepartmentId: data.belongingDepartmentId,
+        status: data.status,
+        remark: data.remark,
+        unitPrice: data.unitPrice || 'True',
+        dealCurrencyId: data.dealCurrencyId,
+        accountBelong: data.accountBelong,
+        rateId: data.rateId,
+        purchaseInvoiceId: data.purchaseInvoiceId,
+        purchaseInvoiceNo: data.purchaseInvoiceNo,
+        purchaseInvoice: data.purchaseInvoice,
+        settlementMethod: data.settlementMethod
+      });
+    }
+  } catch (error) {
+    console.error('加载ERP供应商信息失败:', error);
+  }
+};
+
+// 监听付款条件字典加载完成后默认选择第一个
+watch(
+  () => payment_clause.value,
+  (val) => {
+    if (!erpForm.settlementMethod && val && val.length > 0) {
+      erpForm.settlementMethod = val[0].value;
+    }
+  },
+  { immediate: true }
+);
+
+// 监听supplierId变化,重新加载ERP数据
+watch(
+  () => props.supplierId,
+  (newId) => {
+    if (newId) {
+      loadErpSupplierInfo();
+    }
+  },
+  { immediate: true }
+);
+
+const onSaveClick = async () => {
+  if (!erpFormRef.value) return;
+
+  try {
+    await erpFormRef.value.validate();
+  } catch {
+    return;
+  }
+
+  if (!props.supplierId) {
+    ElMessage.warning('请先保存基本信息');
+    return;
+  }
+
+  try {
+    const erpData: ErpSupplierInfoForm = {
+      ...erpForm,
+      supplierId: props.supplierId
+    };
+    if (erpData.id) {
+      await updateErpSupplierInfo(erpData);
+    } else {
+      await addErpSupplierInfo(erpData);
+      // 重新加载以获取新生成的id
+      await loadErpSupplierInfo();
+    }
+    ElMessage.success('ERP供应商信息保存成功');
+    emit('saved');
+  } catch (error) {
+    console.error('保存ERP供应商信息失败:', error);
+  }
+};
+
+onMounted(() => {
+  loadErpStaffList();
+  loadTaxrateList();
+  loadCurrencyList();
+});
+</script>
+
+<style scoped>
+.tab-content {
+  --el-component-size: 24px;
+  padding: 16px;
+}
+
+.detail-form :deep(.el-form-item__label) {
+  white-space: nowrap;
+}
+
+.detail-form :deep(.form-row) {
+  margin-bottom: 2px;
+}
+
+.detail-form :deep(.el-form-item) {
+  margin-bottom: 8px;
+}
+
+.tab-content :deep(.form-row) {
+  margin-bottom: 2px;
+}
+
+.tab-content :deep(.el-form-item) {
+  margin-bottom: 8px;
+}
+
+.tab-content :deep(.info-section) {
+  margin-bottom: 20px;
+}
+
+.tab-content :deep(.section-title-row) {
+  margin-bottom: 12px;
+  padding-bottom: 8px;
+}
+
+.tab-content :deep(.section-title-text) {
+  font-size: 14px;
+}
+
+.tab-content :deep(.el-form-item__label) {
+  font-size: 13px;
+  height: var(--el-component-size);
+  line-height: var(--el-component-size);
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.detail-form :deep(.el-input),
+.detail-form :deep(.el-select) {
+  width: 100%;
+}
+
+.detail-form :deep(.el-input__wrapper),
+.detail-form :deep(.el-select__wrapper) {
+  min-height: var(--el-component-size);
+  height: var(--el-component-size);
+  align-items: center;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.detail-form :deep(.el-form-item__content) {
+  align-items: center;
+  min-height: var(--el-component-size);
+}
+
+.detail-form :deep(.el-input__inner) {
+  height: var(--el-component-size);
+  line-height: var(--el-component-size);
+}
+
+.section-title-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.section-title-left {
+  display: flex;
+  align-items: baseline;
+  gap: 4px;
+}
+
+.w-full {
+  width: 100%;
+}
+</style>

+ 15 - 24
src/views/customer/info/detail.vue

@@ -130,6 +130,16 @@
           @currentChange="handleContractCurrentChange"
         />
       </el-tab-pane>
+
+      <!-- ERP供应商信息 -->
+      <el-tab-pane label="ERP供应商信息" name="erpSupplier">
+        <ErpSupplierInfoTab
+          :supplierId="detailData.supplierId"
+          :supplierNo="detailData.supplierNo"
+          :isViewMode="isViewMode"
+          @saved="handleErpSupplierSaved"
+        />
+      </el-tab-pane>
     </el-tabs>
 
     <!-- 付款信息对话框 -->
@@ -578,8 +588,6 @@ import { InvoiceTypeVO } from '@/api/system/invoiceType/types';
 import { listBank as listSystemBank } from '@/api/system/bank';
 import { BankVO as SystemBankVO } from '@/api/system/bank/types';
 import { getInfoTemporary, addInfoTemporary } from '@/api/supplier/infoTemporary';
-import { addErpSupplierInfo, updateErpSupplierInfo } from '@/api/supplier/erpSupplierInfo';
-import { ErpSupplierInfoForm } from '@/api/supplier/erpSupplierInfo/types';
 import { getChinaArea } from '@/api/system/addressarea/index';
 import download from '@/plugins/download';
 import { listQualification } from '@/api/supplier/qualification';
@@ -593,6 +601,7 @@ import AddressTab from './components/AddressTab.vue';
 import AccountTab from './components/AccountTab.vue';
 import ContractTab from './components/ContractTab.vue';
 import QualificationTab from './components/QualificationTab.vue';
+import ErpSupplierInfoTab from './components/ErpSupplierInfoTab.vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_platform_yes_no, sys_user_sex, sys_normal_disable } = toRefs<any>(
@@ -1072,7 +1081,7 @@ const handleGetBusinessInfo = async () => {
 };
 
 /** 保存数据 */
-const handleSave = async (erpSupplierInfoForm?: ErpSupplierInfoForm) => {
+const handleSave = async () => {
   try {
     // 验证必填字段
     if (!detailData.value.ownedCompany) {
@@ -1172,9 +1181,6 @@ const handleSave = async (erpSupplierInfoForm?: ErpSupplierInfoForm) => {
         isBasicInfoSaved.value = true;
         detailData.value.id = newId;
 
-        // 保存ERP供应商信息
-        await saveErpSupplierInfo(erpSupplierInfoForm, newId);
-
         // 重新加载供应商详情以获取完整信息(包括supplierNo)
         try {
           const detailRes = await getInfo(newId);
@@ -1198,8 +1204,6 @@ const handleSave = async (erpSupplierInfoForm?: ErpSupplierInfoForm) => {
     } else {
       // 编辑模式,直接刷新当前数据
       if (detailData.value.id) {
-        // 保存ERP供应商信息
-        await saveErpSupplierInfo(erpSupplierInfoForm, detailData.value.supplierId);
         await getDetail();
       }
     }
@@ -1208,22 +1212,9 @@ const handleSave = async (erpSupplierInfoForm?: ErpSupplierInfoForm) => {
   }
 };
 
-/** 保存ERP供应商信息 */
-const saveErpSupplierInfo = async (erpSupplierInfoForm: ErpSupplierInfoForm | undefined, supplierId: string | number) => {
-  if (!erpSupplierInfoForm || !supplierId) return;
-  try {
-    const erpData: ErpSupplierInfoForm = {
-      ...erpSupplierInfoForm,
-      supplierId
-    };
-    if (erpData.id) {
-      await updateErpSupplierInfo(erpData);
-    } else {
-      await addErpSupplierInfo(erpData);
-    }
-  } catch (e) {
-    console.error('保存ERP供应商信息失败:', e);
-  }
+/** ERP供应商信息保存成功后的回调 */
+const handleErpSupplierSaved = () => {
+  // ERP tab handles its own save, nothing additional needed here
 };
 
 /** 初始化省市区级联选择器数据 */

+ 5 - 5
src/views/product/brand/edit.vue

@@ -14,7 +14,7 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="品牌名称" prop="brandName">
-              <el-input v-model="form.brandName" placeholder="京东方" :disabled="isView" />
+              <el-input v-model="form.brandName" placeholder="请输入品牌名称" :disabled="isView" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -95,7 +95,7 @@
           </el-col>
         </el-row>
 
-        <el-form-item label="到期时间" prop="expireTime">
+        <!-- <el-form-item label="到期时间" prop="expireTime">
           <el-date-picker
             v-model="form.expireTime"
             type="datetime"
@@ -104,7 +104,7 @@
             style="width: 100%"
             :disabled="isView"
           />
-        </el-form-item>
+        </el-form-item> -->
 
         <el-form-item v-if="!isAdd" label="授权信息:" style="margin-bottom: 0">
           <div class="w-full">
@@ -127,11 +127,11 @@
                   <span>{{ scope.row.categorysMap?.threeLevelName || '-' }}</span>
                 </template>
               </el-table-column>
-              <el-table-column prop="authorizationEndTime" label="截止时间" align="center">
+              <!-- <el-table-column prop="authorizationEndTime" label="截止时间" align="center">
                 <template #default="scope">
                   <span>{{ scope.row.authorizationEndTime ? scope.row.authorizationEndTime.split(' ')[0] : '-' }}</span>
                 </template>
-              </el-table-column>
+              </el-table-column> -->
               <el-table-column prop="province" label="授权区域(省)" align="center" show-overflow-tooltip />
               <el-table-column prop="city" label="授权区域(市)" align="center" show-overflow-tooltip />
               <el-table-column prop="authorizedStatus" label="状态" align="center">

+ 54 - 81
src/views/product/brand/index.vue

@@ -36,7 +36,7 @@
             <span>{{ String(scope.row.brandStatus) === '1' ? '是' : '否' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="授权区域" align="center" prop="position" show-overflow-tooltip>
+        <!-- <el-table-column label="授权区域" align="center" prop="position" show-overflow-tooltip>
           <template #default="scope">
             <span>{{ scope.row.position || '无' }}</span>
           </template>
@@ -45,7 +45,7 @@
           <template #default="scope">
             <span>{{ scope.row.expireTime ? parseTime(scope.row.expireTime, '{y}-{m}-{d}') : '无' }}</span>
           </template>
-        </el-table-column>
+        </el-table-column> -->
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
           <template #default="scope">
             <div class="flex items-center justify-center gap-2 whitespace-nowrap">
@@ -84,10 +84,10 @@
           <el-input v-model="form.brandTitle" placeholder="请输入品牌标题" />
         </el-form-item>
         <el-form-item label="品牌大图" prop="brandBigImage">
-          <image-upload v-model="form.brandBigImage"/>
+          <image-upload v-model="form.brandBigImage" />
         </el-form-item>
         <el-form-item label="品牌故事" prop="brandStory">
-            <el-input v-model="form.brandStory" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.brandStory" type="textarea" placeholder="请输入内容" />
         </el-form-item>
         <el-form-item label="是否显示" prop="isShow">
           <el-input v-model="form.isShow" placeholder="请输入是否显示" />
@@ -102,15 +102,17 @@
           <el-input v-model="form.registrationCertificate" placeholder="请输入注册证书编号" />
         </el-form-item>
         <el-form-item label="证书/许可过期时间" prop="expireTime">
-          <el-date-picker clearable
+          <el-date-picker
+            clearable
             v-model="form.expireTime"
             type="datetime"
             value-format="YYYY-MM-DD HH:mm:ss"
-            placeholder="请选择证书/许可过期时间">
+            placeholder="请选择证书/许可过期时间"
+          >
           </el-date-picker>
         </el-form-item>
         <el-form-item label="品牌描述" prop="brandDescribe">
-            <el-input v-model="form.brandDescribe" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.brandDescribe" type="textarea" placeholder="请输入内容" />
         </el-form-item>
         <el-form-item label="展示位置" prop="position">
           <el-input v-model="form.position" placeholder="请输入展示位置" />
@@ -122,7 +124,7 @@
           <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
         </el-form-item>
         <el-form-item label="备注" prop="remark">
-            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -176,10 +178,10 @@ const initFormData: BrandForm = {
   position: undefined,
   care: undefined,
   dataSource: undefined,
-  remark: undefined,
-}
+  remark: undefined
+};
 const data = reactive<PageData<BrandForm, BrandQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
@@ -202,58 +204,25 @@ const data = reactive<PageData<BrandForm, BrandQuery>>({
     care: undefined,
     dataSource: undefined,
     platformCode: undefined,
-    params: {
-    }
+    params: {}
   },
   rules: {
-    brandInitials: [
-      { required: true, message: "品牌首字母缩写不能为空", trigger: "blur" }
-    ],
-    brandEnglishName: [
-      { required: true, message: "品牌英文名称不能为空", trigger: "blur" }
-    ],
-    recommendValue: [
-      { required: true, message: "推荐值不能为空", trigger: "blur" }
-    ],
-    brandLogo: [
-      { required: true, message: "品牌Logo图片路径或URL不能为空", trigger: "blur" }
-    ],
-    brandTitle: [
-      { required: true, message: "品牌标题不能为空", trigger: "blur" }
-    ],
-    brandBigImage: [
-      { required: true, message: "品牌大图不能为空", trigger: "blur" }
-    ],
-    brandStory: [
-      { required: true, message: "品牌故事不能为空", trigger: "blur" }
-    ],
-    isShow: [
-      { required: true, message: "是否显示不能为空", trigger: "blur" }
-    ],
-    brandRegistrant: [
-      { required: true, message: "品牌注册人不能为空", trigger: "blur" }
-    ],
-    license: [
-      { required: true, message: "许可证编号不能为空", trigger: "blur" }
-    ],
-    registrationCertificate: [
-      { required: true, message: "注册证书编号不能为空", trigger: "blur" }
-    ],
-    expireTime: [
-      { required: true, message: "证书/许可过期时间不能为空", trigger: "blur" }
-    ],
-    brandDescribe: [
-      { required: true, message: "品牌描述不能为空", trigger: "blur" }
-    ],
-    position: [
-      { required: true, message: "展示位置不能为空", trigger: "blur" }
-    ],
-    dataSource: [
-      { required: true, message: "数据来源不能为空", trigger: "blur" }
-    ],
-    remark: [
-      { required: true, message: "备注不能为空", trigger: "blur" }
-    ],
+    brandInitials: [{ required: true, message: '品牌首字母缩写不能为空', trigger: 'blur' }],
+    brandEnglishName: [{ required: true, message: '品牌英文名称不能为空', trigger: 'blur' }],
+    recommendValue: [{ required: true, message: '推荐值不能为空', trigger: 'blur' }],
+    brandLogo: [{ required: true, message: '品牌Logo图片路径或URL不能为空', trigger: 'blur' }],
+    brandTitle: [{ required: true, message: '品牌标题不能为空', trigger: 'blur' }],
+    brandBigImage: [{ required: true, message: '品牌大图不能为空', trigger: 'blur' }],
+    brandStory: [{ required: true, message: '品牌故事不能为空', trigger: 'blur' }],
+    isShow: [{ required: true, message: '是否显示不能为空', trigger: 'blur' }],
+    brandRegistrant: [{ required: true, message: '品牌注册人不能为空', trigger: 'blur' }],
+    license: [{ required: true, message: '许可证编号不能为空', trigger: 'blur' }],
+    registrationCertificate: [{ required: true, message: '注册证书编号不能为空', trigger: 'blur' }],
+    expireTime: [{ required: true, message: '证书/许可过期时间不能为空', trigger: 'blur' }],
+    brandDescribe: [{ required: true, message: '品牌描述不能为空', trigger: 'blur' }],
+    position: [{ required: true, message: '展示位置不能为空', trigger: 'blur' }],
+    dataSource: [{ required: true, message: '数据来源不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
   }
 });
 
@@ -266,31 +235,31 @@ const getList = async () => {
   brandList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {...initFormData};
+  form.value = { ...initFormData };
   brandFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = () => {
@@ -300,7 +269,7 @@ const handleAdd = () => {
       type: 'add'
     }
   });
-}
+};
 
 /** 查看按钮操作 */
 const handleView = async (row?: BrandVO) => {
@@ -313,7 +282,7 @@ const handleView = async (row?: BrandVO) => {
       type: 'view'
     }
   });
-}
+};
 
 /** 编辑按钮操作 */
 const handleEdit = async (row?: BrandVO) => {
@@ -326,7 +295,7 @@ const handleEdit = async (row?: BrandVO) => {
       type: 'edit'
     }
   });
-}
+};
 
 /** 提交按钮 */
 const submitForm = () => {
@@ -334,33 +303,37 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateBrand(form.value).finally(() =>  buttonLoading.value = false);
+        await updateBrand(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addBrand(form.value).finally(() =>  buttonLoading.value = false);
+        await addBrand(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: BrandVO) => {
   const _ids = row?.id;
   if (!_ids) return;
-  await proxy?.$modal.confirm('是否确认删除产品品牌信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await proxy?.$modal.confirm('是否确认删除产品品牌信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
   await delBrand(_ids);
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
   await getList();
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('product/brand/export', {
-    ...queryParams.value
-  }, `brand_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'product/brand/export',
+    {
+      ...queryParams.value
+    },
+    `brand_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
   getList();

+ 122 - 86
src/views/supplier/contract/add.vue

@@ -9,41 +9,53 @@
     <!-- 表单卡片 -->
     <el-card shadow="never" class="form-card">
       <div class="section-title">基本设置</div>
-      
+
       <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
         <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="合同名称" prop="contractName">
-              <el-input v-model="form.contractName" placeholder="请输入合同名称" />
+            <el-form-item label="供应商名称" prop="supplierId">
+              <el-select
+                v-if="!isSupplierPreset"
+                v-model="form.supplierId"
+                placeholder="请选择供应商"
+                style="width: 100%"
+                filterable
+                @change="onSupplierChange"
+              >
+                <el-option v-for="item in supplierList" :key="item.id" :label="`${item.supplierNo} - ${item.enterpriseName}`" :value="item.id" />
+              </el-select>
+              <el-input v-else :model-value="form.supplierName" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="供应商编号" prop="supplierNo">
+              <el-input v-model="form.supplierNo" placeholder="请输入供应商编号" disabled />
             </el-form-item>
           </el-col>
         </el-row>
-
         <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="合同名称" prop="contractName">
+              <el-input v-model="form.contractName" placeholder="请输入合同名称" />
+            </el-form-item>
+          </el-col>
           <el-col :span="12">
             <el-form-item label="合同类型" prop="contractType">
-              <el-select v-model="form.contractType" placeholder="请选择" style="width: 100%;">
-                <el-option 
-                  v-for="item in contractTypeDict" 
-                  :key="item.dictValue" 
-                  :label="item.dictLabel" 
-                  :value="item.dictValue" 
-                />
+              <el-select v-model="form.contractType" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in contractTypeDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
           </el-col>
+        </el-row>
+
+        <!-- <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="提醒时间" prop="demandReminderTime">
-              <el-input-number 
-                v-model="form.demandReminderTime" 
-                :min="1" 
-                :max="365"
-                style="width: 150px;"
-              />
-              <span style="margin-left: 10px;">天</span>
+              <el-input-number v-model="form.demandReminderTime" :min="1" :max="365" style="width: 150px" />
+              <span style="margin-left: 10px">天</span>
             </el-form-item>
           </el-col>
-        </el-row>
+        </el-row> -->
 
         <el-row :gutter="20">
           <el-col :span="12">
@@ -52,18 +64,14 @@
                 v-model="form.contractStartTime"
                 type="date"
                 placeholder="请选择"
-                style="width: 100%;"
+                style="width: 100%"
+                :disabled-date="disabledStartDate"
               />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="截止时间" prop="contractEndTime">
-              <el-date-picker
-                v-model="form.contractEndTime"
-                type="date"
-                placeholder="请选择"
-                style="width: 100%;"
-              />
+              <el-date-picker v-model="form.contractEndTime" type="date" placeholder="请选择" style="width: 100%" :disabled-date="disabledEndDate" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -71,13 +79,15 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="开票类型" prop="invoiceType">
-              <el-select v-model="form.invoiceType" placeholder="请选择" style="width: 100%;">
-                <el-option 
-                  v-for="item in invoiceTypeList" 
-                  :key="item.id" 
-                  :label="item.invoiceTypeName" 
-                  :value="item.id" 
-                />
+              <el-select v-model="form.invoiceType" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in invoiceTypeList" :key="item.id" :label="item.invoiceTypeName" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="结算方式" prop="settlementMethod">
+              <el-select v-model="form.settlementMethod" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in settlementMethodList" :key="item.id" :label="item.settlementName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -93,43 +103,17 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="税率" prop="taxRate">
-              <el-select v-model="form.taxRate" placeholder="请选择" style="width: 100%;">
-                <el-option 
-                  v-for="item in taxRateList" 
-                  :key="item.id" 
-                  :label="item.taxrateName" 
-                  :value="item.id" 
-                />
+              <el-select v-model="form.taxRate" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in taxRateList" :key="item.id" :label="item.taxrateName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
         </el-row>
 
-        <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="结算方式" prop="settlementMethod">
-              <el-select v-model="form.settlementMethod" placeholder="请选择" style="width: 100%;">
-                <el-option 
-                  v-for="item in settlementMethodList" 
-                  :key="item.id" 
-                  :label="item.settlementName" 
-                  :value="item.id" 
-                />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          
-        </el-row>
-
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="合同附件" prop="contractAttachment">
-              <FileUpload 
-                v-model="form.contractAttachment" 
-                :file-type="['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf']"
-                :file-size="50"
-                :limit="1"
-              />
+              <FileUpload v-model="form.contractAttachment" :file-type="['pdf']" :file-size="50" :limit="1" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -137,18 +121,13 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="合同说明" prop="contractDescription">
-              <el-input 
-                v-model="form.contractDescription" 
-                type="textarea" 
-                :rows="4"
-                placeholder="请选择"
-              />
+              <el-input v-model="form.contractDescription" type="textarea" :rows="4" placeholder="请选择" />
             </el-form-item>
           </el-col>
         </el-row>
 
         <el-row>
-          <el-col :span="24" style="text-align: center;">
+          <el-col :span="24" style="text-align: center">
             <el-button type="primary" @click="handleSubmit">提交</el-button>
           </el-col>
         </el-row>
@@ -163,6 +142,7 @@ import { useRoute, useRouter } from 'vue-router';
 import { ArrowLeft } from '@element-plus/icons-vue';
 import { getDictData, getTaxRateList, getSettlementMethodList, getInvoiceTypeList } from '@/api/customer/info';
 import { addContract } from '@/api/supplier/contract';
+import { listInfo, getInfo } from '@/api/supplier/info';
 import { ElMessage } from 'element-plus';
 import FileUpload from '@/components/FileUpload/index.vue';
 
@@ -174,6 +154,8 @@ const contractTypeDict = ref<any[]>([]);
 const taxRateList = ref<any[]>([]);
 const settlementMethodList = ref<any[]>([]);
 const invoiceTypeList = ref<any[]>([]);
+const supplierList = ref<any[]>([]);
+const isSupplierPreset = ref(false);
 
 const form = ref({
   supplierId: '',
@@ -194,18 +176,10 @@ const form = ref({
 });
 
 const rules = {
-  contractName: [
-    { required: true, message: '请输入合同名称', trigger: 'blur' }
-  ],
-  contractType: [
-    { required: true, message: '请选择合同类型', trigger: 'change' }
-  ],
-  contractStartTime: [
-    { required: true, message: '请选择开始时间', trigger: 'change' }
-  ],
-  contractEndTime: [
-    { required: true, message: '请选择截止时间', trigger: 'change' }
-  ]
+  contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
+  contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
+  contractStartTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+  contractEndTime: [{ required: true, message: '请选择截止时间', trigger: 'change' }]
 };
 
 const wanToYuanString = (value: unknown): string => {
@@ -225,6 +199,25 @@ const wanToYuanString = (value: unknown): string => {
   return sign ? '-' + base.toString() : base.toString();
 };
 
+/** 禁用开始时间早于今天 */
+const disabledStartDate = (time: Date) => {
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+  return time.getTime() < today.getTime();
+};
+
+/** 禁用截止时间早于开始时间 */
+const disabledEndDate = (time: Date) => {
+  if (!form.value.contractStartTime) {
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    return time.getTime() < today.getTime();
+  }
+  const start = new Date(form.value.contractStartTime);
+  start.setHours(0, 0, 0, 0);
+  return time.getTime() < start.getTime();
+};
+
 /** 返回上一页 */
 const goBack = () => {
   router.back();
@@ -281,8 +274,17 @@ const handleSubmit = async () => {
         };
         await addContract(payload);
         ElMessage.success('创建成功');
-        // 返回上一页
-        router.back();
+
+        // 判断来源并返回刷新
+        const urlParams = new URLSearchParams(window.location.search);
+        const supplierId = urlParams.get('supplierId');
+        if (supplierId) {
+          // 从"管理"进入 → 返回合同详情页并刷新
+          router.replace({ path: '/supplier/contract/detail', query: { supplierId, _t: Date.now() } });
+        } else {
+          // 从index页面直接进入 → 返回index页刷新统计数据
+          router.replace({ path: '/supplier/contract' });
+        }
       } catch (e) {
         console.error('创建合同失败:', e);
         ElMessage.error('创建失败');
@@ -291,14 +293,48 @@ const handleSubmit = async () => {
   });
 };
 
-onMounted(() => {
-  // 从 URL 获取 supplierId
+/** 供应商选择变更时,自动回显供应商编号 */
+const onSupplierChange = (supplierId: string | number) => {
+  const supplier = supplierList.value.find((item) => item.id === supplierId);
+  if (supplier) {
+    form.value.supplierNo = supplier.supplierNo || '';
+    form.value.supplierName = supplier.enterpriseName || '';
+  }
+};
+
+/** 加载供应商列表(用于下拉选择) */
+const loadSupplierList = async () => {
+  try {
+    const res = await listInfo({ pageNum: 1, pageSize: 9999 });
+    supplierList.value = res.rows || [];
+  } catch (e) {
+    console.error('加载供应商列表失败:', e);
+  }
+};
+
+onMounted(async () => {
   const urlParams = new URLSearchParams(window.location.search);
   const supplierId = urlParams.get('supplierId');
+
   if (supplierId) {
+    // 从"管理"按钮进入,回显供应商名称和编号且不可修改
+    isSupplierPreset.value = true;
     form.value.supplierId = supplierId;
+    try {
+      const res = await getInfo(supplierId);
+      if (res.data) {
+        form.value.supplierNo = res.data.supplierNo || '';
+        form.value.supplierName = res.data.enterpriseName || '';
+      }
+    } catch (e) {
+      console.error('获取供应商信息失败:', e);
+    }
+  } else {
+    // 直接进入创建合同,需要选择供应商
+    isSupplierPreset.value = false;
+    await loadSupplierList();
   }
-  
+
   getContractTypeDict();
   getTaxRateData();
   getSettlementMethodData();

+ 80 - 123
src/views/supplier/contract/detail.vue

@@ -12,35 +12,25 @@
         <el-row :gutter="20">
           <el-col :span="6">
             <el-form-item label="合同编号">
-              <el-input v-model="queryParams.contractNo" placeholder="请输入合同编号" clearable style="width: 100%;" />
+              <el-input v-model="queryParams.contractNo" placeholder="请输入合同编号" clearable style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="合同名称">
-              <el-input v-model="queryParams.contractName" placeholder="请输入合同名称" clearable style="width: 100%;" />
+              <el-input v-model="queryParams.contractName" placeholder="请输入合同名称" clearable style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="合同类型">
-              <el-select v-model="queryParams.contractType" placeholder="请选择" clearable style="width: 100%;">
-                <el-option 
-                  v-for="item in contractTypeDict" 
-                  :key="item.dictValue" 
-                  :label="item.dictLabel" 
-                  :value="item.dictValue" 
-                />
+              <el-select v-model="queryParams.contractType" placeholder="请选择" clearable style="width: 100%">
+                <el-option v-for="item in contractTypeDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="合同状态">
-              <el-select v-model="queryParams.contractStatus" placeholder="请选择" clearable style="width: 100%;">
-                <el-option 
-                  v-for="item in contractStatusDict" 
-                  :key="item.dictValue" 
-                  :label="item.dictLabel" 
-                  :value="item.dictValue" 
-                />
+              <el-select v-model="queryParams.contractStatus" placeholder="请选择" clearable style="width: 100%">
+                <el-option v-for="item in contractStatusDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -48,12 +38,12 @@
         <el-row :gutter="20">
           <el-col :span="6">
             <el-form-item label="开始时间">
-              <el-date-picker v-model="queryParams.contractStartTime" type="date" placeholder="请选择" style="width: 100%;" />
+              <el-date-picker v-model="queryParams.contractStartTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="结束时间">
-              <el-date-picker v-model="queryParams.contractEndTime" type="date" placeholder="请选择" style="width: 100%;" />
+              <el-date-picker v-model="queryParams.contractEndTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -70,7 +60,7 @@
     <!-- 合同信息列表 -->
     <el-card shadow="never" class="table-card">
       <div class="section-title">合同信息列表</div>
-      
+
       <el-table v-loading="loading" :data="contractList" border style="width: 100%">
         <el-table-column prop="contractNo" label="合同编号" align="center" />
         <el-table-column prop="contractName" label="合同名称" align="center" />
@@ -117,38 +107,27 @@
               <el-button link type="primary" @click="handleEdit(scope.row)">修改</el-button>
               <el-button link type="success" @click="handleView(scope.row)">查看</el-button>
               <el-button link type="warning" @click="handleAudit(scope.row)">审核</el-button>
+              <el-button link @click="handleCancel(scope.row)">作废</el-button>
             </template>
-            
+
             <!-- 已生效状态:只能查看 -->
             <template v-if="scope.row.contractStatus === 1 || scope.row.contractStatus === '1'">
               <el-button link type="primary" @click="handleView(scope.row)">查看</el-button>
+              <el-button link @click="handleCancel(scope.row)">作废</el-button>
             </template>
-            
+
             <!-- 已过期状态:无操作按钮 -->
             <template v-if="scope.row.contractStatus === 3 || scope.row.contractStatus === '3'">
-              <span style="color: #999;">-</span>
+              <span style="color: #999">-</span>
             </template>
           </template>
         </el-table-column>
       </el-table>
-      
-      
     </el-card>
 
     <!-- 合同管理对话框 -->
-    <el-dialog
-      v-model="contractDialogVisible"
-      :title="contractDialogTitle"
-      width="900px"
-      :close-on-click-modal="false"
-    >
-      <el-form
-        ref="contractFormRef"
-        :model="contractForm"
-        :rules="contractFormRules"
-        label-width="140px"
-        :disabled="contractDialogReadonly"
-      >
+    <el-dialog v-model="contractDialogVisible" :title="contractDialogTitle" width="900px" :close-on-click-modal="false">
+      <el-form ref="contractFormRef" :model="contractForm" :rules="contractFormRules" label-width="140px" :disabled="contractDialogReadonly">
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="合同名称:" prop="contractName">
@@ -160,48 +139,28 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="合同类型:" prop="contractType">
-              <el-select v-model="contractForm.contractType" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in contractTypeDict"
-                  :key="item.dictValue"
-                  :label="item.dictLabel"
-                  :value="item.dictValue"
-                />
+              <el-select v-model="contractForm.contractType" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in contractTypeDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
+          <!-- <el-col :span="12">
             <el-form-item label="提醒时间:" prop="demandReminderTime">
-              <el-input-number
-                v-model="contractForm.demandReminderTime"
-                :min="1"
-                :max="365"
-                style="width: 150px;"
-              />
-              <span style="margin-left: 10px;">天</span>
+              <el-input-number v-model="contractForm.demandReminderTime" :min="1" :max="365" style="width: 150px" />
+              <span style="margin-left: 10px">天</span>
             </el-form-item>
-          </el-col>
+          </el-col> -->
         </el-row>
 
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="开始时间:" prop="contractStartTime">
-              <el-date-picker
-                v-model="contractForm.contractStartTime"
-                type="date"
-                placeholder="请选择"
-                style="width: 100%;"
-              />
+              <el-date-picker v-model="contractForm.contractStartTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="截止时间:" prop="contractEndTime">
-              <el-date-picker
-                v-model="contractForm.contractEndTime"
-                type="date"
-                placeholder="请选择"
-                style="width: 100%;"
-              />
+              <el-date-picker v-model="contractForm.contractEndTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -209,13 +168,8 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="开票类型:" prop="invoiceType">
-              <el-select v-model="contractForm.invoiceType" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in invoiceTypeList"
-                  :key="item.id"
-                  :label="item.invoiceTypeName"
-                  :value="item.id"
-                />
+              <el-select v-model="contractForm.invoiceType" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in invoiceTypeList" :key="item.id" :label="item.invoiceTypeName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -231,25 +185,15 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="税率:" prop="taxRate">
-              <el-select v-model="contractForm.taxRate" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in taxRateList"
-                  :key="item.id"
-                  :label="item.taxrateName"
-                  :value="item.id"
-                />
+              <el-select v-model="contractForm.taxRate" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in taxRateList" :key="item.id" :label="item.taxrateName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="结算方式:" prop="settlementMethod">
-              <el-select v-model="contractForm.settlementMethod" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in settlementMethodList"
-                  :key="item.id"
-                  :label="item.settlementName"
-                  :value="item.id"
-                />
+              <el-select v-model="contractForm.settlementMethod" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in settlementMethodList" :key="item.id" :label="item.settlementName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -272,12 +216,7 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="合同说明:" prop="contractDescription">
-              <el-input
-                v-model="contractForm.contractDescription"
-                type="textarea"
-                :rows="4"
-                placeholder="请输入合同说明"
-              />
+              <el-input v-model="contractForm.contractDescription" type="textarea" :rows="4" placeholder="请输入合同说明" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -287,11 +226,7 @@
         <div class="dialog-footer">
           <template v-if="contractDialogAudit">
             <el-button @click="contractDialogVisible = false">取消</el-button>
-            <el-button
-              type="primary"
-              @click="handleApprove"
-              :loading="approveLoading"
-            >审核通过</el-button>
+            <el-button type="primary" @click="handleApprove" :loading="approveLoading">审核通过</el-button>
           </template>
           <template v-else-if="contractDialogReadonly">
             <el-button @click="contractDialogVisible = false">关闭</el-button>
@@ -307,7 +242,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, nextTick } from 'vue';
+import { ref, onMounted, onActivated, nextTick } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
 import { ArrowLeft } from '@element-plus/icons-vue';
 import { getContractListById, getDictData, getTaxRateList, getSettlementMethodList, getInvoiceTypeList } from '@/api/customer/info';
@@ -390,18 +325,10 @@ const contractForm = ref({
 
 // 表单验证规则
 const contractFormRules = {
-  contractName: [
-    { required: true, message: '请输入合同名称', trigger: 'blur' }
-  ],
-  contractType: [
-    { required: true, message: '请选择合同类型', trigger: 'change' }
-  ],
-  contractStartTime: [
-    { required: true, message: '请选择开始时间', trigger: 'change' }
-  ],
-  contractEndTime: [
-    { required: true, message: '请选择截止时间', trigger: 'change' }
-  ]
+  contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
+  contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
+  contractStartTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+  contractEndTime: [{ required: true, message: '请选择截止时间', trigger: 'change' }]
 };
 
 // 数据字典
@@ -484,7 +411,7 @@ const getInvoiceTypeData = async () => {
 /** 根据字典值获取标签 */
 const getDictLabel = (dictList: any[], dictValue: string | number) => {
   if (!dictValue && dictValue !== 0) return '-';
-  const dict = dictList.find(item => String(item.dictValue) === String(dictValue));
+  const dict = dictList.find((item) => String(item.dictValue) === String(dictValue));
   return dict ? dict.dictLabel : dictValue;
 };
 
@@ -492,17 +419,17 @@ const getDictLabel = (dictList: any[], dictValue: string | number) => {
 const getContractList = async () => {
   const urlParams = new URLSearchParams(window.location.search);
   const supplierId = urlParams.get('supplierId');
-  
+
   if (!supplierId) {
     return;
   }
-  
+
   loading.value = true;
   try {
     const res = await getContractListById(supplierId, {
       ...queryParams.value
     });
-    
+
     if (Array.isArray(res.data)) {
       contractList.value = res.data;
       pagination.value.total = res.data.length;
@@ -540,12 +467,10 @@ const handleReset = () => {
 const handleAdd = () => {
   const urlParams = new URLSearchParams(window.location.search);
   const supplierId = urlParams.get('supplierId');
-  
+
   router.push({
     path: '/supplier/contract/add',
-    query: {
-      supplierId: supplierId
-    }
+    query: supplierId ? { supplierId } : {}
   });
 };
 
@@ -639,6 +564,34 @@ const handleApprove = async () => {
   }
 };
 
+/** 作废合同 */
+const handleCancel = async (row: any) => {
+  try {
+    await ElMessageBox.confirm('确认作废该合同吗?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
+    });
+  } catch {
+    return;
+  }
+
+  approveLoading.value = true;
+  try {
+    await updateContract({
+      id: row.id,
+      contractStatus: 5
+    });
+    ElMessage.success('操作成功');
+    contractDialogVisible.value = false;
+    getContractList();
+  } catch (e) {
+    ElMessage.error('操作失败');
+  } finally {
+    approveLoading.value = false;
+  }
+};
+
 /** 查看附件 */
 const handleViewAttachment = async (row: any) => {
   if (!row.contractAttachment) {
@@ -651,25 +604,25 @@ const handleViewAttachment = async (row: any) => {
     const res = await listByIds(row.contractAttachment);
     if (res.data && res.data.length > 0) {
       const file = res.data[0];
-      
+
       // 使用fetch获取文件并强制下载
       const response = await fetch(file.url);
       const blob = await response.blob();
-      
+
       // 创建下载链接
       const url = window.URL.createObjectURL(blob);
       const link = document.createElement('a');
       link.href = url;
       link.download = file.originalName || (row.contractName ? `${row.contractName}_合同附件` : '合同附件');
       link.style.display = 'none';
-      
+
       document.body.appendChild(link);
       link.click();
       document.body.removeChild(link);
-      
+
       // 清理URL对象
       window.URL.revokeObjectURL(url);
-      
+
       ElMessage({ message: '开始下载', type: 'info' });
     } else {
       ElMessage.warning('未找到附件文件');
@@ -713,6 +666,10 @@ onMounted(async () => {
   getInvoiceTypeData();
   getContractList();
 });
+
+onActivated(() => {
+  getContractList();
+});
 </script>
 
 <style scoped>

+ 55 - 42
src/views/supplier/contract/index.vue

@@ -10,7 +10,7 @@
             <el-form-item label="供应商名称" prop="supplierName">
               <el-input v-model="queryParams.supplierName" placeholder="请输入供应商名称" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-          
+
             <el-form-item>
               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
               <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -22,8 +22,14 @@
 
     <el-card shadow="never">
       <template #header>
-        <el-row :gutter="10" class="mb8">
-          合同管理信息列表
+        <el-row :gutter="10" class="mb8" type="flex" justify="space-between" align="middle">
+          <!-- 左侧标题 -->
+          <span style="font-size: 16px; font-weight: 500">合同管理信息列表</span>
+
+          <!-- 右侧按钮组 -->
+          <div style="display: flex; flex-wrap: nowrap; gap: 10px">
+            <el-button type="primary" icon="Plus" @click="handleAdd">创建合同</el-button>
+          </div>
         </el-row>
       </template>
 
@@ -45,8 +51,7 @@
     </el-card>
     <!-- 添加或修改合同管理对话框 -->
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
-      <el-form ref="contractFormRef" :model="form" :rules="rules" label-width="80px">
-      </el-form>
+      <el-form ref="contractFormRef" :model="form" :rules="rules" label-width="80px"> </el-form>
       <template #footer>
         <div class="dialog-footer">
           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
@@ -82,20 +87,17 @@ const dialog = reactive<DialogOption>({
   title: ''
 });
 
-const initFormData: ContractForm = {
-}
+const initFormData: ContractForm = {};
 const data = reactive<PageData<ContractForm, ContractQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
     supplierNo: undefined,
     supplierName: undefined,
-    params: {
-    }
+    params: {}
   },
-  rules: {
-  }
+  rules: {}
 });
 
 const { queryParams, form, rules } = toRefs(data);
@@ -107,55 +109,59 @@ const getList = async () => {
   contractList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {...initFormData};
+  form.value = { ...initFormData };
   contractFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: ContractVO[]) => {
-  ids.value = selection.map(item => item.id);
+  ids.value = selection.map((item) => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
-/** 新增按钮操作 */
+/** 创建合同 */
 const handleAdd = () => {
-  reset();
-  dialog.visible = true;
-  dialog.title = "添加合同管理";
-}
+  const urlParams = new URLSearchParams(window.location.search);
+  const supplierId = urlParams.get('supplierId');
+
+  router.push({
+    path: '/supplier/contract/add',
+    query: supplierId ? { supplierId } : {}
+  });
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row?: ContractVO) => {
   reset();
-  const _id = row?.id || ids.value[0]
+  const _id = row?.id || ids.value[0];
   const res = await getContract(_id);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改合同管理";
-}
+  dialog.title = '修改合同管理';
+};
 
 /** 管理按钮操作 - 路由到合同详情页 */
 const handleManage = (row: ContractVO) => {
@@ -166,7 +172,7 @@ const handleManage = (row: ContractVO) => {
       supplierId: row.supplierId
     }
   });
-}
+};
 
 /** 提交按钮 */
 const submitForm = () => {
@@ -174,37 +180,44 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateContract(form.value).finally(() =>  buttonLoading.value = false);
+        await updateContract(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addContract(form.value).finally(() =>  buttonLoading.value = false);
+        await addContract(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: ContractVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除合同管理编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await proxy?.$modal.confirm('是否确认删除合同管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
   await delContract(_ids);
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
   await getList();
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('supplier/contract/export', {
-    ...queryParams.value
-  }, `contract_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'supplier/contract/export',
+    {
+      ...queryParams.value
+    },
+    `contract_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
   getList();
 });
+
+onActivated(() => {
+  getList();
+});
 </script>
 
-<style scoped>
-</style>
+<style scoped></style>

+ 53 - 57
src/views/supplier/contractsupply/add.vue

@@ -12,25 +12,15 @@
         <el-row :gutter="20">
           <el-col :span="8">
             <el-form-item label="所属公司" prop="companyId">
-              <el-select v-model="form.companyId" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in companyList"
-                  :key="item.id"
-                  :label="item.companyName"
-                  :value="item.id"
-                />
+              <el-select v-model="form.companyId" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in companyList" :key="item.id" :label="item.companyName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="供应商" prop="supplierId">
-              <el-select v-model="form.supplierId" placeholder="请选择" style="width: 100%;" @change="handleSupplierChange">
-                <el-option
-                  v-for="item in supplierList"
-                  :key="item.id"
-                  :label="item.enterpriseName"
-                  :value="item.id"
-                />
+              <el-select v-model="form.supplierId" placeholder="请选择" style="width: 100%" @change="handleSupplierChange">
+                <el-option v-for="item in supplierList" :key="item.id" :label="item.enterpriseName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -44,7 +34,9 @@
                 type="date"
                 placeholder="请选择"
                 value-format="YYYY-MM-DD"
-                style="width: 100%;"
+                style="width: 100%"
+                :disabled-date="disabledStartDate"
+                @change="onStartTimeChange"
               />
             </el-form-item>
           </el-col>
@@ -55,7 +47,8 @@
                 type="date"
                 placeholder="请选择"
                 value-format="YYYY-MM-DD"
-                style="width: 100%;"
+                style="width: 100%"
+                :disabled-date="disabledEndDate"
               />
             </el-form-item>
           </el-col>
@@ -64,8 +57,8 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="附件" prop="attachment">
-              <FileUpload 
-                v-model="form.proFile" 
+              <FileUpload
+                v-model="form.proFile"
                 :limit="10"
                 :file-size="50"
                 :file-type="['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf']"
@@ -77,12 +70,7 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="备注" prop="remark">
-              <el-input 
-                v-model="form.remark" 
-                type="textarea" 
-                :rows="4"
-                placeholder="请输入内容"
-              />
+              <el-input v-model="form.remark" type="textarea" :rows="4" placeholder="请输入内容" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -92,16 +80,11 @@
           <el-button type="primary" @click="handleAddProduct">添加商品信息</el-button>
         </div>
 
-        <el-table :data="productList" border style="width: 100%; margin-top: 20px;">
+        <el-table :data="productList" border style="width: 100%; margin-top: 20px">
           <el-table-column prop="productCode" label="产品编号" align="center" width="120" />
           <el-table-column label="产品图片" align="center" width="100">
             <template #default="scope">
-              <el-image 
-                v-if="scope.row.productImage" 
-                :src="scope.row.productImage" 
-                style="width: 60px; height: 60px;"
-                fit="cover"
-              />
+              <el-image v-if="scope.row.productImage" :src="scope.row.productImage" style="width: 60px; height: 60px" fit="cover" />
             </template>
           </el-table-column>
           <el-table-column prop="productName" label="产品名称" align="center" show-overflow-tooltip />
@@ -120,18 +103,12 @@
           </el-table-column>
           <el-table-column label="供应价" align="center" width="120">
             <template #default="scope">
-              <el-input 
-                v-model="scope.row.offerPrice" 
-                placeholder="请输入"
-              />
+              <el-input v-model="scope.row.offerPrice" placeholder="请输入" />
             </template>
           </el-table-column>
           <el-table-column label="供应时效(天)" align="center" width="120">
             <template #default="scope">
-              <el-input 
-                v-model="scope.row.supplyCycle" 
-                placeholder="请输入"
-              />
+              <el-input v-model="scope.row.supplyCycle" placeholder="请输入" />
             </template>
           </el-table-column>
           <el-table-column label="上架状态" align="center" width="100">
@@ -146,9 +123,8 @@
           </el-table-column>
         </el-table>
 
-
-        <el-row style="margin-top: 20px;">
-          <el-col :span="24" style="text-align: center;">
+        <el-row style="margin-top: 20px">
+          <el-col :span="24" style="text-align: center">
             <el-button type="primary" @click="handleSubmit">提交</el-button>
           </el-col>
         </el-row>
@@ -156,11 +132,7 @@
     </el-card>
 
     <!-- 添加商品对话框 -->
-    <Product 
-      v-model:visible="productDialog.visible"
-      v-model:modelValue="productList"
-      @confirm="handleProductConfirm"
-    />
+    <Product v-model:visible="productDialog.visible" v-model:modelValue="productList" @confirm="handleProductConfirm" />
   </div>
 </template>
 
@@ -200,9 +172,33 @@ const form = ref({
 });
 
 const rules = {
-  supplierId: [
-    { required: true, message: '请选择供应商', trigger: 'change' }
-  ]
+  supplierId: [{ required: true, message: '请选择供应商', trigger: 'change' }],
+  startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+  endTime: [{ required: true, message: '请选择结束时间', trigger: 'change' }]
+};
+
+/** 禁用开始时间早于今天 */
+const disabledStartDate = (time: Date) => {
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+  return time.getTime() < today.getTime();
+};
+
+/** 禁用结束时间早于开始时间 */
+const disabledEndDate = (time: Date) => {
+  if (!form.value.startTime) {
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    return time.getTime() < today.getTime();
+  }
+  const start = new Date(form.value.startTime);
+  start.setHours(0, 0, 0, 0);
+  return time.getTime() < start.getTime();
+};
+
+/** 选择开始时间后清空结束时间 */
+const onStartTimeChange = () => {
+  form.value.endTime = '';
 };
 
 /** 返回上一页 */
@@ -232,7 +228,7 @@ const getSupplierData = async () => {
 
 /** 供应商选择变化 */
 const handleSupplierChange = (value: any) => {
-  const supplier = supplierList.value.find(item => String(item.id) === String(value));
+  const supplier = supplierList.value.find((item) => String(item.id) === String(value));
   if (supplier) {
     form.value.supplyNo = supplier.supplierNo || '';
   }
@@ -249,7 +245,7 @@ const handleProductConfirm = (selectedProducts: BaseVO[]) => {
     ElMessage.warning('请选择要添加的商品');
     return;
   }
-  
+
   productList.value = selectedProducts;
   ElMessage.success(`成功添加${selectedProducts.length}个商品`);
 };
@@ -267,7 +263,7 @@ const handleSubmit = async () => {
         // 从表格中收集最新的数据
         const tableInputs = document.querySelectorAll('.el-table input');
         let inputIndex = 0;
-        
+
         productList.value.forEach((item, index) => {
           // 每行有两个输入框:供应价和供应时效
           if (tableInputs[inputIndex]) {
@@ -279,21 +275,21 @@ const handleSubmit = async () => {
             inputIndex++;
           }
         });
-        
+
         // 组装提交数据,包含表单数据和商品列表
         const submitData = {
           ...form.value,
-          contractProduct: productList.value.map(item => ({
+          contractProduct: productList.value.map((item) => ({
             productId: item.productId,
             productNo: item.productCode,
             offerPrice: item.offerPrice || '',
             supplyCycle: item.supplyCycle || ''
           }))
         };
-        
+
         console.log('提交的数据:', submitData);
         console.log('商品列表:', productList.value);
-        
+
         await addContractsupply(submitData);
         ElMessage.success('新增成功');
         router.back();

+ 3 - 3
src/views/system/user/index.vue

@@ -2,7 +2,7 @@
   <div class="p-2">
     <el-row :gutter="20">
       <!-- 部门树 -->
-      <el-col :lg="4" :xs="24" style="">
+      <!-- <el-col :lg="4" :xs="24" style="">
         <el-card shadow="hover">
           <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
           <el-tree
@@ -18,8 +18,8 @@
             @node-click="handleNodeClick"
           />
         </el-card>
-      </el-col>
-      <el-col :lg="20" :xs="24">
+      </el-col> -->
+      <el-col :lg="24" :xs="24">
         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
           <div v-show="showSearch" class="mb-[10px]">
             <el-card shadow="hover">