Files
lilishop-ui/seller/src/views/shop/renovation.vue
lifenlong 88fc1b0b2a refactor: 四端完成 Options API → script setup + vuex → pinia 迁移
- buyer(95) / seller(169) / im(53) / manager(280) 共 597 个组件全部从 Options API 转换为 <script setup>
- 四端 vuex 全部移除,状态管理统一迁移至 pinia 4(stores/ 目录)
- util.js 等基础设施去除 vm 首参依赖;全局属性($Message/$filters 等)在 script 内改为具名导入
- 被外部 ref 访问的公共组件均已补齐 defineExpose(清单见各端 MIGRATION-VUE3.md)
- 各端 eslint 启用 vue/component-api-style 防止新代码回退 Options API
- 四端 yarn build 全部通过;迁移约定与注意事项已更新至各端 MIGRATION-VUE3.md
2026-10-13 07:06:59 +08:00

259 lines
6.2 KiB
Vue

<template>
<div class="renovation">
<div class="btn-bar">
<el-button type="primary" :loading="submitLoading" @click="saveTemplate">保存模板</el-button>
<el-button class="ml_10" @click="resetTemplate">还原模板</el-button>
<el-button class="ml_10" @click="witeLocalStore">将装修内容写入到本地</el-button>
<el-button class="ml_10" v-if="hasCache" @click="clearCache">清空本地装修缓存</el-button>
</div>
<div class="renovation-main">
<div class="model-list">
<div class="classification-title">基础模块</div>
<draggable
tag="ul"
:list="modelData"
:item-key="getModelKey"
:clone="cloneModel"
:group="{ name: 'model', pull: 'clone', put: false }"
:sort="false"
ghost-class="ghost"
handle=".model-item"
>
<template #item="{ element: model }">
<li class="model-item">
<el-icon><Picture /></el-icon>
<span>{{ model.name }}</span>
</li>
</template>
</draggable>
</div>
<div class="show-content">
<model-form ref="modelFormRef" :data="modelForm"></model-form>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";
import { useRoute } from "vue-router";
import { Picture } from "@element-plus/icons-vue";
import { modelData } from "./modelConfig";
import Draggable from "vuedraggable";
import ModelForm from "./modelForm.vue";
import * as API_floor from "@/api/other.js";
import { getStore, setStore } from "@/libs/storage";
import { Message, Modal } from "@/utils/message";
const route = useRoute();
const hasCache = ref(false);
const modelForm = ref({ list: [] });
const submitLoading = ref(false);
const modelFormRef = ref(null);
onMounted(() => {
const cache = getStore('managerPCPageCache')
hasCache.value = !!cache;
if(cache){
Modal.confirm({
title: '提示',
content: '获取到本地有缓存数据,是否使用缓存数据?',
okText: '使用',
cancelText: '取消',
onOk: () => {
applyPageData(cache);
}
});
}
getTemplateItem(route.query.id);
});
function getModelKey(model) {
return model.type || model.name;
}
function cloneModel(model) {
const key = Date.now() + "_" + Math.ceil(Math.random() * 99999);
const cloned = JSON.parse(JSON.stringify(model));
return {
...cloned,
key,
model: cloned.type + "_" + key,
};
}
function clearCache(){
setStore('managerPCPageCache', '')
Message.success('清除成功')
}
function witeLocalStore(){
const data ={...modelForm.value}
data.list.unshift(modelFormRef.value.navList);
data.list.unshift(modelFormRef.value.topAdvert);
setStore('managerPCPageCache', data)
Message.success('写入成功')
}
function saveTemplate() {
submitTemplate(route.query.pageShow ? 'OPEN' : 'CLOSE')
}
function submitTemplate(pageShow) {
submitLoading.value = true
const modelFormData = JSON.parse(JSON.stringify(modelForm.value))
modelFormData.list.unshift(modelFormRef.value.navList);
modelFormData.list.unshift(modelFormRef.value.topAdvert);
const data = {
id: route.query.id,
pageData: JSON.stringify(modelFormData),
pageShow: route.query.pageType === 'SPECIAL' ? 'CLOSE' : pageShow,
pageClientType: 'PC',
};
API_floor.updateHome(route.query.id, data).then((res) => {
submitLoading.value = false
if (res.success) {
Message.success("保存模板成功");
}
});
}
function resetTemplate() {
getTemplateItem(route.query.id);
}
function applyPageData(raw) {
const empty = { list: [] };
if (raw == null || raw === "") {
modelForm.value = empty;
return;
}
let pageData = raw;
if (typeof raw === "string") {
try {
pageData = JSON.parse(raw);
} catch {
modelForm.value = empty;
return;
}
}
const list = Array.isArray(pageData)
? pageData
: Array.isArray(pageData?.list)
? pageData.list
: [];
const form = Array.isArray(pageData) ? { list } : { ...pageData, list };
if (list[0]?.type === "topAdvert") {
modelFormRef.value.topAdvert = list[0];
if (list[1]) {
modelFormRef.value.navList = list[1];
}
modelForm.value = { ...form, list: list.slice(2) };
return;
}
modelForm.value = { ...form, list };
}
function getTemplateItem(id) {
API_floor.getHomeData(id).then((res) => {
if (res.success) {
applyPageData(res.result?.pageData);
}
});
}
watch(modelForm, function (val) {
console.log(val);
}, { deep: true });
</script>
<style lang="scss" scoped>
.renovation {
position: relative;
display: flex;
flex-direction: column;
min-height: 100%;
}
.btn-bar {
position: sticky;
top: 0;
z-index: 99;
background: #fff;
height: 50px;
padding: 10px;
box-shadow: 1px 1px 10px #999;
}
.renovation-main {
display: flex;
align-items: flex-start;
gap: 20px;
flex: 1;
padding-top: 10px;
}
.model-list {
flex-shrink: 0;
width: 130px;
max-height: calc(100vh - 180px);
overflow-y: auto;
padding: 10px;
background: #fff;
position: sticky;
top: 60px;
z-index: 10;
box-shadow: 1px 1px 10px #999;
.classification-title {
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
}
:deep(ul) {
width: 100%;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.model-item {
width: 110px;
height: 30px;
background: #eee;
margin-top: 10px;
line-height: 30px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
color: #999;
transition: 0.15s;
border-radius: 4px;
&:hover {
background: $theme_color;
cursor: move;
color: #fff;
}
}
.ghost::after {
border: none;
height: 0;
content: "";
}
}
.show-content {
flex: 1;
min-width: 0;
overflow-x: auto;
}
.ghost {
background: #fff;
height: 30px;
position: relative;
&::after {
content: "松开鼠标添加模块";
position: absolute;
background: #fff;
border: 1px dashed #409eff;
color: #409eff;
top: 0;
left: 0;
width: 100%;
height: 50px;
text-align: center;
line-height: 50px;
}
}
</style>