From 3873d3c350c8c1edd7bfdc8afe08c9e78f56d968 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期四, 22 十月 2026 23:24:20 +0800
Subject: [PATCH] 调整费用申请模式

---
 src/utils/theme.js |  172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 172 insertions(+), 0 deletions(-)

diff --git a/src/utils/theme.js b/src/utils/theme.js
new file mode 100644
index 0000000..3a778f9
--- /dev/null
+++ b/src/utils/theme.js
@@ -0,0 +1,172 @@
+/**
+ * 涓婚鑹茶繍琛屾椂璁$畻涓庡簲鐢�
+ * ---------------------------------------------------------------
+ * 鑳屾櫙锛欵lement UI 2.x 鐨勪富棰樿壊鏄� SCSS 缂栬瘧鏈熷父閲忥紝杩愯鏃舵棤娉曟敼鍔紱
+ *      鍘熸湁 ThemePicker 渚濊禆 unpkg CDN 鎷夊彇 theme-chalk 鍐嶅瓧绗︿覆鏇挎崲锛�
+ *      鍐呯綉鐜鎷変笉鍒� CSS锛屽鑷�"鏀逛富棰樻病鍙嶅簲"銆�
+ * 鍋氭硶锛氱敱浠绘剰涓昏壊鎺ㄥ嚭涓�濂楄壊闃讹紙hover / active / light-3~95锛夛紝
+ *      鍐欏叆 :root 鐨� CSS 鍙橀噺锛泃heme-runtime.scss 鐢� var() 娑堣垂杩欎簺鍙橀噺锛�
+ *      浠庤�屽疄鐜�"涓�娆$紪璇戙�佽繍琛屾椂鎹㈣偆銆侀〉闈笉鍒锋柊"銆�
+ */
+
+/** 榛樿涓昏壊锛歄PO_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()
+  )
+}
+
+/**
+ * 娣疯壊锛歸eight 涓虹洰鏍囪壊鍗犳瘮锛�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)
+}
+
+/** 鐩稿浜害锛圵CAG锛� */
+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)
+}
+
+/**
+ * 鐢变富鑹叉帹鍏ㄥ鑹查樁
+ * 娣辫壊涓昏壊锛堜寒搴︿綆锛塰over 鐢�"鍔犳繁"锛屾祬鑹蹭富鑹� 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 鍙橀噺锛坱heme-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
+}

--
Gitblit v1.9.3