zhangwencui
4 天以前 2637f60b82c1fd343c790ac2f640a887fde183d7
销售台账修改
已修改1个文件
590 ■■■■■ 文件已修改
src/pages/sales/salesAccount/index.vue 590 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/salesAccount/index.vue
@@ -3,25 +3,35 @@
    <!-- 使用通用页面头部组件 -->
    <PageHeader title="销售台账"
                @back="goBack" />
    <!-- 状态Tab页筛选 -->
    <view class="sales-ledger-status-bar">
      <view v-for="tab in salesLedgerStatusTabs"
            :key="tab.key"
            class="sales-ledger-status-tab"
            :class="{ 'is-active': activeStatusTab === tab.key }"
            @click="handleStatusTabChange(tab.key)">
        {{ tab.label }}
      </view>
    </view>
    <!-- 搜索和筛选区域 -->
    <view class="search-section">
      <view class="search-bar">
        <view class="search-input">
          <up-input class="search-text"
                    placeholder="请输入销售合同号搜索"
                    v-model="salesContractNo"
                    @change="getList"
                    v-model="searchForm.salesContractNo"
                    @change="handleQuery"
                    clearable />
        </view>
        <view class="filter-button"
              @click="getList">
              @click="handleQuery">
          <up-icon name="search"
                   size="24"
                   color="#999"></up-icon>
        </view>
      </view>
    </view>
    <!-- 销售台账瀑布流 -->
    <!-- 销售台账列表 -->
    <view class="ledger-list"
          v-if="ledgerList.length > 0">
      <view v-for="(item, index) in ledgerList"
@@ -37,9 +47,18 @@
              </view>
              <text class="item-id">{{ item.salesContractNo }}</text>
            </view>
            <!--                            <view class="item-tag">-->
            <!--                                <text class="tag-text">{{ item.recorder }}</text>-->
            <!--                            </view>-->
            <view class="item-tag"
                  v-if="item.reviewStatus === 0">
              <text class="tag-text warning">待审核</text>
            </view>
            <view class="item-tag"
                  v-else-if="item.reviewStatus === 1">
              <text class="tag-text success">已审核</text>
            </view>
            <view class="item-tag"
                  v-else>
              <text class="tag-text">已反审</text>
            </view>
          </view>
          <up-divider></up-divider>
          <view class="item-details">
@@ -48,73 +67,34 @@
              <text class="detail-value">{{ item.customerName }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">业务员</text>
              <text class="detail-value">{{ item.salesman }}</text>
            </view>
            <view class="detail-row">
              <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">{{ item.paymentMethod }}</text>
              <text class="detail-label">业务员 / 项目</text>
              <text class="detail-value">{{ item.salesman }} / {{ item.projectName }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">合同金额(元)</text>
              <text class="detail-value highlight">{{ item.contractAmount }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">签订日期</text>
              <text class="detail-value">{{ item.executionDate }}</text>
              <text class="detail-label">面积 / 数量</text>
              <text class="detail-value">{{ item.productTotalArea }}㎡ * {{ item.productTotalQuantity }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">发货状态</text>
              <u-tag size="mini"
                     :type="getLedgerShippingTagType(item)">{{
                getLedgerShippingLabel(item)
              }}</u-tag>
              <text class="detail-label">状态</text>
              <view class="status-tags">
                <u-tag size="mini"
                       :type="getShippingStatusType(item)">{{ getShippingStatusText(item) }}</u-tag>
                <u-tag size="mini"
                       :type="getStockStatusTagType(item)">{{ getStockStatusLabel(item) }}</u-tag>
                <u-tag size="mini"
                       :type="item.orderStatus === 1 ? 'success' : 'primary'">{{ item.orderStatus === 1 ? '已完成' : '进行中' }}</u-tag>
              </view>
            </view>
            <up-divider></up-divider>
            <view class="detail-info">
              <view class="detail-row">
                <text class="detail-label">录入人</text>
                <text class="detail-value">{{ item.entryPersonName }}</text>
                <text class="detail-label">录入人 / 日期</text>
                <text class="detail-value">{{ item.entryPersonName }} / {{ item.entryDate }}</text>
              </view>
              <view class="detail-row">
                <text class="detail-label">录入日期</text>
                <text class="detail-value">{{ item.entryDate }}</text>
              </view>
            </view>
            <up-divider></up-divider>
            <view class="detail-buttons">
              <u-button class="detail-button"
                        size="small"
                        type="primary"
                        plain
                        :disabled="!canLedgerShip(item)"
                        @click.stop="handleShip(item)">
                发货
              </u-button>
              <!-- <u-button class="detail-button"
                        size="small"
                        type="primary"
                        @click.stop="handleInfo('edit', item)">
                编辑
              </u-button>
              <u-button class="detail-button"
                        size="small"
                        type="primary"
                        plain
                        @click.stop="openOut(item)">
                发货状态
              </u-button> -->
              <!-- <u-button class="detail-button"
                        size="small"
                        type="error"
                        plain
                        @click.stop="handleDelete(item)">
                删除
              </u-button> -->
            </view>
          </view>
        </view>
@@ -124,69 +104,163 @@
          class="no-data">
      <text>暂无销售台账数据</text>
    </view>
    <!-- 浮动操作按钮 -->
    <!-- <view class="fab-button"
          @click="handleInfo('add')">
      <up-icon name="plus"
               size="24"
               color="#ffffff"></up-icon>
    </view> -->
  </view>
</template>
<script setup>
  import { ref } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import { ledgerListPage, delLedger, productList } from "@/api/salesManagement/salesLedger";
  import {
    hasShippedProducts,
    getLedgerShippingLabel,
    getLedgerShippingTagType,
    canLedgerShip,
    executeSalesLedgerShip,
  } from "@/utils/salesLedgerShip";
  import useUserStore from "@/store/modules/user";
  import { ref, onMounted } from "vue";
  import { ledgerListPage } from "@/api/salesManagement/salesLedger";
  import PageHeader from "@/components/PageHeader.vue";
  const userStore = useUserStore();
  // 状态Tab页
  const activeStatusTab = ref("all");
  const salesLedgerStatusTabs = [
    { key: "all", label: "全部" },
    { key: "pendingReview", label: "未审核" },
    { key: "reviewed", label: "已审核" },
    { key: "reverseReviewed", label: "反审核" },
    { key: "stocked", label: "已入库" },
    { key: "delivered", label: "已发货" },
    { key: "completed", label: "已完成" },
  ];
  // 搜索表单
  const searchForm = ref({
    salesContractNo: "",
    reviewStatus: undefined,
    stockStatus: undefined,
    deliveryStatus: undefined,
    orderStatus: undefined,
  });
  // 销售台账数据
  const ledgerList = ref([]);
  // 分页
  const page = ref({
    current: 1,
    size: 10,
  });
  // 重置状态筛选
  const resetStatusFilters = () => {
    searchForm.value.reviewStatus = undefined;
    searchForm.value.stockStatus = undefined;
    searchForm.value.deliveryStatus = undefined;
    searchForm.value.orderStatus = undefined;
  };
  // Tab页切换
  const handleStatusTabChange = tabKey => {
    activeStatusTab.value = tabKey;
    resetStatusFilters();
    switch (tabKey) {
      case "all":
        break;
      case "pendingReview":
        searchForm.value.reviewStatus = 0;
        break;
      case "reviewed":
        searchForm.value.reviewStatus = 1;
        break;
      case "reverseReviewed":
        searchForm.value.reviewStatus = 2;
        break;
      case "stocked":
        searchForm.value.stockStatus = 2;
        break;
      case "delivered":
        searchForm.value.deliveryStatus = 5;
        break;
      case "completed":
        searchForm.value.orderStatus = 1;
        break;
      default:
        break;
    }
    handleQuery();
  };
  // 显示加载提示
  const showLoadingToast = message => {
    uni.showLoading({
      title: message,
      mask: true,
    });
  };
  // 关闭提示
  const closeToast = () => {
    uni.hideLoading();
  };
  // 搜索关键词
  const salesContractNo = ref("");
  // 销售台账数据
  const ledgerList = ref([]);
  const handleShip = item => executeSalesLedgerShip(item);
  // 返回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  // 重置搜索
  const resetSearch = () => {
    searchForm.value = {
      salesContractNo: "",
      reviewStatus: undefined,
      stockStatus: undefined,
      deliveryStatus: undefined,
      orderStatus: undefined,
    };
    activeStatusTab.value = "all";
    page.value.current = 1;
    getList();
  };
  // 查询列表
  const handleQuery = () => {
    page.value.current = 1;
    getList();
  };
  // 获取列表
  const getList = () => {
    showLoadingToast("加载中...");
    const page = {
      current: -1,
      size: -1,
    // 构建查询参数
    const params = {
      ...page.value,
      reviewStatusList: [0, 1, 2],
    };
    ledgerListPage({ ...page, salesContractNo: salesContractNo.value })
    // 添加搜索条件
    if (searchForm.value.salesContractNo) {
      params.salesContractNo = searchForm.value.salesContractNo;
    }
    if (searchForm.value.reviewStatus !== undefined) {
      params.reviewStatus = searchForm.value.reviewStatus;
    }
    if (searchForm.value.stockStatus !== undefined) {
      params.stockStatus = searchForm.value.stockStatus;
    }
    if (searchForm.value.deliveryStatus !== undefined) {
      params.deliveryStatus = searchForm.value.deliveryStatus;
    }
    if (searchForm.value.orderStatus !== undefined) {
      params.orderStatus = searchForm.value.orderStatus;
    }
    ledgerListPage(params)
      .then(res => {
        console.log("销售台账----", res);
        ledgerList.value = res.records;
        ledgerList.value = res.records || res.data || [];
        closeToast();
      })
      .catch(() => {
        closeToast();
        uni.showToast({
          title: "查询失败",
          icon: "none",
        });
      });
  };
  // 打开详情页
  const openOut = item => {
    uni.setStorageSync("outData", JSON.stringify(item));
    uni.navigateTo({
@@ -194,114 +268,248 @@
    });
  };
  // 删除单条销售台账
  const handleDelete = async row => {
    if (!row || !row.id) return;
    // 获取产品列表,用于判断是否已发货
    let products = row.children && row.children.length > 0 ? row.children : null;
    if (!products) {
      try {
        const res = await productList({ salesLedgerId: row.id, type: 1 });
        products = res.data || res.records || [];
      } catch (e) {
        products = [];
      }
  // 获取发货状态标签类型
  const getShippingStatusType = item => {
    if (item.shippingDate || item.shippingCarNumber) {
      return "success";
    }
    if (hasShippedProducts(products)) {
      uni.showToast({
        title: "已发货、部分发货或已有发货记录的销售订单不能删除",
        icon: "none",
      });
      return;
    const status = item.shippingStatus;
    if (status === null || status === undefined || status === "") {
      return "info";
    }
    uni.showModal({
      title: "删除确认",
      content: "选中的内容将被删除,是否确认删除?",
      success: async res => {
        if (res.confirm) {
          try {
            showLoadingToast("处理中...");
            await delLedger([row.id]);
            closeToast();
            uni.showToast({
              title: "删除成功",
              icon: "success",
            });
            getList();
          } catch (e) {
            closeToast();
            uni.showToast({
              title: "删除失败,请重试",
              icon: "none",
            });
          }
        }
      },
    });
  };
  // 处理台账信息操作(查看/编辑/新增)
  const handleInfo = (type, row) => {
    try {
      // 设置操作类型
      uni.setStorageSync("operationType", type);
      uni.removeStorageSync("editData");
      // 如果是查看或编辑操作
      if (type !== "add") {
        // 验证行数据是否存在
        if (!row) {
          uni.showToast({
            title: "数据不存在",
            icon: "error",
          });
          return;
        }
        // 检查权限:只有录入人才能编辑
        if (row.entryPerson != userStore.id) {
          // 非录入人跳转到只读详情页面
          uni.setStorageSync("editData", JSON.stringify(row));
          uni.navigateTo({
            url: "/pages/sales/salesAccount/view",
          });
          return;
        }
        // 录入人编辑:存储数据并跳转到编辑页面
        uni.setStorageSync("editData", JSON.stringify(row));
        uni.navigateTo({
          url: "/pages/sales/salesAccount/detail",
        });
        return;
      }
      // 新增操作:直接跳转到编辑页面
      uni.navigateTo({
        url: "/pages/sales/salesAccount/detail",
      });
    } catch (error) {
      console.error("处理台账信息操作失败:", error);
      uni.showToast({
        title: "操作失败,请重试",
        icon: "error",
      });
    }
    const statusStr = String(status).trim();
    const typeMap = {
      待发货: "info",
      待审核: "info",
      审核中: "warning",
      审核拒绝: "danger",
      审核通过: "success",
      已发货: "success",
    };
    return typeMap[statusStr] || "info";
  };
  onShow(() => {
    // 页面显示时刷新列表
  // 获取发货状态文本
  const getShippingStatusText = item => {
    if (item.shippingDate || item.shippingCarNumber) {
      return "已发货";
    }
    const status = item.shippingStatus;
    if (status === null || status === undefined || status === "") {
      return "待发货";
    }
    const statusStr = String(status).trim();
    const textMap = {
      待发货: "待发货",
      待审核: "待审核",
      审核中: "审核中",
      审核拒绝: "审核拒绝",
      审核通过: "审核通过",
      已发货: "已发货",
    };
    return textMap[statusStr] || "待发货";
  };
  // 获取入库状态标签类型
  const getStockStatusTagType = item => {
    if (item.stockStatus === 2) {
      return "success";
    } else if (item.stockStatus === 1) {
      return "warning";
    }
    return "info";
  };
  // 获取入库状态标签
  const getStockStatusLabel = item => {
    if (item.stockStatus === 2) {
      return "已入库";
    } else if (item.stockStatus === 1) {
      return "部分入库";
    }
    return "未入库";
  };
  onMounted(() => {
    getList();
  });
</script>
<style scoped lang="scss">
  @import "@/styles/sales-common.scss";
  .detail-buttons {
  .sales-account {
    min-height: 100vh;
    background: #f8f9fa;
  }
  .sales-ledger-status-bar {
    display: flex;
    gap: 10px;
    background: #fff;
    padding: 12px 16px;
    overflow-x: auto;
    white-space: nowrap;
    gap: 12px;
    border-bottom: 1px solid #eee;
  }
  .sales-ledger-status-tab {
    padding: 8px 16px;
    border-radius: 20px;
    font-size: 14px;
    color: #666;
    background: #f5f7fa;
    transition: all 0.3s;
    flex-shrink: 0;
  }
  .sales-ledger-status-tab.is-active {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: #fff;
  }
  .search-section {
    background: #fff;
    margin: 16px;
    padding: 12px 16px;
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  }
  .search-bar {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .search-input {
    flex: 1;
  }
  .search-text {
    width: 100%;
  }
  .filter-button {
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }
  .ledger-list {
    padding: 0 16px 16px;
  }
  .ledger-item {
    background: #ffffff;
    border-radius: 12px;
    margin-bottom: 16px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    padding: 0 16px;
  }
  .item-header {
    padding: 16px 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .item-left {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .document-icon {
    width: 24px;
    height: 24px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .item-id {
    font-size: 15px;
    color: #333;
    font-weight: 600;
  }
  .item-tag {
    .tag-text {
      font-size: 12px;
      padding: 4px 8px;
      border-radius: 4px;
      background: #f0f2f5;
      color: #666;
      &.warning {
        background: #fff3cd;
        color: #856404;
      }
      &.success {
        background: #d4edda;
        color: #155724;
      }
    }
  }
  .item-details {
    padding-bottom: 16px;
  }
  .detail-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
    &:last-child {
      margin-bottom: 0;
    }
  }
  .detail-label {
    font-size: 13px;
    color: #777777;
    min-width: 100px;
  }
  .detail-value {
    font-size: 13px;
    color: #000000;
    text-align: right;
    flex: 1;
    margin-left: 16px;
    word-break: break-all;
  }
  .detail-value.highlight {
    color: #667eea;
    font-weight: 600;
  }
  .status-tags {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
  .detail-info {
    padding: 8px 0;
  }
  .no-data {
    padding: 60px 0;
    text-align: center;
    color: #999;
  }
</style>