Compare commits

..

2 Commits

Author SHA1 Message Date
lihaoyuan
f929893ad1 build:打板模板市场 2025-12-10 11:43:34 +08:00
lihaoyuan
6331ab74da update:新增模板市场功能 2025-12-10 11:39:52 +08:00
23 changed files with 1213 additions and 100 deletions

View File

@ -5,5 +5,5 @@
window.ver = "2.0.278";
window.SYS = {CONFIG:{}, URL:{}};</script><script>window._AMapSecurityConfig = {
securityJsCode:"07788e7ebd7e913985722bfc5986999f"
}</script><script src="https://mall.gpxscs.cn/admin/config.js?v=2.0.278"></script><script src="https://mall.gpxscs.cn/admin/im/libs3.6.0.min.js?v=2.0.278"></script><script src="https://mall.gpxscs.cn/admin/im/im.js?v=2.0.278"></script><link href="static/css/chunk-19648027.83a11e8c.css" rel="prefetch"><link href="static/css/chunk-e8a7e5a6.40d8e41a.css" rel="prefetch"><link href="static/css/vab-extra.9da8d2d7.css" rel="prefetch"><link href="static/js/chunk-19648027.6233a553.js" rel="prefetch"><link href="static/js/chunk-e8a7e5a6.d20fd7f1.js" rel="prefetch"><link href="static/js/vab-extra.29abc81b.js" rel="prefetch"><link href="static/css/app.d3766ec2.css" rel="preload" as="style"><link href="static/css/element-ui.0e3a750b.css" rel="preload" as="style"><link href="static/js/app.fc267562.js" rel="preload" as="script"><link href="static/js/element-ui.4e8e0db4.js" rel="preload" as="script"><link href="static/js/vue.11eaebc3.js" rel="preload" as="script"><link href="static/css/element-ui.0e3a750b.css" rel="stylesheet"><link href="static/css/app.d3766ec2.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="img/icons/favicon-16x16.png"><link rel="manifest" href="manifest.json"><meta name="theme-color" content="#ffffff"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="apple-mobile-web-app-title" content="xiaofa-admin"><link rel="apple-touch-icon" href="img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="img/icons/safari-pinned-tab.svg" color="#ffffff"><meta name="msapplication-TileImage" content="img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#ffffff"></head><body><noscript></noscript><div id="app"><div class="first-loading-wrp"><div class="loading-wrp"><span class="dot dot-spin"><i></i> <i></i> <i></i> <i></i></span></div><h1>小发同城</h1></div></div><script>if (window.location.hostname !== 'localhost') {
}</script><script src="static/js/element-ui.4e8e0db4.js"></script><script src="static/js/vue.11eaebc3.js"></script><script src="static/js/app.fc267562.js"></script></body></html>
}</script><script src="https://mall.gpxscs.cn/admin/config.js?v=2.0.278"></script><script src="https://mall.gpxscs.cn/admin/im/libs3.6.0.min.js?v=2.0.278"></script><script src="https://mall.gpxscs.cn/admin/im/im.js?v=2.0.278"></script><link href="static/css/chunk-073ecf64.9f18ebbe.css" rel="prefetch"><link href="static/css/chunk-19648027.83a11e8c.css" rel="prefetch"><link href="static/css/vab-extra.9da8d2d7.css" rel="prefetch"><link href="static/js/chunk-073ecf64.e40dc714.js" rel="prefetch"><link href="static/js/chunk-19648027.6233a553.js" rel="prefetch"><link href="static/js/vab-extra.29abc81b.js" rel="prefetch"><link href="static/css/app.d3766ec2.css" rel="preload" as="style"><link href="static/css/element-ui.0e3a750b.css" rel="preload" as="style"><link href="static/js/app.ae904117.js" rel="preload" as="script"><link href="static/js/element-ui.4e8e0db4.js" rel="preload" as="script"><link href="static/js/vue.11eaebc3.js" rel="preload" as="script"><link href="static/css/element-ui.0e3a750b.css" rel="stylesheet"><link href="static/css/app.d3766ec2.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="img/icons/favicon-16x16.png"><link rel="manifest" href="manifest.json"><meta name="theme-color" content="#ffffff"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="apple-mobile-web-app-title" content="xiaofa-admin"><link rel="apple-touch-icon" href="img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="img/icons/safari-pinned-tab.svg" color="#ffffff"><meta name="msapplication-TileImage" content="img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#ffffff"></head><body><noscript></noscript><div id="app"><div class="first-loading-wrp"><div class="loading-wrp"><span class="dot dot-spin"><i></i> <i></i> <i></i> <i></i></span></div><h1>小发同城</h1></div></div><script>if (window.location.hostname !== 'localhost') {
}</script><script src="static/js/element-ui.4e8e0db4.js"></script><script src="static/js/vue.11eaebc3.js"></script><script src="static/js/app.ae904117.js"></script></body></html>

View File

@ -2376,7 +2376,7 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "im/libs3.6.0.min.js"
},
{
"revision": "88f011547a0a41985c5526674d0f47c6",
"revision": "9c9d02e248d6b006ac9d2ad3d0420226",
"url": "index.html"
},
{
@ -2392,17 +2392,17 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "robots.txt"
},
{
"revision": "4844d0db9d3c633fd9ed",
"revision": "5ee4e5a4a62c554a25be",
"url": "static/css/app.d3766ec2.css"
},
{
"revision": "89c0acce5d18563ca3f5",
"url": "static/css/chunk-073ecf64.9f18ebbe.css"
},
{
"revision": "f5dd29b853f67685e75d",
"url": "static/css/chunk-19648027.83a11e8c.css"
},
{
"revision": "3e38a82f0c235d2b0fc9",
"url": "static/css/chunk-e8a7e5a6.40d8e41a.css"
},
{
"revision": "7b9212a0410ce12f6058",
"url": "static/css/element-ui.0e3a750b.css"
@ -2636,17 +2636,17 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "static/img/xiaofa-logo.20439423.png"
},
{
"revision": "4844d0db9d3c633fd9ed",
"url": "static/js/app.fc267562.js"
"revision": "5ee4e5a4a62c554a25be",
"url": "static/js/app.ae904117.js"
},
{
"revision": "89c0acce5d18563ca3f5",
"url": "static/js/chunk-073ecf64.e40dc714.js"
},
{
"revision": "f5dd29b853f67685e75d",
"url": "static/js/chunk-19648027.6233a553.js"
},
{
"revision": "3e38a82f0c235d2b0fc9",
"url": "static/js/chunk-e8a7e5a6.d20fd7f1.js"
},
{
"revision": "7b9212a0410ce12f6058",
"url": "static/js/element-ui.4e8e0db4.js"

View File

@ -14,7 +14,7 @@
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
importScripts(
"precache-manifest.cbd11add7bfdcaeb2256389d2c6d4394.js"
"precache-manifest.ac955b0a969ee87746f15a0ea465d446.js"
);
workbox.core.setCacheNameDetails({prefix: "xiaofa-admin"});

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
/*!
* build: xiaofa-admin
* copyright: https://www.lancerdt.com
* time: 2025-12-2 09:09:03
* time: 2025-12-10 11:40:19
*/
/*!
* Quill Editor v1.3.7

View File

@ -1,5 +1,5 @@
/*!
* build: xiaofa-admin
* copyright: https://www.lancerdt.com
* time: 2025-12-2 09:09:03
* time: 2025-12-10 11:40:19
*/@media only screen and (max-width:767px){.hidden-xs-only{display:none!important}}@media only screen and (min-width:768px){.hidden-sm-and-up{display:none!important}}@media only screen and (min-width:768px) and (max-width:991px){.hidden-sm-only{display:none!important}}@media only screen and (max-width:991px){.hidden-sm-and-down{display:none!important}}@media only screen and (min-width:992px){.hidden-md-and-up{display:none!important}}@media only screen and (min-width:992px) and (max-width:1199px){.hidden-md-only{display:none!important}}@media only screen and (max-width:1199px){.hidden-md-and-down{display:none!important}}@media only screen and (min-width:1200px){.hidden-lg-and-up{display:none!important}}@media only screen and (min-width:1200px) and (max-width:1919px){.hidden-lg-only{display:none!important}}@media only screen and (max-width:1919px){.hidden-lg-and-down{display:none!important}}@media only screen and (min-width:1920px){.hidden-xl-only{display:none!important}}

View File

@ -1,5 +1,5 @@
/*!
* build: xiaofa-admin
* copyright: https://www.lancerdt.com
* time: 2025-12-2 09:09:03
* time: 2025-12-10 11:40:19
*/[data-v-28093814]:export{menu-color:#fff;menu-color-active:#fff;menu-background:#282c34;column-second-menu-background:#fff}.vab-avatar-list[data-v-28093814] .el-avatar{display:inline-block;margin-left:-15px;cursor:pointer;border:3px solid #fff}.echarts{width:600px;height:400px}[data-v-7f7baab5]:export{menu-color:#fff;menu-color-active:#fff;menu-background:#282c34;column-second-menu-background:#fff}@media only screen and (max-width:767px){[data-v-7f7baab5] .vab-cropper-canvas{display:block;float:none;margin:0 auto}[data-v-7f7baab5] .vab-cropper-preview{display:none}}[data-v-7f7baab5] .el-textarea{margin-top:20px}[data-v-7f7baab5] .el-dialog__footer{height:72px}[data-v-7f7baab5] .el-dialog__footer:before{display:block;clear:both;content:""}[data-v-7f7baab5] .el-dialog__footer>div>div{display:inline}[data-v-7f7baab5] .el-dialog__footer>div>div .el-upload-list{display:none}[data-v-7f7baab5] .el-dialog__footer>div>div .el-upload--picture-card{float:right;width:auto;height:32px;line-height:32px;vertical-align:middle;background-color:transparent;border:0;border-radius:0}[data-v-7f7baab5] .el-dialog__footer>div .el-button{float:right;margin-left:10px}.icon-selector-popper .el-card__body{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;height:20px;cursor:pointer}.icon-selector-popper .el-card__body i{font-size:28px;color:rgba(0,0,0,.65);text-align:center;vertical-align:middle;pointer-events:none;cursor:pointer}.icon-selector-popper .el-pagination{margin:0}[data-v-3aef4cea]:export{menu-color:#fff;menu-color-active:#fff;menu-background:#282c34;column-second-menu-background:#fff}.upload[data-v-3aef4cea]{height:500px}.upload .upload-content .el-upload__tip[data-v-3aef4cea]{display:block;height:30px;line-height:30px}.upload .upload-content[data-v-3aef4cea] .el-upload--picture-card{width:128px;height:128px;margin:3px 8px 8px 8px;border:2px dashed #c0ccda}.upload .upload-content[data-v-3aef4cea] .el-upload-list--picture{margin-bottom:20px}.upload .upload-content[data-v-3aef4cea] .el-upload-list--picture-card .el-upload-list__item{width:128px;height:128px;margin:3px 8px 8px 8px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -40,3 +40,44 @@ export function manage(params) {
params,
})
}
export function getBlankTpl() {
return request({
url: URL.shop.page.app.getBlankTpl,
method: 'get',
})
}
export function listMarketPage(params){
return request({
url: URL.shop.page.app.listMarketPage,
method: 'get',
params
})
}
export function editPageApp(param){
return request({
url: URL.shop.page.app.editPageApp,
method: 'post',
data:param,
headers: {
'Content-Type': 'application/json' // 明确指定JSON格式
}
})
}
export function copyDiyByAppId(params){
return request({
url: URL.shop.page.app.copyDiyByAppId,
method: 'post',
params:params
})
}
export function pageAppPublish(params){
return request({
url: URL.shop.page.app.pageAppPublish,
method: 'post',
params:params
})
}

View File

@ -1243,6 +1243,11 @@ let url = {
editApp: api_url + '/admin/shop/shop-page-app/editApp',
setThemes: api_url + '/admin/shop/shop-page-app/setThemes',
manage: api_url + '/admin/shop/shop-page-base/list',
getBlankTpl: api_url + '/admin/shop/shop-page-app/getBlankTpl',
listMarketPage:api_url + '/admin/shop/shop-page-app/listMarketPage',
editPageApp:api_url + '/admin/shop/shop-page-app/editPageApp',
copyDiyByAppId:api_url + '/admin/shop/shop-page-app/copyDiyByAppId',
pageAppPublish:api_url + '/admin/shop/shop-page-app/pageAppPubish',
},
base: {
doEdit: api_url + '/admin/shop/shop-page-base/edit',
@ -1289,6 +1294,11 @@ let url = {
doDelete: api_url + '/admin/shop/shop_plantform_feedback/delete',
},
},
esign:{
signFlow:{
createByFile:api_url+'/admin/shop/esign/sign-flow/create-by-file',
}
},
analytics: {
access: {
history: {

View File

@ -0,0 +1,299 @@
<template>
<el-dialog
title="编辑图片信息"
width="40%"
:visible.sync="visible"
custom-class="template-dialog"
:before-close="handleClose"
>
<div>
<el-form
:model="form"
ref="form"
label-width="100px"
:rules="rules"
size="normal"
>
<el-form-item label="模板id" prop="app_id">
<el-input v-model="form.app_id" disabled />
</el-form-item>
<el-form-item label="模板名称" prop="app_name">
<el-input v-model="form.app_name" placeholder="请输入模板名称" />
</el-form-item>
<el-form-item label="模板类型">
<el-select v-model="form.app_industry" clearable filterable @change="">
<el-option v-for="item in shopModelList"
:key="item.id"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="模板主图" prop="tpl_image">
<upload
:image="form.tpl_image"
@upImage="handleMainImageUpload"
/>
</el-form-item>
<el-form-item label="市场图" prop="app_market_images">
<div v-for="(item, index) in form.app_market_images" :key="index" class="market-image-item">
<upload
:image="item.imageUrl"
@upImage="url => handleMarketImageUpload(index, url)"
/>
<el-input
v-model="item.content"
placeholder="请输入描述"
style="margin-left: 10px; width: 300px;"
/>
<el-button
type="text"
icon="el-icon-delete"
style="margin-left: 10px; color: red;"
@click="removeMarketImage(index)"
/>
</div>
<el-button type="text" icon="el-icon-plus" @click="addMarketImage">添加市场图</el-button>
</el-form-item>
<el-form-item label="是否上架" prop="is_pulish">
<el-select v-model="form.is_pulish" placeholder="请选择">
<el-option label="撤回" value="0" />
<el-option label="上架" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSave" :loading="saving">保存修改</el-button>
<el-button @click="handleClose">取消</el-button>
</el-form-item>
</el-form>
</div>
</el-dialog>
</template>
<script>
import { editPageApp } from '@/api/page/app'
import upload from '@/components/upload'
export default {
name: 'decoarationDetail',
components: {
upload
},
data() {
return {
visible: false,
saving: false,
form: {
app_id: '',
app_name: '',
app_market_images: [], //
tpl_image: '',
is_pulish: '0',
appIndustry:'0',
},
shopModelList:[
{id:"1",label:'超市',value:'1'},
{id:"2",label:'数码家电',value:'2'},
{id:"3",label:'水果生鲜',value:'3'},
{id:"4",label:'烘培饮品',value:'4'},
{id:"5",label:'社区团购',value:'5'},
{id:"6",label:'时尚美妆',value:'6'},
{id:"7",label:'婴儿服饰',value:'7'},
{id:"8",label:'家居',value:'8'},
{id:"9",label:'汽车',value:'9'},
{id:"10",label:'酒店旅游',value:'10'},
{id:"11",label:'鲜花绿植',value:'11'},
{id:"12",label:'医药健康',value:'12'},
{id:"13",label:'工业五金',value:'13'},
{id:"14",label:'节日模板',value:'14'},
{id:"0",label:'其他行业',value:'0'},
],
rules: {
app_name: [
{ required: true, message: '请输入模板名称', trigger: 'blur' },
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
],
tpl_image: [
{ required: true, message: '请输入模板主图URL', trigger: 'blur' }
],
app_market_images: [
{
required: true,
validator: (rule, value, callback) => {
if (!value || value.length === 0) {
callback(new Error('请至少添加一张市场图'))
} else if (value.some(item => !item.imageUrl)) {
callback(new Error('市场图图片URL不能为空'))
} else {
callback()
}
},
trigger: 'change'
}
]
},
originalData: {}
}
},
methods: {
//
open(pageData) {
this.visible = true
this.originalData = JSON.parse(JSON.stringify(pageData))
//
this.form = {
app_id: pageData.app_id || '',
app_name: pageData.app_name || '',
tpl_image: pageData.tpl_image || '',
is_pulish: pageData.is_pulish || pageData.isPublish || '0',
app_market_images: [],
app_industry:pageData.app_industry||'0'
}
//
if (pageData.app_market_images) {
try {
const marketImages = typeof pageData.app_market_images === 'string'
? JSON.parse(pageData.app_market_images)
: pageData.app_market_images
if (Array.isArray(marketImages)) {
this.form.app_market_images = []
marketImages.forEach(item => {
// itemURL
if (item.imageUrl && item.imageUrl.includes(',')) {
const urls = item.imageUrl.split(',')
urls.forEach(url => {
this.form.app_market_images.push({
imageUrl: url.trim(),
content: item.content || item.description || ''
})
})
} else {
//
this.form.app_market_images.push({
imageUrl: item.imageUrl || '',
content: item.content || item.description || ''
})
}
})
}
} catch (e) {
console.error('解析市场图失败:', e)
this.form.app_market_images = []
}
}
//
if (!this.form.app_market_images.length) {
this.addMarketImage()
}
},
//
addMarketImage() {
this.form.app_market_images.push({
imageUrl: '',
content: ''
})
},
handleMainImageUpload(imageUrl) {
this.form.tpl_image = imageUrl;
},
//
removeMarketImage(index) {
this.form.app_market_images.splice(index, 1)
//
if (!this.form.app_market_images.length) {
this.addMarketImage()
}
},
//
handleMarketImageUpload(index, url) {
this.form.app_market_images[index].imageUrl = url;
},
//
async handleSave() {
try {
await this.$refs.form.validate()
this.saving = true
//
const marketImagesArray = this.form.app_market_images.map(item => ({
imageUrl: item.imageUrl,
content: item.content
}))
//
const requestData = {
app_id: this.form.app_id,
app_name: this.form.app_name,
app_market_images: JSON.stringify(marketImagesArray), // JSON
tpl_image: this.form.tpl_image,
is_pulish: parseInt(this.form.is_pulish),
app_industry:this.form.app_industry
}
console.log('最终提交JSON:', requestData)
console.log('app_market_images解析后:', JSON.parse(requestData.app_market_images))
//
const response = await editPageApp(requestData)
if(response.status==200){
this.$message.success('保存成功哈哈哈哈!')
this.visible = false
// this.$emit('update-success', this.form)
this.$emit('editSuccess')
}
} catch (error) {
console.error('保存失败:', error)
this.$message.error('保存失败,请重试!')
} finally {
this.saving = false
}
},
//
handleClose() {
this.visible = false
if (this.$refs.form) {
this.$refs.form.resetFields()
}
}
}
}
</script>
<style scoped>
.template-dialog {
height: 700px !important;
display: flex;
flex-direction: column;
}
.template-dialog .el-dialog__body {
flex: 1;
overflow-y: auto;
max-height: 600px;
}
.market-image-item {
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 8px;
background: #f9f9f9;
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,259 @@
<template>
<el-dialog
title="模板市场"
width="80%"
:visible.sync="visible"
custom-class="template-dialog"
:z-index="2000"
>
<div class="dialog-content">
<div class="search">
<el-select v-model="selectType" clearable filterable @change="searchByType">
<el-option v-for="item in shopModelList"
:key="item.id"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<ul class="ulCls">
<li v-if="emptyPage" class="liCls">
<div align="center" class="div_img_cls">
<img
class="imgCls"
:src="emptyPage.tpl_image"
style="object-fit: fill"
/>
<p class="fontCls">{{ emptyPage.tpl_name }}</p>
</div>
<div class="lightBtn">
<div class="enableExit">
<el-button
type="primary"
@click=""
>
{{ __('创建空白模板') }}
</el-button>
</div>
</div>
</li>
<template v-if="templateList.records.length > 0">
<li v-for="(page, i) in templateList.records" :key="page.app_id || i" class="liCls">
<div align="center" class="div_img_cls">
<img
class="imgCls"
:src="page.tpl_image"
style="object-fit: fill"
/>
<p class="fontCls">{{ page.app_name }}</p>
</div>
<div class="lightBtn">
<div class="enableExit">
<el-button type="primary" @click="openCopy(page)">
{{ __('创建模板') }}
</el-button>
<el-button type="primary" @click="openPreview(page)">
{{ __('预览') }}
</el-button>
</div>
</div>
</li>
</template>
<li v-else class="empty-li">
<el-empty
description="该分类暂无模板"
/>
</li>
</ul>
<copyTemplate ref="copyTemplateRef"></copyTemplate>
<previewTemplate ref="previewTemplateRef"></previewTemplate>
</div>
</el-dialog>
</template>
<script>
import { listMarketPage, setThemes, getBlankTpl } from '@/api/page/app'
import copyTemplate from '@/views/page/sellerApp/copyTemplate.vue'
import previewTemplate from '@/views/page/sellerApp/previewTemplate.vue'
export default {
name: 'TemplateMenu',
components: { copyTemplate, previewTemplate },
data() {
return {
visible: false,
templateList: { records: [] },
emptyPage: null,
app_market_images: null,
copyTemplateRef: null,
previewTemplateRef: null,
selectType:'',
shopModelList:[
{id:"1",label:'超市',value:'1'},
{id:"2",label:'数码家电',value:'2'},
{id:"3",label:'水果生鲜',value:'3'},
{id:"4",label:'烘培饮品',value:'4'},
{id:"5",label:'社区团购',value:'5'},
{id:"6",label:'时尚美妆',value:'6'},
{id:"7",label:'婴儿服饰',value:'7'},
{id:"8",label:'家居',value:'8'},
{id:"9",label:'汽车',value:'9'},
{id:"10",label:'酒店旅游',value:'10'},
{id:"11",label:'鲜花绿植',value:'11'},
{id:"12",label:'医药健康',value:'12'},
{id:"13",label:'工业五金',value:'13'},
{id:"14",label:'节日模板',value:'14'},
{id:"0",label:'其他行业',value:'0'},
],
}
},
created() {
this.getListMarketPages()
this.getBlankTplPage()
},
methods: {
open() {
this.visible = true;
},
async getListMarketPages() {
let data = await listMarketPage()
this.templateList = data;
console.log("aaaaaaaaaaaaaaa")
},
async getBlankTplPage() {
try {
const { data, msg, status } = await getBlankTpl()
if (status === 200) {
this.emptyPage = data
}
} catch (error) {
console.error('获取空白模板失败:', error)
}
},
async searchByType(){
try {
// appIndustry
let data = await listMarketPage({ appIndustry: this.selectType });
this.templateList = data && typeof data === 'object' ? data : { records: [] }
} catch (error) {
console.error('筛选模板失败:', error)
this.templateList = { records: [] }
}
},
showEditApp(page) {
if (page.tpl_id === 107) {
this.$router.push({
path: '/appTemplate',
query: {
app_id: page.app_id,
tpl_id: page.tpl_id,
app_type: 0,
},
})
} else {
this.$router.push({
path: '/setupshop',
})
}
},
async setThemes(tpl_id, tpl_label, app_id) {
this.$baseConfirm(this.__('确定启用此模板风格?'), null, async () => {
const { msg, status } = await setThemes({
tpl_id: tpl_id,
store_template: tpl_label,
app_id: app_id,
})
if (200 == status) {
this.$baseMessage(msg, 'success')
} else {
this.$baseMessage(msg, 'error')
}
this.getAppPages()
})
},
openCopy(page) {
this.$refs.copyTemplateRef?.open(page)
},
openPreview(page) {
this.$refs.previewTemplateRef?.open(page)
},
}
}
</script>
<style scoped>
/* 内容容器样式 */
.dialog-content {
width: 100%;
height: 100%;
}
.ulCls {
list-style: none;
padding: 0;
margin: 0;
}
.ulCls li {
position: relative;
float: left;
width: 195px;
margin: 0 20px 30px;
background-color: #fafafa;
}
.div_img_cls {
height: 328px;
}
.imgCls {
width: 165px;
height: 328px;
}
.fontCls {
color: #979898;
font-weight: bold;
}
.lightBtn {
position: absolute;
opacity: 0;
top: 0;
width: 100%;
height: 328px;
}
.lightBtn:hover {
opacity: 1;
background-color: rgba(151, 152, 152, 0.5);
transition: all 0.5s;
}
.lightBtn:hover .enableExit {
transition: all 0.5s;
transform: translateY(150%);
}
.enableExit {
position: relative;
top: 30%;
width: 100%;
margin-top: -15px;
text-align: center;
}
::v-deep .template-dialog .el-dialog__body {
max-height: 600px; /* 固定最大高度,可根据需求调整 */
overflow-y: auto; /* 超出时显示纵向滚动条 */
overflow-x: hidden; /* 禁止横向滚动 */
padding: 15px;
}
.search{
width: 100%;
margin: 20px;
}
</style>

View File

@ -0,0 +1,108 @@
<template>
<el-dialog
title="创建店铺"
width="30%"
:visible.sync="visible"
custom-class="template-dialog"
:z-index="2020"
:append-to-body="true"
height="300px"
>
<el-form
:model="form"
ref="form"
label-width="80px"
:inline="false"
size="normal"
>
<el-form-item label="app_id" size="normal">
{{ form.app_id }}
</el-form-item>
<el-form-item label="模板名字">
<el-input v-model="form.appName"></el-input>
</el-form-item>
<el-form-item label="模板类型">
<el-select v-model="form.app_industry" clearable filterable @change="">
<el-option v-for="item in shopModelList"
:key="item.id"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="copy">创建模板</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script>
import {copyDiyByAppId} from '@/api/page/app'
export default{
name:'copyTemplate',
data(){
return{
visible: false,
form:{
app_id:'',
appName:'',
appIndustry:''
},
shopModelList:[
{id:"1",label:'超市',value:'1'},
{id:"2",label:'数码家电',value:'2'},
{id:"3",label:'水果生鲜',value:'3'},
{id:"4",label:'烘培饮品',value:'4'},
{id:"5",label:'社区团购',value:'5'},
{id:"6",label:'时尚美妆',value:'6'},
{id:"7",label:'婴儿服饰',value:'7'},
{id:"8",label:'家居',value:'8'},
{id:"9",label:'汽车',value:'9'},
{id:"10",label:'酒店旅游',value:'10'},
{id:"11",label:'鲜花绿植',value:'11'},
{id:"12",label:'医药健康',value:'12'},
{id:"13",label:'工业五金',value:'13'},
{id:"14",label:'节日模板',value:'14'},
{id:"0",label:'其他行业',value:'0'},
],
}
},
methods:{
open(page){
this.visible = true
this.form=page
console.log("pagehhhhhhh",page)
},
async copy(){
let params={
appId:this.form.app_id,
appName:this.form.appName,
appIndustry:this.form.app_industry
}
let res=await copyDiyByAppId(params)
if(res.status==200){
this.$message.success('模板创建成功!')
this.visible = false
this.$emit('copySuccess') //
}
}
}
}
</script>
<style scoped>
.template-dialog {
height: 300px !important;
display: flex;
flex-direction: column;
}
.template-dialog .el-dialog__body {
flex: 1;
overflow-y: auto;
max-height: 300px;
}
</style>

View File

@ -2,8 +2,16 @@
<div class="page-app-container">
<el-row>
<el-card class="box-card">
<div slot="header" class="clearfix">
<div slot="header" class="clearfix header-row">
<span>{{ __('当前使用的模板') }}</span>
<el-button
type="primary"
size="default"
@click="createNewTemplate"
class="create-btn"
>
{{ __('创建店铺模板') }}
</el-button>
</div>
<div>
<div style="width: 100%">
@ -23,7 +31,7 @@
{{ __('模板名称') }}{{ usePage.app_name }}
</span>
<el-button type="primary" @click="showEditApp(usePage)">
{{ __('编辑模版') }}
{{ __('去装修') }}
</el-button>
</div>
</div>
@ -48,14 +56,79 @@
</div>
<div class="lightBtn">
<div class="enableExit">
<el-button
type="primary"
@click="setThemes(page.tpl_id, page.tpl_label,page.app_id)"
>
{{ __('启用') }}
<div style="margin-bottom: 10px;">
<el-button
type="primary"
@click="setThemes(page.tpl_id, page.tpl_label, page.app_id)"
>
{{ __('启用') }}
</el-button>
<el-button type="primary" @click="showEditApp(page)">
{{ __('去装修') }}
</el-button>
</div>
<!-- 下拉菜单 -->
<el-dropdown size="large" @command="handleDropdownCommand(page, $event)">
<el-button type="primary">
{{ __('更多') }}<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">
{{ __('编辑') }}
</el-dropdown-item>
<el-dropdown-item command="upload" v-if="page.is_pulish==0">
{{ __('发布') }}
</el-dropdown-item>
<el-dropdown-item command="pull" v-if="page.is_pulish==1">
{{ __('下架') }}
</el-dropdown-item>
<el-dropdown-item command="preview">
{{ __('预览') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</li>
</ul>
</div>
</el-card>
</el-row>
<el-row>
<el-card>
<div slot="header" class="clearfix header-row">
<span>{{ __('模板市场') }}</span>
<el-button
type="primary"
size="default"
@click="createNewTemplate"
class="create-btn"
>
{{ __('查看更多模板') }}
</el-button>
</div>
<div>
<ul class="ulCls" style="position: relative">
<li
v-for="(page, i) in templateList.records"
:key="i"
class="liCls"
>
<div align="center" class="div_img_cls">
<img
class="imgCls"
:src="page.tpl_image"
style="object-fit: fill"
/>
<p class="fontCls">{{ page.app_name }}</p>
</div>
<div class="lightBtn">
<div class="enableExit">
<el-button type="primary" @click="openCopy(page)">
{{ __('创建模板') }}
</el-button>
<el-button type="primary" @click="showEditApp(page)">
{{ __('编辑') }}
<el-button type="primary" @click="openPreview(page)">
{{ __('预览') }}
</el-button>
</div>
</div>
@ -64,23 +137,46 @@
</div>
</el-card>
</el-row>
<templateMenu ref="templateMenuRef"></templateMenu>
<decoarationDetail ref="decoarationDetailRef" @editSuccess="refreshAllData"></decoarationDetail>
<copyTemplate ref="copyTemplateRef" @copySuccess="refreshAllData"></copyTemplate>
<previewTemplate ref="previewTemplateRef"></previewTemplate>
</div>
</template>
<script>
import { getList, setThemes } from '@/api/page/app'
import {
getList,
setThemes,
listMarketPage,
getBlankTpl,
pageAppPublish
} from '@/api/page/app'
import { translateTitle as __ } from '@/utils/i18n'
import templateMenu from '@/views/page/sellerApp/TemplateMenu.vue'
import decoarationDetail from '@/views/page/sellerApp/DecorationDetail.vue'
import copyTemplate from '@/views/page/sellerApp/copyTemplate.vue'
import previewTemplate from '@/views/page/sellerApp/previewTemplate.vue'
export default {
name: 'PageApp',
components: {},
components: { templateMenu, decoarationDetail,copyTemplate,previewTemplate },
data() {
return {
usePage: {},
list: [],
templateMenuRef: null,
decoarationDetailRef: null,
copyTemplateRef:null,
previewTemplateRef:null,
templateList: [],
emptyPage: null,
app_market_images: null,
}
},
created() {
this.getAppPages()
this.getListMarketPages()
this.getBlankTplPage()
},
methods: {
__,
@ -88,7 +184,6 @@
const { data, msg, status } = await getList()
this.list = data.items
this.usePage = data.current_tpl
//this.getUsePage(data.items)
},
showEditApp(page) {
if (page.tpl_id === 107) {
@ -115,7 +210,7 @@
}
}
},
async setThemes(tpl_id, tpl_label,app_id) {
async setThemes(tpl_id, tpl_label, app_id) {
this.$baseConfirm(this.__('确定启用此模板风格?'), null, async () => {
const { msg, status } = await setThemes({
tpl_id: tpl_id,
@ -130,6 +225,67 @@
this.getAppPages()
})
},
createNewTemplate() {
this.$refs.templateMenuRef?.open()
},
async getListMarketPages() {
let data = await listMarketPage()
this.templateList = data
},
async getBlankTplPage() {
try {
const { data, msg, status } = await getBlankTpl()
if (status === 200) {
this.emptyPage = data
}
} catch (error) {
console.error('获取空白模板失败:', error)
}
},
openDetailEdit(page) {
this.$refs.decoarationDetailRef?.open(page)
},
openCopy(page) {
this.$refs.copyTemplateRef?.open(page)
},
openPreview(page){
this.$refs.previewTemplateRef?.open(page)
},
//
handleDropdownCommand(page, command) {
switch(command) {
case 'edit':
this.openDetailEdit(page)
break
case 'upload':
//
this.handleUpload(page,1)
break
case 'pull':
this.handleUpload(page,0)
break
case 'preview':
this.openPreview(page)
break
}
},
// ,
async handleUpload(page,publishStatus) {
const params={
appId:page.app_id,
isPublish:publishStatus
}
let res=await pageAppPublish(params)
if(res.status==200){
this.$message.success('操作成功7777')
this.refreshAllData()
}
},
//
async refreshAllData() {
await this.getAppPages()
await this.getListMarketPages()
}
},
}
</script>
@ -138,6 +294,13 @@
font-size: 18px;
}
/* 头部行样式 */
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.usertemplate {
float: left;
display: inline-block;
@ -217,4 +380,9 @@
margin-top: -15px;
text-align: center;
}
</style>
/* 下拉菜单样式调整 */
.el-dropdown {
display: inline-block;
}
</style>

View File

@ -0,0 +1,228 @@
<template>
<el-dialog
title="模板预览"
width="20%"
:visible.sync="visible"
custom-class="template-dialog"
:z-index="2020"
:append-to-body="true"
>
<div class="preview-container">
<div class="basic-info">
<p><strong>模板ID</strong>{{ form.app_id }}</p>
<p><strong>模板名称</strong>{{ form.app_name }}</p>
</div>
<div class="carousel-container">
<el-carousel
height="450px"
arrow="always"
:interval="3000"
indicator-position="none"
v-if="imageList.length > 0"
>
<el-carousel-item v-for="(img, index) in imageList" :key="index">
<div class="carousel-item">
<img
:src="img.imageUrl"
:alt="`图片${index+1}`"
class="carousel-image"
@error="handleImageError(index)"
/>
<div class="image-desc" v-if="img.content">
{{ img.content }}
</div>
</div>
</el-carousel-item>
</el-carousel>
<!-- 无图片时的占位 -->
<div class="no-images" v-else>
<el-empty description="暂无图片数据"></el-empty>
</div>
</div>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'previewTemplate',
data() {
return {
visible: false,
form: {
app_id: '',
app_name: '',
app_market_images: ''
},
imageList: [] //
}
},
methods: {
open(page) {
this.visible = true
this.form = { ...page }
// app_market_images
this.processImages(page.app_market_images)
},
//
processImages(imagesData) {
this.imageList = []
if (!imagesData) return
try {
// JSON
let parsedData = typeof imagesData === 'string'
? JSON.parse(imagesData)
: imagesData
// 使
if (Array.isArray(parsedData)) {
parsedData.forEach(item => {
// imageUrl
if (item.imageUrl && item.imageUrl.includes(',')) {
const urls = item.imageUrl.split(',')
urls.forEach(url => {
this.imageList.push({
imageUrl: url.trim(),
content: item.content || ''
})
})
} else if (item.imageUrl) {
this.imageList.push({
imageUrl: item.imageUrl,
content: item.content || ''
})
}
})
}
//
else if (parsedData.imageUrl) {
if (parsedData.imageUrl.includes(',')) {
const urls = parsedData.imageUrl.split(',')
urls.forEach(url => {
this.imageList.push({
imageUrl: url.trim(),
content: parsedData.content || ''
})
})
} else {
this.imageList.push({
imageUrl: parsedData.imageUrl,
content: parsedData.content || ''
})
}
}
} catch (error) {
console.error('解析图片数据失败:', error)
// URL
if (typeof imagesData === 'string' && imagesData.startsWith('http')) {
this.imageList.push({ imageUrl: imagesData })
}
}
},
//
handleImageError(index) {
this.imageList[index].imageUrl = 'https://via.placeholder.com/400x600?text=图片加载失败'
}
}
}
</script>
<style scoped>
.template-dialog {
width: 90% !important;
max-width: 1200px;
height: 700px !important;
}
.preview-container {
padding: 20px;
}
.basic-info {
margin-bottom: 20px;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
}
.basic-info p {
margin: 5px 0;
}
.carousel-container {
margin-top: 20px;
}
.el-carousel {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.carousel-item {
position: relative;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #f9f9f9;
}
.carousel-image {
max-width: 100%;
max-height: 450px;
object-fit: contain;
}
.image-desc {
position: absolute;
bottom: 20px;
left: 0;
right: 0;
padding: 10px;
background-color: rgba(0, 0, 0, 0.5);
color: white;
text-align: center;
font-size: 14px;
}
.no-images {
height: 450px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
border-radius: 8px;
}
/* 轮播指示器样式 */
::v-deep .el-carousel__indicator {
background-color: rgba(255, 255, 255, 0.5);
}
::v-deep .el-carousel__indicator--active {
background-color: #ffffff;
}
/* 轮播箭头样式 */
::v-deep .el-carousel__arrow {
background-color: rgba(0, 0, 0, 0.3);
width: 40px;
height: 40px;
border-radius: 50%;
}
::v-deep .el-carousel__arrow:hover {
background-color: rgba(0, 0, 0, 0.5);
}
::v-deep .el-dialog__body{
padding: 0;
}
</style>