fix(theme): 优化主题色设置功能并修复令牌刷新逻辑

- 移除楼层列表中的主题色设置按钮及路由
- 重构主题色设置页面,新增系统预设色系和自定义模式
- 添加移动端真实页面预览功能,支持商品详情和订单页面预览
- 优化商品详情页优惠券展示样式和布局
- 修复买家端API刷新令牌请求的拦截器递归死锁问题
- 添加无refreshToken时的刷新请求保护机制
This commit is contained in:
pikachu1995@126.com
2026-10-09 15:50:56 +08:00
parent 1bd50cee45
commit bbe336d902
7 changed files with 981 additions and 143 deletions

View File

@@ -63,6 +63,9 @@ export function handleRefreshToken(token) {
url: `/buyer/passport/member/refresh/${token}`, url: `/buyer/passport/member/refresh/${token}`,
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
// 刷新令牌请求自身不再进入 401/403 刷新分支,避免拦截器递归死锁;失败也不弹全局错误提示
skipAuthHandler: true,
skipMessage: true,
}); });
} }

View File

@@ -102,9 +102,8 @@
</div> </div>
<!-- 优惠券展示 --> <!-- 优惠券展示 -->
<div class="item-price-coupon-row" v-if="promotionMap['COUPON'].length"> <div class="item-price-coupon-row" v-if="promotionMap['COUPON'].length">
<div class="Ellipsis">
<span class="item-price-title">优惠券</span> <span class="item-price-title">优惠券</span>
<span> <div class="coupon-tags">
<span <span
class="item-coupon" class="item-coupon"
v-for="(item, index) in promotionMap['COUPON'].slice(0, 6)" v-for="(item, index) in promotionMap['COUPON'].slice(0, 6)"
@@ -118,10 +117,9 @@
item.couponDiscount item.couponDiscount
}}折</span> }}折</span>
</span> </span>
</span>
<div class="dropdown" v-if="promotionMap['COUPON'].length > 6"> <div class="dropdown" v-if="promotionMap['COUPON'].length > 6">
<span>展开更多</span> <span class="dropdown-more">展开更多 ▾</span>
<div class="dropdown-content"> <div class="dropdown-content">
<span <span
class="item-coupon" class="item-coupon"
@@ -898,62 +896,75 @@ export default {
.item-price-coupon-row { .item-price-coupon-row {
display: flex; display: flex;
align-items: center; align-items: flex-start;
margin: 5px 0px; margin: 8px 0px;
.item-price-title {
flex-shrink: 0;
line-height: 22px;
}
} }
.Ellipsis { .coupon-tags {
overflow: hidden; display: flex;
display: -webkit-box; flex-wrap: wrap;
-webkit-line-clamp: 2; //控制显示几行 align-items: center;
-webkit-box-orient: vertical; //webbox方向 gap: 6px;
} }
.dropdown { .dropdown {
position: relative; position: relative;
display: inline-block; display: inline-flex;
align-items: center;
cursor: pointer; cursor: pointer;
z-index: 999; z-index: 999;
} }
.dropdown .item-coupon { .dropdown-more {
display: flex; font-size: 12px;
align-content: center; color: #999;
align-items: center; line-height: 22px;
color: $theme_color; white-space: nowrap;
margin: 5px 0;
font-size: 14px;
background-color: var(--theme-tint-12, #ffdedf);
border: 1px dotted $theme_color;
cursor: pointer;
span { &:hover {
padding: 3px; color: $theme_color;
} }
} }
.dropdown-content { .dropdown-content {
display: none; display: none;
position: absolute; position: absolute;
background-color: #f9f9f9; top: 24px;
min-width: 160px; left: 0;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); background-color: #fff;
padding: 12px 16px; min-width: 220px;
max-width: 320px;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
padding: 12px;
flex-wrap: wrap;
gap: 6px;
} }
.dropdown:hover .dropdown-content { .dropdown:hover .dropdown-content {
display: block; display: flex;
} }
.item-coupon { .item-coupon {
margin-right: 5px; position: relative;
padding: 0 5px; padding: 2px 10px;
color: $theme_color; color: $theme_color;
font-size: 14px; font-size: 12px;
background-color: var(--theme-tint-12, #ffdedf); line-height: 18px;
border: 1px dotted $theme_color; background-color: #fff;
border: 1px solid $theme_color;
border-radius: 3px;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s, color 0.2s;
white-space: nowrap;
span { &:hover {
padding: 3px; background-color: $theme_color;
color: #fff;
} }
} }
.item-promotion { .item-promotion {

View File

@@ -161,9 +161,10 @@ service.interceptors.response.use(
const errorData = errorResponse.data || {}; const errorData = errorResponse.data || {};
if ( if (
errorResponse.status === 401 || !error.config?.skipAuthHandler &&
(errorResponse.status === 401 ||
errorResponse.status === 403 || errorResponse.status === 403 ||
error.response?.data?.code === 20004 error.response?.data?.code === 20004)
) { ) {
isRefreshToken++; isRefreshToken++;
if (isRefreshToken === 1) { if (isRefreshToken === 1) {
@@ -212,8 +213,12 @@ function getTokenDebounce() {
let success = false; let success = false;
return function () { return function () {
if (!lock) { if (!lock) {
lock = true;
const oldRefreshToken = Storage.getItem("refreshToken"); const oldRefreshToken = Storage.getItem("refreshToken");
// 无 refreshToken(未登录)时不发起刷新请求,直接判失败,避免请求 /refresh/undefined 造成拦截器死锁
if (!oldRefreshToken) {
return Promise.resolve("fail");
}
lock = true;
handleRefreshToken(oldRefreshToken) handleRefreshToken(oldRefreshToken)
.then((res) => { .then((res) => {
if (res.success) { if (res.success) {

View File

@@ -361,12 +361,6 @@ export const otherRouter = {
name: "main", name: "main",
component: () => import("@/views/page-decoration/wap/main.vue") 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", path: "add-sms-sign",
title: "短信签名", title: "短信签名",

View File

@@ -11,7 +11,6 @@
</el-tabs> </el-tabs>
<div class="operation mb_10"> <div class="operation mb_10">
<el-button type="primary" @click="createTemp">添加页面</el-button> <el-button type="primary" @click="createTemp">添加页面</el-button>
<el-button @click="goThemeSetting">主题色设置</el-button>
</div> </div>
<el-table v-loading="loading" :data="list" style="width: 100%"> <el-table v-loading="loading" :data="list" style="width: 100%">
<el-table-column prop="name" label="页面名称" min-width="200" show-overflow-tooltip> <el-table-column prop="name" label="页面名称" min-width="200" show-overflow-tooltip>
@@ -169,10 +168,6 @@ export default {
}); });
}, },
goThemeSetting() {
this.$router.push({ name: "theme-setting" });
},
changePageNum(val) { changePageNum(val) {
this.searchForm.pageNumber = val; this.searchForm.pageNumber = val;
this.getTemplateList(); this.getTemplateList();

View File

@@ -1,77 +1,318 @@
<template> <template>
<div class="theme-setting"> <div class="theme-setting">
<el-card shadow="never"> <div class="config-panel">
<el-card shadow="never" class="config-card">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<span>主题色设置</span> <span>主题色系</span>
<span class="desc">配置买家端 PC 与移动端(小程序)的主题色,保存后前台自动生效</span> <span class="desc">配置买家端 PC 与移动端(小程序)的主题色,保存后前台自动生效</span>
</div> </div>
</template> </template>
<el-form
ref="formValidate" <!-- 系统预设色系(始终展示,选中即切为系统模式) -->
v-loading="loading" <div class="mode-section">
label-width="150px" <el-radio v-model="form.mode" label="system">系统</el-radio>
label-position="right" <div class="preset-list" @click="form.mode = 'system'">
:model="formValidate" <div
:rules="ruleValidate" v-for="(item, index) in presetThemes"
:key="index"
class="preset-item"
:class="{ active: form.mode === 'system' && isActivePreset(item) }"
@click="selectPreset(item)"
> >
<el-form-item label="主题色" prop="themeColor"> <span class="swatch" :style="{ background: item.themeColor }"></span>
<el-color-picker v-model="formValidate.themeColor" /> <span class="swatch" :style="{ background: item.aiderLightColor }"></span>
<span class="field-desc">买家端主色,用于按钮、价格、标签等</span> <span class="swatch pale" :style="{ background: item.paleColor }"></span>
</el-form-item> </div>
<el-form-item label="高亮主题色" prop="lightColor"> </div>
<el-color-picker v-model="formValidate.lightColor" /> </div>
<span class="field-desc">用于渐变、高亮背景等</span>
</el-form-item> <!-- 自定义色系(始终展示,修改即切为自定义模式) -->
<el-form-item label="辅助高亮色" prop="aiderLightColor"> <div class="mode-section">
<el-color-picker v-model="formValidate.aiderLightColor" /> <el-radio v-model="form.mode" label="custom">自定义</el-radio>
<span class="field-desc">用于渐变辅助色、次要强调</span> <div class="custom-form" @click="form.mode = 'custom'">
</el-form-item> <div class="color-row">
<el-form-item> <span class="color-label">主题色:</span>
<el-button type="primary" :loading="saveLoading" @click="submit">保存</el-button> <div class="color-box">
</el-form-item> <el-color-picker v-model="form.themeColor" @change="form.mode = 'custom'" />
</el-form> <span class="color-value">{{ form.themeColor }}</span>
</div>
</div>
<div class="color-row">
<span class="color-label">辅助色:</span>
<div class="color-box">
<el-color-picker v-model="form.aiderLightColor" @change="form.mode = 'custom'" />
<span class="color-value">{{ form.aiderLightColor }}</span>
</div>
<el-tooltip
content="辅助色和主题色组成渐变色,用于按钮、卡片、标签、进度条等元素背景"
placement="top"
>
<el-icon class="help-icon"><QuestionFilled /></el-icon>
</el-tooltip>
</div>
</div>
</div>
</el-card> </el-card>
<div class="footer">
<el-button type="primary" :loading="saveLoading" @click="submit">保存</el-button>
</div>
</div>
<!-- 移动端真实页面预览(结构对齐 lilishop-uniapp) -->
<div class="preview-panel">
<!-- 商品详情 pages/product/goods.vue -->
<div class="phone">
<div class="p-status">
<span class="p-time">9:41 AM</span>
<span class="p-icons"><i class="signal"></i><i class="wifi"></i><i class="battery"></i></span>
</div>
<div class="p-nav">
<span class="p-back">‹</span>
<span class="p-title">商品详情</span>
<span class="p-capsule">··· ⊙</span>
</div>
<div class="p-body">
<div class="g-img"><span class="g-img-emoji">👜</span></div>
<div class="g-seckill" :style="{ background: gradient }">
<span class="g-seckill-name">秒杀</span>
<span class="g-seckill-count">距离结束还剩 <i>02</i>:<i>24</i>:<i>59</i></span>
</div>
<div class="g-main">
<div class="g-price-row">
<span class="g-price" :style="{ color: form.themeColor }">¥299.00</span>
<s class="g-price-origin">¥300.00</s>
<span class="g-fav">♡ 收藏</span>
</div>
<div class="g-progress">
<span class="g-progress-text">已抢 82%</span>
<div class="g-progress-track">
<div class="g-progress-inner" :style="{ width: '82%', background: gradient }"></div>
</div>
</div>
<div class="g-name">现代简约北欧风格客厅装饰画沙发背景墙创意玄关挂画组合</div>
<div class="g-sub">软饰焕新颜,尊享优惠双重叠加</div>
</div>
</div>
<div class="p-tabbar goods-bar">
<div class="bar-icons">
<div class="bar-icon">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#666" stroke-width="1.6"><path d="M4 12a8 8 0 0 1 16 0"/><rect x="2" y="12" width="4" height="6" rx="2"/><rect x="18" y="12" width="4" height="6" rx="2"/></svg>
<span>客服</span>
</div>
<div class="bar-icon">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#666" stroke-width="1.6"><path d="M4 9l1-4h14l1 4"/><path d="M4 9h16v11H4z"/><path d="M9 20v-6h6v6"/></svg>
<span>店铺</span>
</div>
<div class="bar-icon">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#666" stroke-width="1.6"><circle cx="9" cy="20" r="1.6"/><circle cx="18" cy="20" r="1.6"/><path d="M2 3h3l2.5 12h11l2-8H6"/></svg>
<span>购物车</span>
</div>
</div>
<span class="bar-btn outline" :style="{ color: form.themeColor, borderColor: form.themeColor }">加入购物车</span>
<span class="bar-btn solid" :style="{ background: gradient }">立即购买</span>
</div>
</div>
<!-- 规格弹层 pages/product/goods.vue SKU 弹窗 -->
<div class="phone">
<div class="p-status">
<span class="p-time">9:41 AM</span>
<span class="p-icons"><i class="signal"></i><i class="wifi"></i><i class="battery"></i></span>
</div>
<div class="p-nav">
<span class="p-back">‹</span>
<span class="p-title">商品详情</span>
<span class="p-capsule">··· ⊙</span>
</div>
<div class="p-body sku-mask">
<div class="sku-popup">
<span class="sku-close">✕</span>
<div class="sku-head">
<div class="sku-thumb">👜</div>
<div>
<div class="sku-price">
<span class="g-price" :style="{ color: form.themeColor }">¥299.00</span>
<s class="g-price-origin">¥300.00</s>
</div>
<div class="sku-tags">
<span class="mini-tag" :style="outlineTagStyle">满减</span>
<span class="mini-tag" :style="outlineTagStyle">券</span>
</div>
</div>
</div>
<div class="sku-title">颜色</div>
<div class="sku-list">
<span class="sku-item selected" :style="tagStyle">印象简约</span>
<span class="sku-item">时空印记</span>
<span class="sku-item">六月物语</span>
<span class="sku-item">远山如黛</span>
</div>
<div class="sku-title">包装</div>
<div class="sku-list">
<span class="sku-item">极简装</span>
<span class="sku-item selected" :style="tagStyle">简装</span>
<span class="sku-item">定制</span>
</div>
<div class="sku-title">尺码</div>
<div class="sku-list">
<span class="sku-item selected" :style="tagStyle">50*70</span>
<span class="sku-item">60*80</span>
<span class="sku-item">80*120</span>
</div>
<div class="sku-count">
<span>数量 <i class="sku-stock">库存999个</i></span>
<span class="stepper"><i>−</i> 1 <i>+</i></span>
</div>
<div class="sku-confirm" :style="{ background: gradient }">加入购物车</div>
</div>
</div>
</div>
<!-- 确认订单 pages/order/fillorder.vue -->
<div class="phone">
<div class="p-status">
<span class="p-time">9:41 AM</span>
<span class="p-icons"><i class="signal"></i><i class="wifi"></i><i class="battery"></i></span>
</div>
<div class="p-nav">
<span class="p-back">‹</span>
<span class="p-title">确认订单</span>
<span class="p-capsule">··· ⊙</span>
</div>
<div class="p-body order-body">
<div class="o-card o-addr-card">
<div class="o-addr-name">王同学 138****9988</div>
<div class="o-addr">北京市海淀区五道口AI原点社区</div>
</div>
<div class="o-card">
<div class="o-store">
<span class="mini-tag" :style="outlineTagStyle">自营</span>小清新自营旗舰店
</div>
<div class="o-reduce">
<span class="mini-tag" :style="outlineTagStyle">满减</span>您已满足满2000减168
</div>
<div class="o-goods">
<div class="sku-thumb">👜</div>
<div class="sku-thumb">🛋️</div>
<div class="o-goods-more">2 ›</div>
</div>
<div class="o-row"><span>发票信息</span><span class="o-muted">不需要发票 ›</span></div>
<div class="o-row"><span>订单备注</span><span class="o-muted">点击输入,100字以内</span></div>
<div class="o-row"><span>订单附件</span><span class="o-muted">上传图片 +</span></div>
<div class="o-row"><span>订单金额</span><span class="o-amount" :style="{ color: form.themeColor }">¥707.00</span></div>
<div class="o-row"><span>商品金额</span><span>¥707.00</span></div>
<div class="o-row"><span>配送费用</span><span>¥0.00</span></div>
</div>
<div class="o-card">
<div class="o-row"><span>支付/配送</span><span>在线支付/快递配送 ··›</span></div>
<div class="o-row">
<span>使用优惠券 <i class="o-coupon" :style="{ color: form.themeColor }">2张可用</i></span>
<span>¥0.00 ··›</span>
</div>
</div>
</div>
<div class="p-tabbar order-bar">
<span class="o-total">合计: <i :style="{ color: form.themeColor }">¥707.00</i></span>
<span class="bar-btn solid" :style="{ background: gradient }">提交订单</span>
</div>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { getSetting, setSetting } from "@/api/index"; import { getSetting, setSetting } from "@/api/index";
import { QuestionFilled } from "@element-plus/icons-vue";
const SETTING_KEY = "THEME_SETTING"; const SETTING_KEY = "THEME_SETTING";
/** 系统预设主题色系:主题色 + 辅助色 + 浅底色(展示用三色块) */
const PRESET_THEMES = [
{ themeColor: "#FF6600", aiderLightColor: "#FF8533", paleColor: "#FFF1E8" },
{ themeColor: "#F7B500", aiderLightColor: "#FAD961", paleColor: "#FFF8E1" },
{ themeColor: "#13C2C2", aiderLightColor: "#36CFC9", paleColor: "#E6FFFB" },
{ themeColor: "#07C160", aiderLightColor: "#4BD88A", paleColor: "#E8F9F0" },
{ themeColor: "#2B85E4", aiderLightColor: "#5CA8FF", paleColor: "#E8F3FF" },
{ themeColor: "#722ED1", aiderLightColor: "#9254DE", paleColor: "#F5EEFF" },
{ themeColor: "#FF4D94", aiderLightColor: "#FF85B3", paleColor: "#FFEAF3" },
{ themeColor: "#F5222D", aiderLightColor: "#FF4D4F", paleColor: "#FFECE8" },
{ themeColor: "#F5C10B", aiderLightColor: "#D4A017", paleColor: "#000000" },
{ themeColor: "#000000", aiderLightColor: "#434343", paleColor: "#F5F5F5" },
];
export default { export default {
name: "theme-setting", name: "theme-setting",
components: { QuestionFilled },
data() { data() {
return { return {
loading: false, loading: false,
saveLoading: false, saveLoading: false,
formValidate: { presetThemes: PRESET_THEMES,
form: {
mode: "custom",
themeColor: "#ff3c2a", themeColor: "#ff3c2a",
lightColor: "#ff6b35",
aiderLightColor: "#ff9f28", aiderLightColor: "#ff9f28",
}, },
ruleValidate: {
themeColor: [{ required: true, message: "请选择主题色", trigger: "change" }],
lightColor: [{ required: true, message: "请选择高亮主题色", trigger: "change" }],
aiderLightColor: [
{ required: true, message: "请选择辅助高亮色", trigger: "change" },
],
},
}; };
}, },
computed: {
// 与移动端一致:提交订单等按钮为 主题色(91deg)→辅助色 渐变
// 见 lilishop-uniapp/pages/order/fillorder.vue .tabbar-right
gradient() {
return `linear-gradient(91deg, ${this.form.themeColor} 1%, ${this.form.aiderLightColor} 99%)`;
},
// 与移动端 --theme-primary-10 一致:主题色 10% 透明度浅底
tint() {
const hex = this.form.themeColor.replace("#", "");
if (hex.length !== 6) return "rgba(0,0,0,0.04)";
const r = parseInt(hex.slice(0, 2), 16);
const g = parseInt(hex.slice(2, 4), 16);
const b = parseInt(hex.slice(4, 6), 16);
return `rgba(${r}, ${g}, ${b}, 0.1)`;
},
// 标签 / 规格选中态:主题色文字 + 主题色描边 + 10% 浅底
tagStyle() {
return {
color: this.form.themeColor,
borderColor: this.form.themeColor,
background: this.tint,
};
},
// 小标签(满减/券/自营):白底 + 主题色描边
outlineTagStyle() {
return {
color: this.form.themeColor,
borderColor: this.form.themeColor,
background: "#fff",
};
},
},
mounted() { mounted() {
this.loadSetting(); this.loadSetting();
}, },
methods: { methods: {
isActivePreset(item) {
return (
this.form.themeColor.toLowerCase() === item.themeColor.toLowerCase() &&
this.form.aiderLightColor.toLowerCase() === item.aiderLightColor.toLowerCase()
);
},
selectPreset(item) {
this.form.themeColor = item.themeColor;
this.form.aiderLightColor = item.aiderLightColor;
},
loadSetting() { loadSetting() {
this.loading = true; this.loading = true;
getSetting(SETTING_KEY) getSetting(SETTING_KEY)
.then((res) => { .then((res) => {
if (res.success && res.result) { if (res.success && res.result) {
this.formValidate = { const data = res.result;
...this.formValidate, this.form = {
...res.result, mode: data.mode || "custom",
themeColor: data.themeColor || this.form.themeColor,
aiderLightColor: data.aiderLightColor || this.form.aiderLightColor,
}; };
} }
}) })
@@ -80,10 +321,19 @@ export default {
}); });
}, },
submit() { submit() {
this.$refs.formValidate.validate((valid) => { if (!this.form.themeColor || !this.form.aiderLightColor) {
if (!valid) return; this.$Message.error("请选择主题色和辅助色");
return;
}
this.saveLoading = true; this.saveLoading = true;
setSetting(SETTING_KEY, this.formValidate) // lightColor(价格文字、进度条高亮)与主题色保持一致
const payload = {
mode: this.form.mode,
themeColor: this.form.themeColor,
lightColor: this.form.themeColor,
aiderLightColor: this.form.aiderLightColor,
};
setSetting(SETTING_KEY, payload)
.then((res) => { .then((res) => {
if (res.success) { if (res.success) {
this.$Message.success("保存成功"); this.$Message.success("保存成功");
@@ -94,7 +344,6 @@ export default {
.finally(() => { .finally(() => {
this.saveLoading = false; this.saveLoading = false;
}); });
});
}, },
}, },
}; };
@@ -102,6 +351,19 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.theme-setting { .theme-setting {
display: flex;
gap: 24px;
align-items: flex-start;
.config-panel {
width: 380px;
flex-shrink: 0;
}
.config-card {
border-radius: 8px;
}
.card-header { .card-header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -114,10 +376,582 @@ export default {
} }
} }
.field-desc { .mode-section {
margin-left: 10px; margin-bottom: 28px;
&:last-of-type {
margin-bottom: 0;
}
}
.preset-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 14px 12px;
margin-top: 16px;
}
.preset-item {
display: flex;
cursor: pointer;
padding: 3px;
border: 1px solid transparent;
border-radius: 6px;
transition: border-color 0.2s, box-shadow 0.2s;
&.active {
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary);
}
.swatch {
flex: 1;
height: 26px;
&:first-child {
border-radius: 4px 0 0 4px;
}
&:last-child {
border-radius: 0 4px 4px 0;
}
&.pale {
border: 1px solid #f0f0f0;
border-left: none;
}
}
}
.custom-form {
margin-top: 16px;
.color-row {
display: flex;
align-items: center;
margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
}
.color-label {
width: 56px;
color: #333;
flex-shrink: 0;
}
.color-box {
display: flex;
align-items: center;
gap: 10px;
background: #f7f8fa;
border-radius: 6px;
padding: 4px 12px;
}
.color-value {
color: #666;
font-size: 13px;
}
.help-icon {
margin-left: 8px;
color: #bbb;
cursor: pointer;
}
}
.footer {
margin-top: 16px;
}
}
/* 移动端真实页面预览 */
.preview-panel {
display: flex;
gap: 28px;
flex: 1;
justify-content: flex-start;
padding: 8px 0 24px;
.phone {
width: 300px;
height: 640px;
background: #f7f8fa;
border-radius: 24px;
overflow: hidden;
display: flex;
flex-direction: column;
font-size: 13px;
color: #303133;
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.1);
border: 1px solid #eee;
}
/* 状态栏 */
.p-status {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px 4px;
font-size: 11px;
color: #333;
background: #fff;
flex-shrink: 0;
.p-icons {
display: inline-flex;
align-items: center;
gap: 5px;
.signal {
width: 13px;
height: 9px;
clip-path: polygon(0 100%, 0 60%, 20% 60%, 20% 100%, 30% 100%, 30% 40%, 45% 40%, 45% 100%, 55% 100%, 55% 20%, 70% 20%, 70% 100%, 80% 100%, 80% 0, 95% 0, 95% 100%);
background: #333;
}
.wifi {
width: 11px;
height: 8px;
border: 1.5px solid #333;
border-bottom: none;
border-left: none;
border-right: none;
border-radius: 9px 9px 0 0;
}
.battery {
width: 17px;
height: 9px;
border: 1px solid #333;
border-radius: 2px;
position: relative;
&::after {
content: "";
position: absolute;
inset: 1px;
right: 3px;
background: #333;
border-radius: 1px;
}
}
}
}
/* 导航栏 */
.p-nav {
position: relative;
height: 42px;
line-height: 42px;
text-align: center;
background: #fff;
flex-shrink: 0;
.p-title {
font-size: 14px;
font-weight: 500;
}
.p-back {
position: absolute;
left: 12px;
font-size: 20px;
color: #333;
line-height: 42px;
}
.p-capsule {
position: absolute;
right: 12px;
top: 9px;
height: 24px;
line-height: 24px;
padding: 0 12px;
border: 1px solid #ececec;
border-radius: 12px;
font-size: 11px;
color: #333;
letter-spacing: 1px;
}
}
.p-body {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.p-tabbar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
background: #fff;
border-top: 1px solid #f2f2f2;
flex-shrink: 0;
}
/* ===== 商品详情 ===== */
.g-img {
height: 240px;
background: linear-gradient(160deg, #f3ede7 0%, #e9ddd2 100%);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
.g-img-emoji {
font-size: 84px;
}
}
.g-seckill {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 14px;
color: #fff;
flex-shrink: 0;
.g-seckill-name {
font-size: 19px;
font-weight: bold;
font-style: italic;
}
.g-seckill-count {
font-size: 10px;
i {
font-style: normal;
background: rgba(255, 255, 255, 0.92);
color: #333;
border-radius: 3px;
padding: 1px 4px;
margin: 0 1px;
}
}
}
.g-main {
background: #fff;
flex: 1;
padding: 10px 14px;
}
.g-price-row {
display: flex;
align-items: baseline;
.g-price {
font-size: 20px;
font-weight: bold;
}
.g-price-origin {
font-size: 11px;
color: #bbb;
margin-left: 6px;
}
.g-fav {
margin-left: auto;
font-size: 11px;
color: #999; color: #999;
}
}
.g-progress {
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
.g-progress-text {
font-size: 10px;
color: #999;
white-space: nowrap;
}
.g-progress-track {
flex: 1;
height: 6px;
background: #f0f0f0;
border-radius: 3px;
overflow: hidden;
.g-progress-inner {
height: 100%;
border-radius: 3px;
}
}
}
.g-name {
margin-top: 8px;
font-size: 13px;
font-weight: 600;
line-height: 1.5;
}
.g-sub {
margin-top: 2px;
font-size: 11px;
color: #999;
}
.goods-bar .bar-icons {
display: flex;
gap: 14px;
.bar-icon {
display: flex;
flex-direction: column;
align-items: center;
gap: 1px;
span {
font-size: 9px;
color: #666;
}
}
}
.bar-btn {
flex: 1;
text-align: center;
font-size: 13px;
padding: 9px 0;
border-radius: 18px;
color: #fff;
&.outline {
border: 1px solid;
background: #fff;
}
}
/* ===== 规格弹层 ===== */
.sku-mask {
background: rgba(0, 0, 0, 0.45);
justify-content: flex-end;
}
.sku-popup {
position: relative;
background: #fff;
border-radius: 16px 16px 0 0;
padding: 14px;
}
.sku-close {
position: absolute;
right: 12px;
top: 10px;
color: #999;
font-size: 13px;
}
.sku-head {
display: flex;
gap: 10px;
.sku-price {
display: flex;
align-items: baseline;
}
.sku-tags {
margin-top: 5px;
}
}
.sku-thumb {
width: 64px;
height: 64px;
background: linear-gradient(160deg, #f3ede7 0%, #e9ddd2 100%);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
flex-shrink: 0;
}
.mini-tag {
display: inline-block;
font-size: 10px;
padding: 0 6px;
line-height: 17px;
border-radius: 3px;
border: 1px solid;
margin-right: 5px;
}
.sku-title {
font-size: 13px;
color: #333;
margin: 14px 0 8px;
}
.sku-list {
display: flex;
flex-wrap: wrap;
gap: 9px;
}
.sku-item {
font-size: 12px; font-size: 12px;
padding: 5px 14px;
border-radius: 15px;
background: #f5f6f8;
color: #333;
border: 1px solid transparent;
}
.sku-count {
display: flex;
justify-content: space-between;
align-items: center;
margin: 16px 0 14px;
font-size: 13px;
.sku-stock {
font-style: normal;
font-size: 11px;
color: #999;
margin-left: 6px;
}
.stepper {
color: #666;
i {
font-style: normal;
display: inline-block;
width: 20px;
text-align: center;
color: #999;
}
}
}
.sku-confirm {
text-align: center;
color: #fff;
border-radius: 20px;
padding: 11px 0;
font-size: 14px;
}
/* ===== 确认订单 ===== */
.order-body {
padding-bottom: 8px;
overflow: hidden;
}
.o-card {
background: #fff;
padding: 12px 14px;
margin: 8px 10px 0;
border-radius: 4px;
flex-shrink: 0;
}
.o-addr-card {
border-radius: 0;
margin: 0;
border-top: 3px solid transparent;
border-image: repeating-linear-gradient(90deg, #ff6b6b 0 16px, #fff 16px 24px, #4d7cfe 24px 40px, #fff 40px 48px) 3;
.o-addr-name {
font-size: 14px;
font-weight: bold;
}
.o-addr {
font-size: 12px;
color: #888;
margin-top: 4px;
}
}
.o-store {
font-size: 13px;
font-weight: bold;
display: flex;
align-items: center;
}
.o-reduce {
font-size: 11px;
color: #888;
margin-top: 6px;
display: flex;
align-items: center;
}
.o-goods {
display: flex;
gap: 8px;
margin: 10px 0;
align-items: center;
.sku-thumb {
width: 52px;
height: 52px;
font-size: 24px;
}
.o-goods-more {
margin-left: auto;
font-size: 12px;
color: #666;
}
}
.o-row {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #555;
padding: 6px 0;
.o-muted {
color: #aaa;
}
.o-amount {
font-weight: bold;
}
.o-coupon {
font-style: normal;
font-size: 10px;
margin-left: 4px;
}
}
.order-bar {
.o-total {
font-size: 13px;
i {
font-style: normal;
font-weight: bold;
font-size: 15px;
}
}
.bar-btn {
flex: none;
padding: 9px 22px;
}
} }
} }
</style> </style>

View File

@@ -11,7 +11,6 @@
</el-tabs> </el-tabs>
<div class="operation mb_10"> <div class="operation mb_10">
<el-button type="primary" @click="handleAdd()">添加页面</el-button> <el-button type="primary" @click="handleAdd()">添加页面</el-button>
<el-button @click="goThemeSetting">主题色设置</el-button>
</div> </div>
<el-table v-loading="loading" :data="list" style="width: 100%"> <el-table v-loading="loading" :data="list" style="width: 100%">
<el-table-column prop="name" label="页面名称" min-width="200" show-overflow-tooltip> <el-table-column prop="name" label="页面名称" min-width="200" show-overflow-tooltip>
@@ -163,9 +162,6 @@ export default {
query: { pagetype: this.params.pageType }, query: { pagetype: this.params.pageType },
}); });
}, },
goThemeSetting() {
this.$router.push({ name: "theme-setting" });
},
changePageSize(v) { changePageSize(v) {
this.params.pageNumber = 1; this.params.pageNumber = 1;
this.params.pageSize = v; this.params.pageSize = v;