feat:优化
This commit is contained in:
1 parent
585e5e2f62
commit
16ec75360e
4 files changed
+401
-95
No files matched your search
@@ -25,16 +25,16 @@ VITE_OAUTH2_APP_CLIENT='mini:mini'
|
||||
# VITE_ZZD_CORP_ID=
|
||||
|
||||
# --------------------------- 开发环境 api地址 ----------------------------------
|
||||
VITE_APP_DEV_SERVICE = https://www.pjzhhq.cn/api # 域名线上
|
||||
# VITE_APP_DEV_SERVICE = https://www.pjzhhq.cn/api # 域名线上
|
||||
#VITE_APP_DEV_SERVICE = http://59.202.170.152:81/api # 信创线上
|
||||
# VITE_APP_DEV_SERVICE = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
VITE_APP_DEV_SERVICE = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
# VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
|
||||
# VITE_APP_DEV_SERVICE = http://123.157.250.162:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 开发环境 图片访问基础地址 ---------------------------
|
||||
VITE_IMAGE_DEV_PATH = https://www.pjzhhq.cn/api # 域名线上
|
||||
# VITE_IMAGE_DEV_PATH = https://www.pjzhhq.cn/api # 域名线上
|
||||
#VITE_IMAGE_DEV_PATH = http://59.202.170.152:81/api # 信创线上
|
||||
# VITE_IMAGE_DEV_PATH = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
VITE_IMAGE_DEV_PATH = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
# VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
|
||||
# VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上
|
||||
|
||||
|
||||
+8
-1
@@ -20,4 +20,11 @@ dist
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env
|
||||
.env
|
||||
|
||||
# AI 辅助工具生成文件(ZCode 等)
|
||||
.zcode/
|
||||
.zcodeignore
|
||||
.mimosa/
|
||||
.v2c/
|
||||
.video_agent/
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { merchantApi } from "@@/api"
|
||||
import { hooks, router } from "@@/index"
|
||||
@@ -12,6 +12,8 @@ const state = reactive<any>({
|
||||
type: "2",
|
||||
parentId: "",
|
||||
},
|
||||
detail: {},
|
||||
parent: null,
|
||||
})
|
||||
const pageHook = hooks.usePage(pageRef, merchantApi.childrenPage, null, "data.records")
|
||||
|
||||
@@ -19,6 +21,24 @@ const query = (page: number, pagesize: number) => {
|
||||
pageHook.startPage(page, pagesize, false, state.pa)
|
||||
}
|
||||
|
||||
const swiperPics = computed(() => String(state.detail?.swiperPic || "").split(",").filter(Boolean))
|
||||
|
||||
// parentId 为空/-1 视为主店,否则是分店
|
||||
const isBranch = computed(() => {
|
||||
const pid = state.detail?.parentId
|
||||
return pid != null && pid !== "" && pid !== -1
|
||||
})
|
||||
|
||||
const jobTimeText = (v: any) => {
|
||||
if (!v?.jobTime || v.jobTime == ",,") return ""
|
||||
const labels = ["早", "中", "晚"]
|
||||
return v.jobTime
|
||||
.split(",")
|
||||
.map((s: string, i: number) => (s ? `${labels[i]} ${s}` : ""))
|
||||
.filter(Boolean)
|
||||
.join(" · ")
|
||||
}
|
||||
|
||||
onLoad((options: any) => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
@@ -49,6 +69,27 @@ onShow(async () => {
|
||||
const getDetail = async () => {
|
||||
const { data } = await merchantApi.detail({ id: state.pa.parentId })
|
||||
state.detail = data
|
||||
await loadParent(data?.parentId)
|
||||
}
|
||||
|
||||
// 若当前店铺是分店,加载父店信息展示
|
||||
const loadParent = async (pid: any) => {
|
||||
state.parent = null
|
||||
if (!pid || pid == -1) return
|
||||
try {
|
||||
const { data } = await merchantApi.detail({ id: pid })
|
||||
state.parent = data || null
|
||||
} catch {
|
||||
state.parent = null
|
||||
}
|
||||
}
|
||||
|
||||
const toParentBrand = async () => {
|
||||
if (!state.parent) return
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (isLogin) {
|
||||
router.jump("/pages/merchant/brandDetail", { parentId: state.parent.id })
|
||||
}
|
||||
}
|
||||
|
||||
const toDetail = async (v: any) => {
|
||||
@@ -60,67 +101,130 @@ const toDetail = async (v: any) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="h-full overflow-hidden">
|
||||
<swiper
|
||||
class="w-100vw h-30vh"
|
||||
circular
|
||||
:indicator-dots="true"
|
||||
indicator-active-color="#0779FD"
|
||||
indicator-color="#ffffff"
|
||||
:autoplay="true"
|
||||
>
|
||||
<swiper-item v-for="(v, i) in state.detail?.swiperPic?.split(',')" :key="i">
|
||||
<image class="w-full h-full" :src="filePath(v)" mode="aspectFill" />
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<z-paging ref="pageRef" height="100%" :fixed="false" v-model="pageHook.list" :default-page-size="10"
|
||||
safe-area-inset-bottom :loading-more-enabled="true" :show-scrollbar="false" @query="query"
|
||||
:auto-clean-list-when-reload="false" :auto-scroll-to-top-when-reload="false"
|
||||
:hide-empty-view="!!state.parent" empty-view-text="暂无分店">
|
||||
<view class="h-30rpx" />
|
||||
|
||||
<crud-layout>
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
height="70%"
|
||||
:fixed="false"
|
||||
v-model="pageHook.list"
|
||||
:default-page-size="10"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="true"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
@scroll="pageHook.scroll"
|
||||
>
|
||||
<view class="h-20rpx" />
|
||||
<view class="flex-row card p-20rpx m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i" @tap="toDetail(v)">
|
||||
<image class="w-180rpx h-180rpx rounded-12rpx my-auto" :src="filePath(v.logoPic)" mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-20rpx">
|
||||
<view class="sub-text-34">{{ v.name }}</view>
|
||||
<view class="m-t-10rpx">
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="flex-1">
|
||||
<view v-if="v.phone" class="flex items-center">
|
||||
<image class="w-24rpx h-24rpx" src="@/static/page/phone.svg" />
|
||||
<view class="second-text-28 ml-1">{{ v.phone }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<tm-tag class="max-w-160rpx" size="xs">
|
||||
{{ v.deptName.length > 5 ? v.deptName.substring(0, 5) + "..." : v.deptName }}
|
||||
</tm-tag>
|
||||
</view>
|
||||
<view class="second-text-24">
|
||||
<view v-if="v.jobTime != ',,'" class="second-text-28">营业时间:</view>
|
||||
<view>{{ v.jobTime?.split(",")[0] ? "早:" + v.jobTime?.split(",")[0] : "" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[1] ? "中:" + v.jobTime?.split(",")[1] : "" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[2] ? "晚:" + v.jobTime?.split(",")[2] : "" }}</view>
|
||||
</view>
|
||||
<view v-if="v.addressDes" class="second-text-28">
|
||||
<image class="w-24rpx h-24rpx" src="@/static/page/address.svg" />
|
||||
<text class="ml-1">地址:</text>
|
||||
<text class="m-l-10rpx">{{ v.addressDes }}</text>
|
||||
</view>
|
||||
<view v-if="swiperPics.length" class="card h-320rpx overflow-hidden m-b-20rpx">
|
||||
<swiper class="w-full h-full" circular :indicator-dots="true" indicator-active-color="#0779FD"
|
||||
indicator-color="rgba(255,255,255,0.8)" :autoplay="true" interval="4000">
|
||||
<swiper-item v-for="(p, i) in swiperPics" :key="i">
|
||||
<image class="w-full h-full" :src="filePath(p)" mode="aspectFill" />
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<view class="card p-24rpx flex">
|
||||
<image class="w-160rpx h-160rpx rounded-16rpx bg-#F2F6FA my-auto flex-none" :src="filePath(state.detail.logoPic)"
|
||||
mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-20rpx min-w-0">
|
||||
<view class="flex items-center">
|
||||
<text class="sub-text-30 font-bold flex-1 min-w-0 show-line">{{ state.detail.name }}</text>
|
||||
<view class="brand-pill m-l-12rpx flex-none">{{ isBranch ? "分店" : "品牌店" }}</view>
|
||||
</view>
|
||||
|
||||
<view v-if="state.detail.discountsPrice" class="promo-bar m-t-12rpx">
|
||||
<tm-icon name="coupon-line" color="#f63a36" :size="24" />
|
||||
<text class="m-l-8rpx flex-1 min-w-0 show-line">{{ state.detail.discountsPrice }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="state.detail.phone || state.detail.deptName" class="m-t-12rpx flex items-center justify-between">
|
||||
<view v-if="state.detail.phone" class="flex items-center flex-1 min-w-0">
|
||||
<tm-icon name="phone-line" color="#A6AEB8" :size="26" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ state.detail.phone }}</text>
|
||||
</view>
|
||||
<tm-tag v-if="state.detail.deptName" class="flex-none" size="xs">
|
||||
{{ state.detail.deptName.length > 5 ? state.detail.deptName.substring(0, 5) + "..." : state.detail.deptName }}
|
||||
</tm-tag>
|
||||
</view>
|
||||
<view v-if="jobTimeText(state.detail)" class="m-t-8rpx flex items-center">
|
||||
<tm-icon name="calendar-schedule-line" color="#A6AEB8" :size="26" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ jobTimeText(state.detail) }}</text>
|
||||
</view>
|
||||
<view v-if="state.detail.addressDes" class="m-t-8rpx flex items-center">
|
||||
<tm-icon name="map-pin-2-line" color="#A6AEB8" :size="26" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ state.detail.addressDes }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="state.parent" class="card p-20rpx m-t-20rpx flex items-center" hover-class="card-hover"
|
||||
@tap="toParentBrand">
|
||||
<image class="w-88rpx h-88rpx rounded-12rpx bg-#F2F6FA flex-none" :src="filePath(state.parent.logoPic)"
|
||||
mode="aspectFill" />
|
||||
<view class="flex-1 min-w-0 m-l-16rpx">
|
||||
<view class="second-text-22">所属品牌</view>
|
||||
<view class="sub-text-28 font-medium m-t-2rpx show-line">{{ state.parent.name }}</view>
|
||||
</view>
|
||||
<tm-icon name="arrow-right-s-line" color="#C2C9D2" :size="28" />
|
||||
</view>
|
||||
|
||||
<view v-if="!state.parent" class="flex items-center m-t-28rpx m-b-16rpx px-4rpx">
|
||||
<view class="section-bar" />
|
||||
<text class="sub-text-28 font-bold m-l-12rpx">分店列表</text>
|
||||
<text v-if="Number(state.detail.mchCount) > 0" class="second-text-24 m-l-8rpx">({{ state.detail.mchCount }}家)</text>
|
||||
</view>
|
||||
<view v-for="(v, i) in pageHook.list" :key="v.id ?? i" class="card p-20rpx m-b-20rpx flex"
|
||||
hover-class="card-hover" @tap="toDetail(v)">
|
||||
<image class="w-140rpx h-140rpx rounded-12rpx bg-#F2F6FA my-auto flex-none" :src="filePath(v.logoPic)"
|
||||
mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-16rpx min-w-0">
|
||||
<view class="flex items-center">
|
||||
<text class="sub-text-28 font-bold flex-1 min-w-0 show-line">{{ v.name }}</text>
|
||||
<tm-icon name="arrow-right-s-line" color="#C2C9D2" :size="28" />
|
||||
</view>
|
||||
<view v-if="v.discountsPrice" class="promo-bar m-t-10rpx">
|
||||
<tm-icon name="coupon-line" color="#f63a36" :size="22" />
|
||||
<text class="m-l-8rpx flex-1 min-w-0 show-line">{{ v.discountsPrice }}</text>
|
||||
</view>
|
||||
<view v-if="v.phone" class="m-t-8rpx flex items-center">
|
||||
<tm-icon name="phone-line" color="#A6AEB8" :size="24" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ v.phone }}</text>
|
||||
</view>
|
||||
<view v-if="v.addressDes" class="m-t-6rpx flex items-center">
|
||||
<tm-icon name="map-pin-2-line" color="#A6AEB8" :size="24" />
|
||||
<text class="second-text-22 m-l-8rpx flex-1 min-w-0 show-line">{{ v.addressDes }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-hover {
|
||||
opacity: 0.86;
|
||||
}
|
||||
|
||||
.brand-pill {
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(7, 121, 253, 0.1);
|
||||
color: #0779fd;
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.promo-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #fff1f0;
|
||||
color: #f63a36;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.section-bar {
|
||||
width: 8rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #0779fd;
|
||||
}
|
||||
</style>
|
||||
@@ -60,6 +60,55 @@ const toDetail = async (v: any) => {
|
||||
uni.showToast({ title: "合作商家类型未知", icon: "none" })
|
||||
}
|
||||
}
|
||||
|
||||
const isBrand = (v: any) => v.supType == "10" || v.supType == "50"
|
||||
const hasBranch = (v: any) => isBrand(v) && Number(v.mchCount) > 0
|
||||
|
||||
const jobTimeText = (v: any) => {
|
||||
if (!v.jobTime || v.jobTime == ",,") return ""
|
||||
const labels = ["早", "中", "晚"]
|
||||
return v.jobTime
|
||||
.split(",")
|
||||
.map((s: string, i: number) => (s ? `${labels[i]} ${s}` : ""))
|
||||
.filter(Boolean)
|
||||
.join(" · ")
|
||||
}
|
||||
|
||||
// 后端对过大 size 的分页查询会返回空列表,这里用小分页循环拉全量
|
||||
const loadBranches = async (v: any) => {
|
||||
v._loading = true
|
||||
try {
|
||||
const size = 10
|
||||
const all: any[] = []
|
||||
for (let current = 1; current <= 50; current++) {
|
||||
const res: any = await merchantApi.childrenPage({ current, size, type: "2", parentId: v.id })
|
||||
if (res.code != 0) throw new Error(res.msg || "分店加载失败")
|
||||
const records = res.data?.records || []
|
||||
all.push(...records)
|
||||
if (records.length < size || all.length >= Number(res.data?.total || 0)) break
|
||||
}
|
||||
v._children = all
|
||||
// 空结果不缓存,避免一次异常返回空后本次会话内再也刷不出来
|
||||
v._childrenLoaded = all.length > 0
|
||||
} catch (error: any) {
|
||||
v._expanded = false
|
||||
uni.showToast({ title: error?.message || "分店加载失败", icon: "none" })
|
||||
} finally {
|
||||
v._loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const toggleBranch = async (v: any) => {
|
||||
v._expanded = !v._expanded
|
||||
if (v._expanded && !v._childrenLoaded && !v._loading) await loadBranches(v)
|
||||
}
|
||||
|
||||
const toBranchDetail = async (b: any) => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (isLogin) {
|
||||
router.jump("/pages/merchant/detail", { id: b.id })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -71,11 +120,11 @@ const toDetail = async (v: any) => {
|
||||
<view class="h-30rpx" />
|
||||
<view class="flex w-full">
|
||||
<tm-input class="flex-1" v-model="state.pa.name" type="text" height="72" minHeight="72"
|
||||
fontSize="28" :showClear="true" :focus="false" placeholder="请输入商家名称"
|
||||
style="border: 4rpx solid #0779fd; border-radius: 14rpx" :focus-highlight="false"
|
||||
color="#ECF4F9">
|
||||
fontSize="28" :showClear="true" :focus="false" placeholder="搜索商家名称"
|
||||
:focus-highlight="false" color="#ffffff"
|
||||
style="border-radius: 36rpx; box-shadow: 0 6rpx 20rpx rgba(7, 121, 253, 0.1)">
|
||||
<template v-slot:rightIcon>
|
||||
<tm-button class="mr-1 px-3 py-26rpx text-30rpx!" size="xs" @click="search">搜 索</tm-button>
|
||||
<tm-button class="mr-1 px-4 py-24rpx text-28rpx!" size="xs" @click="search">搜索</tm-button>
|
||||
</template>
|
||||
</tm-input>
|
||||
</view>
|
||||
@@ -84,39 +133,185 @@ const toDetail = async (v: any) => {
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="flex-row card p-20rpx m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i" @tap="toDetail(v)">
|
||||
<image class="w-180rpx h-180rpx rounded-12rpx my-auto" :src="filePath(v.logoPic)" mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-20rpx">
|
||||
<view class="sub-text-34">
|
||||
<text class="mr-2">{{ v.name }}</text>
|
||||
<!-- <tm-tag v-if="v.supType == '10' && Number(v.mchCount) > 0" size="xs" skin="thin">共{{ v.mchCount }}家</tm-tag> -->
|
||||
</view>
|
||||
<view class="m-t-10rpx">
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="flex-1">
|
||||
<view v-if="v.phone" class="flex items-center">
|
||||
<image class="w-24rpx h-24rpx" src="@/static/page/phone.svg" />
|
||||
<view class="second-text-28 ml-1">{{ v.phone }}</view>
|
||||
</view>
|
||||
<view class="card m-b-20rpx overflow-hidden" hover-class="card-hover" v-for="(v, i) in pageHook.list"
|
||||
:key="v.id ?? i" @tap="toDetail(v)">
|
||||
<view class="flex p-24rpx">
|
||||
<image class="w-160rpx h-160rpx rounded-16rpx bg-#F2F6FA my-auto flex-none" :src="filePath(v.logoPic)"
|
||||
mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-20rpx min-w-0">
|
||||
<view class="flex items-center">
|
||||
<text class="sub-text-30 font-bold flex-1 min-w-0 show-line">{{ v.name }}</text>
|
||||
<view v-if="isBrand(v)" class="brand-pill m-l-12rpx flex-none">品牌店</view>
|
||||
</view>
|
||||
|
||||
<view v-if="v.discountsPrice" class="promo-bar m-t-12rpx">
|
||||
<tm-icon name="coupon-line" color="#f63a36" :size="24" />
|
||||
<text class="m-l-8rpx flex-1 min-w-0 show-line">{{ v.discountsPrice }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="jobTimeText(v)" class="m-t-12rpx flex items-center">
|
||||
<tm-icon name="calendar-schedule-line" color="#A6AEB8" :size="26" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ jobTimeText(v) }}</text>
|
||||
</view>
|
||||
<view v-if="v.phone || v.deptName" class="m-t-8rpx flex items-center justify-between">
|
||||
<view v-if="v.phone" class="flex items-center flex-1 min-w-0">
|
||||
<tm-icon name="phone-line" color="#A6AEB8" :size="26" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ v.phone }}</text>
|
||||
</view>
|
||||
<tm-tag class="max-w-160rpx" size="xs">{{ v.deptName.length > 5 ? v.deptName.substring(0, 5)
|
||||
+ "..." :
|
||||
v.deptName }}</tm-tag>
|
||||
<tm-tag v-if="v.deptName" class="flex-none" size="xs">
|
||||
{{ v.deptName.length > 5 ? v.deptName.substring(0, 5) + "..." : v.deptName }}
|
||||
</tm-tag>
|
||||
</view>
|
||||
<view class="second-text-24">
|
||||
<view v-if="v.jobTime != ',,'" class="second-text-28">营业时间:</view>
|
||||
<view>{{ v.jobTime?.split(",")[0] ? "早:" + v.jobTime?.split(",")[0] : "" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[1] ? "中:" + v.jobTime?.split(",")[1] : "" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[2] ? "晚:" + v.jobTime?.split(",")[2] : "" }}</view>
|
||||
<view v-if="v.addressDes" class="m-t-8rpx flex items-center">
|
||||
<tm-icon name="map-pin-2-line" color="#A6AEB8" :size="26" />
|
||||
<text class="second-text-24 m-l-8rpx flex-1 min-w-0 show-line">{{ v.addressDes }}</text>
|
||||
</view>
|
||||
<view v-if="v.addressDes" class="second-text-28">
|
||||
<image class="w-24rpx h-24rpx" src="@/static/page/address.svg" />
|
||||
<text class="ml-1">地址:</text>
|
||||
<text class="m-l-10rpx">{{ v.addressDes }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="hasBranch(v)">
|
||||
<view class="branch-toggle" hover-class="branch-toggle-hover" @tap.stop="toggleBranch(v)">
|
||||
<view class="flex items-center">
|
||||
<tm-icon name="store-2-line" color="#0779FD" :size="26" />
|
||||
<text class="branch-toggle-text">分店 · {{ v.mchCount }}家</text>
|
||||
</view>
|
||||
<view class="flex items-center">
|
||||
<text class="branch-toggle-hint">{{ v._expanded ? "收起" : "展开" }}</text>
|
||||
<tm-icon name="arrow-down-s-line" color="#0779FD" :size="26"
|
||||
:class="['chevron', v._expanded ? 'chevron-open' : '']" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="v._expanded" class="branch-panel">
|
||||
<view v-if="v._loading" class="branch-tip">分店加载中...</view>
|
||||
<template v-else>
|
||||
<view v-for="(b, bi) in v._children || []" :key="b.id ?? bi" class="branch-item"
|
||||
hover-class="branch-item-hover" @tap.stop="toBranchDetail(b)">
|
||||
<image v-if="b.logoPic" class="w-56rpx h-56rpx rounded-10rpx bg-#F2F6FA flex-none"
|
||||
:src="filePath(b.logoPic)" mode="aspectFill" />
|
||||
<view v-else class="branch-logo-fallback flex-row-center">
|
||||
<tm-icon name="store-2-line" color="#9BBDF6" :size="28" />
|
||||
</view>
|
||||
<view class="flex-1 min-w-0 m-l-14rpx">
|
||||
<text class="sub-text-26 show-line">{{ b.name }}</text>
|
||||
<view v-if="b.addressDes || b.phone" class="m-t-2rpx">
|
||||
<text class="second-text-22 show-line">{{ b.addressDes || b.phone }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<tm-icon name="arrow-right-s-line" color="#C2C9D2" :size="28" />
|
||||
</view>
|
||||
<view v-if="!(v._children || []).length" class="branch-tip">暂无分店信息</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-hover {
|
||||
opacity: 0.86;
|
||||
}
|
||||
|
||||
.brand-pill {
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(7, 121, 253, 0.1);
|
||||
color: #0779fd;
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.promo-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #fff1f0;
|
||||
color: #f63a36;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.branch-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 24rpx;
|
||||
border-top: 1rpx solid #f0f3f7;
|
||||
}
|
||||
|
||||
.branch-toggle-hover {
|
||||
background: #f5f9ff;
|
||||
}
|
||||
|
||||
.branch-toggle-text {
|
||||
margin-left: 8rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: #0779fd;
|
||||
}
|
||||
|
||||
.branch-toggle-hint {
|
||||
font-size: 22rpx;
|
||||
color: #8fa6c4;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
.chevron {
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
|
||||
.chevron-open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.branch-panel {
|
||||
background: #f8fbff;
|
||||
animation: branch-in 0.22s ease both;
|
||||
}
|
||||
|
||||
@keyframes branch-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10rpx);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.branch-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
}
|
||||
|
||||
.branch-item + .branch-item {
|
||||
border-top: 1rpx solid #eef3fa;
|
||||
}
|
||||
|
||||
.branch-item-hover {
|
||||
background: #eff5fd;
|
||||
}
|
||||
|
||||
.branch-logo-fallback {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 10rpx;
|
||||
background: #eaf2fd;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.branch-tip {
|
||||
padding: 24rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #9aa5b1;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user