wanshenmean
10 天以前 035f2a81a59532ac9f892dab9ade44304847b4fb
Code/WMS/WIDESEA_WMSClient/src/views/stock/stockInfo.vue
@@ -1,154 +1,478 @@
<template>
    <view-grid
      ref="grid"
      :columns="columns"
      :detail="detail"
      :editFormFields="editFormFields"
      :editFormOptions="editFormOptions"
      :searchFormFields="searchFormFields"
      :searchFormOptions="searchFormOptions"
      :table="table"
      :extend="extend"
    >
    </view-grid>
  </template>
    <script>
  import extend from "@/extension/stock/stockInfo.js";
  import { ref, defineComponent } from "vue";
  export default defineComponent({
    setup() {
      const table = ref({
        key: "id",
        footer: "Foots",
        cnName: "库存信息",
        name: "stockInfo",
        url: "/StockInfo/",
        sortName: "id",
      });
      const editFormFields = ref({
        deviceCode: "",
        deviceName: "",
        deviceType: "",
        deviceStatus: "",
        deviceIp: "",
        devicePort: "",
        devicePlcType: "",
        deviceRemark: "",
      });
      const editFormOptions = ref([
       [
        {field:'palletCode',title:'托盘编号',type:'string'},
        {field:'locationCode',title:'货位编号',type:'string'},
       ]
  <view-grid
    ref="grid"
    :columns="columns"
    :detail="detail"
    :editFormFields="editFormFields"
    :editFormOptions="editFormOptions"
    :searchFormFields="searchFormFields"
    :searchFormOptions="searchFormOptions"
    :table="table"
    :tableExpand="tableExpand"
    :extend="extend"
  >
  </view-grid>
</template>
<script>
import extend from "@/extension/stock/stockInfo.js";
import {
  defineComponent,
  getCurrentInstance,
  h,
  reactive,
  ref,
  resolveComponent,
} from "vue";
const TEXT = {
  pageName: "库存信息",
  palletCode: "托盘编号",
  locationCode: "货位编号",
  warehouse: "仓库",
  creator: "创建人",
  createDate: "创建时间",
  modifier: "修改人",
  modifyDate: "修改时间",
  detailName: "库存明细",
  materielName: "物料名称",
  serialNumber: "电芯码",
  stockQuantity: "库存数量",
  status: "状态",
  inboundOrderRowNo: "通道号",
  detailLoading: "库存明细加载中...",
  detailLoadFailed: "库存明细加载失败",
  detailEmpty: "当前库存头暂无明细数据",
  expandPrefix: "托盘:",
  expandMiddle: " / ",
  expandLocation: "货位:",
};
export default defineComponent({
  setup() {
    const { proxy } = getCurrentInstance();
    const ElTable = resolveComponent("el-table");
    const ElTableColumn = resolveComponent("el-table-column");
    const table = ref({
      key: "id",
      footer: "Foots",
      cnName: TEXT.pageName,
      name: "stockInfo",
      url: "/StockInfo/",
      sortName: "id",
    });
    const editFormFields = ref({
      palletCode: "",
      locationCode: "",
    });
    const editFormOptions = ref([
      [
        { field: "palletCode", title: TEXT.palletCode, type: "string" },
        { field: "locationCode", title: TEXT.locationCode, type: "string" },
      ],
    ]);
    const searchFormFields = ref({
      palletCode: "",
      locationCode: "",
    });
    const searchFormOptions = ref([
      [
        { title: TEXT.palletCode, field: "palletCode", type: "like" },
        { title: TEXT.locationCode, field: "locationCode", type: "like" },
      ],
    ]);
    const columns = ref([
      {
        field: "id",
        title: "Id",
        type: "int",
        width: 90,
        hidden: true,
        readonly: true,
        require: true,
        align: "left",
      },
      {
        field: "palletCode",
        title: TEXT.palletCode,
        type: "string",
        width: 120,
        align: "left",
      },
      {
        field: "locationCode",
        title: TEXT.locationCode,
        type: "string",
        width: 150,
        align: "left",
      },
      {
        field: "warehouseId",
        title: TEXT.warehouse,
        type: "select",
        width: 100,
        align: "left",
        bind: { key: "warehouseEnum", data: [] },
      },
      {
        field: "creater",
        title: TEXT.creator,
        type: "string",
        width: 90,
        align: "left",
      },
      {
        field: "createDate",
        title: TEXT.createDate,
        type: "datetime",
        width: 160,
        align: "left",
      },
      {
        field: "modifier",
        title: TEXT.modifier,
        type: "string",
        width: 100,
        align: "left",
        hidden: true,
      },
      {
        field: "modifyDate",
        title: TEXT.modifyDate,
        type: "datetime",
        width: 160,
        align: "left",
        hidden: true,
      },
    ]);
    const detail = ref({
      cnName: "#detailCnName",
      table: "",
      columns: [],
      sortName: "",
    });
    const detailState = reactive({
      rowsMap: {},
      loadingMap: {},
      errorMap: {},
    });
    const stockStatusOptions = ref([]);
    const detailColumns = [
      { field: "materielName", title: TEXT.materielName, minWidth: 160 },
      { field: "serialNumber", title: TEXT.serialNumber, minWidth: 160 },
      { field: "stockQuantity", title: TEXT.stockQuantity, minWidth: 120 },
      { field: "status", title: TEXT.status, minWidth: 120 },
      { field: "inboundOrderRowNo", title: TEXT.inboundOrderRowNo, minWidth: 120 },
    ];
    const normalizeValue = (value) => {
      return value === null || value === undefined || value === "" ? "--" : value;
    };
    const formatStatusText = (value) => {
      const matched = stockStatusOptions.value.find((item) => `${item.key}` === `${value}`);
      return matched ? matched.value || matched.label : normalizeValue(value);
    };
    const getDetailRows = (stockId) => {
      return detailState.rowsMap[stockId] || [];
    };
    const loadDetailRows = async (row) => {
      if (!row || !row.id || detailState.loadingMap[row.id]) {
        return;
      }
      if (detailState.rowsMap[row.id]) {
        return;
      }
      detailState.loadingMap[row.id] = true;
      detailState.errorMap[row.id] = "";
      try {
        const result = await proxy.http.post("/api/StockInfoDetail/getPageData", {
          page: 1,
          rows: 200,
          sort: "id",
          order: "asc",
          wheres: JSON.stringify([
            {
              name: "stockId",
              value: String(row.id),
              displayType: "int",
            },
          ]),
        });
        detailState.rowsMap[row.id] = (result && result.rows) || [];
      } catch (error) {
        detailState.rowsMap[row.id] = null;
        detailState.errorMap[row.id] = error?.message || TEXT.detailLoadFailed;
      } finally {
        detailState.loadingMap[row.id] = false;
      }
    };
    const loadStockStatusOptions = async () => {
      try {
        const result = await proxy.http.post("/api/Sys_Dictionary/GetVueDictionary", ["stockStatusEmun"]);
        const matched = (result || []).find((item) => item.dicNo === "stockStatusEmun");
        stockStatusOptions.value = matched ? matched.data || [] : [];
      } catch (error) {
        stockStatusOptions.value = [];
      }
    };
    loadStockStatusOptions();
    const renderStatus = (row) => {
      if (detailState.loadingMap[row.id]) {
        return h("div", { class: "stock-detail-status" }, TEXT.detailLoading);
      }
      if (detailState.errorMap[row.id]) {
        return h(
          "div",
          { class: "stock-detail-status stock-detail-status--error" },
          detailState.errorMap[row.id]
        );
      }
      return null;
    };
    const renderDetailTable = (row) => {
      const statusNode = renderStatus(row);
      if (statusNode) {
        return statusNode;
      }
      const rows = getDetailRows(row.id);
      if (!rows.length) {
        return h("div", { class: "stock-detail-status" }, TEXT.detailEmpty);
      }
      return h("div", { class: "stock-detail-table-wrapper" }, [
        h("div", { class: "stock-detail-toolbar" }, [
          h("div", { class: "stock-detail-toolbar__left" }, TEXT.detailName),
          h("div", { class: "stock-detail-toolbar__right" }, [
            h("span", { class: "stock-detail-count" }, `${rows.length} 条`),
          ]),
        ]),
        h(
          ElTable,
          {
            data: rows,
            border: true,
            stripe: true,
            size: "small",
            class: "stock-detail-el-table",
            maxHeight: 420,
            emptyText: TEXT.detailEmpty,
          },
          () =>
            detailColumns.map((column) =>
              h(ElTableColumn, {
                key: column.field,
                prop: column.field,
                label: column.title,
                minWidth: column.minWidth,
                showOverflowTooltip: true,
                formatter: (detailRow) =>
                  column.field === "status"
                    ? formatStatusText(detailRow[column.field])
                    : normalizeValue(detailRow[column.field]),
              })
            )
        ),
      ]);
      const searchFormFields = ref({
        palletCode: "",
        locationCode: "",
      });
      const searchFormOptions = ref([
        [
          { title: "托盘编号", field: "palletCode" },
          { title: "货位编号", field: "locationCode" },
        ],
      ]);
      const columns = ref([
        {
          field: "id",
          title: "Id",
          type: "int",
          width: 90,
          hidden: true,
          readonly: true,
          require: true,
          align: "left",
        },
        {
          field: "palletCode",
          title: "托盘编号",
          type: "string",
          width: 90,
          align: "left",
        },
        {
          field: "locationCode",
          title: "货位编号",
          type: "string",
          width: 150,
          align: "left",
        },
        // {
        //   field: "isFull",
        //   title: "是否满盘",
        //   type: "string",
        //   width: 150,
        //   align: "left",
        //   bind: { key: "yesno", data: [] },
        // },
         {
          field: "warehouseId",
          title: "仓库",
          type: "select",
          width: 100,
          align: "left",
          bind: { key: "warehouseEnum", data: [] },
        },
        {
          field: "creater",
          title: "创建人",
          type: "string",
          width: 90,
          align: "left",
        },
        {
          field: "createDate",
          title: "创建时间",
          type: "datetime",
          width: 160,
          align: "left",
        },
        {
          field: "modifier",
          title: "修改人",
          type: "string",
          width: 100,
          align: "left",
          hidden:true
        },
        {
          field: "modifyDate",
          title: "修改时间",
          type: "datetime",
          width: 160,
          align: "left",
          hidden:true
        },
        {
          field: "remark",
          title: "备注",
          type: "string",
          width: 100,
          align: "left",
          hidden:true
        },
      ]);
      const detail = ref({
        cnName: "#detailCnName",
        table: "",
        columns: [],
        sortName: "",
      });
      return {
        table,
        extend,
        editFormFields,
        editFormOptions,
        searchFormFields,
        searchFormOptions,
        columns,
        detail,
      };
    },
  });
  </script>
    };
    const tableExpand = ref({
      width: 55,
      onChange(row, expandedRows) {
        const isExpanded = expandedRows.some((item) => item.id === row.id);
        if (isExpanded) {
          loadDetailRows(row);
        }
      },
      render(render, { row }) {
        return render("div", { class: "stock-detail-panel" }, [
          render("div", { class: "stock-detail-header" }, [
            render("div", { class: "stock-detail-header__main" }, [
              render("div", { class: "stock-detail-title" }, TEXT.detailName),
              render(
                "div",
                { class: "stock-detail-subtitle" },
                `${TEXT.expandPrefix}${normalizeValue(row.palletCode)}${TEXT.expandMiddle}${TEXT.expandLocation}${normalizeValue(row.locationCode)}`
              ),
            ]),
            // render("div", { class: "stock-detail-tags" }, [
            //   render("span", { class: "stock-detail-tag" }, normalizeValue(row.palletCode)),
            //   render(
            //     "span",
            //     { class: "stock-detail-tag stock-detail-tag--muted" },
            //     normalizeValue(row.locationCode)
            //   ),
            // ]),
          ]),
          renderDetailTable(row),
        ]);
      },
    });
    return {
      table,
      extend,
      editFormFields,
      editFormOptions,
      searchFormFields,
      searchFormOptions,
      columns,
      detail,
      tableExpand,
    };
  },
});
</script>
<style scoped>
.stock-detail-panel {
  margin: 4px 8px 12px;
  padding: 14px 16px 16px;
  background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%);
  border: 1px solid #e8edf3;
  border-radius: 10px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
.stock-detail-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid #edf1f5;
}
.stock-detail-header__main {
  min-width: 0;
}
.stock-detail-title {
  margin-bottom: 4px;
  font-size: 15px;
  font-weight: 700;
  color: #303133;
}
.stock-detail-subtitle {
  font-size: 13px;
  color: #606266;
  line-height: 1.6;
}
.stock-detail-tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}
.stock-detail-tag {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 10px;
  color: #1f5eff;
  background: #edf4ff;
  border: 1px solid #d8e6ff;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.stock-detail-tag--muted {
  color: #4e5969;
  background: #f4f6f8;
  border-color: #e5e9ef;
}
.stock-detail-status {
  padding: 14px 12px;
  color: #606266;
  background: #f8fafc;
  border: 1px dashed #d9e2ec;
  border-radius: 8px;
}
.stock-detail-status--error {
  color: #f56c6c;
  background: #fef0f0;
  border-color: #fde2e2;
}
.stock-detail-table-wrapper {
  overflow-x: auto;
  border: 1px solid #ebeef5;
  border-radius: 8px;
  background: #fff;
}
.stock-detail-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  background: #f8fafc;
  border-bottom: 1px solid #edf1f5;
}
.stock-detail-toolbar__left {
  font-size: 13px;
  font-weight: 600;
  color: #303133;
}
.stock-detail-count {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 10px;
  color: #606266;
  background: #fff;
  border: 1px solid #e5e9ef;
  border-radius: 999px;
  font-size: 12px;
}
:deep(.stock-detail-el-table) {
  border-top: none;
}
:deep(.stock-detail-el-table .el-table__inner-wrapper::before) {
  display: none;
}
:deep(.stock-detail-el-table th.el-table__cell) {
  background: #f5f7fa;
  color: #303133;
  font-weight: 600;
}
:deep(.stock-detail-el-table td.el-table__cell) {
  color: #606266;
}
:deep(.stock-detail-el-table .el-table__body tr:hover > td.el-table__cell) {
  background: #f0f7ff;
}
</style>