mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-10 19:08:58 +08:00
feat: 新增页面装修-分类设置页(模板选择+商品列表字段开关)
This commit is contained in:
349
manager/src/views/page-decoration/category-setting.vue
Normal file
349
manager/src/views/page-decoration/category-setting.vue
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
<template>
|
||||||
|
<div class="category-setting" v-loading="loading">
|
||||||
|
<el-card shadow="never" class="panel">
|
||||||
|
<div class="section-title">分类导航</div>
|
||||||
|
<div class="section-sub">选择模板</div>
|
||||||
|
<div class="template-list">
|
||||||
|
<div
|
||||||
|
v-for="tpl in templates"
|
||||||
|
:key="tpl.value"
|
||||||
|
class="template-card"
|
||||||
|
:class="{ active: form.template === tpl.value }"
|
||||||
|
@click="form.template = tpl.value"
|
||||||
|
>
|
||||||
|
<!-- 纯 CSS 示意图 -->
|
||||||
|
<div class="mini-phone">
|
||||||
|
<div class="mini-search"></div>
|
||||||
|
<!-- 模板1:左栏 + 宫格 -->
|
||||||
|
<template v-if="tpl.value === 1">
|
||||||
|
<div class="mini-body">
|
||||||
|
<div class="mini-side">
|
||||||
|
<i v-for="n in 6" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-grid">
|
||||||
|
<div class="mini-grid-title"></div>
|
||||||
|
<div class="mini-grid-cells">
|
||||||
|
<i v-for="n in 6" :key="n"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 模板2:顶部图标横排 + 标签行 + 左竖列 + 单列商品 -->
|
||||||
|
<template v-else-if="tpl.value === 2">
|
||||||
|
<div class="mini-icon-row">
|
||||||
|
<i v-for="n in 5" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-tag-row">
|
||||||
|
<i v-for="n in 4" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-body">
|
||||||
|
<div class="mini-side">
|
||||||
|
<i v-for="n in 5" :key="n" :class="{ on: n === 2 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-goods">
|
||||||
|
<i v-for="n in 3" :key="n"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 模板3:顶部图标横排 + 左竖列 + 单列商品(无标签行) -->
|
||||||
|
<template v-else-if="tpl.value === 3">
|
||||||
|
<div class="mini-icon-row">
|
||||||
|
<i v-for="n in 5" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-body">
|
||||||
|
<div class="mini-side">
|
||||||
|
<i v-for="n in 5" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-goods">
|
||||||
|
<i v-for="n in 3" :key="n"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 模板4:左竖列(一级) + 右上文字横排(二级) + 单列商品 -->
|
||||||
|
<template v-else>
|
||||||
|
<div class="mini-body">
|
||||||
|
<div class="mini-side">
|
||||||
|
<i v-for="n in 5" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-right">
|
||||||
|
<div class="mini-tag-row">
|
||||||
|
<i v-for="n in 4" :key="n" :class="{ on: n === 1 }"></i>
|
||||||
|
</div>
|
||||||
|
<div class="mini-goods">
|
||||||
|
<i v-for="n in 3" :key="n"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="template-name">{{ tpl.name }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-title">页面设置</div>
|
||||||
|
<div class="section-sub">商品列表展示字段</div>
|
||||||
|
<div class="field-list">
|
||||||
|
<el-checkbox model-value :disabled="true">商品名称</el-checkbox>
|
||||||
|
<el-checkbox
|
||||||
|
v-for="f in fieldOptions"
|
||||||
|
:key="f.key"
|
||||||
|
v-model="form.showFields[f.key]"
|
||||||
|
>{{ f.label }}</el-checkbox
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-button type="primary" :loading="saveLoading" class="save-btn" @click="submit"
|
||||||
|
>保存设置</el-button
|
||||||
|
>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { getSetting, setSetting } from "@/api/index";
|
||||||
|
import { Message } from "@/utils/message";
|
||||||
|
|
||||||
|
defineOptions({ name: "category-setting" });
|
||||||
|
|
||||||
|
const SETTING_KEY = "CATEGORY_PAGE_SETTING";
|
||||||
|
|
||||||
|
const templates = [
|
||||||
|
{ value: 1, name: "模板一:左树右宫格" },
|
||||||
|
{ value: 2, name: "模板二:图标导航+三级标签" },
|
||||||
|
{ value: 3, name: "模板三:图标导航" },
|
||||||
|
{ value: 4, name: "模板四:侧栏一级+二级横滑" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const fieldOptions = [
|
||||||
|
{ key: "subTitle", label: "商品副标题" },
|
||||||
|
{ key: "spec", label: "规格值" },
|
||||||
|
{ key: "tags", label: "标签" },
|
||||||
|
{ key: "selfTag", label: "自营标签" },
|
||||||
|
{ key: "price", label: "价格(市场价/会员价)" },
|
||||||
|
{ key: "linePrice", label: "划线价" },
|
||||||
|
{ key: "sales", label: "销量/好评/好评率" },
|
||||||
|
{ key: "cart", label: "购物车" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const saveLoading = ref(false);
|
||||||
|
|
||||||
|
function defaultForm() {
|
||||||
|
return {
|
||||||
|
template: 1,
|
||||||
|
showFields: {
|
||||||
|
subTitle: true,
|
||||||
|
spec: true,
|
||||||
|
tags: true,
|
||||||
|
selfTag: true,
|
||||||
|
price: true,
|
||||||
|
linePrice: true,
|
||||||
|
sales: true,
|
||||||
|
cart: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = ref(defaultForm());
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadSetting();
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadSetting() {
|
||||||
|
loading.value = true;
|
||||||
|
getSetting(SETTING_KEY)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.success && res.result) {
|
||||||
|
const data = res.result;
|
||||||
|
const merged = defaultForm();
|
||||||
|
if ([1, 2, 3, 4].includes(data.template)) {
|
||||||
|
merged.template = data.template;
|
||||||
|
}
|
||||||
|
Object.assign(merged.showFields, data.showFields || {});
|
||||||
|
form.value = merged;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
saveLoading.value = true;
|
||||||
|
setSetting(SETTING_KEY, form.value)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
Message.success("保存成功");
|
||||||
|
} else {
|
||||||
|
Message.error("保存失败");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
saveLoading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.category-setting {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.panel {
|
||||||
|
max-width: 960px;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
.section-sub {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.template-list {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.template-card {
|
||||||
|
width: 150px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
&.active {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.template-name {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- 示意图 ---- */
|
||||||
|
.mini-phone {
|
||||||
|
background: #f5f6f8;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
height: 180px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.mini-search {
|
||||||
|
height: 8px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.mini-body {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
.mini-right {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.mini-side {
|
||||||
|
width: 26px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
i {
|
||||||
|
height: 14px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
border-radius: 2px;
|
||||||
|
&.on {
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mini-icon-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
i {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #e4e7ed;
|
||||||
|
&.on {
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mini-tag-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 3px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
i {
|
||||||
|
width: 18px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
&.on {
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mini-grid {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.mini-grid-title {
|
||||||
|
height: 7px;
|
||||||
|
width: 40%;
|
||||||
|
background: #dcdfe6;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.mini-grid-cells {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
i {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mini-goods {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
i {
|
||||||
|
height: 30px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
.el-checkbox {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.save-btn {
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user