Selaa lähdekoodia

feat(forecast): 重构预测表单页面并优化客户选择组件

yz 1 viikko sitten
vanhempi
commit
99cd47b065

+ 1 - 0
src/api/types/common.d.ts

@@ -39,6 +39,7 @@ export interface ApiResponseData<T> {
  * 客户查询参数接口
  */
 export interface CustomerQueryParams extends BaseQueryParams {
+  customerId?: number|string;
   customerCode?: string;
   customerName?: string;
   customerShortName?: string;

+ 7 - 1
src/components/common/customer-select.vue

@@ -260,7 +260,9 @@ export default {
       try {
         this.loading = true
         
-        const response = await getCustomerList(1, 200, {})
+        const response = await getCustomerList(1, 200, {
+          customerId: customerId
+        })
         
         if (response?.data?.success && response.data.data?.records) {
           const allCustomers = response.data.data.records
@@ -268,7 +270,11 @@ export default {
           
           if (customer) {
             // 只保留匹配的客户选项
+            customer.Customer_ID = String(customer.Customer_ID)
             this.options = [customer]
+            // 确保选中状态
+            this.currentValue = String(customer.Customer_ID)
+            console.log('客户回显成功:', customer.Customer_NAME, 'ID:', customer.Customer_ID)
           } else {
             // 如果在当前页没找到,可能需要查询更多页面
             console.warn(`未找到客户ID为 ${customerId} 的客户信息`)

+ 90 - 3
src/components/forecast-form/index.js

@@ -227,6 +227,19 @@ export default {
       if (val && this.visible) {
         this.formData = this.cleanAndFormatFormData(val)
       }
+    },
+
+    /**
+     * 监听预测ID变化
+     * @param {string|number} val - 新的预测ID
+     */
+    forecastId: {
+      handler(val) {
+        if (val && this.isEdit && this.visible) {
+          this.loadForecastDetail(val)
+        }
+      },
+      immediate: true
     }
   },
 
@@ -253,11 +266,27 @@ export default {
      * @private
      */
     cleanAndFormatFormData(data) {
+      // 获取下个月的年份和月份作为默认值
+      const now = new Date()
+      const currentYear = now.getFullYear()
+      const currentMonth = now.getMonth() + 1
+      
+      let defaultYear, defaultMonth
+      if (currentMonth === 12) {
+        // 当前是12月,下个月是明年1月
+        defaultYear = currentYear + 1
+        defaultMonth = 1
+      } else {
+        // 其他月份,直接 +1
+        defaultYear = currentYear
+        defaultMonth = currentMonth + 1
+      }
+      
       return {
         id: data.id || null,
         forecastCode: String(data.forecastCode || ''),
-        year: data.year ? data.year.toString() : new Date().getFullYear().toString(),
-        month: Number(data.month) || new Date().getMonth() + 1,
+        year: data.year ? data.year.toString() : defaultYear.toString(),
+        month: Number(data.month) || defaultMonth,
         customerId: data.customerId ? data.customerId.toString() : null,
         customerCode: String(data.customerCode || ''),
         customerName: String(data.customerName || ''),
@@ -268,7 +297,7 @@ export default {
         itemCode: String(data.itemCode || ''),
         itemName: String(data.itemName || ''),
         specs: String(data.specs || ''),
-        forecastQuantity: Number(data.forecastQuantity) || null,
+        forecastQuantity: data.forecastQuantity !== undefined && data.forecastQuantity !== null && data.forecastQuantity !== '' ? Number(data.forecastQuantity) : null,
         currentInventory: Number(data.currentInventory) || null,
         approvalStatus: Number(data.approvalStatus) || APPROVAL_STATUS.PENDING,
         approvedName: String(data.approvedName || ''),
@@ -296,6 +325,16 @@ export default {
           const detailData = res.data.data
           this.formData = this.cleanAndFormatFormData(detailData)
 
+          // 加载客户选项数据,确保客户下拉框能正确显示
+          if (this.formData.customerId) {
+            await this.loadCustomerOption(this.formData.customerId, this.formData.customerName)
+          }
+
+          // 加载物料选项数据,确保物料下拉框能正确显示
+          if (this.formData.itemId) {
+            await this.loadItemOption(this.formData.itemId, this.formData.itemName, this.formData.itemCode, this.formData.specs)
+          }
+
           // 触发加载完成事件
           this.$emit(FORECAST_FORM_EVENTS.LOADED, this.formData)
         } else {
@@ -310,6 +349,25 @@ export default {
     },
 
     /**
+     * 加载单个客户选项
+     * @description 为编辑模式加载特定客户的选项数据
+     * @param {string|number} customerId - 客户ID
+     * @param {string} customerName - 客户名称
+     * @returns {Promise<void>}
+     */
+    async loadCustomerOption(customerId, customerName) {
+      if (!customerId) return
+
+      try {
+        // customer-select组件会自动处理回显,我们只需要确保formData中有正确的值
+        // 组件的watch会监听value变化并调用loadCustomerById方法
+        console.log('客户回显数据:', { customerId, customerName })
+      } catch (error) {
+        console.error('加载客户选项失败:', error)
+      }
+    },
+
+    /**
      * 远程搜索客户
      * @description 根据关键字远程搜索客户数据
      * @param {string} query - 搜索关键字
@@ -345,6 +403,35 @@ export default {
     },
 
     /**
+     * 加载单个物料选项
+     * @description 为编辑模式加载特定物料的选项数据
+     * @param {string|number} itemId - 物料ID
+     * @param {string} itemName - 物料名称
+     * @param {string} itemCode - 物料编码
+     * @param {string} specs - 规格
+     * @returns {Promise<void>}
+     */
+    async loadItemOption(itemId, itemName, itemCode, specs) {
+      if (!itemId) return
+
+      try {
+        // 如果选项中已经存在该物料,则不需要重新加载
+        const existingOption = this.itemOptions.find(option => option.id === itemId)
+        if (existingOption) return
+
+        // 添加当前物料到选项中
+        this.itemOptions = [{
+          id: itemId,
+          code: itemCode,
+          name: itemName,
+          specs: specs
+        }]
+      } catch (error) {
+        console.error('加载物料选项失败:', error)
+      }
+    },
+
+    /**
      * 远程搜索物料
      * @description 根据关键字远程搜索物料数据
      * @param {string} query - 搜索关键字

+ 0 - 72
src/components/forecast-form/index.scss

@@ -46,68 +46,7 @@ $transition-duration: 0.3s;
   }
 }
 
-// 表单头部导航条
-.forecast-form-header {
-  height: $header-height;
-  background-color: $header-bg;
-  border-bottom: 1px solid $header-border;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding: 0 24px;
-  box-shadow: $shadow-light;
-  position: relative;
-  z-index: 10;
-
-  .header-left {
-    display: flex;
-    align-items: center;
-
-    .back-btn {
-      font-size: 16px;
-      color: $primary-color;
-      margin-right: 16px;
-      padding: 8px 12px;
-      border-radius: $border-radius;
-      transition: all $transition-duration;
-
-      &:hover {
-        background-color: rgba($primary-color, 0.1);
-        color: darken($primary-color, 10%);
-      }
 
-      .el-icon-arrow-left {
-        margin-right: 4px;
-      }
-    }
-
-    .form-title {
-      font-size: 18px;
-      font-weight: 600;
-      color: $text-primary;
-      margin: 0;
-    }
-  }
-
-  .header-right {
-    .el-button {
-      padding: 10px 20px;
-      font-size: 14px;
-      border-radius: $border-radius;
-      transition: all $transition-duration;
-
-      &.el-button--primary {
-        background-color: $primary-color;
-        border-color: $primary-color;
-
-        &:hover {
-          background-color: darken($primary-color, 10%);
-          border-color: darken($primary-color, 10%);
-        }
-      }
-    }
-  }
-}
 
 // 表单内容区域
 .forecast-form-content {
@@ -270,18 +209,7 @@ $transition-duration: 0.3s;
     min-height: auto;
   }
 
-  .forecast-form-header {
-    flex-direction: column;
-    height: auto;
-    padding: 16px;
 
-    .header-left,
-    .header-right {
-      width: 100%;
-      justify-content: center;
-      margin-bottom: 12px;
-    }
-  }
 
   .forecast-form-content {
     padding: 16px;

+ 61 - 56
src/components/forecast-form/index.vue

@@ -1,60 +1,27 @@
 <template>
   <!-- 销售预测表单容器 -->
   <div class="forecast-form-container basic-container">
-    <!-- 表单头部导航 -->
-    <div class="forecast-form-header">
-      <div class="header-left">
-        <el-button
-          type="text"
-          icon="el-icon-arrow-left"
-          size="small"
-          class="back-btn"
-          @click="handleBack"
-        >
-          返回列表
-        </el-button>
-        <span class="form-title">{{ formTitle }}</span>
-      </div>
-      <div class="header-right">
-        <el-button
-          type="primary"
-          icon="el-icon-check"
-          size="small"
-          :loading="saveLoading"
-          @click="handleSave"
-        >
-          保存
-        </el-button>
-      </div>
-    </div>
+
 
     <!-- 表单内容区域 -->
     <div class="forecast-form-content">
       <el-form
         ref="forecastForm"
         :model="formData"
-        :rules="formRules"
+        :rules="dynamicFormRules"
         label-width="120px"
         class="forecast-form"
       >
         <div class="form-section">
           <h3 class="section-title">基本信息</h3>
           <el-row :gutter="20">
-            <el-col :span="12">
+            <el-col :span="12" v-if="isEdit">
               <el-form-item label="预测编码" prop="forecastCode">
                 <el-input
                   v-model="formData.forecastCode"
                   placeholder="请输入预测编码"
-                  :disabled="isEdit"
+                  disabled
                 >
-                  <el-button
-                    v-if="!isEdit"
-                    slot="append"
-                    icon="el-icon-refresh"
-                    @click="generateForecastCode"
-                    title="生成编码"
-                  >
-                  </el-button>
                 </el-input>
               </el-form-item>
             </el-col>
@@ -94,7 +61,6 @@
                 <customer-select
                   v-model="formData.customerId"
                   placeholder="请选择客户"
-                  :disabled="isEdit"
                   @customer-selected="handleCustomerSelected"
                 />
               </el-form-item>
@@ -287,27 +253,50 @@ export default {
       currentInventory: null,
 
       /**
+       * 保存加载状态
+       * @type {boolean}
+       */
+      saveLoading: false,
+
+      /**
        * 表单数据
        * @type {Object}
        */
-      formData: {
-        forecastCode: '', // 预测编码
-        year: new Date().getFullYear().toString(), // 年份
-        month: (new Date().getMonth() + 1).toString().padStart(2, '0'), // 月份
-        customerId: '', // 客户ID
-        customerCode: '', // 客户编码
-        customerName: '', // 客户名称
-        brandId: '', // 品牌ID
-        brandCode: '', // 品牌编码
-        brandName: '', // 品牌名称
-        itemId: '', // 物料ID
-        itemCode: '', // 物料编码
-        itemName: '', // 物料名称
-        itemSpecs: '', // 物料规格
-        forecastQuantity: '', // 预测数量
-        approvalStatus: 0, // 审批状态
-        approvalRemark: '' // 审批备注
-      },
+      formData: (() => {
+        const now = new Date()
+        const currentYear = now.getFullYear()
+        const currentMonth = now.getMonth() + 1
+        
+        let nextYear, nextMonth
+        if (currentMonth === 12) {
+          // 当前是12月,下个月是明年1月
+          nextYear = currentYear + 1
+          nextMonth = 1
+        } else {
+          // 其他月份,直接 +1
+          nextYear = currentYear
+          nextMonth = currentMonth + 1
+        }
+        
+        return {
+          forecastCode: '', // 预测编码
+          year: nextYear.toString(), // 年份
+          month: nextMonth.toString().padStart(2, '0'), // 月份
+          customerId: '', // 客户ID
+          customerCode: '', // 客户编码
+          customerName: '', // 客户名称
+          brandId: '', // 品牌ID
+          brandCode: '', // 品牌编码
+          brandName: '', // 品牌名称
+          itemId: '', // 物料ID
+          itemCode: '', // 物料编码
+          itemName: '', // 物料名称
+          itemSpecs: '', // 物料规格
+          forecastQuantity: '', // 预测数量
+          approvalStatus: 0, // 审批状态
+          approvalRemark: '' // 审批备注
+        }
+      })(),
     }
   },
 
@@ -323,6 +312,22 @@ export default {
      */
     formTitle() {
       return this.isEdit ? '编辑销售预测' : '新增销售预测'
+    },
+
+    /**
+     * 动态表单验证规则
+     * @description 根据编辑模式动态生成验证规则
+     * @returns {Object} 表单验证规则对象
+     */
+    dynamicFormRules() {
+      const rules = { ...this.formRules }
+      
+      // 新增模式时,移除预测编码的验证规则
+      if (!this.isEdit) {
+        delete rules.forecastCode
+      }
+      
+      return rules
     }
   },
 

+ 15 - 3
src/components/order-form/customer-select.vue

@@ -154,9 +154,18 @@ export default {
     value(newVal, oldVal) {
       if (newVal !== oldVal) {
         this.currentValue = newVal
-        // 当value变化时,如果有值且当前选项为空,则加载对应的客户信息
-        if (newVal && this.options.length === 0) {
-          this.loadCustomerById(newVal)
+        
+        if (newVal) {
+          // 检查当前选项中是否已有匹配的客户
+          const existingCustomer = this.options.find(item => String(item.Customer_ID) === String(newVal))
+          
+          if (!existingCustomer) {
+            // 如果没有找到匹配的客户,则加载客户信息
+            this.loadCustomerById(newVal)
+          }
+        } else {
+          // 如果value为空,清空选项
+          this.options = []
         }
       }
     },
@@ -289,6 +298,9 @@ export default {
           if (customer) {
             // 只保留匹配的客户选项
             this.options = [customer]
+            // 设置当前值以确保选中状态
+            this.currentValue = String(customer.Customer_ID)
+            console.log('订单表单客户回显:', customer.Customer_NAME, customer.Customer_ID)
           } else {
             // 如果在当前页没找到,可能需要查询更多页面
             console.warn(`未找到客户ID为 ${customerId} 的客户信息`)

+ 45 - 18
src/constants/forecast.js

@@ -271,27 +271,54 @@ export const APPROVAL_FORM_RULES = {
 }
 
 /**
+ * 获取下个月的年份和月份
+ * @returns {{year: string, month: number}} 下个月的年份和月份
+ */
+function getNextMonthYearAndMonth() {
+  const now = new Date()
+  const currentYear = now.getFullYear()
+  const currentMonth = now.getMonth() + 1 // getMonth() 返回 0-11,需要 +1
+  
+  if (currentMonth === 12) {
+    // 当前是12月,下个月是明年1月
+    return {
+      year: (currentYear + 1).toString(),
+      month: 1
+    }
+  } else {
+    // 其他月份,直接 +1
+    return {
+      year: currentYear.toString(),
+      month: currentMonth + 1
+    }
+  }
+}
+
+/**
  * 默认表单数据
  * @readonly
  */
-export const DEFAULT_FORECAST_FORM = {
-  forecastCode: '',
-  year: new Date().getFullYear().toString(),
-  month: new Date().getMonth() + 1,
-  customerId: null,
-  customerCode: '',
-  customerName: '',
-  brandId: null,
-  brandCode: '',
-  brandName: '',
-  itemId: null,
-  itemCode: '',
-  itemName: '',
-  specs: '',
-  forecastQuantity: null,
-  currentInventory: null,
-  approvalStatus: APPROVAL_STATUS.PENDING
-}
+export const DEFAULT_FORECAST_FORM = (() => {
+  const { year, month } = getNextMonthYearAndMonth()
+  return {
+    forecastCode: '',
+    year,
+    month,
+    customerId: null,
+    customerCode: '',
+    customerName: '',
+    brandId: null,
+    brandCode: '',
+    brandName: '',
+    itemId: null,
+    itemCode: '',
+    itemName: '',
+    specs: '',
+    forecastQuantity: null,
+    currentInventory: null,
+    approvalStatus: APPROVAL_STATUS.PENDING
+  }
+})()
 
 /**
  * 默认审批表单数据

+ 96 - 4
src/views/forecast/forecastIndex.js

@@ -35,10 +35,18 @@ export default {
       loading: true,
       /** @type {boolean} 表单提交状态 */
       submitting: false,
-      /** @type {boolean} 添加/编辑弹窗显示状态 */
+      /** @type {boolean} 保存按钮加载状态 */
+      saveLoading: false,
+      /** @type {boolean} 添加/编辑弹窗显示状态(保留兼容性) */
       dialogVisible: false,
-      /** @type {boolean} 是否为编辑模式 */
+      /** @type {boolean} 是否为编辑模式(保留兼容性) */
       isEdit: false,
+      /** @type {boolean} 表单页面显示状态 */
+      editVisible: false,
+      /** @type {string} 表单模式:'add' | 'edit' | 'view' */
+      editMode: 'add',
+      /** @type {string} 表单标题 */
+      editTitle: '',
       /** @type {string|number|null} 当前编辑的预测记录ID */
       currentForecastId: null,
       /** @type {Object} 分页配置 */
@@ -520,6 +528,28 @@ export default {
     },
 
     /**
+     * 新增预测申报(新版本)
+     * @description 显示新增预测申报表单页面
+     */
+    handleAdd() {
+      console.log('新增预测申报')
+      this.editMode = 'add'
+      this.editTitle = '新增预测申报'
+      this.currentForecastId = null
+      this.editVisible = true
+      
+      // 重置表单数据
+      this.form = { ...DEFAULT_FORECAST_FORM }
+      
+      // 生成预测编码
+      this.generateForecastCode()
+      
+      // 保持兼容性
+      this.isEdit = false
+      this.dialogVisible = true
+    },
+
+    /**
      * 编辑按钮点击
      * @param {Object} row - 行数据
      * @param {number} index - 行索引
@@ -537,12 +567,72 @@ export default {
     },
 
     /**
+     * 编辑按钮点击(新版本)
+     * @param {Object} row - 行数据
+     * @param {number} index - 行索引
+     * @description 显示编辑预测申报表单页面
+     */
+    handleEdit(row, index) {
+      if (!this.canEditRow(row)) {
+        this.$message.warning('已审批或已拒绝的记录不能修改')
+        return
+      }
+
+      console.log('编辑预测申报', row, index)
+      this.editMode = 'edit'
+      this.editTitle = '编辑预测申报'
+      this.currentForecastId = row.id
+      this.editVisible = true
+      
+      // 设置表单数据
+      this.form = { ...row }
+      
+      // 保持兼容性
+      this.isEdit = true
+      this.dialogVisible = true
+    },
+
+    /**
+     * 返回列表
+     * @description 关闭表单页面,返回列表页面
+     */
+    handleBackToList() {
+      this.editVisible = false
+      this.editMode = 'add'
+      this.editTitle = ''
+      this.currentForecastId = null
+      this.form = { ...DEFAULT_FORECAST_FORM }
+      
+      // 保持兼容性
+      this.dialogVisible = false
+      this.isEdit = false
+    },
+
+    /**
+     * 处理保存按钮点击
+     * @returns {void}
+     */
+    handleSave() {
+      if (this.$refs.forecastForm) {
+        this.saveLoading = true
+        this.$refs.forecastForm.handleSave()
+      }
+    },
+
+    /**
      * 处理表单提交成功
      * @param {Object} data - 提交成功的数据
      * @returns {void}
      */
     handleFormSubmit(data) {
+      console.log('表单提交成功', data)
+      this.saveLoading = false
+      // 关闭表单页面,返回列表
+      this.handleBackToList()
+      // 刷新列表数据
       this.refreshChange()
+      // 显示成功消息
+      this.$message.success(this.editMode === 'add' ? '新增成功' : '修改成功')
     },
 
     /**
@@ -550,8 +640,10 @@ export default {
      * @returns {void}
      */
     handleFormClose() {
-      this.dialogVisible = false
-      this.currentForecastId = null
+      console.log('表单关闭')
+      this.saveLoading = false
+      // 返回列表页面
+      this.handleBackToList()
     },
 
     /**

+ 150 - 63
src/views/forecast/index.vue

@@ -1,79 +1,107 @@
 <template>
   <basic-container>
-    <!-- 数据表格 -->
-    <avue-crud
-      :option="option"
-      :table-loading="loading"
-      :data="data"
-      :page.sync="page"
-      ref="crud"
-      v-model="form"
-      :permission="permissionList"
-      @search-change="searchChange"
-      @search-reset="searchReset"
-      @current-change="currentChange"
-      @size-change="sizeChange"
-      @refresh-change="refreshChange"
-      @on-load="onLoad"
-      @row-add="rowAdd"
-      @row-edit="rowEdit"
-      @row-save="rowSave"
-      @row-cancel="rowCancel"
-    >
-      <!-- 自定义新增按钮 -->
-      <template slot="menuLeft">
-        <el-button
-          type="primary"
-          size="small"
-          icon="el-icon-plus"
-          @click="rowAdd"
-        >
-          新增预测申报
-        </el-button>
-      </template>
+    <!-- 预测列表页面 -->
+    <div v-if="!editVisible">
+      <!-- 数据表格 -->
+      <avue-crud
+        :option="option"
+        :table-loading="loading"
+        :data="data"
+        :page.sync="page"
+        ref="crud"
+        v-model="form"
+        :permission="permissionList"
+        @search-change="searchChange"
+        @search-reset="searchReset"
+        @current-change="currentChange"
+        @size-change="sizeChange"
+        @refresh-change="refreshChange"
+        @on-load="onLoad"
+        @row-add="rowAdd"
+        @row-edit="rowEdit"
+        @row-save="rowSave"
+        @row-cancel="rowCancel"
+      >
+        <!-- 自定义新增按钮 -->
+        <template slot="menuLeft">
+          <el-button
+            type="primary"
+            size="small"
+            icon="el-icon-plus"
+            @click="handleAdd"
+          >
+            新增预测申报
+          </el-button>
+        </template>
 
-      <!-- 自定义审批状态显示 -->
-      <template slot-scope="{row}" slot="approvalStatus">
-        <el-tag
-          :type="getApprovalStatusType(row.approvalStatus)"
-          size="small"
-        >
-          {{ getApprovalStatusLabel(row.approvalStatus) }}
-        </el-tag>
-      </template>
+        <!-- 自定义审批状态显示 -->
+        <template slot-scope="{row}" slot="approvalStatus">
+          <el-tag
+            :type="getApprovalStatusType(row.approvalStatus)"
+            size="small"
+          >
+            {{ getApprovalStatusLabel(row.approvalStatus) }}
+          </el-tag>
+        </template>
+
+        <!-- 自定义编辑按钮 -->
+        <template slot-scope="{row, index}" slot="editBtn">
+          <el-button
+            v-if="canEdit(row)"
+            type="primary"
+            size="small"
+            icon="el-icon-edit"
+            @click="handleEdit(row, index)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            v-else
+            type="info"
+            size="small"
+            icon="el-icon-view"
+            disabled
+          >
+            不可编辑
+          </el-button>
+        </template>
+      </avue-crud>
+    </div>
 
-      <!-- 自定义编辑按钮 -->
-      <template slot-scope="{row, index}" slot="editBtn">
+    <!-- 预测表单页面 -->
+    <div v-if="editVisible">
+      <!-- 表单头部操作区域 -->
+      <div class="form-header">
         <el-button
-          v-if="canEdit(row)"
-          type="primary"
+          type="default"
           size="small"
-          icon="el-icon-edit"
-          @click="rowEdit(row, index)"
+          icon="el-icon-arrow-left"
+          @click="handleBackToList"
         >
-          编辑
+          返回列表
         </el-button>
+        <span class="form-title">{{ editTitle }}</span>
         <el-button
-          v-else
-          type="info"
+          type="primary"
+          icon="el-icon-check"
           size="small"
-          icon="el-icon-view"
-          disabled
+          :loading="saveLoading"
+          @click="handleSave"
         >
-          不可编辑
+          保存
         </el-button>
-      </template>
-    </avue-crud>
+      </div>
 
-    <!-- 使用销售预测表单组件 -->
-    <forecast-form
-      v-if="dialogVisible"
-      :visible="dialogVisible"
-      :is-edit="isEdit"
-      :forecast-id="currentForecastId"
-      @close="handleFormClose"
-      @submit="handleFormSubmit"
-    />
+      <!-- 使用销售预测表单组件 -->
+      <forecast-form
+        ref="forecastForm"
+        :visible="true"
+        :is-edit="editMode === 'edit'"
+        :forecast-id="currentForecastId"
+        @close="handleFormClose"
+        @submit="handleFormSubmit"
+      />
+    </div>
   </basic-container>
 </template>
 
@@ -98,4 +126,63 @@ export default {
 
 <style lang="scss">
 @import './index.scss';
+
+/* 表单头部样式 */
+.form-header {
+  background: #fff;
+  padding: 16px 20px;
+  margin-bottom: 20px;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  display: flex;
+  align-items: center;
+  gap: 16px;
+  border-bottom: 1px solid #e4e7ed;
+
+  .form-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #303133;
+    margin-left: 8px;
+    flex: 1;
+  }
+
+  .el-button {
+    border-radius: 4px;
+    padding: 8px 16px;
+    font-size: 13px;
+    
+    &:hover {
+      background-color: #f5f7fa;
+      border-color: #c0c4cc;
+    }
+  }
+}
+
+/* 表单页面容器样式 */
+.form-container {
+  background: #fff;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .form-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 12px;
+    
+    .form-title {
+      margin-left: 0;
+      font-size: 14px;
+    }
+    
+    .el-button {
+      width: 100%;
+      justify-content: center;
+    }
+  }
+}
 </style>