添加加盟店

This commit is contained in:
chenhao 2026-06-03 10:48:43 +08:00
parent a2ad18d9bc
commit aa20aa964b
20 changed files with 778 additions and 158 deletions

BIN
public/img/addr_r.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
public/img/cate_all.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
public/img/clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

BIN
public/img/icon_canpay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

BIN
public/img/icon_disc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

BIN
public/img/icon_phone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/img/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
public/img/shopinfo-top.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

View File

@ -14,7 +14,8 @@ export default {
},
data() {
return {
wechatShareInfo: {}
wechatShareInfo: {},
geo: null
}
},
watch: {
@ -48,6 +49,9 @@ export default {
},
mounted() {
this.init()
this.$geo.getWebGeo().then(pos => {
this.geo = pos
})
},
methods: {
updateTitle(title) {

View File

@ -40,11 +40,11 @@
<van-icon class="r" name="arrow"></van-icon>
</div>
<!-- <div @click="navigateAndClose('Social')">
<div @click="navigateAndClose('Social')">
<img src="/img/my_u7.png" alt="">
<span>合作</span>
<span>加盟</span>
<van-icon class="r" name="arrow"></van-icon>
</div> -->
</div>
</div>
<button @click="loginout">

View File

@ -31,7 +31,7 @@ const routes = [
name: 'Social',
parentName: 'Index',
component: () => import('./views/Tabbars/Social.vue'),
meta: { title: '合作店', cache: true }
meta: { title: '加盟店', cache: true }
},
{
path: '/My',
@ -54,10 +54,15 @@ const routes = [
{
path: '/PointMall',
name: 'PointMall',
parentName: 'Index',
component: () => import('./views/User/PointMall.vue'),
meta: { title: '积分区', cache: true }
},
{
path: '/ShopInfo',
name: 'ShopInfo',
component: () => import('./views/User/ShopInfo.vue'),
meta: { title: '商家详情', cache: true }
},
{
path: '/Login',
name: 'Login',
@ -235,7 +240,7 @@ const routes = [
path: '/Category',
name: 'Category',
component: () => import('./views/Goods/Category.vue'),
meta: { title: '全部分类', noLogin: true, cache: true }
meta: { title: '全部分类', noLogin: true }
},
{
path: '/Operations',

View File

@ -5628,5 +5628,338 @@
background-color: #f5f5f5;
border-radius: 2.67vw 2.67vw 0vw 0vw;
margin-top: -5vw;
padding: 4.8vw 4vw;
.contaniar {
.box;
.box-center-center;
}
.list_pagebox {
.box;
.box-tb;
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
.cate_list {
// .box;
// flex-wrap: wrap;
width: max-content;
display: grid;
grid-template-rows: auto auto;
grid-auto-flow: column;
overflow-x: auto;
.cate_item {
width: 18.4vw;
.box;
.box-tb;
.box-align-center;
height: 20vw;
white-space: nowrap;
img {
width: 12vw;
height: 10.8vw;
margin-bottom: 1.87vw;
}
&.active {
color: #ea3c1f;
}
}
}
.scroll_progress {
position: relative;
height: 1.33vw;
background-color: #ffe4ea;
border-radius: 0.67vw;
margin-top: 2vw;
width: 18vw;
.progress_thumb {
position: absolute;
left: 0;
width: 3vw;
height: 100%;
background-color: #b6536a;
border-radius: 0.67vw;
}
}
.tab {
margin-top: 4vw;
.van-tabs__nav {
background: transparent;
}
.van-tabs__nav--card {
border: none;
margin: 0;
gap: 3.33vw;
// height: 6.67vw;
}
.van-tab--card {
width: 45.33vw;
// height: 6.67vw;
border: none;
background: #fff;
border-radius: 3.33vw;
}
}
.shoplist {
.box;
.box-tb;
margin-top: 4vw;
.shopitem {
.box;
.box-tb;
margin-bottom: 4vw;
background-color: #ffffff;
border-radius: 2.67vw;
padding: 3.33vw;
.top_box {
.box;
width: 100%;
img {
width: 18.67vw;
height: 18.67vw;
border-radius: 2vw;
margin-right: 3.33vw;
}
.info_box {
.box;
.box-tb;
.box-pack-around;
width: 100%;
>div {
.box;
.box-align-center;
}
.name_box {
color: #222222;
b {
font-size: 4vw;
width: 50vw;
.text-hide(1);
}
.type {
.r;
}
}
.tags {
>div {
.box;
.box-align-center;
height: 4.8vw;
background-color: #ec6e8c;
border-radius: 2.4vw;
padding: 0 2vw 0 .27vw;
width: max-content;
.bs;
margin-right: 2.67vw;
img {
width: 4.27vw;
height: 4.27vw;
margin-right: 1.2vw;
}
}
}
}
}
.addr_box {
.box;
.box-align-center;
margin-top: 3.6vw;
color: #222222;
.addr {
width: 60vw;
.text-hide(1);
}
.distance {
.r;
.box;
.box-align-center;
gap: 1.2vw;
img {
height: 3.47vw;
}
}
}
}
}
}
}
.shopinfo {
.shop_details {
background-color: #ffffff;
border-radius: 2.67vw 2.67vw 0vw 0vw;
margin-top: -35vw;
z-index: 1;
position: relative;
padding: 4vw 3.2vw 0;
.shopi_box {
.box;
width: 100%;
padding-bottom: 3.2vw;
border-bottom: 1px solid #f5f5f580;
img {
width: 18.67vw;
height: 18.67vw;
border-radius: 2vw;
margin-right: 3.33vw;
}
.info_box {
.box;
.box-tb;
.box-pack-around;
width: 100%;
>div {
.box;
.box-align-center;
}
.name_box {
color: #222222;
b {
font-size: 4vw;
width: 50vw;
.text-hide(1);
}
.type {
.r;
}
}
.tags {
>div {
.box;
.box-align-center;
height: 4.8vw;
background-color: #ec6e8c;
border-radius: 2.4vw;
padding: 0 2vw 0 .27vw;
width: max-content;
.bs;
margin-right: 2.67vw;
img {
width: 4.27vw;
height: 4.27vw;
margin-right: 1.2vw;
}
}
}
}
}
.tomap {
.box;
.box-align-center;
padding: 3.33vw;
border-bottom: 1px solid #f5f5f580;
.address {
.box;
.addr_icon {
height: 4vw;
width: 3.47vw;
margin-right: 2.53vw;
}
.ri {
span {
color: #222222;
}
.distance {
color: #999999;
}
}
}
}
.map_icon {
.r;
padding-left: 3.33vw;
border-left: 1px solid #eeeeee;
img {
width: 6.4vw;
height: 6.4vw;
background-color: #2dd6aa;
border-radius: 1.33vw;
}
}
.onlinetime {
.box;
.box-align-center;
padding: 3.33vw;
.left_box {
.box;
.box-align-center;
.clock_icon {
width: 3.73vw;
height: 3.73vw;
margin-right: 2.53vw;
}
}
}
}
.intro {
margin: 4vw 0;
padding: 0 3.33vw;
.title {
font-size: 4vw;
color: #222222;
margin-left: 1.2vw;
}
.htmlcontent {
margin-top: 3.33vw;
width: 100%;
img {
width: 100%;
margin-top: 1.2vw;
}
}
}
}

View File

@ -49,21 +49,21 @@
</div>
<div class="pro-list">
<div class="px">
<a @click="toggleValue(0)" :class="searchParams.SortType == 0 ? 'a' : ''">
<a @click="toggleValue(0)" :class="isActive(0) ? 'a' : ''">
综合 <img :src="getImageSource(0)" />
</a>
<a @click="toggleValue(1)" :class="searchParams.SortType == 1 ? 'a' : ''">
<a @click="toggleValue(1)" :class="isActive(1) ? 'a' : ''">
价格 <img :src="getImageSource(1)" />
</a>
<a @click="toggleValue(2)" :class="searchParams.SortType == 2 ? 'a' : ''">
<a @click="toggleValue(2)" :class="isActive(2) ? 'a' : ''">
销量 <img :src="getImageSource(2)" />
</a>
</div>
<div class="content product_content">
<BaseList class="pro-list" ref="productList" :url="`/v1/client/EProsClient`"
<BaseList class="pro-list" ref="productList" page-size="100" :url="`/v1/client/EProsClient`"
:params="queryParams" @load="onLoad">
<template #default="{ item }">
<div class="a1" @click="$navigate('/GoodsDetail?id=' + item.id)">
<div class="a1" @click="goToDetail(item.id)">
<img :src="$file(item.img)" />
<div class="c">
<div class="name">{{ item.name }}</div>
@ -117,8 +117,7 @@ export default {
mainCategory: '',
currentThirdId: '',
searchParams: {
SortType: 0,
IsDesc: true,
orderby: 'latest',
},
queryParams: {
mallstate: 3,
@ -130,57 +129,43 @@ export default {
"/img/pro-list-px-1.png",
"/img/pro-list-px-2.png",
],
_scrollRestored: false,
_pauseScroll: false,
}
},
watch: {
'searchParams.orderby': {
handler(val) {
this.queryParams.orderby = val;
}
},
'$route.fullPath': {
handler(newFullPath, oldFullPath) {
if (newFullPath !== oldFullPath) {
// this.searchKey = ''
// setTimeout(() => {
this.init()
// }, 100);
}
}
}
},
activated() {
this.searchKey = ''
this._scrollRestored = false
this._pauseScroll = false
this.$nextTick(() => {
mounted() {
//
this._scrollLoadCount = 0
this._needRestoreScroll = sessionStorage.getItem('Category_scroll_need_restore') === '1'
if (this._needRestoreScroll) {
sessionStorage.removeItem('Category_scroll_need_restore')
}
const container = document.querySelector('.product_content')
if (container) {
container.addEventListener('scroll', this.saveScroll)
this.restoreScroll(container)
container.addEventListener('scroll', this.saveScroll, { passive: true })
}
})
this.init()
},
beforeRouteLeave(to, from, next) {
this._pauseScroll = true
//
const container = document.querySelector('.product_content')
if (container) {
sessionStorage.setItem('Category_scroll', container.scrollTop || 0)
}
next()
},
deactivated() {
this._pauseScroll = true
const container = document.querySelector('.product_content')
if (container) {
sessionStorage.setItem('Category_scroll', container.scrollTop || 0)
}
},
mounted() {
const container = document.querySelector('.product_content')
if (container) {
container.addEventListener('scroll', this.saveScroll)
}
this.init()
},
beforeUnmount() {
const container = document.querySelector('.product_content')
if (container) {
@ -189,23 +174,17 @@ export default {
},
methods: {
saveScroll() {
if (this._pauseScroll) return
const container = document.querySelector('.product_content')
if (container) {
sessionStorage.setItem('Category_scroll', container.scrollTop || 0)
}
},
restoreScroll(container) {
restoreScroll() {
const container = document.querySelector('.product_content')
if (!container) return
const scrollTop = sessionStorage.getItem('Category_scroll')
if (scrollTop && scrollTop !== '0' && !this._scrollRestored) {
this._scrollRestored = true
container.removeEventListener('scroll', this.saveScroll)
this.$nextTick(() => {
container.scrollTo(0, Number(scrollTop))
})
setTimeout(() => {
container.addEventListener('scroll', this.saveScroll)
}, 100)
if (scrollTop && scrollTop !== '0') {
container.scrollTop = Number(scrollTop)
}
},
async init() {
@ -214,8 +193,7 @@ export default {
this.changeMainById(Number(this.$route.query.id));
}
if (this.$route.query.SortType == 2) {
this.searchParams.SortType = 2;
this.searchParams.IsDesc = true;
this.searchParams.orderby = 'salenumdown';
}
if (this.$route.query.name) {
this.searchKey = this.$route.query.name;
@ -315,23 +293,69 @@ export default {
this.queryParams.name = this.searchKey;
this.refreshProductList();
},
onLoad() {
this._scrollLoadCount = (this._scrollLoadCount || 0) + 1
// BaseList
if (this._scrollLoadCount === 1 && this._needRestoreScroll) {
this._needRestoreScroll = false
this.$nextTick(() => {
this.restoreScroll()
})
}
},
goToDetail(id) {
//
const container = document.querySelector('.product_content')
if (container) {
const scrollTop = container.scrollTop || 0
sessionStorage.setItem('Category_scroll', scrollTop)
if (scrollTop > 0) {
sessionStorage.setItem('Category_scroll_need_restore', '1')
}
}
this.$navigate('/GoodsDetail?id=' + id)
},
refreshProductList() {
this.$refs.productList?.refresh();
},
toggleValue(e) {
if (this.searchParams.SortType == e) {
this.searchParams.IsDesc = !this.searchParams.IsDesc;
const orderbyMap = {
0: ['latest', 'oldest'],
1: ['salepriceup', 'salepricedown'],
2: ['salenumup', 'salenumdown'],
};
const current = orderbyMap[e];
if (!current) return;
if (this.searchParams.orderby === current[0]) {
this.searchParams.orderby = current[1];
} else if (this.searchParams.orderby === current[1]) {
this.searchParams.orderby = current[0];
} else {
this.searchParams.SortType = e;
this.searchParams.IsDesc = true;
this.searchParams.orderby = current[0];
}
this.refreshProductList();
},
isActive(e) {
const orderbyMap = {
0: ['latest', 'oldest'],
1: ['salepriceup', 'salepricedown'],
2: ['salenumup', 'salenumdown'],
};
return orderbyMap[e]?.includes(this.searchParams.orderby);
},
getImageSource(e) {
if (this.searchParams.SortType == e) {
if (this.searchParams.IsDesc) return this.imageSources[2];
else return this.imageSources[1];
} else return this.imageSources[0];
const orderbyMap = {
0: ['latest', 'oldest'],
1: ['salepriceup', 'salepricedown'],
2: ['salenumup', 'salenumdown'],
};
const current = orderbyMap[e];
if (this.searchParams.orderby === current[0]) {
return this.imageSources[2];
} else if (this.searchParams.orderby === current[1]) {
return this.imageSources[1];
}
return this.imageSources[0];
},
}
}

View File

@ -45,7 +45,7 @@ export default {
},
{
Name: 'Social',
Label: '合作店',
Label: '加盟店',
Icon_Active: '/img/Social_Active.png',
Icon_Inactive: '/img/Social_Inactive.png',
},
@ -72,9 +72,9 @@ export default {
methods: {
updateActive() {
const routeName = this.$route.name
if (routeName === 'Social') {
return
}
// if (routeName === 'Social') {
// return
// }
const tabbar = this.Tabbars.find(item => item.Name === routeName)
if (tabbar) {
this.DefaultActive = tabbar.Name
@ -84,9 +84,9 @@ export default {
return item.Badge || ''
},
onTabClick(name) {
if (name === 'Social') {
return
}
// if (name === 'Social') {
// return
// }
if (this.$route.name === name) {
//
// this.$router.replace({ name })
@ -97,11 +97,11 @@ export default {
}
},
onTabChange(name) {
if (name === 'Social') {
this.$showToast('暂未开放')
this.DefaultActive = this.$route.name;
return
}
// if (name === 'Social') {
// this.$showToast('')
// this.DefaultActive = this.$route.name;
// return
// }
this.DefaultActive = name
},
onUpdateShare(title, desc, imgUrl) {

View File

@ -26,23 +26,19 @@
<van-field v-model="formData.huili" label="惠利比例" type="number" readonly>
<template #extra><span style="color:#666">%</span></template>
</van-field>
<!-- <van-field v-model="formData.cellphone" label="商家分类" type="tel" readonly />
<van-field v-model="formData.address" label="经营地址" placeholder="请联系平台修改" type="text" />
<van-field v-model="formData.shopcatename" label="商家分类" readonly />
<van-field v-model="formData.businesstime" label="营业时间" />
<van-field label="营业时间" readonly is-link @click="onBusinessTimeClick">
<template #input>
<span :style="{ color: formData.starttime && formData.endtime ? '#333' : '#ccc' }"
style="text-align: right;width: 100%;">
{{ formData.starttime && formData.endtime ? formData.starttime + '-' + formData.endtime : '选择营业时间' }}
</span>
</template>
</van-field>
<van-collapse v-model="activeNames" style="border: none;">
<van-collapse-item title="商家介绍" name="1" style="border: none;">
<van-collapse v-model="activeNames">
<van-collapse-item title="经营地址" name="1" value="点击展开查看详情">
<div style="color: #222;">{{ formData.shopaddress }}</div>
修改请联系平台
</van-collapse-item>
<van-collapse-item title="商家介绍" name="2" value="点击展开查看详情">
<div class="shop-intro-wrap">
<div class="intro-images">
<div v-for="(img, index) in formData.shopintroimages" :key="index" class="intro-img-item">
<img :src="img" @click="previewImage(img)" />
<img :src="img.url" @click="previewImage(img)" />
<van-icon name="cross" class="delete-btn" @click="removeIntroImage(index)" />
</div>
<van-uploader v-if="formData.shopintroimages.length < 9" :after-read="onIntroImageRead"
@ -50,7 +46,7 @@
</div>
</div>
</van-collapse-item>
</van-collapse> -->
</van-collapse>
</van-cell-group>
</div>
@ -105,37 +101,27 @@
</div>
</van-form>
<van-popup v-model:show="showStartTimePicker" position="bottom" round>
<van-time-picker v-model="currentTime" title="选择开始时间" @confirm="onStartTimeConfirm"
@cancel="showStartTimePicker = false" />
</van-popup>
<van-popup v-model:show="showEndTimePicker" position="bottom" round>
<van-time-picker v-model="currentTime" title="选择结束时间" @confirm="onEndTimeConfirm"
@cancel="showEndTimePicker = false" />
</van-popup>
</div>
</BasePage>
</template>
<script>
import { ImagePreview } from 'vant'
export default {
name: 'MerchantIntroduction',
data() {
return {
saving: false,
activeNames: [],
showStartTimePicker: false,
showEndTimePicker: false,
currentTime: ['12', '00'],
formData: {
shopname: '',
shopimg: '',
AvatarUploader: [],
huili: 20,
cellphone: '',
shopcatename: '',
businesstime: '',
shopaddress: '',
legalpersonname: '',
legalpersonphone: '',
legalidimg: [],
@ -145,10 +131,8 @@ export default {
bankcardnumber: '',
subbank: '',
bankcellphone: '',
starttime: '',
endtime: '',
shopintroimages: [],
}
},
}
},
mounted() {
@ -162,6 +146,9 @@ export default {
this.formData.shopimg = data.shopimg
this.formData.huili = data.feeratio || 20
this.formData.cellphone = data.cellphone
this.formData.shopcatename = data.shopcatename || ''
this.formData.businesstime = data.businesstime || ''
this.formData.shopaddress = data.shopprovince + data.shopcity + data.shopcounty + (data.shopstreet || '') + data.shopaddress
this.formData.legalpersonname = data.legalpersonname
this.formData.legalpersonphone = data.legalpersonphone
this.formData.province = data.shopprovince + data.shopcity + data.shopcounty
@ -179,6 +166,12 @@ export default {
if (data.businesslicenseimg) {
this.formData.licenseimg = [{ url: this.$file(data.businesslicenseimg), isImage: true }]
}
//
if (data.shopdescription) {
// shopdescription
const imgs = data.shopdescription.split(',').filter(Boolean)
this.formData.shopintroimages = imgs.map(url => ({ url: this.$file(url) }))
}
})
},
uploadShopImg(file) {
@ -190,17 +183,41 @@ export default {
this.formData.shopimg = file.file
},
previewImage(url) {
ImagePreview([url])
const imageUrl = typeof url === 'object' ? url.url : url
this.$showImagePreview({ images: [imageUrl], startPosition: 0 })
},
async save() {
if (!this.formData.shopname) {
this.$showFailToast('请输入店铺名称')
return
}
if (!this.formData.cellphone) {
this.$showFailToast('请输入联系电话')
return
}
this.saving = true
try {
const fd = new FormData()
fd.append('shopname', this.formData.shopname)
fd.append('shopphone', this.formData.cellphone)
fd.append('Shopname', this.formData.shopname)
fd.append('Shopphone', this.formData.cellphone)
fd.append('Businesstime', this.formData.businesstime || '')
if (this.formData.shopimg instanceof File) {
fd.append('file', this.formData.shopimg)
fd.append('File', this.formData.shopimg)
}
//
const existingUrls = this.formData.shopintroimages
.filter(item => !item.file && item.url)
.map(item => item.url)
.join(',')
if (existingUrls) {
fd.append('Shopdescription', existingUrls)
}
//
this.formData.shopintroimages.forEach(item => {
if (item.file) {
fd.append('Filedesc', item.file)
}
})
await this.$postForm('/v1/client/DShopsClient/shopinfo', fd)
this.$showSuccessToast('保存成功')
} catch (err) {
@ -209,49 +226,15 @@ export default {
this.saving = false
}
},
uploadFile(url, file) {
const fd = new FormData()
fd.append('file', file)
return fetch(`${import.meta.env.VITE_API_URL}${url}`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${localStorage.getItem('member_token')}` },
body: fd,
}).then(res => res.json()).then(res => {
if (res.status !== 200) throw new Error(res.message)
return res.data
})
},
onStartTimeConfirm({ selectedValues }) {
this.formData.starttime = selectedValues.join(':')
this.showStartTimePicker = false
this.showEndTimePicker = true
},
onEndTimeConfirm({ selectedValues }) {
this.formData.endtime = selectedValues.join(':')
this.showEndTimePicker = false
},
onBusinessTimeClick() {
this.showStartTimePicker = true
},
onIntroImageRead(file) {
const img = file.file
this.uploadFile('/v1/client/DShopsClient/shopintroimg', img).then(url => {
this.formData.shopintroimages.push(this.$file(url))
this.formData.shopintroimages.push({
url: URL.createObjectURL(file.file),
file: file.file,
})
},
removeIntroImage(index) {
this.formData.shopintroimages.splice(index, 1)
},
filter(type, options) {
if (type === 'hour') {
return options.filter(option => option >= 6 && option <= 23)
}
return options
},
onTimeConfirm({ selectedValues }) {
this.formData.businesshours = selectedValues.join(':')
this.showTimePicker = false
}
},
}
</script>
@ -433,12 +416,13 @@ export default {
.intro-images {
display: flex;
flex-wrap: wrap;
gap: 2vw;
gap: 3.33vw;
// justify-content: space-between;
.intro-img-item {
position: relative;
width: 20vw;
height: 20vw;
width: 25vw;
height: 25vw;
border-radius: 4px;
overflow: hidden;
@ -465,8 +449,9 @@ export default {
:deep(.van-uploader) {
.van-uploader__upload {
width: 20vw;
height: 20vw;
width: 25vw;
height: 25vw;
margin: 0;
}
}
}
@ -482,5 +467,6 @@ export default {
font-size: 4.27vw;
}
}
}
</style>

View File

@ -0,0 +1,151 @@
<template>
<div class="social">
<div class="top">
<div class="search_box">
<img src="/img/search.png" alt="搜索">
<input type="text" placeholder="搜索商家门店名称" v-model="searchQuery" @input="onSearchInput">
</div>
</div>
<div class="category_box">
<div class="list_pagebox" ref="listPagebox" @scroll="onScroll">
<div class="cate_list" ref="cateList">
<div class="cate_item" :class="{ active: selectedId === '' }" @click="onSelectCategory('')">
<img src="/img/cate_all.png" alt="全部分类">
<span>全部分类</span>
</div>
<div class="cate_item" v-for="item in categories" :key="item.id" :class="{ active: selectedId === item.id }"
@click="onSelectCategory(item.id)">
<img :src="$file(item.img) || '/img/avatar.png'" alt="分类图片">
<!-- <img src="/img/mall_i15.png" alt=""> -->
<span>{{ item.name }}</span>
</div>
</div>
</div>
<div class="contaniar">
<div class="scroll_progress">
<div class="progress_thumb" :style="thumbStyle"></div>
</div>
</div>
<van-tabs class="tab" v-model:active="active" type="card" color="#841e36" title-active-color="#fff"
title-inactive-color="#222" @change="onTabChange">
<van-tab title="离我最近"></van-tab>
<van-tab title="更大优惠"></van-tab>
</van-tabs>
<BaseList class="shoplist" url="/v1/client/DShopsClient/list" :params="searchparams" :auto-load="true">
<template #default="{ item }">
<div class="shopitem" @click="$navigate(`/ShopInfo?id=${item.userid}`)">
<div class="top_box">
<img :src="$file(item.shopimg) || '/img/avatar.png'" alt="商户图片">
<div class="info_box">
<div class="name_box">
<b>{{ item.shopname }}</b>
<span class="type">{{ item.shopcatename }}</span>
</div>
<div class="tags">
<div class="disc_box"><img src="/img/icon_disc.png" alt="">{{ item.feeratio }}%</div>
<div class="canpay_box"><img src="/img/icon_canpay.png" alt="">可到店消费</div>
</div>
</div>
</div>
<div class="addr_box">
<span class="addr">
{{ item.shopprovince + item.shopcity + item.shopcounty }}{{ item.shopstreet }}{{ item.shopaddress }}
</span>
<span class="distance"><img src="/img/addr_r.png" alt="">{{ (item.distance / 1000)?.toFixed(2)
}}km</span>
</div>
</div>
</template>
</BaseList>
</div>
</div>
</template>
<script>
export default {
name: 'Social',
data() {
return {
searchQuery: '',
scrollPercent: 0,
noScroll: true,
selectedId: '',
active: 0,
categories: [],
searchparams: {
latitude: 29.309300,
longitude: 120.070380,
shopcateid: '',
orderby: '',
shopname: '',
},
}
},
async mounted() {
const res = await this.$geo.getWebGeo();
this.searchparams.latitude = res.lat;
this.searchparams.longitude = res.lon;
this.init();
this.$nextTick(() => {
this.checkScroll();
const ro = new ResizeObserver(() => this.checkScroll());
ro.observe(this.$refs.cateList);
});
},
computed: {
thumbStyle() {
if (this.noScroll) {
return { width: '100%', transform: 'none' };
}
return { transform: `translateX(${this.scrollPercent}vw)` };
},
},
watch: {
active(val) {
this.searchparams.orderby = val === 1 ? 'feeratio' : '';
},
},
methods: {
init() {
Promise.all([
this.$get('/v1/client/dshopcatesclient').then(res => {
this.categories = res.data
})
]).catch(err => {
console.error('初始化失败:', err)
})
},
onSelectCategory(id) {
this.selectedId = id;
this.searchparams.shopcateid = id;
},
onTabChange(val) {
this.searchparams.orderby = val === 1 ? 'feeratio' : '';
},
onScroll() {
const el = this.$refs.listPagebox
if (!el) return
const maxScroll = el.scrollWidth - el.clientWidth
this.noScroll = maxScroll <= 0
if (this.noScroll) {
this.scrollPercent = 0
return
}
const rawPercent = maxScroll > 0 ? (el.scrollLeft / maxScroll) * 15 : 0
this.scrollPercent = Math.max(0, Math.min(rawPercent, 15))
},
checkScroll() {
const el = this.$refs.cateList;
const parent = this.$refs.listPagebox;
if (!el || !parent) return;
this.noScroll = el.scrollWidth <= parent.clientWidth;
},
onSearchInput() {
this.searchparams.shopname = this.searchQuery;
},
},
}
</script>

View File

@ -1,9 +1,12 @@
<template>
<BasePage :back="back" title="订单支付">
<div class="pay">
<div class="amount">
<div class="amount" v-if="orderInfo.mallstate !== 5">
<span></span>{{ orderInfo.needpay || orderInfo.payjifen }}
</div>
<div class="amount" v-else>
{{ orderInfo.needpay || orderInfo.payjifen }} <span> 积分</span>
</div>
<div class="trade-code">
订单号{{ orderInfo.ordernum }}
</div>
@ -147,7 +150,7 @@ export default {
alipay: 2,
wechat: 1,
bankcard: 3,
point: 5,
point: 6,
};
const paychannel = channelMap[method];
const openid = localStorage.getItem('openid') || '';

View File

@ -93,6 +93,10 @@
评价时间
<span>{{ $formatGMT(data.evaltime, 'yyyy-MM-dd HH:mm:ss') }}</span>
</p>
<p v-if="data.refundtime">
退款时间
<span>{{ $formatGMT(data.refundtime, 'yyyy-MM-dd HH:mm:ss') }}</span>
</p>
</div>
<div class="p" v-else>
<p>
@ -150,6 +154,10 @@
评价时间
<span>{{ $formatGMT(data.evaltime, 'yyyy-MM-dd HH:mm:ss') }}</span>
</p>
<p v-if="data.refundtime">
退款时间
<span>{{ $formatGMT(data.refundtime, 'yyyy-MM-dd HH:mm:ss') }}</span>
</p>
</div>
</div>
<!--

106
src/views/User/ShopInfo.vue Normal file
View File

@ -0,0 +1,106 @@
<template>
<BasePage>
<div class="shopinfo">
<img src="/img/shopinfo-top.jpg" style="width: 100%;" alt="店铺图片" class="shop-image">
<div class="shop_details">
<div class="shopi_box">
<img :src="$file(shopInfo.shopimg) || '/img/avatar.png'" alt="">
<div class="info_box">
<div class="name_box">
<b>{{ shopInfo.shopname }}</b>
<span class="type">{{ shopInfo.shopcatename }}</span>
</div>
<div class="tags">
<div class="disc_box"><img src="/img/icon_disc.png" alt="">{{ shopInfo.feeratio }}%</div>
<div class="canpay_box"><img src="/img/icon_canpay.png" alt="">可到店消费</div>
</div>
</div>
</div>
<div class="tomap">
<div class="address">
<img class="addr_icon" src="/img/addr_r.png" alt="">
<div class="ri">
<span>{{ shopInfo.shopprovince }}{{ shopInfo.shopcity }}{{ shopInfo.shopcounty }}{{ shopInfo.shopstreet ||
'' }}{{ shopInfo.shopaddress }}</span>
<div class="distance" v-if="shopInfo.distance">距离{{ (shopInfo.distance / 1000)?.toFixed(2) }}km</div>
</div>
</div>
<div class="map_icon" @click="openMap">
<img src="/img/map.png" alt="">
</div>
</div>
<div class="onlinetime">
<div class="left_box">
<img class="clock_icon" src="/img/clock.png" alt="">
<span>{{ shopInfo.businesstime || '暂未设置' }}</span>
</div>
<div class="map_icon" @click="callPhone">
<img src="/img/icon_phone.png" alt="">
</div>
</div>
</div>
<hr style="margin: 0; border: none; height: 1.6vw; background-color: #f5f5f5;">
<div class="intro">
<b class="title">
商家介绍
</b>
<div class="htmlcontent" v-html="shopInfo.shopdescriptionhtml || '暂无商家介绍'"></div>
</div>
<van-action-bar placeholder>
<van-action-bar-icon icon="shop-o" text="附近的店" @click="$router.back()" />
<van-action-bar-button color="#ca2904" type="danger" text="到店买单" @click="openMap" />
</van-action-bar>
</div>
</BasePage>
</template>
<script>
export default {
name: 'ShopInfo',
data() {
return {
//
shopInfo: {
}
}
},
mounted() {
this.init()
},
methods: {
init() {
this.$get('/v1/client/DShopsClient/list', { userid: this.$route.query.id }).then(res => {
this.shopInfo = res.data.items[0] || {}
})
},
callPhone() {
if (this.shopInfo.shopphone) {
window.location.href = `tel:${this.shopInfo.shopphone}`
}
},
openMap() {
if (this.shopInfo.shoplatitude && this.shopInfo.shoplongitude) {
const lat = this.shopInfo.shoplatitude;
const lon = this.shopInfo.shoplongitude;
const fullAddress = encodeURIComponent(
(this.shopInfo.shopprovince || '') +
(this.shopInfo.shopcity || '') +
(this.shopInfo.shopcounty || '') +
(this.shopInfo.shopstreet || '') +
(this.shopInfo.shopaddress || '')
);
window.open(`https://uri.amap.com/navigation?to=${lon},${lat},${fullAddress}&mode=car&src=shop`, '_blank');
}
},
}
}
</script>