gaoluyang
2025-09-17 3a382eef305870f1fa5e40987d10177048a47b56
采购计划前端页面
已添加2个文件
948 ■■■■■ 文件已修改
src/api/procurementManagement/procurementPlan.js 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementPlan/index.vue 821 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/procurementPlan.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,127 @@
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢é‡‡è´­è®¡åˆ’列表
export function getProcurementPlanList(query) {
  return request({
    url: "/procurement/plan/list",
    method: "get",
    params: query,
  });
}
// æ–°å¢žé‡‡è´­è®¡åˆ’
export function addProcurementPlan(data) {
  return request({
    url: "/procurement/plan/add",
    method: "post",
    data: data,
  });
}
// ä¿®æ”¹é‡‡è´­è®¡åˆ’
export function updateProcurementPlan(data) {
  return request({
    url: "/procurement/plan/update",
    method: "put",
    data: data,
  });
}
// åˆ é™¤é‡‡è´­è®¡åˆ’
export function deleteProcurementPlan(ids) {
  return request({
    url: "/procurement/plan/delete",
    method: "delete",
    data: ids,
  });
}
// æ ¹æ®ID获取采购计划详情
export function getProcurementPlanById(id) {
  return request({
    url: `/procurement/plan/${id}`,
    method: "get",
  });
}
// æ‰§è¡Œé‡‡è´­è®¡åˆ’计算
export function calculateProcurementPlan(data) {
  return request({
    url: "/procurement/plan/calculate",
    method: "post",
    data: data,
  });
}
// èŽ·å–äº§å“çŽ°æœ‰åº“å­˜ä¿¡æ¯
export function getProductExistingStock(productIds) {
  return request({
    url: "/inventory/existingStock/productInfo",
    method: "post",
    data: productIds,
  });
}
// èŽ·å–äº§å“å®‰å…¨åº“å­˜ä¿¡æ¯
export function getProductSafetyStock(productIds) {
  return request({
    url: "/inventory/safetyStock/productInfo",
    method: "post",
    data: productIds,
  });
}
// èŽ·å–äº§å“é¢„è®¡å‡ºåº“ä¿¡æ¯
export function getProductExpectedOutbound(productIds) {
  return request({
    url: "/inventory/expectedOutbound/productInfo",
    method: "post",
    data: productIds,
  });
}
// èŽ·å–äº§å“é¢„è®¡å…¥åº“ä¿¡æ¯
export function getProductExpectedInbound(productIds) {
  return request({
    url: "/inventory/expectedInbound/productInfo",
    method: "post",
    data: productIds,
  });
}
// å¯¼å‡ºé‡‡è´­è®¡åˆ’
export function exportProcurementPlan(query) {
  return request({
    url: "/procurement/plan/export",
    method: "get",
    params: query,
    responseType: "blob",
  });
}
// ç”Ÿæˆé‡‡è´­è®¢å•
export function generatePurchaseOrder(data) {
  return request({
    url: "/procurement/plan/generateOrder",
    method: "post",
    data: data,
  });
}
// éªŒè¯è®¡ç®—公式
export function validateFormula(formula) {
  return request({
    url: "/procurement/plan/validateFormula",
    method: "post",
    data: { formula },
  });
}
// èŽ·å–è®¡ç®—å…¬å¼æ¨¡æ¿
export function getFormulaTemplates() {
  return request({
    url: "/procurement/plan/formulaTemplates",
    method: "get",
  });
}
src/views/procurementManagement/procurementPlan/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,821 @@
<template>
  <div class="app-container">
    <!-- æœç´¢åŒºåŸŸ -->
    <el-card class="search-card" shadow="never">
      <el-form :model="searchForm" :inline="true" class="search-form">
        <el-form-item label="计划名称">
          <el-input v-model="searchForm.planName" placeholder="请输入计划名称" clearable />
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="searchForm.status" placeholder="请选择状态" clearable style="width: 150px">
            <el-option label="启用" value="active" />
            <el-option label="禁用" value="inactive" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">
            <el-icon><Search /></el-icon>
            æœç´¢
          </el-button>
          <el-button @click="handleReset">
            <el-icon><Refresh /></el-icon>
            é‡ç½®
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- æ“ä½œæŒ‰é’® -->
    <el-card class="table-card" shadow="never">
      <div class="table-header">
        <div class="table-title">采购计划列表</div>
        <div class="table-actions">
          <el-button type="primary" @click="handleAdd">
            <el-icon><Plus /></el-icon>
            æ–°å¢žè®¡åˆ’
          </el-button>
          <el-button type="info" @click="handleExport">
            <el-icon><Download /></el-icon>
            å¯¼å‡º
          </el-button>
        </div>
      </div>
      <!-- æ•°æ®è¡¨æ ¼ -->
      <el-table
        v-loading="loading"
        :data="tableData"
        stripe
        border
        style="width: 100%"
      >
        <el-table-column prop="planName" label="计划名称" min-width="150" />
        <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
        <el-table-column prop="formula" label="计算公式" min-width="200" show-overflow-tooltip>
          <template #default="{ row }">
            <el-tag type="info" size="small">{{ row.formula }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态" width="80" align="center">
          <template #default="{ row }">
            <el-tag :type="row.status === 'active' ? 'success' : 'info'" size="small">
              {{ row.status === 'active' ? '启用' : '禁用' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="lastCalculateTime" label="最后计算时间" width="160" />
        <el-table-column label="操作" width="200" fixed="right" align="center">
          <template #default="{ row }">
            <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
            <el-button type="success" link @click="handleCalculate(row)">计算</el-button>
            <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µ -->
      <div class="pagination-container">
        <el-pagination
          v-model:current-page="pagination.current"
          v-model:page-size="pagination.size"
          :page-sizes="[10, 20, 50, 100]"
          :total="pagination.total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </el-card>
    <!-- æ–°å¢ž/编辑对话框 -->
    <el-dialog
      v-model="dialogVisible"
      :title="dialogType === 'add' ? '新增采购计划' : '编辑采购计划'"
      width="1000px"
      :close-on-click-modal="false"
    >
      <div class="form-container">
        <!-- åŸºæœ¬ä¿¡æ¯ -->
        <div class="form-section">
          <div class="section-title">基本信息</div>
          <el-form
            ref="formRef"
            :model="formData"
            :rules="formRules"
            label-width="120px"
          >
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="编码" prop="code">
                  <el-input v-model="formData.code" placeholder="系统自动生成" disabled />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="名称" prop="planName" required>
                  <el-input v-model="formData.planName" placeholder="请输入计划名称" />
                </el-form-item>
              </el-col>
            </el-row>
            <el-form-item label="描述" prop="description">
              <el-input
                v-model="formData.description"
                type="textarea"
                :rows="3"
                placeholder="请输入计划描述"
              />
            </el-form-item>
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="数据状态" prop="dataStatus">
                  <el-select v-model="formData.dataStatus" placeholder="请选择状态" style="width: 100%">
                    <el-option label="草稿" value="draft" />
                    <el-option label="已审核" value="approved" />
                    <el-option label="已禁用" value="disabled" />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="是否系统预置">
                  <el-checkbox v-model="formData.isSystemPreset">是</el-checkbox>
                </el-form-item>
              </el-col>
            </el-row>
          </el-form>
        </div>
        <!-- è®¡ç®—参数 -->
        <div class="form-section">
          <div class="section-title">计算参数</div>
          <el-tabs v-model="activeTab" class="param-tabs">
            <el-tab-pane label="需求参数" name="demand">
              <div class="checkbox-group">
                <el-checkbox v-model="formData.considerExistingStock">考虑现有库存</el-checkbox>
                <el-checkbox v-model="formData.warehouseMRPControl">仓库运行MRP的控制</el-checkbox>
                <el-checkbox v-model="formData.calculateTotalDemand">计算总需求</el-checkbox>
                <el-checkbox v-model="formData.considerSafetyStock">考虑安全库存</el-checkbox>
                <el-checkbox v-model="formData.considerLockedStock">考虑锁库</el-checkbox>
                <el-checkbox v-model="formData.notConsiderMaterialAux">不考虑物料辅助属性</el-checkbox>
                <el-checkbox v-model="formData.negativeStockAsDemand">负库存作为需求</el-checkbox>
              </div>
            </el-tab-pane>
            <el-tab-pane label="计算参数" name="calculation">
              <div class="checkbox-group">
                <el-checkbox v-model="formData.considerExistingStock">考虑现有库存</el-checkbox>
                <el-checkbox v-model="formData.warehouseMRPControl">仓库运行MRP的控制</el-checkbox>
                <el-checkbox v-model="formData.calculateTotalDemand">计算总需求</el-checkbox>
                <el-checkbox v-model="formData.considerSafetyStock">考虑安全库存</el-checkbox>
                <el-checkbox v-model="formData.considerLockedStock">考虑锁库</el-checkbox>
                <el-checkbox v-model="formData.notConsiderMaterialAux">不考虑物料辅助属性</el-checkbox>
                <el-checkbox v-model="formData.negativeStockAsDemand">负库存作为需求</el-checkbox>
              </div>
            </el-tab-pane>
          </el-tabs>
        </div>
        <!-- æ±‡æ€»åˆå¹¶é€‰é¡¹ -->
        <div class="form-section">
          <div class="section-title">汇总合并选项</div>
          <div class="checkbox-group">
            <el-checkbox v-model="formData.summaryMaterial">物料</el-checkbox>
            <el-checkbox v-model="formData.summaryAuxAttributes">辅助属性</el-checkbox>
            <el-checkbox v-model="formData.summaryDemandDate">需求日期</el-checkbox>
          </div>
        </div>
        <!-- è®¡ç®—公式 -->
        <div class="form-section">
          <div class="section-title">计算公式</div>
          <div class="formula-input-section">
            <el-form-item label="计算公式" prop="formula" required>
              <el-input
                v-model="formData.formula"
                placeholder="例如: é¢„计出库数量 - çŽ°æœ‰åº“å­˜ + å®‰å…¨åº“å­˜ - é¢„计入库数量"
                @input="validateFormula"
              />
            </el-form-item>
            <div class="formula-help">
              <el-text type="info" size="small">
                æ”¯æŒå˜é‡ï¼šé¢„计出库数量、现有库存、安全库存、预计入库数量
              </el-text>
            </div>
          </div>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- äº§å“é€‰æ‹©å¯¹è¯æ¡† -->
    <el-dialog
      v-model="productSelectDialogVisible"
      title="选择产品"
      width="800px"
      :close-on-click-modal="false"
    >
      <div class="product-select">
        <el-alert
          title="请选择要计算的产品"
          type="info"
          :closable="false"
          show-icon
        >
          <template #default>
            <p>选择产品后,系统将根据当前计算公式和产品库存情况进行计算。</p>
          </template>
        </el-alert>
        <el-table
          v-loading="productLoading"
          :data="productList"
          @selection-change="handleProductSelectionChange"
          stripe
          border
          style="width: 100%; margin-top: 20px;"
        >
          <el-table-column type="selection" width="55" />
          <el-table-column prop="productName" label="产品名称" min-width="150" />
          <el-table-column prop="productCode" label="产品编码" width="120" />
          <el-table-column prop="existingStock" label="现有库存" width="100" align="right" />
          <el-table-column prop="safetyStock" label="安全库存" width="100" align="right" />
          <el-table-column prop="expectedOutbound" label="预计出库" width="100" align="right" />
          <el-table-column prop="expectedInbound" label="预计入库" width="100" align="right" />
        </el-table>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="productSelectDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleConfirmProductSelection" :disabled="selectedProducts.length === 0">
            ç¡®è®¤è®¡ç®—
          </el-button>
        </div>
      </template>
    </el-dialog>
    <!-- è®¡ç®—结果对话框 -->
    <el-dialog
      v-model="calculateDialogVisible"
      title="采购计算结果"
      width="1000px"
      :close-on-click-modal="false"
    >
      <div class="calculate-result">
        <el-alert
          title="计算结果"
          type="success"
          :closable="false"
          show-icon
        >
          <template #default>
            <p>基于当前配置的计算公式和库存情况,系统已计算出各产品的采购需求。</p>
          </template>
        </el-alert>
        <el-table :data="calculateResult" stripe border style="width: 100%; margin-top: 20px;">
          <el-table-column prop="productName" label="产品名称" min-width="150" />
          <el-table-column prop="productCode" label="产品编码" width="120" />
          <el-table-column prop="existingStock" label="现有库存" width="100" align="right" />
          <el-table-column prop="safetyStock" label="安全库存" width="100" align="right" />
          <el-table-column prop="expectedOutbound" label="预计出库数量" width="120" align="right" />
          <el-table-column prop="expectedInbound" label="预计入库数量" width="120" align="right" />
          <el-table-column prop="weeklyNetDemand" label="按周净需求" width="120" align="right">
            <template #default="{ row }">
              <el-tag :type="row.weeklyNetDemand > 0 ? 'warning' : 'success'" size="small">
                {{ row.weeklyNetDemand }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="suggestedPurchase" label="建议采购" width="100" align="right">
            <template #default="{ row }">
              <el-tag :type="row.suggestedPurchase > 0 ? 'danger' : 'success'" size="small">
                {{ row.suggestedPurchase }}
              </el-tag>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="calculateDialogVisible = false">关闭</el-button>
          <el-button type="primary" @click="handleCreatePurchaseOrder">生成采购订单</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Refresh, Plus, Download } from '@element-plus/icons-vue'
// å“åº”式数据
const loading = ref(false)
const submitLoading = ref(false)
const dialogVisible = ref(false)
const productSelectDialogVisible = ref(false)
const calculateDialogVisible = ref(false)
const dialogType = ref('add')
const productLoading = ref(false)
const selectedProducts = ref([])
const currentPlan = ref(null)
// æœç´¢è¡¨å•
const searchForm = reactive({
  planName: '',
  status: ''
})
// åˆ†é¡µæ•°æ®
const pagination = reactive({
  current: 1,
  size: 20,
  total: 0
})
// è¡¨å•数据
const formData = reactive({
  code: '',
  planName: '',
  description: '',
  dataStatus: '',
  isSystemPreset: false,
  formula: '',
  // è®¡ç®—参数
  considerExistingStock: false,
  warehouseMRPControl: false,
  calculateTotalDemand: false,
  considerSafetyStock: false,
  considerLockedStock: false,
  notConsiderMaterialAux: false,
  negativeStockAsDemand: false,
  // æ±‡æ€»åˆå¹¶é€‰é¡¹
  summaryMaterial: false,
  summaryAuxAttributes: false,
  summaryDemandDate: false
})
// å½“前激活的标签页
const activeTab = ref('demand')
// è¡¨å•验证规则
const formRules = {
  planName: [
    { required: true, message: '请输入计划名称', trigger: 'blur' }
  ],
  dataStatus: [
    { required: true, message: '请选择数据状态', trigger: 'change' }
  ],
  formula: [
    { required: true, message: '请输入计算公式', trigger: 'blur' }
  ]
}
// è¡¨æ ¼æ•°æ®
const tableData = ref([
  {
    id: 1,
    planName: '常规产品采购计划',
    description: '基于历史销售数据的常规产品采购计划',
    formula: '预计出库数量 - çŽ°æœ‰åº“å­˜ + å®‰å…¨åº“å­˜ - é¢„计入库数量',
    status: 'active',
    lastCalculateTime: '2024-12-01 10:30:00',
    remark: '适用于常规产品'
  },
  {
    id: 2,
    planName: '季节性产品采购计划',
    description: '考虑季节因素的季节性产品采购计划',
    formula: '预计出库数量 - çŽ°æœ‰åº“å­˜ + å®‰å…¨åº“å­˜ * 1.2 - é¢„计入库数量',
    status: 'active',
    lastCalculateTime: '2024-11-28 15:20:00',
    remark: '适用于季节性产品'
  }
])
// äº§å“åˆ—表数据
const productList = ref([
  {
    id: 1,
    productName: '产品A',
    productCode: 'PA001',
    existingStock: 100,
    safetyStock: 50,
    expectedOutbound: 200,
    expectedInbound: 30
  },
  {
    id: 2,
    productName: '产品B',
    productCode: 'PB002',
    existingStock: 80,
    safetyStock: 30,
    expectedOutbound: 150,
    expectedInbound: 20
  },
  {
    id: 3,
    productName: '产品C',
    productCode: 'PC003',
    existingStock: 120,
    safetyStock: 60,
    expectedOutbound: 180,
    expectedInbound: 25
  },
  {
    id: 4,
    productName: '产品D',
    productCode: 'PD004',
    existingStock: 90,
    safetyStock: 40,
    expectedOutbound: 160,
    expectedInbound: 35
  }
])
// è®¡ç®—结果数据
const calculateResult = ref([
  {
    productName: '产品A',
    existingStock: 100,
    safetyStock: 50,
    expectedOutbound: 200,
    expectedInbound: 30,
    weeklyNetDemand: 120,
    suggestedPurchase: 150
  },
  {
    productName: '产品B',
    existingStock: 80,
    safetyStock: 30,
    expectedOutbound: 150,
    expectedInbound: 20,
    weeklyNetDemand: 100,
    suggestedPurchase: 120
  }
])
// æ–¹æ³•
const handleSearch = () => {
  pagination.current = 1
  loadData()
}
const handleReset = () => {
  Object.assign(searchForm, {
    planName: '',
    status: ''
  })
  handleSearch()
}
const loadData = () => {
  loading.value = true
  // æ¨¡æ‹ŸAPI调用
  setTimeout(() => {
    pagination.total = tableData.value.length
    loading.value = false
  }, 500)
}
const handleAdd = () => {
  dialogType.value = 'add'
  resetForm()
  // è‡ªåŠ¨ç”Ÿæˆç¼–ç 
  formData.code = 'CGJH' + String(Date.now()).slice(-4)
  dialogVisible.value = true
}
const handleEdit = (row) => {
  dialogType.value = 'edit'
  Object.assign(formData, row)
  dialogVisible.value = true
}
const handleDelete = async (row) => {
  try {
    await ElMessageBox.confirm('确定要删除这个采购计划吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    const index = tableData.value.findIndex(item => item.id === row.id)
    if (index > -1) {
      tableData.value.splice(index, 1)
      ElMessage.success('删除成功')
      loadData()
    }
  } catch {
    // ç”¨æˆ·å–消删除
  }
}
const handleSubmit = async () => {
  try {
    // è¡¨å•验证
    if (!formData.planName || !formData.formula) {
      ElMessage.error('请填写必填项')
      return
    }
    submitLoading.value = true
    if (dialogType.value === 'add') {
      // æ–°å¢ž
      const newItem = {
        ...formData,
        id: Date.now(),
        lastCalculateTime: '-'
      }
      tableData.value.unshift(newItem)
      ElMessage.success('新增成功')
    } else {
      // ç¼–辑
      const index = tableData.value.findIndex(item => item.id === formData.id)
      if (index > -1) {
        tableData.value[index] = { ...formData }
        ElMessage.success('编辑成功')
      }
    }
    dialogVisible.value = false
    loadData()
  } catch (error) {
    ElMessage.error('操作失败')
  } finally {
    submitLoading.value = false
  }
}
const resetForm = () => {
  Object.assign(formData, {
    code: '',
    planName: '',
    description: '',
    dataStatus: '',
    isSystemPreset: false,
    formula: '',
    // è®¡ç®—参数
    considerExistingStock: false,
    warehouseMRPControl: false,
    calculateTotalDemand: false,
    considerSafetyStock: false,
    considerLockedStock: false,
    notConsiderMaterialAux: false,
    negativeStockAsDemand: false,
    // æ±‡æ€»åˆå¹¶é€‰é¡¹
    summaryMaterial: false,
    summaryAuxAttributes: false,
    summaryDemandDate: false
  })
  activeTab.value = 'demand'
}
const validateFormula = () => {
  // ç®€å•的公式验证
  const formula = formData.formula
  if (formula && !/^[a-zA-Z\u4e00-\u9fa5\s\*\+\-\/\(\)\d\.]+$/.test(formula)) {
    ElMessage.warning('公式格式可能不正确,请检查')
  }
}
const handleCalculate = (row) => {
  currentPlan.value = row
  productSelectDialogVisible.value = true
  loadProductList()
}
const loadProductList = () => {
  productLoading.value = true
  // æ¨¡æ‹ŸåŠ è½½äº§å“æ•°æ®
  setTimeout(() => {
    productLoading.value = false
  }, 500)
}
const handleProductSelectionChange = (selection) => {
  selectedProducts.value = selection
}
const handleConfirmProductSelection = () => {
  if (selectedProducts.value.length === 0) {
    ElMessage.warning('请选择要计算的产品')
    return
  }
  ElMessage.success(`正在计算 ${currentPlan.value.planName} çš„采购需求...`)
  productSelectDialogVisible.value = false
  // æ ¹æ®é€‰æ‹©çš„产品和计算公式进行计算
  calculateWithSelectedProducts()
}
const calculateWithSelectedProducts = () => {
  // æ¨¡æ‹Ÿè®¡ç®—过程
  setTimeout(() => {
    // æ ¹æ®é€‰æ‹©çš„产品更新计算结果
    const result = selectedProducts.value.map(product => {
      // è¿™é‡Œåº”该根据实际的计算公式进行计算
      // ç¤ºä¾‹ï¼šé¢„计出库数量 - çŽ°æœ‰åº“å­˜ + å®‰å…¨åº“å­˜ - é¢„计入库数量
      const weeklyNetDemand = product.expectedOutbound - product.existingStock + product.safetyStock - product.expectedInbound
      const suggestedPurchase = Math.max(0, weeklyNetDemand)
      return {
        productName: product.productName,
        productCode: product.productCode,
        existingStock: product.existingStock,
        safetyStock: product.safetyStock,
        expectedOutbound: product.expectedOutbound,
        expectedInbound: product.expectedInbound,
        weeklyNetDemand: weeklyNetDemand,
        suggestedPurchase: suggestedPurchase
      }
    })
    calculateResult.value = result
    calculateDialogVisible.value = true
  }, 1000)
}
const handleCreatePurchaseOrder = () => {
  ElMessage.success('正在生成采购订单...')
  calculateDialogVisible.value = false
}
const handleExport = () => {
  ElMessage.success('正在导出数据...')
}
const handleSizeChange = (size) => {
  pagination.size = size
  loadData()
}
const handleCurrentChange = (current) => {
  pagination.current = current
  loadData()
}
// ç”Ÿå‘½å‘¨æœŸ
onMounted(() => {
  loadData()
})
</script>
<style scoped>
.app-container {
  padding: 20px;
}
.page-header {
  margin-bottom: 20px;
}
.page-header h2 {
  margin: 0 0 8px 0;
  color: #303133;
  font-size: 24px;
  font-weight: 600;
}
.page-header p {
  margin: 0;
  color: #909399;
  font-size: 14px;
}
.search-card {
  margin-bottom: 20px;
}
.search-form {
  margin-bottom: 0;
}
.table-card {
  margin-bottom: 20px;
}
.table-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}
.table-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}
.table-actions {
  display: flex;
  gap: 10px;
}
.pagination-container {
  margin-top: 20px;
  display: flex;
  justify-content: end;
}
.form-container {
  padding: 0 20px;
}
.formula-help {
  margin-top: 5px;
}
.calculate-result {
  padding: 20px 0;
}
.dialog-footer {
  text-align: right;
}
:deep(.el-card__body) {
  padding: 20px;
}
:deep(.el-table) {
  font-size: 14px;
}
:deep(.el-form-item__label) {
  font-weight: 500;
}
.form-container {
  padding: 0;
}
.form-section {
  margin-bottom: 24px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  overflow: hidden;
}
.section-title {
  background-color: #f5f7fa;
  padding: 12px 16px;
  font-weight: 600;
  color: #303133;
  border-bottom: 1px solid #e4e7ed;
}
.form-section .el-form {
  padding: 20px;
}
.param-tabs {
  padding: 20px;
}
.param-tabs :deep(.el-tabs__header) {
  margin-bottom: 20px;
}
.param-tabs :deep(.el-tabs__item.is-active) {
  color: #f56c6c;
  border-bottom-color: #f56c6c;
}
.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.checkbox-group .el-checkbox {
  margin-right: 0;
  margin-bottom: 8px;
}
.formula-input-section {
  padding: 20px;
}
.formula-input-section .el-form-item {
  margin-bottom: 12px;
}
.formula-help {
  text-align: center;
  margin-top: 8px;
}
</style>