Explorar el Código

修改看板菜单为自适应

chensibo hace 1 día
padre
commit
36b83c1be0

+ 75 - 1
src/views/bulletinBoard/components/queryNew.vue

@@ -57,6 +57,7 @@
       border
       :row-style="rowStyle"
       show-overflow-tooltip
+      style="font-size: 8px"
       @selection-change="handleSelectionChange"
       @header-dragend="handleResize"
     >
@@ -182,6 +183,7 @@
       :page.sync="pageNo"
       :limit.sync="pageSize"
       :page-sizes="[5, 10, 20, 30, 50]"
+      :pager-count="1"
       @pagination="handleSearch"
     />
 
@@ -227,7 +229,7 @@ export default {
       list: [],
       originalList: [],
       pageNo: 1,
-      pageSize: 5,
+      pageSize: 3,
       total: 0,
       loading: false,
       form: {},
@@ -1138,4 +1140,76 @@ export default {
   background-color: rgba(255, 255, 255, 0.15) !important;
   color: #fff !important;
 }
+/* 分页组件自适应样式 - 解决页数过多时"每页条数"被挤出的问题 */
+>>> .pagination-container {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 8px; /* 控制分页元素之间的间距 */
+  padding: 8px 0;
+  min-height: 32px; /* 确保有足够高度容纳两行 */
+}
+
+/* 分页主容器弹性布局 */
+>>> .pagination-container .el-pagination {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  flex: 1; /* 占据剩余空间 */
+  min-width: 0; /* 允许收缩 */
+  gap: 4px; /* 页码按钮间距 */
+}
+
+/* 页码区域弹性布局 */
+>>> .el-pagination .el-pager {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+  flex: 1; /* 允许页码区域扩展 */
+  min-width: 0;
+  gap: 2px; /* 页码之间的小间隙 */
+}
+
+/* 调整页码按钮尺寸,节省空间 */
+>>> .el-pagination.is-background .el-pager li {
+  min-width: 28px; /* 减小最小宽度 */
+  height: 28px;
+  line-height: 28px;
+  font-size: 12px;
+  padding: 0 4px; /* 减少内边距 */
+  border: 1px solid rgba(255, 255, 255, 0.25) !important; /* 更细的边框 */
+}
+
+/* 调整分页输入框和选择器的样式 */
+>>> .el-pagination .el-pagination__sizes {
+  flex-shrink: 0; /* 防止被压缩 */
+  margin-right: 8px; /* 与页码区域保持距离 */
+}
+
+>>> .el-pagination .el-pagination__jump {
+  flex-shrink: 0; /* 防止被压缩 */
+  margin-left: 8px;
+  white-space: nowrap; /* 防止换行 */
+}
+
+/* 响应式处理:在空间紧张时调整 */
+@media screen and (max-width: 768px) {
+  >>> .pagination-container {
+    flex-direction: column;
+    align-items: stretch;
+  }
+
+  >>> .pagination-container .el-pagination {
+    justify-content: center;
+  }
+
+  >>> .el-pagination .el-pager {
+    justify-content: center;
+  }
+}
+/* 移除页码按钮边框以节省空间 */
+>>> .el-pagination.is-background .el-pager li {
+  border: none !important; /* 完全移除边框 */
+  margin: 0 1px; /* 用微小外边距替代视觉分隔 */
+}
 </style>

+ 1056 - 0
src/views/bulletinBoard/components/queryNew1.vue

@@ -0,0 +1,1056 @@
+<template>
+  <!-- 唯一根节点:el-card -->
+  <el-card
+    class="el-content-wrap mb-3px"
+    shadow="never"
+    style="height: 100%; display: flex; flex-direction: column"
+  >
+    <!-- 原 content-wrap 的 slot 内容 -->
+    <el-row class="mb-10px" style="flex-shrink: 0">
+      <!-- 按钮区域已注释 -->
+    </el-row>
+
+    <!-- 表格 - 设置高度为100%以撑满剩余空间 -->
+    <el-table
+      id="table_excel"
+      ref="tableRef"
+      v-loading="loading"
+      class="dark-panel"
+      :data="list"
+      border
+      :row-style="rowStyle"
+      :cell-style="cellStyle"
+      height="100%"
+      style="font-size: 11px; flex: 1"
+      show-overflow-tooltip
+      @selection-change="handleSelectionChange"
+      @header-dragend="handleResize"
+    >
+      <el-table-column
+        v-if="showMultipleList.length"
+        key="selection-column"
+        type="selection"
+        width="45"
+      />
+      <el-table-column type="index" width="45" align="center" />
+
+      <template v-for="(item, i) in queryData">
+        <el-table-column
+          v-if="!item.ifHide"
+          :key="item.id"
+          :label="item.columnComment"
+          :prop="item.columnComment"
+          align="center"
+          :min-width="item.javaField || ''"
+          :sortable="false"
+          show-overflow-tooltip
+        >
+          <template slot="header">
+            <div class="mr-5px flex items-center" style="font-size: 11px">
+              <!-- 排序图标 -->
+              <div v-show="item.ifSort" class="mr-5px flex flex-col gap-0">
+                <i
+                  class="el-icon-caret-top"
+                  style="font-size: 12px; cursor: pointer"
+                  :class="{
+                    'is-sort':
+                      currentSortField === item.columnComment &&
+                      currentSortDirection === 'asc',
+                  }"
+                  @click="handleSort(item.columnComment, 'asc')"
+                />
+                <i
+                  ref=""
+                  class="el-icon-caret-bottom -mt-1.2"
+                  style="font-size: 12px; cursor: pointer"
+                  :class="{
+                    'is-sort':
+                      currentSortField === item.columnComment &&
+                      currentSortDirection === 'desc',
+                  }"
+                  @click="handleSort(item.columnComment, 'desc')"
+                />
+              </div>
+
+              <span>{{ item.columnComment }}</span>
+            </div>
+          </template>
+
+          <template slot-scope="{ row }">
+            <div
+              :class="{ active: item.example }"
+              @click="
+                pathChange(item.example, row[item.columnComment], item, row)
+              "
+            >
+              <dict-tag
+                v-if="
+                  isDict(item.columnComment) &&
+                  ![undefined, null].includes(row[item.columnComment])
+                "
+                :type="isDict(item.columnComment)"
+                :value="row[item.columnComment]"
+              />
+              <span
+                v-else-if="
+                  row[item.columnComment] && isDateTime(item.columnComment)
+                "
+              >
+                {{ formatToDateTime(row[item.columnComment]) }}
+              </span>
+              <span v-else>{{ row[item.columnComment] }}</span>
+            </div>
+          </template>
+        </el-table-column>
+      </template>
+    </el-table>
+
+    <!-- 分页 - 仅在刷新时间为0时显示 -->
+    <pagination
+      v-show="total > 0 && refreshMin == 0"
+      :total="total"
+      :page.sync="pageNo"
+      :limit.sync="pageSize"
+      :page-sizes="[5, 10, 20, 30, 50]"
+      style="flex-shrink: 0; margin-top: 4px"
+      @pagination="handleSearch"
+    />
+
+    <!-- 弹窗 -->
+    <ReportPrint ref="reportPrint" />
+    <ParameterDetail ref="parameterDetailRef" @success="getQueryData" />
+  </el-card>
+</template>
+
+<script>
+import * as QueryManageApi from "@/api/mes/queryManage";
+import { getQueryManageButtonPage } from "@/api/mes/queryManage/button";
+import { saveAs } from "file-saver";
+import * as XLSX from "xlsx";
+import FilterColumnInQuery from "@/views/mes/queryManage/components/FilterColumnInQuery.vue";
+import DictTag from "@/components/DictTag";
+import ParameterDetail from "@/views/mes/queryManage/components/ParameterDetail.vue";
+import ReportPrint from "@/views/mes/queryManage/components/ReportPrint.vue";
+import request from "@/utils/request";
+import { getAccessToken, getTenantId } from "@/utils/auth";
+import axios from "axios";
+
+export default {
+  name: "QueryNew",
+  components: {
+    FilterColumnInQuery,
+    ParameterDetail,
+    ReportPrint,
+    DictTag,
+  },
+  props: {
+    documentId: { type: String, required: true },
+    refreshMin: { type: Number, default: 10 },
+  },
+  data() {
+    return {
+      title: "",
+      message: "",
+      baseUrl: "",
+      queryList: [],
+      searchData: [],
+      queryData: [],
+      list: [],
+      originalList: [],
+      pageNo: 1,
+      pageSize: 5,
+      total: 0,
+      loading: false,
+      form: {},
+      visible: false,
+      customFilters: {},
+      currentSortField: null,
+      currentSortDirection: null,
+      dynamicButtons: [],
+      queryParamList: [],
+      exportLoading: false,
+      showMultipleList: [],
+      isClear: false,
+      multipleSelection: [],
+      headerWidthChange: false,
+      filterKey: 0,
+      filterAlive: true,
+      autoPageTimer: null,
+    };
+  },
+  watch: {
+    "$route.query.name": {
+      handler(newName) {
+        this.title =
+          newName || this.$route.redirectedFrom?.meta?.title || "查询";
+      },
+    },
+    "$route.query.id": {
+      handler() {
+        this.init();
+      },
+    },
+    refreshMin: {
+      handler() {
+        this.restartAutoPage();
+      },
+      immediate: true,
+    },
+  },
+  mounted() {
+    this.init();
+    this.startAutoPage();
+  },
+  activated() {
+    this.init();
+  },
+  beforeDestroy() {
+    this.stopAutoPage();
+    this.saveColumnWidth();
+  },
+  created() {
+    this.baseUrl = process.env.VUE_APP_REPORT_API;
+  },
+  methods: {
+    async init() {
+      this.title =
+        this.$route.query?.name ||
+        this.$route.redirectedFrom?.meta?.title ||
+        "查询";
+      if (this.documentId) {
+        await this.getFilterData();
+      } else {
+        this.buildQueryParamFromRoute();
+        await this.getQueryData();
+      }
+    },
+
+    async getQueryData() {
+      try {
+        this.loading = true;
+        const data = await QueryManageApi.getQueryManageColumnListByMasterId(
+          this.documentId
+        );
+        this.queryData = Array.isArray(data.data) ? data.data || [] : [];
+        this.searchData = this.queryData.filter(
+          (item) => item.listOperationResult && item.ifHide === false
+        );
+        this.showMultipleList = this.queryData.filter(
+          (item) => item.listOperationCondition === "1"
+        );
+        this.queryList = [];
+        for (let i = 0; i < this.searchData.length; i++) {
+          const { dataType, htmlType, dictType, columnName } =
+            this.searchData[i];
+          this.queryList.push({
+            dataType,
+            htmlType,
+            dictType,
+            key: columnName,
+            operate: dataType === "ym_string_query_type" ? "like" : "",
+          });
+        }
+        await this.getManageButtons(this.documentId);
+        await this.getList();
+      } catch (error) {
+        console.error("getQueryData 出现了错误:", error);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    async getList() {
+      try {
+        this.loading = true;
+        const data = await QueryManageApi.loadTableData({
+          pageNo: this.pageNo,
+          pageSize: this.pageSize,
+          paramList: this.queryParamList,
+          id: this.documentId,
+        });
+        this.list = data?.data?.list || [];
+        this.originalList = JSON.parse(JSON.stringify(data?.data?.list || []));
+        this.total = data?.data?.total || 0;
+      } catch (error) {
+        console.error("getList错误:", error);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    async getManageButtons(masterId) {
+      const data = await getQueryManageButtonPage({ masterId });
+      this.dynamicButtons = data?.data?.list || [];
+    },
+
+    async handleDynamicButtonClick(btn = {}) {
+      const {
+        ifJimu,
+        interfaceUrl,
+        printSoft,
+        operateType,
+        paramList = [],
+      } = btn;
+
+      if (ifJimu) {
+        this.handlePrintByJimu(btn);
+      } else if (this.isFullUrl(interfaceUrl) && printSoft) {
+        this.handlePrintByOtherSoft(btn);
+      } else if (operateType === 2) {
+        this.$refs.parameterDetailRef.open(
+          "create",
+          btn,
+          this.documentId,
+          [],
+          this.queryData
+        );
+      } else if (operateType === 3) {
+        if (this.multipleSelection.length === 0) {
+          return this.$message.warning("请先选择行数据!");
+        }
+        if (this.multipleSelection.length > 1) {
+          return this.$message.warning("只能选择单条数据修改!");
+        }
+        this.$refs.parameterDetailRef.open(
+          "update",
+          btn,
+          this.documentId,
+          this.multipleSelection,
+          this.queryData
+        );
+      } else if (operateType === 7) {
+        this.$router.push({ path: `${interfaceUrl}` });
+      } else {
+        this.handleDynamic(btn);
+      }
+    },
+
+    getButtonIcon(btn) {
+      const { buttonName, operateType } = btn;
+      const name = buttonName.toLowerCase();
+
+      if (
+        name.includes("新增") ||
+        name.includes("添加") ||
+        name.includes("创建")
+      ) {
+        return "el-icon-circle-plus";
+      } else if (name.includes("保存") || name.includes("提交")) {
+        return "el-icon-check";
+      } else if (name.includes("审核") || name.includes("审批")) {
+        return "el-icon-document-checked";
+      }
+
+      switch (operateType) {
+        case 2:
+          return "el-icon-circle-plus";
+        case 3:
+          return "el-icon-edit";
+        case 4:
+          return "el-icon-delete";
+        case 5:
+          return "el-icon-download";
+        case 6:
+          return "el-icon-printer";
+        case 7:
+          return "el-icon-right";
+        default:
+          return "el-icon-star-off";
+      }
+    },
+
+    getButtonType(btn) {
+      const { operateType } = btn;
+
+      switch (operateType) {
+        case 2:
+          return "success";
+        case 3:
+          return "warning";
+        case 4:
+          return "danger";
+        case 5:
+          return "primary";
+        case 6:
+          return "info";
+        case 7:
+          return "success";
+        default:
+          return "primary";
+      }
+    },
+
+    formatToDateTime(val) {
+      const d = val ? new Date(val) : new Date();
+      if (isNaN(d.getTime())) return "";
+      const pad = (n) => String(n).padStart(2, "0");
+      return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
+        d.getDate()
+      )} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
+    },
+
+    handlePrintByJimu(params) {
+      if (this.multipleSelection.length === 0) {
+        return this.$message.warning("请先选择数据!");
+      }
+
+      const interfaceUrl = String(params.interfaceUrl || "").trim();
+      if (!interfaceUrl || interfaceUrl === "0") {
+        return this.$message.error("接口地址未配置或格式错误!");
+      }
+
+      const token = getAccessToken();
+      const tenantId = getTenantId();
+      const { paramList = [], reportId } = params;
+      const fieldValues = this.paramsToConver(paramList);
+      const printParams = new URLSearchParams({
+        token,
+        tenantId,
+        ...fieldValues,
+      });
+      const src = `${
+        this.baseUrl
+      }${interfaceUrl}${reportId}?${printParams.toString()}`;
+      this.$refs.reportPrint.open(
+        src,
+        this.$route.query?.name ||
+          this.$route.redirectedFrom?.meta?.title ||
+          "报表打印"
+      );
+    },
+
+    async handlePrintByOtherSoft(params) {
+      if (this.multipleSelection.length === 0) {
+        return this.$message.warning("请先选择数据!");
+      }
+
+      const { interfaceUrl, paramList, restMethod, templet } = params;
+      if (!templet) return this.$message.warning("未配置打印模板!");
+
+      const url = String(interfaceUrl || "").trim();
+      if (!url || url === "0") {
+        this.$message.error("接口地址未配置或格式错误!");
+        return;
+      }
+
+      const fieldValues = this.paramsToConver(paramList);
+      const printParams = { ...fieldValues, fileUrl: templet };
+      const config = {
+        method: restMethod,
+        url,
+        [restMethod === "get" || restMethod === "delete" ? "params" : "data"]:
+          printParams,
+      };
+      await axios(config);
+      this.$message.success("操作成功!");
+      this.getList();
+    },
+
+    async handleDynamic(params) {
+      if (this.multipleSelection.length === 0) {
+        return this.$message.warning("请先选择数据!");
+      }
+
+      const {
+        interfaceUrl,
+        restMethod = "get",
+        paramList = [],
+        requestParameter = "0",
+      } = params;
+
+      const url = String(interfaceUrl || "").trim();
+      if (!url || url === "0") {
+        this.$message.error("接口地址未配置或格式错误!");
+        return;
+      }
+
+      const fieldValues = this.paramsToConver(paramList);
+      const config = { method: restMethod, url };
+      this.handleGetDelete(config, fieldValues, String(requestParameter));
+
+      await request(config);
+
+      this.$message.success("操作成功");
+      this.getList();
+    },
+
+    handleGetDelete(config, fieldValues, requestParameter) {
+      switch (requestParameter) {
+        case "1":
+          config.params = fieldValues;
+          break;
+        case "3":
+          const queryString = new URLSearchParams(fieldValues).toString();
+          config.url = queryString
+            ? `${config.url}?${queryString}`
+            : config.url;
+          break;
+        case "4":
+          config.headers = { ...config.headers, ...fieldValues };
+          break;
+        default:
+          config.data = fieldValues;
+      }
+    },
+
+    paramsToConver(paramList) {
+      const matchListWithParam = paramList
+        ?.filter((item) =>
+          this.queryData.some((query) => item.columnId === query?.id)
+        )
+        .map((item) => {
+          const paramItem = this.queryData.find(
+            (query) => item.columnId === query?.id
+          );
+          return { ...item, columnComment: paramItem?.columnComment };
+        });
+      const result = this.generateMappedData(
+        this.multipleSelection,
+        matchListWithParam
+      );
+      const allFields = [...new Set(result.flatMap(Object.keys))];
+      return allFields.reduce((acc, field) => {
+        acc[field] = result.map((item) => item[field]).join(",");
+        return acc;
+      }, {});
+    },
+
+    generateMappedData(selectList, keys) {
+      return selectList.map((item) =>
+        keys.reduce((res, key) => {
+          const { columnComment, paramName } = key;
+          if (item.hasOwnProperty(columnComment)) {
+            const field = paramName.split(".").pop();
+            res[field] = item[columnComment];
+          }
+          return res;
+        }, {})
+      );
+    },
+
+    isFullUrl(url) {
+      try {
+        const parsed = new URL(url);
+        return parsed.protocol === "http:" || parsed.protocol === "https:";
+      } catch {
+        return false;
+      }
+    },
+
+    isDict(key) {
+      if (!Array.isArray(this.queryData)) return false;
+      const item = this.queryData.find((item) => item.columnComment === key);
+      return item ? item.dictType : false;
+    },
+
+    isNumber(key) {
+      if (!Array.isArray(this.queryData)) return false;
+      const item = this.queryData.find((item) => item.columnComment === key);
+      return item && item.dataType === "ym_int_query_type";
+    },
+
+    isDateTime(key) {
+      if (!Array.isArray(this.queryData)) return false;
+      const item = this.queryData.find((item) => item.columnComment === key);
+      if (!item) return false;
+
+      const timeTypes = [
+        "LocalDateTime",
+        "LocalDate",
+        "LocalTime",
+        "Date",
+        "Timestamp",
+        "DateTime",
+        "java.util.Date",
+        "java.sql.Date",
+        "java.sql.Timestamp",
+      ];
+
+      return timeTypes.includes(item.javaType);
+    },
+
+    hasFilter(field) {
+      return !!(this.customFilters[field] && this.customFilters[field].length);
+    },
+
+    handleSort(field, direction) {
+      if (
+        this.currentSortField === field &&
+        this.currentSortDirection === direction
+      ) {
+        this.currentSortField = "";
+        this.currentSortDirection = "";
+        this.list = JSON.parse(JSON.stringify(this.originalList));
+        return;
+      }
+      this.currentSortField = field;
+      this.currentSortDirection = direction;
+      this.list = [...this.originalList].sort((a, b) => {
+        let valA = a[field];
+        let valB = b[field];
+        valA =
+          typeof valA === "string" ? parseFloat(valA.replace(/,/g, "")) : valA;
+        valB =
+          typeof valB === "string" ? parseFloat(valB.replace(/,/g, "")) : valB;
+        if (isNaN(valA)) {
+          return direction === "asc"
+            ? valA > valB
+              ? 1
+              : -1
+            : valA < valB
+            ? 1
+            : -1;
+        }
+        if (isNaN(valB)) {
+          return direction === "asc"
+            ? valA > valB
+              ? 1
+              : -1
+            : valA < valB
+            ? 1
+            : -1;
+        }
+        return direction === "asc" ? valA - valB : valB - valA;
+      });
+    },
+
+    filterData(data, field, type, row) {
+      const { dataType } = row;
+      this.$set(this.customFilters, field, data);
+      const isDateRange = data[0]?.isRange;
+      if (isDateRange) {
+        const valueList = data.flatMap((item) => item.column).join(",");
+        const idx = this.queryParamList.findIndex((item) => item.key === field);
+        if (idx > -1) {
+          this.queryParamList[idx].value = valueList;
+        } else {
+          this.queryParamList.push({
+            key: field,
+            operate: "like",
+            htmlType: type,
+            value: valueList,
+          });
+        }
+        this.getList();
+        return;
+      }
+      let valueStr;
+      if (data.length) {
+        valueStr =
+          dataType === "ym_int_query_type"
+            ? data.map((item) => item.column).join(",")
+            : data.map((item) => `'${item.column}'`).join(",");
+        const idx = this.queryParamList.findIndex((item) => item.key === field);
+        if (idx > -1) {
+          this.queryParamList[idx].value = valueStr;
+        } else {
+          this.queryParamList.push({
+            key: field,
+            operate: "like",
+            htmlType: type,
+            value: valueStr,
+          });
+        }
+      } else {
+        const idx = this.queryParamList.findIndex((item) => item.key === field);
+        if (idx > -1) this.queryParamList.splice(idx, 1);
+      }
+      this.getList();
+    },
+
+    AllConditionReset() {
+      this.filterAlive = false;
+      const tmp = this.queryData;
+      this.queryData = [];
+
+      this.queryParamList = [];
+      this.customFilters = {};
+      this.currentSortField = null;
+      this.currentSortDirection = null;
+      this.pageNo = 1;
+      this.pageSize = 20;
+      this.multipleSelection = [];
+      this.isClear = true;
+
+      this.$nextTick(() => {
+        this.filterKey++;
+        this.queryData = tmp;
+        this.filterAlive = true;
+
+        this.$nextTick(() => {
+          this.getList();
+          setTimeout(() => (this.isClear = false), 1000);
+        });
+      });
+    },
+
+    handleSearch() {
+      this.list = [];
+      this.getList();
+    },
+
+    async Export() {
+      try {
+        await this.$confirm("确定导出当前页?", "提示", { type: "warning" });
+        setTimeout(() => {
+          const xlsxParam = { raw: true };
+          const tables = document.getElementById("table_excel");
+          const table_book = XLSX.utils.table_to_book(tables, xlsxParam);
+          const tableWrite = XLSX.write(table_book, {
+            bookType: "xlsx",
+            bookSST: true,
+            type: "array",
+          });
+          saveAs(
+            new Blob([tableWrite], { type: "application/octet-stream" }),
+            `${this.title}.xlsx`
+          );
+        }, 1000);
+      } catch (error) {
+        if (error !== "cancel") {
+          console.error("导出失败:", error);
+          this.$message.error("导出失败");
+        }
+      }
+    },
+
+    async ExportAll() {
+      try {
+        await this.$confirm("确定导出全部?", "提示", { type: "warning" });
+        this.exportLoading = true;
+        const data = await QueryManageApi.exportExcel({
+          id: this.documentId,
+          paramList: this.queryParamList,
+        });
+        this.$download.excel(data, this.title + ".xls");
+      } catch (error) {
+        if (error !== "cancel") {
+          console.error("导出失败:", error);
+          this.$message.error("导出失败");
+        }
+      } finally {
+        this.exportLoading = false;
+      }
+    },
+
+    getHandleNumber(val) {
+      return Math.round(parseFloat(val) * 100000000) / 100000000;
+    },
+
+    getSummaries({ columns }) {
+      const sums = [];
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = "总计";
+          return;
+        }
+        const values = this.list.map((item) => Number(item[column.property]));
+        if (this.isNumber(column.property)) {
+          sums[index] = values.reduce((acc, cur) => {
+            const value = Number(cur);
+            return !isNaN(value) ? this.getHandleNumber(acc + cur) : acc;
+          }, 0);
+        }
+      });
+      return sums;
+    },
+
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+
+    pathChange(path, val, item, row) {
+      if (path === "sameRouter") return;
+      if (!path) return;
+      const data = {};
+      this.dynamicButtons
+        .filter((v) => v.ifHide && v.paramList.length)
+        .forEach((v) =>
+          v.paramList.forEach((val) => {
+            data[val.paramName] = val.value || row[val.paramComment];
+          })
+        );
+      this.$router.push({ path: `${path}`, query: { id: val, ...data } });
+    },
+
+    handleBack() {
+      this.$router.push({ path: "/querymanage/queryManageIndex" });
+    },
+
+    handleResize() {
+      this.headerWidthChange = true;
+    },
+
+    async saveColumnWidth() {
+      if (!this.headerWidthChange) return;
+      this.headerWidthChange = false;
+
+      const widthList = [];
+      const visibleMap = new Map(
+        this.queryData.filter((c) => !c.ifHide).map((c) => [c.columnComment, c])
+      );
+
+      const thList = Array.from(
+        this.$refs.tableRef.$el.querySelectorAll(
+          ".el-table__header-wrapper tr th"
+        )
+      ).filter(
+        (th) =>
+          !th.classList.contains("el-table-column--selection") &&
+          !th.classList.contains("el-table-column--index")
+      );
+
+      thList.forEach((th) => {
+        const w = th.offsetWidth;
+        if (!w) return;
+        const comment = th.innerText.trim();
+        const col = visibleMap.get(comment);
+        if (col) widthList.push({ id: col.id, javaField: w });
+      });
+
+      if (widthList.length) {
+        await QueryManageApi.updateWidth(widthList);
+      }
+    },
+
+    buildQueryParamFromRoute() {
+      const queryParam = [];
+      for (const i in this.$route.query) {
+        if (i !== "id" && i !== "name") {
+          queryParam.push({
+            key: i,
+            operate: "like",
+            htmlType: "input",
+            value: "'" + this.$route.query[i] + "'",
+          });
+        }
+      }
+      this.queryParamList = queryParam;
+    },
+
+    async getFilterData() {
+      const data = await getQueryManageButtonPage({
+        masterId: this.$route.query?.infraQueryId || this.documentId,
+      });
+      const list = data?.data?.list || data?.data || [];
+      const arr = [];
+      list
+        .filter((v) => v.ifHide && v.paramList.length)
+        .forEach((v) =>
+          v.paramList.forEach((val) => {
+            if (val.filter) arr.push(val.paramName);
+          })
+        );
+      const queryParam = [];
+      for (const i in this.$route.query) {
+        if (arr.indexOf(i) > -1) {
+          queryParam.push({
+            key: i,
+            operate: "like",
+            htmlType: "input",
+            value: "'" + this.$route.query[i] + "'",
+          });
+        }
+      }
+      this.queryParamList = queryParam;
+      await this.getQueryData();
+    },
+
+    handleRefresh() {
+      location.reload(true);
+    },
+
+    startAutoPage() {
+      this.stopAutoPage();
+      const ms = this.refreshMin * 1000;
+      if (!ms || ms <= 0) return;
+      this.autoPageTimer = setInterval(() => {
+        const max = Math.ceil(this.total / this.pageSize);
+        this.pageNo = this.pageNo < max ? this.pageNo + 1 : 1;
+        this.getList();
+      }, ms);
+    },
+
+    stopAutoPage() {
+      if (this.autoPageTimer) {
+        clearInterval(this.autoPageTimer);
+        this.autoPageTimer = null;
+      }
+    },
+
+    restartAutoPage() {
+      this.startAutoPage();
+    },
+
+    // 修改后的 rowStyle - 添加固定行高
+    rowStyle({ row }) {
+      const baseStyle = { height: "28px" };
+      if (row.colorControl) {
+        return {
+          ...baseStyle,
+          backgroundColor: row.colorControl + " !important",
+        };
+      }
+      return baseStyle;
+    },
+
+    // 新增 cellStyle - 控制单元格内边距
+    cellStyle() {
+      return {
+        padding: "2px 0",
+        fontSize: "11px",
+      };
+    },
+  },
+};
+</script>
+
+<style scoped>
+/* ---------- ContentWrap 原样式 ---------- */
+.el-content-wrap {
+  overflow-y: auto;
+}
+.text-16px {
+  font-size: 16px;
+}
+.font-700 {
+  font-weight: 700;
+}
+.ml-5px {
+  margin-left: 5px;
+}
+.max-w-200px {
+  max-width: 200px;
+}
+.mb-3px {
+  margin-bottom: 3px;
+}
+
+/* ---------- 表格样式优化 ---------- */
+/* 行高设置 - 修改为28px */
+:deep(.el-table__row) {
+  height: 28px !important;
+}
+
+/* 单元格样式 */
+:deep(.el-table .cell) {
+  line-height: 24px !important;
+  padding: 2px 4px !important;
+  font-size: 11px !important;
+}
+
+/* 表头样式 */
+:deep(.el-table th) {
+  height: 28px !important;
+  padding: 0 !important;
+}
+
+:deep(.el-table th > .cell) {
+  line-height: 28px !important;
+  font-size: 11px !important;
+  font-weight: 600;
+}
+
+/* 表格整体字体 */
+:deep(.el-table) {
+  font-size: 11px !important;
+}
+
+/* 选中列和索引列宽度调整 */
+:deep(.el-table-column--selection),
+:deep(.el-table-column--index) {
+  width: 45px !important;
+  min-width: 45px !important;
+}
+
+.active:hover {
+  cursor: pointer;
+}
+.has-filter,
+.is-sort,
+.active {
+  color: #1890ff !important;
+}
+
+/* ========= 整卡背景 & 边框 ========= */
+>>> .el-card,
+>>> .el-card__body {
+  background-color: #0a1e44 !important;
+  color: #fff !important;
+  border-color: #1a2e5a !important;
+}
+
+/* ========= 卡片头部 ========= */
+>>> .el-card__header {
+  background-color: #071b38 !important;
+  color: #fff !important;
+  border-bottom: 1px solid #1a2e5a !important;
+}
+
+/* ========= 表格整体 ========= */
+>>> .el-table,
+>>> .el-table__body-wrapper,
+>>> .el-table__header-wrapper {
+  background-color: transparent !important;
+  color: #fff !important;
+}
+
+/* ========= 表头 ========= */
+>>> .el-table th,
+>>> .el-table th > .cell {
+  background-color: #071b38 !important;
+  color: #fff !important;
+}
+
+/* ========= 表行/表格 ========= */
+>>> .el-table tr,
+>>> .el-table td,
+>>> .el-table td > .cell {
+  background-color: transparent !important;
+  color: #fff !important;
+}
+
+/* ========= 鼠标悬停 ========= */
+>>> .el-table__body tr:hover > td {
+  background-color: rgba(255, 255, 255, 0.12) !important;
+}
+
+/* ========= 分页器/底部工具栏 ========= */
+>>> .el-pagination__total,
+>>> .el-pagination__jump,
+>>> .el-pager li {
+  color: #fff !important;
+}
+
+/* ========= 去掉列表与分页之间白块 ========= */
+>>> .el-card__body {
+  padding-bottom: 0 !important;
+}
+
+>>> .pagination-container .el-pagination {
+  margin-top: 0 !important;
+}
+
+>>> .pagination-container {
+  margin-top: -4px;
+  background-color: #0a1e44 !important;
+}
+
+/* ========= 分页数字块 ========= */
+>>> .el-pagination.is-background .el-pager li {
+  background-color: transparent !important;
+  color: #fff !important;
+  border: 1px solid rgba(255, 255, 255, 0.35) !important;
+}
+
+>>> .el-pagination.is-background .el-pager li.active {
+  background-color: rgba(255, 255, 255, 0.9) !important;
+  color: #0a1e44 !important;
+  border-color: transparent !important;
+}
+
+>>> .el-pagination.is-background .el-pager li:hover:not(.active) {
+  background-color: rgba(255, 255, 255, 0.15) !important;
+  color: #fff !important;
+}
+</style>

+ 164 - 91
src/views/bulletinBoard/finishedGoodsWarehouse/index.vue

@@ -1,39 +1,43 @@
 <template>
   <div class="app-container">
-    <span style="color: white; font-weight: bold; margin-right: 10px"
-      >刷新时间(秒,输入0关闭刷新)</span
-    >
-    <el-input
-      v-model="num"
-      style="width: 240px"
-      placeholder="请添加刷新时间"
-      :min="1"
-      type="number"
-      @change="handleChange"
-    />
-    <el-row :gutter="10" type="flex">
-      <!-- 标题 -->
-      <el-col :span="24" class="charts-card chart-header">
-        <DashboardHeader height="4vh" content="成品仓看板" />
-      </el-col>
-    </el-row>
-    <!-- 固定两列,一行两个列表 -->
-    <el-row :gutter="16" class="row-equal-height list-row">
-      <el-col v-for="tab in tabs" :key="tab.name" :span="12">
-        <el-card :header="tab.label" shadow="hover" class="list-card">
-          <QueryNew
-            :document-id="tab.documentId"
-            class="query-container"
-            :refresh-min="num"
-          />
-        </el-card>
-      </el-col>
-    </el-row>
+    <!-- 控制栏 -->
+    <div class="control-bar">
+      <span class="control-label">刷新时间(秒,输入0关闭刷新)</span>
+      <el-input
+        v-model="num"
+        class="refresh-input"
+        placeholder="请添加刷新时间"
+        :min="1"
+        type="number"
+        @change="handleChange"
+      />
+    </div>
+
+    <!-- 标题 -->
+    <div class="header-section">
+      <DashboardHeader height="100%" content="成品仓看板" />
+    </div>
+
+    <!-- 列表区域 -->
+    <div class="content-section">
+      <div class="grid-container">
+        <div v-for="tab in tabs" :key="tab.name" class="grid-item">
+          <el-card :header="tab.label" shadow="hover" class="list-card">
+            <QueryNew
+              :document-id="tab.documentId"
+              class="query-container"
+              :refresh-min="num"
+            />
+          </el-card>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
 import QueryNew from "@/views/bulletinBoard/components/queryNew.vue";
+// import QueryNew from "@/views/bulletinBoard/components/queryNew1.vue";
 import DashboardHeader from "@/views/bulletinBoard/components/dashboardHeader.vue";
 import screenfull from "screenfull";
 export default {
@@ -42,9 +46,6 @@ export default {
   data() {
     return {
       num: 10,
-      /* 配置
-         name属性随便取值,与activeNames一致即可
-      */
       tabs: [
         {
           label: "成品待入库列表",
@@ -71,45 +72,26 @@ export default {
           name: "slitting",
           documentId: "2005540102913298433",
         },
-        // {
-        //   label: "库存呆滞料查询",
-        //   name: "annealing",
-        //   documentId: "2005521571224129538",
-        // },
-        // { label: "包装", name: "packaging", documentId: "1922203958663839745" },
-        // { label: "入库", name: "storage", documentId: "1922209219612901378" },
-      ],
-      /* 默认全部展开 */
-      activeNames: [
-        "preRollPass",
-        "mergedPreRollPass",
-        "rollUp",
-        "finalPass",
-        "slitting",
-        // "annealing",
-        // "packaging",
-        // "storage",
       ],
     };
   },
   mounted() {
-    this.enterFullScreen(); // ② 挂载后调用
+    this.enterFullScreen();
   },
   methods: {
     handleChange(v) {
       const n = Number(v);
       if (isNaN(n) || n < 0) {
         this.$message.warning("请输入≥0的整数,输入0关闭刷新");
-        this.num = 10; // 恢复默认值
+        this.num = 10;
         return;
       }
       this.num = n;
     },
     enterFullScreen() {
-      // 延迟 1 秒避免浏览器拦截
       setTimeout(() => {
         if (screenfull.isEnabled) {
-          screenfull.toggle(); // 等同于 requestFullscreen
+          screenfull.toggle();
         }
       }, 1000);
     },
@@ -118,65 +100,156 @@ export default {
 </script>
 
 <style scoped>
-/* 统一整行高度 */
-.row-equal-height {
+/* 主容器 - 自适应全屏 */
+.app-container {
+  background: -webkit-radial-gradient(
+    50% 35%,
+    farthest-corner,
+    #034f8e,
+    #034987,
+    #02366d,
+    #002353
+  );
+  height: 100vh; /* 使用视口高度 */
+  width: 100vw; /* 使用视口宽度 */
+  padding: 6px 8px;
+  margin: 0 !important;
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  overflow: hidden; /* 禁止滚动条 */
+}
+
+/* 控制栏 - 压缩高度 */
+.control-bar {
+  flex-shrink: 0;
+  height: 28px;
   display: flex;
-  flex-wrap: wrap;
+  align-items: center;
+  margin-bottom: 6px;
 }
 
-/* 卡片容器:统一高度 */
+.control-label {
+  color: white;
+  font-weight: bold;
+  margin-right: 8px;
+  font-size: 12px;
+  white-space: nowrap;
+}
+
+.refresh-input {
+  width: 160px !important;
+}
+
+.refresh-input ::v-deep .el-input__inner {
+  height: 24px;
+  line-height: 24px;
+  padding: 0 8px;
+  font-size: 12px;
+}
+
+/* 标题区域 - 压缩 */
+.header-section {
+  flex-shrink: 0;
+  height: 32px;
+  margin-bottom: 6px;
+}
+
+/* 内容区域 - 剩余所有空间 */
+.content-section {
+  flex: 1;
+  min-height: 0;
+  overflow: hidden; /* 禁止滚动条 */
+}
+
+/* Grid布局 - 3列2行,自适应填充 */
+.grid-container {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  grid-template-rows: repeat(2, minmax(0, 1fr));
+  gap: 6px;
+  height: 100%;
+  width: 100%;
+}
+
+/* 5个卡片的分布:前3个第一行,后2个第二行居中 */
+.grid-item {
+  min-height: 0;
+  min-width: 0;
+  overflow: hidden;
+}
+
+/* 第4、5个卡片在第二行居中显示 */
+.grid-item:nth-child(4) {
+  grid-column: 1 / 2;
+  justify-self: end;
+  width: 95%;
+}
+
+.grid-item:nth-child(5) {
+  grid-column: 2 / 3;
+  justify-self: start;
+  width: 95%;
+}
+
+/* 卡片样式 - 紧凑 */
 .list-card {
   height: 100%;
-  margin-bottom: 16px;
   display: flex;
   flex-direction: column;
 }
 
-/* 内容区撑满剩余高度 */
-.query-container {
-  flex: 1 1 auto;
-  overflow: auto; /* 如果内容超出出现滚动条 */
-}
-
-/* 让卡片标题变蓝 */
-::v-deep .el-card__header {
+.list-card ::v-deep .el-card__header {
   color: #8adfec;
   font-weight: 600;
   background-color: #192849;
+  padding: 4px 8px;
+  height: 26px;
+  line-height: 18px;
+  font-size: 12px;
+  flex-shrink: 0;
 }
 
-/* 深蓝径向渐变背景 */
-.app-container {
-  background: -webkit-radial-gradient(
-    50% 35%,
-    farthest-corner,
-    #034f8e,
-    #034987,
-    #02366d,
-    #002353
-  );
-  min-height: 100vh;
-  width: 100%;
-  padding: 1vh;
-  margin: 0 !important;
+.list-card ::v-deep .el-card__body {
+  flex: 1;
+  padding: 4px;
+  overflow: hidden; /* 禁止滚动条 */
+  display: flex;
+  flex-direction: column;
 }
-.list-row {
-  margin-top: 20px;
+
+/* 内容区 - 内部可滚动 */
+.query-container {
+  flex: 1;
+  min-height: 0;
+  overflow: auto; /* 允许内容区内部滚动 */
 }
+
+/* 输入框样式 */
 ::v-deep .el-input__inner {
-  background: transparent !important; /* 关键:完全透明 */
-  border: 1px solid #034f8e; /* 保留你原来的边框 */
-  color: #fff; /* 字色白色 */
+  background: transparent !important;
+  border: 1px solid #034f8e;
+  color: #fff;
 }
+
 ::v-deep .el-input__inner::placeholder {
-  color: #fff;
+  color: #ccc;
+  font-size: 12px;
 }
-/* 整卡统一深蓝 */
+
+/* 卡片整体样式 */
 ::v-deep .el-card {
   background-color: #0a1e44 !important;
   border: 1px solid #1a2e5a !important;
-  box-shadow: none !important; /* 去掉白色阴影 */
-  border-radius: 0 !important; /* 去掉圆角 */
-  padding: 0 !important; /* 去掉白边 */
+  box-shadow: none !important;
+  border-radius: 2px !important;
+  padding: 0 !important;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+::v-deep .el-card__header {
+  border-bottom: 1px solid #1a2e5a;
 }
 </style>

+ 137 - 110
src/views/bulletinBoard/rawMaterialWarehouse/index.vue

@@ -1,39 +1,43 @@
 <template>
   <div class="app-container">
-    <span style="color: white; font-weight: bold; margin-right: 10px"
-      >刷新时间(秒,输入0关闭刷新)</span
-    >
-    <el-input
-      v-model="num"
-      style="width: 240px"
-      placeholder="请添加刷新时间"
-      :min="1"
-      type="number"
-      @change="handleChange"
-    />
-    <el-row :gutter="10" type="flex">
-      <!-- 标题 -->
-      <el-col :span="24" class="charts-card chart-header">
-        <DashboardHeader height="4vh" content="原材仓看板" />
-      </el-col>
-    </el-row>
-    <!-- 固定两列,一行两个列表 -->
-    <el-row :gutter="16" class="row-equal-height list-row">
-      <el-col v-for="tab in tabs" :key="tab.name" :span="12">
-        <el-card :header="tab.label" shadow="hover" class="list-card">
-          <QueryNew
-            :document-id="tab.documentId"
-            class="query-container"
-            :refresh-min="num"
-          />
-        </el-card>
-      </el-col>
-    </el-row>
+    <!-- 控制栏 -->
+    <div class="control-bar">
+      <span class="control-label">刷新时间(秒,输入0关闭刷新)</span>
+      <el-input
+        v-model="num"
+        class="refresh-input"
+        placeholder="请添加刷新时间"
+        :min="1"
+        type="number"
+        @change="handleChange"
+      />
+    </div>
+
+    <!-- 标题 -->
+    <div class="header-section">
+      <DashboardHeader height="100%" content="原材仓看板" />
+    </div>
+
+    <!-- 列表区域 - 2列3行Grid布局 -->
+    <div class="content-section">
+      <div class="grid-container">
+        <div v-for="tab in tabs" :key="tab.name" class="grid-item">
+          <el-card :header="tab.label" shadow="hover" class="list-card">
+            <QueryNew
+              :document-id="tab.documentId"
+              class="query-container"
+              :refresh-min="num"
+            />
+          </el-card>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
 import QueryNew from "@/views/bulletinBoard/components/queryNew.vue";
+// import QueryNew from "@/views/bulletinBoard/components/queryNew1.vue";
 import DashboardHeader from "@/views/bulletinBoard/components/dashboardHeader.vue";
 import screenfull from "screenfull";
 export default {
@@ -77,23 +81,22 @@ export default {
     };
   },
   mounted() {
-    this.enterFullScreen(); // ② 挂载后调用
+    this.enterFullScreen();
   },
   methods: {
     handleChange(v) {
       const n = Number(v);
       if (isNaN(n) || n < 0) {
         this.$message.warning("请输入≥0的整数,输入0关闭刷新");
-        this.num = 10; // 恢复默认值
+        this.num = 10;
         return;
       }
       this.num = n;
     },
     enterFullScreen() {
-      // 延迟 1 秒避免浏览器拦截
       setTimeout(() => {
         if (screenfull.isEnabled) {
-          screenfull.toggle(); // 等同于 requestFullscreen
+          screenfull.toggle();
         }
       }, 1000);
     },
@@ -102,34 +105,7 @@ export default {
 </script>
 
 <style scoped>
-/* 统一整行高度 */
-.row-equal-height {
-  display: flex;
-  flex-wrap: wrap;
-}
-
-/* 卡片容器:统一高度 */
-.list-card {
-  height: 100%;
-  margin-bottom: 16px;
-  display: flex;
-  flex-direction: column;
-}
-
-/* 内容区撑满剩余高度 */
-.query-container {
-  flex: 1 1 auto;
-  overflow: auto; /* 如果内容超出出现滚动条 */
-}
-
-/* 让卡片标题变蓝 */
-::v-deep .el-card__header {
-  color: #8adfec;
-  font-weight: 600;
-  background-color: #192849;
-}
-
-/* 深蓝径向渐变背景 */
+/* 主容器 - 自适应全屏 */
 .app-container {
   background: -webkit-radial-gradient(
     50% 35%,
@@ -139,81 +115,132 @@ export default {
     #02366d,
     #002353
   );
-  min-height: 100vh;
-  width: 100%;
-  padding: 1vh;
+  height: 100vh;
+  width: 100vw;
+  padding: 6px 8px;
   margin: 0 !important;
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  overflow: hidden; /* 禁止滚动条 */
 }
-.list-row {
-  margin-top: 20px;
+
+/* 控制栏 */
+.control-bar {
+  flex-shrink: 0;
+  height: 28px;
+  display: flex;
+  align-items: center;
+  margin-bottom: 6px;
 }
-::v-deep .el-input__inner {
-  background: transparent !important; /* 关键:完全透明 */
-  border: 1px solid #034f8e; /* 保留你原来的边框 */
-  color: #fff; /* 字色白色 */
+
+.control-label {
+  color: white;
+  font-weight: bold;
+  margin-right: 8px;
+  font-size: 12px;
+  white-space: nowrap;
 }
-::v-deep .el-input__inner::placeholder {
-  color: #fff;
+
+.refresh-input {
+  width: 160px !important;
 }
-</style>
 
-<style scoped>
-/* 统一整行高度 */
-.row-equal-height {
-  display: flex;
-  flex-wrap: wrap;
+.refresh-input ::v-deep .el-input__inner {
+  height: 24px;
+  line-height: 24px;
+  padding: 0 8px;
+  font-size: 12px;
+}
+
+/* 标题区域 */
+.header-section {
+  flex-shrink: 0;
+  height: 32px;
+  margin-bottom: 6px;
+}
+
+/* 内容区域 */
+.content-section {
+  flex: 1;
+  min-height: 0;
+  overflow: hidden;
 }
 
-/* 卡片容器:统一高度 */
+/* Grid布局 - 2列3行 */
+.grid-container {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  grid-template-rows: repeat(2, minmax(0, 1fr));
+  gap: 6px;
+  height: 100%;
+  width: 100%;
+}
+
+.grid-item {
+  min-height: 0;
+  min-width: 0;
+  overflow: hidden;
+}
+
+/* 卡片样式 */
 .list-card {
   height: 100%;
-  margin-bottom: 16px;
   display: flex;
   flex-direction: column;
 }
 
-/* 内容区撑满剩余高度 */
-.query-container {
-  flex: 1 1 auto;
-  overflow: auto; /* 如果内容超出出现滚动条 */
-}
-
-/* 让卡片标题变蓝 */
-::v-deep .el-card__header {
+.list-card ::v-deep .el-card__header {
   color: #8adfec;
   font-weight: 600;
   background-color: #192849;
+  padding: 4px 8px;
+  height: 26px;
+  line-height: 18px;
+  font-size: 12px;
+  flex-shrink: 0;
 }
 
-/* 深蓝径向渐变背景 */
-.app-container {
-  background: -webkit-radial-gradient(
-    50% 35%,
-    farthest-corner,
-    #034f8e,
-    #034987,
-    #02366d,
-    #002353
-  );
-  min-height: 100vh;
-  width: 100%;
-  padding: 1vh;
-  margin: 0 !important;
+.list-card ::v-deep .el-card__body {
+  flex: 1;
+  padding: 4px;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
 }
+
+/* 内容区 */
+.query-container {
+  flex: 1;
+  min-height: 0;
+  overflow: auto; /* 允许卡片内部滚动 */
+}
+
+/* 输入框样式 */
 ::v-deep .el-input__inner {
-  background: transparent !important; /* 关键:完全透明 */
-  border: 1px solid #034f8e; /* 保留你原来的边框 */
-  color: #fff; /* 字色白色 */
+  background: transparent !important;
+  border: 1px solid #034f8e;
+  color: #fff;
 }
+
 ::v-deep .el-input__inner::placeholder {
-  color: #fff;
+  color: #ccc;
+  font-size: 12px;
 }
-/* 整卡统一深蓝 */
+
+/* 卡片整体样式 */
 ::v-deep .el-card {
   background-color: #0a1e44 !important;
   border: 1px solid #1a2e5a !important;
-  box-shadow: none !important; /* 去掉白色阴影 */
-  border-radius: 0 !important; /* 去掉圆角 */
-  padding: 0 !important; /* 去掉白边 */
+  box-shadow: none !important;
+  border-radius: 2px !important;
+  padding: 0 !important;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+::v-deep .el-card__header {
+  border-bottom: 1px solid #1a2e5a;
 }
 </style>