yxh
3 天以前 a79d67f8a9a9fa02f9d25f987b9611af965c484f
修改了风格
已修改92个文件
已添加5个文件
1823 ■■■■■ 文件已修改
public/index.html 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element-override.scss 365 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element-variables.scss 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/ruoyi.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/sidebar.scss 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/theme-runtime.scss 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/tokens.css 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/tokens.scss 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/variables.scss 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ThemePicker/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Settings/index.vue 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/settings.js 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/settings.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/theme.js 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/job/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/job/log.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/logininfor/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/online/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/operlog/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/DonationEvaluation/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/DonationProcess/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/distributedetail/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/documentfiles/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donateannex/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donateannexrequirement/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatebaseinfo/index.vue 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donateconsolationfund/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatefinish/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatefinishcheck/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatefollowup/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donateorgan/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donateorganstatics/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatereview/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donationdetails/index.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donationwitness/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donorcharge/donorcharge/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donorcharge/organcharge/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/ethicalReview/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/externalperson/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/financesubject/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/applyDetail/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/ethicalExpertFeeApply/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/expertFeeApply/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/medicalCostApply/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/officeExpenseApply/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fund/performanceApply/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundcheck/ethicalExpertFeeCheck/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundcheck/expertFeeCheck/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundcheck/medicalCostCheck/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundcheck/officeExpenseCheck/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundcheck/performanceCheck/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/funddetail/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundflow/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundflowrule/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/fundstatistics/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/itemexpense/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/medicalevaluation/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/organallocation/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/organallocation/index0.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/organization/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/reimbursement/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/reimbursementdetail/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/reimbursementpayee/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/relativesconfirmation/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/statistics/applyStatistics/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/statistics/caseStatistics/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/statistics/chargeStatistics/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/statistics/performanceStaristics/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/tallage/computingBill/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/tallage/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/travelexpenseapply/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/travelexpensecheck/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/travelexpensedeal/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/unitCost/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/unitCost/particulars/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/class/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/config/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/costmaintenance/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dict/data.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dict/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/grade/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/medicalevalustion/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/menu/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/notice/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/post/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/authUser.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/selectUser.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/student/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/importTable.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/index.html
@@ -174,7 +174,7 @@
    }
    #loader-wrapper .load_title {
      font-family: 'Open Sans';
      font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;
      color: #FFF;
      font-size: 19px;
      width: 100%;
src/assets/styles/element-override.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,365 @@
// ============================================================
// ç»„件默认外观(静态令牌层)
// ------------------------------------------------------------
// ç›®çš„:不改任何业务页面模板,用全局样式把 Element çš„默认观感
//       ç»Ÿä¸€æˆ"紧凑、清爽、专业"的一套。
// é‡ç‚¹ï¼šè¡¨æ ¼ï¼ˆæ–‘马纹/去竖线/表头底色)、表单、按钮、弹窗、标签。
// é¡ºåºï¼šå¿…须晚于 element-ui ä¸Ž ruoyi.scss(见 main.js)。
// ============================================================
// ---------- å…¨å±€æŽ’版 ----------
body {
  font-family: var(--opo-font-family-base);
  font-size: var(--opo-font-size-base);
  color: var(--opo-text-primary);
  background-color: var(--opo-bg-page);
}
// è¦†ç›– index.scss é‡Œçš„ label { font-weight: 700 }
label {
  font-weight: 400;
}
.app-container {
  // 2026-10-22:统一收紧为 8/12/12(原 12/16),全站列表页一致
  padding: 8px 12px 12px;
}
// æ•°å­—类字段(金额/编号/身份证)可用此类获得等宽数字
.opo-number {
  font-family: var(--opo-font-family-number);
  font-variant-numeric: tabular-nums;
}
// ---------- è¡¨æ ¼ ----------
// 2026-10-22:数据行字号与表头统一(14px / å¸¸è§„字重)
// æ³¨æ„ï¼šå…¨å±€ size=small ä¼šè®©æ¯ä¸ªè¡¨æ ¼å¸¦ä¸Š .el-table--small,
// Element ç”¨å®ƒæŠŠå­—号写回 12px、单元格 padding å†™å›ž 8px,
// æ‰€ä»¥è¿™é‡Œå¿…须同时提高选择器特异性,否则会被压回去。
.el-table,
.el-table.el-table--small,
.el-table.el-table--medium,
.el-table.el-table--mini,
.el-table.el-table--large {
  color: var(--opo-text-primary);
  font-size: var(--opo-font-size-sm);
}
.el-table {
  th,
  th.el-table__cell {
    background-color: var(--opo-bg-thead) !important;
    color: var(--opo-text-primary);
    // è¡¨å¤´ä¸åŠ ç²—ï¼ˆ2026-10-22 åé¦ˆï¼‰
    font-weight: 400;
    font-size: var(--opo-font-size-sm);
    height: 40px;
    padding: 0;
  }
  td,
  td.el-table__cell,
  &.el-table--small td.el-table__cell,
  &.el-table--medium td.el-table__cell,
  &.el-table--mini td.el-table__cell {
    padding: 9px 0;
    // è¡Œåˆ†éš”线(2026-10-22 å†åŠ æ·±ä¸€æ¡£ï¼‰
    border-bottom: 1px solid var(--opo-table-border, #c8cfd8);
  }
  // è¡¨æ ¼åº•部那条线
  &::before {
    background-color: var(--opo-table-border, #c8cfd8);
  }
  // å¸¦è¾¹æ¡†çš„表格,外框线
  &.el-table--border {
    border-color: var(--opo-table-border, #c8cfd8);
  }
  .cell {
    line-height: 23px;
  }
  // è¡¨å¤´ä¸Žå†…容区的分隔线(比行线再深一点,作为分界)
  .el-table__header-wrapper th {
    border-bottom: 1px solid var(--opo-table-border-strong, #b7c0cc);
  }
  // æ–‘马纹:用 CSS å®žçŽ°ï¼Œæ— éœ€ç»™ 162 ä¸ªè¡¨æ ¼é€ä¸ªåŠ  stripe å±žæ€§
  .el-table__body tr:nth-child(2n) > td,
  .el-table__body tr:nth-child(2n) > td.el-table__cell {
    background-color: var(--opo-bg-stripe);
  }
  // é¼ æ ‡è¡Œé«˜äº®ï¼ˆè¦†ç›–斑马纹;Element é»˜è®¤ hover è‰²åç°ï¼‰
  .el-table__body tr:hover > td,
  .el-table__body tr:hover > td.el-table__cell {
    background-color: var(--opo-primary-light-95, #f5f9fd);
  }
  // åŽ»æŽ‰ç«–çº¿ï¼šborder å±žæ€§ä»ä¿ç•™åœ¨æ¨¡æ¿é‡Œï¼Œè¿™é‡Œåªè®©å®ƒåœ¨è§†è§‰ä¸Šæ¶ˆå¤±
  &.el-table--border td,
  &.el-table--border th,
  &.el-table--border th.el-table__cell,
  &.el-table--border td.el-table__cell {
    border-right: none;
  }
  &.el-table--border::after,
  &.el-table--group::after {
    display: none;
  }
  .el-table__empty-text {
    color: var(--opo-text-placeholder);
    font-size: var(--opo-font-size-sm);
  }
}
// éœ€è¦"强网格线"的明细录入表:模板上加 class="table-bordered" å³å¯æ¢å¤
.el-table.table-bordered {
  border: 1px solid var(--opo-table-border, #c8cfd8);
  td,
  th,
  td.el-table__cell,
  th.el-table__cell {
    border-right: 1px solid var(--opo-table-border, #c8cfd8);
  }
}
// è¡¨æ ¼å†…按钮更紧凑,避免把行撑高
.el-table .el-button--mini,
.el-table .el-button--small {
  padding: 5px 8px;
}
// ---------- è¡¨å• ----------
// æŸ¥è¯¢æ¡ä»¶/表单整体收紧:Element é»˜è®¤ margin-bottom 22px,行距明显偏大
.el-form-item {
  margin-bottom: 12px;
  &__label {
    font-weight: 400;
    color: var(--opo-text-regular);
    // æ ‡ç­¾ä¿æŒ 14px:查询区大量使用 label-width="68px"/"70px",
    // æ ‡ç­¾è‹¥éšæ­£æ–‡å‡åˆ° 16px,4 ä¸ªå­—(如"捐献案例")就会换行、行高翻倍
    font-size: var(--opo-font-size-sm);
    padding-right: 8px;
    line-height: 32px;
  }
  &__content {
    line-height: 32px;
    min-height: 32px;
  }
  &.is-required:not(.is-no-asterisk) > .el-form-item__label:before {
    color: var(--opo-danger);
  }
  &__error {
    font-size: var(--opo-font-size-xs);
    line-height: 1.4;
    padding-top: 2px;
  }
}
// æ¨ªå‘排列的查询条件再紧凑一档
.el-form--inline .el-form-item {
  margin-right: 12px;
  margin-bottom: 8px;
}
// ---------- ç´§å‡‘查询区(opt-in) ----------
// ç”¨æ³•:给查询用的 el-form åŠ  class="opo-query-form"(列表页统一约定)
// è¡Œè· 8→4px、标签与控件对齐、最后一行(搜索/重置)去掉下边距
.opo-query-form {
  // æŸ¥è¯¢æ¡ä»¶ä¸Žä¸‹æ–¹"新增/导出"工具栏(对表格的操作)之间留出间距
  margin-bottom: 12px;
  .el-form-item {
    margin-right: 8px;
    margin-bottom: 4px;
  }
  .el-form-item__label {
    line-height: 32px;
    padding-right: 6px;
  }
  .el-form-item__content {
    line-height: 32px;
    min-height: 32px;
  }
  // æœ€åŽä¸€è¡Œé€šå¸¸æ˜¯"搜索/重置",不再额外留白
  > .el-row:last-child .el-form-item {
    margin-bottom: 0;
  }
}
// ç´§è·ŸæŸ¥è¯¢åŒºä¹‹åŽçš„工具栏行(新增/导出):贴近表格,与查询区由 margin-bottom éš”å¼€
.opo-query-form + .el-row.mb8 {
  margin-bottom: 4px;
}
// é¡µé¢é‡Œçš„æŸ¥è¯¢åŒºå¸¸åŒ…在卡片或 el-row ä¸­ï¼ŒåŽ»æŽ‰å¤šä½™çš„å¤–å±‚ç•™ç™½
.el-card__body > .el-form:first-child,
.el-card__body > .el-row:first-child .el-form {
  margin-bottom: 0;
}
.el-input__inner,
.el-textarea__inner {
  border-radius: var(--opo-radius-base);
  color: var(--opo-text-primary);
  &::placeholder {
    color: var(--opo-text-placeholder);
  }
}
// ---------- æŒ‰é’® ----------
.el-button {
  border-radius: var(--opo-radius-base);
  font-weight: 400;
  [class*='el-icon-'] + span {
    margin-left: 4px;
  }
}
// å°/迷你按钮的字号在 Element é‡Œæ˜¯ç¡¬ç¼–码 12px,随正文一起上调(2026-10-22 å†å¤§ä¸€å· â†’ 16px)
.el-button--small,
.el-button--mini {
  font-size: var(--opo-font-size-base);
}
// ---------- å¼¹çª— ----------
.el-dialog {
  border-radius: var(--opo-radius-lg);
  box-shadow: var(--opo-shadow-lg);
  overflow: hidden;
  &__header {
    padding: 16px 20px 12px;
    border-bottom: 1px solid var(--opo-border-light);
  }
  &__title {
    font-size: var(--opo-font-size-lg);
    font-weight: 600;
    color: var(--opo-text-primary);
  }
  &__body {
    padding: 16px 20px;
    color: var(--opo-text-regular);
  }
  &__footer {
    padding: 12px 20px 16px;
    border-top: 1px solid var(--opo-border-light);
  }
}
.el-drawer__header {
  padding: 16px 20px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--opo-border-light);
  color: var(--opo-text-primary);
  font-weight: 600;
}
// ---------- æ ‡ç­¾ ----------
.el-tag {
  border-radius: var(--opo-radius-sm);
  font-size: var(--opo-font-size-xs);
}
// ---------- å¡ç‰‡ ----------
.el-card {
  border-radius: var(--opo-radius-lg);
  border-color: var(--opo-border-light);
  box-shadow: var(--opo-shadow-sm) !important;
  &__header {
    padding: 14px 16px 10px;
    border-bottom: 1px solid var(--opo-border-light);
    font-weight: 600;
    color: var(--opo-text-primary);
  }
  &__body {
    padding: 12px 16px;
  }
}
// ---------- åˆ†é¡µ ----------
// Element æŠŠåˆ†é¡µæ–‡å­—写死 13px、字重 700,和 16px çš„表格正文不搭 â†’ ç»Ÿä¸€ 14px/常规
.el-pagination {
  font-weight: 400;
  color: var(--opo-text-regular);
  font-size: var(--opo-font-size-sm);
  button,
  span:not([class*='suffix']) {
    font-size: var(--opo-font-size-sm);
  }
  .el-pager li {
    font-size: var(--opo-font-size-sm);
  }
}
.pagination-container {
  margin-top: 12px;
  height: auto;
  padding: 8px 16px !important;
}
// ---------- é¢åŒ…屑 / é¡µç­¾ ----------
.el-breadcrumb {
  font-size: var(--opo-font-size-sm);
  &__inner,
  &__inner a {
    font-weight: 400 !important;
    color: var(--opo-text-secondary);
  }
  &__item:last-child .el-breadcrumb__inner {
    color: var(--opo-text-primary);
  }
}
// ---------- æç¤º / æ¶ˆæ¯ ----------
.el-message {
  border-radius: var(--opo-radius-base);
  box-shadow: var(--opo-shadow-md);
}
.el-tooltip__popper {
  font-size: var(--opo-font-size-xs);
}
// ---------- æ»šåŠ¨æ¡ï¼ˆè§‚æ„Ÿç»†èŠ‚ï¼‰ ----------
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, 0.18);
  border-radius: var(--opo-radius-pill);
  &:hover {
    background-color: rgba(0, 0, 0, 0.28);
  }
}
::-webkit-scrollbar-track {
  background-color: transparent;
}
src/assets/styles/element-variables.scss
@@ -1,23 +1,61 @@
/**
* I think element-ui's default theme color is too light for long-term use.
* So I modified the default color and you can modify it to your liking.
**/
 * Element UI ä¸»é¢˜å˜é‡ï¼ˆç¼–译期)
 * ------------------------------------------------------------
 * å“ç‰Œä¸»è‰²ï¼šå–自 src/assets/logo/OPO_Logo.png åœ†çŽ¯é’ #0E768F
 * å±é™©è‰²ï¼š  å–自同图心形玫红 #CD1D4E(白字对比度 5.41,优于原 #F56C6C çš„ 3.4)
 *
 * è¯´æ˜Žï¼šè¿™é‡Œå†³å®š"编译进 CSS çš„默认皮肤";
 *      è¿è¡Œæ—¶æ¢è‚¤ç”± assets/styles/theme-runtime.scss + utils/theme.js è´Ÿè´£ï¼Œ
 *      äºŒè€…通过 CSS å˜é‡ --opo-primary* è¡”接。
 */
/* theme color */
$--color-primary: #1890ff;
$--color-success: #13ce66;
$--color-warning: #ffba00;
$--color-danger: #ff4949;
// $--color-info: #1E1E1E;
/* ---------- ä¸»é¢˜è‰² ---------- */
$--color-primary: #0E768F;
$--color-success: #67C23A;
$--color-warning: #E6A23C;
$--color-danger: #CD1D4E;
$--color-info: #909399;
/* ---------- æ–‡å­— ---------- */
$--color-text-primary: #1F2937;
$--color-text-regular: #4B5563;
$--color-text-secondary: #6B7280;
$--color-text-placeholder: #9CA3AF;
/* ---------- è¾¹æ¡† ---------- */
$--border-color-base: #E5E7EB;
$--border-color-light: #F0F2F5;
$--border-color-lighter: #F5F7FA;
$--border-color-extra-light: #FAFBFC;
/* ---------- èƒŒæ™¯ ---------- */
$--background-color-base: #F5F7FA;
/* ---------- åœ†è§’ ---------- */
$--border-radius-base: 4px;
$--border-radius-small: 2px;
/* ---------- å­—号(2026-10-22 æ•´ä½“上调一号) ---------- */
$--font-size-extra-large: 22px;
$--font-size-large: 20px;
$--font-size-medium: 18px;
$--font-size-base: 16px;
$--font-size-small: 14px;
$--font-size-extra-small: 13px;
/* æŒ‰é’®å­—号默认在小尺寸里被硬编码成 12px,一并上调 */
$--button-font-size: 16px;
$--button-medium-font-size: 16px;
$--button-small-font-size: 14px;
$--button-mini-font-size: 14px;
/* ä¾§è¾¹æ èœå•字号(2026-10-22 ç”± 18px å›žè°ƒä¸€å·ï¼‰ */
$--menu-item-font-size: 16px;
$--button-font-weight: 400;
// $--color-text-regular: #1f2d3d;
$--border-color-light: #dfe4ed;
$--border-color-lighter: #e6ebf5;
$--table-border:1px solid#dfe6ec;
/* ---------- è¡¨æ ¼ ---------- */
$--table-border: 1px solid #E5E7EB;
/* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
src/assets/styles/index.scss
@@ -10,11 +10,12 @@
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
  font-family: $opo-font-family-base;
}
// è¡¨å•标签不再全局加粗(原来 700 è®©æ‰€æœ‰é¡µé¢æ˜¾å¾—很"重")
label {
  font-weight: 700;
  font-weight: 400;
}
html {
@@ -103,8 +104,8 @@
  border-radius: 2px;
  display: block;
  line-height: 32px;
  font-size: 16px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  font-size: $opo-font-size-lg;
  font-family: $opo-font-family-base;
  color: #2c3e50;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
src/assets/styles/ruoyi.scss
@@ -3,6 +3,9 @@
 * Copyright (c) 2019 ruoyi
 */
/* è®¾è®¡ä»¤ç‰Œï¼ˆæœ¬æ–‡ä»¶ä¸ºç‹¬ç«‹å…¥å£ï¼Œéœ€è‡ªè¡Œå¼•入变量) */
@import './tokens.scss';
 /** åŸºç¡€é€šç”¨ **/
.pt5 {
    padding-top: 5px;
@@ -75,10 +78,10 @@
    .el-table__header-wrapper, .el-table__fixed-header-wrapper {
        th {
            word-break: break-word;
            background-color: #f8f8f9;
            color: #515a6e;
            background-color: $opo-bg-thead;
            color: $opo-text-primary;
            height: 40px;
            font-size: 13px;
            font-size: $opo-font-size-sm;
        }
    }
    .el-table__body-wrapper {
@@ -137,7 +140,7 @@
/** è¡¨æ ¼æ›´å¤šæ“ä½œä¸‹æ‹‰æ ·å¼ */
.el-table .el-dropdown-link {
    cursor: pointer;
    color: #409EFF;
    color: var(--opo-primary, #0E768F);
    margin-left: 5px;
}
src/assets/styles/sidebar.scss
@@ -67,17 +67,23 @@
      width: 100% !important;
    }
    // èœå•字号:比正文大两号(正文 16px â†’ èœå• 18px)
    .el-menu-item,
    .el-submenu__title {
      font-size: $opo-font-size-menu;
    }
    .el-menu-item, .el-submenu__title {
      overflow: hidden !important;
      text-overflow: ellipsis !important;
      white-space: nowrap !important;
    }
    // menu hover
    // menu hover(深色底上用透白,原来 rgba(0,0,0,.06) åœ¨æ·±è‰²ä¸Šçœ‹ä¸å‡ºæ¥ï¼‰
    .submenu-title-noDropdown,
    .el-submenu__title {
      &:hover {
        background-color: rgba(0, 0, 0, 0.06) !important;
        background-color: rgba(255, 255, 255, 0.08) !important;
      }
    }
@@ -90,7 +96,7 @@
      min-width: $base-sidebar-width !important;
      &:hover {
        background-color: rgba(0, 0, 0, 0.06) !important;
        background-color: rgba(255, 255, 255, 0.08) !important;
      }
    }
@@ -101,6 +107,36 @@
      &:hover {
        background-color: $base-sub-menu-hover !important;
      }
    }
    // ---- å½“前选中菜单高亮 ----
    // åŽŸçŠ¶ï¼šElement ç¼–译出的 .el-menu-item.is-active æ˜¯ä¸»è‰²æ–‡å­—,
    // åœ¨åŒæ ·æ˜¯é’色的深色侧边栏上几乎看不见 â†’ æ”¹ä¸º"品牌青实底 + ç™½å­— + å·¦ä¾§äº®æ¡"
    & .el-menu-item.is-active {
      position: relative;
      color: #ffffff !important;
      background-color: $opo-primary !important;
      font-weight: 500;
      &::before {
        content: '';
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 3px;
        background-color: #ffffff;
      }
      &:hover {
        background-color: $opo-primary !important;
      }
    }
    // çˆ¶çº§åˆ†ç»„只是"包含选中项",用弱一点的底色,避免和叶子项一样重
    & .el-submenu.is-active > .el-submenu__title {
      background-color: rgba(255, 255, 255, 0.1) !important;
      color: #ffffff !important;
    }
  }
@@ -198,8 +234,8 @@
  .nest-menu .el-submenu>.el-submenu__title,
  .el-menu-item {
    &:hover {
      // you can use $subMenuHover
      background-color: rgba(0, 0, 0, 0.06) !important;
      // æ·±è‰²èœå•用透白覆盖
      background-color: rgba(255, 255, 255, 0.08) !important;
    }
  }
src/assets/styles/theme-runtime.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,270 @@
// ============================================================
// è¿è¡Œæ—¶ä¸»é¢˜å±‚(CSS å˜é‡æ¶ˆè´¹æ–¹ï¼‰
// ------------------------------------------------------------
// Element UI 2.x çš„主题色是 SCSS ç¼–译期常量,无法在运行时修改。
// æœ¬æ–‡ä»¶ä¸æ”¹ Element æºç ï¼Œåª"重写用到主色的选择器",值改为
// var(--opo-primary*);这些变量由 utils/theme.js åœ¨åˆ‡æ¢çš®è‚¤æ—¶å†™å…¥
// :root,因此换肤无需重新编译、无需刷新页面。
//
// è¦†ç›–顺序很关键:本文件必须在 element-ui ä¸Ž ruoyi.scss ä¹‹åŽå¼•å…¥
// ï¼ˆè§ main.js çš„ import é¡ºåºï¼‰ã€‚
// è¦†ç›–范围:按钮/链接/输入/单选复选开关/Tabs/分页/表格/步骤条/
//          æ—¥æœŸ/下拉/加载/进度,其余组件按需补充。
// ============================================================
$opo-fallback: #0E768F;
// ---------- æŒ‰é’® ----------
.el-button--primary {
  background-color: var(--opo-primary, #{$opo-fallback});
  border-color: var(--opo-primary, #{$opo-fallback});
  color: #fff;
  &:hover,
  &:focus {
    background-color: var(--opo-primary-hover, #{$opo-fallback});
    border-color: var(--opo-primary-hover, #{$opo-fallback});
    color: #fff;
  }
  &:active {
    background-color: var(--opo-primary-active, #{$opo-fallback});
    border-color: var(--opo-primary-active, #{$opo-fallback});
    color: #fff;
  }
  &.is-disabled,
  &.is-disabled:hover,
  &.is-disabled:focus,
  &.is-disabled:active {
    background-color: var(--opo-primary-light-5, #{$opo-fallback});
    border-color: var(--opo-primary-light-5, #{$opo-fallback});
    color: #fff;
  }
  &.is-plain {
    background-color: var(--opo-primary-light-9, #fff);
    border-color: var(--opo-primary-light-5, #{$opo-fallback});
    color: var(--opo-primary, #{$opo-fallback});
    &:hover,
    &:focus,
    &:active {
      background-color: var(--opo-primary, #{$opo-fallback});
      border-color: var(--opo-primary, #{$opo-fallback});
      color: #fff;
    }
  }
}
.el-button--text {
  color: var(--opo-primary, #{$opo-fallback});
  &:hover,
  &:focus {
    color: var(--opo-primary-hover, #{$opo-fallback});
  }
  &.is-disabled,
  &.is-disabled:hover {
    color: var(--opo-primary-light-5, #{$opo-fallback});
  }
}
// é»˜è®¤æŒ‰é’® hover æ—¶é€å‡ºå“ç‰Œè‰²ï¼ˆåŽŸæ¥æ˜¯ä¸€ç‰‡ç°ï¼‰
.el-button--default:hover,
.el-button--default:focus {
  color: var(--opo-primary, #{$opo-fallback});
  border-color: var(--opo-primary-light-5, #{$opo-fallback});
  background-color: var(--opo-primary-light-9, #fff);
}
// ---------- é“¾æŽ¥ ----------
.el-link.el-link--primary {
  color: var(--opo-primary, #{$opo-fallback});
  &:hover {
    color: var(--opo-primary-light-3, #{$opo-fallback});
  }
}
// ---------- è¾“入类 ----------
.el-input__inner:focus,
.el-textarea__inner:focus,
.el-input__inner:hover {
  border-color: var(--opo-primary-light-5, #{$opo-fallback});
}
.el-input__inner:focus,
.el-textarea__inner:focus {
  border-color: var(--opo-primary, #{$opo-fallback});
}
.el-select .el-input.is-focus .el-input__inner,
.el-select .el-input__inner:focus {
  border-color: var(--opo-primary, #{$opo-fallback});
}
.el-select-dropdown__item.selected {
  color: var(--opo-primary, #{$opo-fallback});
  font-weight: 600;
}
.el-input-number__decrease:hover,
.el-input-number__increase:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
// ---------- å•选 / å¤é€‰ ----------
.el-radio__input.is-checked .el-radio__inner,
.el-checkbox__input.is-checked .el-checkbox__inner,
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
  border-color: var(--opo-primary, #{$opo-fallback});
  background-color: var(--opo-primary, #{$opo-fallback});
}
.el-radio__input.is-checked + .el-radio__label,
.el-checkbox__input.is-checked + .el-checkbox__label {
  color: var(--opo-primary, #{$opo-fallback});
}
.el-radio-button__orig-radio:checked + .el-radio-button__inner,
.el-checkbox-button__orig-radio:checked + .el-checkbox-button__inner {
  background-color: var(--opo-primary, #{$opo-fallback});
  border-color: var(--opo-primary, #{$opo-fallback});
  box-shadow: -1px 0 0 0 var(--opo-primary, #{$opo-fallback});
  color: #fff;
}
// ---------- å¼€å…³ ----------
.el-switch.is-checked .el-switch__core {
  border-color: var(--opo-primary, #{$opo-fallback});
  background-color: var(--opo-primary, #{$opo-fallback});
}
// ---------- Tabs ----------
.el-tabs__item.is-active,
.el-tabs__item:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
.el-tabs__active-bar {
  background-color: var(--opo-primary, #{$opo-fallback});
}
.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active {
  color: var(--opo-primary, #{$opo-fallback});
  border-bottom-color: transparent;
}
// ---------- åˆ†é¡µ ----------
.el-pager li.active,
.el-pager li:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
.el-pagination.is-background .el-pager li:not(.disabled).active {
  background-color: var(--opo-primary, #{$opo-fallback});
  color: #fff;
}
.el-pagination button:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
// ---------- è¡¨æ ¼ ----------
.el-table .ascending .sort-caret.ascending {
  border-bottom-color: var(--opo-primary, #{$opo-fallback});
}
.el-table .descending .sort-caret.descending {
  border-top-color: var(--opo-primary, #{$opo-fallback});
}
.el-table__body tr.current-row > td {
  background-color: var(--opo-primary-light-9, #fff) !important;
}
.el-table--enable-row-hover .el-table__body tr:hover > td {
  background-color: var(--opo-primary-light-95, #f5f9fd) !important;
}
// ---------- æ­¥éª¤æ¡ ----------
.el-step__head.is-process {
  color: var(--opo-primary, #{$opo-fallback});
  border-color: var(--opo-primary, #{$opo-fallback});
}
.el-step__title.is-process {
  color: var(--opo-primary, #{$opo-fallback});
  font-weight: 600;
}
.el-step__head.is-finish {
  color: var(--opo-primary, #{$opo-fallback});
  border-color: var(--opo-primary, #{$opo-fallback});
}
.el-step__title.is-finish {
  color: var(--opo-primary, #{$opo-fallback});
}
// ---------- æ—¥æœŸ / æ—¶é—´ ----------
.el-date-table td.today span {
  color: var(--opo-primary, #{$opo-fallback});
  font-weight: 700;
}
.el-date-table td.current:not(.disabled) span {
  background-color: var(--opo-primary, #{$opo-fallback});
  color: #fff;
}
.el-date-table td.available:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
.el-date-picker__header-label.active,
.el-date-picker__header-label:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
// ---------- ä¸‹æ‹‰ / å¼¹å‡ºèœå•(只作用于弹出层,避免影响深色侧边栏) ----------
.el-dropdown-menu__item:not(.is-disabled):hover,
.el-dropdown-menu__item:focus {
  color: var(--opo-primary, #{$opo-fallback});
  background-color: var(--opo-primary-light-9, #fff);
}
.el-menu--popup .el-menu-item.is-active,
.el-menu--popup .el-menu-item:hover {
  color: var(--opo-primary, #{$opo-fallback});
}
// ---------- çº§è” ----------
.el-cascader .el-input.is-focus .el-input__inner {
  border-color: var(--opo-primary, #{$opo-fallback});
}
.el-cascader-node.in-active-path,
.el-cascader-node.is-active {
  color: var(--opo-primary, #{$opo-fallback});
}
// ---------- åŠ è½½ / è¿›åº¦ ----------
.el-loading-spinner .path {
  stroke: var(--opo-primary, #{$opo-fallback});
}
.el-progress-bar__inner {
  background-color: var(--opo-primary, #{$opo-fallback});
}
// ---------- æ»‘块 ----------
.el-slider__bar {
  background-color: var(--opo-primary, #{$opo-fallback});
}
.el-slider__button {
  border-color: var(--opo-primary, #{$opo-fallback});
}
src/assets/styles/tokens.css
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,91 @@
/* ============================================================
 * è®¾è®¡ä»¤ç‰Œ Â· CSS è‡ªå®šä¹‰å±žæ€§
 * è¿è¡Œæ—¶æ¢è‚¤åªéœ€æ”¹åЍ --opo-primary åŠå…¶æ´¾ç”Ÿè‰²é˜¶ï¼ˆç”± utils/theme.js æ³¨å…¥ï¼‰
 * è¿™é‡Œçš„值是"品牌青"默认值;JS æ³¨å…¥çš„ inline style ä¼šè¦†ç›– :root
 * ============================================================ */
:root {
  /* å“ç‰Œè‰²ï¼ˆé»˜è®¤ï¼šOPO_Logo åœ†çŽ¯é’ï¼‰ */
  --opo-primary: #0E768F;
  --opo-primary-hover: #0D6A81;
  --opo-primary-active: #0B5E72;
  --opo-primary-light-3: #569FB1;
  --opo-primary-light-5: #87BBC7;
  --opo-primary-light-7: #B7D6DD;
  --opo-primary-light-8: #CFE4E9;
  --opo-primary-light-9: #E7F1F4;
  --opo-primary-light-95: #F3F8F9;
  --opo-primary-dark-2: #0B5E72;
  /* è¯­ä¹‰è‰² */
  --opo-success: #67C23A;
  --opo-success-light: #F0F9EB;
  --opo-warning: #E6A23C;
  --opo-warning-light: #FDF6EC;
  --opo-danger: #CD1D4E;
  --opo-danger-light: #FBEBEF;
  --opo-info: #909399;
  --opo-info-light: #F4F4F5;
  /* ä¸­æ€§è‰² */
  --opo-text-primary: #1F2937;
  --opo-text-regular: #4B5563;
  --opo-text-secondary: #6B7280;
  --opo-text-placeholder: #9CA3AF;
  --opo-border-base: #E5E7EB;
  --opo-border-light: #F0F2F5;
  --opo-border-lighter: #F5F7FA;
  --opo-bg-page: #F5F7FA;
  --opo-bg-card: #FFFFFF;
  --opo-bg-hover: #F5F9FD;
  --opo-bg-stripe: #FAFBFC;
  --opo-bg-thead: #F5F7FA;
  /* è¡¨æ ¼æ¡†çº¿ï¼ˆæ¯”通用边框更深) */
  --opo-table-border: #C8CFD8;
  --opo-table-border-strong: #B7C0CC;
  /* ä¾§è¾¹æ  */
  --opo-sidebar-bg: #0A4655;
  --opo-sidebar-sub-bg: #083B47;
  --opo-sidebar-hover: rgba(14, 118, 143, 0.28);
  --opo-sidebar-text: rgba(255, 255, 255, 0.72);
  --opo-sidebar-text-active: #FFFFFF;
  /* å­—号(2026-10-22 æ•´ä½“上调一号:正文 14→16) */
  --opo-font-size-display: 34px;
  --opo-font-size-h1: 26px;
  --opo-font-size-h2: 20px;
  --opo-font-size-lg: 18px;
  --opo-font-size-base: 16px;
  --opo-font-size-sm: 14px;
  --opo-font-size-xs: 13px;
  --opo-font-size-menu: 16px;
  /* å­—体(不要用 -apple-system æ‰“头,Windows ä¸Šä¼šå˜æˆ Segoe UI,数字显小) */
  --opo-font-family-base: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑",
    "Helvetica Neue", Arial, sans-serif;
  --opo-font-family-number: "DIN Alternate", "SF Mono", "Roboto Mono", Consolas, "Courier New", monospace;
  /* é—´è· */
  --opo-space-1: 4px;
  --opo-space-2: 8px;
  --opo-space-3: 12px;
  --opo-space-4: 16px;
  --opo-space-5: 24px;
  --opo-space-6: 32px;
  /* åœ†è§’ */
  --opo-radius-sm: 2px;
  --opo-radius-base: 4px;
  --opo-radius-lg: 8px;
  --opo-radius-pill: 999px;
  /* é˜´å½± */
  --opo-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06);
  --opo-shadow-md: 0 4px 12px rgba(16, 24, 40, 0.08);
  --opo-shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.12);
  /* æŽ§ä»¶é«˜åº¦ */
  --opo-control-height-small: 32px;
  --opo-control-height-base: 36px;
}
src/assets/styles/tokens.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
// ============================================================
// è®¾è®¡ä»¤ç‰Œï¼ˆDesign Tokens)· SCSS å˜é‡
// å“ç‰Œè‰²å–自 src/assets/logo/OPO_Logo.png åœ†çŽ¯é’ #0E768F
// è¯´æ˜Žè§ï¼šæ–¹æ¡ˆ-前端界面视觉优化方案.md
// çº¦å®šï¼šä¸šåŠ¡æ ·å¼ä¸€å¾‹å¼•ç”¨è¿™é‡Œçš„å˜é‡ï¼Œç¦æ­¢å†å†™è£¸è‰²å€¼
// ============================================================
// ---------- å“ç‰Œè‰²ï¼ˆé’) ----------
$opo-primary:          #0E768F;
$opo-primary-hover:    #0D6A81;
$opo-primary-active:   #0B5E72;
$opo-primary-light-3:  #569FB1;
$opo-primary-light-5:  #87BBC7;
$opo-primary-light-7:  #B7D6DD;
$opo-primary-light-8:  #CFE4E9;
$opo-primary-light-9:  #E7F1F4;
$opo-primary-light-95: #F3F8F9;
$opo-primary-dark-2:   #0B5E72;
// ---------- è¯­ä¹‰è‰² ----------
$opo-success:       #67C23A;
$opo-success-light: #F0F9EB;
$opo-warning:       #E6A23C;
$opo-warning-light: #FDF6EC;
$opo-danger:        #CD1D4E;
$opo-danger-light:  #FBEBEF;
$opo-info:          #909399;
$opo-info-light:    #F4F4F5;
// ---------- ä¸­æ€§è‰² ----------
$opo-text-primary:     #1F2937;
$opo-text-regular:     #4B5563;
$opo-text-secondary:   #6B7280;
$opo-text-placeholder: #9CA3AF;
$opo-border-base:      #E5E7EB;
$opo-border-light:     #F0F2F5;
$opo-border-lighter:   #F5F7FA;
$opo-bg-page:          #F5F7FA;
$opo-bg-card:          #FFFFFF;
$opo-bg-hover:         #F5F9FD;
$opo-bg-stripe:        #FAFBFC;
$opo-bg-thead:         #F5F7FA;
// ---------- è¡¨æ ¼æ¡†çº¿ï¼ˆæ¯”通用边框更深,便于看清分列/分行) ----------
$opo-table-border:        #C8CFD8;
$opo-table-border-strong: #B7C0CC;
// ---------- ä¾§è¾¹æ ï¼ˆä¸Žå“ç‰Œé’同族) ----------
$opo-sidebar-bg:          #0A4655;
$opo-sidebar-sub-bg:      #083B47;
$opo-sidebar-hover:       rgba(14, 118, 143, 0.28);
$opo-sidebar-text:        rgba(255, 255, 255, 0.72);
$opo-sidebar-text-active: #FFFFFF;
// ---------- å­—号(2026-10-22 æ•´ä½“上调一号:正文 14→16) ----------
$opo-font-size-display: 34px;
$opo-font-size-h1:      26px;
$opo-font-size-h2:      20px;
$opo-font-size-lg:      18px;
$opo-font-size-base:    16px;
$opo-font-size-sm:      14px;
$opo-font-size-xs:      13px;
$opo-font-size-menu:    16px;  // ä¾§è¾¹æ èœå•(2026-10-22 ç”± 18px å›žè°ƒä¸€å·ï¼‰
// ---------- è¡Œé«˜ ----------
$opo-line-height-base:    22px;
$opo-line-height-heading: 1.3;
// ---------- å­—体 ----------
// æ³¨æ„ï¼šä¸è¦ç”¨ -apple-system / BlinkMacSystemFont æ‰“头——Windows ä¸Š Chrome ä¼šè§£æžæˆ Segoe UI,
// å¯¼è‡´æ•°å­—/英文走 Segoe UI(比中文细、显小),中文回退微软雅黑,同一行里字号观感不一致。
// è¿™é‡ŒæŒ‰"平台有则用、没有则退到微软雅黑"的顺序,保证中英文同族。
$opo-font-family-base:   "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑",
                         "Helvetica Neue", Arial, sans-serif;
$opo-font-family-number: "DIN Alternate", "SF Mono", "Roboto Mono", Consolas, "Courier New", monospace;
// ---------- é—´è·ï¼ˆ8 ç‚¹æ …格) ----------
$opo-space-1: 4px;
$opo-space-2: 8px;
$opo-space-3: 12px;
$opo-space-4: 16px;
$opo-space-5: 24px;
$opo-space-6: 32px;
// ---------- åœ†è§’ ----------
$opo-radius-sm:   2px;
$opo-radius-base: 4px;
$opo-radius-lg:   8px;
$opo-radius-pill: 999px;
// ---------- é˜´å½± ----------
$opo-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06);
$opo-shadow-md: 0 4px 12px rgba(16, 24, 40, 0.08);
$opo-shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.12);
// ---------- æŽ§ä»¶é«˜åº¦ ----------
$opo-control-height-small:  32px;
$opo-control-height-base:   36px;
src/assets/styles/variables.scss
@@ -1,3 +1,6 @@
// è®¾è®¡ä»¤ç‰Œï¼ˆé¢œè‰²/字号/间距/圆角/阴影/字体的唯一来源)
@import './tokens.scss';
// base color
$blue:#324157;
$light-blue:#3A71A8;
@@ -10,22 +13,21 @@
// é»˜è®¤èœå•主题风格
//菜单字体颜色
$base-menu-color:#fff;
$base-menu-color:$opo-sidebar-text;
//选定子列表时所在列表的字体颜色
// f4f4f5
$base-menu-color-active:#fff;
//整体背景颜色#0187B1
$base-menu-background:#394d74;
$base-menu-color-active:$opo-sidebar-text-active;
//整体背景颜色(与品牌青同族的深青)
$base-menu-background:$opo-sidebar-bg;
//标题字体颜色
$base-logo-title-color: #ffffff;
//
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
//列表背景颜色1f2d3d
$base-sub-menu-background:#394d74;
//
$base-sub-menu-hover:#a76ac3;
//列表背景颜色
$base-sub-menu-background:$opo-sidebar-sub-bg;
//子菜单悬停色(原来是无关联的紫色 #a76ac3)
$base-sub-menu-hover:$opo-sidebar-hover;
// è‡ªå®šä¹‰æš—色菜单风格
/**
@@ -42,7 +44,7 @@
$base-sub-menu-hover:#001528;
*/
$base-sidebar-width: 200px;
$base-sidebar-width: 220px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
src/components/ThemePicker/index.vue
@@ -1,7 +1,7 @@
<template>
  <el-color-picker
    v-model="theme"
    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
    :predefine="['#0E768F', '#CD1D4E', '#409EFF', '#1B8E70', '#7B61FF', '#E6843C', '#304156', '#212121']"
    class="theme-picker"
    popper-class="theme-picker-dropdown"
  />
@@ -42,8 +42,12 @@
  methods: {
    async setTheme(val) {
      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
      if (typeof val !== 'string') return
      // å…ˆé€šçŸ¥å¤–层:主题色由 CSS å˜é‡å±‚(utils/theme.js)立即生效。
      // åŽŸæ¥çš„å®žçŽ°è¦ç­‰ CDN æ‹‰å– theme-chalk å®ŒæˆåŽæ‰ emit,内网拉不到 unpkg
      // æ—¶ Promise æ°¸ä¸ resolve,导致"改主题没有任何反应"。
      this.$emit('change', val)
      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
      const themeCluster = this.getThemeCluster(val.replace('#', ''))
      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
@@ -81,8 +85,6 @@
        if (typeof innerText !== 'string') return
        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
      })
      this.$emit('change', val)
    },
    updateStyle(style, oldCluster, newCluster) {
@@ -96,12 +98,19 @@
    getCSSString(url, variable) {
      return new Promise(resolve => {
        const xhr = new XMLHttpRequest()
        const done = () => resolve()
        xhr.onreadystatechange = () => {
          if (xhr.readyState === 4 && xhr.status === 200) {
          if (xhr.readyState === 4) {
            if (xhr.status === 200) {
            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
            }
            resolve()
          }
        }
        // å†…网/无外网时快速失败,避免 Promise æ‚¬æŒ‚导致换肤卡住
        xhr.onerror = done
        xhr.ontimeout = done
        xhr.timeout = 4000
        xhr.open('GET', url)
        xhr.send()
      })
src/layout/components/Settings/index.vue
@@ -36,6 +36,21 @@
          <span>主题颜色</span>
          <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
        </div>
        <div class="drawer-item">
          <span>预设皮肤</span>
          <div class="opo-preset-list">
            <span
              v-for="p in presets"
              :key="p.color"
              class="opo-preset-item"
              :class="{ 'is-active': isCurrent(p.color) }"
              :style="{ backgroundColor: p.color }"
              :title="p.name"
              @click="themeChange(p.color)"
            />
          </div>
        </div>
      </div>
      <el-divider/>
@@ -77,13 +92,15 @@
<script>
import ThemePicker from '@/components/ThemePicker'
import { PRESETS, applyTheme, setStoredTheme } from '@/utils/theme'
export default {
  components: { ThemePicker },
  data() {
    return {
      theme: this.$store.state.settings.theme,
      sideTheme: this.$store.state.settings.sideTheme
      sideTheme: this.$store.state.settings.sideTheme,
      presets: PRESETS
    };
  },
  computed: {
@@ -147,12 +164,18 @@
    },
  },
  methods: {
    isCurrent(color) {
      return !!this.theme && String(this.theme).toUpperCase() === String(color).toUpperCase();
    },
    themeChange(val) {
      this.$store.dispatch('settings/changeSetting', {
        key: 'theme',
        value: val
      })
      this.theme = val;
      // ç«‹å³ç”Ÿæ•ˆå¹¶è®°ä½ï¼šä¸ä¾èµ– ThemePicker ä»Ž CDN æ‹‰å– theme-chalk
      applyTheme(val);
      setStoredTheme(val);
    },
    handleTheme(val) {
      this.$store.dispatch('settings/changeSetting', {
@@ -252,5 +275,29 @@
    .drawer-switch {
      float: right
    }
    // é¢„设皮肤色块
    .opo-preset-list {
      display: flex;
      align-items: center;
      flex-wrap: wrap;
      margin-top: 8px;
    }
    .opo-preset-item {
      display: inline-block;
      width: 22px;
      height: 22px;
      margin-right: 10px;
      border-radius: 4px;
      cursor: pointer;
      border: 2px solid transparent;
      box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
      &.is-active {
        border-color: #1F2937;
        box-shadow: 0 0 0 2px rgba(31, 41, 55, 0.18);
      }
    }
  }
</style>
src/layout/index.vue
@@ -1,5 +1,5 @@
<template>
  <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
  <div :class="classObj" class="app-wrapper">
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
    <sidebar class="sidebar-container"/>
    <div :class="{hasTagsView:needTagsView}" class="main-container">
@@ -21,6 +21,7 @@
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import variables from '@/assets/styles/variables.scss'
import { applyTheme, setStoredTheme } from '@/utils/theme'
export default {
  name: 'Layout',
@@ -54,7 +55,20 @@
      return variables;
    }
  },
  created() {
    // è¿›å…¥ Layout æ—¶åº”用当前主题色(并记住选择)
    this.applyCurrentTheme()
  },
  watch: {
    theme(val) {
      this.applyCurrentTheme()
      setStoredTheme(val)
    }
  },
  methods: {
    applyCurrentTheme() {
      applyTheme(this.theme)
    },
    handleClickOutside() {
      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
    }
src/main.js
@@ -10,10 +10,14 @@
import Cookies from 'js-cookie'
import Element from 'element-ui'
import '@/assets/styles/tokens.css' // è®¾è®¡ä»¤ç‰Œï¼ˆCSS å˜é‡ï¼Œä¾›è¿è¡Œæ—¶æ¢è‚¤ï¼‰
import './assets/styles/element-variables.scss'
import '@/assets/styles/index.scss' // global css
import '@/assets/styles/ruoyi.scss' // ruoyi css
// è¿è¡Œæ—¶ä¸»é¢˜å±‚ + ç»„件默认外观:必须晚于 element-ui ä¸Ž ruoyi.scss,否则覆盖不生效
import '@/assets/styles/theme-runtime.scss'
import '@/assets/styles/element-override.scss'
import App from './App'
import store from './store'
import router from './router'
@@ -27,6 +31,8 @@
import { getConfigKey } from "@/api/system/config";
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
import dataV from '@jiaminghi/data-view';//dataV
// ä¸»é¢˜è‰²è¿è¡Œæ—¶ï¼ˆCSS å˜é‡æ³¨å…¥ï¼‰
import { applyTheme, getStoredTheme, DEFAULT_PRIMARY } from '@/utils/theme'
// åˆ†é¡µç»„ä»¶
import Pagination from "@/components/Pagination";
// è‡ªå®šä¹‰è¡¨æ ¼å·¥å…·ç»„ä»¶
@@ -102,9 +108,12 @@
 */
Vue.use(Element, {
  size: Cookies.get('size') || 'medium' // set element-ui default size
  size: Cookies.get('size') || 'small' // set element-ui default size(原 medium,改为 small æå‡ä¿¡æ¯å¯†åº¦ï¼‰
})
// å¯åŠ¨å³åº”ç”¨å·²ä¿å­˜çš„ä¸»é¢˜è‰²ï¼ˆç™»å½•é¡µç­‰ä¸ä½¿ç”¨ Layout çš„页面也能生效)
applyTheme(getStoredTheme() || DEFAULT_PRIMARY)
Vue.config.productionTip = false
new Vue({
src/settings.js
@@ -5,9 +5,10 @@
  sideTheme: 'theme-dark',
  /**
   * æ˜¯å¦ç³»ç»Ÿå¸ƒå±€é…ç½®
   * æ˜¯å¦ç³»ç»Ÿå¸ƒå±€é…ç½®ï¼ˆå³ä¸‹è§’齿轮面板)
   * åŽŸä¸º false,导致"主题颜色 / é¢„设皮肤"入口对用户不可见 â†’ æ”¹ä¸º true
   */
  showSettings: false,
  showSettings: true,
  /**
   * æ˜¯å¦æ˜¾ç¤ºé¡¶éƒ¨å¯¼èˆª
@@ -40,87 +41,5 @@
   * The default is only used in the production env
   * If you want to also use it in dev, you can pass ['production', 'development']
   */
  errorLog: 'production',
  // vscode默认启用了根据文件类型自动设置tabsize的选项
  "editor.detectIndentation": false,
  // é‡æ–°è®¾å®štabsize
  "editor.tabSize": 2,
  // #每次保存的时候自动格式化
  "editor.formatOnSave": true,
  // #每次保存的时候将代码按eslint格式进行修复
  "eslint.autoFixOnSave": true,
  "tslint.autoFixOnSave": true,
  // æ·»åŠ  vue æ”¯æŒ
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "vue",
      "autoFix": true
  errorLog: 'production'
    }
  ],
  // #去掉代码结尾的分号
  "prettier.semi": true,
  // #使用带引号替代双引号
  "prettier.singleQuote": true,
  // #让函数(名)和后面的括号之间加个空格
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
  // #这个按用户自身习惯选择
  "vetur.format.defaultFormatter.html": "js-beautify-html",
  // #让vue中的js按编辑器自带的ts格式进行格式化
  "vetur.format.defaultFormatter.js": "vscode-typescript",
  "vetur.format.defaultFormatterOptions": {
    "js-beautify-html": {
      "wrap_attributes": "force-aligned"
      // #vue组件中html代码格式化样式
    }
  },
  // æ ¼å¼åŒ–stylus, éœ€å®‰è£…Manta's Stylus Supremacy插件
  "stylusSupremacy.insertColons": false, // æ˜¯å¦æ’入冒号
  "stylusSupremacy.insertSemicolons": false, // æ˜¯å¦æ’入分好
  "stylusSupremacy.insertBraces": false, // æ˜¯å¦æ’入大括号
  "stylusSupremacy.insertNewLineAroundImports": false, // import之后是否换行
  "stylusSupremacy.insertNewLineAroundBlocks": false,
  "javascript.format.insertSpaceAfterConstructor": true // ä¸¤ä¸ªé€‰æ‹©å™¨ä¸­æ˜¯å¦æ¢è¡Œ
}
src/store/modules/settings.js
@@ -1,11 +1,12 @@
import defaultSettings from '@/settings'
import { DEFAULT_PRIMARY, getStoredTheme } from '@/utils/theme'
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
const state = {
  title: '',
  theme: storageSetting.theme || '#409EFF',
  theme: storageSetting.theme || getStoredTheme() || DEFAULT_PRIMARY,
  sideTheme: storageSetting.sideTheme || sideTheme,
  showSettings: showSettings,
  topNav:  storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
src/utils/theme.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,172 @@
/**
 * ä¸»é¢˜è‰²è¿è¡Œæ—¶è®¡ç®—与应用
 * ---------------------------------------------------------------
 * èƒŒæ™¯ï¼šElement UI 2.x çš„主题色是 SCSS ç¼–译期常量,运行时无法改动;
 *      åŽŸæœ‰ ThemePicker ä¾èµ– unpkg CDN æ‹‰å– theme-chalk å†å­—符串替换,
 *      å†…网环境拉不到 CSS,导致"改主题没反应"。
 * åšæ³•:由任意主色推出一套色阶(hover / active / light-3~95),
 *      å†™å…¥ :root çš„ CSS å˜é‡ï¼›theme-runtime.scss ç”¨ var() æ¶ˆè´¹è¿™äº›å˜é‡ï¼Œ
 *      ä»Žè€Œå®žçް"一次编译、运行时换肤、页面不刷新"。
 */
/** é»˜è®¤ä¸»è‰²ï¼šOPO_Logo.png åœ†çŽ¯é’ */
export const DEFAULT_PRIMARY = '#0E768F'
/** localStorage é”®ï¼ˆä¸Žå¸ƒå±€è®¾ç½®åˆ†å¼€ï¼Œé¿å…äº’相覆盖) */
const STORAGE_KEY = 'opo-theme'
/** é¢„设皮肤 */
export const PRESETS = [
  { name: '品牌青', color: '#0E768F' },
  { name: '玫红', color: '#CD1D4E' },
  { name: 'Element è“', color: '#409EFF' },
  { name: '叶芽绿', color: '#1B8E70' },
  { name: 'ç´«', color: '#7B61FF' },
  { name: '橙', color: '#E6843C' }
]
const WHITE = [255, 255, 255]
const BLACK = [0, 0, 0]
function clamp(v) {
  return Math.max(0, Math.min(255, Math.round(v)))
}
/** #abc / #aabbcc â†’ [r,g,b];非法返回 null */
export function hexToRgb(hex) {
  if (typeof hex !== 'string') return null
  let h = hex.trim().replace(/^#/, '')
  if (h.length === 3) {
    h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2]
  }
  if (!/^[0-9a-fA-F]{6}$/.test(h)) return null
  return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)]
}
/** [r,g,b] â†’ #RRGGBB */
export function rgbToHex(rgb) {
  return (
    '#' +
    rgb
      .map(function (v) {
        const s = clamp(v).toString(16)
        return s.length === 1 ? '0' + s : s
      })
      .join('')
      .toUpperCase()
  )
}
/**
 * æ··è‰²ï¼šweight ä¸ºç›®æ ‡è‰²å æ¯”(0~1)
 * mix([14,118,143], WHITE, 0.3) â‰ˆ 30% ç™½ + 70% ä¸»è‰²
 */
export function mix(rgb, target, weight) {
  const w = Math.max(0, Math.min(1, weight))
  return [
    clamp(rgb[0] * (1 - w) + target[0] * w),
    clamp(rgb[1] * (1 - w) + target[1] * w),
    clamp(rgb[2] * (1 - w) + target[2] * w)
  ]
}
function channelLum(v) {
  const c = v / 255
  return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
}
/** ç›¸å¯¹äº®åº¦ï¼ˆWCAG) */
export function luminance(rgb) {
  return 0.2126 * channelLum(rgb[0]) + 0.7152 * channelLum(rgb[1]) + 0.0722 * channelLum(rgb[2])
}
/** ä¸Žç™½è‰²çš„对比度,用于判断白字是否可读 */
export function contrastWithWhite(rgb) {
  return 1.05 / (luminance(rgb) + 0.05)
}
/**
 * ç”±ä¸»è‰²æŽ¨å…¨å¥—色阶
 * æ·±è‰²ä¸»è‰²ï¼ˆäº®åº¦ä½Žï¼‰hover ç”¨"加深",浅色主色 hover ç”¨"变浅",
 * ä¿è¯ hover æ€çš„白字对比度不会掉下去。
 */
export function buildScale(primary) {
  const base = hexToRgb(primary) || hexToRgb(DEFAULT_PRIMARY)
  const isDark = luminance(base) < 0.4
  const hover = isDark ? mix(base, BLACK, 0.1) : mix(base, WHITE, 0.2)
  const active = isDark ? mix(base, BLACK, 0.2) : mix(base, WHITE, 0.32)
  return {
    primary: rgbToHex(base),
    hover: rgbToHex(hover),
    active: rgbToHex(active),
    light3: rgbToHex(mix(base, WHITE, 0.3)),
    light5: rgbToHex(mix(base, WHITE, 0.5)),
    light7: rgbToHex(mix(base, WHITE, 0.7)),
    light8: rgbToHex(mix(base, WHITE, 0.8)),
    light9: rgbToHex(mix(base, WHITE, 0.9)),
    light95: rgbToHex(mix(base, WHITE, 0.95)),
    dark2: rgbToHex(mix(base, BLACK, 0.2)),
    isDark: isDark,
    contrastWithWhite: Number(contrastWithWhite(base).toFixed(2))
  }
}
/** æŠŠè‰²é˜¶å†™å…¥ :root çš„ CSS å˜é‡ï¼ˆtheme-runtime.scss æ¶ˆè´¹ï¼‰ */
export function applyTheme(primary) {
  const scale = buildScale(primary || DEFAULT_PRIMARY)
  if (typeof document === 'undefined') return scale
  const root = document.documentElement
  const map = {
    '--opo-primary': scale.primary,
    '--opo-primary-hover': scale.hover,
    '--opo-primary-active': scale.active,
    '--opo-primary-light-3': scale.light3,
    '--opo-primary-light-5': scale.light5,
    '--opo-primary-light-7': scale.light7,
    '--opo-primary-light-8': scale.light8,
    '--opo-primary-light-9': scale.light9,
    '--opo-primary-light-95': scale.light95,
    '--opo-primary-dark-2': scale.dark2
  }
  Object.keys(map).forEach(function (k) {
    root.style.setProperty(k, map[k])
  })
  // ä¾›ä¸ªåˆ«éœ€è¦çŸ¥é“"当前是否深色主色"的场景使用
  root.setAttribute('data-opo-dark-primary', scale.isDark ? '1' : '0')
  return scale
}
/** è¯»å–上次选择的主色 */
export function getStoredTheme() {
  try {
    return localStorage.getItem(STORAGE_KEY)
  } catch (e) {
    return null
  }
}
/** è®°ä½é€‰æ‹© */
export function setStoredTheme(color) {
  try {
    localStorage.setItem(STORAGE_KEY, color)
  } catch (e) {
    /* å¿½ç•¥éšç§æ¨¡å¼ç­‰å¼‚常 */
  }
}
export default {
  DEFAULT_PRIMARY: DEFAULT_PRIMARY,
  PRESETS: PRESETS,
  applyTheme: applyTheme,
  buildScale: buildScale,
  getStoredTheme: getStoredTheme,
  setStoredTheme: setStoredTheme,
  hexToRgb: hexToRgb,
  rgbToHex: rgbToHex,
  mix: mix,
  luminance: luminance,
  contrastWithWhite: contrastWithWhite
}
src/views/monitor/job/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="任务名称" prop="jobName">
        <el-input
          v-model="queryParams.jobName"
src/views/monitor/job/log.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="任务名称" prop="jobName">
        <el-input
          v-model="queryParams.jobName"
src/views/monitor/logininfor/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="登录地址" prop="ipaddr">
        <el-input
          v-model="queryParams.ipaddr"
src/views/monitor/online/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
      <el-form-item label="登录地址" prop="ipaddr">
        <el-input
          v-model="queryParams.ipaddr"
src/views/monitor/operlog/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="系统模块" prop="title">
        <el-input
          v-model="queryParams.title"
src/views/project/DonationEvaluation/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/DonationProcess/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
@@ -690,16 +691,10 @@
        this.queryParams.reporterno = this.reportervalue;
      }
      if (this.starttime != "") {
        this.queryParams.starttime = this.starttime;
      } else {
        this.queryParams.starttime = "";
      }
      if (this.endtime != "") {
        this.queryParams.endtime = this.endtime;
      } else {
        this.queryParams.endtime = "";
      }
      // æœªé€‰æ—¶é—´èŒƒå›´æ—¶ä¼  null:空串会让后端拼出 `donatetime >= ''`,
      // MySQL ä¸¥æ ¼æ¨¡å¼ä¼šæŠ¥ Incorrect DATETIME value: ''(见 CHANGELOG 2026-10-22)
      this.queryParams.starttime = this.starttime || null;
      this.queryParams.endtime = this.endtime || null;
      console.log(this.queryParams);
      listDonationProcess(this.queryParams).then(response => {
src/views/project/distributedetail/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="收益人姓名 å®¶å±žæˆ–专家" prop="beneficiaryname">
        <el-input
          v-model="queryParams.beneficiaryname"
src/views/project/documentfiles/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donateannex/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donateannexrequirement/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-row>
        <el-col :span="6">
          <el-form-item label="附件编号" prop="annexno">
src/views/project/donatebaseinfo/index.vue
@@ -3,16 +3,17 @@
    <el-form
      :model="queryParams"
      ref="queryForm"
      class="opo-query-form"
      :inline="true"
      v-show="showSearch"
      label-width="70px"
    >
      <el-row :gutter="8">
        <el-col :span="5">
          <el-form-item label="姓名" prop="name">
          <el-form-item label="捐献者" prop="name">
            <el-input
              v-model="queryParams.name"
              placeholder="请输入姓名"
              placeholder="请输入捐献者姓名"
              clearable
              size="small"
              @keyup.enter.native="handleQuery"
@@ -46,24 +47,25 @@
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="9">
          <el-form-item label="案例时间">
            <el-date-picker
              style="width: 100%"
              v-model="selecttime"
              type="monthrange"
              range-separator="至"
              start-placeholder="开始月份"
              end-placeholder="结束月份"
              value-format="yyyy-MM-dd"
              @change="getTimeList"
       <el-col :span="6">
          <el-form-item label="报告人">
            <el-select
              v-model="queryParams.reporterno"
              placeholder="请选择报告人"
            >
            </el-date-picker>
              <el-option
                v-for="item in reportlist"
                :key="item.index"
                :label="item.reportername"
                :value="item.reporterno"
              >
              </el-option>
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="8">
        <el-col :span="5">
        <el-col :span="6">
          <el-form-item label="捐献进度" prop="workflow">
            <el-select
              v-model="queryParams.workflow"
@@ -80,23 +82,23 @@
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="5">
          <el-form-item label="报告人">
            <el-select
              v-model="queryParams.reporterno"
              placeholder="请选择报告人"
         <el-col :span="9">
          <el-form-item label="案例时间">
            <el-date-picker
              style="width: 100%"
              v-model="selecttime"
              type="monthrange"
              range-separator="至"
              start-placeholder="开始月份"
              end-placeholder="结束月份"
              value-format="yyyy-MM-dd"
              @change="getTimeList"
            >
              <el-option
                v-for="item in reportlist"
                :key="item.index"
                :label="item.reportername"
                :value="item.reporterno"
              >
              </el-option>
            </el-select>
            </el-date-picker>
          </el-form-item>
        </el-col>
        <el-col :span="5">
        <el-col :span="6">
          <el-form-item label="是否终止">
            <el-select
              v-model="queryParams.terminationCase"
@@ -112,19 +114,8 @@
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="9">
          <el-form-item label="籍贯">
            <div>
              <li_area_select
                ref="areaSelect"
                v-model="searchAddress"
              ></li_area_select>
            </div>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="4">
        <!-- æœç´¢/重置紧跟查询条件(与"案例评估"页一致) -->
        <el-col :span="6">
          <el-form-item>
            <el-button
              type="primary"
@@ -206,7 +197,7 @@
        label="捐献编号"
        align="center"
        prop="donorno"
        width="200"
        width="100"
      />
      <el-table-column label="姓名" align="center" prop="name" width="100" />
      <el-table-column label="性别" align="center" prop="sex" width="100">
@@ -233,9 +224,9 @@
      <el-table-column
        label="医疗机构"
        align="center"
        prop="treatmenthospitalname"
        prop="treatmenthospitalname" width="220"
      />
      <el-table-column label="血型" align="center" prop="bloodtype" width="100">
      <el-table-column label="血型" align="center" prop="bloodtype" width="80">
        <template slot-scope="scope">
          <dict-tag
            :options="dict.type.sys_BloodType"
@@ -263,7 +254,7 @@
        prop="reportername"
        width="100"
      />
      <!--
         <el-table-column
        label="现所在地市"
        align="center"
@@ -283,7 +274,7 @@
          />
        </template>
      </el-table-column>
      -->
      <el-table-column
        label="捐献进度"
        align="center"
@@ -304,7 +295,7 @@
        label="操作"
        align="center"
        class-name="small-padding fixed-width"
        fixed="right"
        fixed="right" width="200"
      >
        <template slot-scope="scope">
          <el-button
@@ -1663,19 +1654,16 @@
        this.queryParams.reportno = this.reportervalue;
      }
      if (this.starttime != "") {
        this.queryParams.starttime = this.starttime;
      } else {
        this.queryParams.starttime = "";
      }
      if (this.endtime != "") {
        this.queryParams.endtime = this.endtime;
      } else {
        this.queryParams.endtime = "";
      }
      this.queryParams.residenceprovince = this.$refs.areaSelect.getSheng();
      this.queryParams.residencecity = this.$refs.areaSelect.getShi();
      this.queryParams.residencetown = this.$refs.areaSelect.getQu();
      // æœªé€‰æ‹©æ—¶é—´èŒƒå›´æ—¶å¿…须传 null:传空串会让后端拼出 `donatetime >= ''`,
      // MySQL ä¸¥æ ¼æ¨¡å¼ä¼šæŠ¥ Incorrect DATETIME value: '',导致列表查不出来。
      // request.js åªä¼šæ‹¼æŽ¥éž null/undefined çš„参数,所以 null ç­‰äºŽ"不带该条件"。
      this.queryParams.starttime = this.starttime || null;
      this.queryParams.endtime = this.endtime || null;
      // æŸ¥è¯¢æ¡ä»¶é‡Œçš„"籍贯"已移除,不再从 areaSelect ç»„件取值;
      // ç½®ç©ºä»¥æ¸…掉可能残留的旧条件(参数为 null æ—¶ä¸ä¼šè¢«æ‹¼è¿›è¯·æ±‚)
      this.queryParams.residenceprovince = null;
      this.queryParams.residencecity = null;
      this.queryParams.residencetown = null;
      console.log(this.queryParams);
      listDonatebaseinfo(this.queryParams).then(response => {
@@ -2086,6 +2074,7 @@
</script>
<style scoped>
/* æŸ¥è¯¢åŒºè¡Œè·ã€é¡µé¢å†…边距、工具栏间距已提升为全局规则(.opo-query-form / .app-container),此处不再单独覆盖 */
::v-deep .el-dialog__header {
  padding-top: 40px !important;
  margin: auto !important;
src/views/project/donateconsolationfund/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donatefinish/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donatefinishcheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
@@ -897,16 +898,10 @@
      // this.queryParams.residenceprovince = this.$refs.areaSelect.getSheng();
      // this.queryParams.residencecity = this.$refs.areaSelect.getShi();
      // this.queryParams.residencetown = this.$refs.areaSelect.getQu();
       if (this.starttime != "") {
        this.queryParams.starttime = this.starttime;
      } else {
        this.queryParams.starttime = "";
      }
      if (this.endtime != "") {
        this.queryParams.endtime = this.endtime;
      } else {
        this.queryParams.endtime = "";
      }
      // æœªé€‰æ—¶é—´èŒƒå›´æ—¶ä¼  null:空串会让后端拼出 `donatetime >= ''`,
      // MySQL ä¸¥æ ¼æ¨¡å¼ä¼šæŠ¥ Incorrect DATETIME value: ''(见 CHANGELOG 2026-10-22)
      this.queryParams.starttime = this.starttime || null;
      this.queryParams.endtime = this.endtime || null;
      // this.queryParams.residenceprovince = this.$refs.areaSelect.getSheng();
      // this.queryParams.residencecity = this.$refs.areaSelect.getShi();
      // this.queryParams.residencetown = this.$refs.areaSelect.getQu();
src/views/project/donatefollowup/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donateorgan/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="70px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="70px">
      <el-row>
        <el-col :span="6">
          <el-form-item label="器官名称" prop="organno">
src/views/project/donateorganstatics/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donatereview/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
@@ -1115,16 +1116,10 @@
      // this.queryParams.residenceprovince = this.$refs.areaSelect.getSheng();
      // this.queryParams.residencecity = this.$refs.areaSelect.getShi();
      // this.queryParams.residencetown = this.$refs.areaSelect.getQu();
       if (this.starttime != "") {
        this.queryParams.starttime = this.starttime;
      } else {
        this.queryParams.starttime = "";
      }
      if (this.endtime != "") {
        this.queryParams.endtime = this.endtime;
      } else {
        this.queryParams.endtime = "";
      }
      // æœªé€‰æ—¶é—´èŒƒå›´æ—¶ä¼  null:空串会让后端拼出 `donatetime >= ''`,
      // MySQL ä¸¥æ ¼æ¨¡å¼ä¼šæŠ¥ Incorrect DATETIME value: ''(见 CHANGELOG 2026-10-22)
      this.queryParams.starttime = this.starttime || null;
      this.queryParams.endtime = this.endtime || null;
      listDonatebaseinfo(this.queryParams).then((response) => {
        console.log("getlist", response.rows);
        this.donatebaseinfoList = response.rows;
src/views/project/donationdetails/index.vue
@@ -3,7 +3,7 @@
    <div class="left-course" :class="{ 'left-collapsed': isLeftCollapsed }">
      <div class="postfilx">
        <div class="title">
          å·¥ä½œè¿›ç¨‹
          æ¡ˆä¾‹è¿›ç¨‹
          <el-button
            class="collapse-btn"
            @click="toggleLeftCollapse"
@@ -3485,7 +3485,12 @@
      this.isLeftCollapsed = !this.isLeftCollapsed;
    },
    /** ä¿å­˜ä¸»è¡¨æŒ‰é’® */
    submitForm() {
    submitForm(fromProcess) {
      // ä¿å­˜é˜²é‡ï¼šéž"流程推进"触发的保存,2 ç§’内的重复点击直接忽略(防止重复插入)
      if (!fromProcess && !this.canSave()) {
        this.$modal.msgWarning("请勿重复提交");
        return;
      }
      this.$refs["form"].validate(valid => {
        console.log("提交的数据们:", this.form);
        if (valid) {
@@ -3495,14 +3500,21 @@
            "YYYY-MM-DD HH:mm:ss"
          );
          this.form.diseasetype = this.form.diseasetype.join(",");
          this.form.infectious = this.form.infectious.join(",");
          this.form.selfwill = this.form.selfwill.join(",");
          this.form.othercases = this.form.othercases.join(",");
          this.form.infosources = this.form.infosources.join(",");
          this.form.kinship = this.form.kinship.join(",");
          this.form.patientstate = this.form.patientstate.join(",");
          // å¤šé€‰å­—段转字符串:幂等处理(已是字符串时保持原样),
          // é¿å…"保存成功后未重新加载再次保存"时抛 join is not a function
          [
            "diseasetype",
            "infectious",
            "selfwill",
            "othercases",
            "infosources",
            "kinship",
            "patientstate"
          ].forEach(key => {
            if (Array.isArray(this.form[key])) {
              this.form[key] = this.form[key].join(",");
            }
          });
          this.form.registerprovince = this.$refs.registerSelect.getSheng();
          this.form.registerprovincename = this.registerAddresss.sheng;
@@ -3584,6 +3596,11 @@
    },
    // ä¿å­˜äºŒçº§è¡¨æŒ‰é’®
    Savethedetails() {
      // ä¿å­˜é˜²é‡ï¼š2 ç§’内的重复点击直接忽略(防止重复插入)
      if (!this.canSave()) {
        this.$modal.msgWarning("请勿重复提交");
        return;
      }
      console.log(this.actives);
      if (this.actives == 1) {
        this.medicineform.infoid = this.infoid;
@@ -3594,14 +3611,19 @@
              updateMedicalevaluation(this.medicineform).then(response => {
                this.$modal.msgSuccess("医学评估信息修改成功");
                this.$modal.closeLoading();
                this.Processvalidation();
              });
            } else {
              addMedicalevaluation(this.medicineform).then(response => {
                // å›žå¡«ä¸»é”®ï¼šå¦åˆ™ä¸‹æ¬¡ä¿å­˜ä»èµ°"新增",会产生重复行
                if (response && response.data && response.data.id) {
                  this.medicineform.id = response.data.id;
                }
                this.$modal.msgSuccess("医学评估信息新增成功");
                this.$modal.closeLoading();
                this.Processvalidation();
              });
            }
            this.Processvalidation();
          }
        });
      } else if (this.actives == 2) {
@@ -3621,17 +3643,22 @@
              updateRelativesconfirmation(this.affirmform).then(response => {
                this.$modal.msgSuccess("捐献确认信息修改成功");
                this.$modal.closeLoading();
                this.Processvalidation();
              });
            } else {
              this.affirmform.residenceprovincename = this.defultAddresss.sheng;
              this.affirmform.residencecityname = this.defultAddresss.shi;
              this.affirmform.residencetownname = this.defultAddresss.qu;
              addRelativesconfirmation(this.affirmform).then(response => {
                // å›žå¡«ä¸»é”®ï¼šå¦åˆ™ä¸‹æ¬¡ä¿å­˜ä»èµ°"新增",会产生重复行
                if (response && response.data && response.data.id) {
                  this.affirmform.id = response.data.id;
                }
                this.$modal.msgSuccess("捐献确认信息新增成功");
                this.$modal.closeLoading();
                this.Processvalidation();
              });
            }
            this.Processvalidation();
          }
        });
      } else if (this.actives == 3) {
@@ -3644,15 +3671,20 @@
              updateEthicalreviewopinions(this.ethicform).then(res => {
                this.$modal.msgSuccess("伦理审查信息修改成功");
                this.$modal.closeLoading();
                this.Processvalidation();
              });
            } else {
              //addDonateflowchart(this.ethicform).then(response => {
              addEthicalreviewopinions(this.ethicform).then(res => {
                // å›žå¡«ä¸»é”®ï¼šå¦åˆ™ä¸‹æ¬¡ä¿å­˜ä»èµ°"新增",会产生重复行
                if (res && res.data && res.data.id) {
                  this.ethicform.id = res.data.id;
                }
                this.$modal.msgSuccess("伦理审查信息新增成功");
                this.$modal.closeLoading();
                this.Processvalidation();
              });
            }
            this.Processvalidation();
          }
        });
      } else if (this.actives == 4) {
@@ -3672,6 +3704,12 @@
            }
          });
          saveDonateorgan(this.allocateddata).then(res => {
            // å›žå¡«ä¸»é”®ï¼šåŽç«¯å·²æŒ‰"同一案例同一器官"做 upsert,回填后前端不会再误判为新增
            if (res && res.data && res.data.length === this.allocateddata.length) {
              res.data.forEach((row, i) => {
                this.allocateddata[i].id = row.id;
              });
            }
            if (res.code == 200) {
              this.$modal.msgSuccess("器官捐献分配信息保存成功!");
              this.$modal.closeLoading();
@@ -3720,7 +3758,12 @@
                });
                //保存器官获取表数据
                saveDonationwitnessorgan(this.procureddata).then(res => {
                  if (res == 200) {
                  if (res && res.data && res.data.length === this.procureddata.length) {
                    res.data.forEach((row, i) => {
                      this.procureddata[i].id = row.id;
                    });
                  }
                  if (res.code == 200) {
                    this.$modal.msgSuccess("捐献器官获取信息保存成功!");
                  }
                  this.$modal.closeLoading();
@@ -3729,6 +3772,10 @@
            } else {
              addDonationwitness(this.witnessform).then(response => {
                if (response.code === 200) {
                  // å›žå¡«ä¸»é”®ï¼šå¦åˆ™ä¸‹æ¬¡ä¿å­˜ä»èµ°"新增"
                  if (response.data && response.data.id) {
                    this.witnessform.id = response.data.id;
                  }
                  this.$modal.msgSuccess("获取见证信息新增成功");
                  this.form.donationcategory = this.witnessform.donationcategory;
                  let data = JSON.parse(JSON.stringify(this.form));
@@ -3747,7 +3794,12 @@
                  });
                  //保存器官获取表数据
                  saveDonationwitnessorgan(this.procureddata).then(res => {
                    if (res == 200) {
                    if (res && res.data && res.data.length === this.procureddata.length) {
                      res.data.forEach((row, i) => {
                        this.procureddata[i].id = row.id;
                      });
                    }
                    if (res.code == 200) {
                      this.$modal.msgSuccess("捐献器官获取信息保存成功!");
                    }
                    this.$modal.closeLoading();
@@ -3782,7 +3834,12 @@
              updateDonatecompletioninfo(this.accomplishform).then(response => {
                this.$modal.msgSuccess("完成登记信息修改成功");
                saveDonatecomporgan(this.transplantdata).then(res => {
                  if (res == 200) {
                  if (res && res.data && res.data.length === this.transplantdata.length) {
                    res.data.forEach((row, i) => {
                      this.transplantdata[i].id = row.id;
                    });
                  }
                  if (res.code == 200) {
                    this.$modal.msgSuccess("捐献器官登记信息保存成功!");
                  } else {
                    this.$modal.msgSuccess(res.msg);
@@ -3792,8 +3849,17 @@
              });
            } else {
              addDonatecompletioninfo(this.accomplishform).then(response => {
                // å›žå¡«ä¸»é”®ï¼šå¦åˆ™ä¸‹æ¬¡ä¿å­˜ä»èµ°"新增"
                if (response && response.data && response.data.id) {
                  this.accomplishform.id = response.data.id;
                }
                this.$modal.msgSuccess("完成登记成功");
                saveDonatecomporgan(this.transplantdata).then(res => {
                  if (res && res.data && res.data.length === this.transplantdata.length) {
                    res.data.forEach((row, i) => {
                      this.transplantdata[i].id = row.id;
                    });
                  }
                  if (res.code == 200) {
                    this.$modal.msgSuccess("捐献器官登记信息保存成功!");
                  } else {
@@ -4130,6 +4196,15 @@
        console.log("已到达最大值");
      }
    },
    // ä¿å­˜é˜²é‡ï¼š2 ç§’内重复点击视为重复提交
    canSave() {
      const now = Date.now();
      if (this.saveLockAt && now - this.saveLockAt < 2000) {
        return false;
      }
      this.saveLockAt = now;
      return true;
    },
    // æ›´æ”¹è¿›ç¨‹æ•ˆéªŒ
    Processvalidation() {
      if (this.form.workflow + 1 == this.actives) {
@@ -4137,15 +4212,12 @@
          this.form.workflow++;
        } else {
        }
        this.submitForm();
        // this.GetAttacheddata();
        // ç”±"保存二级表"触发的保存,不参与防重(否则会被 canSave æ‹¦æŽ‰ï¼‰
        this.submitForm(true);
      } else if (this.form.workflow > this.actives) {
        this.submitForm();
        // Modifydonationattachment(this.donatelist).then(res => {});
        // this.GetAttacheddata();
        this.submitForm(true);
      } else {
        this.submitForm();
        // this.$modal.msgWarning("请先完成前部步骤");
        this.submitForm(true);
        return;
      }
    },
@@ -4462,7 +4534,7 @@
<style lang="scss" scoped>
.particularsdiv {
  display: flex;
  background-color: #f5f7fa;
  background-color: var(--opo-bg-page, #f5f7fa);
  height: 100vh;
  overflow: hidden;
  transition: all 0.3s ease;
@@ -4476,7 +4548,7 @@
    margin: 0;
    padding: 0;
    height: 100%;
    box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
    box-shadow: 2px 0 8px rgba(16, 24, 40, 0.08);
    transition: all 0.3s ease;
    position: relative;
    z-index: 100;
@@ -4511,7 +4583,7 @@
      flex-direction: column;
      .title {
        background: #22a2c3;
        background: var(--opo-primary, #0e768f);
        margin-bottom: 0;
        padding: 15px 10px;
        color: #fff;
@@ -4608,7 +4680,7 @@
  }
}
// æ­¥éª¤æ ·å¼ä¼˜åŒ–
// æ­¥éª¤æ ·å¼ä¼˜åŒ–(配色统一到系统品牌色:teal #0E768F)
::v-deep .el-steps {
  &.el-steps--vertical {
    height: 100%;
@@ -4618,27 +4690,28 @@
      .el-step__head {
        &.is-finish {
          color: #22a2c3;
          border-color: #22a2c3;
          color: var(--opo-primary, #0e768f);
          border-color: var(--opo-primary, #0e768f);
        }
      }
      .el-step__title {
        font-size: 14px;
        font-size: var(--opo-font-size-sm);
        font-weight: 600;
        &.is-finish {
          color: #22a2c3;
          color: var(--opo-primary, #0e768f);
        }
      }
      .el-step__description {
        font-size: 12px;
        color: #666;
        font-size: var(--opo-font-size-xs);
        // æè¿°æ–‡å­—统一用中性灰,避免整块面板被品牌色淹没
        color: var(--opo-text-secondary, #6b7280);
        line-height: 1.5;
        &.is-finish {
          color: #22a2c3;
          color: var(--opo-text-regular, #4b5563);
        }
        p {
src/views/project/donationwitness/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/donorcharge/donorcharge/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
      <el-form-item label="捐献姓名" prop="name">
        <el-input v-model="queryParams.name" placeholder="请输入姓名" clearable size="small"
          @keyup.enter.native="handleQuery" />
src/views/project/donorcharge/organcharge/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="器官编码" prop="organcode">
        <el-input
          v-model="queryParams.organcode"
src/views/project/ethicalReview/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/externalperson/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
      <el-form-item label="账号类别" prop="usertype">
        <el-select v-model="queryParams.usertype" placeholder="请选择账号类别" clearable size="small">
src/views/project/financesubject/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="项目类型" prop="itemtype">
        <el-select v-model="queryParams.itemtype" placeholder="请选择项目类型" clearable size="small">
          <el-option v-for="dict in dict.type.sys_ConsolationType" :key="dict.value" :label="dict.label"
src/views/project/fund/applyDetail/index.vue
@@ -832,9 +832,10 @@
        return callback();
      }
      const regex = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}([0-9]|X)$/;
      if (regex.test(value)) {
      } else {
        callback(new Error("身份证号码格式错误"));
      // 2026-10-19:格式不合法立即早退。原来写成 if/else ä½† else é‡Œæ²¡æœ‰ return,
      // ä¼šç»§ç»­å¾€ä¸‹èµ°å¼‚步查重,导致 callback è¢«è°ƒç”¨ä¸¤æ¬¡ã€"身份证号码格式错误"被后续结果覆盖。
      if (!regex.test(value)) {
        return callback(new Error("身份证号码格式错误"));
      }
      // 2. è°ƒç”¨åŽç«¯æŽ¥å£è¿›è¡Œé‡å¤æ€§æ ¡éªŒ
@@ -967,6 +968,10 @@
      },
      dialogrules: {
        // 2026-10-19:账户名称(账户来源=从账户库 æ—¶çš„下拉)也是必输项
        accountname: [
          { required: true, message: "请选择账户名称", trigger: "change" }
        ],
        usertype: [
          { required: true, message: "请输入账户类型", trigger: "blur" }
        ],
@@ -976,6 +981,10 @@
        unitTaxNo: [{ required: true, message: "请输入税号", trigger: "blur" }],
        idcardno: [
          {
            // 2026-10-19:加 required æ ‡è®°åªä¸ºè®© el-form-item æ ‡å‡ºå¿…输星号(Element çš„ isRequired åªè®¤ rule.required)。
            // æœ¬è§„则带 validator,async-validator çš„ getValidationMethod ä¼šç›´æŽ¥è¿”回该 validator、跳过内建 required æ£€æŸ¥ï¼Œ
            // æ‰€ä»¥æ ¡éªŒè¡Œä¸ºä¸Žæ”¹åŠ¨å‰å®Œå…¨ä¸€è‡´ï¼›å¦å¤–**不能加 message**,否则会覆盖下面自定义 validator çš„æŠ¥é”™æ–‡æ¡ˆã€‚
            required: true,
            // è´¦æˆ·ç±»åž‹é€‰æ‹©"单位机构"时不需要身份证号
            validator: (rule, value, callback) => {
              if (this.hasUserType(this.accountselectform.usertype, "org")) {
@@ -3348,6 +3357,10 @@
    //专家/医疗机构/费用报销机构选择
    confirmSelectionDialog() {
      this.$refs["accountselectform"].validate(valid => {
        // 2026-10-19:原来没有判断 valid,校验失败也照样往下走、照样保存(星号/红字形同虚设)
        if (!valid) {
          return;
        }
        let tempIndex = this.accountselectform.index;
        if (this.selectionType == "account") {
          if (this.accountfrom == "1") {
src/views/project/fund/ethicalExpertFeeApply/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/fund/expertFeeApply/index.vue
@@ -13,6 +13,7 @@
          </el-row>
          <div>
            <el-form
              class="opo-query-form"
              :model="queryParams"
              ref="queryForm"
              :inline="true"
src/views/project/fund/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="捐献者编号" prop="donorno">
        <el-input v-model="queryParams.donorno" placeholder="请输入捐献者编号" clearable size="small"
          @keyup.enter.native="handleQuery" />
src/views/project/fund/medicalCostApply/index.vue
@@ -13,6 +13,7 @@
          </el-row>
          <div>
            <el-form
              class="opo-query-form"
              :model="queryParams"
              ref="queryForm"
              :inline="true"
src/views/project/fund/officeExpenseApply/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/fund/performanceApply/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/fundcheck/ethicalExpertFeeCheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
      <el-row>
        <el-col :span="5">
          <el-form-item label="捐献案例" prop="donorname" style="float: left">
src/views/project/fundcheck/expertFeeCheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
      <el-row>
        <el-col :span="5">
          <el-form-item label="捐献案例" prop="donorname" style="float: left">
src/views/project/fundcheck/medicalCostCheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
      <el-row align="left">
        <el-col :span="5">
          <el-form-item label="捐献案例" prop="donorname" style="float: left">
src/views/project/fundcheck/officeExpenseCheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
      <el-row align="left">
        <el-col :span="5">
          <el-form-item label="捐献案例" prop="donorname" style="float: left">
src/views/project/fundcheck/performanceCheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
      <el-row align="left">
        <el-col :span="5">
          <el-form-item label="预审状态" prop="checkstatus" style="float: left">
src/views/project/funddetail/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="专家姓名" prop="beneficiaryname">
        <el-input v-model="queryParams.beneficiaryname" placeholder="请输入专家姓名" clearable size="small"
          @keyup.enter.native="handleQuery" />
src/views/project/fundflow/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <!-- <el-form-item label="费用编号,差旅费关联表service_reimbursement ID; è´¹ç”¨å…³è”费用表service_fund的ID" prop="fundid">
        <el-input
          v-model="queryParams.fundid"
src/views/project/fundflowrule/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/fundstatistics/index.vue
@@ -3,7 +3,8 @@
  <div class="app-container">
    <el-col :span="24" v-if="showType == 'list'">
      <el-card shadow="never">
        <el-form :model="queryParams" ref="queryForm" :inline="true">
        <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true">
          <el-form-item label="姓名" prop="name">
            <el-input
              v-model="queryParams.name"
src/views/project/itemexpense/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="服务项目ID" prop="itemid">
        <el-input
          v-model="queryParams.itemid"
src/views/project/medicalevaluation/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/organallocation/index.vue
@@ -3,6 +3,7 @@
  <div class="app-container">
    <!-- æœç´¢æ¡ä»¶ -->
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/organallocation/index0.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="70px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="70px">
      <el-row>
        <el-col :span="6">
          <el-form-item label="捐献者" prop="name">
src/views/project/organization/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/reimbursement/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="创建者" prop="createBy">
        <el-input
          v-model="queryParams.createBy"
src/views/project/reimbursementdetail/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="创建人" prop="createBy">
        <el-input
          v-model="queryParams.createBy"
src/views/project/reimbursementpayee/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="资金申请主表ID" prop="rbid">
        <el-input
          v-model="queryParams.rbid"
src/views/project/relativesconfirmation/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/statistics/applyStatistics/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/statistics/caseStatistics/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/statistics/chargeStatistics/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/statistics/performanceStaristics/index.vue
@@ -2,6 +2,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/tallage/computingBill/index.vue
@@ -298,6 +298,7 @@
            <el-row :gutter="20">
              <!--用户数据-->
              <el-form
                class="opo-query-form"
                :model="patientqueryParams"
                ref="queryForm"
                size="small"
src/views/project/tallage/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/travelexpenseapply/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-row>
        <!--
        <el-col :span="6">
src/views/project/travelexpensecheck/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
      <el-row>
        <el-col :span="5">
          <el-form-item label="捐献案例" prop="name">
src/views/project/travelexpensedeal/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/project/unitCost/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
      <el-form-item label="医疗机构" prop="name">
        <el-input v-model="queryParams.name" placeholder="请输入医疗机构" clearable size="small"
          @keyup.enter.native="handleQuery" />
src/views/project/unitCost/particulars/index.vue
@@ -329,6 +329,7 @@
            <el-row :gutter="20">
              <!--用户数据-->
              <el-form
                class="opo-query-form"
                :model="patientqueryParams"
                ref="queryForm"
                size="small"
src/views/system/class/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="班级名称" prop="className">
        <el-input
          v-model="queryParams.className"
src/views/system/config/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="参数名称" prop="configName">
        <el-input
          v-model="queryParams.configName"
src/views/system/costmaintenance/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form
      class="opo-query-form"
      :model="queryParams"
      ref="queryForm"
      :inline="true"
src/views/system/dept/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
      <el-form-item label="部门名称" prop="deptName">
        <el-input
          v-model="queryParams.deptName"
src/views/system/dict/data.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="字典名称" prop="dictType">
        <el-select v-model="queryParams.dictType" size="small">
          <el-option
src/views/system/dict/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="字典名称" prop="dictName">
        <el-input
          v-model="queryParams.dictName"
src/views/system/grade/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="年级名称" prop="gradeName">
        <el-input
          v-model="queryParams.gradeName"
src/views/system/medicalevalustion/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="姓名" prop="name">
        <el-input
          v-model="queryParams.name"
src/views/system/menu/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
      <el-form-item label="菜单名称" prop="menuName">
        <el-input
          v-model="queryParams.menuName"
src/views/system/notice/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="公告标题" prop="noticeTitle">
        <el-input
          v-model="queryParams.noticeTitle"
src/views/system/post/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="岗位编码" prop="postCode">
        <el-input
          v-model="queryParams.postCode"
src/views/system/role/authUser.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
     <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
      <el-form-item label="用户名称" prop="userName">
        <el-input
          v-model="queryParams.userName"
src/views/system/role/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
      <el-form-item label="角色名称" prop="roleName">
        <el-input
          v-model="queryParams.roleName"
src/views/system/role/selectUser.vue
@@ -1,7 +1,8 @@
<template>
  <!-- æŽˆæƒç”¨æˆ· -->
  <el-dialog title="选择用户" :visible.sync="visible" width="800px" top="5vh" append-to-body>
    <el-form :model="queryParams" ref="queryForm" :inline="true">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true">
      <el-form-item label="用户名称" prop="userName">
        <el-input
          v-model="queryParams.userName"
src/views/system/student/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="学生名称" prop="studentName">
        <el-input
          v-model="queryParams.studentName"
src/views/system/user/index.vue
@@ -27,7 +27,8 @@
      </el-col>
      <!--用户数据-->
      <el-col :span="20" :xs="24">
        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
        <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
          <el-form-item label="用户名称" prop="userName">
            <el-input
              v-model="queryParams.userName"
src/views/tool/gen/importTable.vue
@@ -1,7 +1,8 @@
<template>
  <!-- å¯¼å…¥è¡¨ -->
  <el-dialog title="导入表" :visible.sync="visible" width="800px" top="5vh" append-to-body>
    <el-form :model="queryParams" ref="queryForm" :inline="true">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true">
      <el-form-item label="表名称" prop="tableName">
        <el-input
          v-model="queryParams.tableName"
src/views/tool/gen/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
    <el-form
      class="opo-query-form" :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="表名称" prop="tableName">
        <el-input
          v-model="queryParams.tableName"