进销存-升级
1.财务报表查询接口传参修改
2.会计核算页面修改且查询接口传参修改
3.项目利润、增值税对比页面联调
已修改4个文件
524 ■■■■■ 文件已修改
src/views/equipmentManagement/ledger/Form.vue 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/index.vue 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/accounting/index.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/projectProfit/index.vue 186 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/Form.vue
@@ -1,5 +1,5 @@
<template>
  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
  <el-form :model="form" label-width="120px" :rules="formRules" ref="formRef">
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="设备名称" prop="deviceName">
@@ -14,6 +14,27 @@
      <el-col :span="12">
        <el-form-item label="设备品牌" prop="deviceBrand">
          <el-input v-model="form.deviceBrand" placeholder="请输入设备品牌" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="设备类型" prop="type">
          <el-select
            v-model="form.type"
            placeholder="请选择或输入设备类型"
            clearable
            filterable
            allow-create
            default-first-option
            style="width: 100%"
            @change="handleDeviceTypeChange"
          >
            <el-option
              v-for="item in deviceTypeOptions"
              :key="item"
              :label="item"
              :value="item"
            />
          </el-select>
        </el-form-item>
      </el-col>
      <el-col :span="12">
@@ -32,8 +53,19 @@
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="启用折旧" prop="enableDepreciation">
          <el-switch v-model="form.enableDepreciation" :active-value="true" :inactive-value="false" />
        <el-form-item label="启用折旧" prop="isDepr">
          <el-switch v-model="form.isDepr" :active-value="1" :inactive-value="2" />
        </el-form-item>
      </el-col>
      <el-col :span="12" v-if="form.isDepr === 1">
        <el-form-item label="每年折旧金额" prop="annualDepreciationAmount">
          <el-input-number
            :step="0.01"
            :min="0"
            style="width: 100%"
            v-model="form.annualDepreciationAmount"
            placeholder="请输入每年折旧金额"
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
@@ -149,24 +181,47 @@
});
const formRef = ref(null);
const operationType = ref('');
// 设备类型固定选项
const deviceTypeOptions = ref([
  '生产设备',
  '办公设备',
  '检测设备',
  '运输设备',
  '其他设备'
]);
const formRules = {
    deviceName: [{ required: true, trigger: "blur", message: "请输入" }],
    deviceModel: [{ required: true, trigger: "blur", message: "请输入" }],
    type: [{ required: true, trigger: "change", message: "请选择或输入设备类型" }],
    supplierName: [{ required: true, trigger: "blur", message: "请输入" }],
    unit: [{ required: true, trigger: "blur", message: "请输入" }],
    number: [{ required: true, trigger: "blur", message: "请输入" }],
    taxIncludingPriceUnit: [{ required: true, trigger: "blur", message: "请输入" }],
    taxRate: [{ required: true, trigger: "change", message: "请输入" }],
    planRuntimeTime: [{ required: true, trigger: "change", message: "请选择" }],
    annualDepreciationAmount: [
        {
            validator: (rule, value, callback) => {
                if (form.isDepr === 1 && (value === undefined || value === null || value === '')) {
                    callback(new Error('启用折旧时,请输入每年折旧金额'));
                } else {
                    callback();
                }
            },
            trigger: "blur"
        }
    ],
}
const { form, resetForm } = useFormData({
  deviceName: undefined, // 设备名称
  deviceModel: undefined, // 规格型号
  deviceBrand: undefined, // 设备品牌
  type: undefined, // 设备类型
  supplierName: undefined, // 供应商
  storageLocation: undefined, // 存放位置
  enableDepreciation: false, // 是否启用折旧
  isDepr: 2, // 是否启用折旧 1-是 2-否
  annualDepreciationAmount: undefined, // 每年折旧金额
  unit: undefined, // 单位
  number: 1, // 数量
  taxIncludingPriceUnit: undefined, // 含税单价
@@ -187,9 +242,11 @@
    form.deviceName = data.deviceName;
    form.deviceModel = data.deviceModel;
    form.deviceBrand = data.deviceBrand;
    form.type = data.type;
    form.supplierName = data.supplierName;
    form.storageLocation = data.storageLocation;
    form.enableDepreciation = data.enableDepreciation;
    form.isDepr = data.isDepr;
    form.annualDepreciationAmount = data.annualDepreciationAmount;
    form.unit = data.unit;
    form.number = 1;
    form.taxIncludingPriceUnit = data.taxIncludingPriceUnit;
@@ -200,6 +257,13 @@
  }
};
const handleDeviceTypeChange = (value) => {
  // 如果输入的新值不在固定选项中,则添加到选项列表
  if (value && !deviceTypeOptions.value.includes(value)) {
    deviceTypeOptions.value.push(value);
  }
};
const mathNum = () => {
  if (!form.taxIncludingPriceUnit) {
    ElMessage.error("请输入单价");
src/views/equipmentManagement/ledger/index.vue
@@ -7,7 +7,6 @@
          style="width: 240px"
          placeholder="请输入设备名称"
          clearable
          :prefix-icon="Search"
          @change="getTableData"
        />
      </el-form-item>
@@ -17,7 +16,6 @@
            style="width: 240px"
            placeholder="请输入规格型号"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
@@ -27,17 +25,6 @@
            style="width: 240px"
            placeholder="请输入供应商"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="单位">
        <el-input
            v-model="filters.unit"
            style="width: 240px"
            placeholder="请输入单位"
            clearable
            :prefix-icon="Search"
            @change="getTableData"
        />
      </el-form-item>
@@ -130,81 +117,53 @@
    deviceName: undefined,
    deviceModel: undefined,
    supplierName: undefined,
    unit: undefined,
    entryDateStart: undefined,
    entryDateEnd: undefined,
  },
  [
    {
      label: "设备名称",
      align: "center",
      prop: "deviceName",
    },
    {
      label: "规格型号",
      align: "center",
      prop: "deviceModel",
    },
    {
      label: "设备品牌",
      align: "center",
      prop: "deviceBrand",
    },
    {
      label: "设备类型",
      prop: "type",
    },
    {
      label: "供应商",
      align: "center",
      prop: "supplierName",
    },
    {
      label: "单位",
      align: "center",
      prop: "unit",
    },
    {
      label: "存放位置",
      align: "center",
      prop: "storageLocation",
    },
    {
      label: "数量",
      align: "center",
      prop: "number",
    },
    {
      label: "含税单价",
      align: "center",
      prop: "taxIncludingPriceUnit",
    },
    {
      label: "含税总价",
      align: "center",
      prop: "taxIncludingPriceTotal",
    },
    {
      label: "税率",
      align: "center",
      prop: "taxRate",
    },
    {
      label: "不含税总价",
      align: "center",
      prop: "unTaxIncludingPriceTotal",
    },
    {
      label: "启用折旧",
      align: "center",
      prop: "enableDepreciation",
      formatData: (v) => (v ? "是" : "否"),
    },
    {
      label: "录入人",
      align: "center",
      prop: "createUser",
    },
    {
      label: "录入日期",
      align: "center",
      prop: "createTime",
      formatData: (v) => {
        if (!v) return '';
        // 如果包含时分秒,只取日期部分
        if (v.includes(' ')) {
          return v.split(' ')[0];
        }
        return v;
      },
    },
        {
            dataType: "action",
@@ -215,14 +174,12 @@
            operation: [
                {
                    name: "编辑",
                    type: "text",
                    clickFun: (row) => {
                        edit(row.id)
                    },
                },
                {
                    name: "生成二维码",
                    type: "text",
                    clickFun: (row) => {
                        showQRCode(row)
                    },
src/views/financialManagement/accounting/index.vue
@@ -2,14 +2,31 @@
  <div style="padding: 20px;">
    <!-- 页面标题和筛选条件 -->
    <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;">
      <el-button
        type="primary"
        icon="Refresh"
        @click="resetFilters"
        size="default"
      >
        查询
      </el-button>
      <el-form :inline="true">
        <el-form-item label="年份">
          <el-date-picker
            v-model="selectedYear"
            type="year"
            placeholder="请选择年份"
            format="YYYY"
            value-format="YYYY"
            clearable
            @change="fetchData()"
            style="width: 200px"
            :disabled-date="(date) => date.getFullYear() > new Date().getFullYear()"
          />
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
            icon="Refresh"
            @click="resetFilters"
            size="default"
          >
            重置
          </el-button>
        </el-form-item>
      </el-form>
    </div>
    <main class="container mx-auto px-4 pb-10">
@@ -27,7 +44,7 @@
        <el-card class="bg3">
          <p>资产原值</p>
          <h3>
            ¥{{ assetInfo.totalOriginalValue }}
            ¥{{ formatCurrency(assetInfo.totalOriginalValue) }}
          </h3>
        </el-card>
@@ -35,7 +52,7 @@
        <el-card class="bg4">
          <p>累计折旧</p>
          <h3>
            ¥{{ assetInfo.totalDepreciation }}
            ¥{{ formatCurrency(assetInfo.totalDepreciation) }}
          </h3>
        </el-card>
@@ -43,7 +60,21 @@
        <el-card class="bg5">
          <p>净值</p>
          <h3>
            ¥{{ assetInfo.totalNetValue }}
            ¥{{ formatCurrency(assetInfo.totalNetValue) }}
          </h3>
        </el-card>
        <!-- 负债 -->
        <el-card class="bg2">
          <p>负债</p>
          <h3>
            ¥{{ formatCurrency(assetInfo.debt) }}
          </h3>
        </el-card>
        <!-- 库存资产 -->
        <el-card class="bg3">
          <p>库存资产</p>
          <h3>
            ¥{{ formatCurrency(assetInfo.inventoryValue) }}
          </h3>
        </el-card>
      </div>
@@ -62,7 +93,7 @@
                style="height: 260px; width: 35%;">
              <div class="chart-num">
                <span style="font-size: 22px;">设备类型</span>
                <span style="font-size: 36px; font-weight: 500; font-family: 'MyCustomFont', sans-serif;">{{ assetInfo.totalEquipment }}</span>
                <span style="font-size: 36px; font-weight: 500; font-family: 'MyCustomFont', sans-serif;">{{ deviceTypeTotalCount }}</span>
              </div>
            </Echarts>
            <Echarts
@@ -86,7 +117,6 @@
          style="width: 100%"
          :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
        >
          <el-table-column prop="id" label="资产编号" width="120" />
          <el-table-column prop="deviceName" label="设备名称" width="250" />
          <el-table-column prop="deviceModel" label="型号规格" min-width="150" />
          <el-table-column prop="supplierName" label="供应商" min-width="120" />
@@ -94,27 +124,17 @@
          <el-table-column prop="number" label="数量" width="120" />
          <el-table-column prop="originalValue" label="原值(元)" width="120">
            <template #default="{ row }">
              ¥{{ formatCurrency(row.taxIncludingPriceTotal) }}
              {{ formatCurrency(row.taxIncludingPriceTotal) }}
            </template>
          </el-table-column>
          <el-table-column prop="depreciation" label="累计折旧(元)" width="140">
            <template #default="{ row }">
              ¥{{ formatCurrency(row.taxIncludingPriceTotal-row.unTaxIncludingPriceTotal) }}
              {{ formatCurrency(row.deprAmount) }}
            </template>
          </el-table-column>
          <el-table-column prop="netValue" label="净值(元)" width="120">
            <template #default="{ row }">
              ¥{{ formatCurrency(row.unTaxIncludingPriceTotal) }}
            </template>
          </el-table-column>
          <el-table-column prop="status" label="状态" width="100">
            <template #default="{ row }">
              <el-tag
                :type="getStatusTagType(row.status)"
                size="small"
              >
                {{ row.status }}
              </el-tag>
              {{ formatCurrency(row.netValue) }}
            </template>
          </el-table-column>
        </el-table>
@@ -142,20 +162,27 @@
import 'element-plus/dist/index.css';
import Echarts from "@/components/Echarts/echarts.vue";
import { getLedgerPage } from "@/api/equipmentManagement/ledger";
import { getAccountingTotal, getDeviceTypeDistribution, getCalculateDepreciation } from "@/api/financialManagement/accounting";
import dayjs from "dayjs";
// 筛选条件
const dateRange = ref(null);
const equipmentType = ref('');
const selectedYear = ref(dayjs().format('YYYY')); // 默认当前年份
// 固定资产信息
const assetInfo = ref({
  totalEquipment: 0,
  totalOriginalValue: 0,
  totalDepreciation: 0,
  totalNetValue: 0
  totalEquipment: 0, // deviceTotal
  totalOriginalValue: 0, // deviceAmount
  totalDepreciation: 0, // deprAmount
  totalNetValue: 0, // netValue
  debt: 0, // 负债
  inventoryValue: 0 // 库存资产
});
// 设备类型总数(用于图表显示)
const deviceTypeTotalCount = ref(0);
// 设备列表
const equipmentList = ref([]);
@@ -306,63 +333,96 @@
const fetchData = async () => {
  try {
    // 获取固定资产汇总信息
    const assetInfoRes = await getAssetInfo({
    const assetInfoRes = await getAccountingTotal({
      startDate: dateRange.value ? dateRange.value[0] : null,
      endDate: dateRange.value ? dateRange.value[1] : null,
      equipmentType: equipmentType.value
      equipmentType: equipmentType.value,
      year: selectedYear.value
    });
    if (assetInfoRes.code === 200) {
      assetInfo.value = assetInfoRes.data;
      // 映射后端字段到前端字段
      const data = assetInfoRes.data;
      assetInfo.value = {
        totalEquipment: data.deviceTotal || 0, // 设备总数
        totalOriginalValue: data.deviceAmount || 0, // 资产原值
        totalDepreciation: data.deprAmount || 0, // 累计折旧
        totalNetValue: data.netValue || 0, // 净值
        debt: data.debt || 0, // 负债
        inventoryValue: data.inventoryValue || 0 // 库存资产
      };
    }
    // 获取设备列表
    const equipmentListRes = await getLedgerPage({
      current: pagination.value.currentPage,
      size: pagination.value.pageSize,
    // 获取设备类型分布数据(饼图和折线图)
    const distributionRes = await getDeviceTypeDistribution({
      startDate: dateRange.value ? dateRange.value[0] : null,
      endDate: dateRange.value ? dateRange.value[1] : null,
      equipmentType: equipmentType.value
      equipmentType: equipmentType.value,
      year: selectedYear.value
    });
    if (equipmentListRes.code === 200) {
      equipmentList.value = equipmentListRes.data.records;
      pagination.value.total = equipmentListRes.data.total;
      // 根据 equipmentList 按 deviceName 进行分类统计
      const deviceNameMap = {};
      equipmentList.value.forEach(item => {
        const deviceName = item.deviceName;
        if (!deviceNameMap[deviceName]) {
          deviceNameMap[deviceName] = {
            name: deviceName,
            count: 0,
            totalValue: 0
          };
        }
        deviceNameMap[deviceName].count += item.number || 1; // 假设 number 为设备数量
        deviceNameMap[deviceName].totalValue += item.taxIncludingPriceTotal || 0; // 累加含税总价
      });
      // 转换为 typeDistributionData 格式
      typeDistributionData.value = Object.values(deviceNameMap).map(item => ({
        name: item.name,
        value: item.count,
        count: item.count,
        amount: `¥${formatCurrency(item.totalValue)}`
      }));
    if (distributionRes.code === 200) {
      const data = distributionRes.data;
      // 更新设备类型总数
      deviceTypeTotalCount.value = data.totalCount || 0;
      // 转换饼图数据格式
      if (data.details && data.details.length > 0) {
        typeDistributionData.value = data.details.map(item => ({
          name: item.type || '',
          value: Number(item.count || 0),
          count: Number(item.count || 0),
          amount: `¥${formatCurrency(item.amount || 0)}`
        }));
      } else if (data.categories && data.categories.length > 0) {
        // 如果没有 details,使用 categories、countData 和 amountData 构建
        typeDistributionData.value = data.categories.map((category, index) => ({
          name: category,
          value: Number(data.countData[index] || 0),
          count: Number(data.countData[index] || 0),
          amount: `¥${formatCurrency(data.amountData[index] || 0)}`
        }));
      } else {
        typeDistributionData.value = [];
      }
      // 更新x轴数据
      xAxis.value[0].data = typeDistributionData.value.map(item => item.name);
      xAxis.value[0].data = data.categories || typeDistributionData.value.map(item => item.name);
      // 构建折线图数据
      typeDistributionLineSeries.value = [
        {
          name: '设备数量',
          type: 'line',
          data: typeDistributionData.value.map(item => item.count)
          data: data.countData || typeDistributionData.value.map(item => item.count)
        }
      ];
    }
    // 获取设备列表(折旧计算数据)
    const equipmentListRes = await getCalculateDepreciation({
      current: pagination.value.currentPage,
      size: pagination.value.pageSize,
      startDate: dateRange.value ? dateRange.value[0] : null,
      endDate: dateRange.value ? dateRange.value[1] : null,
      equipmentType: equipmentType.value,
      year: selectedYear.value
    });
    if (equipmentListRes.code === 200) {
      // 如果返回的是分页数据
      if (equipmentListRes.data.records) {
        equipmentList.value = equipmentListRes.data.records;
        pagination.value.total = equipmentListRes.data.total;
      } else if (Array.isArray(equipmentListRes.data)) {
        // 如果返回的是数组
        equipmentList.value = equipmentListRes.data;
        pagination.value.total = equipmentListRes.data.length;
      } else {
        equipmentList.value = [];
        pagination.value.total = 0;
      }
    }
  } catch (error) {
    console.error('获取固定资产数据失败:', error);
@@ -401,6 +461,7 @@
const resetFilters = () => {
  dateRange.value = null;
  equipmentType.value = '';
  selectedYear.value = dayjs().format('YYYY'); // 重置为当前年份
  fetchData();
};
@@ -486,10 +547,10 @@
  }
}
/* 大屏幕及以上 (lg:grid-cols-5) */
/* 大屏幕及以上 (lg:grid-cols-6) */
@media (min-width: 1024px) {
  .grid-container {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}
src/views/reportAnalysis/projectProfit/index.vue
@@ -1,30 +1,32 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true" label-width="80px">
      <el-form-item label="客户名称">
        <el-input v-model="filters.customerName" placeholder="请输入客户名称" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData"> 搜索 </el-button>
        <el-button @click="resetFilters"> 重置 </el-button>
        <el-button @click="handleOut"> 导出 </el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <PIMTable
        rowKey="id"
        :column="columns"
        :tableLoading="loading"
        :tableData="dataList"
        :page="{
    <div class="app-container">
        <el-form :model="filters" :inline="true" label-width="80px">
            <el-form-item label="客户名称">
                <el-input v-model="filters.customerName" placeholder="请输入客户名称" clearable style="width: 240px"/>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="getTableData"> 搜索 </el-button>
                <el-button @click="resetFilters"> 重置 </el-button>
                <el-button @click="handleOut"> 导出 </el-button>
            </el-form-item>
        </el-form>
        <div class="table_list">
            <PIMTable
                rowKey="id"
                :column="columns"
                :tableLoading="loading"
                :tableData="dataList"
                :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
          total: pagination.total
        }"
        @pagination="changePage"
      ></PIMTable>
    </div>
  </div>
                :isShowSummary="true"
                :summaryMethod="summarizeMainTable"
                @pagination="changePage"
            ></PIMTable>
        </div>
    </div>
</template>
<script setup>
@@ -36,93 +38,89 @@
const { proxy } = getCurrentInstance();
defineOptions({
  name: "项目利润",
    name: "项目利润",
});
const {
  loading,
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
    loading,
    filters,
    columns,
    dataList,
    pagination,
    getTableData,
    resetFilters,
    onCurrentChange,
} = usePaginationApi(
  getPurchaseList,
  {
    customerName: undefined,
  },
  [
    {
      label: "销售合同号",
      align: "center",
      prop: "customerContractNo",
    },
    {
      label: "客户名称",
      align: "center",
      prop: "customerName",
    },
    {
      label: "项目名称",
      align: "center",
      prop: "projectName",
    },
    {
      label: "合同金额",
      align: "center",
      prop: "contractAmount",
    },
    {
      label: "采购金额",
      align: "center",
      prop: "purchaseAmount",
    },
    {
      label: "利润",
      align: "center",
      prop: "balance",
    },
    {
      label: "利润率",
      align: "center",
      prop: "balanceRatio",
    },
    {
      label: "增值税",
      align: "center",
      prop: "balanceAmount",
    },
  ]
    getPurchaseList,
    {
        customerName: undefined,
    },
    [
        {
            label: "销售合同号",
            align: "center",
            prop: "customerContractNo",
        },
        {
            label: "客户名称",
            align: "center",
            prop: "customerName",
        },
        {
            label: "合同金额",
            align: "center",
            prop: "contractAmount",
        },
        {
            label: "采购金额",
            align: "center",
            prop: "purchaseAmount",
        },
        {
            label: "利润",
            align: "center",
            prop: "balance",
        },
        {
            label: "利润率",
            align: "center",
            prop: "balanceRatio",
        },
    ]
);
const changePage = ({ page }) => {
  pagination.currentPage = page;
  onCurrentChange(page);
const changePage = ({ page, limit }) => {
    pagination.currentPage = page;
    pagination.pageSize = limit;
    onCurrentChange(page);
};
// 主表合计方法
const summarizeMainTable = (param) => {
    return proxy.summarizeTable(param, ["contractAmount", "purchaseAmount", "balance"]);
};
// 导出
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/purchase/report/export", {}, "项目利润.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/purchase/report/export", {}, "项目利润.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
onMounted(() => {
  getTableData();
    getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
    margin-top: unset;
}
</style>