Переглянути джерело

feat(profile): 添加基本信息标签页和个人资料详情功能

- 实现了基本资料信息显示界面
- 集成了个人资料详情查看功能
- 添加了标签页导航组件
- 完善了用户个人信息展示逻辑
Lijingyang 1 місяць тому
батько
коміт
01a4a69ff6

+ 36 - 9
src/views/customer/info/components/BasicInfoTab.vue

@@ -7,7 +7,7 @@
           <span class="section-title-divider">/</span>
           <span class="supplier-no">供应商编码:{{ detailData.supplierNo }}</span>
         </div>
-        <el-button v-if="!isViewMode" type="primary" icon="Document" @click="emit('save')">保存</el-button>
+        <el-button v-if="!isViewMode" type="primary" icon="Document" @click="onSaveClick">保存</el-button>
       </div>
 
       <el-form :model="detailData" label-width="120px" class="detail-form">
@@ -74,12 +74,12 @@
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item label="固定电话:">
+            <el-form-item label="固定电话:" :error="fixedPhoneError">
               <el-input
                 v-model="detailData.fixedPhone"
                 placeholder="请输入固定电话"
                 type="tel"
-                @input="onFixedPhoneInput"
+                @blur="onFixedPhoneBlur"
               />
             </el-form-item>
           </el-col>
@@ -206,7 +206,7 @@
       </el-row>
 
       <el-row :gutter="12" class="form-row">
-        <el-col :span="12">
+        <el-col :span="8">
           <div class="form-item">
             <span class="label">营业执照:</span>
             <ImageUpload
@@ -220,7 +220,7 @@
             />
           </div>
         </el-col>
-        <el-col :span="12">
+        <el-col :span="8">
           <div class="form-item">
             <span class="label">法人身份证照片:</span>
             <ImageUpload
@@ -234,6 +234,7 @@
             />
           </div>
         </el-col>
+        <el-col :span="8" />
       </el-row>
     </div>
 
@@ -268,6 +269,7 @@
 
 <script setup lang="ts">
 import ImageUpload from '@/components/ImageUpload/index.vue';
+import { ElMessage } from 'element-plus';
 
 const props = defineProps<{
   detailData: any;
@@ -306,11 +308,36 @@ const onOfficeRegionChange = (val: unknown) => {
   emit('officeRegionChange', (val || []) as string[]);
 };
 
-const onFixedPhoneInput = (val: string) => {
-  const next = (val || '').replace(/\D+/g, '');
-  if (next !== props.detailData.fixedPhone) {
-    props.detailData.fixedPhone = next;
+const fixedPhoneError = ref('');
+const fixedPhoneReg = /^(\d{3,4}-?)?\d{7,8}(-\d{1,6})?$/;
+
+const validateFixedPhone = (val: unknown) => {
+  const v = String(val ?? '').trim();
+  if (!v) return '';
+  if (!fixedPhoneReg.test(v)) return '请输入正确的固定电话';
+  return '';
+};
+
+watch(
+  () => props.detailData?.fixedPhone,
+  (v) => {
+    fixedPhoneError.value = validateFixedPhone(v);
+  },
+  { immediate: true }
+);
+
+const onFixedPhoneBlur = () => {
+  fixedPhoneError.value = validateFixedPhone(props.detailData?.fixedPhone);
+};
+
+const onSaveClick = () => {
+  const err = validateFixedPhone(props.detailData?.fixedPhone);
+  fixedPhoneError.value = err;
+  if (err) {
+    ElMessage.warning(err);
+    return;
   }
+  emit('save');
 };
 </script>
 

+ 41 - 35
src/views/customer/info/detail.vue

@@ -879,6 +879,8 @@ const paymentForm = ref<BankForm>({
   businessAddress: ''
 });
 
+const fixedPhoneReg = /^(\d{3,4}-?)?\d{7,8}(-\d{1,6})?$/;
+
 // 发票类型列表和银行列表
 const invoiceTypeList = ref<InvoiceTypeVO[]>([]);
 const systemBankList = ref<SystemBankVO[]>([]);
@@ -886,10 +888,43 @@ const systemBankList = ref<SystemBankVO[]>([]);
 // 付款信息表单验证规则
 const paymentFormRules = {
   invoiceTypeNo: [{ required: true, message: '请选择开票类型', trigger: 'change' }],
-  bankNum: [{ required: true, message: '请输入开户行行号', trigger: 'blur' }],
+  bankNum: [
+    {
+      required: true,
+      validator: (_rule: any, value: any, callback: any) => {
+        const v = String(value ?? '').trim();
+        if (!v) return callback(new Error('请输入开户行行号'));
+        if (!/^\d+$/.test(v)) return callback(new Error('开户行行号只能输入数字'));
+        callback();
+      },
+      trigger: 'blur'
+    }
+  ],
   bankInfoNo: [{ required: true, message: '请选择开户行名称', trigger: 'change' }],
-  bankNo: [{ required: true, message: '请输入银行账户', trigger: 'blur' }],
-  phone: [{ required: true, message: '请输入固定电话', trigger: 'blur' }],
+  bankNo: [
+    {
+      required: true,
+      validator: (_rule: any, value: any, callback: any) => {
+        const v = String(value ?? '').trim();
+        if (!v) return callback(new Error('请输入银行账户'));
+        if (!/^\d+$/.test(v)) return callback(new Error('银行账户只能输入数字'));
+        callback();
+      },
+      trigger: 'blur'
+    }
+  ],
+  phone: [
+    {
+      required: true,
+      validator: (_rule: any, value: any, callback: any) => {
+        const v = String(value ?? '').trim();
+        if (!v) return callback(new Error('请输入固定电话'));
+        if (!fixedPhoneReg.test(v)) return callback(new Error('请输入正确的固定电话'));
+        callback();
+      },
+      trigger: 'blur'
+    }
+  ],
   num: [{ required: true, message: '请选择是否主账号', trigger: 'change' }]
 };
 
@@ -1076,8 +1111,8 @@ const handleSave = async () => {
       ElMessage.warning('请输入工商名称');
       return;
     }
-    if (detailData.value.fixedPhone && !/^\d+$/.test(String(detailData.value.fixedPhone))) {
-      ElMessage.warning('固定电话只能输入数字');
+    if (detailData.value.fixedPhone && !fixedPhoneReg.test(String(detailData.value.fixedPhone).trim())) {
+      ElMessage.warning('请输入正确的固定电话');
       return;
     }
     if (!detailData.value.shortName) {
@@ -1187,7 +1222,6 @@ const handleSave = async () => {
     }
   } catch (e) {
     console.error('保存失败:', e);
-    ElMessage.error('保存失败');
   }
 };
 
@@ -1682,7 +1716,6 @@ const handleSaveCategories = async () => {
     ElMessage.success('保存成功');
   } catch (e) {
     console.error('保存供货类目失败:', e);
-    ElMessage.error('保存失败');
   }
 };
 
@@ -1705,7 +1738,6 @@ const handleSavePurchaseInfo = async () => {
     ElMessage.success('保存成功');
   } catch (e) {
     console.error('保存采购信息失败:', e);
-    ElMessage.error('保存失败');
   }
 };
 
@@ -1832,7 +1864,6 @@ const handleBrandSubmit = async () => {
     brandDialogVisible.value = false;
   } catch (e) {
     console.error('保存品牌失败:', e);
-    ElMessage.error('保存失败');
   } finally {
     brandSubmitLoading.value = false;
   }
@@ -2095,24 +2126,7 @@ const handleSupplyAreaSubmit = async () => {
     const areaList = buildAreaListFromSelectedProvinceCityIds(selectedSupplyAreaCodes.value);
     console.log('构建的 areaList:', areaList);
 
-    // 前端兜底去重:避免后端按“追加插入”导致重复省/市
-    // 只提交“新增的”省/市(已存在的省/市不重复提交)
-    const existedKeys = new Set<string>();
-    (savedAreaData.value || []).forEach((a: any) => {
-      const level = String(a.level);
-      const areaId = String(a.areaId ?? a.id ?? '');
-      if (!areaId) return;
-      if (level === '1' || level === '2') {
-        existedKeys.add(`${level}-${areaId}`);
-      }
-    });
-
-    const areaListToSubmit = (areaList || []).filter((a: any) => {
-      const level = String(a.level);
-      const areaId = String(a.areaId ?? '');
-      if (!areaId) return false;
-      return !existedKeys.has(`${level}-${areaId}`);
-    });
+    const areaListToSubmit = areaList || [];
 
     // 从选中的编码中提取区域信息(用于显示)
     const regionData = extractRegionDataFromSelectedProvinceCityIds(selectedSupplyAreaCodes.value);
@@ -2127,13 +2141,6 @@ const handleSupplyAreaSubmit = async () => {
     
     console.log('提交的数据:', submitData);
 
-    if (!submitData.areaList || submitData.areaList.length === 0) {
-      ElMessage.success('保存成功');
-      supplyAreaDialogVisible.value = false;
-      await getSupplyAreaList();
-      return;
-    }
-
     await addArea(submitData);
 
     // 更新本地数据
@@ -2188,7 +2195,6 @@ const handleSupplyAreaSubmit = async () => {
     await getSupplyAreaList();
   } catch (e) {
     console.error('保存供货区域失败:', e);
-    ElMessage.error('保存失败');
   } finally {
     supplyAreaSubmitLoading.value = false;
   }