数据字典改按需请求、商城爆款改茶品飘香轮播、分类页支持 pid 定位

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chenhao 2026-07-23 08:57:01 +08:00
parent 7083c8d27e
commit 1f98c287cd
9 changed files with 158 additions and 93 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -99,7 +99,8 @@ export default {
this._skipWatch = true
this.loadMore()
this.$emit('refresh', this.list)
this._skipWatch = false
// params deep watcher tick
this.$nextTick(() => { this._skipWatch = false })
},
},
}

View File

@ -68,12 +68,11 @@ window.__currentPath = () => currentPath;
app.use(router);
import pinia from './stores';
import { useDatadicStore, dictCache } from './stores/datadic';
import { useDatadicStore } from './stores/datadic';
import { useUserStore } from './stores/user';
app.use(pinia);
const datadicStore = useDatadicStore()
datadicStore.init()
const userStore = useUserStore()
@ -90,8 +89,11 @@ const userStore = useUserStore()
// });
app.config.globalProperties.$datadic = {
get: (code) => dictCache[code] || null,
getContent: (code) => dictCache[code] ? dictCache[code].contents : '',
get: (code) => datadicStore.fetch(code),
getContent: async (code) => {
const item = await datadicStore.fetch(code)
return item ? item.contents : ''
},
}
app.config.globalProperties.$userInfo = userStore.getUserInfo;

View File

@ -1,53 +1,17 @@
import { defineStore } from 'pinia'
import { get } from '@/api/http'
export let dictCache = {}
const SESSION_KEY = 'dict_cache'
// 按需请求:调用时才拉,不做本地缓存
export const useDatadicStore = defineStore('datadic', {
state: () => ({
dicts: {},
loaded: false
}),
getters: {
getByCode: (state) => (code) => {
return dictCache[code] || null
},
getContent: (code) => {
const item = dictCache[code]
return item ? item.contents : ''
}
},
actions: {
async init() {
// 优先从 sessionStorage 读取缓存
const cached = sessionStorage.getItem(SESSION_KEY)
if (cached) {
try {
dictCache = JSON.parse(cached)
this.dicts = dictCache
this.loaded = true
return
} catch (e) {
sessionStorage.removeItem(SESSION_KEY)
}
}
if (this.loaded) return
async fetch(code) {
try {
// 使用持久请求,防止被路由切换时的 abortAll() 取消
const res = await get('/v1/client/CDatadicsClient', undefined, undefined, undefined, true)
if (res.status === 200 && res.data) {
res.data.forEach(item => {
dictCache[item.code] = item
})
this.dicts = dictCache
this.loaded = true
sessionStorage.setItem(SESSION_KEY, JSON.stringify(dictCache))
}
const res = await get(`/v1/client/CDatadicsClient/${code}`)
return res?.data || null
} catch (e) {
console.error('数据字典加载失败', e)
console.error('数据字典加载失败', code, e)
return null
}
}
}
})
})

View File

@ -1134,53 +1134,74 @@
}
.mall_page__hot {
background: #fff;
border-radius: 2vw;
overflow: hidden;
margin-top: 4vw;
margin-bottom: 4vw;
background-image: linear-gradient(0deg,
#ffffff 0%,
#d5ecd6 100%);
border-radius: 2.67vw;
.mall_page__hot_header {
.box;
.box-align-center;
height: 10vw;
padding: 0vw 2.8vw;
background-color: #ffb43d;
color: #a86906;
height: 12.53vw;
padding: 2.93vw;
color: #2e5d31;
img {
width: 4.27vw;
width: 4.8vw;
}
b {
font-size: 4.8vw;
color: #ffffff;
color: #000000;
margin: 0 3.6vw 0 1.47vw;
}
p {
color: #a86906;
color: #2e5d31;
}
}
.van-swipe {
width: calc(100% - 5.86vw);
}
.mall_page__hot_list {
.box;
// margin-bottom: 3vw;
padding: 4vw 3.33vw;
overflow-x: auto
background-color: #ffffff;
border-radius: 2.67vw;
// padding: 4vw 3.73vw;
padding: 4vw 0;
margin: 0 2.93vw;
.van-swipe-item {
display: grid;
grid-template-columns: repeat(3, 1fr);
row-gap: 3.2vw;
column-gap: 4vw;
box-sizing: border-box;
padding: 0 3.73vw;
}
.van-swipe__indicators {
bottom: 1.6vw;
}
}
.mall_page__hot_item {
.box;
.box-tb;
margin-right: 2.67vw;
width: 34.67vw;
.box-align-start;
width: max-content;
img {
object-fit: contain;
width: 34.67vw;
height: 34.67vw;
background-color: #e5e5e5;
width: 24vw;
height: 24vw;
border-radius: 1.33vw;
}
@ -1188,23 +1209,17 @@
font-size: 3.2vw;
font-weight: bold;
line-height: 4vw;
min-height: 4vw;
max-width: 24.27vw;
color: #333333;
min-height: 8vw;
.text-hide(2);
margin-top: 2.8vw;
}
.mall_page__hot_price--original {
font-size: 3.2vw;
text-decoration: line-through;
// line-height: 4.8vw;
color: #b1b1b1;
margin-top: 1.67vw;
.text-hide(1);
margin-top: 1.6vw;
}
.mall_page__hot_price {
font-size: 4vw;
font-size: 3.47vw;
font-weight: bold;
line-height: 4.8vw;
color: #ea3e23;
}
}

View File

@ -84,7 +84,7 @@
<!-- 用户协议 -->
<van-checkbox icon-size="3.73vw" class="login_page__agreement" v-model="checked"
checked-color="var(--main-color)">
选中即代表同意<a @click.stop="showContract = true">用户协议</a><a @click.stop="showPolicy = true">隐私政策</a>
选中即代表同意<a @click.stop="openContract">用户协议</a><a @click.stop="openPolicy">隐私政策</a>
</van-checkbox>
<!-- 底部链接 -->
@ -106,13 +106,13 @@
<!-- 用户协议弹窗 -->
<van-action-sheet v-model:show="showContract" safe-area-inset-bottom title="用户协议" closeable
style="min-height: 50%; padding: 0px 10px 10px 10px">
<div class="w100 html" v-html="$datadic.getContent('code_yhxy')"></div>
<div class="w100 html" v-html="contractHtml"></div>
</van-action-sheet>
<!-- 隐私政策弹窗 -->
<van-action-sheet v-model:show="showPolicy" safe-area-inset-bottom title="隐私政策" closeable
style="min-height: 50%; padding: 0px 10px 10px 10px">
<div class="w100 html" v-html="$datadic.getContent('code_yszc')"></div>
<div class="w100 html" v-html="policyHtml"></div>
</van-action-sheet>
</template>
@ -137,6 +137,8 @@ export default {
showConfirmPassword: false,
showContract: false,
showPolicy: false,
contractHtml: '',
policyHtml: '',
loading: false,
smsCode: '', //
countdown: {
@ -147,6 +149,14 @@ export default {
}
},
methods: {
async openContract() {
this.showContract = true
this.contractHtml = await this.$datadic.getContent('code_yhxy')
},
async openPolicy() {
this.showPolicy = true
this.policyHtml = await this.$datadic.getContent('code_yszc')
},
init() {
// code
if (sessionStorage.getItem('wx_code_processed') === '1') {

View File

@ -74,7 +74,7 @@
<b><span></span>{{ item.saleprice?.toFixed(2) }}</b>
<span class="r" style="color: #8a8a8a;font-size: 3.2vw;">销量{{
item.salenums
}}</span>
}}</span>
</div>
</div>
</div>
@ -186,6 +186,9 @@ export default {
if (this.$route.query.id) {
this.changeMainById(Number(this.$route.query.id));
}
if (this.$route.query.pid) {
this.selectByPid(Number(this.$route.query.pid));
}
if (this.$route.query.SortType == 2) {
this.searchParams.orderby = 'salenumdown';
}
@ -263,6 +266,52 @@ export default {
this.changeMain(item);
}
},
// pid
selectByPid(pid) {
const third = this.thirdCategories.find(x => x.id === pid);
if (third) {
const first = this.firstCategories.find(x => x.id === third.rootId);
if (first) {
this.mainCategory = first.id;
this.typeName = first.name;
this.selectedSecond = this.secondCategories.filter(x => x.parentId === first.id);
}
this.selectedThird = this.thirdCategories.filter(x => x.parentId === third.parentId);
this.goodsCategoryIndex = this.selectedThird.findIndex(x => x.id === pid) + 1;
this.currentThirdId = pid;
this.queryParams.pid = pid;
this.refreshProductList();
this.$nextTick(() => {
this.secondCategory = third.parentId;
});
return;
}
const second = this.secondCategories.find(x => x.id === pid);
if (second) {
const first = this.firstCategories.find(x => x.id === second.parentId);
if (first) {
this.mainCategory = first.id;
this.typeName = first.name;
this.selectedSecond = this.secondCategories.filter(x => x.parentId === first.id);
}
this.selectedThird = this.thirdCategories.filter(x => x.parentId === pid);
this.goodsCategoryIndex = 0;
this.currentThirdId = '';
this.queryParams.pid = pid;
this.refreshProductList();
this.$nextTick(() => {
this.secondCategory = pid;
});
return;
}
const first = this.firstCategories.find(x => x.id === pid);
if (first) {
this.changeMain(first);
return;
}
this.queryParams.pid = pid;
this.refreshProductList();
},
changeSecond(e) {
if (e) {
this.queryParams.pid = e;

View File

@ -9,8 +9,8 @@
<div class="mall_page__banner">
<van-swipe :autoplay="3000" indicator-color="white" @change="onSwipeChange">
<van-swipe-item v-for="item in data.Carousel">
<a @click="item.link ? $openUrl(item.link) : ''"><img :src="$file(item.img) || '/img/img-avatar-default.png'"
width="100%"></a>
<a @click="item.link ? $openUrl(item.link) : ''"><img
:src="$file(item.img) || '/img/img-avatar-default.png'" width="100%"></a>
</van-swipe-item>
</van-swipe>
</div>
@ -41,18 +41,33 @@
</div>
</div>
<div class="mall_page__hot" v-if="hotData.length > 0">
<div class="mall_page__hot">
<div class="mall_page__hot_header">
<img src="/img/icon-hot.png" alt="">
<b>爆款好物</b>
<p>超多会员已购买</p>
<span class="r" @click="$navigate('Category?SortType=2')">
<b>茶品飘香</b>
<p>精选茶叶礼盒</p>
<span class="r" @click="$navigate('Category?pid=1044')">
查看更多
<van-icon name="arrow" />
</span>
</div>
<div class="mall_page__hot_list">
<van-swipe class="mall_page__hot_list" indicator-color="white" :autoplay="3000">
<van-swipe-item class="contaniar" v-for="(group, gi) in comHotData" :key="gi">
<div class="mall_page__hot_item" v-for="list in group" :key="list.id"
@click="$navigate('GoodsDetail?id=' + list.id)">
<img :src="$file(list.img)" alt="">
<span class="mall_page__hot_title">
{{ list.name }}
</span>
<span class="mall_page__hot_price">
{{ list.saleprice?.toFixed(2) }}
</span>
</div>
</van-swipe-item>
</van-swipe>
<!-- <div class="mall_page__hot_list">
<div class="mall_page__hot_item" v-for="list in hotData" @click="$navigate('GoodsDetail?id=' + list.id)">
<img :src="$file(list.img)" alt="">
<span class="mall_page__hot_title">
@ -65,7 +80,7 @@
{{ list.saleprice?.toFixed(2) }}
</span>
</div>
</div>
</div> -->
</div>
<div class="mall_page__goods">
@ -148,7 +163,7 @@ export default {
this.data.Carousel = res.data
this.bgcolor = res.data?.[0]?.bgcolor || ''
}),
this.$get('/v1/client/EProsClient?recommend=true').then(res => {
this.$get('/v1/client/EProsClient?pid=1044&pageSize=100').then(res => {
this.hotData = res.data.items || []
}),
this.$get('/v1/client/EProcatesClient/3').then(res => {
@ -175,6 +190,13 @@ export default {
btnStyle() {
return this.bgcolor ? { background: this.bgcolor } : {}
},
comHotData() {
const groups = []
for (let i = 0; i < this.hotData.length; i += 9) {
groups.push(this.hotData.slice(i, i + 9))
}
return groups
}
},
}
</script>

View File

@ -4,7 +4,7 @@
<div class="balance_page__top">
<div class="balance_page__line">
<b class="balance_page__title">
当前余额 <van-icon name="question-o" @click.stop="showTerm = true"></van-icon>
当前余额 <van-icon name="question-o" @click.stop="onShowTerm"></van-icon>
</b>
<div v-if="!hide" class="balance_page__record_link" @click="$navigate('CashoutRecord')">
@ -124,7 +124,7 @@
</van-popup>
<van-action-sheet v-model:show="showTerm" safe-area-inset-bottom :title="`${this.$route.meta.title}说明`"
closeable style="min-height: 50%; padding: 0px 10px 10px 10px">
<div class="w100 html" v-html="$datadic.getContent('code_yesm')" />
<div class="w100 html" v-html="termHtml" />
</van-action-sheet>
</BasePage>
@ -158,6 +158,7 @@ export default {
},
loading: false,
showTerm: false,
termHtml: '',
list: [],
isVIP: '',
hide: false,
@ -200,8 +201,9 @@ export default {
this.searchParams.type = e || '';
// this.$refs.baselist.refresh();
},
onShowTerm() {
async onShowTerm() {
this.showTerm = true;
this.termHtml = await this.$datadic.getContent('code_yesm');
}
}
}