曹睿
21 小时以前 4b1304917b0b16b09dd50191fab59d96933c0cf3
feat: 6月15日任务完90%
已修改19个文件
已添加8个文件
11597 ■■■■ 文件已修改
package.json 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 4316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/projectProfit.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/salesLedger.js 105 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImageUpload/index.vue 178 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/PIMTable.vue 347 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/FileUpload.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/index.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useFormData.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/usePaginationApi.jsx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/index.js 292 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/ImportExcel/index.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/index.vue 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/supplierManage/index.vue 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 666 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 466 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentLedger/index.vue 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/index.vue 279 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 920 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/reportAnalysis/projectProfit/index.vue 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 449 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 521 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPayment/index.vue 481 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentLedger/index.vue 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/index.vue 761 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -21,8 +21,9 @@
    "@vueuse/core": "10.11.0",
    "axios": "0.28.1",
    "clipboard": "2.0.11",
    "dayjs": "^1.11.13",
    "echarts": "5.5.1",
    "element-plus": "2.7.6",
    "element-plus": "2.7.7",
    "file-saver": "2.0.5",
    "fuse.js": "6.6.2",
    "js-beautify": "1.14.11",
@@ -30,6 +31,7 @@
    "jsencrypt": "3.3.2",
    "nprogress": "0.2.0",
    "pinia": "2.1.7",
    "sortablejs": "^1.15.6",
    "splitpanes": "3.1.5",
    "vue": "3.4.31",
    "vue-cropper": "1.1.1",
pnpm-lock.yaml
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
src/api/procurementManagement/projectProfit.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function getPurchaseList(query) {
  return request({
    url: "/purchase/report/list",
    method: "get",
    params: query,
  });
}
src/api/salesManagement/salesLedger.js
@@ -1,102 +1,111 @@
// é”€å”®å°è´¦é¡µé¢æŽ¥å£
import request from '@/utils/request'
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function ledgerList(query) {
    return request({
        url: '/sales/ledger/list',
        method: 'get',
        params: query
    })
    url: "/sales/ledger/list",
    method: "get",
    params: query,
  });
}
// å­è¡¨æ ¼æŸ¥è¯¢
export function productList(query) {
    return request({
        url: '/sales/product/list',
        method: 'get',
        params: query
    })
    url: "/sales/product/list",
    method: "get",
    params: query,
  });
}
// æŸ¥è¯¢å®¢æˆ·åç§°åˆ—表
export function customerList(query) {
    return request({
        url: '/basic/customer/customerList',
        method: 'get',
        params: query
    })
    url: "/basic/customer/customerList",
    method: "get",
    params: query,
  });
}
// æ–°å¢žã€ä¿®æ”¹é”€å”®å°è´¦
export function addOrUpdateSalesLedger(query) {
    return request({
        url: '/sales/ledger/addOrUpdateSalesLedger',
        method: 'post',
        data: query
    })
    url: "/sales/ledger/addOrUpdateSalesLedger",
    method: "post",
    data: query,
  });
}
// åˆ é™¤é”€å”®å°è´¦
export function delLedger(query) {
    return request({
        url: '/sales/ledger/delLedger',
        method: 'delete',
        data: query
    })
    url: "/sales/ledger/delLedger",
    method: "delete",
    data: query,
  });
}
// æŸ¥è¯¢é”€å”®å°è´¦è¯¦æƒ…
export function getSalesLedgerWithProducts(query) {
    return request({
        url: '/sales/ledger/getSalesLedgerWithProducts',
        method: 'get',
        params: query
    })
    url: "/sales/ledger/getSalesLedgerWithProducts",
    method: "get",
    params: query,
  });
}
// å®žæ—¶ä¿®æ”¹äº§å“ä¿¡æ¯
export function addOrUpdateSalesLedgerProduct(query) {
    return request({
        url: '/sales/product/addOrUpdateSalesLedgerProduct',
        method: 'post',
        data: query
    })
    url: "/sales/product/addOrUpdateSalesLedgerProduct",
    method: "post",
    data: query,
  });
}
// åˆ é™¤äº§å“
export function delProduct(query) {
    return request({
        url: '/sales/product/delProduct',
        method: 'delete',
        data: query
    })
    url: "/sales/product/delProduct",
    method: "delete",
    data: query,
  });
}
// ä¸Šä¼ é™„ä»¶
export function upload(query) {
    return request({
        url: '/file/upload',
        method: 'post',
    url: "/file/upload",
    method: "post",
        data: query,
        responseType: 'blob'
    })
    responseType: "blob",
  });
}
// ç¼–辑时删除附件
export function delLedgerFile(query) {
    return request({
        url: '/sales/ledger/delLedgerFile',
        method: 'delete',
    url: "/sales/ledger/delLedgerFile",
    method: "delete",
        data: query,
    })
  });
}
// é”€å”®ä¸åˆ†é¡µæŸ¥è¯¢
export function ledgerListNoPage(query) {
    return request({
        url: '/sales/ledger/listNoPage',
        method: 'get',
        params: query
    })
    url: "/sales/ledger/listNoPage",
    method: "get",
    params: query,
  });
}
// åˆ†é¡µæŸ¥è¯¢
export function ledgerListPage(query) {
    return request({
        url: '/sales/ledger/listPage',
        method: 'get',
        params: query
    })
    url: "/sales/ledger/listPage",
    method: "get",
    params: query,
  });
}
// æ ¹æ®é”€å”®åˆåŒå·æŸ¥äº§å“ä¿¡æ¯
export function getProductInfoByContractNo(query) {
  return request({
    url: "/purchase/ledger/getProductBySalesNo",
    method: "get",
    params: query,
  });
}
src/components/ImageUpload/index.vue
@@ -47,197 +47,205 @@
</template>
<script setup>
import { getToken } from "@/utils/auth"
import { isExternal } from "@/utils/validate"
import Sortable from 'sortablejs'
import { getToken } from "@/utils/auth";
import { isExternal } from "@/utils/validate";
import Sortable from "sortablejs";
const props = defineProps({
  modelValue: [String, Object, Array],
  // ä¸Šä¼ æŽ¥å£åœ°å€
  action: {
    type: String,
    default: "/common/upload"
    default: "/common/upload",
  },
  // ä¸Šä¼ æºå¸¦çš„参数
  data: {
    type: Object
    type: Object,
  },
  // å›¾ç‰‡æ•°é‡é™åˆ¶
  limit: {
    type: Number,
    default: 5
    default: 5,
  },
  // å¤§å°é™åˆ¶(MB)
  fileSize: {
    type: Number,
    default: 5
    default: 5,
  },
  // æ–‡ä»¶ç±»åž‹, ä¾‹å¦‚['png', 'jpg', 'jpeg']
  fileType: {
    type: Array,
    default: () => ["png", "jpg", "jpeg"]
    default: () => ["png", "jpg", "jpeg"],
  },
  // æ˜¯å¦æ˜¾ç¤ºæç¤º
  isShowTip: {
    type: Boolean,
    default: true
    default: true,
  },
  // æ‹–动排序
  drag: {
    type: Boolean,
    default: true
  }
})
    default: true,
  },
});
const { proxy } = getCurrentInstance()
const emit = defineEmits()
const number = ref(0)
const uploadList = ref([])
const dialogImageUrl = ref("")
const dialogVisible = ref(false)
const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action) // ä¸Šä¼ çš„图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() })
const fileList = ref([])
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const number = ref(0);
const uploadList = ref([]);
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action); // ä¸Šä¼ çš„图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
  () => props.isShowTip && (props.fileType || props.fileSize)
)
);
watch(() => props.modelValue, val => {
watch(
  () => props.modelValue,
  (val) => {
  if (val) {
    // é¦–先将值转为数组
    const list = Array.isArray(val) ? val : props.modelValue.split(",")
      const list = Array.isArray(val) ? val : props.modelValue.split(",");
    // ç„¶åŽå°†æ•°ç»„转为对象数组
    fileList.value = list.map(item => {
      fileList.value = list.map((item) => {
      if (typeof item === "string") {
        if (item.indexOf(baseUrl) === -1 && !isExternal(item)) {
          item = { name: baseUrl + item, url: baseUrl + item }
            item = { name: baseUrl + item, url: baseUrl + item };
        } else {
          item = { name: item, url: item }
            item = { name: item, url: item };
        }
      }
      return item
    })
        return item;
      });
  } else {
    fileList.value = []
    return []
      fileList.value = [];
      return [];
  }
},{ deep: true, immediate: true })
  },
  { deep: true, immediate: true }
);
// ä¸Šä¼ å‰loading加载
function handleBeforeUpload(file) {
  let isImg = false
  let isImg = false;
  if (props.fileType.length) {
    let fileExtension = ""
    let fileExtension = "";
    if (file.name.lastIndexOf(".") > -1) {
      fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1)
      fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
    }
    isImg = props.fileType.some(type => {
      if (file.type.indexOf(type) > -1) return true
      if (fileExtension && fileExtension.indexOf(type) > -1) return true
      return false
    })
    isImg = props.fileType.some((type) => {
      if (file.type.indexOf(type) > -1) return true;
      if (fileExtension && fileExtension.indexOf(type) > -1) return true;
      return false;
    });
  } else {
    isImg = file.type.indexOf("image") > -1
    isImg = file.type.indexOf("image") > -1;
  }
  if (!isImg) {
    proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join("/")}图片格式文件!`)
    return false
    proxy.$modal.msgError(
      `文件格式不正确,请上传${props.fileType.join("/")}图片格式文件!`
    );
    return false;
  }
  if (file.name.includes(',')) {
    proxy.$modal.msgError('文件名不正确,不能包含英文逗号!')
    return false
  if (file.name.includes(",")) {
    proxy.$modal.msgError("文件名不正确,不能包含英文逗号!");
    return false;
  }
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize
    const isLt = file.size / 1024 / 1024 < props.fileSize;
    if (!isLt) {
      proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`)
      return false
      proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
      return false;
    }
  }
  proxy.$modal.loading("正在上传图片,请稍候...")
  number.value++
  proxy.$modal.loading("正在上传图片,请稍候...");
  number.value++;
}
// æ–‡ä»¶ä¸ªæ•°è¶…出
function handleExceed() {
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} ä¸ª!`)
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} ä¸ª!`);
}
// ä¸Šä¼ æˆåŠŸå›žè°ƒ
function handleUploadSuccess(res, file) {
  if (res.code === 200) {
    uploadList.value.push({ name: res.fileName, url: res.fileName })
    uploadedSuccessfully()
    uploadList.value.push({ name: res.fileName, url: res.fileName });
    uploadedSuccessfully();
  } else {
    number.value--
    proxy.$modal.closeLoading()
    proxy.$modal.msgError(res.msg)
    proxy.$refs.imageUpload.handleRemove(file)
    uploadedSuccessfully()
    number.value--;
    proxy.$modal.closeLoading();
    proxy.$modal.msgError(res.msg);
    proxy.$refs.imageUpload.handleRemove(file);
    uploadedSuccessfully();
  }
}
// åˆ é™¤å›¾ç‰‡
function handleDelete(file) {
  const findex = fileList.value.map(f => f.name).indexOf(file.name)
  const findex = fileList.value.map((f) => f.name).indexOf(file.name);
  if (findex > -1 && uploadList.value.length === number.value) {
    fileList.value.splice(findex, 1)
    emit("update:modelValue", listToString(fileList.value))
    return false
    fileList.value.splice(findex, 1);
    emit("update:modelValue", listToString(fileList.value));
    return false;
  }
}
// ä¸Šä¼ ç»“束处理
function uploadedSuccessfully() {
  if (number.value > 0 && uploadList.value.length === number.value) {
    fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
    uploadList.value = []
    number.value = 0
    emit("update:modelValue", listToString(fileList.value))
    proxy.$modal.closeLoading()
    fileList.value = fileList.value
      .filter((f) => f.url !== undefined)
      .concat(uploadList.value);
    uploadList.value = [];
    number.value = 0;
    emit("update:modelValue", listToString(fileList.value));
    proxy.$modal.closeLoading();
  }
}
// ä¸Šä¼ å¤±è´¥
function handleUploadError() {
  proxy.$modal.msgError("上传图片失败")
  proxy.$modal.closeLoading()
  proxy.$modal.msgError("上传图片失败");
  proxy.$modal.closeLoading();
}
// é¢„览
function handlePictureCardPreview(file) {
  dialogImageUrl.value = file.url
  dialogVisible.value = true
  dialogImageUrl.value = file.url;
  dialogVisible.value = true;
}
// å¯¹è±¡è½¬æˆæŒ‡å®šå­—符串分隔
function listToString(list, separator) {
  let strs = ""
  separator = separator || ","
  let strs = "";
  separator = separator || ",";
  for (let i in list) {
    if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) {
      strs += list[i].url.replace(baseUrl, "") + separator
      strs += list[i].url.replace(baseUrl, "") + separator;
    }
  }
  return strs != "" ? strs.substr(0, strs.length - 1) : ""
  return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
// åˆå§‹åŒ–拖拽排序
onMounted(() => {
  if (props.drag) {
    nextTick(() => {
      const element = document.querySelector('.el-upload-list')
      const element = document.querySelector(".el-upload-list");
      Sortable.create(element, {
        onEnd: (evt) => {
          const movedItem = fileList.value.splice(evt.oldIndex, 1)[0]
          fileList.value.splice(evt.newIndex, 0, movedItem)
          emit('update:modelValue', listToString(fileList.value))
          const movedItem = fileList.value.splice(evt.oldIndex, 1)[0];
          fileList.value.splice(evt.newIndex, 0, movedItem);
          emit("update:modelValue", listToString(fileList.value));
        },
      });
    });
        }
      })
    })
  }
})
});
</script>
<style scoped lang="scss">
src/components/PIMTable/PIMTable.vue
@@ -1,25 +1,70 @@
<template>
  <el-table ref="multipleTable" v-loading="tableLoading" :border="border" :data="tableData"
    :header-cell-style="{ background: '#F0F1F5', color: '#333333' }" height="calc(100vh - 18.5em)"
    :highlight-current-row="highlightCurrentRow" :row-class-name="rowClassName" :row-style="rowStyle" :row-key="rowKey"
    style="width: 100%" tooltip-effect="dark" @row-click="rowClick" @current-change="currentChange" :show-summary="isShowSummary"
  <el-table
    ref="multipleTable"
    v-loading="tableLoading"
    :border="border"
    :data="tableData"
    :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
    height="calc(100vh - 18.5em)"
    :highlight-current-row="highlightCurrentRow"
    :row-class-name="rowClassName"
    :row-style="rowStyle"
    :row-key="rowKey"
    style="width: 100%"
    tooltip-effect="dark"
    @row-click="rowClick"
    @current-change="currentChange"
    :show-summary="isShowSummary"
            :summary-method="summaryMethod"
    @selection-change="handleSelectionChange" class="lims-table">
    <el-table-column align="center" type="selection" width="55"  v-if="isSelection"/>
    @selection-change="handleSelectionChange"
    class="lims-table"
  >
    <el-table-column
      align="center"
      type="selection"
      width="55"
      v-if="isSelection"
    />
    <el-table-column align="center" label="序号" type="index" width="60" />
    <el-table-column v-for="(item, index) in column" :key="index" :column-key="item.columnKey"
      :filter-method="item.filterHandler" :filter-multiple="item.filterMultiple" :filtered-value="item.filteredValue"
      :filters="item.filters" :fixed="item.fixed" :label="item.label" :prop="item.prop" show-overflow-tooltip
      :align="item.align" :sortable="!!item.sortable" :type="item.type" :width="item.width">
      <template v-if="item.hasOwnProperty('colunmTemplate')" #[item.colunmTemplate]="scope">
        <slot v-if="item.theadSlot" :name="item.theadSlot" :index="scope.$index" :row="scope.row" />
    <el-table-column
      v-for="(item, index) in column"
      :key="index"
      :column-key="item.columnKey"
      :filter-method="item.filterHandler"
      :filter-multiple="item.filterMultiple"
      :filtered-value="item.filteredValue"
      :filters="item.filters"
      :fixed="item.fixed"
      :label="item.label"
      :prop="item.prop"
      show-overflow-tooltip
      :align="item.align"
      :sortable="!!item.sortable"
      :type="item.type"
      :width="item.width"
    >
      <template
        v-if="item.hasOwnProperty('colunmTemplate')"
        #[item.colunmTemplate]="scope"
      >
        <slot
          v-if="item.theadSlot"
          :name="item.theadSlot"
          :index="scope.$index"
          :row="scope.row"
        />
      </template>
      <template #default="scope">
        <!-- æ’æ§½ -->
        <div v-if="item.dataType == 'slot'">
          <slot v-if="item.slot" :index="scope.$index" :name="item.slot" :row="scope.row" />
          <slot
            v-if="item.slot"
            :index="scope.$index"
            :name="item.slot"
            :row="scope.row"
          />
        </div>
        <!-- è¿›åº¦æ¡ -->
        <div v-else-if="item.dataType == 'progress'">
@@ -27,26 +72,47 @@
        </div>
        <!-- å›¾ç‰‡ -->
        <div v-else-if="item.dataType == 'image'">
          <img :src="javaApi + '/img/' + scope.row[item.prop]" alt=""
            style="width: 40px; height: 40px; margin-top: 10px" />
          <img
            :src="javaApi + '/img/' + scope.row[item.prop]"
            alt=""
            style="width: 40px; height: 40px; margin-top: 10px"
          />
        </div>
        <!-- tag -->
        <div v-else-if="item.dataType == 'tag'">
          <el-tag v-if="typeof dataTypeFn(scope.row[item.prop], item.formatData) === 'string'"
          <el-tag
            v-if="
              typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
              'string'
            "
            :title="formatters(scope.row[item.prop], item.formatData)"
            :type="formatType(scope.row[item.prop], item.formatType)">
            :type="formatType(scope.row[item.prop], item.formatType)"
          >
            {{ formatters(scope.row[item.prop], item.formatData) }}
          </el-tag>
          <el-tag v-for="(tag, index) in dataTypeFn(scope.row[item.prop], item.formatData)"
            v-else-if="typeof dataTypeFn(scope.row[item.prop], item.formatData) === 'object'" :key="index"
            :title="formatters(scope.row[item.prop], item.formatData)" :type="formatType(tag, item.formatType)">
          <el-tag
            v-for="(tag, index) in dataTypeFn(
              scope.row[item.prop],
              item.formatData
            )"
            v-else-if="
              typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
              'object'
            "
            :key="index"
            :title="formatters(scope.row[item.prop], item.formatData)"
            :type="formatType(tag, item.formatType)"
          >
            {{ item.tagGroup ? tag[item.tagGroup.label] ?? tag : tag }}
          </el-tag>
          <el-tag v-else :title="formatters(scope.row[item.prop], item.formatData)"
            :type="formatType(scope.row[item.prop], item.formatType)">
          <el-tag
            v-else
            :title="formatters(scope.row[item.prop], item.formatData)"
            :type="formatType(scope.row[item.prop], item.formatType)"
          >
            {{ formatters(scope.row[item.prop], item.formatData) }}
          </el-tag>
        </div>
@@ -54,91 +120,146 @@
        <!-- æŒ‰é’® -->
        <div v-else-if="item.dataType == 'action'">
          <template v-for="(o, key) in item.operation" :key="key">
            <el-button v-show="o.type != 'upload'" size="small" v-if="o.showHide ? o.showHide(scope.row) : true"
              :disabled="o.disabled ? o.disabled(scope.row) : false" :plain="o.plain" type="primary"
              :style="{ color: (o.name === '删除' || o.name === 'delete') ? '#f56c6c' : o.color }" link
              @click="o.clickFun(scope.row)" :key="key">
            <el-button
              v-show="o.type != 'upload'"
              size="small"
              v-if="o.showHide ? o.showHide(scope.row) : true"
              :disabled="o.disabled ? o.disabled(scope.row) : false"
              :plain="o.plain"
              type="primary"
              :style="{
                color:
                  o.name === '删除' || o.name === 'delete'
                    ? '#f56c6c'
                    : o.color,
              }"
              link
              @click="o.clickFun(scope.row)"
              :key="key"
            >
              {{ o.name }}
            </el-button>
            <el-upload :action="javaApi + o.url + '?id=' + (o.uploadIdFun ? o.uploadIdFun(scope.row) : scope.row.id)"
              ref="uploadRef" size="small" :multiple="o.multiple ? o.multiple : false" :limit="1"
            <el-upload
              :action="
                javaApi +
                o.url +
                '?id=' +
                (o.uploadIdFun ? o.uploadIdFun(scope.row) : scope.row.id)
              "
              ref="uploadRef"
              size="small"
              :multiple="o.multiple ? o.multiple : false"
              :limit="1"
              :disabled="o.disabled ? o.disabled(scope.row) : false"
              :accept="o.accept ? o.accept : '.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'"
              v-if="o.type == 'upload'" style="display: inline-block; width: 50px"
              v-show="o.showHide ? o.showHide(scope.row) : true" :headers="uploadHeader"
              :accept="
                o.accept
                  ? o.accept
                  : '.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'
              "
              v-if="o.type == 'upload'"
              style="display: inline-block; width: 50px"
              v-show="o.showHide ? o.showHide(scope.row) : true"
              :headers="uploadHeader"
              :before-upload="(file) => beforeUpload(file, scope.$index)"
              :on-change="(file, fileList) => handleChange(file, fileList, scope.$index)"
              :on-error="(error, file, fileList) => onError(error, file, fileList, scope.$index)"
              :on-success="(response, file, fileList) => handleSuccessUp(response, file, fileList, scope.$index)"
              :on-exceed="onExceed" :show-file-list="false">
              <el-button :size="o.size ? o.size : 'small'" link type="primary"
                :disabled="o.disabled ? o.disabled(scope.row) : false">{{ o.name }}</el-button>
              :on-change="
                (file, fileList) => handleChange(file, fileList, scope.$index)
              "
              :on-error="
                (error, file, fileList) =>
                  onError(error, file, fileList, scope.$index)
              "
              :on-success="
                (response, file, fileList) =>
                  handleSuccessUp(response, file, fileList, scope.$index)
              "
              :on-exceed="onExceed"
              :show-file-list="false"
            >
              <el-button
                :size="o.size ? o.size : 'small'"
                link
                type="primary"
                :disabled="o.disabled ? o.disabled(scope.row) : false"
                >{{ o.name }}</el-button
              >
            </el-upload>
          </template>
        </div>
        <!-- å¯ç‚¹å‡»çš„æ–‡å­— -->
        <div v-else-if="item.dataType == 'link'" class="cell link" style="width: 100%"
          @click="goLink(scope.row, item.linkMethod)">
        <div
          v-else-if="item.dataType == 'link'"
          class="cell link"
          style="width: 100%"
          @click="goLink(scope.row, item.linkMethod)"
        >
          <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
        </div>
        <!-- é»˜è®¤çº¯å±•示数据 -->
        <div v-else class="cell" style="width: 100%">
          <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
          <span v-else>{{ formatters(scope.row[item.prop], item.formatData) }}</span>
          <span v-else>{{
            formatters(scope.row[item.prop], item.formatData)
          }}</span>
        </div>
      </template>
    </el-table-column>
  </el-table>
  <pagination v-show="total > 0" :total="total" :layout="page.layout" :page="page.current" :limit="page.size"
    @pagination="paginationSearch" />
  <pagination
    v-show="total > 0"
    :total="total"
    :layout="page.layout"
    :page="page.current"
    :limit="page.size"
    @pagination="paginationSearch"
  />
</template>
<script setup>
import pagination from './Pagination.vue'
import { ref, inject, getCurrentInstance } from "vue"
import { ElMessage } from "element-plus"
import pagination from "./Pagination.vue";
import { ref, inject, getCurrentInstance } from "vue";
import { ElMessage } from "element-plus";
// èŽ·å–å…¨å±€çš„ uploadHeader
const { proxy } = getCurrentInstance()
const uploadHeader = proxy.uploadHeader
const javaApi = proxy.javaApi
const { proxy } = getCurrentInstance();
const uploadHeader = proxy.uploadHeader;
const javaApi = proxy.javaApi;
const emit = defineEmits(["pagination"]);
// Filters
const typeFn = (val, row) => {
  return typeof val === 'function' ? val(row) : val
}
  return typeof val === "function" ? val(row) : val;
};
const formatters = (val, format) => {
  return typeof format === 'function' ? format(val) : val
}
  return typeof format === "function" ? format(val) : val;
};
// Props(使用 defineProps çš„非 TS å½¢å¼ï¼‰
const props = defineProps({
  tableLoading: {
    type: Boolean,
    default: false
    default: false,
  },
  handleSelectionChange: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  summaryMethod: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  rowClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  currentChange: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  border: {
    type: Boolean,
    default: true
    default: true,
  },
  isSelection: {
    type: Boolean,
@@ -150,31 +271,31 @@
  },
  highlightCurrentRow: {
    type: Boolean,
    default: false
    default: false,
  },
  headerCellStyle: {
    type: Object,
    default: () => ({})
    default: () => ({}),
  },
  column: {
    type: Array,
    default: () => []
    default: () => [],
  },
  rowClassName: {
    type: Function,
    default: () => ''
    default: () => "",
  },
  rowStyle: {
    type: [Object, Function],
    default: () => ({})
    default: () => ({}),
  },
  tableData: {
    type: Array,
    default: () => []
    default: () => [],
  },
  rowKey: {
    type: String,
    default: undefined
    default: undefined,
  },
  page: {
    type: Object,
@@ -182,108 +303,108 @@
      total: 0,
      current: 0,
      size: 10,
      layout: 'total, sizes, prev, pager, next, jumper'
    })
      layout: "total, sizes, prev, pager, next, jumper",
    }),
  },
  total: {
    type: Number,
    default: 0
  }
})
    default: 0,
  },
});
// Data
const uploadRefs = ref([])
const currentFiles = ref({})
const uploadKeys = ref({})
const uploadRefs = ref([]);
const currentFiles = ref({});
const uploadKeys = ref({});
const indexMethod = (index) => {
  return (props.page.current - 1) * props.page.size + index + 1
}
  return (props.page.current - 1) * props.page.size + index + 1;
};
// ç‚¹å‡» link äº‹ä»¶
const goLink = (row, linkMethod) => {
  if (!linkMethod) {
    return ElMessage.warning("请配置 link äº‹ä»¶")
    return ElMessage.warning("请配置 link äº‹ä»¶");
  }
  const parentMethod = getParentMethod(linkMethod)
  if (typeof parentMethod === 'function') {
    parentMethod(row)
  const parentMethod = getParentMethod(linkMethod);
  if (typeof parentMethod === "function") {
    parentMethod(row);
  } else {
    console.warn(`父组件中未找到方法: ${linkMethod}`)
    console.warn(`父组件中未找到方法: ${linkMethod}`);
  }
}
};
// èŽ·å–çˆ¶ç»„ä»¶æ–¹æ³•ï¼ˆç¤ºä¾‹å®žçŽ°ï¼‰
const getParentMethod = (methodName) => {
  const parentMethods = inject('parentMethods', {})
  return parentMethods[methodName]
}
  const parentMethods = inject("parentMethods", {});
  return parentMethods[methodName];
};
const dataTypeFn = (val, format) => {
  if (typeof format === "function") {
    return format(val)
  } else return val
}
    return format(val);
  } else return val;
};
const formatType = (val, format) => {
  if (typeof format === "function") {
    return format(val)
  } else return ""
}
    return format(val);
  } else return "";
};
// æ–‡ä»¶å˜åŒ–处理
const handleChange = (file, fileList, index) => {
  if (fileList.length > 1) {
    const earliestFile = fileList[0]
    uploadRefs.value[index]?.handleRemove(earliestFile)
    const earliestFile = fileList[0];
    uploadRefs.value[index]?.handleRemove(earliestFile);
  }
  currentFiles.value[index] = file
}
  currentFiles.value[index] = file;
};
// æ–‡ä»¶ä¸Šä¼ å‰æ ¡éªŒ
const beforeUpload = (rawFile, index) => {
  currentFiles.value[index] = {}
  currentFiles.value[index] = {};
  if (rawfile.size > 1024 * 1024 * 10 * 10) {
    ElMessage.error('上传文件不超过10M')
    return false
    ElMessage.error("上传文件不超过10M");
    return false;
  }
  return true
}
  return true;
};
// ä¸Šä¼ æˆåŠŸ
const handleSuccessUp = (response, file, fileList, index) => {
  if (response.code == 200) {
    if (uploadRefs[index]) {
      uploadRefs[index].clearFiles()
      uploadRefs[index].clearFiles();
    }
    currentFiles[index] = file
    ElMessage.success("上传成功")
    resetUploadComponent(index)
    currentFiles[index] = file;
    ElMessage.success("上传成功");
    resetUploadComponent(index);
  } else {
    ElMessage.error(response.message)
    ElMessage.error(response.message);
  }
}
};
const resetUploadComponent = (index) => {
  uploadKeys[index] = Date.now()
}
  uploadKeys[index] = Date.now();
};
// ä¸Šä¼ å¤±è´¥
const onError = (error, file, fileList, index) => {
  ElMessage.error('文件上传失败,请重试')
  ElMessage.error("文件上传失败,请重试");
  if (uploadRefs.value[index]) {
    uploadRefs.value[index].clearFiles()
    uploadRefs.value[index].clearFiles();
  }
}
};
// æ–‡ä»¶æ•°é‡è¶…限提示
const onExceed = () => {
  ElMessage.warning('超出文件个数')
}
  ElMessage.warning("超出文件个数");
};
const paginationSearch = ({ page, limit }) => {
  emit("pagination", { page: page, limit: limit });
}
};
</script>
<style scoped lang="scss">
src/components/Upload/FileUpload.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
<script setup>
import { ref } from "vue";
defineOptions({
  name: "文件上传组件",
});
const props = defineProps({
  downloadTemplate: Function,
  showTips: Boolean,
  accept: {
    type: String,
    default: ".xls, .xlsx",
  },
  headers: Object,
  action: String,
  disabled: {
    type: Boolean,
    default: false,
  },
});
const emits = defineEmits(["success", "error"]);
const uploadRef = ref();
const fileList = ref([]);
const uploadApi = () => {
  uploadRef.value.submit();
};
const handleFileSuccess = (response, file, fileList) => {
  upload.open = false;
  upload.isUploading = false;
  uploadRef.value.handleRemove(file);
  emits("success", response, file, fileList);
};
defineExpose({
  fileList,
  uploadApi,
});
</script>
<template>
  <el-upload
    ref="uploadRef"
    v-model:file-list="fileList"
    drag
    multiple
    :action="action"
    :accept="accept"
    :headers="headers"
    :disabled="disabled"
    :auto-upload="false"
    :limit="1"
    :drag="true"
    :on-success="handleFileSuccess"
  >
    <div class="el-upload__text">
      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
      <div class="el-upload__text">
        å°†æ–‡ä»¶æ‹–到此处,或
        <em>点击导入数据</em>
      </div>
    </div>
    <template #tip>
      <div class="el-upload__tip text-center">
        åªèƒ½ä¸Šä¼ xlsx/xls文件,且不超过10M
        <el-button
          type="primary"
          link
          class="reset-margin"
          @click="props.downloadTemplate()"
        >
          <span style="font-size: 12px; font-weight: normal">下载模板</span>
        </el-button>
      </div>
    </template>
  </el-upload>
</template>
src/components/Upload/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
export { default as FileUpload } from "./FileUpload.vue";
src/hooks/useFormData.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
import { reactive } from "vue";
import { deepClone } from "@/utils/index.js"
export default function useFormData(initData) {
  const form = reactive(deepClone(initData, true));
  function resetForm() {
    const initData2 = JSON.parse(JSON.stringify(initData));
    Object.keys(initData).forEach(key => {
      form[key] = initData2[key];
    });
  }
  return { form, resetForm };
}
src/hooks/usePaginationApi.jsx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
import { ref, reactive, watchEffect, unref } from "vue";
import useFormData from "@/hooks/useFormData";
import { deepClone, isEqual } from "@/utils/index.js"
/**
 * åˆ†é¡µapi
 * @param api æŽ¥å£
 * @param initalFilters åˆå§‹åŒ–筛选条件
 * @param sorters
 * @param filterTransformer
 */
export function usePaginationApi(
  api,
  initalFilters,
  columns,
  sorters,
  filterTransformer,
  cb
) {
  const dataList = ref([]);
  const { form: filters, resetForm } = useFormData(initalFilters);
  let lastFilters = deepClone(initalFilters);
  const sorter = reactive(sorters || {});
  const others = ref({});
  const loading = ref(true);
  const paginationAlign = ref("right");
  /** åˆ†é¡µé…ç½® */
  const pagination = reactive({
    pageSize: 10,
    currentPage: 1,
    pageSizes: [10, 15, 20],
    total: 0,
    align: "right",
    background: true
  });
  /** åŠ è½½åŠ¨ç”»é…ç½® */
  const loadingConfig = reactive({
    text: "正在加载第一页...",
    viewBox: "-10, -10, 50, 50",
    spinner: `
        <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
      `
    // svg: "",
    // background: rgba()
  });
  function getFinalParams() {
    const finalFilters = {};
    const beforeParams = unref(filters);
    if (filterTransformer) {
      Object.keys(beforeParams).forEach(key => {
        if (filterTransformer[key]) {
          Object.assign(
            finalFilters,
            filterTransformer[key](beforeParams[key], beforeParams)
          );
        } else {
          finalFilters[key] = beforeParams[key];
        }
      });
    }
    return filterTransformer
      ? { ...finalFilters, ...sorter }
      : { ...beforeParams, ...sorter };
  }
  async function getTableData() {
    // å¦‚果这次和上次的filter不同,那么就重置页码
    if (!isEqual(unref(filters), lastFilters)) {
      pagination.currentPage = 1;
      lastFilters = deepClone(unref(filters));
    }
    loading.value = true;
    api({
      ...getFinalParams(),
      current: pagination.currentPage,
      size: pagination.pageSize
    }).then(({ code, data, ...rest }) => {
      if (code == 200) {
        // pagination.currentPage = meta.current_page;
        // pagination.pageSize = meta.per_page;
        pagination.total = data.total;
        others.value = rest;
        dataList.value = data.records;
        cb && cb(data);
        loading.value = false;
      } else {
        loading.value = false;
        ElMessage({ message: data.msg, type: "error" });
      }
    });
  }
  function onSizeChange(val) {
    pagination.pageSize = val;
    pagination.currentPage = 1;
    getTableData();
  }
  function onCurrentChange(val) {
    loadingConfig.text = `正在加载第${val}页...`;
    loading.value = true;
    getTableData();
  }
  function resetFilters() {
    resetForm();
    pagination.currentPage = 1;
    getTableData();
  }
  watchEffect(() => {
    pagination.align = paginationAlign.value
  });
  // onMounted(() => {
  //   getTableData();
  // });
  return {
    loading,
    columns,
    dataList,
    pagination,
    loadingConfig,
    paginationAlign,
    filters,
    sorter,
    others,
    onSizeChange,
    onCurrentChange,
    getTableData,
    resetFilters
  };
}
src/utils/index.js
@@ -1,18 +1,25 @@
import { parseTime } from './ruoyi'
import { parseTime } from "./ruoyi";
/**
 * è¡¨æ ¼æ—¶é—´æ ¼å¼åŒ–
 */
export function formatDate(cellValue) {
  if (cellValue == null || cellValue == "") return ""
  var date = new Date(cellValue)
  var year = date.getFullYear()
  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
  var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
  return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
  if (cellValue == null || cellValue == "") return "";
  var date = new Date(cellValue);
  var year = date.getFullYear();
  var month =
    date.getMonth() + 1 < 10
      ? "0" + (date.getMonth() + 1)
      : date.getMonth() + 1;
  var day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
  var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
  var minutes =
    date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
  var seconds =
    date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
  return (
    year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds
  );
}
/**
@@ -21,40 +28,40 @@
 * @returns {string}
 */
export function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = parseInt(time) * 1000
  if (("" + time).length === 10) {
    time = parseInt(time) * 1000;
  } else {
    time = +time
    time = +time;
  }
  const d = new Date(time)
  const now = Date.now()
  const d = new Date(time);
  const now = Date.now();
  const diff = (now - d) / 1000
  const diff = (now - d) / 1000;
  if (diff < 30) {
    return '刚刚'
    return "刚刚";
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
    return Math.ceil(diff / 60) + "分钟前";
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
    return Math.ceil(diff / 3600) + "小时前";
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
    return "1天前";
  }
  if (option) {
    return parseTime(time, option)
    return parseTime(time, option);
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      "月" +
      d.getDate() +
      '日' +
      "日" +
      d.getHours() +
      '时' +
      "时" +
      d.getMinutes() +
      '分'
    )
      "分"
    );
  }
}
@@ -63,18 +70,18 @@
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url
  const search = url.substring(url.lastIndexOf('?') + 1)
  const obj = {}
  const reg = /([^?&=]+)=([^?&=]*)/g
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf("?") + 1);
  const obj = {};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)
    let val = decodeURIComponent($2)
    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}
/**
@@ -83,14 +90,14 @@
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length
  let s = str.length;
  for (var i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i)
    if (code > 0x7f && code <= 0x7ff) s++
    else if (code > 0x7ff && code <= 0xffff) s += 2
    if (code >= 0xDC00 && code <= 0xDFFF) i--
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s += 2;
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s
  return s;
}
/**
@@ -98,13 +105,13 @@
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = []
  const newArray = [];
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i])
      newArray.push(actual[i]);
    }
  }
  return newArray
  return newArray;
}
/**
@@ -112,13 +119,13 @@
 * @returns {Array}
 */
export function param(json) {
  if (!json) return ''
  if (!json) return "";
  return cleanArray(
    Object.keys(json).map(key => {
      if (json[key] === undefined) return ''
      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
    Object.keys(json).map((key) => {
      if (json[key] === undefined) return "";
      return encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
    })
  ).join('&')
  ).join("&");
}
/**
@@ -126,21 +133,21 @@
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
  const search = decodeURIComponent(url.split("?")[1]).replace(/\+/g, " ");
  if (!search) {
    return {}
    return {};
  }
  const obj = {}
  const searchArr = search.split('&')
  searchArr.forEach(v => {
    const index = v.indexOf('=')
  const obj = {};
  const searchArr = search.split("&");
  searchArr.forEach((v) => {
    const index = v.indexOf("=");
    if (index !== -1) {
      const name = v.substring(0, index)
      const val = v.substring(index + 1, v.length)
      obj[name] = val
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  })
  return obj
  });
  return obj;
}
/**
@@ -148,9 +155,9 @@
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement('div')
  div.innerHTML = val
  return div.textContent || div.innerText
  const div = document.createElement("div");
  div.innerHTML = val;
  return div.textContent || div.innerText;
}
/**
@@ -160,21 +167,21 @@
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== 'object') {
    target = {}
  if (typeof target !== "object") {
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice()
    return source.slice();
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property]
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty)
  Object.keys(source).forEach((property) => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === "object") {
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      target[property] = sourceProperty
      target[property] = sourceProperty;
    }
  })
  return target
  });
  return target;
}
/**
@@ -183,18 +190,18 @@
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return
    return;
  }
  let classString = element.className
  const nameIndex = classString.indexOf(className)
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += '' + className
    classString += "" + className;
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length)
      classString.substr(nameIndex + className.length);
  }
  element.className = classString
  element.className = classString;
}
/**
@@ -202,10 +209,10 @@
 * @returns {Date}
 */
export function getTime(type) {
  if (type === 'start') {
    return new Date().getTime() - 3600 * 1000 * 24 * 90
  if (type === "start") {
    return new Date().getTime() - 3600 * 1000 * 24 * 90;
  } else {
    return new Date(new Date().toDateString())
    return new Date(new Date().toDateString());
  }
}
@@ -216,38 +223,38 @@
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result
  let timeout, args, context, timestamp, result;
  const later = function() {
    // æ®ä¸Šä¸€æ¬¡è§¦å‘æ—¶é—´é—´éš”
    const last = +new Date() - timestamp
    const last = +new Date() - timestamp;
    // ä¸Šæ¬¡è¢«åŒ…装函数被调用时间间隔 last å°äºŽè®¾å®šæ—¶é—´é—´éš” wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null
      timeout = null;
      // å¦‚果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  }
  };
  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // å¦‚果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
      result = func.apply(context, args);
      context = args = null;
    }
    return result
  }
    return result;
  };
}
/**
@@ -258,18 +265,18 @@
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments', 'deepClone')
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone");
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys]
      targetObj[keys] = source[keys];
    }
  })
  return targetObj
  });
  return targetObj;
}
/**
@@ -277,16 +284,16 @@
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr))
  return Array.from(new Set(arr));
}
/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + ''
  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
  return (+(randomNum + timestamp)).toString(32)
  const timestamp = +new Date() + "";
  const randomNum = parseInt((1 + Math.random()) * 65536) + "";
  return (+(randomNum + timestamp)).toString(32);
}
/**
@@ -296,7 +303,7 @@
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
}
/**
@@ -305,7 +312,7 @@
 * @param {string} cls
 */
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls
  if (!hasClass(ele, cls)) ele.className += " " + cls;
}
/**
@@ -315,76 +322,77 @@
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
    ele.className = ele.className.replace(reg, ' ')
    const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
    ele.className = ele.className.replace(reg, " ");
  }
}
export function makeMap(str, expectsLowerCase) {
  const map = Object.create(null)
  const list = str.split(',')
  const map = Object.create(null);
  const list = str.split(",");
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
    map[list[i]] = true;
  }
  return expectsLowerCase
    ? val => map[val.toLowerCase()]
    : val => map[val]
  return expectsLowerCase ? (val) => map[val.toLowerCase()] : (val) => map[val];
}
 
export const exportDefault = 'export default '
export const exportDefault = "export default ";
export const beautifierConf = {
  html: {
    indent_size: '2',
    indent_char: ' ',
    max_preserve_newlines: '-1',
    indent_size: "2",
    indent_char: " ",
    max_preserve_newlines: "-1",
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: 'separate',
    brace_style: 'end-expand',
    indent_scripts: "separate",
    brace_style: "end-expand",
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: false,
    end_with_newline: true,
    wrap_line_length: '110',
    wrap_line_length: "110",
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true
    indent_empty_lines: true,
  },
  js: {
    indent_size: '2',
    indent_char: ' ',
    max_preserve_newlines: '-1',
    indent_size: "2",
    indent_char: " ",
    max_preserve_newlines: "-1",
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: 'normal',
    brace_style: 'end-expand',
    indent_scripts: "normal",
    brace_style: "end-expand",
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: true,
    end_with_newline: true,
    wrap_line_length: '110',
    wrap_line_length: "110",
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true
  }
}
    indent_empty_lines: true,
  },
};
// é¦–字母大小
export function titleCase(str) {
  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
  return str.replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}
// ä¸‹åˆ’转驼峰
export function camelCase(str) {
  return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
  return str.replace(/_[a-z]/g, (str1) => str1.substr(-1).toUpperCase());
}
export function isNumberStr(str) {
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}
 
export function isEqual(obj1, obj2) {
  return JSON.stringify(obj1) === JSON.stringify(obj2);
}
src/views/basicData/product/ImportExcel/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
<template>
  <el-button type="info" plain icon="Upload" @click="handleImport">
    å¯¼å…¥
  </el-button>
  <el-dialog v-model="upload.open" :title="upload.title">
    <FileUpload
      ref="fileUploadRef"
      accept=".xlsx, .xls"
      :headers="upload.headers"
      :action="upload.url + '?updateSupport=' + upload.updateSupport"
      :disabled="upload.isUploading"
      @success="handleFileSuccess"
    />
    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
        <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup>
import { reactive } from "vue";
import { getToken } from "@/utils/auth.js";
import { FileUpload } from "@/components/Upload";
import { ElMessage } from "element-plus";
defineOptions({
  name: "产品维护导入",
});
const emits = defineEmits(["uploadSuccess"]);
const fileUploadRef = ref();
const upload = reactive({
  // æ˜¯å¦æ˜¾ç¤ºå¼¹å‡ºå±‚(供应商导入)
  open: false,
  // å¼¹å‡ºå±‚标题(供应商导入)
  title: "",
  // æ˜¯å¦ç¦ç”¨ä¸Šä¼ 
  isUploading: false,
  // è®¾ç½®ä¸Šä¼ çš„请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import",
});
// ç‚¹å‡»å¯¼å…¥
const handleImport = () => {
  upload.open = true;
  upload.title = "产品导入";
};
const submitFileForm = () => {
  fileUploadRef.value.uploadApi();
};
const handleFileSuccess = (response) => {
  const { code, msg } = response;
  if (code == 200) {
    ElMessage({ message: "导入成功", type: "success" });
    upload.open = false;
    emits("uploadSuccess");
  } else {
    ElMessage({ message: msg, type: "error" });
  }
};
</script>
src/views/basicData/product/index.vue
@@ -11,19 +11,42 @@
            clearable
            prefix-icon="Search"
        />
        <el-button type="primary" @click="openProDia('addOne')" style="margin-left: 10px">新增产品大类</el-button>
        <el-button
          type="primary"
          @click="openProDia('addOne')"
          style="margin-left: 10px"
          >新增产品大类</el-button
        >
      </div>
      <div ref="containerRef">
        <el-tree ref="tree" v-loading="treeLoad" :data="list" @node-click="handleNodeClick"
                 :expand-on-click-node="false" default-expand-all
                 :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;">
        <el-tree
          ref="tree"
          v-loading="treeLoad"
          :data="list"
          @node-click="handleNodeClick"
          :expand-on-click-node="false"
          default-expand-all
          :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
                  type="primary"
                  link
                  @click="openProDia('edit', data)"
                >
                  ç¼–辑
                </el-button>
                <el-button type="primary" link @click="openProDia('add', data)">
@@ -46,18 +69,46 @@
    </div>
    <div class="right">
      <div style="margin-bottom: 10px" v-if="isShowButton">
        <el-button type="primary" @click="openModelDia('add')">新增规格型号</el-button>
        <el-button type="danger" @click="handleDelete" style="margin-left: 10px" plain>删除</el-button>
        <el-button type="primary" @click="openModelDia('add')">
          æ–°å¢žè§„格型号
        </el-button>
        <ImportExcel @uploadSuccess="getModelList" />
        <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>
      <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-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-input
                v-model="form.productName"
                placeholder="请输入产品名称"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -69,19 +120,38 @@
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="modelDia" title="规格型号" width="400px" @close="closeModelDia">
      <el-form :model="modelForm" label-width="140px" label-position="top" :rules="modelRules" ref="modelFormRef">
    <el-dialog
      v-model="modelDia"
      title="规格型号"
      width="400px"
      @close="closeModelDia"
    >
      <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-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-input
                v-model="modelForm.unit"
                placeholder="请输入单位"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -102,278 +172,285 @@
import {
  addOrEditProduct,
  addOrEditProductModel,
  delProduct, delProductModel,
  delProduct,
  delProductModel,
  modelListPage,
  productTreeList
  productTreeList,
} from "@/api/basicData/product.js";
const { proxy } = getCurrentInstance()
const tree = ref(null)
const containerRef = ref(null)
import ImportExcel from "./ImportExcel/index.vue";
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 { proxy } = getCurrentInstance();
const tree = ref(null);
const containerRef = ref(null);
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: "model",
  },
  {
    label: '单位',
    prop: 'unit',
    label: "单位",
    prop: "unit",
  },
  {
    dataType: "action",
    label: "操作",
    align: 'center',
    align: "center",
    operation: [
      {
        name: "编辑",
        type: "text",
        clickFun: (row) => {
          openModelDia('edit', row);
          openModelDia("edit", row);
        },
      },
    ],
  },
])
const tableData = ref([])
const tableLoading = ref(false)
const isShowButton = ref(false)
const total = ref(0)
const selectedRows = ref([])
]);
const tableData = ref([]);
const tableLoading = ref(false);
const isShowButton = ref(false);
const total = ref(0);
const selectedRows = ref([]);
const page = reactive({
  current: 1,
  size: 10,
})
});
const data = reactive({
  form: {
    productName: '',
    productName: "",
  },
  rules: {
    productName: [{ required: true, message: "请输入", trigger: "blur" }],
  },
  modelForm: {
    model: '',
    unit: '',
    model: "",
    unit: "",
  },
  modelRules: {
    model: [{ required: true, message: "请输入", trigger: "blur" }],
    unit: [{ required: true, message: "请输入", trigger: "blur" }],
  }
})
const { form, rules, modelForm, modelRules } = toRefs(data)
  },
});
const { form, rules, modelForm, modelRules } = toRefs(data);
// æŸ¥è¯¢äº§å“æ ‘
const getProductTreeList = () => {
  treeLoad.value = true;
  productTreeList().then(res => {
    list.value = res
  productTreeList()
    .then((res) => {
      list.value = res;
    list.value.forEach((a) => {
      expandedKeys.value.push(a.label);
    });
    treeLoad.value = false;
  }).catch(err => {
    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
  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}
  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 => {
  proxy.$refs.formRef.validate((valid) => {
    if (valid) {
      if (operationType.value === 'add') {
        form.value.parentId = currentId.value
        form.value.id = ''
      } else if (operationType.value === 'addOne') {
        form.value.id = ''
        form.value.parentId = ''
      if (operationType.value === "add") {
        form.value.parentId = currentId.value;
        form.value.id = "";
      } else if (operationType.value === "addOne") {
        form.value.id = "";
        form.value.parentId = "";
      } else {
        form.value.id = currentId.value
        form.value.parentId = ''
        form.value.id = currentId.value;
        form.value.parentId = "";
      }
      addOrEditProduct(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeProDia()
        getProductTreeList()
      })
      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
  let ids = [];
  ids.push(data.id);
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .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) => {
  // åˆ¤æ–­æ˜¯å¦ä¸ºå¶å­èŠ‚ç‚¹
  isShowButton.value = !(val.children && val.children.length > 0);
  // åªæœ‰å¶å­èŠ‚ç‚¹æ‰æ‰§è¡Œä»¥ä¸‹é€»è¾‘
  currentId.value = val.id
  currentParentId.value = val.parentId
  getModelList()
}
  currentId.value = val.id;
  currentParentId.value = val.parentId;
  getModelList();
};
// æäº¤è§„格型号修改
const submitModelForm = () => {
  proxy.$refs.modelFormRef.validate(valid => {
  proxy.$refs.modelFormRef.validate((valid) => {
    if (valid) {
      modelForm.value.productId = currentId.value
      addOrEditProductModel(modelForm.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeModelDia()
        getModelList()
      })
      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
}
  selectedRows.value = selection;
};
// æŸ¥è¯¢è§„格型号
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getModelList()
}
  getModelList();
};
const getModelList = () => {
  tableLoading.value = true
  modelListPage({id: currentId.value,
  tableLoading.value = true;
  modelListPage({
    id: currentId.value,
                       current: page.current,
                       size: page.size,
                      }
            ).then(res => {
    console.log('res',res)
    tableData.value = res.records
    total.value = res.total
    tableLoading.value = false
  })
}
  }).then((res) => {
    console.log("res", res);
    tableData.value = res.records;
    total.value = res.total;
    tableLoading.value = false;
  });
};
// åˆ é™¤è§„格型号
const handleDelete = () => {
  let ids = []
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
    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
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .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
  if (!value) {
    //如果数据为空,则返回true,显示所有的数据项
    return true;
  }
  // æŸ¥è¯¢åˆ—表是否有匹配数据,将值小写,匹配英文数据
  let val = value.toLowerCase()
  return chooseNode(val, data, node) // è°ƒç”¨è¿‡æ»¤äºŒå±‚方法
}
  let val = value.toLowerCase();
  return chooseNode(val, data, node); // è°ƒç”¨è¿‡æ»¤äºŒå±‚方法
};
// è¿‡æ»¤çˆ¶èŠ‚ç‚¹ / å­èŠ‚ç‚¹ (如果输入的参数是父节点且能匹配,则返回该节点以及其下的所有子节点;如果参数是子节点,则返回该节点的父节点。name是中文字符,enName是英文字符.
const chooseNode = (value, data, node) => {
  if (data.label.indexOf(value) !== -1) {
    return true
    return true;
  }
  const level = node.level
  const level = node.level;
  // å¦‚果传入的节点本身就是一级节点就不用校验了
  if (level === 1) {
    return false
    return false;
  }
  // å…ˆå–当前节点的父节点
  let parentData = node.parent
  let parentData = node.parent;
  // éåŽ†å½“å‰èŠ‚ç‚¹çš„çˆ¶èŠ‚ç‚¹
  let index = 0
  let index = 0;
  while (index < level - 1) {
    // å¦‚果匹配到直接返回,此处name值是中文字符,enName是英文字符。判断匹配中英文过滤
    if (parentData.data.label.indexOf(value) !== -1) {
      return true
      return true;
    }
    // å¦åˆ™çš„话再往上一层做匹配
    parentData = parentData.parent
    index++
    parentData = parentData.parent;
    index++;
  }
  // æ²¡åŒ¹é…åˆ°è¿”回false
  return false
}
getProductTreeList()
  return false;
};
getProductTreeList();
</script>
<style scoped>
src/views/basicData/supplierManage/index.vue
@@ -11,74 +11,144 @@
            clearable
            :prefix-icon="Search"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        <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('add')"
          >新增供应商</el-button
        >
        <el-button @click="handleOut">导出</el-button>
        <el-button type="info" plain icon="Upload" @click="handleImport">导入</el-button>
        <el-button type="info" plain icon="Upload" @click="handleImport"
          >导入</el-button
        >
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
      <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" :handleSelectionChange="handleSelectionChange"
                :tableLoading="tableLoading" @pagination="pagination" :total="total"></PIMTable>
      <PIMTable
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :isSelection="true"
        :handleSelectionChange="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
        :total="total"
      ></PIMTable>
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增供应商信息' : '编辑供应商信息'" width="70%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <el-dialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增供应商信息' : '编辑供应商信息'"
      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="supplierName">
              <el-input v-model="form.supplierName" placeholder="请输入" clearable/>
              <el-input
                v-model="form.supplierName"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="纳税人识别号:" prop="taxpayerIdentificationNum">
              <el-input v-model="form.taxpayerIdentificationNum" placeholder="请输入" clearable/>
            <el-form-item
              label="纳税人识别号:"
              prop="taxpayerIdentificationNum"
            >
              <el-input
                v-model="form.taxpayerIdentificationNum"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="公司地址:" prop="companyAddress">
              <el-input v-model="form.companyAddress" placeholder="请输入" clearable/>
              <el-input
                v-model="form.companyAddress"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="公司电话:" prop="companyPhone">
              <el-input v-model="form.companyPhone" placeholder="请输入" clearable/>
              <el-input
                v-model="form.companyPhone"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="开户行:" prop="bankAccountName">
              <el-input v-model="form.bankAccountName" placeholder="请输入" clearable/>
              <el-input
                v-model="form.bankAccountName"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="账号:" prop="bankAccountNum">
              <el-input v-model="form.bankAccountNum" placeholder="请输入" clearable/>
              <el-input
                v-model="form.bankAccountNum"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="联系人:" prop="contactUserName">
              <el-input v-model="form.contactUserName" placeholder="请输入" clearable/>
              <el-input
                v-model="form.contactUserName"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话:" prop="contactUserPhone">
              <el-input v-model="form.contactUserPhone" placeholder="请输入" clearable/>
              <el-input
                v-model="form.contactUserPhone"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="维护人:" prop="maintainUserId">
              <el-select v-model="form.maintainUserId" placeholder="请选择" clearable disabled>
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.userId"/>
              <el-select
                v-model="form.maintainUserId"
                placeholder="请选择"
                clearable
                disabled
              >
                <el-option
                  v-for="item in userList"
                  :key="item.nickName"
                  :label="item.nickName"
                  :value="item.userId"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -107,14 +177,36 @@
    </el-dialog>
    <!-- ä¾›åº”商导入对话框 -->
    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
      <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
    <el-dialog
      :title="upload.title"
      v-model="upload.open"
      width="400px"
      append-to-body
    >
      <el-upload
        ref="uploadRef"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        drag
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip text-center">
            <span>仅允许导入xls、xlsx格式文件。</span>
            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
            <el-link
              type="primary"
              :underline="false"
              style="font-size: 12px; vertical-align: baseline"
              @click="importTemplate"
              >下载模板</el-link
            >
          </div>
        </template>
      </el-upload>
@@ -129,104 +221,111 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref } from "vue";
import {Search} from "@element-plus/icons-vue";
import { delSupplier} from "@/api/basicData/supplierManageFile.js";
import {ElMessageBox } from "element-plus";
import {userListNoPage} from "@/api/system/user.js";
import {addSupplier,getSupplier,listSupplier,updateSupplier} from "@/api/basicData/supplierManageFile.js";
import useUserStore from "@/store/modules/user"
import {
  addSupplier,
  getSupplier,
  listSupplier,
  updateSupplier,
} from "@/api/basicData/supplierManageFile.js";
import useUserStore from "@/store/modules/user";
import {getToken} from "@/utils/auth.js";
const { proxy } = getCurrentInstance()
const userStore = useUserStore()
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const tableColumn = ref([
  {
    label: '供应商名称',
    prop: 'supplierName',
    label: "供应商名称",
    prop: "supplierName",
    width: 250,
  },
  {
    label: '公司地址',
    prop: 'companyAddress',
    label: "公司地址",
    prop: "companyAddress",
    width: 220,
  },
  {
    label: '联系方式',
    prop: 'companyPhone'
    label: "联系方式",
    prop: "companyPhone",
  },
  {
    label: '开户行',
    prop: 'bankAccountName'
    label: "开户行",
    prop: "bankAccountName",
  },
  {
    label: '账号',
    prop: 'bankAccountNum'
    label: "账号",
    prop: "bankAccountNum",
  },
  {
    label: '联系人',
    prop: 'contactUserName',
    label: "联系人",
    prop: "contactUserName",
  },
  {
    label: '联系电话',
    prop: 'contactUserPhone',
    label: "联系电话",
    prop: "contactUserPhone",
  },
  {
    label: '维护人',
    prop: 'maintainUserName',
    label: "维护人",
    prop: "maintainUserName",
  },
  {
    label: '维护时间',
    prop: 'maintainTime',
    label: "维护时间",
    prop: "maintainTime",
  },
  {
    dataType: "action",
    label: "操作",
    align: 'center',
    align: "center",
    operation: [
      {
        name: "编辑",
        type: "text",
        clickFun: (row) => {
          openForm('edit', row);
          openForm("edit", row);
        },
      },
    ],
  },
])
const tableData = ref([])
const selectedRows = ref([])
const userList = ref([])
const tableLoading = ref(false)
]);
const tableData = ref([]);
const selectedRows = ref([]);
const userList = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 10,
})
const total = ref(0)
});
const total = ref(0);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
const operationType = ref("");
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    supplierName: '',
    supplierName: "",
  },
  form: {
    supplierName: '',
    taxpayerIdentificationNum: '',
    companyAddress: '',
    companyPhone: '',
    bankAccountName:'',
    bankAccountNum:'',
    contactUserName: '',
    contactUserPhone: '',
    maintainUserId: '',
    maintainTime: '',
    supplierName: "",
    taxpayerIdentificationNum: "",
    companyAddress: "",
    companyPhone: "",
    bankAccountName: "",
    bankAccountNum: "",
    contactUserName: "",
    contactUserPhone: "",
    maintainUserId: "",
    maintainTime: "",
  },
  rules: {
    supplierName: [{ required: true, message: "请输入", trigger: "blur" }],
    taxpayerIdentificationNum: [{ required: true, message: "请输入", trigger: "blur" }],
    taxpayerIdentificationNum: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    companyAddress: [{ required: true, message: "请输入", trigger: "blur" }],
    companyPhone: [{ required: true, message: "请输入", trigger: "blur" }],
    bankAccountName: [{ required: true, message: "请输入", trigger: "blur" }],
@@ -235,33 +334,33 @@
    contactUserPhone: [{ required: false, message: "请输入", trigger: "blur" }],
    maintainUserId: [{ required: false, message: "请选择", trigger: "change" }],
    maintainTime: [{ required: false, message: "请选择", trigger: "change" }],
  }
})
const { searchForm, form, rules } = toRefs(data)
  },
});
const { searchForm, form, rules } = toRefs(data);
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
/** æäº¤ä¸Šä¼ æ–‡ä»¶ */
function submitFileForm() {
  proxy.$refs["uploadRef"].submit()
  proxy.$refs["uploadRef"].submit();
}
const getList = () => {
  tableLoading.value = true
  listSupplier({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
    tableData.value = res.data.records
    total.value = res.data.total
  })
}
  tableLoading.value = true;
  listSupplier({ ...searchForm.value, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.data.records;
    total.value = res.data.total;
  });
};
const upload = reactive({
  // æ˜¯å¦æ˜¾ç¤ºå¼¹å‡ºå±‚(供应商导入)
  open: false,
@@ -272,122 +371,122 @@
  // è®¾ç½®ä¸Šä¼ çš„请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import"
})
  url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import",
});
/** å¯¼å…¥æŒ‰é’®æ“ä½œ */
function handleImport() {
  upload.title = "供应商导入"
  upload.open = true
  upload.title = "供应商导入";
  upload.open = true;
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
}
  selectedRows.value = selection;
};
// æ‰“开弹框
const openForm = (type, row) => {
  operationType.value = type
  form.value = {}
  form.value.maintainUserId = userStore.id
  operationType.value = type;
  form.value = {};
  form.value.maintainUserId = userStore.id;
  form.value.maintainTime = getCurrentDate();
  userListNoPage().then(res => {
    userList.value = res.data
  })
  if (type === 'edit') {
    getSupplier(row.id).then(res => {
      form.value = {...res.data}
    })
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
  if (type === "edit") {
    getSupplier(row.id).then((res) => {
      form.value = { ...res.data };
    });
  }
  dialogFormVisible.value = true
}
  dialogFormVisible.value = true;
};
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      if (operationType.value === "edit") {
        submitEdit()
        submitEdit();
      } else {
        submitAdd()
        submitAdd();
      }
    }
  })
}
  });
};
// æäº¤æ–°å¢ž
const submitAdd = () => {
  addSupplier(form.value).then(res => {
    proxy.$modal.msgSuccess("提交成功")
    closeDia()
    getList()
  })
}
  addSupplier(form.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
    getList();
  });
};
// æäº¤ä¿®æ”¹
const submitEdit = () => {
  updateSupplier(form.value).then(res => {
    proxy.$modal.msgSuccess("提交成功")
    closeDia()
    getList()
  })
}
  updateSupplier(form.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
    getList();
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm(
      '选中的内容将被导出,是否确认导出?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    proxy.download("/system/supplier/export", {}, '供应商档案.xlsx')
  }).catch(() => {
    proxy.$modal.msg("已取消")
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
}
    .then(() => {
      proxy.download("/system/supplier/export", {}, "供应商档案.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// åˆ é™¤
const handleDelete = () => {
  let ids = []
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm(
      '选中的内容将被删除,是否确认删除?',
      '删除提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    tableLoading.value = true
    delSupplier(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getList()
    }).finally(() => {
      tableLoading.value = false
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .then(() => {
      tableLoading.value = true;
      delSupplier(ids)
        .then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
  })
}
        .finally(() => {
          tableLoading.value = false;
        });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, '0'); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, '0');
  const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
getList()
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>
src/views/procurementManagement/invoiceEntry/index.vue
@@ -3,9 +3,17 @@
    <div class="search_form">
      <div>
        <span class="search_title">采购合同号:</span>
        <el-input v-model="searchForm.purchaseContractNumber" style="width: 240px" placeholder="请输入"
          @change="handleQuery" clearable prefix-icon="Search" />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        <el-input
          v-model="searchForm.purchaseContractNumber"
          style="width: 240px"
          placeholder="请输入"
          @change="handleQuery"
          clearable
          prefix-icon="Search"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
      </div>
      <div>
        <el-button type="primary" @click="handleAdd">新增登记</el-button>
@@ -14,47 +22,123 @@
      </div>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
        :expand-row-keys="expandedRowKeys" :row-key="row => row.id" show-summary :summary-method="summarizeMainTable"
        @expand-change="expandChange" height="calc(100vh - 18.5em)">
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        @selection-change="handleSelectionChange"
        :expand-row-keys="expandedRowKeys"
        :row-key="(row) => row.id"
        show-summary
        :summary-method="summarizeMainTable"
        @expand-change="expandChange"
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column type="expand">
          <template #default="props">
            <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable">
              <el-table-column align="center" label="序号" type="index" width="60" />
            <el-table
              :data="props.row.children"
              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" />
              <el-table-column label="单位" prop="unit" />
              <el-table-column label="数量" prop="quantity" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <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="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" :formatter="formattedNumber" />
              <el-table-column
                label="本次来票金额(元)"
                prop="ticketsAmount"
                :formatter="formattedNumber"
              />
              <el-table-column label="未来票数" prop="futureTickets" />
              <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber" />
              <el-table-column
                label="未来票金额(元)"
                prop="futureTicketsAmount"
                :formatter="formattedNumber"
              />
            </el-table>
          </template>
        </el-table-column>
        <el-table-column align="center" label="序号" type="index" width="60" />
        <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="projectName" show-overflow-tooltip />
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber" />
        <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="projectName"
          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>
          </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" />
      <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="80%"
      @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <el-dialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增来票登记' : '编辑来票登记'"
      width="80%"
      @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="purchaseLedgerNo">
@@ -63,77 +147,190 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="销售合同号:" prop="salesContractNo">
              <el-input v-model="form.salesContractNo" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.salesContractNo"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="供应商名称:" prop="supplierName">
              <el-input v-model="form.supplierName" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.supplierName"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="项目名称:" prop="projectName">
              <el-input v-model="form.projectName" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.projectName"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票号:" prop="invoiceNumber">
              <el-input v-model="form.invoiceNumber" placeholder="请输入" clearable />
              <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-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 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" type="date" clearable />
              <el-date-picker
                style="width: 100%"
                v-model="form.issueDate"
                type="date"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="录入日期:" prop="createTime">
              <el-date-picker
                style="width: 100%"
                v-model="form.createTime"
                type="date"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-form-item label="产品信息:" prop="entryDate">
          </el-form-item>
          <el-form-item label="产品信息:" prop="entryDate"> </el-form-item>
        </el-row>
        <el-table :data="productData" border @selection-change="productSelected" show-summary style="width: 100%" :summary-method="summarizeChildrenTable">
          <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table
          :data="productData"
          border
          @selection-change="productSelected"
          show-summary
          style="width: 100%"
          :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" width="70" />
          <el-table-column label="数量" prop="quantity" width="70"/>
          <el-table-column label="税率(%)" prop="taxRate" width="80" />
          <el-table-column label="含税单价(元)" width="150" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
          <el-table-column label="含税总价(元)" width="150" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
          <el-table-column label="不含税总价(元)" width="150" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
          <el-table-column
            label="含税单价(元)"
            width="150"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="含税总价(元)"
            width="150"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="不含税总价(元)"
            width="150"
            prop="taxExclusiveTotalPrice"
            :formatter="formattedNumber"
          />
          <el-table-column label="本次来票数" prop="ticketsNum" width="170">
            <template #default="scope">
              <el-input-number v-model="scope.row.ticketsNum" placeholder="请选择" :min="0" :step="0.1" clearable style="width: 100%"
                @change="invoiceNumBlur(scope.row)" />
              <el-input-number
                v-model="scope.row.ticketsNum"
                placeholder="请选择"
                :min="0"
                :step="0.1"
                clearable
                style="width: 100%"
                @change="invoiceNumBlur(scope.row)"
              />
            </template>
          </el-table-column>
          <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :min="0" :step="0.1" :formatter="formattedNumber" @change="invoiceAmountBlur"  width="170">
          <el-table-column
            label="本次来票金额(元)"
            prop="ticketsAmount"
            :min="0"
            :step="0.1"
            :formatter="formattedNumber"
            @change="invoiceAmountBlur"
            width="170"
          >
            <template #default="scope">
              <el-input-number v-model="scope.row.ticketsAmount" placeholder="请选择" :min="0" :step="0.1" clearable style="width: 100%"
                               @change="invoiceAmountBlur(scope.row)" />
              <el-input-number
                v-model="scope.row.ticketsAmount"
                placeholder="请选择"
                :min="0"
                :step="0.1"
                clearable
                style="width: 100%"
                @change="invoiceAmountBlur(scope.row)"
              />
            </template>
          </el-table-column>
          <el-table-column label="未来票数" prop="futureTickets"
            : ="(row) => row.futureTickets == null || row.futureTickets === '' ? row.quantity : row.futureTickets">
          <el-table-column
            label="未来票数"
            prop="futureTickets"
            :="
              (row) =>
                row.futureTickets == null || row.futureTickets === ''
                  ? row.quantity
                  : row.futureTickets
            "
          >
          </el-table-column>
          <el-table-column label="未来票金额(元)" prop="futureTicketsAmount"
            :formatter="(row) => (row.futureTicketsAmount !== undefined && row.futureTicketsAmount !== null && row.futureTicketsAmount !== '' ? row.futureTicketsAmount : row.taxExclusiveTotalPrice)">
          <el-table-column
            label="未来票金额(元)"
            prop="futureTicketsAmount"
            :formatter="
              (row) =>
                row.futureTicketsAmount !== undefined &&
                row.futureTicketsAmount !== null &&
                row.futureTicketsAmount !== ''
                  ? row.futureTicketsAmount
                  : row.taxExclusiveTotalPrice
            "
          >
          </el-table-column>
        </el-table>
      </el-form>
@@ -148,27 +345,27 @@
</template>
<script setup>
import pagination from '@/components/PIMTable/Pagination.vue'
import { ref } from 'vue'
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref } from "vue";
import {ElMessageBox } from "element-plus";
import {userListNoPage} from "@/api/system/user.js";
import {productList} from "@/api/procurementManagement/procurementLedger.js";
import useUserStore from '@/store/modules/user';
const userStore = useUserStore()
const { proxy } = getCurrentInstance()
const tableData = ref([])
const productData = ref([])
const selectedRows = ref([])
const productSelectedRows = ref([])
const userList = ref([])
const purchaseLedgerList = ref([])
const tableLoading = ref(false)
import useUserStore from "@/store/modules/user";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const productData = ref([]);
const selectedRows = ref([]);
const productSelectedRows = ref([]);
const userList = ref([]);
const purchaseLedgerList = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
const fileList = ref([])
});
const total = ref(0);
const fileList = ref([]);
import {
  addOrUpdateRegistration,
  delRegistration,
@@ -176,288 +373,305 @@
  getInfo,
  getProduct,
  getPurchaseNoById,
  getRegistrationById
  getRegistrationById,
} from "@/api/procurementManagement/invoiceEntry.js";
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
const operationType = ref("");
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    purchaseContractNumber: '',
    purchaseContractNumber: "",
  },
  form: {
    issueDate:"",// å¼€ç¥¨æ—¥æœŸ
    purchaseLedgerId: '',
    purchaseLedgerNo: '',
    issUerId: '', // å¼€ç¥¨äººid
    issUer: '' ,// å¼€ç¥¨äººå§“名
    purchaseLedgerId: "",
    purchaseLedgerNo: "",
    issUerId: "", // å¼€ç¥¨äººid
    issUer: "", // å¼€ç¥¨äººå§“名
    invoiceNumber:"", // å‘票号
    invoiceAmount:"", // å‘票金额
    createTime: "", // å½•入日期
  },
  rules: {
    invoiceNumber: [{ required: true, message: '请输入发票号' , trigger: 'blur' },{type:"string"}],
    invoiceAmount: [{ required: true, message: '请输入发票金额' , trigger: 'blur'}],
  }
})
const { searchForm, form, rules } = toRefs(data)
    invoiceNumber: [
      { required: true, message: "请输入发票号", trigger: "blur" },
      { type: "string" },
    ],
    invoiceAmount: [
      { required: true, message: "请输入发票金额", trigger: "blur" },
    ],
  },
});
const { searchForm, form, rules } = toRefs(data);
// äº§å“è¡¨å•弹框数据
const productFormVisible = ref(false)
const productOperationType = ref('')
const currentId = ref('')
const productFormVisible = ref(false);
const productOperationType = ref("");
const currentId = ref("");
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  gePurchaseListPage({ ...searchForm.value, ...page }).then(res => {
    tableLoading.value = false
  tableLoading.value = true;
  gePurchaseListPage({ ...searchForm.value, ...page })
    .then((res) => {
      tableLoading.value = false;
    tableData.value = res.records;
    tableData.value.map(item => {
      item.children = []
      tableData.value.map((item) => {
        item.children = [];
      });
      total.value = res.total;
      expandedRowKeys.value = [];
    })
    total.value = res.total
    expandedRowKeys.value = []
  }).catch(() => {
    tableLoading.value = false
  })
}
    .catch(() => {
      tableLoading.value = false;
    });
};
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection.filter(item => item.purchaseContractNumber !== undefined);
}
  selectedRows.value = selection.filter(
    (item) => item.purchaseContractNumber !== undefined
  );
};
const productSelected = (selectedRows) => {
  productSelectedRows.value = selectedRows
}
const expandedRowKeys = ref([])
  productSelectedRows.value = selectedRows;
};
const expandedRowKeys = ref([]);
// å±•开行
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
    try {
      productList({ salesLedgerId: row.id, type: 2 }).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
      productList({ salesLedgerId: row.id, type: 2 }).then((res) => {
        const index = tableData.value.findIndex((item) => item.id === row.id);
        if (index > -1) {
          tableData.value[index].children = res;
        }
        expandedRowKeys.value.push(row.id)
      })
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error)
      console.log(error);
    }
  } else {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
  }
}
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['contractAmount'], {
  return proxy.summarizeTable(param, ["contractAmount"], {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'], {
  return proxy.summarizeTable(
    param,
    [
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
      "ticketsNum",
      "ticketsAmount",
      "futureTickets",
      "futureTicketsAmount",
    ],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
const handleAdd = () => {
  if (selectedRows.value.length !== 1) {
    proxy.$modal.msgWarning('请先选中一条数据');
    proxy.$modal.msgWarning("请先选中一条数据");
    return;
  }
  openForm('add', selectedRows.value[0]);
}
  openForm("add", selectedRows.value[0]);
};
// æ‰“开弹框
const openForm = (type, row) => {
  invoiceNumBlur(row)
  operationType.value = type
  form.value = {}
  productData.value = []
  fileList.value = []
  form.value.issUerId = userStore.id
  form.value.issUer = userStore.name
  form.value.issueDate = getNowFormatDate()
  userListNoPage().then(res => {
    userList.value = res.data
  })
  invoiceNumBlur(row);
  operationType.value = type;
  form.value = {};
  productData.value = [];
  fileList.value = [];
  form.value.issUerId = userStore.id;
  form.value.issUer = userStore.name;
  form.value.issueDate = getNowFormatDate();
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
  // æ–°å¢žæ—¶ä¼ å…¥å½“前行id并查询采购合同号
  if (type === 'add' && row && row.id) {
    form.value.purchaseLedgerId = row.id
    getPurchaseNoById({ id: row.id }).then(res => {
      let result = res.data
      purchaseLedgerList.value = result,
        form.value.purchaseLedgerNo = result.purchaseContractNumber;
  if (type === "add" && row && row.id) {
    form.value.purchaseLedgerId = row.id;
    getPurchaseNoById({ id: row.id }).then((res) => {
      let result = res.data;
      (purchaseLedgerList.value = result),
        (form.value.purchaseLedgerNo = result.purchaseContractNumber);
        form.value.invoiceAmount = result.invoiceAmount;
        form.value.invoiceNumber = result.invoiceNumber;
      setInfo(result.id)
    })
      setInfo(result.id);
    });
  } else {
    getProduct().then(res => {
      purchaseLedgerList.value = res
    })
    getProduct().then((res) => {
      purchaseLedgerList.value = res;
    });
  }
  if (type === 'edit') {
  if (type === "edit") {
    currentId.value = row.id;
    getRegistrationById({ id: row.id }).then(res => {
      form.value = { ...res }
      productData.value = form.value.productData
    getRegistrationById({ id: row.id }).then((res) => {
      form.value = { ...res };
      productData.value = form.value.productData;
      if (form.value.salesLedgerFiles) {
        fileList.value = form.value.salesLedgerFiles
        fileList.value = form.value.salesLedgerFiles;
      } else {
        fileList.value = []
        fileList.value = [];
      }
    })
    });
  }
  dialogFormVisible.value = true
}
  dialogFormVisible.value = true;
};
// é€‰æ‹©é‡‡è´­åˆåŒå·èµ‹å€¼
const setInfo = (value) => {
  getInfo({ id: value }).then(res => {
    let result = res.data
    form.value.salesContractNo = result.salesContractNo
    form.value.projectName = result.projectName
    productData.value = result.productData
    form.value.supplierName = result.supplierName
  })
}
  getInfo({ id: value }).then((res) => {
    let result = res.data;
    form.value.salesContractNo = result.salesContractNo;
    form.value.projectName = result.projectName;
    productData.value = result.productData;
    form.value.supplierName = result.supplierName;
  });
};
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      form.value.productData = proxy.HaveJson(productData.value)
      addOrUpdateRegistration(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeDia()
        getList()
      })
      form.value.productData = proxy.HaveJson(productData.value);
      addOrUpdateRegistration(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        getList();
      });
    }
  })
}
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm(
    '选中的内容将被导出,是否确认导出?',
    '导出', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  }
  ).then(() => {
    proxy.download("/purchase/registration/export", {}, '来票登记.xlsx')
  }).catch(() => {
    proxy.$modal.msg("已取消")
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
}
    .then(() => {
      proxy.download("/purchase/registration/export", {}, "来票登记.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// åˆ é™¤
const handleDelete = () => {
  let ids = []
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm(
    '选中的内容将被删除,是否确认删除?',
    '导出', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  }
  ).then(() => {
    delRegistration(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getList()
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .then(() => {
      delRegistration(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
  })
}
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
//本次来票数失焦操作
const invoiceNumBlur = (row) => {
  if (!row.ticketsNum || row.ticketsNum === '') {
      row.ticketsNum = 0
  if (!row.ticketsNum || row.ticketsNum === "") {
    row.ticketsNum = 0;
  }
  if (Number(row.ticketsNum) > Number(row.tempFutureTickets)) {
    proxy.$modal.msgWarning('本次开票数不得大于未开票数')
    row.ticketsNum = 0
    return
    proxy.$modal.msgWarning("本次开票数不得大于未开票数");
    row.ticketsNum = 0;
    return;
  }
  // è®¡ç®—本次来票金额
  row.ticketsAmount = row.ticketsNum * row.taxInclusiveUnitPrice
  row.ticketsAmount = row.ticketsNum * row.taxInclusiveUnitPrice;
  // è®¡ç®—未来票数
  row.futureTickets = row.tempFutureTickets - row.ticketsNum
  row.futureTickets = row.tempFutureTickets - row.ticketsNum;
  // è®¡ç®—未来票金额
  row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount
  calculateinvoiceAmount()
}
  row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount;
  calculateinvoiceAmount();
};
// æœ¬æ¬¡æ¥ç¥¨é‡‘额失焦操作
const invoiceAmountBlur = (row) => {
  if(!row.ticketsAmount){
    row.ticketsAmount = 0
    row.ticketsAmount = 0;
  }
  // è®¡ç®—是否超过来票总金额
  if(row.ticketsAmount > row.tempFutureTicketsAmount){
    proxy.$modal.msgWarning('本次来票金额不得大于未来票金额')
    row.ticketsAmount = 0
    proxy.$modal.msgWarning("本次来票金额不得大于未来票金额");
    row.ticketsAmount = 0;
  }
  // è®¡ç®—本次来票数
  row.ticketsNum = (row.ticketsAmount / row.taxInclusiveUnitPrice).toFixed(2)
  row.ticketsNum = (row.ticketsAmount / row.taxInclusiveUnitPrice).toFixed(2);
  // è®¡ç®—未来票数
  row.futureTickets = row.tempFutureTickets - row.ticketsNum
  row.futureTickets = row.tempFutureTickets - row.ticketsNum;
  // è®¡ç®—未来票金额
  row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount
  calculateinvoiceAmount()
}
  row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount;
  calculateinvoiceAmount();
};
// èŽ·å–å½“å‰æ—¥æœŸå‡½æ•°
function getNowFormatDate() {
  let date = new Date(),
    year = date.getFullYear(), //获取完整的年份(4位)
    month = date.getMonth() + 1, //获取当前月份(0-11,0代表1月)
    strDate = date.getDate() // èŽ·å–å½“å‰æ—¥(1-31)
  if (month < 10) month = `0${month}` // å¦‚果月份是个位数,在前面补0
  if (strDate < 10) strDate = `0${strDate}` // å¦‚果日是个位数,在前面补0
  return `${year}-${month}-${strDate}`
    strDate = date.getDate(); // èŽ·å–å½“å‰æ—¥(1-31)
  if (month < 10) month = `0${month}`; // å¦‚果月份是个位数,在前面补0
  if (strDate < 10) strDate = `0${strDate}`; // å¦‚果日是个位数,在前面补0
  return `${year}-${month}-${strDate}`;
}
function calculateinvoiceAmount() {
  console.log('productData',productData.value)
  var invoiceAmountTotal = 0
  productData.value.forEach(item => {
  console.log("productData", productData.value);
  var invoiceAmountTotal = 0;
  productData.value.forEach((item) => {
    if(item.ticketsAmount){
      invoiceAmountTotal += item.ticketsAmount
      invoiceAmountTotal += item.ticketsAmount;
    }
  })
  form.value.invoiceAmount = invoiceAmountTotal.toFixed(2)
  });
  form.value.invoiceAmount = invoiceAmountTotal.toFixed(2);
}
getList()
getList();
</script>
<style scoped lang="scss"></style>
src/views/procurementManagement/paymentEntry/index.vue
@@ -1,67 +1,169 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
      <el-form :inline="true" :model="searchForm" style="width: 100%">
        <el-row justify="space-between">
          <el-col :span="20">
            <el-form-item label="供应商名称/合同号">
              <el-input
                v-model="searchForm.supplierNameOrContractNo"
                style="width: 240px"
                placeholder="输入供应商名称/合同号搜索"
                clearable
                prefix-icon="Search"
                @change="handleQuery"
              />
            </el-form-item>
            <el-form-item label="不显示待回款">
              <el-checkbox
                v-model="searchForm.status"
                :label="0"
                @change="handleQuery"
              />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item style="float: right; margin-right: unset">
              <el-button type="primary" @click="openForm('add')">
                æ–°å¢žä»˜æ¬¾
              </el-button>
              <el-button type="danger" plain @click="handleDelete">
                åˆ é™¤
              </el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <!-- <div>
        <span class="search_title">供应商名称/合同号:</span>
        <el-input v-model="searchForm.supplierNameOrContractNo" style="width: 240px" placeholder="输入供应商名称/合同号搜索"
          @change="handleQuery" clearable :prefix-icon="Search" />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        <el-input
          v-model="searchForm.supplierNameOrContractNo"
          style="width: 240px"
          placeholder="输入供应商名称/合同号搜索"
          @change="handleQuery"
          clearable
          :prefix-icon="Search"
        />
        <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="danger" plain @click="handleDelete">删除</el-button>
      </div>
      </div> -->
    </div>
    <div class="table_list">
      <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true"
      <PIMTable
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :isSelection="true"
                :isShowSummary="isShowSummarySon"
                :summaryMethod="summarizeMainTable1"
        :handleSelectionChange="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination"
        :total="total"></PIMTable>
        :handleSelectionChange="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
        :total="total"
      ></PIMTable>
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增付款登记' : '编辑付款登记'" width="60%"
      @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <el-dialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增付款登记' : '编辑付款登记'"
      width="60%"
      @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="purchaseContractNumber">
              <el-input v-model="form.purchaseContractNumber" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.purchaseContractNumber"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="销售合同号:" prop="salesContractNo">
              <el-input v-model="form.salesContractNo" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.salesContractNo"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="供应商名称:" prop="supplierName">
              <el-input v-model="form.supplierName" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.supplierName"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="发票号:" prop="invoiceNumber">
              <el-input v-model="form.invoiceNumber" placeholder="自动填充" clearable disabled />
              <el-input
                v-model="form.invoiceNumber"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票金额(元):" prop="invoiceAmount">
              <el-input type="number" :step="0.01" v-model="form.invoiceAmount" placeholder="自动填充" clearable disabled />
              <el-input
                type="number"
                :step="0.01"
                v-model="form.invoiceAmount"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="本次付款金额:" prop="currentPaymentAmount">
              <el-input type="number" :step="0.01" v-model="form.currentPaymentAmount" placeholder="请输入" clearable />
              <el-input
                type="number"
                :step="0.01"
                v-model="form.currentPaymentAmount"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="付款方式:" prop="paymentMethod">
              <el-select v-model="form.paymentMethod" placeholder="请选择" clearable>
              <el-select
                v-model="form.paymentMethod"
                placeholder="请选择"
                clearable
              >
                <el-option label="电汇" value="电汇" />
                <el-option label="承兑" value="承兑" />
              </el-select>
@@ -69,20 +171,38 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="登记人:" prop="registrant">
              <el-input v-model="form.registrant" placeholder="请输入" clearable disabled />
              <el-input
                v-model="form.registrant"
                placeholder="请输入"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="付款日期:" prop="paymentDate">
              <el-date-picker disabled style="width: 100%" v-model="form.paymentDate" value-format="YYYY-MM-DD"
                format="YYYY-MM-DD" type="date" placeholder="请选择" clearable />
              <el-date-picker
                disabled
                style="width: 100%"
                v-model="form.paymentDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="登记日期:" prop="registrationtDate">
              <el-input v-model="form.registrationtDate" placeholder="请输入" clearable disabled />
              <el-input
                v-model="form.registrationtDate"
                placeholder="请输入"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -98,249 +218,269 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref } from "vue";
import { Search } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user.js";
import {
  byPurchaseId,
  paymentRegistrationAdd, paymentRegistrationDel,
  paymentRegistrationAdd,
  paymentRegistrationDel,
  paymentRegistrationEdit,
  getTicketNo
  getTicketNo,
} from "@/api/procurementManagement/paymentEntry.js";
import {invoiceListPage} from "@/api/procurementManagement/procurementInvoiceLedger.js"
const { proxy } = getCurrentInstance()
import { invoiceListPage } from "@/api/procurementManagement/procurementInvoiceLedger.js";
import useFormData from "@/hooks/useFormData";
const { proxy } = getCurrentInstance();
const tableColumn = ref([
  {
    label: '采购合同号',
    prop: 'purchaseContractNumber',
    label: "采购合同号",
    prop: "purchaseContractNumber",
  },
  {
    label: '销售合同号',
    prop: 'salesContractNo',
    label: "销售合同号",
    prop: "salesContractNo",
  },
  {
    label: '供应商名称',
    prop: 'supplierName',
    label: "供应商名称",
    prop: "supplierName",
  },
  {
    label: '发票号',
    prop: 'invoiceNumber'
    label: "发票号",
    prop: "invoiceNumber",
  },
  {
    label: '发票金额(元)',
    prop: 'invoiceAmount',
    label: "发票金额(元)",
    prop: "invoiceAmount",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
    },
  },
  {
    label: '已付款金额(元)',
    prop: 'paymentAmountTotal',
    label: "已付款金额(元)",
    prop: "paymentAmountTotal",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
    },
  },
  {
    label: '待付款金额(元)',
    prop: 'unPaymentAmountTotal',
    label: "待付款金额(元)",
    prop: "unPaymentAmountTotal",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
  },
])
const tableData = ref([])
const selectedRows = ref([])
const tableLoading = ref(false)
const invoiceNumberList = ref([])
const userStore = useUserStore()
  },
]);
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const invoiceNumberList = ref([]);
const userStore = useUserStore();
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
});
const total = ref(0);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
const operationType = ref("");
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    supplierNameOrContractNo: '',
    supplierNameOrContractNo: "",
    status: false,
  },
  form: {
    purchaseContractNumber:'',
    purchaseLedgerId: '',
    salesContractNo: '',
    supplierName: '',
    invoiceNumber: '',
    invoiceAmount: '',
    taxRate: '',
    currentPaymentAmount: '',
    paymentMethod: '',
    registrant: '',
    registrantId: '',
    paymentDate: '',
    purchaseContractNumber: "",
    purchaseLedgerId: "",
    salesContractNo: "",
    supplierName: "",
    invoiceNumber: "",
    invoiceAmount: "",
    taxRate: "",
    currentPaymentAmount: "",
    paymentMethod: "",
    registrant: "",
    registrantId: "",
    paymentDate: "",
    registrationtDate: "",
  },
  rules: {
    purchaseLedgerId: [{ required: true, message: "请选择", trigger: "change" }],
    currentPaymentAmount: [{ required: true, message: "请输入", trigger: "blur" }],
    purchaseLedgerId: [
      { required: true, message: "请选择", trigger: "change" },
    ],
    currentPaymentAmount: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    paymentMethod: [{ required: true, message: "请选择", trigger: "change" }],
    invoiceNumber: [{ required: true, message: "请选择采购合同号", trigger: "change" }],
  }
})
const { searchForm, form, rules } = toRefs(data)
    invoiceNumber: [
      { required: true, message: "请选择采购合同号", trigger: "change" },
    ],
  },
});
const { form, rules } = toRefs(data);
const { form: searchForm, resetForm } = useFormData(data.searchForm);
const isShowSummarySon = ref(true);
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable1 = (param) => {
  return proxy.summarizeTable(param, ['invoiceAmount', 'paymentAmountTotal', 'unPaymentAmountTotal'], {
  return proxy.summarizeTable(
    param,
    ["invoiceAmount", "paymentAmountTotal", "unPaymentAmountTotal"],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  invoiceListPage({ ...searchForm.value, ...page }).then(res => {
    tableLoading.value = false
    tableData.value = res.records
    total.value = res.total
  })
}
  tableLoading.value = true;
  invoiceListPage({ ...searchForm, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
    total.value = res.total;
  });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
}
  selectedRows.value = selection;
};
// æ‰“开弹框
const openForm = (type, row) => {
  if(selectedRows.value.length !== 1 ) {
    proxy.$message.error("请选择一条发票数据")
    return
    proxy.$message.error("请选择一条发票数据");
    return;
  }
  operationType.value = type
  form.value = {}
  form.value = {...selectedRows.value[0]}
  form.value.ticketRegistrationId = selectedRows.value[0].id
  form.value.id = null
  operationType.value = type;
  form.value = {};
  form.value = { ...selectedRows.value[0] };
  form.value.ticketRegistrationId = selectedRows.value[0].id;
  form.value.id = null;
  // æŸ¥è¯¢é‡‡è´­åˆåŒå·
  form.value.registrationtDate = getCurrentDate();
  form.value.paymentDate = getCurrentDate();
  form.value.registrant = userStore.name
  dialogFormVisible.value = true
}
  form.value.registrant = userStore.name;
  dialogFormVisible.value = true;
};
// é€‰æ‹©å‘票号以后给发票金额赋值
const setInvoiceAmount = (value) => {
  if (value) {
    invoiceNumberList.value.forEach(item => {
    invoiceNumberList.value.forEach((item) => {
      if (item.invoiceNumber === value) {
        form.value.invoiceAmount = item.invoiceAmount
        form.value.ticketRegistrationId = item.id
        form.value.invoiceAmount = item.invoiceAmount;
        form.value.ticketRegistrationId = item.id;
      }
    })
    });
  } else {
    form.value.invoiceAmount = ''
    form.value.invoiceAmount = "";
  }
}
};
// é€‰æ‹©é‡‡è´­åˆåŒå·èµ‹å€¼
const setInfo = (value) => {
  getTicketNo({ id: value }).then((res) => {
    invoiceNumberList.value = res.data
  })
    invoiceNumberList.value = res.data;
  });
  if (value) {
    byPurchaseId(value).then(res => {
      form.value.salesContractNo = res.data.salesContractNo
      form.value.supplierName = res.data.supplierName
      form.value.taxRate = res.data.taxRate
      form.value.supplierId = res.data.supplierId
    })
    byPurchaseId(value).then((res) => {
      form.value.salesContractNo = res.data.salesContractNo;
      form.value.supplierName = res.data.supplierName;
      form.value.taxRate = res.data.taxRate;
      form.value.supplierId = res.data.supplierId;
    });
  } else {
    form.value.salesContractNo = ''
    form.value.supplierName = ''
    form.value.taxRate = ''
    form.value.supplierId = ''
    form.value.salesContractNo = "";
    form.value.supplierName = "";
    form.value.taxRate = "";
    form.value.supplierId = "";
  }
}
};
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      if (operationType.value === "edit") {
        submitEdit()
        submitEdit();
      } else {
        submitAdd()
        submitAdd();
      }
    }
  })
}
  });
};
// æäº¤æ–°å¢ž
const submitAdd = () => {
  paymentRegistrationAdd(form.value).then(res => {
    proxy.$modal.msgSuccess("提交成功")
    closeDia()
    getList()
  })
}
  paymentRegistrationAdd(form.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
    getList();
  });
};
// æäº¤ä¿®æ”¹
const submitEdit = () => {
  paymentRegistrationEdit(form.value).then(res => {
    proxy.$modal.msgSuccess("提交成功")
    closeDia()
    getList()
  })
}
  paymentRegistrationEdit(form.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
    getList();
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// åˆ é™¤
const handleDelete = () => {
  let ids = []
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm(
    '选中的内容将被删除,是否确认删除?',
    '删除提示', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  }
  ).then(() => {
    tableLoading.value = true
    paymentRegistrationDel(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getList()
    }).finally(() => {
      tableLoading.value = false
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .then(() => {
      tableLoading.value = true;
      paymentRegistrationDel(ids)
        .then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
  })
}
        .finally(() => {
          tableLoading.value = false;
        });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, '0'); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, '0');
  const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
getList()
getList();
</script>
<style scoped lang="scss"></style>
<style scoped lang="scss">
.table_list {
  margin-top: unset;
}
</style>
src/views/procurementManagement/paymentLedger/index.vue
@@ -41,24 +41,29 @@
              type="index"
              width="60"
            />
            <el-table-column label="供应商名称" prop="supplierName" />
            <el-table-column
              v-for="(item, index) in tableColumn"
              :key="index"
              :column-key="item.columnKey"
              :filter-method="item.filterHandler"
              :filter-multiple="item.filterMultiple"
              :filtered-value="item.filteredValue"
              :filters="item.filters"
              :fixed="item.fixed"
              :label="item.label"
              :prop="item.prop"
              label="发票金额(元)"
              prop="invoiceAmount"
              show-overflow-tooltip
              :align="item.align"
              :sortable="!!item.sortable"
              :type="item.type"
              :width="item.width"
              :formatter="formattedNumber"
            />
            <el-table-column
              label="付款金额(元)"
              prop="paymentAmount"
              show-overflow-tooltip
              :formatter="formattedNumber"
            />
            <el-table-column
              label="应付金额(元)"
              prop="payableAmount"
              show-overflow-tooltip
            >
              <template #default="{ row, column }">
                <el-text type="danger">
                  {{ formattedNumber(row, column, row.payableAmount) }}
                </el-text>
              </template>
            </el-table-column>
          </el-table>
          <pagination
@@ -80,7 +85,13 @@
            :tableLoading="tableLoadingSon"
            :isShowSummary="isShowSummarySon"
            :summaryMethod="summarizeMainTable1"
          ></PIMTable>
          >
            <template #payableAmountSlot="{ row }">
              <el-text type="danger">
                {{ parseFloat(row.payableAmount).toFixed(2) }}
              </el-text>
            </template>
          </PIMTable>
          <pagination
              v-show="sonTotal > 0"
              :total="sonTotal"
@@ -98,7 +109,10 @@
<script setup>
import { ref, toRefs } from "vue";
import { Search } from "@element-plus/icons-vue";
import { paymentLedgerList,paymentRecordList } from "@/api/procurementManagement/paymentLedger.js";
import {
  paymentLedgerList,
  paymentRecordList,
} from "@/api/procurementManagement/paymentLedger.js";
import Pagination from "../../../components/PIMTable/Pagination.vue";
const tableColumn = ref([
@@ -138,10 +152,10 @@
const sonTotal = ref(0);
const isShowSummary = ref(true);
const { searchForm } = toRefs(data);
const currentSupplierId = ref('')
const currentSupplierId = ref("");
const rowClick = (row) => {
  currentSupplierId.value = row.supplierId;
  getPaymenRecordtList(row.supplierId)
  getPaymenRecordtList(row.supplierId);
};
// å­æ¨¡å—
const tableColumnSon = ref([
@@ -154,21 +168,19 @@
    prop: "invoiceAmount",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
    },
  },
  {
    label: "付款金额(元)",
    prop: "currentPaymentAmount",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
    },
  },
  {
    label: "应付金额(元)",
    prop: "payableAmount",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
    dataType: "slot",
    slot: "payableAmountSlot",
  },
]);
const tableDataSon = ref([]);
@@ -177,27 +189,38 @@
const isShowSummarySon = ref(true);
const detailPageNum = ref(1);
const detailPageSize = ref(10);
const { proxy } = getCurrentInstance()
const { proxy } = getCurrentInstance();
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['invoiceAmount', 'paymentAmount', 'payableAmount'], {
  return proxy.summarizeTable(
    param,
    ["invoiceAmount", "paymentAmount", "payableAmount"],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable1 = (param) => {
  let summarizeTable = proxy.summarizeTable(param, ['invoiceAmount', 'currentPaymentAmount'], {
  let summarizeTable = proxy.summarizeTable(
    param,
    ["invoiceAmount", "currentPaymentAmount"],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
  if(originalTableDataSon.value.length > 0) {
    summarizeTable[summarizeTable.length -1] = originalTableDataSon.value[originalTableDataSon.value.length - 1].payableAmount.toFixed(2)
  }else {
    summarizeTable[summarizeTable.length -1] = 0.00
  }
  return summarizeTable
  );
  if (originalTableDataSon.value.length > 0) {
    summarizeTable[summarizeTable.length - 1] =
      originalTableDataSon.value[
        originalTableDataSon.value.length - 1
      ].payableAmount.toFixed(2);
  } else {
    summarizeTable[summarizeTable.length - 1] = 0.0;
  }
  return summarizeTable;
};
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
@@ -223,23 +246,24 @@
    total.value = result.total || 0;
    if(tableData.value.length > 0) {
      getPaymenRecordtList(tableData.value[0].supplierId);
      currentSupplierId.value = tableData.value[0].supplierId
      currentSupplierId.value = tableData.value[0].supplierId;
    }
  });
};
const getPaymenRecordtList = (supplierId) => {
  tableLoadingSon.value = true;
  paymentRecordList(supplierId).then(res => {
  paymentRecordList(supplierId)
    .then((res) => {
    tableLoadingSon.value = false;
    tableDataSon.value = res.data
      tableDataSon.value = res.data;
    handlePagination({ page: 1, limit: sonPage.size });
    sonTotal.value = res.data.length
  }).catch((e) => {
    tableLoadingSon.value = false;
      sonTotal.value = res.data.length;
  })
}
    .catch((e) => {
      tableLoadingSon.value = false;
    });
};
const handlePagination = ({ page, limit }) => {
  sonPage.current = page;
  sonPage.size = limit;
@@ -248,24 +272,23 @@
  const end = start + limit;
  originalTableDataSon.value = tableDataSon.value.slice(start, end);
}
};
const sonPaginationSearch = (pagination) => {
  // æŽ¥æ”¶åˆ†é¡µå™¨å‚æ•° { page, limit }
  handlePagination(pagination);
}
};
const formattedNumber = (row, column, cellValue) => {
  if (column.property !== 'supplierName') {
  if (column.property !== "supplierName") {
    return parseFloat(cellValue).toFixed(2);
  } else {
    return cellValue
    return cellValue;
  }
};
getList();
</script>
<style scoped lang="scss">
.el-pagination {
  width: 100%;
  height: 55px;
src/views/procurementManagement/procurementInvoiceLedger/index.vue
@@ -26,171 +26,284 @@
            v-model="searchForm.issueDate"
            value-format="YYYY-MM-DD"
            format="YYYY-MM-DD"
            type="date"
            placeholder="请选择"
          type="daterange"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
            clearable
          @change="changeDateRange"
          @clear="clearRange"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
      </div>
      <div>
        <el-button @click="handleOut">导出</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading"
        :expand-row-keys="expandedRowKeys" :row-key="row => row.id" show-summary :summary-method="summarizeMainTable"
        @expand-change="expandChange" height="calc(100vh - 18.5em)">
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        :expand-row-keys="expandedRowKeys"
        :row-key="(row) => row.id"
        show-summary
        :summary-method="summarizeMainTable"
        @expand-change="expandChange"
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center"  label="序号" type="index" width="55" />
        <el-table-column type="expand">
          <template #default="props">
            <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable">
              <el-table-column align="center" label="序号" type="index" width="60" />
            <el-table
              :data="props.row.children"
              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" />
              <el-table-column label="单位" prop="unit" />
              <el-table-column label="数量" prop="quantity" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <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="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" :formatter="formattedNumber" />
              <el-table-column
                label="本次来票金额(元)"
                prop="ticketsAmount"
                :formatter="formattedNumber"
              />
              <el-table-column label="未来票数" prop="futureTickets" />
              <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber" />
              <el-table-column
                label="未来票金额(元)"
                prop="futureTicketsAmount"
                :formatter="formattedNumber"
              />
            </el-table>
          </template>
        </el-table-column>
        <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="invoiceNumber" show-overflow-tooltip />
        <el-table-column label="合同金额(元)" prop="invoiceAmount" show-overflow-tooltip :formatter="formattedNumber" />
        <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="invoiceNumber"
          show-overflow-tooltip
        />
        <el-table-column
          label="合同金额(元)"
          prop="invoiceAmount"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column label="开票人" prop="issUer" show-overflow-tooltip />
        <el-table-column label="开票日期" prop="issueDate" show-overflow-tooltip />
        <el-table-column
          label="开票日期"
          prop="issueDate"
          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" />
      <pagination
        v-show="total > 0"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="page.current"
        :limit="page.size"
        @pagination="paginationChange"
      />
    </div>
  </div>
</template>
<script setup>
import pagination from '@/components/PIMTable/Pagination.vue'
import { ref } from 'vue'
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref } from "vue";
import {Search} from "@element-plus/icons-vue";
import {ElMessageBox } from "element-plus";
import {productRecordList} from "@/api/procurementManagement/procurementInvoiceLedger.js";
import {
  invoiceListPage
} from "@/api/procurementManagement/procurementInvoiceLedger.js";
const { proxy } = getCurrentInstance()
const tableData = ref([])
const tableLoading = ref(false)
import { invoiceListPage } from "@/api/procurementManagement/procurementInvoiceLedger.js";
import dayjs from "dayjs";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
});
const total = ref(0);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
  const data = reactive({
  searchForm: {
    purchaseContractNumber: '',
    supplierName: '',
    issueDate:''
    purchaseContractNumber: "",
    supplierName: "",
    issueDate: [
      dayjs().startOf("month").format("YYYY-MM-DD"),
      dayjs().endOf("month").format("YYYY-MM-DD"),
    ],
    issueDateStart: dayjs().startOf("month").format("YYYY-MM-DD"),
    issueDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"),
  },
  form: {
    issueDate:"",// å¼€ç¥¨æ—¥æœŸ
    purchaseLedgerId: '',
    purchaseLedgerNo: '',
    issUerId: '', // å¼€ç¥¨äººid
    issUer: '' ,// å¼€ç¥¨äººå§“名
    purchaseLedgerId: "",
    purchaseLedgerNo: "",
    issUerId: "", // å¼€ç¥¨äººid
    issUer: "", // å¼€ç¥¨äººå§“名
  },
  rules: {
    purchaseLedgerId: [{ required: true, message: "请选择", trigger: "change" }],
  }
})
const { searchForm } = toRefs(data)
    purchaseLedgerId: [
      { required: true, message: "请选择", trigger: "change" },
    ],
  },
});
const { searchForm } = toRefs(data);
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  invoiceListPage({ ...searchForm.value, ...page }).then(res => {
    tableLoading.value = false
    tableData.value = res.records
    tableData.value.map(item => {
      item.children = []
  tableLoading.value = true;
  const { issueDate, ...rest } = searchForm.value;
  invoiceListPage({ ...rest, ...page })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.records;
      tableData.value.map((item) => {
        item.children = [];
      });
      total.value = res.total;
      expandedRowKeys.value = [];
    })
    total.value = res.total
    expandedRowKeys.value = []
  }).catch(() => {
    tableLoading.value = false
  })
}
    .catch(() => {
      tableLoading.value = false;
    });
};
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const expandedRowKeys = ref([])
const expandedRowKeys = ref([]);
// å±•开行
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
    try {
      productRecordList({ id: row.id }).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
      productRecordList({ id: row.id }).then((res) => {
        const index = tableData.value.findIndex((item) => item.id === row.id);
        if (index > -1) {
          tableData.value[index].children = res;
        }
        expandedRowKeys.value.push(row.id)
      })
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error)
      console.log(error);
    }
  } else {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
  }
}
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['invoiceAmount'], {
  return proxy.summarizeTable(param, ["invoiceAmount"], {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'], {
  return proxy.summarizeTable(
    param,
    [
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
      "ticketsNum",
      "ticketsAmount",
      "futureTickets",
      "futureTicketsAmount",
    ],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm(
    '选中的内容将被导出,是否确认导出?',
    '导出', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  }
  ).then(() => {
    proxy.download("/purchase/registration/export", {}, '来票登记.xlsx')
  }).catch(() => {
    proxy.$modal.msg("已取消")
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/purchase/registration/export", {}, "来票登记.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
const changeDateRange = (date) => {
  if (date) {
    searchForm.receiptPaymentDateStart = date[0];
    searchForm.receiptPaymentDateEnd = date[1];
    getList();
}
getList()
};
const clearRange = () => {
  searchForm.value.issueDate = [];
  searchForm.value.issueDateStart = undefined;
  searchForm.value.issueDateEnd = undefined;
  getList();
};
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss"></style>
src/views/procurementManagement/procurementLedger/index.vue
@@ -11,7 +11,9 @@
            clearable
            prefix-icon="Search"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增台账</el-button>
@@ -20,61 +22,156 @@
      </div>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading"
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
                @selection-change="handleSelectionChange"
                :expand-row-keys="expandedRowKeys"
                :row-key="row => row.id"
        :row-key="(row) => row.id"
                show-summary
                :summary-method="summarizeMainTable"
                @expand-change="expandChange"
                height="calc(100vh - 18.5em)">
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column type="expand">
          <template #default="props">
            <el-table :data="props.row.children" border
            <el-table
              :data="props.row.children"
              border
                      show-summary
                      :summary-method="summarizeChildrenTable">
              <el-table-column align="center" label="序号" type="index" width="60" />
              :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" :formatter="formattedNumber" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
              <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>
        <el-table-column align="center" label="序号" type="index" width="60" />
        <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="projectName" 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">
        <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="projectName"
          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"
        >
          <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('edit', 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" />
      <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-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <el-dialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增采购台账页面' : '编辑采购台账页面'"
      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="purchaseContractNumber">
              <el-input v-model="form.purchaseContractNumber" placeholder="请输入" clearable/>
              <el-input
                v-model="form.purchaseContractNumber"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="销售合同号:" prop="salesLedgerId">
              <el-select v-model="form.salesLedgerId" placeholder="请选择" clearable @change="salesLedgerChange">
                <el-option v-for="item in salesContractList" :key="item.id" :label="item.salesContractNo" :value="item.id"/>
              <el-select
                v-model="form.salesLedgerId"
                placeholder="请选择"
                clearable
                @change="salesLedgerChange"
              >
                <el-option
                  v-for="item in salesContractList"
                  :key="item.id"
                  :label="item.salesContractNo"
                  :value="item.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -82,22 +179,45 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="供应商名称:" prop="supplierId">
              <el-select v-model="form.supplierId" placeholder="请选择" clearable>
                <el-option v-for="item in supplierList" :key="item.id" :label="item.supplierName" :value="item.id"/>
              <el-select
                v-model="form.supplierId"
                placeholder="请选择"
                clearable
              >
                <el-option
                  v-for="item in supplierList"
                  :key="item.id"
                  :label="item.supplierName"
                  :value="item.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="项目名称:" prop="projectName">
              <el-input v-model="form.projectName" placeholder="请输入" clearable/>
              <el-input
                v-model="form.projectName"
                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"/>
              <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"
                />
              </el-select>
            </el-form-item>
          </el-col>
@@ -118,31 +238,78 @@
        </el-row>
        <el-row>
          <el-form-item label="产品信息:" prop="entryDate">
            <el-button type="primary" @click="openProductForm('add')">添加</el-button>
            <el-button plain type="danger" @click="deleteProduct">删除</el-button>
            <el-button type="primary" @click="openProductForm('add')"
              >添加</el-button
            >
            <el-button plain type="danger" @click="deleteProduct"
              >删除</el-button
            >
          </el-form-item>
        </el-row>
        <el-table :data="productData" border @selection-change="productSelected" show-summary :summary-method="summarizeProTable">
        <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
            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" width="70" />
          <el-table-column label="数量" prop="quantity" width="70" />
          <el-table-column label="税率(%)" prop="taxRate" width="70" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="150"/>
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150"/>
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150"/>
          <el-table-column fixed="right" label="操作" min-width="60" align="center">
          <el-table-column
            label="含税单价(元)"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
            width="150"
          />
          <el-table-column
            label="含税总价(元)"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
            width="150"
          />
          <el-table-column
            label="不含税总价(元)"
            prop="taxExclusiveTotalPrice"
            :formatter="formattedNumber"
            width="150"
          />
          <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, scope.$index);">编辑</el-button>
              <el-button
                link
                type="primary"
                size="small"
                @click="openProductForm('edit', scope.row, scope.$index)"
                >编辑</el-button
              >
            </template>
          </el-table-column>
        </el-table>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="备注·:" prop="remark">
              <el-input v-model="form.remark" placeholder="请输入" clearable type="textarea" :rows="2"/>
              <el-input
                v-model="form.remark"
                placeholder="请输入"
                clearable
                type="textarea"
                :rows="2"
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -164,7 +331,8 @@
                <el-button type="primary">上传</el-button>
                <template #tip>
                  <div class="el-upload__tip">
                    æ–‡ä»¶æ ¼å¼æ”¯æŒ doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z
                    æ–‡ä»¶æ ¼å¼æ”¯æŒ
                    doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z
                  </div>
                </template>
              </el-upload>
@@ -179,14 +347,26 @@
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%" @close="closeProductDia">
      <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
    <el-dialog
      v-model="productFormVisible"
      :title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
      width="40%"
      @close="closeProductDia"
    >
      <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="productId">
              <el-tree-select
                  v-model="productForm.productId"
                  placeholder="请选择" clearable
                placeholder="请选择"
                clearable
                  check-strictly
                  @change="getModels"
                  :data="productOptions"
@@ -199,8 +379,18 @@
        <el-row :gutter="30">
          <el-col :span="24">
            <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
                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>
@@ -208,24 +398,45 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="单位:" prop="unit">
              <el-input v-model="productForm.unit" placeholder="请输入" clearable/>
              <el-input
                v-model="productForm.unit"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input v-model="productForm.quantity" placeholder="请输入" clearable @change="mathNum"/>
              <el-input
                v-model="productForm.quantity"
                placeholder="请输入"
                clearable
                @change="mathNum"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
              <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="2" :step="0.1" clearable style="width: 100%" @change="mathNum"/>
              <el-input-number
                v-model="productForm.taxInclusiveUnitPrice"
                :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="taxRate">
              <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="mathNum">
              <el-select
                v-model="productForm.taxRate"
                placeholder="请选择"
                clearable
                @change="mathNum"
              >
                <el-option label="1" value="1"/>
                <el-option label="6" value="6"/>
                <el-option label="13" value="13"/>
@@ -236,11 +447,21 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
              <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" clearable style="width: 100%" disabled/>
              <el-input-number
                v-model="productForm.taxInclusiveTotalPrice"
                :precision="2"
                :step="0.1"
                clearable
                style="width: 100%"
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice">
            <el-form-item
              label="不含税总价(元):"
              prop="taxExclusiveTotalPrice"
            >
              <el-input v-model="productForm.taxExclusiveTotalPrice" disabled/>
            </el-form-item>
          </el-col>
@@ -248,7 +469,11 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票类型:" prop="invoiceType">
              <el-select v-model="productForm.invoiceType" placeholder="请选择" clearable>
              <el-select
                v-model="productForm.invoiceType"
                placeholder="请选择"
                clearable
              >
                <el-option label="增普票" value="增普票"/>
                <el-option label="增专票" value="增专票"/>
              </el-select>
@@ -267,106 +492,120 @@
</template>
<script setup>
import { getToken } from "@/utils/auth"
import pagination from '@/components/PIMTable/Pagination.vue'
import { ref } from 'vue'
import { getToken } from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref, onMounted } from "vue";
import {Search} from "@element-plus/icons-vue";
import {ElMessageBox } from "element-plus";
import {userListNoPage} from "@/api/system/user.js";
import {
  getSalesLedgerWithProducts, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile
  getSalesLedgerWithProducts,
  addOrUpdateSalesLedgerProduct,
  delProduct,
  delLedgerFile,
  getProductInfoByContractNo,
} from "@/api/salesManagement/salesLedger.js";
import {
  addOrEditPurchase,
  delPurchase,
  getSalesNo,
  purchaseListPage,
  productList, getPurchaseById, getOptions
  productList,
  getPurchaseById,
  getOptions,
} from "@/api/procurementManagement/procurementLedger.js";
const { proxy } = getCurrentInstance()
const tableData = ref([])
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)
const { proxy } = getCurrentInstance();
const tableData = ref([]);
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);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
const fileList = ref([])
import useUserStore from "@/store/modules/user"
});
const total = ref(0);
const fileList = ref([]);
import useUserStore from "@/store/modules/user";
import {modelList, productTreeList} from "@/api/basicData/product.js";
const userStore = useUserStore()
const userStore = useUserStore();
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
const operationType = ref("");
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    purchaseContractNumber: '',
    purchaseContractNumber: "",
  },
  form: {
    purchaseContractNumber: '',
    salesLedgerId: '',
    projectName: '',
    recorderId: '',
    entryDate: '',
    purchaseContractNumber: "",
    salesLedgerId: "",
    projectName: "",
    recorderId: "",
    entryDate: "",
    productData: [],
    supplierName: '',
    supplierId: '',
    supplierName: "",
    supplierId: "",
  },
  rules: {
    purchaseContractNumber: [{ required: true, message: "请输入", trigger: "blur" }],
    purchaseContractNumber: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    projectName: [{ required: true, message: "请输入", trigger: "blur" }],
    supplierId: [{ required: true, message: "请输入", trigger: "blur" }],
  }
})
const { searchForm, form, rules } = toRefs(data)
  },
});
const { searchForm, form, rules } = toRefs(data);
// äº§å“è¡¨å•弹框数据
const productFormVisible = ref(false)
const productOperationType = ref('')
const productOperationIndex = ref('')
const currentId = ref('')
const productFormVisible = ref(false);
const productOperationType = ref("");
const productOperationIndex = ref("");
const currentId = ref("");
const productFormData = reactive({
  productForm: {
    productId: '',
    productCategory: '',
    productModelId: '',
    specificationModel: '',
    unit: '',
    quantity: '',
    taxInclusiveUnitPrice: '',
    taxRate: '',
    taxInclusiveTotalPrice: '',
    taxExclusiveTotalPrice: '',
    invoiceType: '',
    productId: "",
    productCategory: "",
    productModelId: "",
    specificationModel: "",
    unit: "",
    quantity: "",
    taxInclusiveUnitPrice: "",
    taxRate: "",
    taxInclusiveTotalPrice: "",
    taxExclusiveTotalPrice: "",
    invoiceType: "",
  },
  productRules: {
    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" }],
    taxInclusiveUnitPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxRate: [{ required: true, message: "请选择", trigger: "change" }],
    taxInclusiveTotalPrice: [{ required: true, message: "请输入", trigger: "blur" }],
    taxExclusiveTotalPrice: [{ required: true, message: "请输入", trigger: "blur" }],
    taxInclusiveTotalPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxExclusiveTotalPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
  }
})
const { productForm, productRules } = toRefs(productFormData)
  },
});
const { productForm, productRules } = toRefs(productFormData);
const upload = reactive({
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
  // è®¾ç½®ä¸Šä¼ çš„请求头部
  headers: { Authorization: "Bearer " + getToken() },
})
});
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
@@ -374,200 +613,218 @@
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'], {
  return proxy.summarizeTable(
    param,
    [
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
      "ticketsNum",
      "ticketsAmount",
      "futureTickets",
      "futureTicketsAmount",
    ],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  purchaseListPage({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
    tableData.value = res.records
    tableData.value.map(item => {
      item.children = []
  tableLoading.value = true;
  purchaseListPage({ ...searchForm.value, ...page })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.records;
      tableData.value.map((item) => {
        item.children = [];
      });
      total.value = res.total;
      expandedRowKeys.value = [];
    })
    total.value = res.total
    expandedRowKeys.value = []
  }).catch(() => {
    tableLoading.value = false
  })
}
    .catch(() => {
      tableLoading.value = false;
    });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
}
  selectedRows.value = selection;
};
const productSelected = (selectedRows) => {
  productSelectedRows.value = selectedRows
}
const expandedRowKeys = ref([])
  productSelectedRows.value = selectedRows;
};
const expandedRowKeys = ref([]);
// å±•开行
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
    try {
      productList({salesLedgerId: row.id, type: 2}).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
      productList({ salesLedgerId: row.id, type: 2 }).then((res) => {
        const index = tableData.value.findIndex((item) => item.id === row.id);
        if (index > -1) {
          tableData.value[index].children = res;
        }
        expandedRowKeys.value.push(row.id)
      })
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error)
      console.log(error);
    }
  } else {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
  }
}
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['contractAmount']);
  return proxy.summarizeTable(param, ["contractAmount"]);
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeProTable = (param) => {
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice']);
  return proxy.summarizeTable(param, [
    "taxInclusiveUnitPrice",
    "taxInclusiveTotalPrice",
    "taxExclusiveTotalPrice",
  ]);
};
// æ‰“开弹框
const openForm = (type, row) => {
  operationType.value = type
  form.value = {}
  productData.value = []
  fileList.value = []
  userListNoPage().then(res => {
    userList.value = res.data
  })
  getSalesNo().then(res => {
    salesContractList.value = res
  })
  getOptions().then(res => {
    supplierList.value = res.data
  })
  form.value.recorderId = userStore.id
  operationType.value = type;
  form.value = {};
  productData.value = [];
  fileList.value = [];
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
  getSalesNo().then((res) => {
    salesContractList.value = res;
  });
  getOptions().then((res) => {
    supplierList.value = res.data;
  });
  form.value.recorderId = userStore.id;
  form.value.entryDate = getCurrentDate();
  if (type === 'edit') {
  if (type === "edit") {
    currentId.value = row.id;
    getPurchaseById({id: row.id, type: 2}).then(res => {
      form.value = {...res}
      productData.value = form.value.productData
    getPurchaseById({ id: row.id, type: 2 }).then((res) => {
      form.value = { ...res };
      productData.value = form.value.productData;
      if(form.value.salesLedgerFiles) {
        fileList.value = form.value.salesLedgerFiles
        fileList.value = form.value.salesLedgerFiles;
      } else {
        fileList.value = []
        fileList.value = [];
      }
    })
    });
  }
  dialogFormVisible.value = true
}
  dialogFormVisible.value = true;
};
// ä¸Šä¼ å‰æ ¡æ£€
function handleBeforeUpload(file) {
  // æ ¡æ£€æ–‡ä»¶å¤§å°
  if (file.size > 1024 * 1024 * 10) {
    proxy.$modal.msgError('上传文件大小不能超过10MB!')
    return false
    proxy.$modal.msgError("上传文件大小不能超过10MB!");
    return false;
  }
  proxy.$modal.loading("正在上传文件,请稍候...")
  return true
  proxy.$modal.loading("正在上传文件,请稍候...");
  return true;
}
// ä¸Šä¼ å¤±è´¥
function handleUploadError(err) {
  proxy.$modal.msgError("上传文件失败")
  proxy.$modal.closeLoading()
  proxy.$modal.msgError("上传文件失败");
  proxy.$modal.closeLoading();
}
// ä¸Šä¼ æˆåŠŸå›žè°ƒ
function handleUploadSuccess(res, file, uploadFiles) {
  proxy.$modal.closeLoading()
  proxy.$modal.closeLoading();
  if (res.code === 200) {
    file.tempId = res.data.tempId
    proxy.$modal.msgSuccess("上传成功")
    file.tempId = res.data.tempId;
    proxy.$modal.msgSuccess("上传成功");
  } else {
    proxy.$modal.msgError(res.msg)
    proxy.$refs.fileUpload.handleRemove(file)
    proxy.$modal.msgError(res.msg);
    proxy.$refs.fileUpload.handleRemove(file);
  }
}
// ç§»é™¤æ–‡ä»¶
function handleRemove (file) {
  console.log('handleRemove', file.id)
  if (operationType.value === 'edit') {
    let ids = []
    ids.push(file.id)
    delLedgerFile(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
    })
  console.log("handleRemove", file.id);
  if (operationType.value === "edit") {
    let ids = [];
    ids.push(file.id);
    delLedgerFile(ids).then((res) => {
      proxy.$modal.msgSuccess("删除成功");
    });
  }
}
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      if (productData.value.length > 0) {
        form.value.productData = proxy.HaveJson(productData.value)
        form.value.productData = proxy.HaveJson(productData.value);
      } else {
        proxy.$modal.msgWarning('请添加产品信息')
        return
        proxy.$modal.msgWarning("请添加产品信息");
        return;
      }
      let tempFileIds = []
      let tempFileIds = [];
      if (fileList.value.length > 0) {
        tempFileIds = fileList.value.map(item => item.tempId)
        tempFileIds = fileList.value.map((item) => item.tempId);
      }
      form.value.tempFileIds = tempFileIds
      form.value.type = 2
      addOrEditPurchase(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeDia()
        getList()
      })
      form.value.tempFileIds = tempFileIds;
      form.value.type = 2;
      addOrEditPurchase(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        getList();
      });
    }
  })
}
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// æ‰“开产品弹框
const openProductForm = (type, row, index) => {
  productOperationType.value = type
  productOperationIndex.value = index
  productForm.value = {}
  proxy.resetForm("productFormRef")
  if (type === 'edit') {
    productForm.value = {...row}
  productOperationType.value = type;
  productOperationIndex.value = index;
  productForm.value = {};
  proxy.resetForm("productFormRef");
  if (type === "edit") {
    productForm.value = { ...row };
  }
  productFormVisible.value = true
  getProductOptions()
}
  productFormVisible.value = true;
  getProductOptions();
};
const getProductOptions = () => {
  productTreeList().then(res => {
    productOptions.value = convertIdToValue(res)
  })
}
  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
  })
}
  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);
  const index = modelOptions.value.findIndex((item) => item.id === value);
  if (index !== -1) {
    productForm.value.specificationModel = modelOptions.value[index].model;
    productForm.value.unit = modelOptions.value[index].unit;
  } else {
    productForm.value.specificationModel = null;
    productForm.value.unit = null
    productForm.value.unit = null;
  }
}
};
const findNodeById = (nodes, productId) => {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i].value === productId) {
@@ -583,11 +840,11 @@
  return null; // æ²¡æœ‰æ‰¾åˆ°èŠ‚ç‚¹ï¼Œè¿”å›žnull
};
function convertIdToValue(data) {
  return data.map(item => {
  return data.map((item) => {
    const { id, children, ...rest } = item;
    const newItem = {
      ...rest,
      value: id // å°† id æ”¹ä¸º value
      value: id, // å°† id æ”¹ä¸º value
    };
    if (children && children.length > 0) {
      newItem.children = convertIdToValue(children);
@@ -598,152 +855,173 @@
}
// æäº¤äº§å“è¡¨å•
const submitProduct = () => {
  proxy.$refs["productFormRef"].validate(valid => {
  proxy.$refs["productFormRef"].validate((valid) => {
    if (valid) {
      if (operationType.value === "edit") {
        submitProductEdit()
        submitProductEdit();
      } else {
        if (productOperationType.value === 'add') {
          productData.value.push({...productForm.value})
          console.log('productData.value---', productData.value)
        if (productOperationType.value === "add") {
          productData.value.push({ ...productForm.value });
          console.log("productData.value---", productData.value);
        } else {
          productData.value[productOperationIndex.value] = {...productForm.value}
          productData.value[productOperationIndex.value] = {
            ...productForm.value,
          };
        }
        closeProductDia()
        closeProductDia();
      }
    }
  })
}
  });
};
const submitProductEdit = () => {
  productForm.value.salesLedgerId = currentId.value
  productForm.value.type = 2
  addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
    proxy.$modal.msgSuccess("提交成功")
    closeProductDia()
    getPurchaseById({id: currentId.value, type: 2}).then(res => {
      productData.value = res.productData
    })
  })
}
  productForm.value.salesLedgerId = currentId.value;
  productForm.value.type = 2;
  addOrUpdateSalesLedgerProduct(productForm.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeProductDia();
    getPurchaseById({ id: currentId.value, type: 2 }).then((res) => {
      productData.value = res.productData;
    });
  });
};
// åˆ é™¤äº§å“
const deleteProduct = () => {
  if (productSelectedRows.value.length === 0) {
    proxy.$modal.msgWarning('请选择数据')
    return
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  if (operationType.value === 'add') {
    productSelectedRows.value.forEach(selectedRow => {
      const index = productData.value.findIndex(product => product.id === selectedRow.id);
  if (operationType.value === "add") {
    productSelectedRows.value.forEach((selectedRow) => {
      const index = productData.value.findIndex(
        (product) => product.id === selectedRow.id
      );
      if (index !== -1) {
        productData.value.splice(index, 1);
      }
    });
  } else {
    let ids = []
    let ids = [];
    if (productSelectedRows.value.length > 0) {
      ids = productSelectedRows.value.map(item => item.id);
      ids = productSelectedRows.value.map((item) => item.id);
    }
    ElMessageBox.confirm(
        '选中的内容将被删除,是否确认删除?',
        '导出', {
          confirmButtonText: '确认',
          cancelButtonText: '取消',
          type: 'warning',
        }
    ).then(() => {
      delProduct(ids).then(res => {
        proxy.$modal.msgSuccess("删除成功")
        closeProductDia()
        getSalesLedgerWithProducts({id: currentId.value, type: 2}).then(res => {
          productData.value = res.productData
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
        })
      })
    }).catch(() => {
      proxy.$modal.msg("已取消")
    })
      .then(() => {
        delProduct(ids).then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          closeProductDia();
          getSalesLedgerWithProducts({ id: currentId.value, type: 2 }).then(
            (res) => {
              productData.value = res.productData;
  }
          );
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
}
};
// å…³é—­äº§å“å¼¹æ¡†
const closeProductDia = () => {
  proxy.resetForm("productFormRef")
  productFormVisible.value = false
}
  proxy.resetForm("productFormRef");
  productFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm(
      '选中的内容将被导出,是否确认导出?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    proxy.download("/purchase/ledger/export", {}, '采购台账.xlsx')
  }).catch(() => {
    proxy.$modal.msg("已取消")
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
}
    .then(() => {
      proxy.download("/purchase/ledger/export", {}, "采购台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// åˆ é™¤
const handleDelete = () => {
  let ids = []
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning('请选择数据')
    return
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm(
      '选中的内容将被删除,是否确认删除?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    delPurchase(ids).then(res => {
      proxy.$modal.msgSuccess("删除成功")
      getList()
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .then(() => {
      delPurchase(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
  })
}
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, '0'); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, '0');
  const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
const mathNum = () => {
  console.log('productForm.value',productForm.value)
  console.log("productForm.value", productForm.value);
  if(!productForm.value.taxInclusiveUnitPrice){
    return
    return;
  }
  if(!productForm.value.quantity){
    return
    return;
  }
  // å«ç¨Žæ€»ä»·è®¡ç®—
  productForm.value.taxInclusiveTotalPrice = proxy.calculateTaxIncludeTotalPrice(productForm.value.taxInclusiveUnitPrice, productForm.value.quantity)
  productForm.value.taxInclusiveTotalPrice =
    proxy.calculateTaxIncludeTotalPrice(
      productForm.value.taxInclusiveUnitPrice,
      productForm.value.quantity
    );
  if(productForm.value.taxRate){
    // ä¸å«ç¨Žæ€»ä»·è®¡ç®—
    productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate)
    productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
}
};
// é”€å”®åˆåŒé€‰æ‹©æ”¹å˜æ–¹æ³•
const salesLedgerChange = (row) => {
  console.log('row',row)
  var index = salesContractList.value.findIndex(item => item.id == row);
  console.log('index',index)
const salesLedgerChange = async (row) => {
  console.log("row", row);
  var index = salesContractList.value.findIndex((item) => item.id == row);
  console.log("index", index);
  if(index > -1){
    form.value.projectName = salesContractList.value[index].projectName
    form.value.projectName = salesContractList.value[index].projectName;
    await querygProductInfoByContractNo();
  }
};
const querygProductInfoByContractNo = async () => {
  const { code, data } = await getProductInfoByContractNo({
    contractNo: form.value.salesLedgerId,
  });
  if (code == 200) {
    productData.value = data;
}
getList()
};
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>
src/views/procurementManagement/reportAnalysis/projectProfit/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
<template>
  <div class="app-container">
    <el-form class="search_form" :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-form-item>
    </el-form>
    <div class="table_list">
      <PIMTable
        :column="columns"
        :tableLoading="loading"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
        }"
        @pagination="onCurrentChange"
      ></PIMTable>
    </div>
  </div>
</template>
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import { getPurchaseList } from "@/api/procurementManagement/projectProfit";
import { onMounted } from "vue";
defineOptions({
  name: "项目利润",
});
const {
  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",
    },
  ]
);
onMounted(() => {
  getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
</style>
src/views/salesManagement/invoiceLedger/index.vue
@@ -1,8 +1,8 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">客户名称/合同号:</span>
      <el-form :inline="true" :model="searchForm">
        <el-form-item label="客户名称/合同号">
        <el-input
            v-model="searchForm.searchText"
            style="width: 240px"
@@ -11,59 +11,139 @@
            clearable
            :prefix-icon="Search"
        />
        <span class="search_title" style="margin-left: 10px">开票日期:</span>
        </el-form-item>
        <el-form-item label="开票日期">
        <el-date-picker
            style="width: 240px"
            v-model="searchForm.invoiceDate"
            value-format="YYYY-MM-DD"
            format="YYYY-MM-DD"
            type="date"
            placeholder="请选择"
            type="daterange"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            clearable
            @change="changeDateRange"
            @clear="clearRange"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
      </div>
      <div>
        <el-button @click="handleOut" type="primary" style="width: 100px">导出</el-button>
      </div>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
          <el-button @click="resetForm"> é‡ç½® </el-button>
          <el-button @click="handleOut" type="primary">导出</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading"
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
                @selection-change="handleSelectionChange"
                :row-key="row => row.id"
        :row-key="(row) => row.id"
                show-summary
                :summary-method="summarizeMainTable"
                height="calc(100vh - 18.5em)">
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <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="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="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column
          label="发票号"
          prop="invoiceNo"
          show-overflow-tooltip
        />
        <el-table-column
          label="发票金额(元)"
          prop="invoiceTotal"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <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/>
        <el-table-column label="发票" prop="invoiceFileName" show-overflow-tooltip>
        <el-table-column
          label="开票人"
          prop="invoicePerson"
          show-overflow-tooltip
        />
        <el-table-column
          label="开票日期"
          prop="invoiceDate"
          show-overflow-tooltip
        />
        <el-table-column
          label="发票"
          prop="invoiceFileName"
          show-overflow-tooltip
        >
          <template #default="scope">
            <span v-if="scope.row.invoiceFileName">{{ scope.row.invoiceFileName }}</span>
            <el-button v-else link type="primary" @click="handleDownload(scope.row)">上传</el-button>
            <span v-if="scope.row.invoiceFileName">{{
              scope.row.invoiceFileName
            }}</span>
            <el-button
              v-else
              link
              type="primary"
              @click="handleDownload(scope.row)"
              >上传</el-button
            >
          </template>
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="150" align="center" >
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm(scope.row);">编辑</el-button>
            <el-button link type="primary" size="small" @click="delInvoiceLedger(scope.row);">删除</el-button>
            <el-button
              link
              type="primary"
              size="small"
              @click="openForm(scope.row)"
              >编辑</el-button
            >
            <el-button
              link
              type="primary"
              size="small"
              @click="delInvoiceLedger(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" />
      <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="开票台账页面" width="70%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <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="salesContractNo">
@@ -72,26 +152,46 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="客户名称:" prop="customerName">
              <el-input v-model="form.customerName" placeholder="自动填充" clearable disabled/>
              <el-input
                v-model="form.customerName"
                placeholder="自动填充"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票号:" prop="invoiceNo">
              <el-input v-model="form.invoiceNo" placeholder="请输入" clearable/>
              <el-input
                v-model="form.invoiceNo"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="发票金额(元):" prop="invoiceTotal">
              <el-input type="number" :step="0.01" v-model="form.invoiceTotal" placeholder="请输入" clearable/>
              <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="invoicePerson">
              <el-input v-model="form.invoicePerson" placeholder="请输入" clearable disabled/>
              <el-input
                v-model="form.invoicePerson"
                placeholder="请输入"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -104,7 +204,6 @@
                  type="date"
                  placeholder="请选择"
                  clearable
                  disabled
              />
            </el-form-item>
          </el-col>
@@ -129,9 +228,7 @@
                <el-button type="primary">上传</el-button>
                <template #tip>
<!--                  æ–‡ä»¶æ ¼å¼æ”¯æŒ doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z-->
                  <div class="el-upload__tip">
                    æ–‡ä»¶æ ¼å¼æ”¯æŒ pdf
                  </div>
                  <div class="el-upload__tip">文件格式支持 pdf</div>
                </template>
              </el-upload>
            </el-form-item>
@@ -167,9 +264,7 @@
            >
              <el-button type="primary">上传</el-button>
              <template #tip>
                <div class="el-upload__tip">
                  æ–‡ä»¶æ ¼å¼ä»…支持 pdf
                </div>
                <div class="el-upload__tip">文件格式仅支持 pdf</div>
              </template>
            </el-upload>
          </el-form-item>
@@ -186,45 +281,54 @@
</template>
<script setup>
import pagination from '@/components/PIMTable/Pagination.vue'
import { ref } from 'vue'
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref } from "vue";
import {Search} from "@element-plus/icons-vue";
import {ElMessageBox } from "element-plus";
import { getToken } from "@/utils/auth"
import { getToken } from "@/utils/auth";
import {
  invoiceLedgerSaveOrUpdate,
  invoiceLedgerProductInfo,
  commitFile,
  registrationProductPage, delInvoiceLedgerByRegProductId
  registrationProductPage,
  delInvoiceLedgerByRegProductId,
} from "../../../api/salesManagement/invoiceLedger.js";
import useUserStore from "@/store/modules/user.js";
const { proxy } = getCurrentInstance()
const tableData = ref([])
const productData = ref([])
const selectedRows = ref([])
const tableLoading = ref(false)
import useFormData from "@/hooks/useFormData";
import dayjs from "dayjs";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const productData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
const fileList = ref([])
const dialogFormVisible = ref(false)
});
const total = ref(0);
const fileList = ref([]);
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    searchText: '',
    invoiceDate:''
    searchText: "",
    invoiceDate: [
      dayjs().startOf("month").format("YYYY-MM-DD"),
      dayjs().endOf("month").format("YYYY-MM-DD"),
    ],
    invoiceDateStart: dayjs().startOf("month").format("YYYY-MM-DD"),
    invoiceDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"),
  },
  form: {
    salesLedgerId: '',
    customerId: '',
    invoiceNo: '',
    invoiceTotal: '',
    taxRate: '',
    invoicePerson: '',
    invoiceDate: '',
    customerName:'',
    fileList:[]
    salesLedgerId: "",
    customerId: "",
    invoiceNo: "",
    invoiceTotal: "",
    taxRate: "",
    invoicePerson: "",
    invoiceDate: "",
    customerName: "",
    fileList: [],
  },
  rules: {
    salesLedgerId: [{ required: true, message: "请选择", trigger: "change" }],
@@ -235,72 +339,74 @@
    invoicePerson: [{ required: true, message: "请选择", trigger: "change" }],
    invoiceDate: [{ required: true, message: "请选择", trigger: "change" }],
    customerName: [{ required: true, message: "请选择", trigger: "change" }],
  }
})
const { searchForm, form, rules } = toRefs(data)
const currentId = ref('')
const userStore = useUserStore()
  },
});
const { form, rules } = toRefs(data);
const { form: searchForm, resetForm } = useFormData(data.searchForm);
const currentId = ref("");
const userStore = useUserStore();
const upload = reactive({
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/invoiceLedger/uploadFile",
  // è®¾ç½®ä¸Šä¼ çš„请求头部
  headers: { Authorization: "Bearer " + getToken() },
})
const matchFileType = ref(['pdf'])
const uploadModal = ref(false)
});
const matchFileType = ref(["pdf"]);
const uploadModal = ref(false);
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  registrationProductPage({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
  tableLoading.value = true;
  const { invoiceDate, ...rest } = searchForm;
  registrationProductPage({ ...rest, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.data.records;
    total.value = res.data.total;
  })
}
  });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
}
  selectedRows.value = selection;
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['invoiceTotal'], {
  return proxy.summarizeTable(param, ["invoiceTotal"], {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
};
// æ‰“开弹框
const openForm = (row) => {
  form.value = {}
  productData.value = []
  fileList.value = []
  form.value = {};
  productData.value = [];
  fileList.value = [];
  currentId.value = row.id;
  invoiceLedgerProductInfo({id: row.id}).then(res => {
    form.value = {...res.data}
  invoiceLedgerProductInfo({ id: row.id }).then((res) => {
    form.value = { ...res.data };
    fileList.value = res.data.fileList;
    if(!form.value.invoicePerson){
      form.value.invoicePerson = userStore.nickName
      form.value.invoicePerson = userStore.nickName;
      form.value.entryDate = getCurrentDate();
    }
    if(!form.value.invoiceDate){
      form.value.invoiceDate = getCurrentDate();
    }
  })
  dialogFormVisible.value = true
}
  });
  dialogFormVisible.value = true;
};
// ä¸Šä¼ å¤šä¸ªæ–‡ä»¶å°±è¦†ç›–原来的
const handleExceed = (files) => {
  proxy.$refs["fileUpload"].clearFiles();
@@ -310,131 +416,148 @@
};
// ä¸Šä¼ å‰æ ¡æ£€
function handleBeforeUpload(file) {
  console.log('file',file)
  console.log("file", file);
  // æ ¡æ£€æ–‡ä»¶å¤§å°
  if (file.size > 1024 * 1024 * 10) {
    proxy.$modal.msgError('上传文件大小不能超过10MB!')
    return false
    proxy.$modal.msgError("上传文件大小不能超过10MB!");
    return false;
  }
  // åˆ¤æ–­æ–‡ä»¶æ ¼å¼æ˜¯å¦ç¬¦åˆ
  const fileType = file.name.split('.').pop().toLowerCase();
  const fileType = file.name.split(".").pop().toLowerCase();
  if(!matchFileType.value.includes(fileType)) {
    proxy.$modal.msgError('文件格式不匹配')
    return false
    proxy.$modal.msgError("文件格式不匹配");
    return false;
  }
  proxy.$modal.loading("正在上传文件,请稍候...")
  return true
  proxy.$modal.loading("正在上传文件,请稍候...");
  return true;
}
// ä¸Šä¼ å¤±è´¥
function handleUploadError(err) {
  proxy.$modal.msgError("上传文件失败")
  proxy.$modal.closeLoading()
  proxy.$modal.msgError("上传文件失败");
  proxy.$modal.closeLoading();
}
// ä¸Šä¼ æˆåŠŸå›žè°ƒ
function handleUploadSuccess(res, file, uploadFiles) {
  proxy.$modal.closeLoading()
  proxy.$modal.closeLoading();
  if (res.code === 200) {
    proxy.$refs["fileUpload"].handleRemove(file)
    fileList.value.push(res.data)
    proxy.$modal.msgSuccess("上传成功")
    proxy.$refs["fileUpload"].handleRemove(file);
    fileList.value.push(res.data);
    proxy.$modal.msgSuccess("上传成功");
  } else {
    proxy.$modal.msgError(res.msg)
    proxy.$refs.fileUpload.handleRemove(file)
    proxy.$modal.msgError(res.msg);
    proxy.$refs.fileUpload.handleRemove(file);
  }
}
// ç§»é™¤æ–‡ä»¶
function handleRemove (file) {
  let index = fileList.value.findIndex(item => item.url === file.url)
  let index = fileList.value.findIndex((item) => item.url === file.url);
  if(index > -1) {
    fileList.value.splice(index, 1)
    fileList.value.splice(index, 1);
  }
}
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      form.value.fileList = fileList.value;
      invoiceLedgerSaveOrUpdate(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeDia()
        getList()
      })
      invoiceLedgerSaveOrUpdate(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        getList();
      });
    }
  })
}
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm(
      '选中的内容将被导出,是否确认导出?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    proxy.download("/invoiceLedger/export", {}, '开票台账.xlsx')
  }).catch(() => {
    proxy.$modal.msg("已取消")
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
}
    .then(() => {
      proxy.download("/invoiceLedger/export", {}, "开票台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// æ‰“开附件上传弹窗
const handleDownload = (val) => {
  fileList.value = []
  uploadModal.value = true
  currentId.value = val.id
}
  fileList.value = [];
  uploadModal.value = true;
  currentId.value = val.id;
};
// ç¡®è®¤æ–‡ä»¶ä¸Šä¼ 
const commiInvoicetFile = () => {
  const object = {
    fileList: fileList.value,
    id: currentId.value,
  }
  commitFile(object).then(res => {
  };
  commitFile(object).then((res) => {
    if (res.code === 200) {
      proxy.$modal.msgSuccess("提交成功")
      uploadModal.value = false
      proxy.$modal.msgSuccess("提交成功");
      uploadModal.value = false;
    }
    getList();
    currentId.value = ''
    fileList.value = []
  })
}
    currentId.value = "";
    fileList.value = [];
  });
};
// åˆ é™¤å¼€ç¥¨å°è´¦
const delInvoiceLedger = (row) => {
  ElMessageBox.confirm(
      '该发票台账将被删除,是否确认删除', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    delInvoiceLedgerByRegProductId(row.id).then(res => {
      getList()
  ElMessageBox.confirm("该发票台账将被删除,是否确认删除", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    })
  }).catch(() => {
    proxy.$modal.msg("已取消")
    .then(() => {
      delInvoiceLedgerByRegProductId(row.id).then((res) => {
        getList();
      });
  })
}
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, '0'); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, '0');
  const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
const changeDateRange = (date) => {
  if (date) {
    searchForm.invoiceDateStart = date[0];
    searchForm.invoiceDateEnd = date[1];
    getList();
  }
};
getList()
const clearRange = () => {
  searchForm.invoiceDate = [];
  searchForm.invoiceDateStart = undefined;
  searchForm.invoiceDateEnd = undefined;
  getList();
};
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss">
.table_list {
  margin-top: unset;
}
</style>
src/views/salesManagement/invoiceRegistration/index.vue
@@ -1,68 +1,181 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">开票登记:</span>
      <el-form :inline="true" :model="searchForm">
        <el-form-item label="开票登记">
        <el-input
            v-model="searchForm.customerName"
            style="width: 240px"
            placeholder="请输入名称搜索"
            @change="handleQuery"
            clearable
            :prefix-icon="Search"
            @change="handleQuery"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
      </div>
      <div>
        <el-button type="primary" @click="openForm">新增登记</el-button>
      </div>
        </el-form-item>
        <el-form-item label="未开票金额是否为0">
          <el-select v-model="searchForm.status" style="width: 90px" clearable>
            <el-option label="否" :value="0" />
            <el-option label="是" :value="1" />
          </el-select>
        </el-form-item>
        <el-form-item label="客户合同号">
          <el-input
            v-model="searchForm.customerContractNo"
            placeholder="请输入客户合同号"
            clearable
          />
        </el-form-item>
        <el-form-item label="项目名称">
          <el-input
            v-model="searchForm.projectName"
            placeholder="请输入项目名称"
            clearable
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
          <el-button @click="resetForm"> é‡ç½® </el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading"
                @selection-change="handleSelectionChange"
      <el-button type="primary" @click="openForm" style="margin-bottom: 8px">
        æ–°å¢žç™»è®°
      </el-button>
      <el-table
        :data="tableData"
        :border="true"
        height="calc(100vh - 21em)"
        v-loading="tableLoading"
                :expand-row-keys="expandedRowKeys"
                :row-key="row => row.id"
        :row-key="(row) => row.id"
                show-summary
                :summary-method="summarizeMainTable"
                @expand-change="expandChange"
                height="calc(100vh - 18.5em)">
        @selection-change="handleSelectionChange"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column type="expand">
          <template #default="props">
            <el-table :data="props.row.children" border
            <el-table
              :data="props.row.children"
              border
                      show-summary
                      :summary-method="summarizeChildrenTable">
              <el-table-column align="center" label="序号" type="index" width="60" />
              :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" width="70"/>
              <el-table-column label="数量" prop="quantity" width="70"/>
              <el-table-column label="税率" prop="taxRate" width="70" />
              <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="invoiceNum" :formatter="formattedNumber" />
              <el-table-column label="开票金额(元)" prop="invoiceAmount" :formatter="formattedNumber" />
              <el-table-column label="未开票数" prop="noInvoiceNum" :formatter="formattedNumber" />
              <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" :formatter="formattedNumber"/>
              <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="invoiceNum"
                :formatter="formattedNumber"
              />
              <el-table-column
                label="开票金额(元)"
                prop="invoiceAmount"
                :formatter="formattedNumber"
              />
              <el-table-column
                label="未开票数"
                prop="noInvoiceNum"
                :formatter="formattedNumber"
              />
              <el-table-column
                label="未开票金额(元)"
                prop="noInvoiceAmount"
                :formatter="formattedNumber"
              />
            </el-table>
          </template>
        </el-table-column>
        <el-table-column align="center" label="序号" type="index" width="60" />
        <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="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="salesman" show-overflow-tooltip/>
        <el-table-column label="项目名称" prop="projectName" show-overflow-tooltip/>
        <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column label="已开票金额(元)" prop="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column label="未开票金额(元)" prop="noInvoiceAmountTotal" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column
          label="项目名称"
          prop="projectName"
          show-overflow-tooltip
        />
        <el-table-column
          label="合同金额(元)"
          prop="contractAmount"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column
          label="已开票金额(元)"
          prop="invoiceTotal"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column label="未开票金额(元)" show-overflow-tooltip>
          <template #default="{ row, column }">
            <el-text type="danger">
              {{ formattedNumber(row, column, row.noInvoiceAmountTotal) }}
            </el-text>
          </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" />
      <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="新增开票登记页面" width="85%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <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="salesContractNo">
@@ -71,54 +184,120 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="客户名称:" prop="customerName">
                <el-input v-model="form.customerName" placeholder="自动填充" disabled></el-input>
              <el-input
                v-model="form.customerName"
                placeholder="自动填充"
                disabled
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="业务员:" prop="salesman">
              <el-input v-model="form.salesman" placeholder="自动填充" disabled/>
              <el-input
                v-model="form.salesman"
                placeholder="自动填充"
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="项目名称:" prop="projectName">
              <el-input v-model="form.projectName" placeholder="自动填充" disabled/>
              <el-input
                v-model="form.projectName"
                placeholder="自动填充"
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-form-item label="产品信息:" prop="entryDate">
          </el-form-item>
          <el-form-item label="产品信息:" prop="entryDate"> </el-form-item>
        </el-row>
        <el-table :data="productData" border show-summary :summary-method="summarizeChildrenTable">
          <el-table-column align="center" label="序号" type="index" width="60" />
        <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" />
          <el-table-column label="单位" prop="unit" />
          <el-table-column label="数量" prop="quantity" width="70" />
          <el-table-column label="税率" prop="taxRate" width="70" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" />
          <el-table-column
            label="含税单价(元)"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="含税总价(元)"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="不含税总价(元)"
            prop="taxExclusiveTotalPrice"
            :formatter="formattedNumber"
            width="150"
          />
          <el-table-column label="本次开票数" prop="currentInvoiceNum">
            <template #default="scope">
              <el-input type="number" :step="0.1" min="0" v-model="scope.row.currentInvoiceNum" @blur="invoiceNumBlur(scope.row)"></el-input>
              <el-input
                type="number"
                :step="0.1"
                min="0"
                v-model="scope.row.currentInvoiceNum"
                @blur="invoiceNumBlur(scope.row)"
              ></el-input>
            </template>
          </el-table-column>
          <el-table-column label="本次开票金额(元)" prop="currentInvoiceAmount" width="150">
          <el-table-column
            label="本次开票金额(元)"
            prop="currentInvoiceAmount"
            width="150"
          >
            <template #default="scope">
              <el-input type="number" :step="0.01" min="0" v-model="scope.row.currentInvoiceAmount" @blur="invoiceAmountBlur(scope.row)" ></el-input>
              <el-input
                type="number"
                :step="0.01"
                min="0"
                v-model="scope.row.currentInvoiceAmount"
                @blur="invoiceAmountBlur(scope.row)"
              ></el-input>
            </template>
          </el-table-column>
          <el-table-column label="未开票数" prop="noInvoiceNum" >
            <template #default="scope">
              <el-input type="number" min="0" disabled 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"  width="150" >
          <el-table-column
            label="未开票金额(元)"
            prop="noInvoiceAmount"
            width="150"
          >
            <template #default="scope">
              <el-input type="number" min="0" disabled v-model="scope.row.noInvoiceAmount" :precision="2" :step="0.01"></el-input>
              <el-input
                type="number"
                min="0"
                disabled
                v-model="scope.row.noInvoiceAmount"
                :precision="2"
                :step="0.01"
              ></el-input>
            </template>
          </el-table-column>
        </el-table>
@@ -134,8 +313,8 @@
</template>
<script setup>
import pagination from '@/components/PIMTable/Pagination.vue'
import { ref } from 'vue'
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref } from "vue";
import {Search} from "@element-plus/icons-vue";
import {ElMessageBox } from "element-plus";
// import {userListNoPage} from "@/api/system/user.js";
@@ -144,38 +323,42 @@
  ledgerListPage,
  productList,
} from "@/api/salesManagement/salesLedger.js";
import {
  invoiceRegistrationSave,
} from "@/api/salesManagement/invoiceRegistration.js";
const { proxy } = getCurrentInstance()
const tableData = ref([])
const productData = ref([])
const selectedRows = ref([])
const tableLoading = ref(false)
import { invoiceRegistrationSave } from "@/api/salesManagement/invoiceRegistration.js";
import useFormData from "@/hooks/useFormData";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const productData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
});
const total = ref(0);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref('')
const dialogFormVisible = ref(false)
const operationType = ref("");
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    customerName: '',
    customerName: "",
    status: 0,
    customerContractNo: undefined, // å®¢æˆ·åˆåŒå·
    projectName: undefined, // é¡¹ç›®åç§°
  },
  form: {
    salesLedgerId: '',
    customerName: '',
    salesman: '',
    projectName: '',
    productData: []
    salesLedgerId: "",
    customerName: "",
    salesman: "",
    projectName: "",
    productData: [],
  },
  rules: {
    salesLedgerId: [{ required: true, message: "请选择", trigger: "change" }]
  }
})
const { searchForm, form, rules } = toRefs(data)
    salesLedgerId: [{ required: true, message: "请选择", trigger: "change" }],
  },
});
const { form, rules } = toRefs(data);
const { form: searchForm, resetForm } = useFormData(data.searchForm);
const formattedNumber = (row, column, cellValue) => {
  if (cellValue == 0) {
@@ -190,149 +373,175 @@
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  ledgerListPage({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
  tableLoading.value = true;
  ledgerListPage({ ...searchForm, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
    total.value = res.total
    expandedRowKeys.value = []
  })
}
    total.value = res.total;
    expandedRowKeys.value = [];
  });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  console.log('selection', selection)
  selectedRows.value = selection.filter(item => item.salesContractNo !== undefined);
}
const expandedRowKeys = ref([])
  console.log("selection", selection);
  selectedRows.value = selection.filter(
    (item) => item.salesContractNo !== undefined
  );
};
const expandedRowKeys = ref([]);
// å±•开行
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
    try {
      productList({salesLedgerId: row.id,
                   type: 1 }).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
      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;
        }
        expandedRowKeys.value.push(row.id)
      })
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error)
      console.log(error);
    }
  } else {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
  }
}
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['contractAmount','noInvoiceAmountTotal','invoiceTotal']);
  return proxy.summarizeTable(param, [
    "contractAmount",
    "noInvoiceAmountTotal",
    "invoiceTotal",
  ]);
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice','invoiceNum','invoiceAmount','noInvoiceNum','noInvoiceAmount']);
}
  return proxy.summarizeTable(param, [
    "taxInclusiveUnitPrice",
    "taxInclusiveTotalPrice",
    "taxExclusiveTotalPrice",
    "invoiceNum",
    "invoiceAmount",
    "currentInvoiceAmount",
    "noInvoiceNum",
    "noInvoiceAmount",
  ]);
};
// æ‰“开弹框
const openForm = () => {
  // åˆ¤æ–­æ˜¯å¦å¤šé€‰
  if(selectedRows.value.length != 1) {
    proxy.$modal.msgError("请选择一条合同")
    proxy.$modal.msgError("请选择一条合同");
    return;
  }
  form.value = {}
  productData.value = []
  getSalesLedgerWithProducts({id: selectedRows.value[0].id}).then(res => {
    form.value = {...res}
    productData.value = form.value.productData.map(item => {
      return item
    })
    dialogFormVisible.value = true
    console.log('productData.value ',productData.value )
  })
}
  form.value = {};
  productData.value = [];
  getSalesLedgerWithProducts({ id: selectedRows.value[0].id }).then((res) => {
    form.value = { ...res };
    productData.value = form.value.productData.map((item) => {
      return item;
    });
    dialogFormVisible.value = true;
    console.log("productData.value ", productData.value);
  });
};
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      form.value.productData = proxy.HaveJson(productData.value)
      invoiceRegistrationSave(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeDia()
        getList()
      })
      form.value.productData = proxy.HaveJson(productData.value);
      invoiceRegistrationSave(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        getList();
      });
    }
  })
}
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm(
      '选中的内容将被导出,是否确认导出?',
      '导出', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    proxy.download("/invoiceRegistration/export", {}, '开票登记信息.xlsx')
  }).catch(() => {
    proxy.$modal.msg("已取消")
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
}
    .then(() => {
      proxy.download("/invoiceRegistration/export", {}, "开票登记信息.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
//本次开票失焦操作
const invoiceNumBlur = (row) => {
  if(!row.currentInvoiceNum){
    row.currentInvoiceNum = 0
    row.currentInvoiceNum = 0;
  }
  if(row.currentInvoiceNum > row.tempNoInvoiceNum){
    proxy.$modal.msgWarning('本次开票数不得大于未开票数')
    row.currentInvoiceNum = 0
    proxy.$modal.msgWarning("本次开票数不得大于未开票数");
    row.currentInvoiceNum = 0;
  }
  // è®¡ç®—本次开票金额
  row.currentInvoiceAmount = (row.currentInvoiceNum * row.taxInclusiveUnitPrice).toFixed(2)
  row.currentInvoiceAmount = (
    row.currentInvoiceNum * row.taxInclusiveUnitPrice
  ).toFixed(2);
  // è®¡ç®—未开票数
  row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed(2)
  row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed(
    2
  );
  // è®¡ç®—未开票金额
  row.noInvoiceAmount = (row.tempnoInvoiceAmount -  row.currentInvoiceAmount).toFixed(2)
}
  row.noInvoiceAmount = (
    row.tempnoInvoiceAmount - row.currentInvoiceAmount
  ).toFixed(2);
};
// æœ¬æ¬¡å¼€ç¥¨é‡‘额失焦操作
const invoiceAmountBlur = (row) => {
  if(!row.currentInvoiceAmount){
    row.currentInvoiceAmount = 0
    row.currentInvoiceAmount = 0;
  }
  // è®¡ç®—是否超过开票总金额
  if(row.currentInvoiceAmount > row.tempnoInvoiceAmount){
    proxy.$modal.msgWarning('本次开票金额不得大于未开票金额')
    row.currentInvoiceAmount = 0
    proxy.$modal.msgWarning("本次开票金额不得大于未开票金额");
    row.currentInvoiceAmount = 0;
  }
  // è®¡ç®—本次开票数
  row.currentInvoiceNum = (row.currentInvoiceAmount / row.taxInclusiveUnitPrice).toFixed(2)
  console.log('row.currentInvoiceNum ',row.currentInvoiceNum )
  console.log(' row.originalNoInvoiceNum  ', row.originalNoInvoiceNum  )
  row.currentInvoiceNum = (
    row.currentInvoiceAmount / row.taxInclusiveUnitPrice
  ).toFixed(2);
  console.log("row.currentInvoiceNum ", row.currentInvoiceNum);
  console.log(" row.originalNoInvoiceNum  ", row.originalNoInvoiceNum);
  // è®¡ç®—未开票数
  row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed(2)
  row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed(
    2
  );
  // è®¡ç®—未开票金额
  row.noInvoiceAmount = (row.tempnoInvoiceAmount -  row.currentInvoiceAmount).toFixed(2)
}
  row.noInvoiceAmount = (
    row.tempnoInvoiceAmount - row.currentInvoiceAmount
  ).toFixed(2);
};
getList()
getList();
</script>
<style scoped lang="scss">
.table_list {
  margin-top: unset;
}
</style>
src/views/salesManagement/receiptPayment/index.vue
@@ -1,48 +1,91 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">回款登记:</span>
      <el-form :inline="true" :model="searchForm" style="width: 100%">
        <el-row justify="space-between">
          <el-col :span="20">
            <el-form-item label="回款登记">
        <el-input
            v-model="searchForm.searchText"
            style="width: 240px"
            placeholder="输入客户名称/合同号搜索"
            @change="handleQuery"
            clearable
            prefix-icon="Search"
                @change="handleQuery"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增回款</el-button>
      </div>
            </el-form-item>
            <el-form-item label="不显示待回款">
              <el-checkbox
                v-model="searchForm.status"
                :label="0"
                @change="handleQuery"
              />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item style="float: right; margin-right: unset">
              <el-button type="primary" @click="openForm('add')">
                æ–°å¢žå›žæ¬¾
              </el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading"
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
                @selection-change="handleSelectionChange"
                :row-key="row => row.id"
        :row-key="(row) => row.id"
                show-summary
                :summary-method="summarizeMainTable"
                :expand-row-keys="expandedRowKeys"
                @expand-change="expandChange"
                height="calc(100vh - 18.5em)">
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column type="expand">
          <template #default="props">
            <el-table :data="props.row.children" border
            <el-table
              :data="props.row.children"
              border
                      show-summary
                      :summary-method="summarizeChildrenTable">
              <el-table-column align="center" label="序号" type="index" width="60" />
              :summary-method="summarizeChildrenTable"
            >
              <el-table-column
                align="center"
                label="序号"
                type="index"
                width="60"
              />
              <el-table-column label="回款日期" prop="receiptPaymentDate" />
              <el-table-column label="回款金额" prop="receiptPaymentAmount">
                <template #default="scope">
                  <el-input v-model="scope.row.receiptPaymentAmount" :disabled="!scope.row.editType"></el-input>
                  <el-input
                    v-model="scope.row.receiptPaymentAmount"
                    :disabled="!scope.row.editType"
                  ></el-input>
                </template>
              </el-table-column>
              <el-table-column label="回款方式" prop="receiptPaymentType"  >
                <template #default="scope">
                  <el-select v-model="scope.row.receiptPaymentType" placeholder="请选择" clearable :disabled="!scope.row.editType">
                    <el-option v-for="item in receipt_payment_type" :key="item.value" :label="item.label" :value="item.value"/>
                  <el-select
                    v-model="scope.row.receiptPaymentType"
                    placeholder="请选择"
                    clearable
                    :disabled="!scope.row.editType"
                  >
                    <el-option
                      v-for="item in receipt_payment_type"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value"
                    />
                  </el-select>
                </template>
              </el-table-column>
@@ -50,77 +93,204 @@
              <el-table-column label="登记日期" prop="createTime"  />
              <el-table-column label="操作" width="150">
                <template #default="scope">
                  <el-button link type="primary" size="small" @click="changeEditType(scope.row)" v-if="!scope.row.editType">编辑</el-button>
                  <el-button link type="primary" size="small" @click="saveReceiptPayment(scope.row)" v-if="scope.row.editType">保存</el-button>
                  <el-button link type="primary" size="small" @click="delReceiptRecord(scope.row)">删除</el-button>
                  <el-button
                    link
                    type="primary"
                    size="small"
                    @click="changeEditType(scope.row)"
                    v-if="!scope.row.editType"
                    >编辑</el-button
                  >
                  <el-button
                    link
                    type="primary"
                    size="small"
                    @click="saveReceiptPayment(scope.row)"
                    v-if="scope.row.editType"
                    >保存</el-button
                  >
                  <el-button
                    link
                    type="primary"
                    size="small"
                    @click="delReceiptRecord(scope.row)"
                    >删除</el-button
                  >
                </template>
              </el-table-column>
            </el-table>
          </template>
        </el-table-column>
        <el-table-column align="center" label="序号" type="index" width="60" />
        <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" show-overflow-tooltip/>
        <el-table-column label="发票号" prop="invoiceNo" show-overflow-tooltip/>
        <el-table-column label="发票金额(元)" prop="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber"/>
        <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="customerName"
          show-overflow-tooltip
        />
        <el-table-column
          label="产品大类"
          prop="productCategory"
          show-overflow-tooltip
        />
        <el-table-column
          label="发票号"
          prop="invoiceNo"
          show-overflow-tooltip
        />
        <el-table-column
          label="发票金额(元)"
          prop="invoiceTotal"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column label="税率" prop="taxRate" show-overflow-tooltip/>
        <el-table-column label="回款金额(元)" prop="receiptPaymentAmountTotal" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column label="待回款金额(元)" prop="noReceiptAmount" show-overflow-tooltip :formatter="formattedNumber"/>
        <el-table-column
          label="回款金额(元)"
          prop="receiptPaymentAmountTotal"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column
          label="待回款金额(元)"
          prop="noReceiptAmount"
          show-overflow-tooltip
        >
          <template #default="{ row, column }">
            <el-text type="danger">
              {{ formattedNumber(row, column, row.noReceiptAmount) }}
            </el-text>
          </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" />
      <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="新增发票号页面" width="70%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
    <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="salesContractNo">
              <el-input v-model="form.salesContractNo" placeholder="自动填充" disabled />
              <el-input
                v-model="form.salesContractNo"
                placeholder="自动填充"
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="客户名称:" prop="customerName">
              <el-input v-model="form.customerName" placeholder="自动填充" disabled />
              <el-input
                v-model="form.customerName"
                placeholder="自动填充"
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票号:" prop="invoiceNo">
              <el-input v-model="form.invoiceNo" placeholder="自动填充" disabled/>
              <el-input
                v-model="form.invoiceNo"
                placeholder="自动填充"
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="发票金额(元):" prop="invoiceTotal">
              <el-input type="number" v-model="form.invoiceTotal" placeholder="自动填充" :step="0.01" disabled/>
              <el-input
                type="number"
                v-model="form.invoiceTotal"
                placeholder="自动填充"
                :step="0.01"
                disabled
              />
            </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" v-model="form.taxRate" placeholder="自动填充" :step="0.01" disabled/>
              <el-input
                type="number"
                v-model="form.taxRate"
                placeholder="自动填充"
                :step="0.01"
                disabled
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="本次回款金额:" prop="receiptPaymentAmount">
              <el-input type="number" min="0" v-model="form.receiptPaymentAmount" placeholder="请输入" :step="0.01" clearable/>
              <el-input
                type="number"
                min="0"
                v-model="form.receiptPaymentAmount"
                placeholder="请输入"
                :step="0.01"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="回款形式:" prop="receiptPaymentType">
              <el-select v-model="form.receiptPaymentType" placeholder="请选择" clearable>
                <el-option v-for="item in receipt_payment_type" :key="item.value" :label="item.label" :value="item.value"/>
              <el-select
                v-model="form.receiptPaymentType"
                placeholder="请选择"
                clearable
              >
                <el-option
                  v-for="item in receipt_payment_type"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="登记人:" prop="registrant">
              <el-input v-model="form.registrant" placeholder="请输入" clearable disabled/>
              <el-input
                v-model="form.registrant"
                placeholder="请输入"
                clearable
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -151,45 +321,48 @@
</template>
<script setup>
import pagination from '@/components/PIMTable/Pagination.vue'
import { ref } from 'vue'
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref } from "vue";
import {
  receiptPaymentSaveOrUpdate,
  bindInvoiceNoRegPage,
  invoiceInfo,
  receiptPaymentHistoryListNoPage,
  receiptPaymentDel
  receiptPaymentDel,
} from "../../../api/salesManagement/receiptPayment.js";
import useUserStore from '@/store/modules/user'
import { ElMessage,ElMessageBox } from 'element-plus'
const userStore = useUserStore()
const { proxy } = getCurrentInstance()
const tableData = ref([])
const selectedRows = ref([])
const tableLoading = ref(false)
import useUserStore from "@/store/modules/user";
import { ElMessage, ElMessageBox } from "element-plus";
import useFormData from "@/hooks/useFormData";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
const expandedRowKeys = ref([])
});
const total = ref(0);
const expandedRowKeys = ref([]);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const dialogFormVisible = ref(false)
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    searchText: '',
    searchText: "",
    status: false,
  },
  form: {
    salesContractNo: '',
    customerName: '',
    invoiceNo: '',
    invoiceTotal: '',
    taxRate: '',
    receiptPaymentAmount: '',
    receiptPaymentType: '',
    registrant: '',
    receiptPaymentDate: ''
    salesContractNo: "",
    customerName: "",
    invoiceNo: "",
    invoiceTotal: "",
    taxRate: "",
    receiptPaymentAmount: "",
    receiptPaymentType: "",
    registrant: "",
    receiptPaymentDate: "",
  },
  rules: {
    salesContractNo: [{ required: true, message: "请选择", trigger: "change" }],
@@ -197,14 +370,21 @@
    invoiceNo: [{ required: true, message: "请选择", trigger: "change" }],
    invoiceTotal: [{ required: true, message: "请输入", trigger: "blur" }],
    taxRate: [{ required: true, message: "请选择", trigger: "change" }],
    receiptPaymentAmount: [{ required: true, message: "请选择", trigger: "change" }],
    receiptPaymentType: [{ required: true, message: "请选择", trigger: "change" }],
    receiptPaymentAmount: [
      { required: true, message: "请选择", trigger: "change" },
    ],
    receiptPaymentType: [
      { required: true, message: "请选择", trigger: "change" },
    ],
    registrant: [{ required: true, message: "请选择", trigger: "change" }],
    receiptPaymentDate: [{ required: true, message: "请选择", trigger: "change" }],
  }
})
const { searchForm, form, rules } = toRefs(data)
const { receipt_payment_type } = proxy.useDict("receipt_payment_type")
    receiptPaymentDate: [
      { required: true, message: "请选择", trigger: "change" },
    ],
  },
});
const { form, rules } = toRefs(data);
const { form: searchForm, resetForm } = useFormData(data.searchForm);
const { receipt_payment_type } = proxy.useDict("receipt_payment_type");
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
@@ -212,108 +392,118 @@
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  expandedRowKeys.value = []
  tableLoading.value = true
  bindInvoiceNoRegPage({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
    tableData.value = res.data.records
    total.value = res.data.total
  }).catch(() => {
    tableLoading.value = false
  expandedRowKeys.value = [];
  tableLoading.value = true;
  bindInvoiceNoRegPage({ ...searchForm, ...page })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records;
      total.value = res.data.total;
  })
}
    .catch(() => {
      tableLoading.value = false;
    });
};
// å±•开行
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
    try {
      receiptPaymentHistoryListNoPage({invoiceLedgerId: row.id,
        type: 1 }).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
      receiptPaymentHistoryListNoPage({
        invoiceLedgerId: row.id,
        type: 1,
      }).then((res) => {
        const index = tableData.value.findIndex((item) => item.id === row.id);
        if (index > -1) {
          if(res?.length > 0) {
            res.forEach(item => {
              item.editType = false
            })
            res.forEach((item) => {
              item.editType = false;
            });
          }
          tableData.value[index].children = res;
        }
        expandedRowKeys.value.push(row.id)
      })
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error)
      console.log(error);
    }
  } else {
    expandedRowKeys.value = []
    expandedRowKeys.value = [];
  }
}
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  console.log('selection', selection)
  selectedRows.value = selection.filter(item => item.customerContractNo !== null);
}
  console.log("selection", selection);
  selectedRows.value = selection.filter(
    (item) => item.customerContractNo !== null
  );
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['invoiceTotal', 'receiptPaymentAmountTotal', 'noReceiptAmount'], {
  return proxy.summarizeTable(
    param,
    ["invoiceTotal", "receiptPaymentAmountTotal", "noReceiptAmount"],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
  return proxy.summarizeTable(param, ['receiptPaymentAmount']);
}
  return proxy.summarizeTable(param, ["receiptPaymentAmount"]);
};
// æ‰“开弹框
const openForm = () => {
  form.value = {}
  form.value = {};
  if(selectedRows.value.length !== 1) {
    proxy.$modal.msgError("请选择一条数据")
    return
    proxy.$modal.msgError("请选择一条数据");
    return;
  }
  //
  console.log('(selectedRows.value',selectedRows.value)
  console.log("(selectedRows.value", selectedRows.value);
  if(selectedRows.value[0].noReceiptAmount === 0){
    proxy.$modal.msgError("待回款金额为0元")
    return
    proxy.$modal.msgError("待回款金额为0元");
    return;
  }
  invoiceInfo({id: selectedRows.value[0].id}).then(res => {
    form.value = {...res.data}
    form.value.invoiceLedgerId = form.value.id
    form.value.id = ''
    form.value.registrant = userStore.nickName
  })
  dialogFormVisible.value = true
}
  invoiceInfo({ id: selectedRows.value[0].id }).then((res) => {
    form.value = { ...res.data };
    form.value.invoiceLedgerId = form.value.id;
    form.value.id = "";
    form.value.registrant = userStore.nickName;
  });
  dialogFormVisible.value = true;
};
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      receiptPaymentSaveOrUpdate(form.value).then(res => {
        proxy.$modal.msgSuccess("提交成功")
        closeDia()
        getList()
      })
      receiptPaymentSaveOrUpdate(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        getList();
      });
    }
  })
}
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef")
  dialogFormVisible.value = false
}
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// åˆ é™¤å›žæ¬¾è®°å½•
const delReceiptRecord = (row) => {
  console.log('row',row)
  console.log("row", row);
  ElMessageBox.confirm("确认删除该记录吗?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
@@ -321,8 +511,8 @@
  })
      .then(async () => {
        try {
          let ids = []
          ids.push(row.id)
        let ids = [];
        ids.push(row.id);
          await receiptPaymentDel(ids);
          ElMessage.success("删除成功");
          getList();
@@ -334,29 +524,30 @@
      .catch(() => {
        ElMessage.info("已取消删除");
      });
}
};
// ç¼–辑修改状态
const changeEditType = (row) => {
  row.editType = !row.editType
}
  row.editType = !row.editType;
};
// ä¿å­˜å›žæ¬¾è®°å½•
const saveReceiptPayment = (row) => {
  let updateData = {
    id:row.id,
    receiptPaymentType: row.receiptPaymentType,
    receiptPaymentAmount: row.receiptPaymentAmount
  }
  receiptPaymentSaveOrUpdate(updateData).then(res => {
    row.editType = !row.editType
  })
}
    receiptPaymentAmount: row.receiptPaymentAmount,
  };
  receiptPaymentSaveOrUpdate(updateData).then((res) => {
    row.editType = !row.editType;
  });
};
getList()
getList();
</script>
<style scoped lang="scss">
.table_list {
  margin-top: unset;
}
</style>
src/views/salesManagement/receiptPaymentHistory/index.vue
@@ -1,119 +1,174 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">客户名称:</span>
        <el-input v-model="searchForm.searchText" style="width: 240px" placeholder="输入客户名称搜索"
                  @change="handleQuery" clearable :prefix-icon="Search" />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
      </div>
    </div>
    <el-form :model="searchForm" :inline="true">
      <el-form-item label="客户名称">
        <el-input
          v-model="searchForm.searchText"
          style="width: 240px"
          placeholder="输入客户名称搜索"
          @change="handleQuery"
          clearable
          :prefix-icon="Search"
        />
      </el-form-item>
      <el-form-item label="回款日期">
        <el-date-picker
          v-model="searchForm.receiptPaymentDate"
          value-format="YYYY-MM-DD"
          format="YYYY-MM-DD"
          type="daterange"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
          clearable
          @change="changeDateRange"
          @clear="clearRange"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true"
      <PIMTable
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :isSelection="true"
                :isShowSummary="isShowSummarySon"
                :summaryMethod="summarizeMainTable1"
                :handleSelectionChange="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination"
                :total="total"></PIMTable>
        :handleSelectionChange="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
        :total="total"
      ></PIMTable>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue'
import { ref } from "vue";
import { Search } from "@element-plus/icons-vue";
import {
  receiptPaymentHistoryListPage
} from "@/api/salesManagement/receiptPayment.js";
const { proxy } = getCurrentInstance()
import { receiptPaymentHistoryListPage } from "@/api/salesManagement/receiptPayment.js";
import useFormData from "@/hooks/useFormData";
import dayjs from "dayjs";
const { proxy } = getCurrentInstance();
const tableColumn = ref([
  {
    label: '回款日期',
    prop: 'receiptPaymentDate',
    label: "回款日期",
    prop: "receiptPaymentDate",
  },
  {
    label: '客户名称',
    prop: 'customerName',
    label: "客户名称",
    prop: "customerName",
  },
  {
    label: '回款金额',
    prop: 'receiptPaymentAmount',
    label: "回款金额(元)",
    prop: "receiptPaymentAmount",
    formatData: (params) => {
      return parseFloat(params).toFixed(2);
    }
    },
  },
  {
    label: '回款方式',
    prop: 'receiptPaymentType',
    dataType: 'tag',
    label: "回款方式",
    prop: "receiptPaymentType",
    dataType: "tag",
    formatData: (params) => {
      if (params == 0) {
        return '电汇';
        return "电汇";
      } else if (params == 1) {
        return '承兑';
        return "承兑";
      } else {
        return null
        return null;
      }
    },
    formatType: (params) => {
      return "info"
    }
      return "info";
    },
  },
  {
    label: '登记人',
    prop: 'registrant'
    label: "登记人",
    prop: "registrant",
  },
  {
    label: '登记日期',
    prop: 'createTime'
  }
])
const tableData = ref([])
const selectedRows = ref([])
const tableLoading = ref(false)
    label: "登记日期",
    prop: "createTime",
  },
]);
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
const data = reactive({
  searchForm: {
    searchText: '',
  },
})
const { searchForm } = toRefs(data)
const { receipt_payment_type } = proxy.useDict("receipt_payment_type")
});
const total = ref(0);
const { form: searchForm } = useFormData({
  searchText: undefined,
  receiptPaymentDate: [
    dayjs().startOf("month").format("YYYY-MM-DD"),
    dayjs().endOf("month").format("YYYY-MM-DD"),
  ],
  receiptPaymentDateStart: dayjs().startOf("month").format("YYYY-MM-DD"),
  receiptPaymentDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"),
});
const { receipt_payment_type } = proxy.useDict("receipt_payment_type");
const isShowSummarySon = ref(true);
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  receiptPaymentHistoryListPage({ ...searchForm.value, ...page }).then(res => {
    tableLoading.value = false
    tableData.value = res.records
    total.value = res.total
  })
}
  tableLoading.value = true;
  const { receiptPaymentDate, ...rest } = searchForm;
  receiptPaymentHistoryListPage({ ...rest, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
    total.value = res.total;
  });
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable1 = (param) => {
  return proxy.summarizeTable(param, ['receiptPaymentAmount'], {
  return proxy.summarizeTable(param, ["receiptPaymentAmount"], {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection
  selectedRows.value = selection;
};
const changeDateRange = (date) => {
  if (date) {
    searchForm.receiptPaymentDateStart = date[0];
    searchForm.receiptPaymentDateEnd = date[1];
    getList();
}
getList()
};
const clearRange = () => {
  searchForm.receiptPaymentDate = [];
  searchForm.receiptPaymentDateStart = undefined;
  searchForm.receiptPaymentDateEnd = undefined;
  getList();
};
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss"></style>
<style scoped lang="scss">
.table_list {
  margin-top: unset;
}
</style>
src/views/salesManagement/receiptPaymentLedger/index.vue
@@ -11,151 +11,237 @@
            clearable
            prefix-icon="Search"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
      </div>
    </div>
    <div style="display: flex">
      <div class="table_list">
        <el-table :data="tableData" border v-loading="tableLoading"
                  :row-key="row => row.id"
        <el-table
          :data="tableData"
          border
          v-loading="tableLoading"
          :row-key="(row) => row.id"
                  show-summary
                  :summary-method="summarizeMainTable"
                  @row-click = "rowClickMethod"
                  height="calc(100vh - 18.5em)">
          <el-table-column align="center" label="序号" type="index" width="60" />
          <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip/>
          <el-table-column label="开票金额(元)" prop="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber"/>
          <el-table-column label="回款金额(元)" prop="receiptPaymentAmount" show-overflow-tooltip :formatter="formattedNumber"/>
          <el-table-column label="未回款金额(元)" prop="unReceiptPaymentAmount" show-overflow-tooltip :formatter="formattedNumber"/>
          height="calc(100vh - 18.5em)"
        >
          <el-table-column
            align="center"
            label="序号"
            type="index"
            width="60"
          />
          <el-table-column
            label="客户名称"
            prop="customerName"
            show-overflow-tooltip
          />
          <el-table-column
            label="开票金额(元)"
            prop="invoiceTotal"
            show-overflow-tooltip
            :formatter="formattedNumber"
          />
          <el-table-column
            label="回款金额(元)"
            prop="receiptPaymentAmount"
            show-overflow-tooltip
            :formatter="formattedNumber"
          />
          <el-table-column
            label="应收金额(元)"
            prop="unReceiptPaymentAmount"
            show-overflow-tooltip
          >
            <template #default="{ row, column }">
              <el-text type="danger">
                {{ formattedNumber(row, column, row.unReceiptPaymentAmount) }}
              </el-text>
            </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" />
        <pagination
          v-show="total > 0"
          :total="total"
          layout="total, sizes, prev, pager, next, jumper"
          :page="page.current"
          :limit="page.size"
          @pagination="paginationChange"
        />
      </div>
      <div class="table_list">
        <el-table :data="receiptRecord" border
                  :row-key="row => row.id"
        <el-table
          :data="receiptRecord"
          border
          :row-key="(row) => row.id"
                  show-summary
                  :summary-method="summarizeMainTable1"
                  height="calc(100vh - 18.5em)">
          <el-table-column align="center" label="序号" type="index" width="60" />
          <el-table-column label="发生日期" prop="happenTime" show-overflow-tooltip/>
          <el-table-column label="开票金额(元)" prop="invoiceAmount" show-overflow-tooltip :formatter="formattedNumber"/>
          <el-table-column label="回款金额(元)" prop="receiptAmount" show-overflow-tooltip :formatter="formattedNumber"/>
          <el-table-column label="应收金额(元)" prop="unReceiptAmount" show-overflow-tooltip :formatter="formattedNumber"/>
          height="calc(100vh - 18.5em)"
        >
          <el-table-column
            align="center"
            label="序号"
            type="index"
            width="60"
          />
          <el-table-column
            label="发生日期"
            prop="happenTime"
            show-overflow-tooltip
          />
          <el-table-column
            label="开票金额(元)"
            prop="invoiceAmount"
            show-overflow-tooltip
            :formatter="formattedNumber"
          />
          <el-table-column
            label="回款金额(元)"
            prop="receiptAmount"
            show-overflow-tooltip
            :formatter="formattedNumber"
          />
          <el-table-column
            label="应收金额(元)"
            prop="unReceiptAmount"
            show-overflow-tooltip
          >
            <template #default="{ row, column }">
              <el-text type="danger">
                {{ formattedNumber(row, column, row.unReceiptAmount) }}
              </el-text>
            </template>
          </el-table-column>
        </el-table>
        <pagination v-show="recordTotal > 0" :total="recordTotal" layout="total, sizes, prev, pager, next, jumper" :page="recordPage.current"
                    :limit="recordPage.size" @pagination="recordPaginationChange" />
        <pagination
          v-show="recordTotal > 0"
          :total="recordTotal"
          layout="total, sizes, prev, pager, next, jumper"
          :page="recordPage.current"
          :limit="recordPage.size"
          @pagination="recordPaginationChange"
        />
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue'
import {
  invoiceLedgerSalesAccount,
} from "../../../api/salesManagement/invoiceLedger.js";
import {
  customerInteractions
} from "../../../api/salesManagement/receiptPayment.js";
import { ref } from "vue";
import { invoiceLedgerSalesAccount } from "../../../api/salesManagement/invoiceLedger.js";
import { customerInteractions } from "../../../api/salesManagement/receiptPayment.js";
import Pagination from "../../../components/PIMTable/Pagination.vue";
const { proxy } = getCurrentInstance()
const tableData = ref([])
const receiptRecord = ref([])
const tableLoading = ref(false)
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const receiptRecord = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
})
});
const recordPage = reactive({
  current: 1,
  size: 100,
})
const total = ref(0)
const recordTotal = ref(0)
});
const total = ref(0);
const recordTotal = ref(0);
const data = reactive({
  searchForm: {
    searchText: '',
    invoiceDate:''
  }
})
const customerId = ref('')
const { searchForm } = toRefs(data)
const originReceiptRecord = ref([])
    searchText: "",
    invoiceDate: "",
  },
});
const customerId = ref("");
const { searchForm } = toRefs(data);
const originReceiptRecord = ref([]);
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1
  getList()
}
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
  console.log('paginationChange', current,limit)
  console.log("paginationChange", current, limit);
  page.current = obj.page;
  page.size = obj.limit;
  getList()
}
  getList();
};
const getList = () => {
  tableLoading.value = true
  invoiceLedgerSalesAccount({...searchForm.value, ...page}).then(res => {
    tableLoading.value = false
  tableLoading.value = true;
  invoiceLedgerSalesAccount({ ...searchForm.value, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.data.records;
    total.value = res.data.total;
    if(tableData.value.length > 0) {
      recordPage.current = 1
      customerId.value = tableData.value[0].id
      recordPage.current = 1;
      customerId.value = tableData.value[0].id;
      receiptPaymentList(customerId.value);
    }
  })
}
  });
};
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// ä¸»è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, ['invoiceTotal', 'receiptPaymentAmount', 'unReceiptPaymentAmount'], {
  return proxy.summarizeTable(
    param,
    ["invoiceTotal", "receiptPaymentAmount", "unReceiptPaymentAmount"],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
    }
  );
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeMainTable1 = (param) => {
  var summarizeTable = proxy.summarizeTable(param, ['invoiceAmount', 'receiptAmount'], {
  var summarizeTable = proxy.summarizeTable(
    param,
    ["invoiceAmount", "receiptAmount"],
    {
    ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
    futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
  });
  console.log('summarizeTable',summarizeTable)
  // å–最后一行数据
  if(receiptRecord.value?.length > 0) {
    summarizeTable[summarizeTable.length - 1] = receiptRecord.value[receiptRecord.value.length - 1].unReceiptAmount.toFixed(2);
  }else {
    summarizeTable[summarizeTable.length - 1] = 0.00
  }
  return summarizeTable
  );
  // å–最后一行数据;
  if (receiptRecord.value?.length > 0) {
    const index = tableData.value.findIndex(
      (item) => item.id == customerId.value
    );
    summarizeTable[summarizeTable.length - 1] =
      tableData.value[index].unReceiptPaymentAmount.toFixed(2);
  } else {
    summarizeTable[summarizeTable.length - 1] = 0.0;
  }
  // const sb = tableData.findIndex((item) => item.id == customerId.value);
  // console.log(sb);
  return summarizeTable;
};
const receiptPaymentList = (id) => {
  const param = {
    customerId:id
  }
  console.log('param', param)
  customerInteractions(param).then(res => {
    customerId: id,
  };
  console.log("param", param);
  customerInteractions(param).then((res) => {
    originReceiptRecord.value = res.data;
    handlePagination({ page: 1, limit: recordPage.size });
    recordTotal.value = res.data.length;
  })
}
  });
};
// æ±‡æ¬¾è®°å½•列表分页
const recordPaginationChange = (pagination) => {
  handlePagination(pagination);
}
};
const rowClickMethod = (row) => {
  customerId.value = row.id;
  receiptPaymentList(customerId.value);
}
};
const handlePagination = ({ page, limit }) => {
  recordPage.current = page;
@@ -165,16 +251,13 @@
  const end = start + limit;
  receiptRecord.value = originReceiptRecord.value.slice(start, end);
}
};
getList()
getList();
</script>
<style scoped lang="scss">
.table_list {
  width: 50%;
}
</style>
src/views/system/user/index.vue
@@ -1,69 +1,209 @@
<template>
  <div class="app-container">
    <el-row :gutter="20" style="height: calc(100vh - 8em)">
      <splitpanes :horizontal="appStore.device === 'mobile'" class="default-theme">
      <splitpanes
        :horizontal="appStore.device === 'mobile'"
        class="default-theme"
      >
        <!--部门数据-->
        <pane size="16">
          <el-col style="padding: 10px">
            <div class="head-container">
              <el-input v-model="deptName" placeholder="请输入部门名称" clearable prefix-icon="Search" style="margin-bottom: 20px" />
              <el-input
                v-model="deptName"
                placeholder="请输入部门名称"
                clearable
                prefix-icon="Search"
                style="margin-bottom: 20px"
              />
            </div>
            <div class="head-container">
              <el-tree :data="deptOptions" :props="{ label: 'label', children: 'children' }" :expand-on-click-node="false" :filter-node-method="filterNode" ref="deptTreeRef" node-key="id" highlight-current default-expand-all @node-click="handleNodeClick" />
              <el-tree
                :data="deptOptions"
                :props="{ label: 'label', children: 'children' }"
                :expand-on-click-node="false"
                :filter-node-method="filterNode"
                ref="deptTreeRef"
                node-key="id"
                highlight-current
                default-expand-all
                @node-click="handleNodeClick"
              />
            </div>
          </el-col>
        </pane>
        <!--用户数据-->
        <pane size="84">
          <el-col style="padding: 10px">
            <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
            <el-form
              :model="queryParams"
              ref="queryRef"
              :inline="true"
              v-show="showSearch"
              label-width="68px"
            >
              <el-form-item label="登录账号" prop="userName">
                <el-input v-model="queryParams.userName" placeholder="请输入登录账号" clearable style="width: 240px" @keyup.enter="handleQuery" />
                <el-input
                  v-model="queryParams.userName"
                  placeholder="请输入登录账号"
                  clearable
                  style="width: 240px"
                  @keyup.enter="handleQuery"
                />
              </el-form-item>
              <el-form-item label="手机号码" prop="phonenumber">
                <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
                <el-input
                  v-model="queryParams.phonenumber"
                  placeholder="请输入手机号码"
                  clearable
                  style="width: 240px"
                  @keyup.enter="handleQuery"
                />
              </el-form-item>
              <el-form-item label="状态" prop="status">
                <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
                  <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                <el-select
                  v-model="queryParams.status"
                  placeholder="用户状态"
                  clearable
                  style="width: 240px"
                >
                  <el-option
                    v-for="dict in sys_normal_disable"
                    :key="dict.value"
                    :label="dict.label"
                    :value="dict.value"
                  />
                </el-select>
              </el-form-item>
              <el-form-item label="创建时间" style="width: 308px">
                <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
                <el-date-picker
                  v-model="dateRange"
                  value-format="YYYY-MM-DD"
                  type="daterange"
                  range-separator="-"
                  start-placeholder="开始日期"
                  end-placeholder="结束日期"
                ></el-date-picker>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                <el-button type="primary" icon="Search" @click="handleQuery"
                  >搜索</el-button
                >
                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
              </el-form-item>
            </el-form>
            <el-row :gutter="10" class="mb8">
              <el-col :span="1.5">
                <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
                <el-button
                  type="primary"
                  plain
                  icon="Plus"
                  @click="handleAdd"
                  v-hasPermi="['system:user:add']"
                  >新增</el-button
                >
              </el-col>
              <el-col :span="1.5">
                <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
                <el-button
                  type="success"
                  plain
                  icon="Edit"
                  :disabled="single"
                  @click="handleUpdate"
                  v-hasPermi="['system:user:edit']"
                  >修改</el-button
                >
              </el-col>
              <el-col :span="1.5">
                <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
                <el-button
                  type="danger"
                  plain
                  icon="Delete"
                  :disabled="multiple"
                  @click="handleDelete"
                  v-hasPermi="['system:user:remove']"
                  >删除</el-button
                >
              </el-col>
              <el-col :span="1.5">
                <el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
                <el-button
                  type="info"
                  plain
                  icon="Upload"
                  @click="handleImport"
                  v-hasPermi="['system:user:import']"
                  >导入</el-button
                >
              </el-col>
              <el-col :span="1.5">
                <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
                <el-button
                  type="warning"
                  plain
                  icon="Download"
                  @click="handleExport"
                  v-hasPermi="['system:user:export']"
                  >导出</el-button
                >
              </el-col>
              <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
              <right-toolbar
                v-model:showSearch="showSearch"
                @queryTable="getList"
                :columns="columns"
              ></right-toolbar>
            </el-row>
            <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
            <el-table
              v-loading="loading"
              :data="userList"
              @selection-change="handleSelectionChange"
            >
              <el-table-column type="selection" width="50" align="center" />
              <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
              <el-table-column label="登录账号" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
              <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
              <el-table-column label="部门" align="center" key="deptNames" prop="deptNames" v-if="columns[3].visible" :show-overflow-tooltip="true" />
              <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
              <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
              <el-table-column
                label="用户编号"
                align="center"
                key="userId"
                prop="userId"
                v-if="columns[0].visible"
              />
              <el-table-column
                label="登录账号"
                align="center"
                key="userName"
                prop="userName"
                v-if="columns[1].visible"
                :show-overflow-tooltip="true"
              />
              <el-table-column
                label="用户昵称"
                align="center"
                key="nickName"
                prop="nickName"
                v-if="columns[2].visible"
                :show-overflow-tooltip="true"
              />
              <el-table-column
                label="部门"
                align="center"
                key="deptNames"
                prop="deptNames"
                v-if="columns[3].visible"
                :show-overflow-tooltip="true"
              />
              <el-table-column
                label="手机号码"
                align="center"
                key="phonenumber"
                prop="phonenumber"
                v-if="columns[4].visible"
                width="120"
              />
              <el-table-column
                label="状态"
                align="center"
                key="status"
                v-if="columns[5].visible"
              >
                <template #default="scope">
                  <el-switch
                    v-model="scope.row.status"
@@ -73,29 +213,86 @@
                  ></el-switch>
                </template>
              </el-table-column>
              <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
              <el-table-column
                label="创建时间"
                align="center"
                prop="createTime"
                v-if="columns[6].visible"
                width="160"
              >
                <template #default="scope">
                  <span>{{ parseTime(scope.row.createTime) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
              <el-table-column
                label="操作"
                align="center"
                width="150"
                class-name="small-padding fixed-width"
              >
                <template #default="scope">
                  <el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
                    <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
                  <el-tooltip
                    content="修改"
                    placement="top"
                    v-if="scope.row.userId !== 1"
                  >
                    <el-button
                      link
                      type="primary"
                      icon="Edit"
                      @click="handleUpdate(scope.row)"
                      v-hasPermi="['system:user:edit']"
                    ></el-button>
                  </el-tooltip>
                  <el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
                    <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
                  <el-tooltip
                    content="删除"
                    placement="top"
                    v-if="scope.row.userId !== 1"
                  >
                    <el-button
                      link
                      type="primary"
                      icon="Delete"
                      @click="handleDelete(scope.row)"
                      v-hasPermi="['system:user:remove']"
                    ></el-button>
                  </el-tooltip>
                  <el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
                    <el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
                  <el-tooltip
                    content="重置密码"
                    placement="top"
                    v-if="scope.row.userId !== 1"
                  >
                    <el-button
                      link
                      type="primary"
                      icon="Key"
                      @click="handleResetPwd(scope.row)"
                      v-hasPermi="['system:user:resetPwd']"
                    ></el-button>
                  </el-tooltip>
                  <el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
                    <el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
                  <el-tooltip
                    content="分配角色"
                    placement="top"
                    v-if="scope.row.userId !== 1"
                  >
                    <el-button
                      link
                      type="primary"
                      icon="CircleCheck"
                      @click="handleAuthRole(scope.row)"
                      v-hasPermi="['system:user:edit']"
                    ></el-button>
                  </el-tooltip>
                </template>
              </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
            <pagination
              v-show="total > 0"
              :total="total"
              v-model:page="queryParams.pageNum"
              v-model:limit="queryParams.pageSize"
              @pagination="getList"
            />
          </el-col>
        </pane>
      </splitpanes>
@@ -107,7 +304,11 @@
        <el-row>
          <el-col :span="12">
            <el-form-item label="用户昵称" prop="nickName">
              <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
              <el-input
                v-model="form.nickName"
                placeholder="请输入用户昵称"
                maxlength="30"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -118,31 +319,58 @@
                  :render-after-expand="false"
                  show-checkbox
                  multiple
                  placeholder="请选择归属公司" />
                placeholder="请选择归属公司"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="手机号码" prop="phonenumber">
              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
              <el-input
                v-model="form.phonenumber"
                placeholder="请输入手机号码"
                maxlength="11"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="邮箱" prop="email">
              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
              <el-input
                v-model="form.email"
                placeholder="请输入邮箱"
                maxlength="50"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item v-if="form.userId == undefined" label="登录账号" prop="userName">
              <el-input v-model="form.userName" placeholder="请输入登录账号" maxlength="30" />
            <el-form-item
              v-if="form.userId == undefined"
              label="登录账号"
              prop="userName"
            >
              <el-input
                v-model="form.userName"
                placeholder="请输入登录账号"
                maxlength="30"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
            <el-form-item
              v-if="form.userId == undefined"
              label="用户密码"
              prop="password"
            >
              <el-input
                v-model="form.password"
                placeholder="请输入用户密码"
                type="password"
                maxlength="20"
                show-password
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -150,14 +378,24 @@
          <el-col :span="12">
            <el-form-item label="用户性别">
              <el-select v-model="form.sex" placeholder="请选择">
                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
                <el-option
                  v-for="dict in sys_user_sex"
                  :key="dict.value"
                  :label="dict.label"
                  :value="dict.value"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="状态">
              <el-radio-group v-model="form.status">
                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
                <el-radio
                  v-for="dict in sys_normal_disable"
                  :key="dict.value"
                  :value="dict.value"
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item>
          </el-col>
@@ -166,14 +404,26 @@
          <el-col :span="12">
            <el-form-item label="岗位">
              <el-select v-model="form.postIds" multiple placeholder="请选择">
                <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1"></el-option>
                <el-option
                  v-for="item in postOptions"
                  :key="item.postId"
                  :label="item.postName"
                  :value="item.postId"
                  :disabled="item.status == 1"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="角色">
              <el-select v-model="form.roleIds" multiple placeholder="请选择">
                <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
                <el-option
                  v-for="item in roleOptions"
                  :key="item.roleId"
                  :label="item.roleName"
                  :value="item.roleId"
                  :disabled="item.status == 1"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
@@ -181,7 +431,11 @@
        <el-row>
          <el-col :span="24">
            <el-form-item label="备注">
              <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
              <el-input
                v-model="form.remark"
                type="textarea"
                placeholder="请输入内容"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
@@ -195,17 +449,41 @@
    </el-dialog>
    <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
      <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
    <el-dialog
      :title="upload.title"
      v-model="upload.open"
      width="400px"
      append-to-body
    >
      <el-upload
        ref="uploadRef"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        drag
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip text-center">
            <div class="el-upload__tip">
              <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
              <el-checkbox
                v-model="upload.updateSupport"
              />是否更新已经存在的用户数据
            </div>
            <span>仅允许导入xls、xlsx格式文件。</span>
            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
            <el-link
              type="primary"
              :underline="false"
              style="font-size: 12px; vertical-align: baseline"
              @click="importTemplate"
              >下载模板</el-link
            >
          </div>
        </template>
      </el-upload>
@@ -220,33 +498,45 @@
</template>
<script setup name="User">
import { getToken } from "@/utils/auth"
import useAppStore from '@/store/modules/app'
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
import { getToken } from "@/utils/auth";
import useAppStore from "@/store/modules/app";
import {
  changeUserStatus,
  listUser,
  resetUserPwd,
  delUser,
  getUser,
  updateUser,
  addUser,
  deptTreeSelect,
} from "@/api/system/user";
import { Splitpanes, Pane } from "splitpanes";
import "splitpanes/dist/splitpanes.css";
const router = useRouter()
const appStore = useAppStore()
const { proxy } = getCurrentInstance()
const { sys_normal_disable, sys_user_sex } = proxy.useDict("sys_normal_disable", "sys_user_sex")
const router = useRouter();
const appStore = useAppStore();
const { proxy } = getCurrentInstance();
const { sys_normal_disable, sys_user_sex } = proxy.useDict(
  "sys_normal_disable",
  "sys_user_sex"
);
const userList = ref([])
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
const dateRange = ref([])
const deptName = ref("")
const deptOptions = ref(undefined)
const enabledDeptOptions = ref(undefined)
const initPassword = ref(undefined)
const postOptions = ref([])
const roleOptions = ref([])
const userList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const deptName = ref("");
const deptOptions = ref(undefined);
const enabledDeptOptions = ref(undefined);
const initPassword = ref(undefined);
const postOptions = ref([]);
const roleOptions = ref([]);
/*** ç”¨æˆ·å¯¼å…¥å‚æ•° */
const upload = reactive({
  // æ˜¯å¦æ˜¾ç¤ºå¼¹å‡ºå±‚(用户导入)
@@ -260,8 +550,8 @@
  // è®¾ç½®ä¸Šä¼ çš„请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
})
  url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData",
});
// åˆ—显隐信息
const columns = ref([
  { key: 0, label: `用户编号`, visible: true },
@@ -270,8 +560,8 @@
  { key: 3, label: `部门`, visible: true },
  { key: 4, label: `手机号码`, visible: true },
  { key: 5, label: `状态`, visible: true },
  { key: 6, label: `创建时间`, visible: true }
])
  { key: 6, label: `创建时间`, visible: true },
]);
const data = reactive({
  form: {},
@@ -281,136 +571,188 @@
    userName: undefined,
    phonenumber: undefined,
    status: undefined,
    deptId: undefined
    deptId: undefined,
  },
  rules: {
    userName: [{ required: true, message: "登录账号不能为空", trigger: "blur" }, { min: 2, max: 20, message: "登录账号长度必须介于 2 å’Œ 20 ä¹‹é—´", trigger: "blur" }],
    nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
    userName: [
      { required: true, message: "登录账号不能为空", trigger: "blur" },
      {
        min: 2,
        max: 20,
        message: "登录账号长度必须介于 2 å’Œ 20 ä¹‹é—´",
        trigger: "blur",
      },
    ],
    nickName: [
      { required: true, message: "用户昵称不能为空", trigger: "blur" },
    ],
    deptIds: [{ required: true, message: "公司不能为空", trigger: "change" }],
    password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 å’Œ 20 ä¹‹é—´", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
    email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
    phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
  }
})
    password: [
      { required: true, message: "用户密码不能为空", trigger: "blur" },
      {
        min: 5,
        max: 20,
        message: "用户密码长度必须介于 5 å’Œ 20 ä¹‹é—´",
        trigger: "blur",
      },
      {
        pattern: /^[^<>"'|\\]+$/,
        message: "不能包含非法字符:< > \" ' \\\ |",
        trigger: "blur",
      },
    ],
    email: [
      {
        type: "email",
        message: "请输入正确的邮箱地址",
        trigger: ["blur", "change"],
      },
    ],
    phonenumber: [
      {
        pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
        message: "请输入正确的手机号码",
        trigger: "blur",
      },
    ],
  },
});
const { queryParams, form, rules } = toRefs(data)
const { queryParams, form, rules } = toRefs(data);
/** é€šè¿‡æ¡ä»¶è¿‡æ»¤èŠ‚ç‚¹  */
const filterNode = (value, data) => {
  if (!value) return true
  return data.label.indexOf(value) !== -1
}
  if (!value) return true;
  return data.label.indexOf(value) !== -1;
};
/** æ ¹æ®åç§°ç­›é€‰éƒ¨é—¨æ ‘ */
watch(deptName, val => {
  proxy.$refs["deptTreeRef"].filter(val)
})
watch(deptName, (val) => {
  proxy.$refs["deptTreeRef"].filter(val);
});
/** æŸ¥è¯¢ç”¨æˆ·åˆ—表 */
function getList() {
  loading.value = true
  listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(res => {
    loading.value = false
    userList.value = res.rows
    total.value = res.total
  })
  loading.value = true;
  listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(
    (res) => {
      loading.value = false;
      userList.value = res.rows;
      total.value = res.total;
    }
  );
}
/** æŸ¥è¯¢éƒ¨é—¨ä¸‹æ‹‰æ ‘结构 */
function getDeptTree() {
  deptTreeSelect().then(response => {
    deptOptions.value = response.data
    enabledDeptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
  })
  deptTreeSelect().then((response) => {
    deptOptions.value = response.data;
    enabledDeptOptions.value = filterDisabledDept(
      JSON.parse(JSON.stringify(response.data))
    );
  });
}
/** è¿‡æ»¤ç¦ç”¨çš„部门 */
function filterDisabledDept(deptList) {
  return deptList.filter(dept => {
  return deptList.filter((dept) => {
    if (dept.disabled) {
      return false
      return false;
    }
    if (dept.children && dept.children.length) {
      dept.children = filterDisabledDept(dept.children)
      dept.children = filterDisabledDept(dept.children);
    }
    return true
  })
    return true;
  });
}
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.deptId = data.id
  handleQuery()
  queryParams.value.deptId = data.id;
  handleQuery();
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
function handleQuery() {
  queryParams.value.pageNum = 1
  getList()
  queryParams.value.pageNum = 1;
  getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
function resetQuery() {
  dateRange.value = []
  proxy.resetForm("queryRef")
  queryParams.value.deptId = undefined
  proxy.$refs.deptTreeRef.setCurrentKey(null)
  handleQuery()
  dateRange.value = [];
  proxy.resetForm("queryRef");
  queryParams.value.deptId = undefined;
  proxy.$refs.deptTreeRef.setCurrentKey(null);
  handleQuery();
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
function handleDelete(row) {
  const userIds = row.userId || ids.value
  proxy.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
    return delUser(userIds)
  }).then(() => {
    getList()
    proxy.$modal.msgSuccess("删除成功")
  }).catch(() => {})
  const userIds = row.userId || ids.value;
  proxy.$modal
    .confirm('是否确认删除用户编号为"' + userIds + '"的数据项?')
    .then(function () {
      return delUser(userIds);
    })
    .then(() => {
      getList();
      proxy.$modal.msgSuccess("删除成功");
    })
    .catch(() => {});
}
/** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
function handleExport() {
  proxy.download("system/user/export", {
  proxy.download(
    "system/user/export",
    {
    ...queryParams.value,
  },`user_${new Date().getTime()}.xlsx`)
    },
    `user_${new Date().getTime()}.xlsx`
  );
}
/** ç”¨æˆ·çŠ¶æ€ä¿®æ”¹  */
function handleStatusChange(row) {
  let text = row.status === "0" ? "启用" : "停用"
  proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
    return changeUserStatus(row.userId, row.status)
  }).then(() => {
    proxy.$modal.msgSuccess(text + "成功")
  }).catch(function () {
    row.status = row.status === "0" ? "1" : "0"
  let text = row.status === "0" ? "启用" : "停用";
  proxy.$modal
    .confirm('确认要"' + text + '""' + row.userName + '"用户吗?')
    .then(function () {
      return changeUserStatus(row.userId, row.status);
  })
    .then(() => {
      proxy.$modal.msgSuccess(text + "成功");
    })
    .catch(function () {
      row.status = row.status === "0" ? "1" : "0";
    });
}
/** æ›´å¤šæ“ä½œ */
function handleCommand(command, row) {
  switch (command) {
    case "handleResetPwd":
      handleResetPwd(row)
      break
      handleResetPwd(row);
      break;
    case "handleAuthRole":
      handleAuthRole(row)
      break
      handleAuthRole(row);
      break;
    default:
      break
      break;
  }
}
/** è·³è½¬è§’色分配 */
function handleAuthRole(row) {
  const userId = row.userId
  router.push("/system/user-auth/role/" + userId)
  const userId = row.userId;
  router.push("/system/user-auth/role/" + userId);
}
/** é‡ç½®å¯†ç æŒ‰é’®æ“ä½œ */
function handleResetPwd(row) {
  proxy.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
  proxy
    .$prompt('请输入"' + row.userName + '"的新密码', "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    closeOnClickModal: false,
@@ -418,52 +760,63 @@
    inputErrorMessage: "用户密码长度必须介于 5 å’Œ 20 ä¹‹é—´",
    inputValidator: (value) => {
      if (/<|>|"|'|\||\\/.test(value)) {
        return "不能包含非法字符:< > \" ' \\\ |"
          return "不能包含非法字符:< > \" ' \\\ |";
      }
    },
  }).then(({ value }) => {
    resetUserPwd(row.userId, value).then(response => {
      proxy.$modal.msgSuccess("修改成功,新密码是:" + value)
    })
  }).catch(() => {})
    .then(({ value }) => {
      resetUserPwd(row.userId, value).then((response) => {
        proxy.$modal.msgSuccess("修改成功,新密码是:" + value);
      });
    })
    .catch(() => {});
}
/** é€‰æ‹©æ¡æ•°  */
function handleSelectionChange(selection) {
  ids.value = selection.map(item => item.userId)
  single.value = selection.length != 1
  multiple.value = !selection.length
  ids.value = selection.map((item) => item.userId);
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}
/** å¯¼å…¥æŒ‰é’®æ“ä½œ */
function handleImport() {
  upload.title = "用户导入"
  upload.open = true
  upload.title = "用户导入";
  upload.open = true;
}
/** ä¸‹è½½æ¨¡æ¿æ“ä½œ */
function importTemplate() {
  proxy.download("system/user/importTemplate", {
  }, `user_template_${new Date().getTime()}.xlsx`)
  proxy.download(
    "system/user/importTemplate",
    {},
    `user_template_${new Date().getTime()}.xlsx`
  );
}
/**文件上传中处理 */
const handleFileUploadProgress = (event, file, fileList) => {
  upload.isUploading = true
}
  upload.isUploading = true;
};
/** æ–‡ä»¶ä¸Šä¼ æˆåŠŸå¤„ç† */
const handleFileSuccess = (response, file, fileList) => {
  upload.open = false
  upload.isUploading = false
  proxy.$refs["uploadRef"].handleRemove(file)
  proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
  getList()
}
  upload.open = false;
  upload.isUploading = false;
  proxy.$refs["uploadRef"].handleRemove(file);
  proxy.$alert(
    "<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
      response.msg +
      "</div>",
    "导入结果",
    { dangerouslyUseHTMLString: true }
  );
  getList();
};
/** æäº¤ä¸Šä¼ æ–‡ä»¶ */
function submitFileForm() {
  proxy.$refs["uploadRef"].submit()
  proxy.$refs["uploadRef"].submit();
}
/** é‡ç½®æ“ä½œè¡¨å• */
@@ -480,67 +833,67 @@
    status: "0",
    remark: undefined,
    postIds: [],
    roleIds: []
  }
  proxy.resetForm("userRef")
    roleIds: [],
  };
  proxy.resetForm("userRef");
}
/** å–消按钮 */
function cancel() {
  open.value = false
  reset()
  open.value = false;
  reset();
}
/** æ–°å¢žæŒ‰é’®æ“ä½œ */
function handleAdd() {
  reset()
  getUser().then(response => {
    postOptions.value = response.posts
    roleOptions.value = response.roles
    open.value = true
    title.value = "添加用户"
    form.value.password = initPassword.value
  })
  reset();
  getUser().then((response) => {
    postOptions.value = response.posts;
    roleOptions.value = response.roles;
    open.value = true;
    title.value = "添加用户";
    form.value.password = initPassword.value;
  });
}
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
function handleUpdate(row) {
  reset()
  const userId = row.userId || ids.value
  getUser(userId).then(response => {
    form.value = response.data
    postOptions.value = response.posts
    roleOptions.value = response.roles
    form.value.postIds = response.postIds
    form.value.roleIds = response.roleIds
    form.value.deptIds = response.deptIds
    open.value = true
    title.value = "修改用户"
    form.password = ""
  })
  reset();
  const userId = row.userId || ids.value;
  getUser(userId).then((response) => {
    form.value = response.data;
    postOptions.value = response.posts;
    roleOptions.value = response.roles;
    form.value.postIds = response.postIds;
    form.value.roleIds = response.roleIds;
    form.value.deptIds = response.deptIds;
    open.value = true;
    title.value = "修改用户";
    form.password = "";
  });
}
/** æäº¤æŒ‰é’® */
function submitForm() {
  proxy.$refs["userRef"].validate(valid => {
  proxy.$refs["userRef"].validate((valid) => {
    if (valid) {
      if (form.value.userId != undefined) {
        updateUser(form.value).then(response => {
          proxy.$modal.msgSuccess("修改成功")
          open.value = false
          getList()
        })
        updateUser(form.value).then((response) => {
          proxy.$modal.msgSuccess("修改成功");
          open.value = false;
          getList();
        });
      } else {
        addUser(form.value).then(response => {
          proxy.$modal.msgSuccess("新增成功")
          open.value = false
          getList()
        })
        addUser(form.value).then((response) => {
          proxy.$modal.msgSuccess("新增成功");
          open.value = false;
          getList();
        });
      }
    }
  })
  });
}
getDeptTree()
getList()
getDeptTree();
getList();
</script>
vite.config.js
@@ -2,12 +2,14 @@
import path from 'path'
import createVitePlugins from './vite/plugins'
const baseUrl = 'http://127.0.0.1:7003' // åŽç«¯æŽ¥å£
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
  const env = loadEnv(mode, process.cwd())
  const { VITE_APP_ENV } = env
  const baseUrl = VITE_APP_ENV == 'development'
    ? 'http://192.168.10.2:7003' // å¼€å‘环境后端接口
    : 'http://114.132.189.42:7004' // ç”Ÿäº§çŽ¯å¢ƒåŽç«¯æŽ¥å£
  return {
    // éƒ¨ç½²ç”Ÿäº§çŽ¯å¢ƒå’Œå¼€å‘çŽ¯å¢ƒä¸‹çš„URL。
    // é»˜è®¤æƒ…况下,vite ä¼šå‡è®¾ä½ çš„应用是被部署在一个域名的根路径上