From 295aaf1a0115de0a62d58c2d3b110af19fc8cbaf Mon Sep 17 00:00:00 2001 From: "pikachu1995@126.com" Date: Tue, 7 Jul 2026 10:56:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E8=89=B2=E8=AE=BE=E7=BD=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buyer/src/App.vue | 8 +- buyer/src/api/common.js | 9 ++ buyer/src/assets/styles/element.scss | 27 ++-- buyer/src/assets/styles/global.scss | 2 +- .../src/components/goodsDetail/ShowGoods.vue | 4 +- .../indexDecorate/modelList/Seckill.vue | 2 +- .../indexDecorate/modelList/goodsAndType.vue | 4 +- .../modelList/mixs/mix-goods.vue | 4 +- buyer/src/main.js | 5 +- buyer/src/utils/theme.js | 95 ++++++++++++++ manager/public/config.js | 8 +- manager/src/router/router.js | 6 + manager/src/views/login.vue | 2 +- .../src/views/page-decoration/floorList.vue | 5 + .../views/page-decoration/theme-setting.vue | 123 ++++++++++++++++++ .../src/views/page-decoration/wap/wapList.vue | 4 + 16 files changed, 275 insertions(+), 33 deletions(-) create mode 100644 buyer/src/utils/theme.js create mode 100644 manager/src/views/page-decoration/theme-setting.vue diff --git a/buyer/src/App.vue b/buyer/src/App.vue index ea59df2a..8130cf7d 100644 --- a/buyer/src/App.vue +++ b/buyer/src/App.vue @@ -6,7 +6,9 @@ diff --git a/buyer/src/api/common.js b/buyer/src/api/common.js index b3e5e630..db827304 100644 --- a/buyer/src/api/common.js +++ b/buyer/src/api/common.js @@ -94,3 +94,12 @@ export function getBaseSite(){ needToken: false }) } + +// 获取主题色配置 +export function getThemeSetting() { + return request({ + url: `${commonUrl}/common/common/site/theme`, + method: Method.GET, + needToken: false, + }); +} diff --git a/buyer/src/assets/styles/element.scss b/buyer/src/assets/styles/element.scss index e89ef0d9..8e9cca44 100644 --- a/buyer/src/assets/styles/element.scss +++ b/buyer/src/assets/styles/element.scss @@ -1,18 +1,9 @@ :root { - // --el-color-primary: #ff5c58; - // --el-color-success: #68cabe; - // --el-color-warning: #fa6419; - // --el-color-danger: #ff3c2a; + --el-color-primary: var(--theme-color, #ff3c2a); + --el-color-danger: var(--theme-color, #ff3c2a); --el-font-size-base: 14px; } -// .el-button--primary { -// --el-button-bg-color: #ff5c58; -// --el-button-border-color: #ff5c58; -// --el-button-hover-bg-color: #ff7875; -// --el-button-hover-border-color: #ff7875; -// } - .el-table--border { .el-table__cell { border-right: none !important; @@ -20,12 +11,12 @@ } .link-text { - color: #409eff; + color: var(--theme-color, #ff3c2a); cursor: pointer; text-decoration: none; &:hover { - color: #66b1ff; + opacity: 0.85; } } @@ -34,16 +25,16 @@ color: #dcdfe6; } -/* 与「我的订单」确认收货按钮一致的橙色操作按钮 */ +/* 次要强调按钮,使用高亮主题色(如「立即购买」) */ .confirm-receipt-btn { - background-color: #ff9900 !important; - border-color: #ff9900 !important; + background-color: var(--theme-light, #ff6b35) !important; + border-color: var(--theme-light, #ff6b35) !important; color: #fff !important; &:hover, &:focus { - background-color: #e68a00 !important; - border-color: #e68a00 !important; + background-color: color-mix(in srgb, var(--theme-light, #ff6b35) 88%, black) !important; + border-color: color-mix(in srgb, var(--theme-light, #ff6b35) 88%, black) !important; color: #fff !important; } } diff --git a/buyer/src/assets/styles/global.scss b/buyer/src/assets/styles/global.scss index b1b298da..7f5103e9 100644 --- a/buyer/src/assets/styles/global.scss +++ b/buyer/src/assets/styles/global.scss @@ -10,7 +10,7 @@ $warning_color: #ff9900; $error_color: #ed3f14; $handle-btn-color: #438cde; -$theme_color: #F31947; +$theme_color: var(--theme-color, #ff3c2a); $border_color: #dddee1; $title_color: #8c8c8c; diff --git a/buyer/src/components/goodsDetail/ShowGoods.vue b/buyer/src/components/goodsDetail/ShowGoods.vue index 44e1c7df..6f801921 100644 --- a/buyer/src/components/goodsDetail/ShowGoods.vue +++ b/buyer/src/components/goodsDetail/ShowGoods.vue @@ -814,7 +814,7 @@ export default { color: $theme_color; margin: 5px 0; font-size: 12px; - background-color: #ffdedf; + background-color: var(--theme-tint-12, #ffdedf); border: 1px dotted $theme_color; cursor: pointer; @@ -839,7 +839,7 @@ export default { padding: 0 5px; color: $theme_color; font-size: 12px; - background-color: #ffdedf; + background-color: var(--theme-tint-12, #ffdedf); border: 1px dotted $theme_color; cursor: pointer; diff --git a/buyer/src/components/indexDecorate/modelList/Seckill.vue b/buyer/src/components/indexDecorate/modelList/Seckill.vue index 93fdddbc..3e98cc50 100644 --- a/buyer/src/components/indexDecorate/modelList/Seckill.vue +++ b/buyer/src/components/indexDecorate/modelList/Seckill.vue @@ -130,7 +130,7 @@ export default { width: 190px; height: 100%; color: #fff; - background: linear-gradient(180deg, #ff5c58 0%, #e84a46 100%); + background: linear-gradient(180deg, var(--theme-color, #F31947) 0%, var(--theme-light, #ff6b35) 100%); .title { width: 100%; text-align: center; diff --git a/buyer/src/components/indexDecorate/modelList/goodsAndType.vue b/buyer/src/components/indexDecorate/modelList/goodsAndType.vue index 55b15872..e199cf6f 100644 --- a/buyer/src/components/indexDecorate/modelList/goodsAndType.vue +++ b/buyer/src/components/indexDecorate/modelList/goodsAndType.vue @@ -173,7 +173,7 @@ export default { text-align: center; letter-spacing: 0px; - color: #f31947; + color: $theme_color; -webkit-text-stroke: #979797 0.7px; /* 浏览器可能不支持 */ } .goods-type-line { @@ -190,7 +190,7 @@ export default { color: #333333; } .active { - color: #f31947; + color: $theme_color; } .goods-type-labels { cursor: pointer; diff --git a/buyer/src/components/indexDecorate/modelList/mixs/mix-goods.vue b/buyer/src/components/indexDecorate/modelList/mixs/mix-goods.vue index 69206be0..e6ae0a77 100644 --- a/buyer/src/components/indexDecorate/modelList/mixs/mix-goods.vue +++ b/buyer/src/components/indexDecorate/modelList/mixs/mix-goods.vue @@ -85,7 +85,7 @@ export default { font-size: 14px; font-weight: normal; line-height: 17px; - color: #f31947; + color: $theme_color; margin-top: 8px; } @@ -139,7 +139,7 @@ export default { height: 27px; line-height: 27px; border-radius: 13.3px 0 0 13.3px; - background: #f31947; + background: $theme_color; font-size: 12.6px; text-align: center; color: #ffffff; diff --git a/buyer/src/main.js b/buyer/src/main.js index 90953af6..dc35c0ff 100644 --- a/buyer/src/main.js +++ b/buyer/src/main.js @@ -10,6 +10,8 @@ import { setupLegacyMessage } from "@/utils/message"; import { registerGlobalComponents } from "@/components/global.js"; import * as filters from "./plugins/filters"; import storage from "@/plugins/storage"; +import { fetchAndApplyTheme } from "@/utils/theme"; +import { getThemeSetting } from "@/api/common.js"; const { aMapSecurityJsCode, inputMaxLength } = require("@/config"); @@ -49,6 +51,7 @@ app.config.globalProperties.connectCs = function ( window.open(url, "_blank"); }; -router.isReady().then(() => { +router.isReady().then(async () => { + await fetchAndApplyTheme(getThemeSetting); app.mount("#app"); }); diff --git a/buyer/src/utils/theme.js b/buyer/src/utils/theme.js new file mode 100644 index 00000000..5ab17c85 --- /dev/null +++ b/buyer/src/utils/theme.js @@ -0,0 +1,95 @@ +/** + * 平台主题色工具 + */ +const DEFAULT_THEME = { + themeColor: "#ff3c2a", + lightColor: "#ff6b35", + aiderLightColor: "#ff9f28", +}; + +const STORAGE_KEY = "theme_setting"; +const EXPIRATION_KEY = "theme_setting_expiration_time"; + +export function getDefaultTheme() { + return { ...DEFAULT_THEME }; +} + +function applyElementColorVars(style, prefix, color) { + const key = `--el-color-${prefix}`; + style.setProperty(key, color); + style.setProperty(`${key}-light-3`, `color-mix(in srgb, ${color} 70%, white)`); + style.setProperty(`${key}-light-5`, `color-mix(in srgb, ${color} 50%, white)`); + style.setProperty(`${key}-light-7`, `color-mix(in srgb, ${color} 30%, white)`); + style.setProperty(`${key}-light-8`, `color-mix(in srgb, ${color} 20%, white)`); + style.setProperty(`${key}-light-9`, `color-mix(in srgb, ${color} 10%, white)`); + style.setProperty(`${key}-dark-2`, `color-mix(in srgb, ${color} 80%, black)`); +} + +export function applyThemeToDocument(theme) { + if (typeof document === "undefined") return; + const primary = theme.themeColor || DEFAULT_THEME.themeColor; + const light = theme.lightColor || DEFAULT_THEME.lightColor; + const aider = theme.aiderLightColor || DEFAULT_THEME.aiderLightColor; + const root = document.documentElement.style; + + root.setProperty("--theme-color", primary); + root.setProperty("--theme-light", light); + root.setProperty("--theme-aider", aider); + root.setProperty("--theme-tint-12", `color-mix(in srgb, ${primary} 12%, white)`); + + applyElementColorVars(root, "primary", primary); + // 买家端大量按钮使用 type="danger",统一映射到主题色 + applyElementColorVars(root, "danger", primary); +} + +export function cacheTheme(theme) { + const expirationTime = new Date().setHours(new Date().getHours() + 1); + localStorage.setItem(EXPIRATION_KEY, String(expirationTime)); + localStorage.setItem(STORAGE_KEY, JSON.stringify(theme)); +} + +export function loadCachedTheme() { + const expirationTime = localStorage.getItem(EXPIRATION_KEY); + const cacheValid = + expirationTime && new Date() <= new Date(Number(expirationTime)); + if (!cacheValid) return null; + try { + const raw = localStorage.getItem(STORAGE_KEY); + return raw ? JSON.parse(raw) : null; + } catch { + return null; + } +} + +export function normalizeTheme(data = {}) { + return { + themeColor: data.themeColor || DEFAULT_THEME.themeColor, + lightColor: data.lightColor || DEFAULT_THEME.lightColor, + aiderLightColor: data.aiderLightColor || DEFAULT_THEME.aiderLightColor, + }; +} + +export async function fetchAndApplyTheme(requestFn) { + const cachedTheme = loadCachedTheme(); + if (cachedTheme) { + applyThemeToDocument(normalizeTheme(cachedTheme)); + } + + try { + const res = await requestFn(); + if (res?.success && res?.result?.settingValue) { + const data = JSON.parse(res.result.settingValue); + const normalized = normalizeTheme(data); + applyThemeToDocument(normalized); + cacheTheme(normalized); + return normalized; + } + } catch (error) { + console.warn( + "[theme] 主题色加载失败,请确认 common-api(8890) 已启动且已执行 version4.9to4.10.sql", + error + ); + } + + return cachedTheme ? normalizeTheme(cachedTheme) : normalizeTheme(); +} diff --git a/manager/public/config.js b/manager/public/config.js index 9f51858a..09375686 100644 --- a/manager/public/config.js +++ b/manager/public/config.js @@ -3,10 +3,10 @@ var BASE = { * @description api请求基础路径 */ API_DEV: { - common: "https://common-api.pickmall.cn", - buyer: "https://buyer-api.pickmall.cn", - seller: "https://store-api.pickmall.cn", - manager: "https://admin-api.pickmall.cn", + common: "http://127.0.0.1:8890", + buyer: "http://127.0.0.1:8888", + seller: "http://127.0.0.1:8889", + manager: "http://127.0.0.1:8887", }, API_PROD: { common: "https://common-api.pickmall.cn", diff --git a/manager/src/router/router.js b/manager/src/router/router.js index 0546e218..faa6c5bd 100644 --- a/manager/src/router/router.js +++ b/manager/src/router/router.js @@ -349,6 +349,12 @@ export const otherRouter = { name: "main", component: () => import("@/views/page-decoration/wap/main.vue") }, + { + path: "/floorList/theme-setting", + title: "主题色设置", + name: "theme-setting", + component: () => import("@/views/page-decoration/theme-setting.vue") + }, { path: "add-sms-sign", title: "短信签名", diff --git a/manager/src/views/login.vue b/manager/src/views/login.vue index 592ad6d3..a9ea8d72 100644 --- a/manager/src/views/login.vue +++ b/manager/src/views/login.vue @@ -377,7 +377,7 @@ export default { transition: background-color 0.2s ease, opacity 0.2s ease; &:hover { - background: darken($theme_color, 4%); + background: color-mix(in srgb, #{$theme_color} 96%, black); opacity: 1; } } diff --git a/manager/src/views/page-decoration/floorList.vue b/manager/src/views/page-decoration/floorList.vue index 63f3786c..3f8b5197 100644 --- a/manager/src/views/page-decoration/floorList.vue +++ b/manager/src/views/page-decoration/floorList.vue @@ -11,6 +11,7 @@
添加页面 + 主题色设置
@@ -168,6 +169,10 @@ export default { }); }, + goThemeSetting() { + this.$router.push({ name: "theme-setting" }); + }, + changePageNum(val) { this.searchForm.pageNumber = val; this.getTemplateList(); diff --git a/manager/src/views/page-decoration/theme-setting.vue b/manager/src/views/page-decoration/theme-setting.vue new file mode 100644 index 00000000..1858fed8 --- /dev/null +++ b/manager/src/views/page-decoration/theme-setting.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/manager/src/views/page-decoration/wap/wapList.vue b/manager/src/views/page-decoration/wap/wapList.vue index b3cbb984..872f3a1c 100644 --- a/manager/src/views/page-decoration/wap/wapList.vue +++ b/manager/src/views/page-decoration/wap/wapList.vue @@ -11,6 +11,7 @@
添加页面 + 主题色设置
@@ -149,6 +150,9 @@ export default { query: { pagetype: this.params.pageType }, }); }, + goThemeSetting() { + this.$router.push({ name: "theme-setting" }); + }, changePageSize(v) { this.params.pageNumber = 1; this.params.pageSize = v;