gaoluyang
2026-06-04 0e2d3f632e5286485321fc15a50b2531e53d6094
马铃薯app
1.客户往来、供应商往来查询展示修改
已添加5个文件
已修改11个文件
1065 ■■■■■ 文件已修改
src/api/equipmentManagement/deviceArea.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/environmentalMonitoring.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/paymentLedger.js 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/deliveryLedger.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/indicatorStats.js 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/config/oaWorkbench.js 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/environmentalMonitoring/index.vue 373 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/paymentLedger/detail.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/paymentLedger/index.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/finalInspection/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/materialInspection/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/processInspection/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/receiptPaymentLedger/detail.vue 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/receiptPaymentLedger/index.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/works.vue 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/deviceArea.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
import request from "@/utils/request";
export function getDeviceAreaTree(params) {
  return request({
    url: "/device/area/tree",
    method: "get",
    params,
  });
}
export function getDeviceAreaTreeWithDevices(params) {
  return request({
    url: "/device/area/treeWithDevices",
    method: "get",
  });
}
export function getDeviceAreaPage(params) {
  return request({
    url: "/device/area/page",
    method: "get",
    params,
  });
}
export function getDeviceAreaDetail(id) {
  return request({
    url: `/device/area/${id}`,
    method: "get",
  });
}
export function addDeviceArea(data) {
  return request({
    url: "/device/area",
    method: "post",
    data,
  });
}
export function updateDeviceArea(data) {
  return request({
    url: "/device/area",
    method: "put",
    data,
  });
}
export function deleteDeviceArea(ids) {
  return request({
    url: "/device/area",
    method: "delete",
    data: ids,
  });
}
src/api/inventoryManagement/environmentalMonitoring.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
import request from "@/utils/request";
export const getEnvironmentalRealData = () => {
  return request({
    url: "/iot/getRealData",
    method: "get",
  });
};
src/api/procurementManagement/paymentLedger.js
@@ -1,20 +1,19 @@
// é‡‡è´­å°è´¦é¡µé¢æŽ¥å£
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
/** ä»˜æ¬¾å°è´¦ - ä¾›åº”商往来汇总 */
export function paymentLedgerList(query) {
  return request({
    url: "/purchase/paymentRegistration/supplierNameListPage",
    url: "/purchase/report/supplierTransactions",
    method: "get",
    params: query,
  });
}
// åˆ†é¡µæŸ¥è¯¢
export function paymentRecordList(supplierId) {
/** ä»˜æ¬¾å°è´¦ - ä¾›åº”商往来明细 */
export function paymentRecordList(params) {
  return request({
    url: "/purchase/paymentRegistration/supplierNameListPageDetails",
    url: "/purchase/report/supplierTransactionsDetails",
    method: "get",
    params: supplierId,
    params,
  });
}
src/api/salesManagement/deliveryLedger.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
// å‘货台账页面接口
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢å‘货台账(根据客户ID)
export function deliveryLedgerListPage(query) {
  return request({
    url: "/shippingInfo/listPage",
    method: "get",
    params: query,
  });
}
src/api/salesManagement/indicatorStats.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
// æŒ‡æ ‡ç»Ÿè®¡é¡µé¢æŽ¥å£
import request from "@/utils/request";
// å¤´éƒ¨ç»Ÿè®¡æŽ¥å£
export function getTotalStatistics(query) {
  return request({
    url: "/metricStatistics/total",
    method: "get",
    params: query,
  });
}
// æŸ±çŠ¶å›¾æ•°æ®æŽ¥å£
export function getStatisticsTable(query) {
  return request({
    url: "/metricStatistics/statisticsTable",
    method: "get",
    params: query,
  });
}
// å®¢æˆ·å¾€æ¥åˆ—表
export function customewTransactions(query) {
  return request({
    url: "/metricStatistics/customewTransactions",
    method: "get",
    params: query,
  });
}
// å®¢æˆ·å¾€æ¥æ˜Žç»†
export function customewTransactionsDetails(query) {
  return request({
    url: "/metricStatistics/customewTransactionsDetails",
    method: "get",
    params: query,
  });
}
src/config/oaWorkbench.js
@@ -1,69 +1,8 @@
import { OA_NAV } from "./oaPaths.js";
/**
 * OA æ¨¡å—分组(工作台展示 / æ–‡æ¡£å¯¹ç…§ï¼‰
 * æ³¨ï¼šäººäº‹ç®¡ç†/假勤管理/报销管理/审批管理 å·²è¿ç§»è‡³å¯¹åº”业务模块
 */
export const OA_MODULES = [
  {
    key: "HrManage",
    name: "人事管理",
    children: [
      // { label: "员工档案", icon: "/static/images/icon/renyuanxinzi.svg", path: OA_NAV.staffArchive },
      // { label: "员工合同", icon: "/static/images/icon/hetongguanli.svg", path: OA_NAV.staffContract },
      { label: "转正申请", icon: "/static/images/icon/hetongguanli.svg", path: OA_NAV.regularApply },
      { label: "调岗申请", icon: "/static/images/icon/renyuanxinzi.svg", path: OA_NAV.transferApply },
      // { label: "离职申请", icon: "/static/images/icon/qingjiaguanli.svg", path: OA_NAV.resignApply },
      { label: "工作交接", icon: "/static/images/icon/gongchuguanli.svg", path: OA_NAV.workHandover },
      // { label: "岗位管理", icon: "/static/images/icon/gongxuguanli.svg", path: OA_NAV.postManage },
    ],
  },
  {
    key: "AttendManage",
    name: "假勤管理",
    children: [
      { label: "请假申请", icon: "/static/images/icon/qingjiaguanli.svg", path: OA_NAV.leaveApply },
      { label: "加班申请", icon: "/static/images/icon/dakaqiandao.svg", path: OA_NAV.overtimeApply },
    ],
  },
  {
    key: "ReimburseManage",
    name: "报销管理",
    children: [
      { label: "差旅报销", icon: "/static/images/icon/chuchaiguanli.svg", path: OA_NAV.travelReimburse },
      { label: "费用报销", icon: "/static/images/icon/baoxiaoguanli.svg", path: OA_NAV.costReimburse },
    ],
  },
  // {
  //   key: "ContractManage",
  //   name: "合同管理",
  //   children: [
  //     { label: "采购合同", icon: "/static/images/icon/caigoutaizhang.svg", path: OA_NAV.purchaseContract },
  //     { label: "销售合同", icon: "/static/images/icon/xiaoshoutaizhang.svg", path: OA_NAV.saleContract },
  //   ],
  // },
  {
    key: "ApproveManage",
    name: "审批管理",
    children: [
      { label: "审批列表", icon: "/static/images/icon/xietongshenpi.svg", path: OA_NAV.approveList },
      { label: "审批模板", icon: "/static/images/icon/guizhangzhidu.svg", path: OA_NAV.approveTemplate },
    ],
  },
  // {
  //   key: "EnterpriseNews",
  //   name: "企业新闻",
  //   children: [
  //     { label: "企业新闻", icon: "/static/images/icon/zhishiku.svg", path: OA_NAV.enterpriseNews },
  //   ],
  // },
  // {
  //   key: "NoticeAnnouncement",
  //   name: "公告通知",
  //   children: [
  //     { label: "公告通知", icon: "/static/images/icon/tongzhigonggao.svg", path: OA_NAV.noticeAnnouncement },
  //   ],
  // },
];
export const OA_MODULES = [];
/** å·¥ä½œå°æ‰å¹³èœå•(纯前端配置) */
export const OA_WORKBENCH_ITEMS = OA_MODULES.flatMap(module =>
src/pages.json
@@ -922,6 +922,13 @@
      }
    },
    {
      "path": "pages/inventoryManagement/environmentalMonitoring/index",
      "style": {
        "navigationBarTitleText": "环境检测",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/safeProduction/safeQualifications/index",
      "style": {
        "navigationBarTitleText": "规程与资质",
@@ -1148,7 +1155,7 @@
    {
      "path": "pages/qualityManagement/materialInspection/index",
      "style": {
        "navigationBarTitleText": "原材料检验",
        "navigationBarTitleText": "原料检验",
        "navigationStyle": "custom"
      }
    },
src/pages/inventoryManagement/environmentalMonitoring/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,373 @@
<template>
  <view class="environment-page">
    <PageHeader title="环境监测" @back="goBack" />
    <scroll-view scroll-y class="page-scroll">
      <view class="summary-card">
        <view class="summary-header">
          <text class="summary-title">实时环境概览</text>
          <text class="summary-desc">每15秒自动刷新一次设备环境数据</text>
        </view>
        <view v-if="deviceCards.length" class="summary-grid">
          <view class="summary-item">
            <text class="summary-label">设备数量</text>
            <text class="summary-value">{{ deviceCards.length }}</text>
          </view>
          <view class="summary-item">
            <text class="summary-label">平均温度</text>
            <text class="summary-value">{{ averageMetrics.temperature }}</text>
          </view>
          <view class="summary-item">
            <text class="summary-label">平均湿度</text>
            <text class="summary-value">{{ averageMetrics.humidity }}</text>
          </view>
          <view class="summary-item">
            <text class="summary-label">平均光照</text>
            <text class="summary-value">{{ averageMetrics.light }}</text>
          </view>
        </view>
        <view v-else class="empty-block">
          <text class="empty-text">暂无环境数据</text>
        </view>
      </view>
      <view class="section-block">
        <view class="section-header">
          <text class="section-title">设备监测列表</text>
        </view>
        <view v-if="deviceCards.length" class="device-list">
          <view
            v-for="item in deviceCards"
            :key="item.name"
            class="device-card"
          >
            <view class="device-card__header">
              <view class="device-base">
                <text class="device-name">{{ item.name }}</text>
                <text class="device-meta">设备编码:{{ item.guid || "--" }}</text>
              </view>
              <text class="device-tag">在线监测</text>
            </view>
            <view class="metrics-grid">
              <view
                v-for="metric in metricConfig"
                :key="metric.key"
                class="metric-item"
              >
                <text class="metric-label">{{ metric.label }}</text>
                <text class="metric-value" :style="{ color: metric.color }">
                  {{ item[metric.key] }}
                </text>
              </view>
            </view>
          </view>
        </view>
        <view v-else class="empty-block">
          <text class="empty-text">暂无设备监测信息</text>
        </view>
      </view>
    </scroll-view>
  </view>
</template>
<script setup>
import { computed, ref } from "vue";
import { onHide, onShow, onUnload } from "@dcloudio/uni-app";
import PageHeader from "@/components/PageHeader.vue";
import { getEnvironmentalRealData } from "@/api/inventoryManagement/environmentalMonitoring";
const POLL_INTERVAL = 17000;
const TEMP_MARK_1 = "\u2103";
const TEMP_MARK_2 = "\u00B0C";
const TEMP_UNIT = TEMP_MARK_2;
const latestDevices = ref([]);
let pollTimer = null;
const metricConfig = [
  { key: "temperature", label: "温度", color: "#ff7a59", unit: TEMP_UNIT },
  { key: "humidity", label: "湿度", color: "#1ea7fd", unit: "%RH" },
  { key: "co2", label: "CO2", color: "#12c48b", unit: "ppm" },
  { key: "light", label: "光照", color: "#8b5cf6", unit: "Lux" },
];
const extractNumericValue = (rawValue) => {
  const matched = String(rawValue ?? "").match(/-?\d+(\.\d+)?/);
  return matched ? Number(matched[0]) : 0;
};
const normalizeMetricObject = (source, index) => {
  const normalized = {
    name: source?.deviceName || source?.name || source?.deviceNo || `设备${index + 1}`,
    guid: source?.guid || source?.deviceGuid || source?.id || "",
    deviceCode: source?.deviceCode || source?.deviceNo || source?.code || "",
    temperature: 0,
    humidity: 0,
    co2: 0,
    light: 0,
  };
  Object.entries(source || {}).forEach(([key, value]) => {
    const rawText = String(value ?? "");
    if (rawText.includes(TEMP_MARK_1) || rawText.includes(TEMP_MARK_2)) {
      normalized.temperature = extractNumericValue(rawText);
      return;
    }
    if (rawText.includes("%RH")) {
      normalized.humidity = extractNumericValue(rawText);
      return;
    }
    if (rawText.includes("ppm")) {
      normalized.co2 = extractNumericValue(rawText);
      return;
    }
    if (rawText.includes("Lux")) {
      normalized.light = extractNumericValue(rawText);
      return;
    }
    if (key === "temperature") {
      normalized.temperature = extractNumericValue(rawText);
    } else if (key === "humidity") {
      normalized.humidity = extractNumericValue(rawText);
    } else if (key === "co2") {
      normalized.co2 = extractNumericValue(rawText);
    } else if (key === "light") {
      normalized.light = extractNumericValue(rawText);
    }
  });
  return normalized;
};
const formatMetric = (value, unit) => `${Number(value || 0).toFixed(2)}${unit}`;
const deviceCards = computed(() =>
  latestDevices.value.map((item) => ({
    name: item.name,
    guid: item.guid,
    deviceCode: item.deviceCode,
    temperature: formatMetric(item.temperature, TEMP_UNIT),
    humidity: formatMetric(item.humidity, "%RH"),
    co2: formatMetric(item.co2, "ppm"),
    light: formatMetric(item.light, "Lux"),
  }))
);
const averageMetrics = computed(() => {
  if (!latestDevices.value.length) {
    return {
      temperature: `0.00${TEMP_UNIT}`,
      humidity: "0.00%RH",
      light: "0.00Lux",
    };
  }
  const total = latestDevices.value.reduce(
    (result, item) => {
      result.temperature += Number(item.temperature || 0);
      result.humidity += Number(item.humidity || 0);
      result.light += Number(item.light || 0);
      return result;
    },
    { temperature: 0, humidity: 0, light: 0 }
  );
  const count = latestDevices.value.length;
  return {
    temperature: formatMetric(total.temperature / count, TEMP_UNIT),
    humidity: formatMetric(total.humidity / count, "%RH"),
    light: formatMetric(total.light / count, "Lux"),
  };
});
const fetchRealData = async () => {
  try {
    const res = await getEnvironmentalRealData();
    const dataList = Array.isArray(res?.data) ? res.data : [];
    latestDevices.value = dataList.map((item, index) => normalizeMetricObject(item, index));
  } catch (error) {
    latestDevices.value = [];
  }
};
const clearPolling = () => {
  if (pollTimer) {
    clearInterval(pollTimer);
    pollTimer = null;
  }
};
const startPolling = () => {
  clearPolling();
  fetchRealData();
  pollTimer = setInterval(fetchRealData, POLL_INTERVAL);
};
const goBack = () => {
  uni.navigateBack();
};
onShow(() => {
  startPolling();
});
onHide(() => {
  clearPolling();
});
onUnload(() => {
  clearPolling();
});
</script>
<style scoped lang="scss">
.environment-page {
  min-height: 100vh;
  background: #f4f7fb;
}
.page-scroll {
  height: calc(100vh - 88rpx);
  padding: 24rpx;
  box-sizing: border-box;
}
.summary-card,
.section-block {
  background: #ffffff;
  border-radius: 24rpx;
  padding: 28rpx;
  box-shadow: 0 8rpx 24rpx rgba(31, 54, 88, 0.06);
}
.section-block {
  margin-top: 24rpx;
}
.summary-header,
.section-header {
  margin-bottom: 24rpx;
}
.summary-title,
.section-title {
  display: block;
  font-size: 32rpx;
  font-weight: 600;
  color: #1d344f;
}
.summary-desc {
  display: block;
  margin-top: 12rpx;
  font-size: 24rpx;
  color: #7b8aa0;
}
.summary-grid,
.metrics-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 20rpx;
}
.summary-item {
  width: calc(50% - 10rpx);
  padding: 24rpx;
  border-radius: 20rpx;
  background: linear-gradient(135deg, #f8fbff 0%, #eef5ff 100%);
  box-sizing: border-box;
}
.summary-label,
.metric-label {
  display: block;
  font-size: 24rpx;
  color: #7b8aa0;
}
.summary-value,
.metric-value {
  display: block;
  margin-top: 14rpx;
  font-size: 30rpx;
  font-weight: 600;
  color: #1d344f;
}
.device-list {
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}
.device-card {
  padding: 24rpx;
  border-radius: 20rpx;
  background: #f8fbff;
}
.device-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 20rpx;
  gap: 20rpx;
}
.device-base {
  min-width: 0;
  flex: 1;
}
.device-name {
  display: block;
  font-size: 30rpx;
  font-weight: 600;
  color: #1d344f;
}
.device-meta {
  display: block;
  margin-top: 8rpx;
  font-size: 22rpx;
  color: #7b8aa0;
  word-break: break-all;
}
.device-tag {
  flex-shrink: 0;
  padding: 8rpx 16rpx;
  border-radius: 999rpx;
  background: rgba(18, 196, 139, 0.12);
  font-size: 22rpx;
  color: #12c48b;
}
.metric-item {
  width: calc(50% - 10rpx);
  padding: 20rpx;
  border-radius: 16rpx;
  background: #ffffff;
  box-sizing: border-box;
}
.empty-block {
  padding: 60rpx 0;
  text-align: center;
}
.empty-text {
  font-size: 26rpx;
  color: #98a6b9;
}
</style>
src/pages/procurementManagement/paymentLedger/detail.vue
@@ -3,27 +3,7 @@
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="供应商往来详情"
                @back="goBack" />
    <!-- ç»Ÿè®¡ä¿¡æ¯ -->
    <view class="summary-info"
          v-if="tableData.length > 0">
      <view class="summary-item">
        <text class="summary-label">总记录数</text>
        <text class="summary-value">{{ tableData.length }}</text>
      </view>
      <view class="summary-item">
        <text class="summary-label">开票总金额</text>
        <text class="summary-value">{{ formatAmount(invoiceTotal) }}</text>
      </view>
      <view class="summary-item">
        <text class="summary-label">回款总金额</text>
        <text class="summary-value highlight">{{ formatAmount(receiptTotal) }}</text>
      </view>
      <view class="summary-item">
        <text class="summary-label">应收总金额</text>
        <text class="summary-value danger">{{ formatAmount(unReceiptTotal) }}</text>
      </view>
    </view>
    <!-- å›žæ¬¾è®°å½•明细列表 -->
    <!-- é‡‡è´­å°è´¦æ˜Žç»† -->
    <view class="detail-list"
          v-if="tableData.length > 0">
      <view v-for="(item, index) in tableData"
@@ -36,98 +16,98 @@
                       size="16"
                       color="#ffffff"></up-icon>
            </view>
            <text class="item-index">{{ index + 1 }}</text>
            <text class="item-index">{{ item.purchaseContractNumber }}</text>
          </view>
          <view class="item-date">{{ item.happenTime }}</view>
          <view class="item-status">
            <text class="status-tag"
                  :class="getReceiptStatusClass(item.status)">{{ receiptStatusText[item.status] || '未知状态' }}</text>
          </view>
        </view>
        <up-divider></up-divider>
        <view class="item-details">
          <view class="detail-row">
            <text class="detail-label">发票金额(元)</text>
            <text class="detail-value">{{ formatAmount(item.invoiceAmount) }}</text>
            <text class="detail-label">合同签订日期</text>
            <text class="detail-value">{{ item.executionDate }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">付款金额(元)</text>
            <text class="detail-value highlight">{{ formatAmount(item.currentPaymentAmount) }}</text>
            <text class="detail-label">项目名称</text>
            <text class="detail-value">{{ item.projectName }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">应付金额(元)</text>
            <text class="detail-value danger">{{ formatAmount(item.payableAmount) }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">发生日期</text>
            <text class="detail-value">{{ item.paymentDate }}</text>
            <text class="detail-label">合同金额(元)</text>
            <text class="detail-value">{{ formatAmount(item.contractAmount) }}</text>
          </view>
        </view>
      </view>
    </view>
    <view v-else
          class="no-data">
      <text>暂无回款记录</text>
      <text>暂无采购台账记录</text>
    </view>
  </view>
</template>
<script setup>
  import { ref, computed, onMounted } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import {
    paymentLedgerList,
    paymentRecordList,
  } from "@/api/procurementManagement/paymentLedger";
  import { ref, onMounted } from "vue";
  import { gePurchaseListPage } from "@/api/procurementManagement/invoiceEntry.js";
  // å®¢æˆ·ä¿¡æ¯
  const supplierId = ref("");
  const supplierName = ref("");
  // è¡¨æ ¼æ•°æ®
  const tableData = ref([]);
  const invoiceTotal = computed(() => {
    return tableData.value.reduce((sum, item) => {
      return sum + (parseFloat(item.invoiceAmount) || 0);
    }, 0);
  });
  // æ”¶è´§çŠ¶æ€æ–‡æœ¬æ˜ å°„
  const receiptStatusText = {
    1: '待收货',
    2: '收货中',
    3: '已收货'
  };
  const receiptTotal = computed(() => {
    return tableData.value.reduce((sum, item) => {
      return sum + (parseFloat(item.receiptAmount) || 0);
    }, 0);
  });
  const unReceiptTotal = computed(() => {
    return tableData.value.reduce((sum, item) => {
      return sum + (parseFloat(item.unReceiptAmount) || 0);
    }, 0);
  });
  // æ”¶è´§çŠ¶æ€æ ‡ç­¾æ ·å¼
  const getReceiptStatusClass = (status) => {
    const classMap = {
      1: 'status-info',
      2: 'status-warning',
      3: 'status-success'
    };
    return classMap[status] || 'status-info';
  };
  // è¿”回上一页
  const goBack = () => {
    uni.removeStorageSync("supplierId");
    uni.removeStorageSync("supplierName");
    uni.navigateBack();
  };
  // èŽ·å–é¡µé¢å‚æ•°
  const getPageParams = () => {
    // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å–ä¾›åº”å•†ID
    const storedSupplierId = uni.getStorageSync("supplierId");
    if (storedSupplierId) {
      supplierId.value = storedSupplierId;
    const storedSupplierName = uni.getStorageSync("supplierName");
    if (storedSupplierName) {
      supplierName.value = storedSupplierName;
    }
  };
  // æŸ¥è¯¢åˆ—表
  const getList = () => {
    if (!supplierId.value) {
    if (!supplierName.value) {
      uni.showToast({
        title: "客户信息缺失",
        title: "供应商信息缺失",
        icon: "error",
      });
      return;
    }
    showLoadingToast("加载中...");
    paymentRecordList({ supplierId: supplierId.value })
    gePurchaseListPage({ supplierName: supplierName.value, current: 1, size: 1000 })
      .then(res => {
        tableData.value = res.data;
        let orders = [];
        if (res.data) {
          if (Array.isArray(res.data)) {
            orders = res.data;
          } else if (res.data.records && Array.isArray(res.data.records)) {
            orders = res.data.records;
          }
        }
        tableData.value = orders;
        closeToast();
      })
      .catch(() => {
@@ -173,46 +153,6 @@
  .u-divider {
    margin: 0 !important;
  }
  .summary-info {
    background: #ffffff;
    margin: 20px 20px 0 20px;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  }
  .summary-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
    &:last-child {
      margin-bottom: 0;
    }
  }
  .summary-label {
    font-size: 14px;
    color: #666;
  }
  .summary-value {
    font-size: 14px;
    color: #333;
    font-weight: 500;
  }
  .summary-value.highlight {
    color: #2979ff;
    font-weight: 600;
  }
  .summary-value.danger {
    color: #ff4757;
    font-weight: 600;
  }
  .detail-list {
@@ -262,6 +202,32 @@
    color: #666;
  }
  .item-status {
    display: flex;
    align-items: center;
  }
  .status-tag {
    font-size: 12px;
    padding: 2px 8px;
    border-radius: 4px;
  }
  .status-success {
    color: #67c23a;
    background: rgba(103, 194, 58, 0.1);
  }
  .status-warning {
    color: #e6a23c;
    background: rgba(230, 162, 60, 0.1);
  }
  .status-info {
    color: #909399;
    background: rgba(144, 147, 153, 0.1);
  }
  .item-details {
    padding: 16px 0;
  }
@@ -289,16 +255,6 @@
    text-align: right;
    flex: 1;
    margin-left: 16px;
  }
  .detail-value.highlight {
    color: #2979ff;
    font-weight: 500;
  }
  .detail-value.danger {
    color: #ff4757;
    font-weight: 500;
  }
  .no-data {
src/pages/procurementManagement/paymentLedger/index.vue
@@ -45,15 +45,7 @@
          <view class="item-details">
            <view class="detail-row">
              <text class="detail-label">合同金额(元)</text>
              <text class="detail-value">{{ formattedNumber(item.invoiceAmount) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">付款金额(元)</text>
              <text class="detail-value">{{ formattedNumber(item.paymentAmount) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">应付金额(元)</text>
              <text class="detail-value highlight danger">{{ formattedNumber(item.payableAmount) }}</text>
              <text class="detail-value">{{ formattedNumber(item.contractAmounts) }}</text>
            </view>
          </view>
        </view>
@@ -132,7 +124,7 @@
const rowClickMethod = (row) => {
  // ä½¿ç”¨ uni.setStorageSync å­˜å‚¨ä¾›åº”商信息
  uni.setStorageSync('supplierId', row.supplierId);
  uni.setStorageSync('supplierName', row.supplierName);
  // è·³è½¬åˆ°å›žæ¬¾è®°å½•明细页面
  uni.navigateTo({
    url: '/pages/procurementManagement/paymentLedger/detail'
src/pages/qualityManagement/finalInspection/index.vue
@@ -121,7 +121,7 @@
            <u-button type="primary"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState"
                      :disabled="!!item.inspectState"
                      @click.stop="startInspection(item)">
              ç¼–辑
            </u-button>
@@ -134,7 +134,7 @@
            <u-button type="success"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState"
                      :disabled="!!item.inspectState"
                      @click.stop="submitInspection(item)">
              æäº¤
            </u-button>
@@ -149,7 +149,7 @@
            <u-button type="warning"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState || item.checkName !== ''"
                      :disabled="!!item.inspectState || item.checkName !== ''"
                      @click.stop="assignInspector(item)">
              åˆ†é…æ£€éªŒå‘˜
            </u-button>
src/pages/qualityManagement/materialInspection/index.vue
@@ -1,7 +1,7 @@
<template>
  <view class="material-inspection-page">
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="原材料检验"
    <PageHeader title="原料检验"
                @back="goBack" />
    <!-- æœç´¢åŒºåŸŸ -->
    <view class="search-section">
@@ -121,7 +121,7 @@
            <u-button type="primary"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState"
                      :disabled="!!item.inspectState"
                      @click.stop="startInspection(item)">
              ç¼–辑
            </u-button>
@@ -134,7 +134,7 @@
            <u-button type="success"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState"
                      :disabled="!!item.inspectState"
                      @click.stop="submitInspection(item)">
              æäº¤
            </u-button>
@@ -149,7 +149,7 @@
            <u-button type="warning"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState || item.checkName !== ''"
                      :disabled="!!item.inspectState || item.checkName !== ''"
                      @click.stop="assignInspector(item)">
              åˆ†é…æ£€éªŒå‘˜
            </u-button>
src/pages/qualityManagement/processInspection/index.vue
@@ -121,7 +121,7 @@
            <u-button type="primary"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState"
                      :disabled="!!item.inspectState"
                      @click.stop="startInspection(item)">
              ç¼–辑
            </u-button>
@@ -134,7 +134,7 @@
            <u-button type="success"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState"
                      :disabled="!!item.inspectState"
                      @click.stop="submitInspection(item)">
              æäº¤
            </u-button>
@@ -149,7 +149,7 @@
            <u-button type="warning"
                      size="small"
                      class="action-btn"
                      :disabled="item.inspectState || item.checkName !== ''"
                      :disabled="!!item.inspectState || item.checkName !== ''"
                      @click.stop="assignInspector(item)">
              åˆ†é…æ£€éªŒå‘˜
            </u-button>
src/pages/sales/receiptPaymentLedger/detail.vue
@@ -3,27 +3,7 @@
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="客户往来详情"
                @back="goBack" />
    <!-- ç»Ÿè®¡ä¿¡æ¯ -->
    <view class="summary-info"
          v-if="tableData.length > 0">
      <view class="summary-item">
        <text class="summary-label">总记录数</text>
        <text class="summary-value">{{ tableData.length }}</text>
      </view>
      <view class="summary-item">
        <text class="summary-label">开票总金额</text>
        <text class="summary-value">{{ formatAmount(invoiceTotal) }}</text>
      </view>
      <view class="summary-item">
        <text class="summary-label">回款总金额</text>
        <text class="summary-value highlight">{{ formatAmount(receiptTotal) }}</text>
      </view>
      <view class="summary-item">
        <text class="summary-label">应收总金额</text>
        <text class="summary-value danger">{{ formatAmount(unReceiptTotal) }}</text>
      </view>
    </view>
    <!-- å›žæ¬¾è®°å½•明细列表 -->
    <!-- å‘货台账明细 -->
    <view class="detail-list"
          v-if="tableData.length > 0">
      <view v-for="(item, index) in tableData"
@@ -36,66 +16,59 @@
                       size="16"
                       color="#ffffff"></up-icon>
            </view>
            <text class="item-index">{{ index + 1 }}</text>
            <text class="item-index">{{ item.salesContractNo }}</text>
          </view>
          <view class="item-date">{{ item.happenTime }}</view>
          <view class="item-status">
            <text class="status-tag"
                  :class="getStatusClass(item.status)">{{ item.status || '--' }}</text>
          </view>
        </view>
        <up-divider></up-divider>
        <view class="item-details">
          <view class="detail-row">
            <text class="detail-label">开票金额(元)</text>
            <text class="detail-value">{{ formatAmount(item.invoiceTotal) }}</text>
            <text class="detail-label">客户名称</text>
            <text class="detail-value">{{ item.customerName }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">回款金额(元)</text>
            <text class="detail-value highlight">{{ formatAmount(item.receiptPaymentAmount) }}</text>
            <text class="detail-label">产品名称</text>
            <text class="detail-value">{{ item.productName }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">应收金额(元)</text>
            <text class="detail-value danger">{{ formatAmount(item.unReceiptPaymentAmount) }}</text>
            <text class="detail-label">规格型号</text>
            <text class="detail-value">{{ item.specificationModel }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">发生日期</text>
            <text class="detail-value">{{ item.receiptPaymentDate }}</text>
            <text class="detail-label">发货时间</text>
            <text class="detail-value">{{ item.shippingDate }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">发货数量</text>
            <text class="detail-value">{{ item.totalQuantity }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">出库单号</text>
            <text class="detail-value">{{ item.outboundBatches }}</text>
          </view>
        </view>
      </view>
    </view>
    <view v-else
          class="no-data">
      <text>暂无回款记录</text>
      <text>暂无发货记录</text>
    </view>
  </view>
</template>
<script setup>
  import { ref, computed, onMounted } from "vue";
  import { ref, onMounted } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { customerInteractions } from "@/api/salesManagement/receiptPayment.js";
  import { deliveryLedgerListPage } from "@/api/salesManagement/deliveryLedger.js";
  // å®¢æˆ·ä¿¡æ¯
  const customerId = ref("");
  // è¡¨æ ¼æ•°æ®
  const tableData = ref([]);
  const invoiceTotal = computed(() => {
    return tableData.value.reduce((sum, item) => {
      return sum + (parseFloat(item.invoiceTotal) || 0);
    }, 0);
  });
  const receiptTotal = computed(() => {
    return tableData.value.reduce((sum, item) => {
      return sum + (parseFloat(item.receiptPaymentAmount) || 0);
    }, 0);
  });
  const unReceiptTotal = computed(() => {
    return tableData.value.reduce((sum, item) => {
      return sum + (parseFloat(item.unReceiptPaymentAmount) || 0);
    }, 0);
  });
  // è¿”回上一页
  const goBack = () => {
@@ -105,7 +78,6 @@
  // èŽ·å–é¡µé¢å‚æ•°
  const getPageParams = () => {
    // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å–å®¢æˆ·ID
    const storedCustomerId = uni.getStorageSync("customerId");
    if (storedCustomerId) {
      customerId.value = storedCustomerId;
@@ -123,15 +95,21 @@
    }
    showLoadingToast("加载中...");
    const param = {
    deliveryLedgerListPage({
      customerId: customerId.value,
      current: -1,
      size: -1,
    };
    customerInteractions(param)
      current: 1,
      size: 1000,
    })
      .then(res => {
        tableData.value = res.data;
        let orders = [];
        if (res.data) {
          if (Array.isArray(res.data)) {
            orders = res.data;
          } else if (res.data.records && Array.isArray(res.data.records)) {
            orders = res.data.records;
          }
        }
        tableData.value = orders;
        closeToast();
      })
      .catch(() => {
@@ -143,9 +121,15 @@
      });
  };
  // æ ¼å¼åŒ–金额
  const formatAmount = amount => {
    return amount ? parseFloat(amount).toFixed(2) : "0.00";
  // å‘货状态样式
  const getStatusClass = (status) => {
    const statusMap = {
      '已发货': 'status-success',
      '审核通过': 'status-success',
      '审核中': 'status-warning',
      '审核不通过': 'status-danger',
    };
    return statusMap[status] || 'status-info';
  };
  // æ˜¾ç¤ºåŠ è½½æç¤º
@@ -183,46 +167,6 @@
  .u-divider {
    margin: 0 !important;
  }
  .summary-info {
    background: #ffffff;
    margin: 20px 20px 0 20px;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  }
  .summary-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
    &:last-child {
      margin-bottom: 0;
    }
  }
  .summary-label {
    font-size: 14px;
    color: #666;
  }
  .summary-value {
    font-size: 14px;
    color: #333;
    font-weight: 500;
  }
  .summary-value.highlight {
    color: #2979ff;
    font-weight: 600;
  }
  .summary-value.danger {
    color: #ff4757;
    font-weight: 600;
  }
  .detail-list {
@@ -272,6 +216,37 @@
    color: #666;
  }
  .item-status {
    display: flex;
    align-items: center;
  }
  .status-tag {
    font-size: 12px;
    padding: 2px 8px;
    border-radius: 4px;
  }
  .status-success {
    color: #67c23a;
    background: rgba(103, 194, 58, 0.1);
  }
  .status-warning {
    color: #e6a23c;
    background: rgba(230, 162, 60, 0.1);
  }
  .status-danger {
    color: #f56c6c;
    background: rgba(245, 108, 108, 0.1);
  }
  .status-info {
    color: #909399;
    background: rgba(144, 147, 153, 0.1);
  }
  .item-details {
    padding: 16px 0;
  }
@@ -301,19 +276,10 @@
    margin-left: 16px;
  }
  .detail-value.highlight {
    color: #2979ff;
    font-weight: 500;
  }
  .detail-value.danger {
    color: #ff4757;
    font-weight: 500;
  }
  .no-data {
    padding: 40px 0;
    text-align: center;
    color: #999;
  }
</style>
src/pages/sales/receiptPaymentLedger/index.vue
@@ -47,16 +47,8 @@
          <up-divider></up-divider>
          <view class="item-details">
            <view class="detail-row">
              <text class="detail-label">开票金额(元)</text>
              <text class="detail-value">{{ formattedNumber(item.invoiceTotal) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">回款金额(元)</text>
              <text class="detail-value">{{ formattedNumber(item.receiptPaymentAmount) }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">应收金额(元)</text>
              <text class="detail-value highlight danger">{{ formattedNumber(item.unReceiptPaymentAmount) }}</text>
              <text class="detail-label">合同金额(元)</text>
              <text class="detail-value">{{ formattedNumber(item.contractAmounts) }}</text>
            </view>
          </view>
        </view>
@@ -72,7 +64,7 @@
<script setup>
  import { onMounted, ref, reactive, toRefs } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { invoiceLedgerSalesAccount } from "@/api/salesManagement/invoiceLedger";
  import { customewTransactions } from "@/api/salesManagement/indicatorStats.js";
  const tableData = ref([]);
@@ -106,7 +98,7 @@
  const getList = () => {
    showLoadingToast("加载中...");
    invoiceLedgerSalesAccount({ ...searchForm.value, ...page })
    customewTransactions({ ...searchForm.value, ...page })
      .then(res => {
        tableData.value = res.data.records;
        closeToast();
@@ -139,7 +131,7 @@
  const rowClickMethod = row => {
    // ä½¿ç”¨ uni.setStorageSync å­˜å‚¨å®¢æˆ·ä¿¡æ¯
    uni.setStorageSync("customerId", row.id);
    uni.setStorageSync("customerId", row.customerId);
    // è·³è½¬åˆ°å›žæ¬¾è®°å½•明细页面
    uni.navigateTo({
      url: "/pages/sales/receiptPaymentLedger/detail",
src/pages/works.vue
@@ -328,14 +328,17 @@
<script setup>
  import { ref, onMounted, nextTick, reactive, computed } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { userLoginFacotryList } from "@/api/login";
  import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
  import { createVersionUpgradeChecker } from "@/utils/versionUpgrade";
  import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
  import { OA_WORKBENCH_ITEMS } from "@/config/oaWorkbench.js";
  import modal from "@/plugins/modal";
  import useUserStore from "@/store/modules/user";
  const userStore = useUserStore();
  const { triggerVersionCheck } = createVersionUpgradeChecker({ logPrefix: "[version-works]" });
  const show = ref(false);
  const factoryList = ref([]);
  const factoryListTem = ref([]);
@@ -495,6 +498,10 @@
      icon: "/static/images/icon/kucunguanli.svg",
      label: "库存管理",
    },
    {
      icon: "/static/images/icon/weixianzuoye.svg",
      label: "环境检测",
    },
  ]);
  const humanResourcesItems = reactive([
@@ -510,11 +517,26 @@
      icon: "/static/images/icon/hetongguanli.svg",
      label: "合同管理",
    },
    {
      icon: "/static/images/icon/hetongguanli.svg",
      label: "转正申请",
      path: "/pages/oa/HrManage/regular-apply/index",
    },
    {
      icon: "/static/images/icon/renyuanxinzi.svg",
      label: "调岗申请",
      path: "/pages/oa/HrManage/transfer-apply/index",
    },
    {
      icon: "/static/images/icon/gongchuguanli.svg",
      label: "工作交接",
      path: "/pages/oa/HrManage/work-handover/index",
    },
  ]);
  const qualityItems = reactive([
    {
      icon: "/static/images/icon/yuancailiaojianyan.svg",
      label: "原材料检验",
      label: "原料检验",
    },
    {
      icon: "/static/images/icon/guochengjianyan.svg",
@@ -593,6 +615,36 @@
    {
      icon: "/static/images/icon/kehubaifang.svg",
      label: "客户拜访",
    },
    {
      icon: "/static/images/icon/qingjiaguanli.svg",
      label: "请假申请",
      path: "/pages/oa/AttendManage/leave-apply/index",
    },
    {
      icon: "/static/images/icon/dakaqiandao.svg",
      label: "加班申请",
      path: "/pages/oa/AttendManage/overtime-apply/index",
    },
    {
      icon: "/static/images/icon/chuchaiguanli.svg",
      label: "差旅报销",
      path: "/pages/oa/ReimburseManage/travel-reimburse/index",
    },
    {
      icon: "/static/images/icon/baoxiaoguanli.svg",
      label: "费用报销",
      path: "/pages/oa/ReimburseManage/cost-reimburse/index",
    },
    {
      icon: "/static/images/icon/xietongshenpi.svg",
      label: "审批列表",
      path: "/pages/oa/ApproveManage/approve-list/index",
    },
    {
      icon: "/static/images/icon/guizhangzhidu.svg",
      label: "审批模板",
      path: "/pages/oa/ApproveManage/approve-template/index",
    },
  ]);
@@ -1018,7 +1070,7 @@
          url: "/pages/humanResources/contractManagement/index",
        });
        break;
      case "原材料检验":
      case "原料检验":
        uni.navigateTo({
          url: "/pages/qualityManagement/materialInspection/index",
        });
@@ -1038,6 +1090,11 @@
          url: "/pages/inventoryManagement/stockManagement/index",
        });
        break;
      case "环境检测":
        uni.navigateTo({
          url: "/pages/inventoryManagement/environmentalMonitoring/index",
        });
        break;
      case "反馈登记":
        uni.navigateTo({
          url: "/pages/customerService/feedbackRegistration/index",