<template>
  <div class="app-container luckysheet-page">
    <div class="sheet-toolbar">
      <div class="left-actions">
        <el-button size="mini" icon="el-icon-back" @click="goBack">返回列表</el-button>
        <el-button size="mini" icon="el-icon-refresh" :loading="loading" @click="reloadRuntimeData">刷新数据</el-button>
        <el-button size="mini" type="primary" icon="el-icon-setting" @click="openSettingsDialog">模板设置</el-button>
      </div>
      <div class="toolbar-meta">
        <span class="meta-text">打印报表工作台 | 报表ID: {{ currentReportId }} | 字段 {{ allFields.length }} | 数据 {{ rows.length }} 行</span>
      </div>
    </div>

    <div class="sheet-stage">
      <div :id="luckysheetContainerId" class="luckysheet-editor"></div>
    </div>

    <el-dialog title="模板设置" :visible.sync="settingsDialogVisible" width="560px" append-to-body>
      <el-form label-width="90px" size="small">
        <el-form-item label="模板名称">
          <el-input v-model="printTemplate.templateName" />
        </el-form-item>
        <el-form-item label="打印范围">
          <el-radio-group v-model="printScope.mode">
            <el-radio label="currentPage">当前页</el-radio>
            <el-radio label="filteredAll">当前筛选全部</el-radio>
            <el-radio label="customLimit">自定义条数</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item v-if="printScope.mode === 'customLimit'" label="打印条数">
          <el-input-number v-model="printScope.customLimit" :min="1" :max="maxPrintRows" />
        </el-form-item>
        <el-form-item label="模板说明">
          <el-input
            v-model="sheetTemplate.printOptions.note"
            type="textarea"
            :rows="4"
            placeholder="可填写模板用途说明，保存后会一并持久化"
          />
        </el-form-item>
      </el-form>
      <div class="sheet-tip">
        <div>1. 页面主体全屏编辑，优先用于格式和排版。</div>
        <div>2. 默认第 1 行为表头，第 2 行开始映射数据。</div>
        <div>3. 保存为每报表共享模板，覆盖更新。</div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="settingsDialogVisible = false">关 闭</el-button>
        <el-button @click="resetTemplateDefaults">重建默认模板</el-button>
        <el-button type="primary" :loading="sheetLoading" @click="saveSheetTemplate">保存模板</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { getReportPrintTemplate, queryReportRuntime, saveReportPrintTemplate } from "@/api/erp/runtime";

export default {
  name: "ErpUserReportPrintPage",
  data() {
    return {
      loading: false,
      sheetLoading: false,
      settingsDialogVisible: false,
      queryForm: {
        pageNum: 1,
        pageSize: 20
      },
      queryContext: {
        filters: [],
        sorts: []
      },
      currentReportId: "",
      rows: [],
      allFields: [],
      printTemplate: {
        templateName: "默认打印模板"
      },
      sheetTemplate: {
        sheetJson: [],
        printOptions: {
          note: ""
        },
        bindMeta: {
          rowStart: 1,
          fields: [],
          templateDataRowCount: 0
        }
      },
      luckysheetContainerId: "erp-report-luckysheet-page",
      luckysheetReady: false,
      luckysheetAssetsReady: false,
      printLoading: false,
      printInProgress: false,
      alertPatched: false,
      originAlert: null,
      printScope: {
        mode: "currentPage",
        customLimit: 100
      },
      maxPrintRows: 2000
    };
  },
  async created() {
    this.syncFromRoute();
    if (!this.currentReportId) {
      this.$modal.msgWarning("缺少报表ID，无法打开打印设置页");
      return;
    }
    await this.reloadRuntimeData();
    this.loadTemplate();
  },
  beforeDestroy() {
    this.restoreAlertPatch();
    this.destroyLuckysheet();
  },
  methods: {
    openSettingsDialog() {
      this.settingsDialogVisible = true;
    },
    goBack() {
      this.$router.push({
        path: "/erp/report",
        query: {
          reportId: this.currentReportId
        }
      });
    },
    syncFromRoute() {
      const idFromQuery = this.$route.query.reportId;
      const idFromCompat = this.$route.query.reportI;
      this.currentReportId = String(idFromQuery || idFromCompat || "").trim();
      const pageNum = Number(this.$route.query.pageNum || 1);
      const pageSize = Number(this.$route.query.pageSize || 20);
      this.queryForm.pageNum = pageNum > 0 ? pageNum : 1;
      this.queryForm.pageSize = pageSize > 0 ? pageSize : 20;
    },
    buildRuntimeQueryPayload(override = {}) {
      return {
        pageNum: override.pageNum || this.queryForm.pageNum,
        pageSize: override.pageSize || this.queryForm.pageSize,
        filters: Array.isArray(override.filters) ? override.filters : this.queryContext.filters || [],
        sorts: Array.isArray(override.sorts) ? override.sorts : this.queryContext.sorts || []
      };
    },
    async reloadRuntimeData() {
      if (!this.currentReportId) {
        return;
      }
      this.loading = true;
      try {
        const res = await queryReportRuntime(this.currentReportId, this.buildRuntimeQueryPayload());
        const data = (res && res.data) || {};
        this.rows = data.rows || [];
        this.allFields = Object.keys(this.rows[0] || {});
      } finally {
        this.loading = false;
      }
    },
    loadStyleOnce(href) {
      return new Promise((resolve, reject) => {
        const exists = document.querySelector(`link[data-luckysheet="${href}"]`);
        if (exists) {
          resolve();
          return;
        }
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.href = href;
        link.setAttribute("data-luckysheet", href);
        link.onload = () => resolve();
        link.onerror = () => reject(new Error(`样式加载失败: ${href}`));
        document.head.appendChild(link);
      });
    },
    loadScriptOnce(src) {
      return new Promise((resolve, reject) => {
        const exists = document.querySelector(`script[data-luckysheet="${src}"]`);
        if (exists) {
          if (exists.getAttribute("data-loaded") === "1") {
            resolve();
            return;
          }
          exists.addEventListener("load", () => resolve(), { once: true });
          exists.addEventListener("error", () => reject(new Error(`脚本加载失败: ${src}`)), { once: true });
          return;
        }
        const script = document.createElement("script");
        script.src = src;
        script.async = false;
        script.setAttribute("data-luckysheet", src);
        script.onload = () => {
          script.setAttribute("data-loaded", "1");
          resolve();
        };
        script.onerror = () => reject(new Error(`脚本加载失败: ${src}`));
        document.body.appendChild(script);
      });
    },
    async ensureLuckysheetAssets() {
      if (this.luckysheetAssetsReady && window.luckysheet) {
        return;
      }
      const publicBase = (process.env.BASE_URL || "/").replace(/\/+$/, "");
      const localBase = `${publicBase}/luckysheet`;
      const cdnBase = "https://cdn.jsdelivr.net/npm/luckysheet/dist";
      const loadFromBase = async (base) => {
        await this.loadStyleOnce(`${base}/plugins/css/pluginsCss.css`);
        await this.loadStyleOnce(`${base}/plugins/plugins.css`);
        await this.loadStyleOnce(`${base}/css/luckysheet.css`);
        await this.loadStyleOnce(`${base}/assets/iconfont/iconfont.css`);
        await this.loadScriptOnce(`${base}/plugins/js/plugin.js`);
        await this.loadScriptOnce(`${base}/luckysheet.umd.js`);
      };
      try {
        await loadFromBase(localBase);
      } catch (e) {
        await loadFromBase(cdnBase);
      }
      this.luckysheetAssetsReady = !!window.luckysheet;
      if (!this.luckysheetAssetsReady) {
        throw new Error("Luckysheet 资源加载失败");
      }
    },
    getLuckysheetInstance() {
      return window.luckysheet || null;
    },
    destroyLuckysheet() {
      const instance = this.getLuckysheetInstance();
      if (instance && typeof instance.destroy === "function") {
        instance.destroy();
      }
      this.luckysheetReady = false;
    },
    installLuckysheetPrintFallback() {
      if (this.alertPatched) {
        return;
      }
      this.originAlert = window.alert;
      const that = this;
      window.alert = function(msg) {
        const text = String(msg === undefined || msg === null ? "" : msg);
        if (/暂不支持|not support|under development|开发中|敬请期待/i.test(text)) {
          that.runLuckysheetPrintFallback();
          return;
        }
        if (typeof that.originAlert === "function") {
          that.originAlert.call(window, msg);
        }
      };
      this.alertPatched = true;
    },
    restoreAlertPatch() {
      if (this.alertPatched && typeof this.originAlert === "function") {
        window.alert = this.originAlert;
      }
      this.alertPatched = false;
      this.originAlert = null;
    },
    createCellValue(raw, extra = {}) {
      const text = raw === null || raw === undefined ? "" : String(raw);
      return {
        v: raw === null || raw === undefined ? "" : raw,
        m: text,
        ct: { fa: "General", t: "g" },
        ...extra
      };
    },
    buildDefaultSheetFromRows(rows) {
      const safeRows = Array.isArray(rows) ? rows : [];
      const fields = this.allFields && this.allFields.length ? this.allFields : Object.keys(safeRows[0] || {});
      const celldata = [];
      fields.forEach((field, colIdx) => {
        celldata.push({
          r: 0,
          c: colIdx,
          v: this.createCellValue(field, { bl: 1, bg: "#f0f2f5", ht: 1 })
        });
      });
      safeRows.forEach((row, rowIdx) => {
        fields.forEach((field, colIdx) => {
          celldata.push({ r: rowIdx + 1, c: colIdx, v: this.createCellValue(row[field]) });
        });
      });
      return [{
        name: "报表模板",
        index: "0",
        status: 1,
        order: 0,
        row: Math.max(safeRows.length + 20, 40),
        column: Math.max(fields.length + 4, 12),
        celldata: celldata,
        config: {},
        luckysheet_select_save: [{ row: [0, 0], column: [0, 0] }],
        scrollLeft: 0,
        scrollTop: 0
      }];
    },
    initLuckysheet(sheetJson, options = {}) {
      const waitForReady = !!options.waitForReady;
      const readyTimeout = Number(options.readyTimeout || 5000);
      const instance = this.getLuckysheetInstance();
      if (!instance || typeof instance.create !== "function") {
        this.$modal.msgError("Luckysheet 初始化失败，请刷新页面后重试");
        this.luckysheetReady = false;
        return Promise.resolve(false);
      }
      this.destroyLuckysheet();
      return new Promise((resolve) => {
        let done = false;
        let timeoutId = null;
        const finish = (isReady) => {
          if (done) return;
          done = true;
          if (timeoutId) {
            clearTimeout(timeoutId);
          }
          this.installLuckysheetPrintFallback();
          this.luckysheetReady = true;
          resolve(!!isReady);
        };
        const createOptions = {
        container: this.luckysheetContainerId,
        lang: "zh",
        data: sheetJson,
        showinfobar: false,
        title: "Luckysheet",
        showtoolbar: true,
        showsheetbar: true,
        showstatisticBar: true,
        allowEdit: true,
        enableAddBackTop: false,
        forceCalculation: false
        };
        if (waitForReady) {
          createOptions.hook = {
            workbookCreateAfter: () => {
              finish(true);
            }
          };
          timeoutId = setTimeout(() => {
            this.$modal.msgWarning("打印渲染等待超时，已按当前状态继续");
            finish(false);
          }, readyTimeout > 0 ? readyTimeout : 5000);
        }
        instance.create(createOptions);
        if (!waitForReady) {
          finish(true);
        }
      });
    },
    getCurrentSheetJson() {
      const instance = this.getLuckysheetInstance();
      if (!instance) return [];
      const getter = instance.getLuckysheetfile || instance.getluckysheetfile;
      if (typeof getter !== "function") return [];
      const data = getter();
      return Array.isArray(data) ? JSON.parse(JSON.stringify(data)) : [];
    },
    normalizeLegacyTemplate(tableStyle) {
      const fields = Array.isArray(tableStyle.selectedFields) && tableStyle.selectedFields.length
        ? tableStyle.selectedFields
        : this.allFields;
      const rows = (this.rows || []).map((row) => {
        const item = {};
        (fields || []).forEach((field) => {
          item[field] = row[field];
        });
        return item;
      });
      const sheetJson = this.buildDefaultSheetFromRows(rows);
      const aliasMap = tableStyle.columnAlias || {};
      sheetJson[0].celldata.filter((item) => item.r === 0).forEach((cell, idx) => {
        const field = fields[idx];
        if (aliasMap[field]) {
          cell.v.v = aliasMap[field];
          cell.v.m = aliasMap[field];
        }
      });
      return {
        sheetJson: sheetJson,
        printOptions: { note: "" },
        bindMeta: {
          rowStart: 1,
          fields: fields || [],
          templateDataRowCount: rows.length
        }
      };
    },
    normalizeSheetTemplateFromBackend(tpl) {
      const tableStyle = this.safeJsonParse(tpl.tableStyleJson);
      if (tableStyle && tableStyle.mode === "luckysheet" && Array.isArray(tableStyle.sheetJson)) {
        const printScope = tableStyle.printOptions && tableStyle.printOptions.printScope;
        if (printScope && printScope.mode) {
          this.printScope.mode = printScope.mode;
          this.printScope.customLimit = Number(printScope.customLimit || this.printScope.customLimit || 100);
        }
        return {
          sheetJson: tableStyle.sheetJson,
          printOptions: tableStyle.printOptions || { note: "" },
          bindMeta: tableStyle.bindMeta || { rowStart: 1, fields: this.allFields || [], templateDataRowCount: this.rows.length || 0 }
        };
      }
      return this.normalizeLegacyTemplate(tableStyle || {});
    },
    async loadTemplate() {
      if (!this.currentReportId) return;
      const res = await getReportPrintTemplate(this.currentReportId);
      const tpl = (res && res.data) || null;
      if (!tpl) {
        this.sheetTemplate.sheetJson = this.buildDefaultSheetFromRows(this.rows || []);
      } else {
        this.printTemplate.templateName = tpl.templateName || "默认打印模板";
        this.sheetTemplate = this.normalizeSheetTemplateFromBackend(tpl);
      }
      await this.ensureLuckysheetAssets();
      this.$nextTick(async () => {
        const sheetJson = this.sheetTemplate.sheetJson && this.sheetTemplate.sheetJson.length
          ? this.sheetTemplate.sheetJson
          : this.buildDefaultSheetFromRows(this.rows || []);
        await this.initLuckysheet(sheetJson);
      });
    },
    buildBindMetaFromSheet(sheetJson, rowCount) {
      return {
        rowStart: 1,
        fields: this.allFields || [],
        templateDataRowCount: rowCount || 0
      };
    },
    normalizeTemplatePayload(sheetJson) {
      const safeName = (this.printTemplate.templateName || "").trim() || "默认打印模板";
      const tableStyle = {
        mode: "luckysheet",
        version: 2,
        sheetJson: sheetJson,
        printOptions: {
          ...(this.sheetTemplate.printOptions || { note: "" }),
          printScope: {
            mode: this.printScope.mode,
            customLimit: this.printScope.customLimit
          }
        },
        bindMeta: this.buildBindMetaFromSheet(sheetJson, (this.rows || []).length)
      };
      return {
        templateName: safeName,
        pageSize: "A4",
        pageOrientation: "PORTRAIT",
        titleText: "Luckysheet打印模板",
        titleStyleJson: JSON.stringify({}),
        headerLayoutJson: JSON.stringify({}),
        tableStyleJson: JSON.stringify(tableStyle),
        footerText: "",
        isDefault: 1
      };
    },
    async saveSheetTemplate() {
      if (!this.currentReportId) {
        this.$modal.msgWarning("当前报表ID不存在，无法保存模板");
        return;
      }
      const sheetJson = this.getCurrentSheetJson();
      if (!sheetJson.length) {
        this.$modal.msgWarning("请先完成 Luckysheet 模板初始化");
        return;
      }
      this.sheetLoading = true;
      try {
        await saveReportPrintTemplate(this.currentReportId, this.normalizeTemplatePayload(sheetJson));
        this.sheetTemplate.sheetJson = sheetJson;
        this.$modal.msgSuccess("模板保存成功");
      } finally {
        this.sheetLoading = false;
      }
    },
    resetTemplateDefaults() {
      const defaultSheet = this.buildDefaultSheetFromRows(this.rows || []);
      this.sheetTemplate = {
        sheetJson: defaultSheet,
        printOptions: {
          note: ""
        },
        bindMeta: {
          rowStart: 1,
          fields: this.allFields || [],
          templateDataRowCount: (this.rows || []).length
        }
      };
      this.$nextTick(() => {
        this.initLuckysheet(defaultSheet);
      });
      this.$modal.msgSuccess("已重建默认模板");
    },
    getCellMap(celldata) {
      const map = {};
      (celldata || []).forEach((cell) => {
        map[`${cell.r}_${cell.c}`] = cell;
      });
      return map;
    },
    buildMergeAnchorMap(sheet) {
      const anchorMap = {};
      const mergeConfig = (sheet && sheet.config && sheet.config.merge) || {};
      Object.values(mergeConfig).forEach((mergeItem) => {
        if (!mergeItem) return;
        const r = Number(mergeItem.r);
        const c = Number(mergeItem.c);
        const rs = Math.max(Number(mergeItem.rs || 1), 1);
        const cs = Math.max(Number(mergeItem.cs || 1), 1);
        if (!Number.isFinite(r) || !Number.isFinite(c)) return;
        for (let rr = r; rr < r + rs; rr += 1) {
          for (let cc = c; cc < c + cs; cc += 1) {
            anchorMap[`${rr}_${cc}`] = `${r}_${c}`;
          }
        }
      });
      return anchorMap;
    },
    resolveWritableCellKey(r, c, mergeAnchorMap) {
      const key = `${r}_${c}`;
      return (mergeAnchorMap && mergeAnchorMap[key]) || key;
    },
    buildPrintableSheet(sheetJson, rows) {
      const source = Array.isArray(sheetJson) && sheetJson.length ? sheetJson : this.buildDefaultSheetFromRows(rows);
      const first = JSON.parse(JSON.stringify(source[0]));
      const bindMeta = this.sheetTemplate.bindMeta || {};
      const rowStart = Number(bindMeta.rowStart || 1);
      const fields = Array.isArray(bindMeta.fields) && bindMeta.fields.length ? bindMeta.fields : this.allFields;
      const templateCount = Number(bindMeta.templateDataRowCount || 0);
      const cellMap = this.getCellMap(first.celldata || []);
      const mergeAnchorMap = this.buildMergeAnchorMap(first);
      const maxRow = rowStart + Math.max(templateCount, rows.length) - 1;
      const clearedKeys = new Set();
      for (let r = rowStart; r <= maxRow; r += 1) {
        fields.forEach((_, c) => {
          const writableKey = this.resolveWritableCellKey(r, c, mergeAnchorMap);
          if (clearedKeys.has(writableKey)) {
            return;
          }
          if (cellMap[writableKey]) {
            cellMap[writableKey].v = this.createCellValue("");
            clearedKeys.add(writableKey);
          }
        });
      }
      const writtenKeys = new Set();
      rows.forEach((row, rowIdx) => {
        fields.forEach((field, colIdx) => {
          const r = rowStart + rowIdx;
          const writableKey = this.resolveWritableCellKey(r, colIdx, mergeAnchorMap);
          if (writtenKeys.has(writableKey)) {
            return;
          }
          if (cellMap[writableKey]) {
            cellMap[writableKey].v = this.createCellValue(row[field]);
            writtenKeys.add(writableKey);
          } else {
            const anchorParts = writableKey.split("_");
            const targetR = Number(anchorParts[0]);
            const targetC = Number(anchorParts[1]);
            cellMap[writableKey] = {
              r: Number.isFinite(targetR) ? targetR : r,
              c: Number.isFinite(targetC) ? targetC : colIdx,
              v: this.createCellValue(row[field])
            };
            writtenKeys.add(writableKey);
          }
        });
      });
      first.celldata = Object.values(cellMap);
      first.row = Math.max(first.row || 0, rowStart + rows.length + 10);
      first.column = Math.max(first.column || 0, fields.length + 2);
      return [first];
    },
    buildPrintHtmlFromLuckysheet() {
      const container = document.getElementById(this.luckysheetContainerId);
      if (!container) {
        return "<html><body><p>Luckysheet 容器不存在，无法打印。</p></body></html>";
      }
      const headAssets = Array.from(document.querySelectorAll("link[rel='stylesheet'], style"))
        .map((el) => el.outerHTML)
        .join("\n");
      return `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>${(this.printTemplate.templateName || "报表打印")}</title>
  ${headAssets}
  <style>
    body { margin: 0; padding: 0; background: #fff; }
    .print-wrap { width: 100%; min-height: 100vh; background: #fff; }
  </style>
</head>
<body>
  <div class="print-wrap">${container.outerHTML}</div>
</body>
</html>
      `;
    },
    async getRowsForPrint() {
      const mode = this.printScope.mode;
      if (mode === "currentPage") {
        return this.rows || [];
      }
      const pageSize = mode === "customLimit"
        ? Math.min(Number(this.printScope.customLimit || 0), this.maxPrintRows)
        : this.maxPrintRows;
      if (!pageSize || pageSize < 1) {
        this.$modal.msgWarning("请输入有效的打印条数");
        return [];
      }
      this.printLoading = true;
      try {
        const payload = this.buildRuntimeQueryPayload({ pageNum: 1, pageSize: pageSize });
        const res = await queryReportRuntime(this.currentReportId, payload);
        const rows = (res && res.data && res.data.rows) || [];
        if (rows.length >= this.maxPrintRows && mode !== "currentPage") {
          this.$modal.msgWarning("打印数据已截断，请缩小筛选范围");
        }
        return rows;
      } finally {
        this.printLoading = false;
      }
    },
    async runLuckysheetPrintFallback() {
      if (this.printInProgress) {
        this.$modal.msgWarning("打印任务执行中，请稍候");
        return;
      }
      if (!this.currentReportId) {
        this.$modal.msgWarning("当前菜单未绑定报表ID，请联系管理员检查菜单配置");
        return;
      }
      if (!this.rows.length) {
        this.$modal.msgWarning("暂无可打印数据，请先查询");
        return;
      }
      const printRows = await this.getRowsForPrint();
      if (!printRows.length) {
        this.$modal.msgWarning("当前打印范围内无数据");
        return;
      }
      this.printInProgress = true;
      const currentSheet = this.getCurrentSheetJson();
      try {
        const printableSheet = this.buildPrintableSheet(currentSheet, printRows);
        const renderReady = await this.initLuckysheet(printableSheet, { waitForReady: true, readyTimeout: 5000 });
        if (!renderReady) {
          await new Promise((resolve) => setTimeout(resolve, 350));
        }
        const html = this.buildPrintHtmlFromLuckysheet();
        const printWindow = window.open("", "_blank");
        if (!printWindow) {
          this.$modal.msgError("浏览器拦截了新窗口，请允许弹窗后重试");
          return;
        }
        printWindow.document.open();
        printWindow.document.write(html);
        printWindow.document.close();
        printWindow.focus();
        await new Promise((resolve) => setTimeout(resolve, 300));
        printWindow.print();
      } catch (error) {
        this.$modal.msgError("打印失败，请稍后重试");
      } finally {
        if (currentSheet && currentSheet.length) {
          await this.initLuckysheet(currentSheet);
        }
        this.printInProgress = false;
      }
    },
    safeJsonParse(text) {
      if (!text) return {};
      try {
        return JSON.parse(text);
      } catch (e) {
        return {};
      }
    }
  }
};
</script>

<style scoped>
.luckysheet-page {
  padding: 0 !important;
  margin: 0;
  overflow: hidden;
  background: #fff;
  height: calc(100vh - 84px);
  display: flex;
  flex-direction: column;
}
.sheet-toolbar {
  flex: 0 0 52px;
  min-height: 52px;
  padding: 8px 12px;
  border-bottom: 1px solid #ebeef5;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.left-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.toolbar-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.meta-text {
  color: #909399;
  font-size: 12px;
  white-space: nowrap;
}
.sheet-hint {
  color: #606266;
  font-size: 12px;
  white-space: nowrap;
}
.sheet-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  background: #fff;
}
.luckysheet-editor {
  position: absolute;
  inset: 0;
}
.sheet-tip {
  color: #606266;
  line-height: 1.8;
  font-size: 12px;
}
@media (max-width: 1200px) {
  .sheet-toolbar {
    flex-wrap: wrap;
    min-height: auto;
  }
  .toolbar-meta {
    width: 100%;
    justify-content: space-between;
  }
}
</style>
