已修改7个文件
已添加3个文件
1141 ■■■■■ 文件已修改
src/api/basicData/product.js 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/invoiceLedger.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/invoiceRegistration.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/summarizeTable.js 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/index.vue 385 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 151 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 188 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/basicData/product.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
// äº§å“ç»´æŠ¤é¡µé¢æŽ¥å£
import request from '@/utils/request'
// äº§å“æ ‘查询
export function productTreeList(query) {
    return request({
        url: '/basic/product/list',
        method: 'get',
        params: query
    })
}
// äº§å“æ ‘新增修改
export function addOrEditProduct(query) {
    return request({
        url: '/basic/product/addOrEditProduct',
        method: 'post',
        data: query
    })
}
// è§„格型号新增修改
export function addOrEditProductModel(query) {
    return request({
        url: '/basic/product/addOrEditProductModel',
        method: 'post',
        data: query
    })
}
// äº§å“æ ‘删除
export function delProduct(query) {
    return request({
        url: '/basic/product/delProduct',
        method: 'delete',
        data: query
    })
}
// è§„格型号删除
export function delProductModel(query) {
    return request({
        url: '/basic/product/delProductModel',
        method: 'delete',
        data: query
    })
}
// è§„格型号查询
export function modelList(query) {
    return request({
        url: '/basic/product/modelList',
        method: 'get',
        params: query
    })
}
src/api/salesManagement/invoiceLedger.js
@@ -64,3 +64,22 @@
    })
}
// äº§å“å¼€ç¥¨è®°å½•分页查询
export function registrationProductPage(query) {
    return request({
        url: '/invoiceLedger/registrationProductPage',
        method: 'get',
        params: query
    })
}
// äº§å“å¼€ç¥¨è¯¦æƒ…查询
export function invoiceLedgerProductInfo(query) {
    return request({
        url: '/invoiceLedger/invoiceLedgerProductInfo',
        method: 'get',
        params: query
    })
}
src/api/salesManagement/invoiceRegistration.js
@@ -10,9 +10,9 @@
    })
}
// å¼€ç¥¨ç™»è®°æ–°å¢ž
export function invoiceRegistrationSaveOrUpdate(query) {
export function invoiceRegistrationSave(query) {
    return request({
        url: '/invoiceRegistration/saveOrUpdate',
        url: '/invoiceRegistration/save',
        method: 'post',
        data: query
    })
src/main.js
@@ -46,6 +46,7 @@
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import { getToken } from "@/utils/auth";
import {calculateTaxExclusiveTotalPrice, summarizeTable} from "@/utils/summarizeTable.js";
const app = createApp(App)
@@ -54,6 +55,8 @@
app.config.globalProperties.download = download
app.config.globalProperties.parseTime = parseTime
app.config.globalProperties.resetForm = resetForm
app.config.globalProperties.summarizeTable = summarizeTable
app.config.globalProperties.calculateTaxExclusiveTotalPrice = calculateTaxExclusiveTotalPrice
app.config.globalProperties.handleTree = handleTree
app.config.globalProperties.addDateRange = addDateRange
app.config.globalProperties.selectDictLabel = selectDictLabel
src/utils/summarizeTable.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
/**
 * é€šç”¨çš„表格合计方法
 * @param {Object} param - åŒ…含表格列配置和数据源的对象
 * @param {Array<string>} summaryProps - éœ€è¦æ±‡æ€»çš„字段名数组
 * @param {Object} specialFormat - ç‰¹æ®Šæ ¼å¼åŒ–规则:字段名 -> æ ¼å¼åŒ–选项(如是否去掉小数)
 * @returns {Array} åˆè®¡è¡Œæ•°æ®
 */
const summarizeTable = (param, summaryProps, specialFormat = {}) => {
    const { columns, data } = param;
    const sums = [];
    columns.forEach((column, index) => {
        if (index === 0) {
            sums[index] = '合计';
            return;
        }
        const prop = column.property;
        if (summaryProps.includes(prop)) {
            const values = data.map(item => Number(item[prop]));
            // åªå¯¹æœ‰æ•ˆæ•°å­—进行求和
            if (!values.every(isNaN)) {
                const sum = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
                if (specialFormat[prop] && specialFormat[prop].noDecimal) {
                    // å¦‚果指定了不需要保留小数,则直接转换为整数
                    sums[index] = Math.round(sum).toString();
                } else {
                    // é»˜è®¤ä¿ç•™ä¸¤ä½å°æ•°
                    sums[index] = parseFloat(sum).toFixed(specialFormat[prop]?.decimalPlaces ?? 2);
                }
            } else {
                sums[index] = '';
            }
        } else {
            sums[index] = '';
        }
    });
    return sums;
}
const calculateTaxExclusiveTotalPrice = (taxInclusiveTotalPrice, taxRate) => {
    const taxRateDecimal = taxRate / 100;
    return (taxInclusiveTotalPrice / (1 + taxRateDecimal)).toFixed(2);
}
// å¯¼å‡ºå‡½æ•°ä¾›å…¶ä»–文件使用
export { summarizeTable, calculateTaxExclusiveTotalPrice };
src/views/basicData/product/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,385 @@
<template>
  <div class="app-container product-view">
    <div class="left">
      <div>
        <el-input
            v-model="search"
            style="width: 240px"
            placeholder="输入关键字进行搜索"
            @change="searchFilter"
            @clear="searchFilter"
            clearable
            prefix-icon="Search"
        />
        <el-button type="primary" @click="openProDia('add')" style="margin-left: 10px">新增产品</el-button>
      </div>
      <div>
        <el-tree ref="tree" v-loading="treeLoad" :data="list" @node-click="handleNodeClick"
                 :expand-on-click-node="false"
                 :default-expanded-keys="expandedKeys" :draggable="true" :filter-node-method="filterNode"
                 :props="{ children: 'children', label: 'label' }" highlight-current node-key="id"
                 style="height: calc(100vh - 190px);overflow-y: scroll;scrollbar-width: none;">
          <template #default="{ node, data }">
            <div class="custom-tree-node">
              <span>{{ node.label }}</span>
              <div>
                <el-button type="primary" link @click="openProDia('edit', data)">
                  ç¼–辑
                </el-button>
                <!-- ä¿®æ”¹æ­¤å¤„ -->
                <el-button
                    v-if="!node.childNodes.length"
                    style="margin-left: 4px"
                    type="danger"
                    link
                    @click="remove(node, data)"
                >
                  åˆ é™¤
                </el-button>
              </div>
            </div>
          </template>
        </el-tree>
      </div>
    </div>
    <div class="right">
      <div style="margin-bottom: 10px">
        <el-button type="primary" @click="openModelDia('add')">新增规格型号</el-button>
        <el-button type="danger" @click="handleDelete" style="margin-left: 10px" plain>删除</el-button>
      </div>
      <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" :handleSelectionChange="handleSelectionChange"
                :tableLoading="tableLoading" @pagination="pagination" :total="total"></PIMTable>
    </div>
    <el-dialog v-model="productDia" title="产品" width="400px">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="产品名称:" prop="productName">
              <el-input v-model="form.productName" placeholder="请输入产品名称" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确认</el-button>
          <el-button @click="closeProDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="modelDia" title="产品" width="400px">
      <el-form :model="modelForm" label-width="140px" label-position="top" :rules="modelRules" ref="modelFormRef">
        <el-row>
          <el-col :span="24">
            <el-form-item label="规格型号:" prop="model">
              <el-input v-model="modelForm.model" placeholder="请输入规格型号" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="单位:" prop="unit">
              <el-input v-model="modelForm.unit" placeholder="请输入单位" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitModelForm">确认</el-button>
          <el-button @click="closeProDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {ref} from "vue";
import {ElMessageBox} from "element-plus";
import {
  addOrEditProduct,
  addOrEditProductModel,
  delProduct, delProductModel,
  modelList,
  productTreeList
} from "@/api/basicData/product.js";
const { proxy } = getCurrentInstance()
const productDia = ref(false)
const modelDia = ref(false)
const modelOperationType = ref('')
const search = ref('')
const currentId = ref('')
const currentParentId = ref('')
const operationType = ref('')
const treeLoad = ref(false)
const list = ref([])
const expandedKeys = ref([])
const tableColumn = ref([
  {
    label: '规格型号',
    prop: 'model',
  },
  {
    label: '单位',
    prop: 'unit',
  },
  {
    dataType: "action",
    label: "操作",
    align: 'center',
    operation: [
      {
        name: "编辑",
        type: "text",
        clickFun: (row) => {
          openModelDia('edit', row);
        },
      },
    ],
  },
])
const tableData = ref([])
const tableLoading = ref(false)
const total = ref(0)
const selectedRows = ref([])
const page = reactive({
  current: 1,
  size: 10,
})
const data = reactive({
  form: {
    productName: '',
  },
  rules: {
    productName: [{ required: true, message: "请输入", trigger: "blur" }],
  },
  modelForm: {
    model: '',
    unit: '',
  },
  modelRules: {
    model: [{ required: true, message: "请输入", trigger: "blur" }],
    unit: [{ required: true, message: "请输入", trigger: "blur" }],
  }
})
const { form, rules, modelForm, modelRules } = toRefs(data)
// æŸ¥è¯¢äº§å“æ ‘
const getProductTreeList = () => {
  treeLoad.value = true;
  productTreeList().then(res => {
    list.value = res
    list.value.forEach((a) => {
      expandedKeys.value.push(a.label);
    });
    treeLoad.value = false;
  }).catch(err => {
    treeLoad.value = false;
  })
}
// è¿‡æ»¤äº§å“æ ‘
const searchFilter = () => {
  proxy.$refs.tree.filter(search.value);
}
// æ‰“开产品弹框
const openProDia = (type, data) => {
  operationType.value = type;
  productDia.value = true
  form.value.productName = ''
  if (type === 'edit') {
    form.value.productName = data.productName
  }
}
// æ‰“开规格型号弹框
const openModelDia = (type, data) => {
  modelOperationType.value = type;
  modelDia.value = true
  modelForm.value.model = ''
  modelForm.value.model = ''
  modelForm.value.id = ''
  if (type === 'edit') {
    modelForm.value = {...data}
  }
}
// æäº¤äº§å“åç§°ä¿®æ”¹
const submitForm = () => {
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      if (operationType.value === 'add') {
        form.value.parentId = currentId.value
        form.value.id = ''
      } else {
        form.value.id = currentId.value
        form.value.parentId = ''
      }
      addOrEditProduct(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeProDia()
        getProductTreeList()
      })
    }
  })
}
// å…³é—­äº§å“å¼¹æ¡†
const closeProDia = () => {
  proxy.$refs.formRef.resetFields();
  productDia.value = false;
}
// åˆ é™¤äº§å“
const remove = (node, data) => {
  let ids = []
  ids.push(data.id)
  ElMessageBox.confirm(
      '选中的内容将被删除,是否确认删除?',
      '删除提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    tableLoading.value = true
    delProduct(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getProductTreeList()
    }).finally(() => {
      tableLoading.value = false
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
  })
}
// é€‰æ‹©äº§å“
const handleNodeClick = (val, node, el) => {
  currentId.value = val.id
  currentParentId.value = val.parentId
  getModelList()
}
// æäº¤è§„格型号修改
const submitModelForm = () => {
  proxy.$refs.modelFormRef.validate(valid => {
    if (valid) {
      modelForm.value.productId = currentId.value
      addOrEditProductModel(modelForm.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeModelDia()
        getModelList()
      })
    }
  })
}
// å…³é—­äº§å“å¼¹æ¡†
const closeModelDia = () => {
  proxy.$refs.modelFormRef.resetFields();
  modelDia.value = false;
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
}
// æŸ¥è¯¢è§„格型号
const pagination = ({ current, limit }) => {
  page.current = current;
  page.size = limit;
  getModelList()
}
const getModelList = () => {
  tableLoading.value = true
  modelList({id: currentId.value}).then(res => {
    tableLoading.value = false
    tableData.value = res
  })
}
// åˆ é™¤è§„格型号
const handleDelete = () => {
  let ids = []
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
  }
  ElMessageBox.confirm(
      '选中的内容将被删除,是否确认删除?',
      '删除提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    tableLoading.value = true
    delProductModel(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getModelList()
    }).finally(() => {
      tableLoading.value = false
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
  })
}
// è°ƒç”¨tree过滤方法 ä¸­æ–‡è‹±è¿‡æ»¤
const filterNode = (value, data, node) => {
  if (!value) {    //如果数据为空,则返回true,显示所有的数据项
    return true
  }
  // æŸ¥è¯¢åˆ—表是否有匹配数据,将值小写,匹配英文数据
  let val = value.toLowerCase()
  return chooseNode(val, data, node) // è°ƒç”¨è¿‡æ»¤äºŒå±‚方法
}
// è¿‡æ»¤çˆ¶èŠ‚ç‚¹ / å­èŠ‚ç‚¹ (如果输入的参数是父节点且能匹配,则返回该节点以及其下的所有子节点;如果参数是子节点,则返回该节点的父节点。name是中文字符,enName是英文字符.
const chooseNode = (value, data, node) => {
  if (data.label.indexOf(value) !== -1) {
    return true
  }
  const level = node.level
  // å¦‚果传入的节点本身就是一级节点就不用校验了
  if (level === 1) {
    return false
  }
  // å…ˆå–当前节点的父节点
  let parentData = node.parent
  // éåŽ†å½“å‰èŠ‚ç‚¹çš„çˆ¶èŠ‚ç‚¹
  let index = 0
  while (index < level - 1) {
    // å¦‚果匹配到直接返回,此处name值是中文字符,enName是英文字符。判断匹配中英文过滤
    if (parentData.data.label.indexOf(value) !== -1) {
      return true
    }
    // å¦åˆ™çš„话再往上一层做匹配
    parentData = parentData.parent
    index++
  }
  // æ²¡åŒ¹é…åˆ°è¿”回false
  return false
}
getProductTreeList()
</script>
<style scoped>
.product-view {
  display: flex;
}
.left {
  width: 380px;
  padding: 16px;
  background: #ffffff;
}
.right {
  width: calc(100% - 380px);
  padding: 16px;
  margin-left: 20px;
  background: #ffffff;
}
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
</style>
src/views/procurementManagement/invoiceEntry/index.vue
@@ -40,13 +40,13 @@
              <el-table-column label="单位" prop="unit" />
              <el-table-column label="数量" prop="quantity" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber"/>
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber"/>
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber"/>
              <el-table-column label="本次来票数" prop="ticketsNum" />
              <el-table-column label="本次来票金额(元)" prop="ticketsAmount" />
              <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :formatter="formattedNumber"/>
              <el-table-column label="未来票数" prop="futureTickets" />
              <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" />
              <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber"/>
            </el-table>
          </template>
        </el-table-column>
@@ -54,9 +54,8 @@
        <el-table-column label="采购合同号" prop="purchaseContractNumber" show-overflow-tooltip/>
        <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip/>
        <el-table-column label="供应商名称" prop="supplierName" show-overflow-tooltip/>
        <el-table-column label="业务员" prop="businessPerson" show-overflow-tooltip/>
        <el-table-column label="项目名称" prop="projectName" show-overflow-tooltip/>
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip/>
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column fixed="right" label="操作" min-width="60" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">编辑</el-button>
@@ -96,10 +95,34 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="业务员:" prop="businessPersonId">
              <el-select v-model="form.businessPersonId" placeholder="自动填充" clearable disabled>
                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId"/>
              </el-select>
            <el-form-item label="发票号:" prop="invoiceNumber">
              <el-input v-model="form.invoiceNumber" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="发票金额(元):" prop="invoiceAmount">
              <el-input type="number" :step="0.01" v-model="form.invoiceAmount" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="开票人:" prop="issUer">
              <el-input v-model="form.issUer" placeholder="请输入" clearable disabled/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="开票日期:" prop="issueDate">
              <el-date-picker
                  disabled
                  style="width: 100%"
                  v-model="form.issueDate"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  type="date"
                  placeholder="请选择"
                  clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -107,42 +130,25 @@
          <el-form-item label="产品信息:" prop="entryDate">
          </el-form-item>
        </el-row>
        <el-table :data="productData" border @selection-change="productSelected">
        <el-table :data="productData" border @selection-change="productSelected" show-summary
                  :summary-method="summarizeChildrenTable">
          <el-table-column align="center" label="序号" type="index" width="60" />
          <el-table-column label="产品大类" prop="productCategory" />
          <el-table-column label="规格型号" prop="specificationModel" />
          <el-table-column label="单位" prop="unit" />
          <el-table-column label="数量" prop="quantity" />
          <el-table-column label="税率(%)" prop="taxRate" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" />
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" />
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" />
          <el-table-column label="本次来票数" prop="ticketsNum">
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber"/>
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber"/>
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber"/>
          <el-table-column label="本次来票数" prop="ticketsNum" width="170">
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.ticketsNum"></el-input>
              <el-input-number v-model="scope.row.ticketsNum" :precision="0" :step="1" clearable style="width: 100%"  @blur="invoiceNumBlur(scope.row)"/>
            </template>
          </el-table-column>
          <el-table-column label="本次来票金额(元)" prop="ticketsAmount">
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.ticketsAmount"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="未来票数" prop="futureTickets">
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.futureTickets"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="未来票金额(元)" prop="futureTicketsAmount">
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.futureTicketsAmount"></el-input>
            </template>
          </el-table-column>
          <el-table-column fixed="right" label="操作" min-width="60" align="center">
            <template #default="scope">
              <el-button v-if="!scope.row.editFlag" link type="primary" size="small" @click="openProductEdit(scope.row);">编辑</el-button>
              <el-button v-else link type="primary" size="small" @click="openProductEdit(scope.row);">保存</el-button>
            </template>
          </el-table-column>
          <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :formatter="formattedNumber"></el-table-column>
          <el-table-column label="未来票数" prop="futureTickets"></el-table-column>
          <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber"> </el-table-column>
        </el-table>
      </el-form>
      <template #footer>
@@ -229,6 +235,9 @@
    tableLoading.value = false
  })
}
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
@@ -258,49 +267,17 @@
}
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  const { columns, data } = param;
  const sums = [];
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = '合计';
      return;
    }
    const prop = column.property;
    if (['contractAmount'].includes(prop)) {
      const values = data.map(item => Number(item[prop]));
      if (!values.every(value => isNaN(value))) {
        sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
      } else {
        sums[index] = '';
      }
    } else {
      sums[index] = '';
    }
  })
  return sums;
  return proxy.summarizeTable(param, ['contractAmount'], {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  const { columns, data } = param;
  const sums = [];
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = '合计';
      return;
    }
    const prop = column.property;
    if (['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'].includes(prop)) {
      const values = data.map(item => Number(item[prop]));
      if (!values.every(value => isNaN(value))) {
        sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
      } else {
        sums[index] = '';
      }
    } else {
      sums[index] = '';
    }
  });
  return sums;
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'],{
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
});
}
// æ‰“开弹框
const openForm = (type, row) => {
@@ -337,7 +314,6 @@
    form.value.projectName = res.projectName
    productData.value = res.productData
    form.value.supplierName = res.supplierName
    form.value.businessPersonId = res.businessPersonId
  })
}
// æäº¤è¡¨å•
@@ -405,6 +381,23 @@
    proxy.$modal.msg("已取消")
  })
}
//本次开票失焦操作
const invoiceNumBlur = (row) => {
  if(!row.ticketsNum){
    row.ticketsNum = 0
  }
  if(row.ticketsNum > row.futureTickets){
    proxy.$modal.msgWarning('本次开票数不得大于未开票数')
    row.ticketsNum = 0
  }
  row.futureTickets = row.futureTickets - row.ticketsNum
  // è®¡ç®—本次开票金额
  row.ticketsAmount = row.ticketsNum * row.taxInclusiveUnitPrice
  // è®¡ç®—未开票数
  row.futureTickets = row.futureTickets - row.ticketsNum
  // è®¡ç®—未开票金额
  row.futureTicketsAmount = row.futureTickets * row.taxInclusiveUnitPrice
}
getList()
</script>
src/views/procurementManagement/procurementLedger/index.vue
@@ -40,9 +40,9 @@
              <el-table-column label="单位" prop="unit" />
              <el-table-column label="数量" prop="quantity" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
            </el-table>
          </template>
        </el-table-column>
@@ -50,9 +50,8 @@
        <el-table-column label="采购合同号" prop="purchaseContractNumber" show-overflow-tooltip/>
        <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip/>
        <el-table-column label="供应商名称" prop="supplierName" show-overflow-tooltip/>
        <el-table-column label="业务员" prop="businessPerson" show-overflow-tooltip/>
        <el-table-column label="项目名称" prop="projectName" show-overflow-tooltip/>
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip/>
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column label="录入人" prop="recorderName" show-overflow-tooltip/>
        <el-table-column label="录入日期" prop="entryDate" show-overflow-tooltip/>
        <el-table-column fixed="right" label="操作" min-width="60" align="center">
@@ -96,20 +95,6 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="业务员:" prop="businessPersonId">
              <el-select v-model="form.businessPersonId" placeholder="请选择" clearable @change="setPhone">
                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId"/>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="电话:" prop="phoneNumber">
              <el-input v-model="form.phoneNumber" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="录入人:" prop="recorderId">
              <el-select v-model="form.recorderId" placeholder="请选择" clearable disabled>
                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId"/>
@@ -137,7 +122,7 @@
            <el-button plain type="danger" @click="deleteProduct">删除</el-button>
          </el-form-item>
        </el-row>
        <el-table :data="productData" border @selection-change="productSelected">
        <el-table :data="productData" border @selection-change="productSelected" show-summary :summary-method="summarizeProTable">
          <el-table-column align="center" type="selection" width="55" />
          <el-table-column align="center" label="序号" type="index" width="60" />
          <el-table-column label="产品大类" prop="productCategory" />
@@ -145,12 +130,12 @@
          <el-table-column label="单位" prop="unit" />
          <el-table-column label="数量" prop="quantity" />
          <el-table-column label="税率(%)" prop="taxRate" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" />
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" />
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber"/>
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber"/>
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber"/>
          <el-table-column fixed="right" label="操作" min-width="60" align="center">
            <template #default="scope">
              <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row);">编辑</el-button>
              <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row, scope.$index);">编辑</el-button>
            </template>
          </el-table-column>
        </el-table>
@@ -198,18 +183,24 @@
      <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="产品大类:" prop="productCategory">
              <el-select v-model="productForm.productCategory" placeholder="请选择" clearable>
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
              </el-select>
            <el-form-item label="产品大类:" prop="productId">
              <el-tree-select
                  v-model="productForm.productId"
                  placeholder="请选择" clearable
                  check-strictly
                  @change="getModels"
                  :data="productOptions"
                  :render-after-expand="false"
                  style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="规格型号:" prop="specificationModel">
              <el-select v-model="productForm.specificationModel" placeholder="请选择" clearable>
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
            <el-form-item label="规格型号:" prop="productModelId">
              <el-select v-model="productForm.productModelId" placeholder="请选择" clearable @change="getProductModel">
                <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id"/>
              </el-select>
            </el-form-item>
          </el-col>
@@ -229,7 +220,7 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
              <el-input v-model="productForm.taxInclusiveUnitPrice" placeholder="请输入" clearable/>
              <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="2" :step="0.1" clearable style="width: 100%"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -245,12 +236,12 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
              <el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="请输入" clearable/>
              <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" clearable style="width: 100%" @change="mathNum"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice">
              <el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="请输入" clearable/>
              <el-input v-model="productForm.taxExclusiveTotalPrice" disabled/>
            </el-form-item>
          </el-col>
        </el-row>
@@ -297,7 +288,9 @@
const productData = ref([])
const selectedRows = ref([])
const productSelectedRows = ref([])
const modelOptions = ref([])
const userList = ref([])
const productOptions = ref([])
const salesContractList = ref([])
const supplierList = ref([])
const tableLoading = ref(false)
@@ -308,6 +301,7 @@
const total = ref(0)
const fileList = ref([])
import useUserStore from "@/store/modules/user"
import {modelList, productTreeList} from "@/api/basicData/product.js";
const userStore = useUserStore()
@@ -325,8 +319,6 @@
    recorderId: '',
    entryDate: '',
    productData: [],
    businessPersonId: '',
    phoneNumber: '',
    supplierName: '',
    supplierId: '',
  },
@@ -334,8 +326,6 @@
    purchaseContractNumber: [{ required: true, message: "请输入", trigger: "blur" }],
    salesLedgerId: [{ required: true, message: "请选择", trigger: "change" }],
    projectName: [{ required: true, message: "请输入", trigger: "blur" }],
    businessPersonId: [{ required: true, message: "请选择", trigger: "change" }],
    phoneNumber: [{ required: true, message: "请输入", trigger: "blur" }],
    supplierId: [{ required: true, message: "请输入", trigger: "blur" }],
  }
})
@@ -343,10 +333,13 @@
// äº§å“è¡¨å•弹框数据
const productFormVisible = ref(false)
const productOperationType = ref('')
const productOperationIndex = ref('')
const currentId = ref('')
const productFormData = reactive({
  productForm: {
    productId: '',
    productCategory: '',
    productModelId: '',
    specificationModel: '',
    unit: '',
    quantity: '',
@@ -357,8 +350,8 @@
    invoiceType: '',
  },
  productRules: {
    productCategory: [{ required: true, message: "请选择", trigger: "change" }],
    specificationModel: [{ required: true, message: "请选择", trigger: "change" }],
    productId: [{ required: true, message: "请选择", trigger: "change" }],
    productModelId: [{ required: true, message: "请选择", trigger: "change" }],
    unit: [{ required: true, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    taxInclusiveUnitPrice: [{ required: true, message: "请输入", trigger: "blur" }],
@@ -376,7 +369,9 @@
  headers: { Authorization: "Bearer " + getToken() },
})
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
@@ -431,50 +426,12 @@
}
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  const { columns, data } = param;
  const sums = [];
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = '合计';
      return;
    }
    const prop = column.property;
    if (['contractAmount'].includes(prop)) {
      const values = data.map(item => Number(item[prop]));
      if (!values.every(value => isNaN(value))) {
        sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
      } else {
        sums[index] = '';
      }
    } else {
      sums[index] = '';
    }
  })
  return sums;
  return proxy.summarizeTable(param, ['contractAmount']);
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  const { columns, data } = param;
  const sums = [];
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = '合计';
      return;
    }
    const prop = column.property;
    if (['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice'].includes(prop)) {
      const values = data.map(item => Number(item[prop]));
      if (!values.every(value => isNaN(value))) {
        sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
      } else {
        sums[index] = '';
      }
    } else {
      sums[index] = '';
    }
  });
  return sums;
}
const summarizeProTable = (param) => {
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice']);
};
// æ‰“开弹框
const openForm = (type, row) => {
  operationType.value = type
@@ -505,10 +462,6 @@
    })
  }
  dialogFormVisible.value = true
}
// èµ‹å€¼ç”µè¯
const setPhone = (id) => {
  form.value.phoneNumber = userList.value.find(u => u.userId === id)?.phonenumber || '';
}
// ä¸Šä¼ å‰æ ¡æ£€
function handleBeforeUpload(file) {
@@ -577,14 +530,63 @@
  dialogFormVisible.value = false
}
// æ‰“开产品弹框
const openProductForm = (type, row) => {
const openProductForm = (type, row, index) => {
  productOperationType.value = type
  productOperationIndex.value = index
  productForm.value = {}
  proxy.resetForm("productFormRef")
  if (type === 'edit') {
    productForm.value = {...row}
  }
  productFormVisible.value = true
  getProductOptions()
}
const getProductOptions = () => {
  productTreeList().then(res => {
    productOptions.value = convertIdToValue(res)
  })
}
const getModels =(value) => {
  productForm.value.productCategory = findNodeById(productOptions.value, value)
  modelList({id: value}).then(res => {
    modelOptions.value = res
  })
}
const getProductModel =(value) => {
  const index = modelOptions.value.findIndex(item => item.id === value);
  if (index !== -1) {
    productForm.value.specificationModel = modelOptions.value[index].model;
  } else {
    productForm.value.specificationModel = null;
  }
}
const findNodeById = (nodes, productId) => {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i].value === productId) {
      return nodes[i].label; // æ‰¾åˆ°èŠ‚ç‚¹ï¼Œè¿”å›žè¯¥èŠ‚ç‚¹
    }
    if (nodes[i].children && nodes[i].children.length > 0) {
      const foundNode = findNodeById(nodes[i].children, productId);
      if (foundNode) {
        return foundNode.label; // åœ¨å­èŠ‚ç‚¹ä¸­æ‰¾åˆ°ï¼Œè¿”å›žè¯¥èŠ‚ç‚¹
      }
    }
  }
  return null; // æ²¡æœ‰æ‰¾åˆ°èŠ‚ç‚¹ï¼Œè¿”å›žnull
};
function convertIdToValue(data) {
  return data.map(item => {
    const { id, children, ...rest } = item;
    const newItem = {
      ...rest,
      value: id // å°† id æ”¹ä¸º value
    };
    if (children && children.length > 0) {
      newItem.children = convertIdToValue(children);
    }
    return newItem;
  });
}
// æäº¤äº§å“è¡¨å•
const submitProduct = () => {
@@ -593,7 +595,12 @@
      if (operationType.value === "edit") {
        submitProductEdit()
      } else {
        productData.value.push({...productForm.value})
        if (productOperationType.value === 'add') {
          productData.value.push({...productForm.value})
          console.log('productData.value---', productData.value)
        } else {
          productData.value[productOperationIndex.value] = {...productForm.value}
        }
        closeProductDia()
      }
    }
@@ -702,6 +709,9 @@
  const day = String(today.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}
const mathNum = (val) => {
  productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(val, productForm.value.taxRate)
}
getList()
</script>
src/views/salesManagement/invoiceLedger/index.vue
@@ -24,9 +24,7 @@
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增台账</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
        <el-button @click="handleOut" type="primary" style="width: 100px">导出</el-button>
      </div>
    </div>
    <div class="table_list">
@@ -41,8 +39,10 @@
        <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip/>
        <el-table-column label="客户合同号" prop="customerContractNo" show-overflow-tooltip/>
        <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip/>
        <el-table-column label="产品大类" prop="productCategory" />
        <el-table-column label="规格型号" prop="specificationModel" />
        <el-table-column label="发票号" prop="invoiceNo" show-overflow-tooltip/>
        <el-table-column label="发票金额(元)" prop="invoiceAmount" show-overflow-tooltip/>
        <el-table-column label="发票金额(元)" prop="invoiceTotal" show-overflow-tooltip/>
        <el-table-column label="税率" prop="taxRate" show-overflow-tooltip/>
        <el-table-column label="开票人" prop="invoicePerson" show-overflow-tooltip/>
        <el-table-column label="开票日期" prop="invoiceDate" show-overflow-tooltip/>
@@ -54,26 +54,24 @@
        </el-table-column>
        <el-table-column fixed="right" label="操作" min-width="60" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">编辑</el-button>
            <el-button link type="primary" size="small" @click="openForm(scope.row);">编辑</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current"
                  :limit="page.size" @pagination="paginationChange" />
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增开票台账页面' : '编辑开票台账页面'" width="70%" @close="closeDia">
    <el-dialog v-model="dialogFormVisible" title="开票台账页面" width="70%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="销售合同号:" prop="salesLedgerId">
              <el-select v-model="form.salesLedgerId" placeholder="请选择" clearable @change="ledgerChange" :disabled="operationType === 'edit'">
                <el-option v-for="item in ledgerList" :key="item.id" :label="item.salesContractNo" :value="item.id"/>
              </el-select>
            <el-form-item label="销售合同号:" prop="salesContractNo">
              <el-input v-model="form.salesContractNo" disabled></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="客户名称:" prop="customerName">
              <el-input v-model="form.customerName" placeholder="自动填充" clearable :disabled="operationType === 'edit'"/>
              <el-input v-model="form.customerName" placeholder="自动填充" clearable disabled/>
            </el-form-item>
          </el-col>
        </el-row>
@@ -84,24 +82,17 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="发票金额(元):" prop="invoiceAmount">
              <el-input type="number" :step="0.01" v-model="form.invoiceAmount" placeholder="请输入" clearable/>
            <el-form-item label="发票金额(元):" prop="invoiceTotal">
              <el-input type="number" :step="0.01" v-model="form.invoiceTotal" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="税率:" prop="taxRate">
              <el-input type="number" :step="0.01" v-model="form.taxRate" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="开票人:" prop="invoicePerson">
              <el-input v-model="form.invoicePerson" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="开票日期:" prop="invoiceDate">
              <el-date-picker
@@ -196,17 +187,12 @@
import { ref } from 'vue'
import {Search} from "@element-plus/icons-vue";
import {ElMessageBox } from "element-plus";
import {
  getSalesLedgerWithProducts,
  ledgerListNoPage
} from "@/api/salesManagement/salesLedger.js";
import { getToken } from "@/utils/auth"
import {
  invoiceLedgerList,
  invoiceLedgerDel,
  invoiceLedgerSaveOrUpdate,
  invoiceLedgerDetail,
  invoiceLedgerProductInfo,
  commitFile,
  registrationProductPage
} from "../../../api/salesManagement/invoiceLedger.js";
const { proxy } = getCurrentInstance()
const tableData = ref([])
@@ -219,9 +205,6 @@
})
const total = ref(0)
const fileList = ref([])
const ledgerList = ref([])
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
const data = reactive({
  searchForm: {
@@ -232,7 +215,7 @@
    salesLedgerId: '',
    customerId: '',
    invoiceNo: '',
    invoiceAmount: '',
    invoiceTotal: '',
    taxRate: '',
    invoicePerson: '',
    invoiceDate: '',
@@ -273,7 +256,7 @@
}
const getList = () => {
  tableLoading.value = true
  invoiceLedgerList({...searchForm.value, ...page}).then(res => {
  registrationProductPage({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
    tableData.value = res.data.records;
    total.value = res.data.total;
@@ -307,22 +290,15 @@
  return sums;
};
// æ‰“开弹框
const openForm = (type, row) => {
  operationType.value = type
const openForm = (row) => {
  form.value = {}
  productData.value = []
  fileList.value = []
  // æŸ¥è¯¢é”€å”®åˆåŒ
  ledgerListNoPage({}).then(res => {
    ledgerList.value = res.data;
  currentId.value = row.id;
  invoiceLedgerProductInfo({id: row.id}).then(res => {
    form.value = {...res.data}
    fileList.value = res.data.fileList;
  })
  if (type === 'edit') {
    currentId.value = row.id;
    invoiceLedgerDetail({id: row.id}).then(res => {
      form.value = {...res.data}
      fileList.value = res.data.fileList;
    })
  }
  dialogFormVisible.value = true
}
// ä¸Šä¼ å¤šä¸ªæ–‡ä»¶å°±è¦†ç›–原来的
@@ -404,49 +380,6 @@
  }).catch(() => {
    proxy.$modal.msg("已取消")
  })
}
// åˆ é™¤
const handleDelete = () => {
  let ids = []
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
  }
  ElMessageBox.confirm(
      '选中的内容将被删除,是否确认删除?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    invoiceLedgerDel(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getList()
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
  })
}
// é”€å”®å°è´¦ç­›é€‰
const ledgerChange = (val) => {
  if(val){
    getSalesLedgerWithProducts({id: val}).then(res => {
      form.value = {
        salesLedgerId: res.id,
        customerName: res.customerName,
        customerId: res.customerId,
        salesContractNo: res.salesContractNo
      }
    })
  }else {
    form.value.salesLedgerId = ''
    form.value.customerName = ''
    form.value.customerId = ''
  }
}
// æ‰“开附件上传弹窗
src/views/salesManagement/invoiceRegistration/index.vue
@@ -14,9 +14,8 @@
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增登记</el-button>
        <el-button type="primary" @click="openForm">新增登记</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
@@ -43,10 +42,10 @@
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" />
              <el-table-column label="本次开票数" prop="invoiceNum" />
              <el-table-column label="本次开票金额(元)" prop="invoiceAmount" />
              <el-table-column label="未开票数(元)" prop="noInvoiceNum" />
              <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" />
              <el-table-column label="开票数" prop="invoiceNum" />
              <el-table-column label="开票金额(元)" prop="invoiceAmount" />
              <el-table-column label="未开票数" prop="noInvoiceNum" />
              <el-table-column label="未开票金额(元)" prop="noInvoiceAmount"/>
            </el-table>
          </template>
        </el-table-column>
@@ -57,23 +56,17 @@
        <el-table-column label="业务员" prop="salesman" show-overflow-tooltip/>
        <el-table-column label="项目名称" prop="projectName" show-overflow-tooltip/>
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip/>
        <el-table-column fixed="right" label="操作" min-width="60" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">编辑</el-button>
          </template>
        </el-table-column>
        <el-table-column label="未开票金额(元)" prop="noInvoiceAmountTotal" show-overflow-tooltip/>
      </el-table>
      <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current"
                  :limit="page.size" @pagination="paginationChange" />
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增开票登记页面' : '编辑开票登记页面'" width="70%" @close="closeDia">
    <el-dialog v-model="dialogFormVisible" title="新增开票登记页面" width="85%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="销售合同号:" prop="salesLedgerId">
              <el-select v-model="form.salesLedgerId" placeholder="请选择" clearable @change="ledgerChange" :disabled="operationType === 'edit'">
                <el-option v-for="item in ledgerList" :key="item.id" :label="item.salesContractNo" :value="item.id"/>
              </el-select>
            <el-form-item label="销售合同号:" prop="salesContractNo">
              <el-input v-model="form.salesContractNo" disabled></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -98,7 +91,7 @@
          <el-form-item label="产品信息:" prop="entryDate">
          </el-form-item>
        </el-row>
        <el-table :data="productData" border>
        <el-table :data="productData" border show-summary :summary-method="summarizeChildrenTable">
          <el-table-column align="center" label="序号" type="index" width="60" />
          <el-table-column label="产品大类" prop="productCategory" />
          <el-table-column label="规格型号" prop="specificationModel" />
@@ -108,30 +101,24 @@
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" />
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" />
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" />
          <el-table-column label="本次开票数" prop="invoiceNum">
          <el-table-column label="本次开票数" prop="currentInvoiceNum">
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.invoiceNum"></el-input>
              <el-input type="number" :step="1" min="0" v-model="scope.row.currentInvoiceNum" @blur="invoiceNumBlur(scope.row)"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="本次开票金额(元)" prop="invoiceAmount" >
          <el-table-column label="本次开票金额(元)" prop="currentInvoiceAmount" >
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.invoiceAmount"></el-input>
              <el-input type="number" :step="0.01" min="0" v-model="scope.row.currentInvoiceAmount" disabled></el-input>
            </template>
          </el-table-column>
          <el-table-column label="未开票数(元)" prop="noInvoiceNum" >
          <el-table-column label="未开票数" prop="noInvoiceNum" >
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.noInvoiceNum"></el-input>
              <el-input type="number" min="0" disabled v-model="scope.row.noInvoiceNum"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" >
            <template #default="scope">
              <el-input :disabled="!scope.row.editFlag" v-model="scope.row.noInvoiceAmount"></el-input>
            </template>
          </el-table-column>
          <el-table-column fixed="right" label="操作" min-width="60" align="center">
            <template #default="scope">
              <el-button v-if="!scope.row.editFlag" link type="primary" size="small" @click="openProductEdit(scope.row);">编辑</el-button>
              <el-button v-else link type="primary" size="small" @click="openProductEdit(scope.row);">保存</el-button>
              <el-input  type="number" min="0"  disabled v-model="scope.row.noInvoiceAmount"></el-input>
            </template>
          </el-table-column>
        </el-table>
@@ -153,15 +140,12 @@
import {ElMessageBox } from "element-plus";
// import {userListNoPage} from "@/api/system/user.js";
import {
  ledgerListNoPage,
  getSalesLedgerWithProducts,
  ledgerList,
  productList,
} from "@/api/salesManagement/salesLedger.js";
import {
  invoiceRegistrationList,
  invoiceRegistrationSaveOrUpdate,
  invoiceRegistrationDel,
  productList,
  invoiceRegistrationDetail,
  invoiceRegistrationSave,
} from "@/api/salesManagement/invoiceRegistration.js";
const { proxy } = getCurrentInstance()
const tableData = ref([])
@@ -173,7 +157,6 @@
  size: 10,
})
const total = ref(0)
const ledgerList = ref([])
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
@@ -193,21 +176,6 @@
  }
})
const { searchForm, form, rules } = toRefs(data)
// äº§å“è¡¨å•弹框数据
const productFormData = reactive({
  productForm: {
    productCategory: '',
    specificationModel: '',
    unit: '',
    quantity: '',
    taxInclusiveUnitPrice: '',
    taxRate: '',
    taxInclusiveTotalPrice: '',
    taxExclusiveTotalPrice: '',
    invoiceType: '',
  },
})
const { productForm } = toRefs(productFormData)
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
@@ -222,17 +190,16 @@
}
const getList = () => {
  tableLoading.value = true
  invoiceRegistrationList({...searchForm.value, ...page}).then(res => {
  ledgerList({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
    tableData.value = res.data.records;
    tableData.value.map(item => {
      item.children = []
    })
    total.value = res.data.total
    tableData.value = res.rows;
    total.value = res.total
    expandedRowKeys.value = []
  })
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  console.log('selection', selection)
  selectedRows.value = selection
}
const expandedRowKeys = ref([])
@@ -241,10 +208,11 @@
  if (expandedRows.length > 0) {
    expandedRowKeys.value = []
    try {
      productList({invoiceRegistrationId: row.id}).then(res => {
      productList({salesLedgerId: row.id,
                   type: 1 }).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
        if (index > -1) {
          tableData.value[index].children = res.data;
          tableData.value[index].children = res;
        }
        expandedRowKeys.value.push(row.id)
      })
@@ -302,33 +270,30 @@
  return sums;
}
// æ‰“开弹框
const openForm = (type, row) => {
  operationType.value = type
const openForm = () => {
  // åˆ¤æ–­æ˜¯å¦å¤šé€‰
  if(selectedRows.value.length != 1) {
    proxy.$modal.msgError("请选择一条合同")
    return;
  }
  form.value = {}
  productData.value = []
  // æŸ¥è¯¢é”€å”®åˆåŒ
  ledgerListNoPage({}).then(res => {
    ledgerList.value = res.data;
  })
  if (type === 'edit') {
    invoiceRegistrationDetail({id: row.id}).then(res => {
      form.value = {...res.data}
      form.value.productDtoList = res.data.productDtoList
      productData.value = form.value.productDtoList
  getSalesLedgerWithProducts({id: selectedRows.value[0].id}).then(res => {
    form.value = {...res}
    productData.value = form.value.productData.map(item => {
      return item
    })
  }
  dialogFormVisible.value = true
    dialogFormVisible.value = true
    console.log('productData.value ',productData.value )
  })
}
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      form.value.productDtoList = proxy.HaveJson(productData.value)
      form.value.productDtoList.forEach(item => {
        item.id = ''
      })
      delete form.value.productData
      invoiceRegistrationSaveOrUpdate(form.value).then(res => {
      form.value.productData = proxy.HaveJson(productData.value)
      invoiceRegistrationSave(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeDia()
        getList()
@@ -340,13 +305,6 @@
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
// æ‰“开产品弹框
const openProductEdit = (row) => {
   const index =  productData.value.findIndex(item => item.id === row.id);
   if (index > -1) {
     productData.value[index].editFlag = !productData.value[index].editFlag
   }
}
// å¯¼å‡º
const handleOut = () => {
@@ -363,54 +321,24 @@
    proxy.$modal.msg("已取消")
  })
}
// åˆ é™¤
const handleDelete = () => {
  let ids = []
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
//本次开票失焦操作
const invoiceNumBlur = (row) => {
  if(!row.currentInvoiceNum){
    row.currentInvoiceNum = 0
  }
  ElMessageBox.confirm(
      '选中的内容将被删除,是否确认删除?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    invoiceRegistrationDel(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getList()
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
  })
}
// é”€å”®å°è´¦ç­›é€‰
const ledgerChange = (val) => {
  if(val){
    getSalesLedgerWithProducts({id: val}).then(res => {
      form.value = {
        salesLedgerId: res.id,
        customerName: res.customerName,
        salesman: res.salesman,
        projectName: res.projectName,
        productData: res.productData,
        salesContractNo: res.salesContractNo,
        customerId: res.customerId,
      }
      productData.value = form.value.productData.map(item => {
        item.editFlag = false
        return item
      })
    })
  }else {
    proxy.resetForm("formRef")
    productData.value = []
  if(row.currentInvoiceNum > row.noInvoiceNum){
    proxy.$modal.msgWarning('本次开票数不得大于未开票数')
    row.currentInvoiceNum = 0
  }
  // è®¡ç®—本次开票金额
  row.currentInvoiceAmount = row.currentInvoiceNum * row.taxInclusiveUnitPrice
  // è®¡ç®—未开票数
  row.noInvoiceNum = row.noInvoiceNum - row.currentInvoiceNum
  // è®¡ç®—未开票金额
  row.noInvoiceAmount = row.noInvoiceNum * row.taxInclusiveUnitPrice
}
getList()
</script>