mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-07 17:38:55 +08:00
refactor(decoration): 重构店铺装修组件配置并规范化环境变量
- 重构装修组件配置,新增 icon 与 group 分类字段 - 将组件"图片"重命名为"热区","图片轮播"重命名为"轮播图" - 新增搜索、公告、视频组件配置项 - 统一为各图片项添加 model 字段标识跳转模式 - 将装修页面组件间 pageGap 间距由 10 调整为 0 - 移除 im 模块中 VUE_APP_COMMON 变量,统一使用 VUE_APP_BUYER - 为 im 环境变量与配置文件添加详细注释说明
This commit is contained in:
@@ -114,7 +114,7 @@ const DEFAULTS = {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
contentGap: 0,
|
||||
borderRadius: 0,
|
||||
imgRadius: 0,
|
||||
|
||||
@@ -98,7 +98,7 @@ const DEFAULTS = {
|
||||
paddingBottom: 10,
|
||||
contentGap: 10,
|
||||
paddingX: 0,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
};
|
||||
const DEFAULT_ITEM = { title: "文章列表", categoryId: "", count: 6 };
|
||||
|
||||
@@ -37,7 +37,7 @@ const DEFAULTS = {
|
||||
bgColor2: "#f5f5f5",
|
||||
height: 10,
|
||||
paddingX: 0,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -89,7 +89,7 @@ const DEFAULTS = {
|
||||
paddingBottom: 10,
|
||||
contentGap: 5,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
};
|
||||
const DEFAULT_ITEM = { title: "优惠券", count: 5 };
|
||||
|
||||
@@ -108,7 +108,7 @@ const DEFAULTS = {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
imgRadius: 0,
|
||||
};
|
||||
|
||||
@@ -339,7 +339,7 @@ const DEFAULTS = {
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
contentGap: 10,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
contentRadius: 7,
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ const DEFAULTS = {
|
||||
lineStyle: "dashed",
|
||||
lineHeight: 1,
|
||||
paddingX: 0,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -179,7 +179,7 @@ const DEFAULTS = {
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
contentGap: 10,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
imgRadius: 30,
|
||||
};
|
||||
|
||||
@@ -164,7 +164,7 @@ const DEFAULTS = {
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
itemColor: "#333333",
|
||||
};
|
||||
|
||||
@@ -231,7 +231,7 @@ const DEFAULTS = {
|
||||
paddingBottom: 10,
|
||||
contentGap: 10,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
imgRadius: 10,
|
||||
showGoodsName: true,
|
||||
|
||||
@@ -58,7 +58,7 @@ const DEFAULTS = {
|
||||
bgColor1: "#FFFFFF",
|
||||
bgColor2: "#FFFFFF",
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
};
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ const DEFAULTS = {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingX: 0,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
imgRadius: 7,
|
||||
};
|
||||
|
||||
@@ -157,7 +157,7 @@ const DEFAULTS = {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
radiusTop: 0,
|
||||
radiusBottom: 0,
|
||||
color: "#282828",
|
||||
|
||||
@@ -115,7 +115,7 @@ const DEFAULTS = {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
imgRadius: 0,
|
||||
};
|
||||
|
||||
@@ -851,7 +851,7 @@ export const modelData = [
|
||||
bgColor: "#f5f5f5",
|
||||
height: 10,
|
||||
paddingX: 0,
|
||||
pageGap: 10
|
||||
pageGap: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -866,7 +866,7 @@ export const modelData = [
|
||||
lineStyle: "dashed",
|
||||
lineHeight: 1,
|
||||
paddingX: 0,
|
||||
pageGap: 10
|
||||
pageGap: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -879,7 +879,7 @@ export const modelData = [
|
||||
content: "",
|
||||
bgColor: "#FFFFFF",
|
||||
paddingX: 12,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0
|
||||
}
|
||||
},
|
||||
@@ -988,7 +988,7 @@ export const modelData = [
|
||||
list: [{ title: "文章列表", categoryId: "", count: 3 }],
|
||||
bgColor: "#FFFFFF",
|
||||
paddingX: 0,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0
|
||||
}
|
||||
},
|
||||
@@ -1002,7 +1002,7 @@ export const modelData = [
|
||||
list: [{ title: "店铺列表", count: 4 }],
|
||||
bgColor: "#FFFFFF",
|
||||
paddingX: 0,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0
|
||||
}
|
||||
},
|
||||
@@ -1044,7 +1044,7 @@ export const modelData = [
|
||||
paddingBottom: 10,
|
||||
paddingX: 12,
|
||||
contentGap: 10,
|
||||
pageGap: 10,
|
||||
pageGap: 0,
|
||||
borderRadius: 0,
|
||||
contentRadius: 7
|
||||
}
|
||||
|
||||
@@ -34,12 +34,13 @@
|
||||
<el-button size="default" type="primary" @click="handleSpinShow">保存页面</el-button>
|
||||
|
||||
<el-dialog
|
||||
title="保存中"
|
||||
:title="progress ? '保存页面' : '保存中'"
|
||||
v-model="saveDialog"
|
||||
:show-close="true"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@closed="handleDialogClosed"
|
||||
>
|
||||
<div v-if="progress">
|
||||
<div class="model-item">
|
||||
@@ -56,7 +57,7 @@
|
||||
</div>
|
||||
<div class="model-item">
|
||||
将当前装修内容写入到本地缓存中,下次进入页面时可继续使用
|
||||
<el-button type="small" @click="witeLocalStore">写入</el-button>
|
||||
<el-button size="small" @click="witeLocalStore">写入</el-button>
|
||||
</div>
|
||||
|
||||
<el-button type="primary" @click="save()">保存</el-button>
|
||||
@@ -84,7 +85,7 @@ const appStore = useAppStore();
|
||||
|
||||
const hasCache = ref(false); // 是否有缓存
|
||||
const progress = ref(true); // 展示进度
|
||||
const num = ref(20); // 提交进度
|
||||
const num = ref(0); // 提交进度
|
||||
const saveDialog = ref(false); // 加载状态
|
||||
const way = ref([
|
||||
// 装修tab栏切换
|
||||
@@ -119,10 +120,17 @@ function startEditName() {
|
||||
|
||||
const submitWay = reactive({
|
||||
// 表单信息
|
||||
pageShow: route.query.type || false,
|
||||
pageShow: route.query.type === "true" || route.query.type === true || route.query.type === "OPEN",
|
||||
pageClientType: "H5"
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.query.type,
|
||||
(val) => {
|
||||
submitWay.pageShow = val === "true" || val === true || val === "OPEN";
|
||||
}
|
||||
);
|
||||
|
||||
// 模板名称与「页面设置」面板共用 store 中的同一份数据,双向同步
|
||||
const pageName = computed({
|
||||
get() {
|
||||
@@ -191,9 +199,16 @@ function clickBtn(val) {
|
||||
* 加载,并保存模板
|
||||
*/
|
||||
function handleSpinShow() {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = true;
|
||||
}
|
||||
|
||||
function handleDialogClosed() {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
}
|
||||
|
||||
// 填写是否发布,模板名称之后保存
|
||||
function save() {
|
||||
// 楼层装修页面(非开屏/弹窗广告)需校验页面设置的必填项
|
||||
@@ -220,49 +235,57 @@ function save() {
|
||||
return false;
|
||||
}
|
||||
|
||||
submitWay?.pageShow === true
|
||||
? (submitWay.pageShow = "OPEN")
|
||||
: (submitWay.pageShow = "CLOSE");
|
||||
|
||||
submitWay.name = pageName.value;
|
||||
submitWay.pageData = JSON.stringify(appStore.styleStore);
|
||||
submitWay.pageType = "INDEX";
|
||||
submitWay.pageType = route.query.pagetype || "INDEX";
|
||||
// submitWay.pageType = props.pagetype;
|
||||
const payload = {
|
||||
...submitWay,
|
||||
pageShow: submitWay.pageShow ? "OPEN" : "CLOSE",
|
||||
name: pageName.value,
|
||||
pageData: JSON.stringify(appStore.styleStore),
|
||||
pageType: route.query.pagetype || "INDEX",
|
||||
};
|
||||
|
||||
if (route.query.pagetype == 'ALERT' || route.query.pagetype == 'OPEN_SCREEN_ANIMATION') {
|
||||
update(submitWay);
|
||||
update(payload);
|
||||
} else {
|
||||
route.query.id ? updateHome() : submit(submitWay);
|
||||
route.query.id ? updateHome(payload) : submit(payload);
|
||||
}
|
||||
|
||||
// route.query.id ? update() : submit(submitWay);
|
||||
}
|
||||
|
||||
// 更新
|
||||
function updateHome() {
|
||||
function updateHome(payload) {
|
||||
progress.value = false;
|
||||
API_Other.updateHome(route.query.id, {
|
||||
num.value = 20;
|
||||
const data = payload || {
|
||||
pageData: JSON.stringify(appStore.styleStore),
|
||||
name: pageName.value,
|
||||
pageShow: submitWay.pageShow,
|
||||
pageType: submitWay.pageType,
|
||||
pageShow: submitWay.pageShow ? "OPEN" : "CLOSE",
|
||||
pageType: submitWay.pageType || route.query.pagetype || "INDEX",
|
||||
pageClientType: "H5",
|
||||
})
|
||||
};
|
||||
API_Other.updateHome(route.query.id, data)
|
||||
.then(res => {
|
||||
num.value = 50;
|
||||
num.value = 60;
|
||||
if (res.success) {
|
||||
num.value = 80;
|
||||
num.value = 100;
|
||||
/**制作保存成功动画¸ */
|
||||
setTimeout(() => {
|
||||
saveDialog.value = false;
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
Message.success("修改成功");
|
||||
goBack();
|
||||
}, 1000);
|
||||
}, 800);
|
||||
} else {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = false;
|
||||
Message.error("修改失败,请稍后重试");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = false;
|
||||
Message.error("修改失败,请稍后重试");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -274,6 +297,7 @@ function update(submitWay) {
|
||||
return false;
|
||||
}
|
||||
progress.value = false;
|
||||
num.value = 20;
|
||||
|
||||
let id = route.query.id;
|
||||
const pagetype = route.query.pagetype;
|
||||
@@ -283,29 +307,40 @@ function update(submitWay) {
|
||||
OPEN_SCREEN_ANIMATION: "OPEN_SCREEN_ANIMATION",
|
||||
}[pagetype ? pagetype : "INDEX"];
|
||||
|
||||
const payload = { ...submitWay };
|
||||
if (pagetype) {
|
||||
submitWay.pageData = JSON.stringify(
|
||||
payload.pageData = JSON.stringify(
|
||||
appStore.openStyleStore[0]
|
||||
);
|
||||
submitWay.pageType = pageType;
|
||||
payload.pageType = pageType;
|
||||
id = appStore.openStoreId;
|
||||
}
|
||||
|
||||
API_Other.updateHome(id, submitWay)
|
||||
API_Other.updateHome(id, payload)
|
||||
.then((res) => {
|
||||
num.value = 50;
|
||||
num.value = 60;
|
||||
if (res.success) {
|
||||
num.value = 80;
|
||||
num.value = 100;
|
||||
/**制作保存成功动画¸ */
|
||||
setTimeout(() => {
|
||||
saveDialog.value = false;
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
Message.success("修改成功");
|
||||
goBack();
|
||||
}, 1000);
|
||||
}, 800);
|
||||
} else {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = false;
|
||||
Message.error("修改失败,请稍后重试");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = false;
|
||||
Message.error("修改失败,请稍后重试");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -313,28 +348,42 @@ function update(submitWay) {
|
||||
|
||||
// 返回查询数据页面
|
||||
function goBack() {
|
||||
router.go(-1);
|
||||
if (window.history.state?.back) {
|
||||
router.go(-1);
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
// 保存
|
||||
function submit(submitWay) {
|
||||
progress.value = false;
|
||||
num.value = 20;
|
||||
API_Other.setHomeSetup(submitWay)
|
||||
.then(res => {
|
||||
num.value = 50;
|
||||
num.value = 60;
|
||||
if (res.success) {
|
||||
num.value = 80;
|
||||
num.value = 100;
|
||||
/**制作保存成功动画¸ */
|
||||
setTimeout(() => {
|
||||
saveDialog.value = false;
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
Message.success("保存成功");
|
||||
goBack();
|
||||
}, 1000);
|
||||
}, 800);
|
||||
} else {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = false;
|
||||
Message.error("保存失败,请稍后重试");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
progress.value = true;
|
||||
num.value = 0;
|
||||
saveDialog.value = false;
|
||||
Message.error("保存失败,请稍后重试");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
.layout {
|
||||
padding: 8px;
|
||||
margin: 4px 0;
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
}
|
||||
.layout,
|
||||
|
||||
@@ -58,7 +58,7 @@ export default {
|
||||
return {
|
||||
background: this.res.bgColor || "#FFFFFF",
|
||||
padding: `10px ${this.res.paddingX || 0}px`,
|
||||
marginBottom: `${this.res.pageGap !== undefined ? this.res.pageGap : 10}px`,
|
||||
marginBottom: `${this.res.pageGap !== undefined ? this.res.pageGap : 0}px`,
|
||||
borderRadius: `${this.res.borderRadius || 0}px`,
|
||||
overflow: "hidden",
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:style="{
|
||||
background: blankBg,
|
||||
height: px(res.height ?? 10),
|
||||
margin: `0 ${px(res.paddingX ?? 0)} ${px(res.pageGap ?? 10)}`,
|
||||
margin: `0 ${px(res.paddingX ?? 0)} ${px(res.pageGap ?? 0)}`,
|
||||
}"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
@@ -145,7 +145,7 @@ export default {
|
||||
return {
|
||||
background: this.res.bgColor || "#FFFFFF",
|
||||
padding: `10px ${this.res.paddingX || 0}px`,
|
||||
marginBottom: `${this.res.pageGap !== undefined ? this.res.pageGap : 10}px`,
|
||||
marginBottom: `${this.res.pageGap !== undefined ? this.res.pageGap : 0}px`,
|
||||
borderRadius: `${this.res.borderRadius || 0}px`,
|
||||
overflow: "hidden",
|
||||
};
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
/>
|
||||
<div v-else class="integral-head-title" :style="headTitleStyle">{{ title }}</div>
|
||||
<div class="integral-head-space"></div>
|
||||
<div class="integral-head-more" :style="moreStyle">更多 ></div>
|
||||
<div class="integral-head-more" :style="moreStyle">更多 ></div>
|
||||
</div>
|
||||
<!-- 老数据:原始四列样式 -->
|
||||
<div v-if="!styled" class="join-box">
|
||||
<div class="join-item" v-for="item in 4" :key="item">
|
||||
<div class="join-item" v-for="item in count" :key="item">
|
||||
<div class="item-img-box">
|
||||
<img
|
||||
class="item-img"
|
||||
@@ -71,6 +71,45 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
const INTEGRAL_DEMO = [
|
||||
{
|
||||
goodsName: "小米小爱音箱 Play 增强版 智能红外遥控",
|
||||
points: 1200,
|
||||
originalPrice: 149,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "Apple 20W USB-C 官方原装快充充电器",
|
||||
points: 1500,
|
||||
originalPrice: 149,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "米家自动洗手机 套装 抑菌洗手液",
|
||||
points: 800,
|
||||
originalPrice: 79,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "多功能桌面风扇 超长续航三档风力",
|
||||
points: 600,
|
||||
originalPrice: 59,
|
||||
thumbnail: "/demo/vivo-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "精品保温杯 316不锈钢 480ml",
|
||||
points: 990,
|
||||
originalPrice: 99,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "无线双模鼠标 2.4G+蓝牙 轻音便携",
|
||||
points: 750,
|
||||
originalPrice: 69,
|
||||
thumbnail: "/demo/vivo-phone.png",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
const props = defineProps(["res"]);
|
||||
|
||||
@@ -79,9 +118,27 @@ const title = computed(
|
||||
);
|
||||
const firstItem = computed(() => (props.res.list && props.res.list[0]) || {});
|
||||
const layoutStyle = computed(() => props.res.layoutStyle || "1");
|
||||
const count = computed(() => {
|
||||
const c = firstItem.value?.count ?? props.res?.count;
|
||||
if (c !== undefined && c !== null && !isNaN(Number(c)) && Number(c) > 0) {
|
||||
return Number(c);
|
||||
}
|
||||
return layoutStyle.value === "1" ? 4 : 6;
|
||||
});
|
||||
|
||||
const displayData = computed(() => {
|
||||
const data = (firstItem.value && firstItem.value.data) || [];
|
||||
return layoutStyle.value === "1" ? data.slice(0, 4) : data.slice(0, 6);
|
||||
const raw = (firstItem.value && firstItem.value.data) || [];
|
||||
const data = raw.length ? raw : INTEGRAL_DEMO;
|
||||
const targetCount = count.value;
|
||||
if (data.length >= targetCount) {
|
||||
return data.slice(0, targetCount);
|
||||
}
|
||||
// 如果设置的数量大于现有模拟数据长度,循环补齐,使预览数量与配置数量严格一致
|
||||
const result = [...data];
|
||||
while (result.length < targetCount) {
|
||||
result.push({ ...data[result.length % data.length] });
|
||||
}
|
||||
return result.slice(0, targetCount);
|
||||
});
|
||||
|
||||
// 面板保存过样式字段才启用新样式,老数据保持原样
|
||||
@@ -94,7 +151,7 @@ const wrapperStyle = computed(() => {
|
||||
return {
|
||||
background: res.bgColor || "#FFFFFF",
|
||||
padding: `0 ${res.paddingX || 0}px`,
|
||||
marginBottom: `${res.pageGap !== undefined ? res.pageGap : 10}px`,
|
||||
marginBottom: `${res.pageGap !== undefined ? res.pageGap : 0}px`,
|
||||
borderRadius: `${res.borderRadius || 0}px`,
|
||||
overflow: "hidden",
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:style="{
|
||||
background: lineBg,
|
||||
padding: `0 ${px(res.paddingX ?? 0)}`,
|
||||
marginBottom: px(res.pageGap ?? 10),
|
||||
marginBottom: px(res.pageGap ?? 0),
|
||||
}"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<span class="pt-success">{{ firstItem.groupSuccess }}</span>
|
||||
</template>
|
||||
<span class="pt-space"></span>
|
||||
<span class="pt-more" :style="moreStyle">更多 ></span>
|
||||
<span class="pt-more" :style="moreStyle">更多 ></span>
|
||||
</div>
|
||||
<div class="pt-body">
|
||||
<!-- 样式一:纵向商品行 -->
|
||||
@@ -154,7 +154,7 @@
|
||||
<span v-else class="lv-head-title">{{ firstItem.title || "精彩直播" }}</span>
|
||||
<span class="lv-head-sub" :style="titleStyle">{{ firstItem.title1 || "精彩抢先看" }}</span>
|
||||
<span class="lv-space"></span>
|
||||
<span class="lv-more" :style="moreStyle">更多 ></span>
|
||||
<span class="lv-more" :style="moreStyle">更多 ></span>
|
||||
</div>
|
||||
<div class="lv-head-en">Exciting live streaming</div>
|
||||
<!-- 单行:横向滑动卡片 -->
|
||||
@@ -201,7 +201,7 @@
|
||||
<span class="sk-divider"></span>
|
||||
<span class="sk-head-sub" :style="titleStyle">{{ firstItem.title1 || "邀请你的好友来参与" }}</span>
|
||||
<span class="sk-space"></span>
|
||||
<span class="sk-go">GO ></span>
|
||||
<span class="sk-go">GO ></span>
|
||||
</div>
|
||||
<!-- 样式一:横向滑动 -->
|
||||
<div v-if="layoutStyle === '1'" class="sk-scroll" :style="gapStyle">
|
||||
@@ -246,7 +246,7 @@
|
||||
<span class="sk-divider"></span>
|
||||
<span class="sk-head-sub" :style="titleStyle">{{ firstItem.title1 || "邀请好友来砍价" }}</span>
|
||||
<span class="sk-space"></span>
|
||||
<span class="sk-go">GO ></span>
|
||||
<span class="sk-go">GO ></span>
|
||||
</div>
|
||||
<!-- 样式一:横向滑动 -->
|
||||
<div v-if="layoutStyle === '1'" class="sk-scroll" :style="gapStyle">
|
||||
@@ -287,7 +287,7 @@
|
||||
<div v-if="styled && (res.icon || res.moreUrl)" class="promo-head">
|
||||
<img v-if="res.icon" class="promo-head-icon" :src="res.icon" alt="" />
|
||||
<div class="promo-head-space"></div>
|
||||
<div v-if="res.moreUrl" class="promo-more" :style="moreStyle">更多 ></div>
|
||||
<div v-if="res.moreUrl" class="promo-more" :style="moreStyle">更多 ></div>
|
||||
</div>
|
||||
<div class="join-list" :style="gapStyle">
|
||||
<div
|
||||
@@ -343,6 +343,155 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
const SECKILL_DEMO = [
|
||||
{
|
||||
goodsName: "iPhone 16 Pro 256GB 黑色钛金属",
|
||||
price: 6999,
|
||||
originalPrice: 8999,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "Xiaomi 15 Pro 16GB+512GB 沉墨色",
|
||||
price: 4699,
|
||||
originalPrice: 5299,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "vivo X200 Pro 16GB+512GB 钛色",
|
||||
price: 4899,
|
||||
originalPrice: 5499,
|
||||
thumbnail: "/demo/vivo-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "Apple Watch Series 10 46mm GPS款",
|
||||
price: 2699,
|
||||
originalPrice: 3199,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "AirPods Pro (第二代) 配USB-C充电盒",
|
||||
price: 1399,
|
||||
originalPrice: 1899,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "Xiaomi 平板 6S Pro 12.4英寸",
|
||||
price: 2799,
|
||||
originalPrice: 3299,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
},
|
||||
];
|
||||
|
||||
const PINTUAN_DEMO = [
|
||||
{
|
||||
goodsName: "iPhone 16 Pro 5G智能手机 256GB 白色钛金属",
|
||||
price: 7999,
|
||||
originalPrice: 8999,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
groupNum: 2,
|
||||
joined: 128,
|
||||
},
|
||||
{
|
||||
goodsName: "Xiaomi 15 5G智能手机 12GB+256GB 白色",
|
||||
price: 3699,
|
||||
originalPrice: 4299,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
groupNum: 2,
|
||||
joined: 256,
|
||||
},
|
||||
{
|
||||
goodsName: "vivo X200 5G智能手机 12GB+256GB 宝石蓝",
|
||||
price: 3999,
|
||||
originalPrice: 4599,
|
||||
thumbnail: "/demo/vivo-phone.png",
|
||||
groupNum: 3,
|
||||
joined: 89,
|
||||
},
|
||||
{
|
||||
goodsName: "Apple AirPods 4 主动降噪无线耳机",
|
||||
price: 1099,
|
||||
originalPrice: 1399,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
groupNum: 2,
|
||||
joined: 412,
|
||||
},
|
||||
{
|
||||
goodsName: "小米手环 9 Pro 晨曦金 金属机身",
|
||||
price: 349,
|
||||
originalPrice: 399,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
groupNum: 2,
|
||||
joined: 680,
|
||||
},
|
||||
{
|
||||
goodsName: "vivo Pad3 Pro 13英寸 3.1K 超清大屏",
|
||||
price: 2999,
|
||||
originalPrice: 3399,
|
||||
thumbnail: "/demo/vivo-phone.png",
|
||||
groupNum: 2,
|
||||
joined: 195,
|
||||
},
|
||||
];
|
||||
|
||||
const KANJIA_DEMO = [
|
||||
{
|
||||
goodsName: "米家智能空气炸锅 6.5L 嫩烤大容量",
|
||||
purchasePrice: 0,
|
||||
price: 0,
|
||||
originalPrice: 299,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "电动声波牙刷 T300 高频震动洁齿",
|
||||
purchasePrice: 0,
|
||||
price: 0,
|
||||
originalPrice: 129,
|
||||
thumbnail: "/demo/vivo-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "小米随身手持小风扇 大风力轻便便携",
|
||||
purchasePrice: 0,
|
||||
price: 0,
|
||||
originalPrice: 59,
|
||||
thumbnail: "/demo/xiaomi-phone.png",
|
||||
},
|
||||
{
|
||||
goodsName: "智能温湿度计 电子墨水屏高精度",
|
||||
purchasePrice: 0,
|
||||
price: 0,
|
||||
originalPrice: 69,
|
||||
thumbnail: "/demo/apple-phone.png",
|
||||
},
|
||||
];
|
||||
|
||||
const LIVE_DEMO = [
|
||||
{
|
||||
cover: "/demo/apple-phone.png",
|
||||
title: "双11新品首发专场 抢先看",
|
||||
anchorName: "官方品牌主播",
|
||||
status: "LIVE",
|
||||
tagText: "直播中",
|
||||
tagClass: "lv-tag-live",
|
||||
},
|
||||
{
|
||||
cover: "/demo/xiaomi-phone.png",
|
||||
title: "米粉狂欢日 爆款好物直降",
|
||||
anchorName: "好物推荐官",
|
||||
status: "PREVIEW",
|
||||
startTime: "10/22 19:00",
|
||||
tagText: "预告",
|
||||
tagClass: "lv-tag-preview",
|
||||
},
|
||||
{
|
||||
cover: "/demo/vivo-phone.png",
|
||||
title: "旗舰影像新机实测现场",
|
||||
anchorName: "数码达人",
|
||||
status: "REPLAY",
|
||||
tagText: "回放",
|
||||
tagClass: "lv-tag-replay",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
const props = defineProps(["res"]);
|
||||
|
||||
@@ -354,7 +503,8 @@ const isLive = computed(() => firstItem.value.type === "LIVE");
|
||||
const isSeckill = computed(() => firstItem.value.type === "SECKILL");
|
||||
const isKanjia = computed(() => firstItem.value.type === "KANJIA");
|
||||
const seckillData = computed(() => {
|
||||
const data = (firstItem.value && firstItem.value.data) || [];
|
||||
const raw = (firstItem.value && firstItem.value.data) || [];
|
||||
const data = raw.length ? raw : (isKanjia.value ? KANJIA_DEMO : SECKILL_DEMO);
|
||||
return layoutStyle.value === "2" ? data.slice(0, 4) : data.slice(0, 6);
|
||||
});
|
||||
// 老数据未保存过样式时,给个红→白渐变兜底背景
|
||||
@@ -382,9 +532,12 @@ const fmtLiveTime = (t) => {
|
||||
return s;
|
||||
};
|
||||
const liveData = computed(() => {
|
||||
const data = (firstItem.value && firstItem.value.data) || [];
|
||||
const raw = (firstItem.value && firstItem.value.data) || [];
|
||||
if (!raw.length) {
|
||||
return LIVE_DEMO;
|
||||
}
|
||||
const limit = layoutStyle.value === "2" ? 3 : 6;
|
||||
return data.slice(0, limit).map((item) => {
|
||||
return raw.slice(0, limit).map((item) => {
|
||||
const tag = liveTagOf(item.status != null ? item.status : item.liveStatus);
|
||||
return {
|
||||
cover: item.cover || item.roomImg || item.shareImg || item.thumbnail || "",
|
||||
@@ -398,11 +551,12 @@ const liveData = computed(() => {
|
||||
});
|
||||
});
|
||||
const displayData = computed(() => {
|
||||
const data = (firstItem.value && firstItem.value.data) || [];
|
||||
const raw = (firstItem.value && firstItem.value.data) || [];
|
||||
const data = raw.length ? raw : PINTUAN_DEMO;
|
||||
if (layoutStyle.value === "3" || layoutStyle.value === "4") {
|
||||
return data.slice(0, 6);
|
||||
}
|
||||
return data.slice(0, 2);
|
||||
return data.slice(0, 4);
|
||||
});
|
||||
const headTitleImage = computed(() =>
|
||||
props.res.headTitleType === "image" ? props.res.headTitleImage : ""
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:style="{
|
||||
background: richBg,
|
||||
padding: `0 ${px(res.paddingX ?? 12)}`,
|
||||
marginBottom: px(res.pageGap ?? 10),
|
||||
marginBottom: px(res.pageGap ?? 0),
|
||||
borderRadius: px(res.borderRadius ?? 0),
|
||||
overflow: 'hidden',
|
||||
}"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="shop-head" v-if="headIcon || title || hasMore">
|
||||
<img v-if="headIcon" class="shop-head-icon" :src="headIcon" alt="" />
|
||||
<div class="shop-title" :style="titleStyle">{{ title }}</div>
|
||||
<div v-if="hasMore" class="shop-more" :style="moreStyle">更多 ></div>
|
||||
<div v-if="hasMore" class="shop-more" :style="moreStyle">更多 ></div>
|
||||
</div>
|
||||
|
||||
<!-- 老数据:两列网格 -->
|
||||
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 样式一:店铺卡片三列 -->
|
||||
<!-- 样式一:店铺卡片三列(全景大片橱窗) -->
|
||||
<div v-else-if="shopStyle === 'one'" class="shop-grid">
|
||||
<div class="shop-card" v-for="(shop, i) in previewShops" :key="i">
|
||||
<img
|
||||
@@ -25,6 +25,7 @@
|
||||
alt=""
|
||||
/>
|
||||
<div v-else class="shop-card-bg shop-card-bg-empty" :style="logoStyle"></div>
|
||||
<div class="shop-card-badge" v-if="isSelf(shop)">自营</div>
|
||||
<div class="shop-card-body">
|
||||
<img v-if="showLogo" class="shop-card-logo" :src="shop.logo" alt="" />
|
||||
<div v-if="showName" class="shop-card-name" :style="nameStyle">{{ shop.name }}</div>
|
||||
@@ -32,19 +33,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 样式二:店铺卡片 + 商品列表 -->
|
||||
<!-- 样式二:店铺卡片 + 商品列表(大牌名店街 + 精品橱窗) -->
|
||||
<div v-else class="shop-street-list">
|
||||
<div class="shop-street-card" v-for="(shop, i) in previewShops" :key="i">
|
||||
<div class="shop-street-head">
|
||||
<img v-if="showLogo" class="shop-street-logo" :src="shop.logo" alt="" />
|
||||
<div v-if="showName" class="shop-street-name" :style="nameStyle">{{ shop.name }}</div>
|
||||
<img
|
||||
v-if="shop.goodsImage"
|
||||
class="shop-street-banner"
|
||||
:style="logoStyle"
|
||||
:src="shop.goodsImage"
|
||||
alt=""
|
||||
/>
|
||||
<div class="shop-street-info">
|
||||
<img v-if="showLogo" class="shop-street-logo" :src="shop.logo" alt="" />
|
||||
<div class="shop-street-meta">
|
||||
<div class="shop-street-name-row">
|
||||
<div v-if="showName" class="shop-street-name" :style="nameStyle">{{ shop.name }}</div>
|
||||
<span class="shop-street-tag" v-if="isSelf(shop)">自营</span>
|
||||
</div>
|
||||
<div class="shop-street-desc">热卖好物甄选中</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shop-street-enter">进店逛逛 ></div>
|
||||
</div>
|
||||
<div class="shop-street-goods">
|
||||
<div
|
||||
@@ -52,9 +55,13 @@
|
||||
v-for="(goods, goodsIndex) in shop.goods"
|
||||
:key="goodsIndex"
|
||||
>
|
||||
<img class="street-goods-img" :src="goods.img" alt="" />
|
||||
<div class="street-goods-cover">
|
||||
<img class="street-goods-img" :src="goods.img" alt="" />
|
||||
</div>
|
||||
<div class="street-goods-name">{{ goods.name }}</div>
|
||||
<div class="street-goods-price">¥{{ $filters.unitPrice(goods.price) }}</div>
|
||||
<div class="street-goods-price">
|
||||
<span class="street-goods-symbol">¥</span>{{ $filters.unitPrice(goods.price) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,8 +145,9 @@ export default {
|
||||
id: s.id,
|
||||
name: s.storeName,
|
||||
logo: s.storeLogo,
|
||||
selfOperated: s.selfOperated,
|
||||
goods,
|
||||
goodsImage: goods[0]?.img || s.goodsImage || s.storeBanner || "",
|
||||
goodsImage: goods[0]?.img || s.goodsImage || s.storeBanner || s.storeLogo || "",
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -174,7 +182,7 @@ export default {
|
||||
return {
|
||||
background: this.res.bgColor || "#FFFFFF",
|
||||
padding: `10px ${this.res.paddingX || 0}px`,
|
||||
marginBottom: `${this.res.pageGap !== undefined ? this.res.pageGap : 10}px`,
|
||||
marginBottom: `${this.res.pageGap !== undefined ? this.res.pageGap : 0}px`,
|
||||
borderRadius: `${this.res.borderRadius || 0}px`,
|
||||
overflow: "hidden",
|
||||
};
|
||||
@@ -205,6 +213,17 @@ export default {
|
||||
this.loadGoodsImages();
|
||||
},
|
||||
methods: {
|
||||
isSelf(shop) {
|
||||
if (!shop) return false;
|
||||
return Boolean(
|
||||
shop.selfOperated === true ||
|
||||
shop.selfOperated === 'true' ||
|
||||
shop.selfOperated === 1 ||
|
||||
shop.selfOperated === '1' ||
|
||||
(shop.name && shop.name.includes('自营')) ||
|
||||
(shop.storeName && shop.storeName.includes('自营'))
|
||||
);
|
||||
},
|
||||
loadGoodsImages() {
|
||||
if (this.first.dataMode !== "custom") return;
|
||||
(this.first.shopList || []).forEach((shop) => {
|
||||
@@ -282,132 +301,213 @@ export default {
|
||||
color: #333;
|
||||
margin-left: 8px;
|
||||
}
|
||||
/* 样式一 */
|
||||
/* 样式一:全景大片橱窗 */
|
||||
.shop-grid {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.shop-card {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
border-radius: 6px;
|
||||
height: 112px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #f7f7f7;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.shop-card-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
background: #eee;
|
||||
}
|
||||
.shop-card-bg-empty {
|
||||
background: linear-gradient(135deg, #f5f5f5, #e8e8e8);
|
||||
}
|
||||
.shop-card-badge {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
z-index: 2;
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
background: #e1251b;
|
||||
padding: 1px 5px;
|
||||
border-radius: 4px;
|
||||
line-height: 1.3;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.shop-card-body {
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
padding: 16px 6px 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.25) 35%, rgba(0, 0, 0, 0.72) 100%);
|
||||
}
|
||||
.shop-card-logo {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
display: block;
|
||||
width: 60px;
|
||||
height: 24px;
|
||||
margin: -12px auto 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
object-fit: contain;
|
||||
background: #fff;
|
||||
padding: 1px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.shop-card-name {
|
||||
font-size: 12px;
|
||||
margin-top: 3px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
/* 样式二:店铺卡片 + 商品列表 */
|
||||
|
||||
/* 样式二:大牌名店街 + 精品橱窗 */
|
||||
.shop-street-list {
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
gap: 10px;
|
||||
}
|
||||
.shop-street-card {
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
background: #f7f7f7;
|
||||
background: #fbfbfb;
|
||||
border: 1px solid #f0f0f0;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
.shop-street-head {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 34px;
|
||||
padding: 0 8px;
|
||||
box-sizing: border-box;
|
||||
background: $theme_color;
|
||||
overflow: hidden;
|
||||
justify-content: space-between;
|
||||
padding: 8px 10px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
.shop-street-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.shop-street-logo {
|
||||
flex-shrink: 0;
|
||||
width: 44px;
|
||||
height: 16px;
|
||||
padding: 1px 3px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 2px;
|
||||
box-sizing: border-box;
|
||||
object-fit: contain;
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #eee;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.shop-street-meta {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.shop-street-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.shop-street-name {
|
||||
max-width: calc(100% - 110px);
|
||||
margin-left: 6px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.shop-street-banner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 80px;
|
||||
height: 34px;
|
||||
object-fit: cover;
|
||||
.shop-street-tag {
|
||||
flex-shrink: 0;
|
||||
font-size: 9px;
|
||||
color: #fff;
|
||||
background: #e1251b;
|
||||
padding: 0 4px;
|
||||
border-radius: 3px;
|
||||
line-height: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.shop-street-desc {
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.shop-street-enter {
|
||||
flex-shrink: 0;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
color: $theme_color;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(255, 60, 42, 0.25);
|
||||
padding: 3px 8px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 2px rgba(255, 60, 42, 0.05);
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.shop-street-goods {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
padding: 6px;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.street-goods-item {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
border-radius: 4px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
border: 1px solid #f2f2f2;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.street-goods-cover {
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
overflow: hidden;
|
||||
background: #fafafa;
|
||||
}
|
||||
.street-goods-img {
|
||||
width: 100%;
|
||||
height: 58px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
background: #eee;
|
||||
}
|
||||
.street-goods-name {
|
||||
padding: 4px 4px 0;
|
||||
color: #282828;
|
||||
padding: 4px 6px 0;
|
||||
color: #333;
|
||||
font-size: 11px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.street-goods-price {
|
||||
padding: 2px 4px 5px;
|
||||
padding: 2px 6px 6px;
|
||||
color: $theme_color;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.street-goods-symbol {
|
||||
font-size: 9px;
|
||||
font-weight: normal;
|
||||
margin-right: 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<span class="title-sub" :style="subStyle" v-if="item.title1">{{ item.title1 }}</span>
|
||||
</div>
|
||||
<div v-if="item.showMore" class="title-more" :style="moreStyle">
|
||||
{{ item.moreText || "更多" }} >
|
||||
{{ item.moreText || "更多" }} >
|
||||
</div>
|
||||
</div>
|
||||
<!-- 老数据:保持原样 -->
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
{{ formatTime(row.createTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="修改时间" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(row.updateTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<el-form ref="formValidateRef" label-width="200px" label-position="right" :model="formValidate" :rules="ruleValidate">
|
||||
<el-form-item label="数据脱敏级别" prop="sensitiveLevel">
|
||||
<el-radio-group v-model="formValidate.sensitiveLevel">
|
||||
<el-radio :value="0">不做脱敏</el-radio>
|
||||
<el-radio :value="1">管理端脱敏</el-radio>
|
||||
<el-radio :value="2">全端脱敏</el-radio>
|
||||
</el-radio-group>
|
||||
<span class="desc">控制手机号、收货地址、身份证等敏感信息脱敏显示策略</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="演示站点保护" prop="isDemoSite">
|
||||
<el-switch v-model="formValidate.isDemoSite" active-text="开启" inactive-text="关闭" />
|
||||
<span class="desc">开启后拦截核心管理端修改与删除请求,防止演示数据被篡改</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="买家端Token有效期" prop="buyerTokenExpireTime">
|
||||
<el-input type="number" v-model="formValidate.buyerTokenExpireTime">
|
||||
<template #append>分钟</template>
|
||||
</el-input>
|
||||
<span class="desc">买家免密登录会话有效时长</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="管理/商家端Token有效期" prop="managerTokenExpireTime">
|
||||
<el-input type="number" v-model="formValidate.managerTokenExpireTime">
|
||||
<template #append>分钟</template>
|
||||
</el-input>
|
||||
<span class="desc">管理后台及店铺端操作人员会话有效时长</span>
|
||||
</el-form-item>
|
||||
|
||||
<div class="label-btns" style="margin-left: 200px;">
|
||||
<el-button type="primary" @click="submit('formValidateRef')">保存设置</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCurrentInstance, reactive, ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { setSetting } from "@/api/index";
|
||||
import { handleSubmit } from "./validate";
|
||||
|
||||
const props = defineProps(["res", "type"]);
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const formValidate = ref({
|
||||
sensitiveLevel: 1,
|
||||
isDemoSite: false,
|
||||
buyerTokenExpireTime: 259200,
|
||||
managerTokenExpireTime: 86400,
|
||||
});
|
||||
|
||||
const ruleValidate = reactive({
|
||||
buyerTokenExpireTime: [
|
||||
{ required: true, message: "请输入买家端Token有效时间", trigger: "blur" }
|
||||
],
|
||||
managerTokenExpireTime: [
|
||||
{ required: true, message: "请输入管理端Token有效时间", trigger: "blur" }
|
||||
],
|
||||
});
|
||||
|
||||
function submit(name) {
|
||||
handleSubmit(proxy, name)
|
||||
.then(() => {
|
||||
setupSetting();
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function setupSetting() {
|
||||
setSetting(props.type, formValidate.value).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("保存成功!");
|
||||
} else {
|
||||
ElMessage.error(res.message || "保存失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (props.res) {
|
||||
try {
|
||||
const parsed = typeof props.res === "string" ? JSON.parse(props.res) : props.res;
|
||||
formValidate.value = {
|
||||
sensitiveLevel: Number(parsed.sensitiveLevel ?? 1),
|
||||
isDemoSite: Boolean(parsed.isDemoSite ?? false),
|
||||
buyerTokenExpireTime: Number(parsed.buyerTokenExpireTime ?? 259200),
|
||||
managerTokenExpireTime: Number(parsed.managerTokenExpireTime ?? 86400),
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("解析安全设置失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./style.scss";
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.el-radio-group {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin-left: 12px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<el-form ref="formValidateRef" label-width="160px" label-position="right" :model="formValidate" :rules="ruleValidate">
|
||||
<el-form-item label="有效时间(秒)" prop="effectiveTime">
|
||||
<el-input-number v-model="formValidate.effectiveTime" :min="30" :max="3600" />
|
||||
<span class="desc">包含滑块生成及校验结果缓存的有效时间(秒)</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="水印文字" prop="watermark">
|
||||
<el-input class="label-appkey" v-model="formValidate.watermark" placeholder="例如: LILI-SHOP" />
|
||||
<span class="desc">滑块背景图水印文本</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="干扰块数量" prop="interfereNum">
|
||||
<el-input-number v-model="formValidate.interfereNum" :min="0" :max="2" />
|
||||
<span class="desc">滑块干扰块数量,最大为 2</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="容错像素" prop="faultTolerant">
|
||||
<el-input-number v-model="formValidate.faultTolerant" :min="0" :max="20" />
|
||||
<span class="desc">滑块比对横坐标容错像素范围</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="登录免验证码" prop="loginBypassEnabled">
|
||||
<el-switch v-model="formValidate.loginBypassEnabled" active-text="开启" inactive-text="关闭" />
|
||||
<span class="desc">开启后登录流程跳过滑块校验,仅建议本地或测试验收环境开启</span>
|
||||
</el-form-item>
|
||||
|
||||
<div class="label-btns">
|
||||
<el-button type="primary" @click="submit('formValidateRef')">保存</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCurrentInstance, reactive, ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { setSetting } from "@/api/index";
|
||||
import { handleSubmit } from "./validate";
|
||||
|
||||
const props = defineProps(["res", "type"]);
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const formValidate = ref({
|
||||
effectiveTime: 300,
|
||||
watermark: "LILI-SHOP",
|
||||
interfereNum: 0,
|
||||
faultTolerant: 3,
|
||||
loginBypassEnabled: false,
|
||||
});
|
||||
|
||||
const ruleValidate = reactive({
|
||||
effectiveTime: [
|
||||
{ required: true, message: "请输入有效时间", trigger: "blur" }
|
||||
],
|
||||
watermark: [
|
||||
{ required: true, message: "请输入水印文字", trigger: "blur" }
|
||||
],
|
||||
interfereNum: [
|
||||
{ required: true, message: "请输入干扰块数量", trigger: "blur" }
|
||||
],
|
||||
faultTolerant: [
|
||||
{ required: true, message: "请输入容错像素", trigger: "blur" }
|
||||
],
|
||||
});
|
||||
|
||||
function submit(name) {
|
||||
handleSubmit(proxy, name)
|
||||
.then(() => {
|
||||
setupSetting();
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function setupSetting() {
|
||||
setSetting(props.type, formValidate.value).then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("保存成功!");
|
||||
} else {
|
||||
ElMessage.error(res.message || "保存失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (props.res) {
|
||||
try {
|
||||
const parsed = typeof props.res === "string" ? JSON.parse(props.res) : props.res;
|
||||
formValidate.value = {
|
||||
effectiveTime: Number(parsed.effectiveTime ?? 300),
|
||||
watermark: String(parsed.watermark ?? "LILI-SHOP"),
|
||||
interfereNum: Number(parsed.interfereNum ?? 0),
|
||||
faultTolerant: Number(parsed.faultTolerant ?? 3),
|
||||
loginBypassEnabled: Boolean(parsed.loginBypassEnabled ?? false),
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("解析验证码设置失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./style.scss";
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@@ -75,6 +75,14 @@ const setting = ref([
|
||||
type: "LIVE_SETTING",
|
||||
name: "直播设置",
|
||||
},
|
||||
{
|
||||
type: "VERIFICATION_SETTING",
|
||||
name: "验证码设置",
|
||||
},
|
||||
{
|
||||
type: "SECURITY_SETTING",
|
||||
name: "安全设置",
|
||||
},
|
||||
]);
|
||||
const authLogin = ref([
|
||||
// 登录设置
|
||||
|
||||
@@ -9,6 +9,8 @@ import SMS_SETTING from "./setting/SMS_SETTING";
|
||||
import IM_SETTING from "./setting/IM_SETTING";
|
||||
import LIVE_SETTING from "./setting/LIVE_SETTING";
|
||||
import WITHDRAWAL_SETTING from "./setting/WITHDRAWAL_SETTING";
|
||||
import VERIFICATION_SETTING from "./setting/VERIFICATION_SETTING";
|
||||
import SECURITY_SETTING from "./setting/SECURITY_SETTING";
|
||||
import ALIPAY_PAYMENT from "./pay/ALIPAY_PAYMENT";
|
||||
import WECHAT_PAYMENT from "./pay/WECHAT_PAYMENT";
|
||||
import PAYMENT_SUPPORT from "./pay/PAYMENT_SUPPORT";
|
||||
@@ -27,6 +29,8 @@ export default {
|
||||
IM_SETTING: markRaw(IM_SETTING),
|
||||
LIVE_SETTING: markRaw(LIVE_SETTING),
|
||||
WITHDRAWAL_SETTING: markRaw(WITHDRAWAL_SETTING),
|
||||
VERIFICATION_SETTING: markRaw(VERIFICATION_SETTING),
|
||||
SECURITY_SETTING: markRaw(SECURITY_SETTING),
|
||||
PAYMENT_SUPPORT: markRaw(PAYMENT_SUPPORT),
|
||||
WECHAT_PAYMENT: markRaw(WECHAT_PAYMENT),
|
||||
ALIPAY_PAYMENT: markRaw(ALIPAY_PAYMENT),
|
||||
|
||||
Reference in New Issue
Block a user