feat(芯导): 仓储库存管理/协同审批会议提醒/采购付款查询导出/营销回款流水导出/生产设备补字段

- 仓储物流:库存管理改为 4 个 tab(实时库存/变动明细/库存盘点/库存时间设置);入库加登记人、出库加领用数量;库存预警支持生成采购建议/滞销处理提示
- 协同办公:请假管理改名请假审批、新增合同审批;修复会议纪要加载、新增会议提醒
- 采购管理:开票台账支持发票日期/金额查询;回款流水新增导出
- 营销管理:开票台账支持发票日期/客户/金额查询
- 生产管控:生产订单加产品名称/项目名称/排产数量;生产派工加生产要求/完成期限
- 设备管理:设备保养加保养周期/保养内容;检定记录加下次检定日期
已修改22个文件
已添加5个文件
899 ■■■■■ 文件已修改
src/api/inventoryManagement/stockTaking.js 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockWarningLedger.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/meetingBoard/index.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/meetingManagement/index.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/summary/index.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/calibration/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/PlanForm.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/dispatchLog/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/issueManagement/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockCenter/index.vue 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockMovement/index.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockTaking/index.vue 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockTimeSetting/index.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockWarningLedger/index.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentHistory/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/components/formDia.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockTaking.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
import request from "@/utils/request";
// åº“存盘点-分页
export const getStockTakingPage = (params) => {
  return request({ url: "/stockTaking/listPage", method: "get", params });
};
// åº“存盘点-新增
export const addStockTaking = (data) => {
  return request({ url: "/stockTaking", method: "post", data });
};
// åº“存盘点-修改
export const updateStockTaking = (data) => {
  return request({ url: "/stockTaking", method: "put", data });
};
// åº“存盘点-删除
export const delStockTaking = (ids) => {
  return request({ url: "/stockTaking/" + ids.join(","), method: "delete" });
};
// åº“存时间设置-列表
export const getStockTimeSettingList = () => {
  return request({ url: "/stockTimeSetting/list", method: "get" });
};
// åº“存时间设置-新增
export const addStockTimeSetting = (data) => {
  return request({ url: "/stockTimeSetting", method: "post", data });
};
// åº“存时间设置-修改
export const updateStockTimeSetting = (data) => {
  return request({ url: "/stockTimeSetting", method: "put", data });
};
// åº“存时间设置-删除
export const delStockTimeSetting = (ids) => {
  return request({ url: "/stockTimeSetting/" + ids.join(","), method: "delete" });
};
src/api/inventoryManagement/stockWarningLedger.js
@@ -8,3 +8,11 @@
    params,
  });
};
// ç”Ÿæˆé‡‡è´­å»ºè®® / æ»žé”€å¤„理提示
export const generateSuggestion = (data) => {
  return request({
    url: "/customStorageWarning/generateSuggestion",
    method: "post",
    data,
  });
};
src/views/collaborativeApproval/approvalProcess/index.vue
@@ -3,12 +3,13 @@
    <!-- æ ‡ç­¾é¡µåˆ‡æ¢ä¸åŒçš„审批类型 -->
    <el-tabs v-if="!fixedApproveType" v-model="activeTab" @tab-change="handleTabChange" class="approval-tabs">
      <el-tab-pane label="自由协同审批" name="1"></el-tab-pane>
      <el-tab-pane label="请假管理" name="2"></el-tab-pane>
      <el-tab-pane label="请假审批" name="2"></el-tab-pane>
      <el-tab-pane label="销售审批" name="3"></el-tab-pane>
      <el-tab-pane label="报销审批" name="4"></el-tab-pane>
      <el-tab-pane label="采购审批" name="5"></el-tab-pane>
      <el-tab-pane label="报价审批" name="6"></el-tab-pane>
      <el-tab-pane label="出库审批" name="7"></el-tab-pane>
      <el-tab-pane label="合同审批" name="8"></el-tab-pane>
    </el-tabs>
    
    <div class="search_form">
@@ -301,12 +302,13 @@
  const nameMap = {
    0: "自由协同审批表",
    1: "自由协同审批表",
    2: "请假管理审批表",
    2: "请假审批表",
    3: "销售合同审批表",
    4: "报销管理审批表",
    5: "采购计划审批表",
    6: "报价审批表",
    7: "出库审批表",
    8: "合同审批表",
  }
  const fileName = nameMap[type] || nameMap[0]
  proxy.download(url, {}, `${fileName}.xlsx`)
src/views/collaborativeApproval/meetingBoard/index.vue
@@ -165,7 +165,13 @@
  meetings.value = resp2.data.map(item => {
    return {
      ...item,
      participants: JSON.parse(item.participants)
      participants: (() => {
        if (Array.isArray(item.participants)) return item.participants
        const s = String(item.participants || '').trim()
        if (!s) return []
        if (s.startsWith('[')) { try { return JSON.parse(s) } catch (e) { return [] } }
        return s.split(',').map(v => v.trim()).filter(Boolean)
      })()
    }
  })
  console.log('会议看板页面加载完成')
src/views/collaborativeApproval/meetingManagement/index.vue
@@ -1,5 +1,18 @@
<template>
  <div class="app-container">
    <!-- ç«™å†…提醒横幅:即将开始的会议 -->
    <el-alert
      v-if="upcomingMeetings.length"
      class="remind-banner"
      type="warning"
      :closable="false"
      show-icon
    >
      <template #title>
        ä¼šè®®æé†’:{{ upcomingText }}
      </template>
    </el-alert>
    <div class="tabs-wrapper">
      <el-tabs
        v-model="activeTab"
@@ -24,7 +37,10 @@
</template>
<script setup>
import { ref, computed } from 'vue'
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { ElNotification } from 'element-plus'
import dayjs from 'dayjs'
import { getMeetingPublish } from '@/api/collaborativeApproval/meeting.js'
import MeetSetting from '../notificationManagement/meetSetting/index.vue'
import MeetIndex from '../notificationManagement/meetIndex/index.vue'
import MeetApplication from '../notificationManagement/meetApplication/index.vue'
@@ -48,9 +64,100 @@
function handleTabChange(name) {
  activeTab.value = name
}
/* ==================== ä¼šè®®æé†’(站内 + æµè§ˆå™¨/手机端弹窗) ==================== */
const REMIND_WINDOW_MIN = 30 // ä¼šè®®å¼€å§‹å‰ 30 åˆ†é’Ÿå†…提醒
const REMIND_STORAGE_KEY = 'meeting_remind_sent'
const POLL_INTERVAL = 60 * 1000 // æ¯ 60 ç§’检查一次
const upcomingMeetings = ref([])
let remindTimer = null
const getSentMap = () => {
  try {
    return JSON.parse(localStorage.getItem(REMIND_STORAGE_KEY) || '{}')
  } catch (e) {
    return {}
  }
}
const markSent = (key) => {
  const m = getSentMap()
  m[key] = Date.now()
  // åªä¿ç•™æœ€è¿‘ 200 æ¡ï¼Œé¿å… localStorage æ— é™å¢žé•¿
  const entries = Object.entries(m).sort((a, b) => b[1] - a[1]).slice(0, 200)
  localStorage.setItem(REMIND_STORAGE_KEY, JSON.stringify(Object.fromEntries(entries)))
}
// è®¡ç®—会议开始时间(兼容 startTime ä¸º datetime / çº¯æ—¶é—´ä¸¤ç§æ ¼å¼ï¼‰
const parseStart = (m) => {
  const raw = m.startTime
  if (!raw) return null
  const s = String(raw)
  if (s.length > 10) return dayjs(s)
  if (!m.meetingDate) return null
  return dayjs(`${m.meetingDate} ${s}`)
}
const checkRemind = async () => {
  try {
    const resp = await getMeetingPublish({ current: 1, size: 100 })
    const records = (resp && resp.data && resp.data.records) || []
    const now = dayjs()
    const sent = getSentMap()
    const upcoming = []
    records.forEach((m) => {
      const start = parseStart(m)
      if (!start || !start.isValid()) return
      const diffMin = start.diff(now, 'minute', true)
      // åªæé†’「即将开始」:0 ~ 30 åˆ†é’Ÿ
      if (diffMin < 0 || diffMin > REMIND_WINDOW_MIN) return
      const flagKey = `${m.id}_${start.format('YYYYMMDDHHmm')}`
      upcoming.push({ title: m.title || '会议', start, diffMin })
      if (sent[flagKey]) return
      markSent(flagKey)
      ElNotification({
        title: '会议提醒',
        message: `【${m.title || '会议'}】将于 ${start.format('HH:mm')} å¼€å§‹${
          diffMin <= 1 ? '(即将开始)' : `(约 ${Math.round(diffMin)} åˆ†é’ŸåŽï¼‰`
        }`,
        type: 'warning',
        duration: 15000,
        position: 'bottom-right'
      })
    })
    upcoming.sort((a, b) => a.start.valueOf() - b.start.valueOf())
    upcomingMeetings.value = upcoming
  } catch (e) {
    // æé†’失败不影响主流程
  }
}
const upcomingText = computed(() =>
  upcomingMeetings.value
    .map((x) => `${x.title}(${x.start.format('MM-DD HH:mm')})`)
    .join(';')
)
onMounted(() => {
  checkRemind()
  remindTimer = setInterval(checkRemind, POLL_INTERVAL)
})
onUnmounted(() => {
  if (remindTimer) {
    clearInterval(remindTimer)
    remindTimer = null
  }
})
</script>
<style scoped lang="scss">
.remind-banner {
  margin-bottom: 12px;
}
.tabs-wrapper {
  margin-bottom: 10px;
@@ -60,4 +167,3 @@
  min-height: 400px;
}
</style>
src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue
@@ -232,12 +232,12 @@
  loading.value = true
  let resp = await getExamineList({...searchForm, ...queryParams})
  approvalList.value = resp.data.records.map(it => {
    let room = roomEnum.value.find(room => it.roomId === room.id)
    it.location = `${room.name}(${room.location})`
    let staffs = JSON.parse(it.participants)
    it.staffCount = staffs.size
    const room = (roomEnum.value || []).find(r => r.id === it.roomId)
    it.location = room ? `${room.name}(${room.location})` : (it.location || '-')
    let staffs = []; if (Array.isArray(it.participants)) { staffs = it.participants } else if (it.participants) { const ps = String(it.participants).trim(); if (ps.startsWith('[')) { try { staffs = JSON.parse(ps) } catch (e) { staffs = [] } } else { staffs = ps.split(',').map(v => v.trim()).filter(Boolean) } }; if (!Array.isArray(staffs)) staffs = []; staffs = staffs.map(v => String(v));
    it.staffCount = staffs.length
    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
    it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => {
    it.participants = (staffList.value || []).filter(staff => staffs.some(id => String(id) === String(staff.id))).map(staff => {
      return {
        id: staff.id,
        name: `${staff.staffName}(${staff.postJob})`
src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue
@@ -230,13 +230,13 @@
  loading.value = true
  let resp = await getMeetingPublish({...searchForm, ...queryParams})
  approvalList.value = resp.data.records.map(it => {
    let room = roomEnum.value.find(room => it.roomId === room.id)
    it.location = `${room.name}(${room.location})`
    let staffs = JSON.parse(it.participants)
    it.staffCount = staffs.size
    const room = (roomEnum.value || []).find(r => r.id === it.roomId)
    it.location = room ? `${room.name}(${room.location})` : (it.location || '-')
    let staffs = []; if (Array.isArray(it.participants)) { staffs = it.participants } else if (it.participants) { const ps = String(it.participants).trim(); if (ps.startsWith('[')) { try { staffs = JSON.parse(ps) } catch (e) { staffs = [] } } else { staffs = ps.split(',').map(v => v.trim()).filter(Boolean) } }; if (!Array.isArray(staffs)) staffs = []; staffs = staffs.map(v => String(v));
    it.staffCount = staffs.length
    it.status = it.publishStatus
    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
    it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => {
    it.participants = (staffList.value || []).filter(staff => staffs.some(id => String(id) === String(staff.id))).map(staff => {
      return {
        id: staff.id,
        name: `${staff.staffName}(${staff.postJob})`
src/views/collaborativeApproval/notificationManagement/summary/index.vue
@@ -204,24 +204,48 @@
// æŸ¥è¯¢æ•°æ®
const getList = async () => {
  loading.value = true
  let resp = await getMeetingPublish({ ...searchForm, ...queryParams })
  meetingList.value = resp.data.records.map(it => {
    let room = roomEnum.value.find(room => it.roomId === room.id)
    it.location = `${room.name}(${room.location})`
    let staffs = JSON.parse(it.participants)
    it.staffCount = staffs.size
    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
    it.participants = staffList.value.filter(staff => staffs.some(id => id === staff.id)).map(staff => {
      return {
        id: staff.id,
        name: `${staff.staffName}(${staff.postJob})`
  try {
    const resp = await getMeetingPublish({ ...searchForm, ...queryParams })
    const records = resp && resp.data && resp.data.records ? resp.data.records : []
    meetingList.value = records.map(it => {
      const room = (roomEnum.value || []).find(r => r.id === it.roomId)
      it.location = room ? `${room.name}(${room.location})` : (it.location || '—')
      let staffIds = []
      const rawParticipants = it.participants
      if (Array.isArray(rawParticipants)) {
        staffIds = rawParticipants
      } else if (rawParticipants) {
        const s = String(rawParticipants).trim()
        if (s.startsWith('[')) {
          try {
            staffIds = JSON.parse(s)
          } catch (e) {
            staffIds = []
      }
    })
        } else {
          // å…¼å®¹ "130,131,132" é€—号分隔格式
          staffIds = s.split(',').map(v => v.trim()).filter(Boolean)
        }
      }
      if (!Array.isArray(staffIds)) staffIds = []
      staffIds = staffIds.map(v => String(v))
      it.staffCount = staffIds.length
      const s = it.startTime ? dayjs(it.startTime).format('HH:mm:ss') : ''
      const e2 = it.endTime ? dayjs(it.endTime).format('HH:mm:ss') : ''
      it.meetingTime = `${it.meetingDate || ''} ${s} ~ ${e2}`.trim()
      it.participants = (staffList.value || [])
        .filter(staff => staffIds.some(id => String(id) === String(staff.id)))
        .map(staff => ({ id: staff.id, name: `${staff.staffName}(${staff.postJob})` }))
    return it
  })
  total.value = resp.data.total
    total.value = (resp && resp.data && resp.data.total) || 0
  } catch (err) {
    console.error('会议纪要列表加载失败', err)
    meetingList.value = []
    total.value = 0
  } finally {
  loading.value = false
  }
}
// æœç´¢æŒ‰é’®æ“ä½œ
@@ -337,10 +361,17 @@
// é¡µé¢åŠ è½½æ—¶èŽ·å–æ•°æ®
onMounted(async () => {
  const [resp1, resp2] = await Promise.all([getRoomEnum(), getStaffOnJob()])
  roomEnum.value = resp1.data
  staffList.value = resp2.data
  try {
    const [resp1, resp2] = await Promise.all([
      getRoomEnum().catch(() => ({ data: [] })),
      getStaffOnJob().catch(() => ({ data: [] }))
    ])
    roomEnum.value = (resp1 && resp1.data) || []
    staffList.value = (resp2 && resp2.data) || []
  } catch (e) {
    roomEnum.value = []
    staffList.value = []
  }
  await getList()
})
</script>
src/views/equipmentManagement/calibration/index.vue
@@ -123,6 +123,11 @@
        width: 100,
    },
    {
        label: "下次检定日期",
        prop: "nextDate",
        width: 130,
    },
    {
        label: "录入人",
        prop: "userName",
    },
src/views/equipmentManagement/upkeep/Form/PlanForm.vue
@@ -32,6 +32,21 @@
        clearable
      />
    </el-form-item>
    <el-form-item label="保养周期">
      <el-input
        v-model="form.maintenanceCycle"
        placeholder="请输入保养周期(如:每月一次 / æ¯å­£åº¦ / 30天)"
        clearable
      />
    </el-form-item>
    <el-form-item label="保养内容">
      <el-input
        v-model="form.maintenanceContent"
        type="textarea"
        :rows="3"
        placeholder="请输入保养内容"
      />
    </el-form-item>
  </el-form>
</template>
@@ -56,6 +71,8 @@
  deviceName: undefined, // è®¾å¤‡åç§°
  deviceModel: undefined, // è§„格型号
  maintenancePlanTime: undefined, // è®¡åˆ’保养日期
  maintenanceCycle: undefined, // ä¿å…»å‘¨æœŸ
  maintenanceContent: undefined, // ä¿å…»å†…容
});
const setDeviceModel = (id) => {
@@ -78,6 +95,8 @@
  form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
    "YYYY-MM-DD HH:mm:ss"
  );
  form.maintenanceCycle = data.maintenanceCycle;
  form.maintenanceContent = data.maintenanceContent;
};
const loadForm = () => {};
src/views/equipmentManagement/upkeep/index.vue
@@ -178,6 +178,17 @@
    formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
  },
  {
    label: "保养周期",
    align: "center",
    prop: "maintenanceCycle",
  },
  {
    label: "保养内容",
    align: "center",
    prop: "maintenanceContent",
    showOverflowTooltip: true,
  },
  {
    label: "录入人",
    align: "center",
    prop: "createUserName",
src/views/inventoryManagement/dispatchLog/index.vue
@@ -48,6 +48,7 @@
                <el-table-column label="单位" prop="unit" show-overflow-tooltip />
                <el-table-column label="物品类型" prop="itemType" show-overflow-tooltip />
                <el-table-column label="发料数量" prop="inboundNum" show-overflow-tooltip />
                <el-table-column label="领用数量" prop="requisitionNum" show-overflow-tooltip />
                <el-table-column label="单价(元)" prop="taxInclusiveUnitPrice" width="150"></el-table-column>
                <el-table-column label="总价(元)" prop="taxInclusiveTotalPrice" width="150"></el-table-column>
                <el-table-column label="发料人" prop="createBy" show-overflow-tooltip />
src/views/inventoryManagement/issueManagement/index.vue
@@ -69,6 +69,9 @@
        <el-form-item :label="cfg.qtyLabel" prop="inboundQuantity">
          <el-input-number :step="0.01" :min="0" :max="currentRowNum" style="width: 100%" v-model="form.inboundQuantity" placeholder="请输入" clearable />
        </el-form-item>
        <el-form-item label="领用数量:">
          <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.requisitionNum" placeholder="请输入" clearable />
        </el-form-item>
        <el-form-item :label="cfg.dateLabel" prop="inboundTime">
          <el-date-picker style="width: 100%" v-model="form.inboundTime" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
            type="date" placeholder="请选择" clearable />
@@ -237,6 +240,7 @@
    form.value = {
      productrecordId: '',
      inboundQuantity: currentRowNum.value,
      requisitionNum: 0,
      inboundTime: getCurrentDate(),
      nickName: defaultUserId,
    }
@@ -244,6 +248,7 @@
    form.value = {
      productrecordId: '',
      inboundQuantity: currentRowNum.value,
      requisitionNum: 0,
      inboundTime: getCurrentDate(),
      nickName: '',
    }
@@ -262,6 +267,7 @@
        id: currentRow.value.id, // æ¥æºå…¥åº“记录ID
        salesLedgerProductId: currentRow.value.salesLedgerProductId || 0,
        quantity: form.value.inboundQuantity, // å‡ºåº“数量
        requisitionNum: form.value.requisitionNum, // é¢†ç”¨æ•°é‡
        time: form.value.inboundTime, // å‡ºåº“æ—¶é—´
        userId: form.value.nickName, // ç»æ‰‹äºº
        type: cfg.value.type, // å‡ºåº“类型:3发料 / 2销售出库 / 5退货出库
src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue
@@ -2,6 +2,10 @@
  <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">
      <div style="margin-bottom: 10px; display: flex; align-items: center; gap: 12px;">
        <span>登记人:</span>
        <el-input v-model="form.registrant" style="width: 220px" placeholder="请输入登记人" clearable />
      </div>
      <div style="margin-bottom: 10px;" v-if="operationType === 'add'">
        <el-button type="primary" @click="addProductRow">新增</el-button>
      </div>
@@ -142,6 +146,7 @@
    supplierName: '',       // ä¾›åº”商名称
    recorderId: userStore.userId, // å½•入人ID
    recorderName: userStore.name, // å½•入人姓名
    registrant: userStore.name, // ç™»è®°äºº
    entryDate: getCurrentDate(),  // å½•入日期
    remark: '',             // å¤‡æ³¨
  },
@@ -224,6 +229,7 @@
    const payloadList = productList.value.map(product => ({
      id: product.id ?? null,
      registrant: form.value.registrant || '',
            inboundNum: Number(product.inboundNum),
      productCategory: product.productCategory,
      specificationModel: product.specificationModel,
src/views/inventoryManagement/receiptManagement/index.vue
@@ -54,6 +54,7 @@
        <el-table-column label="单价(元)" prop="taxInclusiveUnitPrice" width="150" />
        <el-table-column label="总价(元)" prop="taxInclusiveTotalPrice" width="150" />
        <el-table-column label="入库人" prop="createBy" width="80" show-overflow-tooltip />
        <el-table-column label="登记人" prop="registrant" width="90" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" width="100" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button>
src/views/inventoryManagement/stockCenter/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
<template>
  <div class="stock-center">
    <el-tabs v-model="activeTab" class="center-tabs">
      <el-tab-pane label="实时库存" name="stock" />
      <el-tab-pane label="库存变动明细" name="movement" />
      <el-tab-pane label="库存盘点" name="taking" />
      <el-tab-pane label="库存时间设置" name="setting" />
    </el-tabs>
    <div class="center-body">
      <keep-alive>
        <component :is="currentComponent" />
      </keep-alive>
    </div>
  </div>
</template>
<script setup>
import { ref, computed } from "vue";
import StockRealTime from "../stockManagement/index.vue";
import StockMovement from "../stockMovement/index.vue";
import StockTaking from "../stockTaking/index.vue";
import StockTimeSetting from "../stockTimeSetting/index.vue";
defineOptions({
  name: "库存管理",
});
const activeTab = ref("stock");
const tabMap = {
  stock: StockRealTime,
  movement: StockMovement,
  taking: StockTaking,
  setting: StockTimeSetting,
};
const currentComponent = computed(() => tabMap[activeTab.value] || StockRealTime);
</script>
<style scoped lang="scss">
.stock-center {
  padding: 10px 12px;
}
.center-tabs {
  margin-bottom: 6px;
}
/* å­é¡µé¢è‡ªå¸¦çš„ app-container ä¼šå¤šä¸€å±‚内边距,这里去掉 */
.center-body :deep(.app-container) {
  padding: 0;
}
</style>
src/views/inventoryManagement/stockMovement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
<template>
  <div class="app-container">
    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
      <el-tab-pane label="入库明细" name="in" />
      <el-tab-pane label="出库明细" name="out" />
    </el-tabs>
    <div class="search_form">
      <div>
        <span class="search_title">产品大类:</span>
        <el-input v-model="searchForm.productCategory" style="width: 220px" placeholder="请输入" clearable @change="handleQuery" />
        <el-button type="primary" style="margin-left: 10px" @click="handleQuery">搜索</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 20em)">
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column v-if="activeTab === 'in'" label="入库日期" prop="inboundDate" width="120" />
        <el-table-column v-else label="出库日期" prop="createTime" width="160" />
        <el-table-column label="批次号" prop="code" width="140" show-overflow-tooltip />
        <el-table-column label="产品大类" prop="productCategory" show-overflow-tooltip />
        <el-table-column label="规格型号" prop="specificationModel" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" width="70" />
        <el-table-column v-if="activeTab === 'in'" label="入库数量" prop="inboundNum" width="110" />
        <el-table-column v-else label="出库数量" prop="inboundNum" width="110" />
        <el-table-column v-if="activeTab === 'out'" label="领用数量" prop="requisitionNum" width="110" />
        <el-table-column label="单价(元)" prop="taxInclusiveUnitPrice" width="120" />
        <el-table-column label="总价(元)" prop="taxInclusiveTotalPrice" width="130" />
        <el-table-column label="经手人" prop="createBy" width="100" show-overflow-tooltip />
      </el-table>
      <pagination v-show="page.total > 0" :total="page.total" layout="total, sizes, prev, pager, next, jumper"
        :page="page.current" :limit="page.size" @pagination="paginationChange" />
    </div>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import pagination from "@/components/PIMTable/Pagination.vue";
import { getInPageByCustom } from "@/api/inventoryManagement/stockIn.js";
import { getStockOutPage } from "@/api/inventoryManagement/stockOut.js";
import { getCurrentDate } from "@/utils/index.js";
const activeTab = ref("in");
const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({ current: 1, size: 100, total: 0 });
const searchForm = reactive({ productCategory: "", timeStr: getCurrentDate() });
const getList = () => {
  tableLoading.value = true;
  const params = { ...searchForm, ...page };
  if (activeTab.value === "in") {
    params.flag = false;
    getInPageByCustom(params).then((res) => {
      tableLoading.value = false;
      tableData.value = (res.data && res.data.records) || [];
      page.total = (res.data && res.data.total) || 0;
    }).catch(() => { tableLoading.value = false; });
  } else {
    getStockOutPage(params).then((res) => {
      tableLoading.value = false;
      tableData.value = (res.data && res.data.records) || [];
      page.total = (res.data && res.data.total) || 0;
    }).catch(() => { tableLoading.value = false; });
  }
};
const handleQuery = () => { page.current = 1; getList(); };
const resetQuery = () => { searchForm.productCategory = ""; handleQuery(); };
const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); };
const handleTabChange = () => { page.current = 1; getList(); };
onMounted(() => { getList(); });
</script>
<style scoped lang="scss">
.table_list { margin-top: unset; }
</style>
src/views/inventoryManagement/stockTaking/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,136 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">产品大类:</span>
        <el-input v-model="searchForm.productCategory" style="width: 220px" placeholder="请输入" clearable @change="handleQuery" />
        <span class="search_title ml10">规格型号:</span>
        <el-input v-model="searchForm.specificationModel" style="width: 220px" placeholder="请输入" clearable @change="handleQuery" />
        <el-button type="primary" style="margin-left: 10px" @click="handleQuery">搜索</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增盘点</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 18.5em)">
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column label="盘点单号" prop="code" width="140" show-overflow-tooltip />
        <el-table-column label="批次号" prop="inboundBatches" width="140" show-overflow-tooltip />
        <el-table-column label="产品大类" prop="productCategory" show-overflow-tooltip />
        <el-table-column label="规格型号" prop="specificationModel" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" width="70" />
        <el-table-column label="账面数量" prop="bookNum" width="110" />
        <el-table-column label="实盘数量" prop="actualNum" width="110" />
        <el-table-column label="差异数量" prop="diffNum" width="110">
          <template #default="scope">
            <span :style="{ color: Number(scope.row.diffNum) === 0 ? '' : (Number(scope.row.diffNum) > 0 ? '#67c23a' : '#f56c6c') }">
              {{ scope.row.diffNum == null ? '-' : scope.row.diffNum }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="盘点日期" prop="takingDate" width="120" />
        <el-table-column label="盘点人" prop="takingUser" width="100" />
        <el-table-column label="备注" prop="remark" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" width="130" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button>
            <el-button link type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="page.total > 0" :total="page.total" layout="total, sizes, prev, pager, next, jumper"
        :page="page.current" :limit="page.size" @pagination="paginationChange" />
    </div>
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" @close="closeDialog">
      <el-form :model="form" label-width="110px" label-position="top">
        <el-row :gutter="20">
          <el-col :span="12"><el-form-item label="产品大类"><el-input v-model="form.productCategory" clearable /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="规格型号"><el-input v-model="form.specificationModel" clearable /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="单位"><el-input v-model="form.unit" clearable /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="批次号"><el-input v-model="form.inboundBatches" clearable /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="账面数量"><el-input-number v-model="form.bookNum" :step="0.01" :min="0" style="width: 100%" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="实盘数量"><el-input-number v-model="form.actualNum" :step="0.01" :min="0" style="width: 100%" /></el-form-item></el-col>
          <el-col :span="12">
            <el-form-item label="盘点日期">
              <el-date-picker v-model="form.takingDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12"><el-form-item label="盘点人"><el-input v-model="form.takingUser" clearable /></el-form-item></el-col>
          <el-col :span="24"><el-form-item label="备注"><el-input v-model="form.remark" type="textarea" :rows="2" /></el-form-item></el-col>
        </el-row>
      </el-form>
      <template #footer>
        <el-button type="primary" @click="submitForm">确认</el-button>
        <el-button @click="closeDialog">取消</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import pagination from "@/components/PIMTable/Pagination.vue";
import { getStockTakingPage, addStockTaking, updateStockTaking, delStockTaking } from "@/api/inventoryManagement/stockTaking.js";
import useUserStore from "@/store/modules/user";
const userStore = useUserStore();
const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({ current: 1, size: 100, total: 0 });
const searchForm = reactive({ productCategory: "", specificationModel: "" });
const dialogVisible = ref(false);
const dialogTitle = ref("新增盘点");
const dialogMode = ref("add");
const emptyForm = () => ({
  id: null, productCategory: "", specificationModel: "", unit: "", inboundBatches: "",
  bookNum: 0, actualNum: 0, takingDate: "", takingUser: userStore.nickName || "", remark: "",
});
const form = reactive(emptyForm());
const getList = () => {
  tableLoading.value = true;
  getStockTakingPage({ ...searchForm, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = (res.data && res.data.records) || [];
    page.total = (res.data && res.data.total) || 0;
  }).catch(() => { tableLoading.value = false; });
};
const handleQuery = () => { page.current = 1; getList(); };
const resetQuery = () => { searchForm.productCategory = ""; searchForm.specificationModel = ""; handleQuery(); };
const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); };
const openForm = (mode, row) => {
  dialogMode.value = mode;
  dialogTitle.value = mode === "add" ? "新增盘点" : "编辑盘点";
  Object.assign(form, emptyForm());
  if (mode === "edit" && row) {
    Object.keys(form).forEach((k) => { if (row[k] !== undefined) form[k] = row[k]; });
  }
  dialogVisible.value = true;
};
const closeDialog = () => { dialogVisible.value = false; };
const submitForm = () => {
  const payload = { ...form };
  const req = dialogMode.value === "add" ? addStockTaking(payload) : updateStockTaking(payload);
  req.then(() => {
    ElMessage.success(dialogMode.value === "add" ? "新增成功" : "修改成功");
    closeDialog();
    getList();
  }).catch(() => ElMessage.error("操作失败"));
};
const handleDelete = (row) => {
  ElMessageBox.confirm("确认删除该盘点记录?", "提示", { type: "warning" }).then(() => {
    delStockTaking([row.id]).then(() => { ElMessage.success("删除成功"); getList(); });
  }).catch(() => {});
};
onMounted(() => { getList(); });
</script>
<style scoped lang="scss">
.table_list { margin-top: unset; }
</style>
src/views/inventoryManagement/stockTimeSetting/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">库存时间设置:配置库存预警检测时间、盘点周期、周转率预警天数等</span>
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增设置</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 18.5em)">
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column label="预警检测时间" prop="warningCheckTime" width="140" />
        <el-table-column label="盘点周期" prop="stockTakingCycle" width="120" />
        <el-table-column label="周转率预警天数" prop="turnoverWarnDays" width="150" />
        <el-table-column label="每月自动盘点日" prop="autoTakingDay" width="150" />
        <el-table-column label="是否启用" prop="enabled" width="100">
          <template #default="scope">
            <el-tag :type="scope.row.enabled === 1 ? 'success' : 'info'">{{ scope.row.enabled === 1 ? '启用' : '停用' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="备注" prop="remark" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" width="130" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button>
            <el-button link type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" @close="closeDialog">
      <el-form :model="form" label-width="140px" label-position="top">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="预警检测时间(HH:mm)">
              <el-time-picker v-model="form.warningCheckTime" format="HH:mm" value-format="HH:mm" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="盘点周期">
              <el-select v-model="form.stockTakingCycle" style="width: 100%" placeholder="请选择">
                <el-option label="每日" value="日" />
                <el-option label="每周" value="周" />
                <el-option label="每月" value="月" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="周转率预警天数">
              <el-input-number v-model="form.turnoverWarnDays" :min="1" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="每月自动盘点日">
              <el-input-number v-model="form.autoTakingDay" :min="1" :max="31" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否启用">
              <el-switch v-model="form.enabled" :active-value="1" :inactive-value="0" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="备注">
              <el-input v-model="form.remark" type="textarea" :rows="2" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <el-button type="primary" @click="submitForm">确认</el-button>
        <el-button @click="closeDialog">取消</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { getStockTimeSettingList, addStockTimeSetting, updateStockTimeSetting, delStockTimeSetting } from "@/api/inventoryManagement/stockTaking.js";
const tableData = ref([]);
const tableLoading = ref(false);
const dialogVisible = ref(false);
const dialogTitle = ref("新增设置");
const dialogMode = ref("add");
const emptyForm = () => ({
  id: null, warningCheckTime: "09:00", stockTakingCycle: "月", turnoverWarnDays: 30, autoTakingDay: 1, enabled: 1, remark: "",
});
const form = reactive(emptyForm());
const getList = () => {
  tableLoading.value = true;
  getStockTimeSettingList().then((res) => {
    tableLoading.value = false;
    tableData.value = res.data || [];
  }).catch(() => { tableLoading.value = false; });
};
const openForm = (mode, row) => {
  dialogMode.value = mode;
  dialogTitle.value = mode === "add" ? "新增设置" : "编辑设置";
  Object.assign(form, emptyForm());
  if (mode === "edit" && row) {
    Object.keys(form).forEach((k) => { if (row[k] !== undefined) form[k] = row[k]; });
  }
  dialogVisible.value = true;
};
const closeDialog = () => { dialogVisible.value = false; };
const submitForm = () => {
  const payload = { ...form };
  const req = dialogMode.value === "add" ? addStockTimeSetting(payload) : updateStockTimeSetting(payload);
  req.then(() => {
    ElMessage.success(dialogMode.value === "add" ? "新增成功" : "修改成功");
    closeDialog();
    getList();
  }).catch(() => ElMessage.error("操作失败"));
};
const handleDelete = (row) => {
  ElMessageBox.confirm("确认删除该设置?", "提示", { type: "warning" }).then(() => {
    delStockTimeSetting([row.id]).then(() => { ElMessage.success("删除成功"); getList(); });
  }).catch(() => {});
};
onMounted(() => { getList(); });
</script>
<style scoped lang="scss">
.table_list { margin-top: unset; }
</style>
src/views/inventoryManagement/stockWarningLedger/index.vue
@@ -85,6 +85,14 @@
            <span v-else>-</span>
          </template>
        </el-table-column>
        <el-table-column label="建议类型" prop="suggestionType" width="110" show-overflow-tooltip />
        <el-table-column label="建议内容" prop="suggestionContent" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" width="210" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="handleSuggestion(scope.row, '采购建议')">采购建议</el-button>
            <el-button link type="warning" size="small" @click="handleSuggestion(scope.row, '滞销处理')">滞销提示</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
@@ -104,7 +112,8 @@
import { ElMessage } from 'element-plus'
import pagination from '@/components/PIMTable/Pagination.vue'
import {
  getStockWarningLedgerPage
  getStockWarningLedgerPage,
  generateSuggestion
} from '@/api/inventoryManagement/stockWarningLedger.js'
// å“åº”式数据
@@ -273,6 +282,16 @@
}
// é¡µé¢åŠ è½½
// ç”Ÿæˆé‡‡è´­å»ºè®® / æ»žé”€å¤„理提示
const handleSuggestion = (row, type) => {
  generateSuggestion({ id: row.id, type }).then((res) => {
    ElMessage({ message: res.msg || res.data || '已生成', type: 'success', duration: 6000, showClose: true })
    getList()
  }).catch(() => {
    ElMessage.error('生成失败')
  })
}
onMounted(() => {
  getList()
})
src/views/procurementManagement/paymentEntry/index.vue
@@ -14,6 +14,36 @@
                @change="handleQuery"
              />
            </el-form-item>
            <el-form-item label="发票日期">
              <el-date-picker
                v-model="searchForm.issueDateRange"
                style="width: 250px"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="daterange"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                clearable
                @change="handleIssueDateChange"
              />
            </el-form-item>
            <el-form-item label="发票金额">
              <el-input
                v-model="searchForm.invoiceAmountStart"
                style="width: 110px"
                placeholder="最小"
                clearable
                @change="handleQuery"
              />
              <span style="margin: 0 6px">-</span>
              <el-input
                v-model="searchForm.invoiceAmountEnd"
                style="width: 110px"
                placeholder="最大"
                clearable
                @change="handleQuery"
              />
            </el-form-item>
            <el-form-item>
              <el-checkbox
                v-model="searchForm.status"
@@ -309,6 +339,11 @@
    width:200
  },
  {
    label: "发票日期",
    prop: "issueDate",
    width: 120,
  },
  {
    label: "发票金额(元)",
    prop: "invoiceAmount",
    formatData: (params) => {
@@ -353,6 +388,11 @@
  searchForm: {
    supplierNameOrContractNo: "",
    status: false,
    issueDateRange: [],
    issueDateStart: undefined,
    issueDateEnd: undefined,
    invoiceAmountStart: undefined,
    invoiceAmountEnd: undefined,
  },
  form: {
    purchaseContractNumber: "",
@@ -412,6 +452,17 @@
  page.current = 1;
  getList();
};
// å‘票日期区间变化
const handleIssueDateChange = (val) => {
  if (val && val.length === 2) {
    searchForm.issueDateStart = val[0];
    searchForm.issueDateEnd = val[1];
  } else {
    searchForm.issueDateStart = undefined;
    searchForm.issueDateEnd = undefined;
  }
  handleQuery();
};
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
@@ -419,7 +470,12 @@
};
const getList = () => {
  tableLoading.value = true;
  invoiceListPage({ ...searchForm, ...page }).then((res) => {
  const params = { ...searchForm, ...page };
  // å‘票日期区间用 start/end ä¼ ç»™åŽç«¯ï¼ŒåŽ»æŽ‰ä»…å‰ç«¯ç”¨çš„æ•°ç»„
  delete params.issueDateRange;
  if (params.invoiceAmountStart === "" || params.invoiceAmountStart === null) delete params.invoiceAmountStart;
  if (params.invoiceAmountEnd === "" || params.invoiceAmountEnd === null) delete params.invoiceAmountEnd;
  invoiceListPage(params).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
        page.total = res.total;
src/views/procurementManagement/paymentHistory/index.vue
@@ -32,6 +32,7 @@
        >
          æœç´¢
        </el-button>
        <el-button @click="handleExport">导出</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
@@ -120,6 +121,11 @@
  page.current = 1;
  getList();
};
// å¯¼å‡ºä»˜æ¬¾æµæ°´ï¼ˆæŒ‰å½“前查询条件导出全部)
const handleExport = () => {
  const { paymentDate, ...rest } = searchForm;
  proxy.download("/purchase/paymentRegistration/export", { ...rest }, "付款流水.xlsx");
};
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
src/views/productionManagement/operationScheduling/index.vue
@@ -120,6 +120,16 @@
        prop: "pendingNum",
        width: 100,
    },
    {
        label: "生产要求",
        prop: "productionRequirement",
        showOverflowTooltip: true,
    },
    {
        label: "完成期限",
        prop: "completionDeadline",
        width: 120,
    },
]);
const tableData = ref([]);
const selectedRows = ref([]);
src/views/productionManagement/productionDispatching/components/formDia.vue
@@ -4,6 +4,7 @@
        v-model="dialogFormVisible"
        title="生产派工"
        width="50%"
        top="5vh"
        @close="closeDia"
    >
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
@@ -72,6 +73,33 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="生产要求:" prop="productionRequirement">
              <el-input
                  v-model="form.productionRequirement"
                  type="textarea"
                  :rows="2"
                  placeholder="请输入生产要求"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="完成期限:" prop="completionDeadline">
              <el-date-picker
                  v-model="form.completionDeadline"
                  type="date"
                  placeholder="请选择完成期限"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  clearable
                  style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
@@ -104,6 +132,8 @@
        schedulingDate: "",
        pendingQuantity: "",
        salesLedgerProductId: "",
        productionRequirement: "",
        completionDeadline: "",
  },
  rules: {
        schedulingNum: [{ required: true, message: "请输入", trigger: "blur" },],
@@ -130,6 +160,8 @@
    form.value.schedulingNum = 0
    form.value.schedulingUserId = userStore.id
    form.value.schedulingDate = dayjs().format("YYYY-MM-DD");
    form.value.productionRequirement = "";
    form.value.completionDeadline = "";
}
//
src/views/productionManagement/productionOrder/index.vue
@@ -50,6 +50,20 @@
                    clearable
                />
            </el-form-item>
            <el-form-item label="产品名称" prop="productName">
                <el-input
                    v-model="form.productName"
                    placeholder="请输入产品名称"
                    clearable
                />
            </el-form-item>
            <el-form-item label="项目名称" prop="projectName">
                <el-input
                    v-model="form.projectName"
                    placeholder="请输入项目名称"
                    clearable
                />
            </el-form-item>
            <el-form-item label="规格型号" prop="specificationModel">
                <el-input
                    v-model="form.specificationModel"
@@ -101,6 +115,14 @@
        prop: "productCategory",
    },
    {
        label: "产品名称",
        prop: "productName",
    },
    {
        label: "项目名称",
        prop: "projectName",
    },
    {
        label: "规格型号",
        prop: "specificationModel",
    },
@@ -112,11 +134,11 @@
        label: "数量",
        prop: "quantity",
    },
    // {
    //     label: "排产数量",
    //     prop: "schedulingNum",
    //     width: 100,
    // },
    {
        label: "排产数量",
        prop: "schedulingNum",
        width: 100,
    },
    // {
    //     label: "完工数量",
    //     prop: "successNum",
@@ -148,6 +170,8 @@
    id: null,
    registerDate: dayjs().format("YYYY-MM-DD"),
    productCategory: "",
    productName: "",
    projectName: "",
    specificationModel: "",
    unit: "",
    quantity: null,
@@ -185,6 +209,8 @@
        form.id = row.id;
        form.registerDate = row.registerDate;
        form.productCategory = row.productCategory;
        form.productName = row.productName;
        form.projectName = row.projectName;
        form.specificationModel = row.specificationModel;
        form.unit = row.unit;
        form.quantity = row.quantity;
@@ -201,6 +227,8 @@
    form.id = null;
    form.registerDate = dayjs().format("YYYY-MM-DD");
    form.productCategory = "";
    form.productName = "";
    form.projectName = "";
    form.specificationModel = "";
    form.unit = "";
    form.quantity = null;
@@ -213,6 +241,8 @@
            const payload = {
                registerDate: form.registerDate,
                productCategory: form.productCategory,
                productName: form.productName,
                projectName: form.projectName,
                specificationModel: form.specificationModel,
                unit: form.unit,
                quantity: form.quantity,
src/views/salesManagement/invoiceLedger/index.vue
@@ -15,13 +15,17 @@
          <el-date-picker style="width: 100%" v-model="searchForm.createTimeStart" value-format="YYYY-MM-DD HH:mm:ss"
            format="YYYY-MM-DD" type="date" placeholder="请选择" clearable @change="handleQuery" />
        </el-form-item>
      <el-form-item label="发票金额">
        <el-input v-model="searchForm.invoiceAmountStart" style="width: 110px" placeholder="最小" clearable @change="handleQuery" />
        <span style="margin: 0 6px">-</span>
        <el-input v-model="searchForm.invoiceAmountEnd" style="width: 110px" placeholder="最大" clearable @change="handleQuery" />
      </el-form-item>
        <el-form-item label="不显示有发票行">
          <el-checkbox v-model="searchForm.status" @change="handleQuery" />
        </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>
@@ -192,6 +196,8 @@
    invoiceDateStart: dayjs().startOf("month").format("YYYY-MM-DD"),
    invoiceDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"),
    createTimeStart: "", // å½•入日期
    invoiceAmountStart: undefined,
    invoiceAmountEnd: undefined,
  },
  form: {
    salesLedgerId: "",
@@ -351,21 +357,6 @@
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/invoiceLedger/export", {}, "开票台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// æ‰“开附件上传弹窗
const handleDownload = (val) => {
  fileList.value = [];
src/views/salesManagement/receiptPaymentHistory/index.vue
@@ -44,6 +44,7 @@
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
        <el-button @click="handleOut">导出</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
@@ -156,6 +157,12 @@
  page.size = obj.limit;
  getList();
};
// å¯¼å‡ºå›žæ¬¾æµæ°´ï¼ˆæŒ‰å½“前查询条件)
const handleOut = () => {
  const { receiptPaymentDate, ...rest } = searchForm;
  proxy.download("/receiptPayment/exportOne", { ...rest }, "回款流水.xlsx");
};
const getList = () => {
  tableLoading.value = true;
  const { receiptPaymentDate, ...rest } = searchForm;