mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 10:57:26 +08:00
feat: 添加主题色设置功能
This commit is contained in:
@@ -6,7 +6,9 @@
|
||||
|
||||
<script>
|
||||
import storage from "@/plugins/storage";
|
||||
import { getBaseSite } from "@/api/common.js";
|
||||
import { getBaseSite, getThemeSetting } from "@/api/common.js";
|
||||
import { fetchAndApplyTheme } from "@/utils/theme";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
mounted() {
|
||||
@@ -42,6 +44,7 @@ export default {
|
||||
});
|
||||
}
|
||||
this.getSite();
|
||||
this.getTheme();
|
||||
},
|
||||
getSite() {
|
||||
getBaseSite().then((res) => {
|
||||
@@ -55,6 +58,9 @@ export default {
|
||||
}
|
||||
}).catch(() => {});
|
||||
},
|
||||
getTheme() {
|
||||
fetchAndApplyTheme(getThemeSetting).catch(() => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
95
buyer/src/utils/theme.js
Normal file
95
buyer/src/utils/theme.js
Normal file
@@ -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();
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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: "短信签名",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</el-tabs>
|
||||
<div class="operation mb_10">
|
||||
<el-button type="primary" @click="createTemp">添加页面</el-button>
|
||||
<el-button @click="goThemeSetting">主题色设置</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="list" style="width: 100%">
|
||||
<el-table-column prop="name" label="页面名称" min-width="200" show-overflow-tooltip>
|
||||
@@ -168,6 +169,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
goThemeSetting() {
|
||||
this.$router.push({ name: "theme-setting" });
|
||||
},
|
||||
|
||||
changePageNum(val) {
|
||||
this.searchForm.pageNumber = val;
|
||||
this.getTemplateList();
|
||||
|
||||
123
manager/src/views/page-decoration/theme-setting.vue
Normal file
123
manager/src/views/page-decoration/theme-setting.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="theme-setting">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>主题色设置</span>
|
||||
<span class="desc">配置买家端 PC 与移动端(小程序)的主题色,保存后前台自动生效</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="formValidate"
|
||||
v-loading="loading"
|
||||
label-width="150px"
|
||||
label-position="right"
|
||||
:model="formValidate"
|
||||
:rules="ruleValidate"
|
||||
>
|
||||
<el-form-item label="主题色" prop="themeColor">
|
||||
<el-color-picker v-model="formValidate.themeColor" />
|
||||
<span class="field-desc">买家端主色,用于按钮、价格、标签等</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="高亮主题色" prop="lightColor">
|
||||
<el-color-picker v-model="formValidate.lightColor" />
|
||||
<span class="field-desc">用于渐变、高亮背景等</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="辅助高亮色" prop="aiderLightColor">
|
||||
<el-color-picker v-model="formValidate.aiderLightColor" />
|
||||
<span class="field-desc">用于渐变辅助色、次要强调</span>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saveLoading" @click="submit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSetting, setSetting } from "@/api/index";
|
||||
|
||||
const SETTING_KEY = "THEME_SETTING";
|
||||
|
||||
export default {
|
||||
name: "theme-setting",
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
saveLoading: false,
|
||||
formValidate: {
|
||||
themeColor: "#ff3c2a",
|
||||
lightColor: "#ff6b35",
|
||||
aiderLightColor: "#ff9f28",
|
||||
},
|
||||
ruleValidate: {
|
||||
themeColor: [{ required: true, message: "请选择主题色", trigger: "change" }],
|
||||
lightColor: [{ required: true, message: "请选择高亮主题色", trigger: "change" }],
|
||||
aiderLightColor: [
|
||||
{ required: true, message: "请选择辅助高亮色", trigger: "change" },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.loadSetting();
|
||||
},
|
||||
methods: {
|
||||
loadSetting() {
|
||||
this.loading = true;
|
||||
getSetting(SETTING_KEY)
|
||||
.then((res) => {
|
||||
if (res.success && res.result) {
|
||||
this.formValidate = {
|
||||
...this.formValidate,
|
||||
...res.result,
|
||||
};
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
submit() {
|
||||
this.$refs.formValidate.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.saveLoading = true;
|
||||
setSetting(SETTING_KEY, this.formValidate)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("保存成功");
|
||||
} else {
|
||||
this.$Message.error("保存失败");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.saveLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.theme-setting {
|
||||
.card-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
.desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.field-desc {
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,6 +11,7 @@
|
||||
</el-tabs>
|
||||
<div class="operation mb_10">
|
||||
<el-button type="primary" @click="handleAdd()">添加页面</el-button>
|
||||
<el-button @click="goThemeSetting">主题色设置</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="list" style="width: 100%">
|
||||
<el-table-column prop="name" label="页面名称" min-width="200" show-overflow-tooltip>
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user