feat: 添加静态资源文件及基础组件

- 新增大量图片资源,包括图标、背景图、海报等,用于页面展示
- 添加字体文件及样式配置,支持自定义字体
- 引入 uni-ui 组件库,包括图标、弹窗、日期选择器等常用组件
- 添加网络状态监听、加密工具等基础工具函数
- 配置 Vuex 状态管理,包括购物车数量、热门搜索词等
- 增加页面组件,如用户协议、分销信息、提现状态等
- 配置项目构建和忽略文件,优化开发体验
This commit is contained in:
2026-02-26 17:59:51 +08:00
commit a5c5d753b6
720 changed files with 178840 additions and 0 deletions

View File

@@ -0,0 +1,164 @@
<script>
import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
export default {
props: {
visible: {
type: Boolean,
default: false,
},
cateList:{
type:Array,
default: () => []
},
brandList:{
type:Array,
default: () => []
},
},
data(){
return {
cateGoryList:[],
brand_id: [],
cateId:[],
sid:''
}
},
watch:{
cateList:{
handler(val){
this.cateGoryList = val;
this.cateGoryList.map(item=>{
this.$set(item,'more', true);
})
},
immediate: true
},
},
computed: {
fixedTop() {
// #ifdef MP || APP-PLUS
return uni.getWindowInfo().statusBarHeight
// #endif
// #ifdef H5
return 20
// #endif
},
},
components: {
baseDrawer
},
methods: {
closeDrawer() {
this.$emit('closeDrawer');
},
checkBrand(item){
if(this.brand_id.includes(item.id)){
this.brand_id = this.brand_id.filter(function (ele){return ele != item.id;});
}else{
this.brand_id.push(item.id);
}
},
checkCate(item){
this.sid = item.id;
},
checkMore(item){
item.more = !item.more
},
confirmFilter(){
let data = {
brand_id: this.brand_id.join(','),
sid: this.sid
};
this.$emit('filterChange',data);
},
resetFilter(){
this.brand_id = [];
this.sid = '';
let data = {
brand_id: '',
sid: ''
};
this.$emit('filterChange',data);
}
}
}
</script>
<template>
<view>
<base-drawer mode="right" :visible="visible" background-color="transparent" mask maskClosable
@close="closeDrawer">
<view class="drawer_box bg--w111-fff px-32 h-full">
<scroll-view scroll-y="true" style="height: 100vh;">
<view :style="{height:fixedTop + 'px'}"></view>
<view class="h-80 flex-center fs-34 fw-500 text--w111-333">筛选</view>
<view class="activity_box py-24">
<view v-if="brandList.length">
<view class="fs-28 text--w111-333 fw-500 mt-24">品牌</view>
<view class="grid-column-3 box_gap mt-24">
<view class="h-56 rd-28rpx bg--w111-f5f5f5 flex-center fs-24 text--w111-333"
v-for="item in brandList" :key="item.id"
:class="{active: brand_id.includes(item.id)}"
@tap="checkBrand(item)">
<text class="inline-block w-full line1 px-12 text-center">{{item.brand_name}}</text>
</view>
</view>
</view>
<view v-if="cateGoryList.length">
<view class="fs-28 text--w111-333 fw-500 mt-48">分类</view>
<view v-for="(item,i) in cateGoryList" :key="i">
<view class="flex-between-center mt-48">
<text class='fs-24'>{{item.cate_name}}</text>
<view class="flex-y-center fs-20 text--w111-999 lh-34rpx" @tap="checkMore(item)">
<text>{{ item.more ? '收起' : '展开' }}</text>
<text class="iconfont fs-20" :class="item.more ? 'icon-ic_uparrow' : 'icon-ic_downarrow'"></text>
</view>
</view>
<view class="grid-column-3 box_gap mt-24" v-show="item.more">
<view class="h-56 rd-28rpx bg--w111-f5f5f5 flex-center fs-24 text--w111-333"
v-for="(cate,k) in item.children" :key="k"
:class="{active: cate.id == sid}"
@tap="checkCate(cate)">
<text class="inline-block w-full line1 px-12 text-center">{{cate.cate_name}}</text>
</view>
</view>
</view>
</view>
</view>
<view class="pb-safe">
<view class="h-112"></view>
</view>
</scroll-view>
<view class="fixed-lb pb-safe bg--w111-fff w-full">
<view class="px-32 flex-between-center h-112">
<view class="w-296 h-72 rd-40rpx flex-center text-mer con_border bg--w111-fff"
@tap="resetFilter()">重置</view>
<view class="w-296 h-72 rd-40rpx flex-center text--w111-fff mer-bg" @tap="confirmFilter()">确定</view>
</view>
</view>
</view>
</base-drawer>
</view>
</template>
<style lang="scss">
.drawer_box {
width: 668rpx;
border-radius: 40rpx 0 0 40rpx;
overflow: auto;
}
.box_gap {
grid-row-gap: 24rpx;
grid-column-gap: 26rpx;
}
.con_border{
border: 1rpx solid $primary-merchant;
}
.active{
border: 1px solid $primary-merchant;
color: $primary-merchant;
background: $light-primary-merchant;
}
.text-mer{
color: $primary-merchant;
}
</style>

View File

@@ -0,0 +1,46 @@
<script>
import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
export default {
props: {
visible: {
type: Boolean,
default: false
},
ensureInfo: {
type: Object,
default: () => {}
}
},
components: {
baseDrawer
},
methods: {
closeDrawer() {
this.$emit('closeDrawer');
}
}
};
</script>
<template>
<view>
<base-drawer mode="bottom" :visible="visible" background-color="transparent" mask maskClosable @close="closeDrawer">
<view class="w-full bg--w111-fff rd-t-40rpx py-32">
<view class="text-center fs-32 text--w111-333 fw-500 mb-34">服务</view>
<scroll-view scroll-y="true" class="h-400">
<view class="px-32">
<view class="mb-38" v-for="(item, index) in ensureInfo.ensure" :key="index">
<view class="flex-y-center">
<image class="w-34 h-34" :src="item.image"></image>
<text class="pl-12 text--w111-333 fs-28 fw-500">{{ item.name }}</text>
</view>
<view class="mt-6 pl-40 fs-22 text--w111-999">{{ item.desc }}</view>
</view>
</view>
</scroll-view>
<view class="mx-20 pb-safe">
<view class="mt-52 h-72 flex-center rd-36px mer-bg fs-26 text--w111-fff" @click="closeDrawer">确定</view>
</view>
</view>
</base-drawer>
</view>
</template>

View File

@@ -0,0 +1,134 @@
<template>
<base-drawer mode="bottom" :visible="attr.cartAttr" background-color="transparent" zIndex="3000" mask maskClosable
@close="closeDrawer">
<view>
<view class="bg--w111-fff rd-t-40rpx">
<view class="w-full pt-32">
<view class="px-32 flex">
<image class="w-180 h-180 rd-16rpx" :src="attr.productSelect.image" @tap="showImg"></image>
<view class="pl-24">
<baseMoney :money="attr.productSelect.channel_price" symbolSize="32" integerSize="48"
decimalSize="32" color="#FF7E00" weight></baseMoney>
<view class="mt-20 fs-24 text--w111-999">库存:{{ attr.productSelect.stock }}</view>
</view>
</view>
</view>
<scroll-view class="px-32" scroll-y="true" style="max-height: 400rpx;">
<view class="item mt-32" v-for="(item, indexw) in attr.productAttr" :key="indexw">
<view class="fs-28">{{ item.attr_name }}</view>
<view class="flex-y-center flex-wrap">
<view class="sku-item" :class="item.index === itemn.attr ? 'active' : ''"
v-for="(itemn, indexn) in item.attr_value" @click="tapAttr(indexw, indexn)"
:key="indexn">
{{ itemn.attr }}
</view>
</view>
</view>
</scroll-view>
<view class="flex-between-center px-32 mt-24">
<text class="fs-28">数量</text>
<view class="flex-y-center">
<view class="jia-btn w-84 h-48 flex-center" @click="CartNumAdd(false)">
<text class="iconfont icon-ic_Reduce fs-24"></text>
</view>
<view class='w-84 h-48 text-center lh-48rpx bg--w111-f5f5f5'>{{ attr.productSelect.cart_num }}</view>
<view class="jia-btn w-84 h-48 flex-center" @click="CartNumAdd(true)">
<text class="iconfont icon-ic_increase fs-24"></text>
</view>
</view>
</view>
<view class="mx-20 pb-box">
<view class="mt-52 h-72 flex-center rd-36px mer-bg fs-26 text--w111-fff" @click="confirmCartAdd"
v-if="attr.productSelect.stock">
确定</view>
<view class="mt-52 h-72 flex-center rd-36px bg-gray fs-26 text--w111-fff" v-else>已售罄</view>
</view>
</view>
</view>
</base-drawer>
</template>
<script>
export default {
props:{
attr: {
type: Object,
default: () => {}
},
storeInfo: {
type: Object,
default: () => {}
},
},
data(){
return {
}
},
methods:{
CartNumAdd(type){
this.$emit('ChangeCartNum', type);
},
closeDrawer(){
this.$emit('myevent');
},
confirmCartAdd(){
this.$emit('onConfirm');
},
tapAttr: function(indexw, indexn) {
let that = this;
that.$emit("attrVal", {
indexw: indexw,
indexn: indexn
});
this.$set(this.attr.productAttr[indexw], 'index', this.attr.productAttr[indexw].attr_values[indexn]);
let value = that
.getCheckedValue()
.join(",");
that.$emit("ChangeAttr", value);
},
//获取被选中属性;
getCheckedValue: function() {
let productAttr = this.attr.productAttr;
let value = [];
for (let i = 0; i < productAttr.length; i++) {
for (let j = 0; j < productAttr[i].attr_values.length; j++) {
if (productAttr[i].index === productAttr[i].attr_values[j]) {
value.push(productAttr[i].attr_values[j]);
}
}
}
return value;
},
showImg(){
this.$emit('getImg');
}
}
}
</script>
<style lang="scss">
.sku-item {
height: 56rpx;
line-height: 56rpx;
border: 1px solid #F2F2F2;
font-size: 24rpx;
color: #333;
padding: 0 44rpx;
border-radius: 28rpx;
margin: 24rpx 0 0 16rpx;
background-color: #F2F2F2;
word-break: break-all;
}
.active {
color: $primary-merchant;
background: $light-primary-merchant;
border-color: $primary-merchant;
}
.pb-box{
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
}
.bg-gray{
background-color: #ccc;
}
</style>

View File

@@ -0,0 +1,45 @@
<template>
<!-- 产品参数 -->
<base-drawer mode="bottom" :visible="specsInfo.show" background-color="transparent" mask maskClosable @close="closeSpecs">
<view class="w-full bg--w111-fff rd-t-40rpx py-32">
<view class="text-center fs-32 text--w111-333 fw-500 mb-34">参数</view>
<scroll-view scroll-y="true" class="h-400">
<view class="px-32 scroll-content">
<view class="item flex break_word" v-for="(item,index) in specsInfo.specs" :key="index">
<view class="w-160 text--w111-999 mr-12">{{item.name}}</view>
<view class="flex-1">{{item.value}}</view>
</view>
</view>
</scroll-view>
<view class="mx-20 pb-safe">
<view class="mt-52 h-72 flex-center rd-36px mer-bg fs-26 text--w111-fff" @click="closeSpecs">确定</view>
</view>
</view>
</base-drawer>
</template>
<script>
import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
export default {
props: {
specsInfo: {
type: Object,
default: () => {}
},
},
components: {
baseDrawer
},
methods: {
closeSpecs() {
this.$emit('myevent');
}
}
}
</script>
<style scoped lang="scss">
.item ~ .item{
margin-top: 40rpx;
}
</style>

View File

@@ -0,0 +1,128 @@
<template>
<!-- 底部导航 -->
<keep-alive>
<view class="page-footer">
<view class="foot-item" :class="item.pagePath == activeRouter?'active':''"
v-for="(item,index) in footerList" :key="index" @click="goRouter(item)">
<block v-if="item.pagePath == activeRouter">
<image :src="item.selectedIconPath"></image>
<view class="txt">{{item.text}}</view>
</block>
<block v-else>
<image :src="item.iconPath"></image>
<view class="txt">{{item.text}}</view>
</block>
<uni-badge v-if="index == 1 && cartNum > 0" class="badge-style" :text="cartNum" absolute="rightTop"></uni-badge>
</view>
</view>
</keep-alive>
</template>
<script>
import { mapGetters } from 'vuex';
import {getCartCounts} from '@/api/order.js';
export default {
name: 'footer',
props: {},
created() {
let routes = getCurrentPages(); //获取当前打开过的页面路由数组
let curRoute = routes[routes.length - 1].route //获取当前页面路由
this.activeRouter = '/' + curRoute
},
computed: {
...mapGetters(['isLogin', 'cartNum']),
styleType(){
return this.$store.state.app.system_channel_style;
}
},
data() {
return {
activeRouter:'',
footerList:[
{
pagePath: "/pages/merchant/index/index",
iconPath: require("../../static/1-0.png"),
selectedIconPath: require("../../static/1-1.png"),
text: "首页"
},
{
pagePath: "/pages/merchant/cart/index",
iconPath: require("../../static/2-0.png"),
selectedIconPath: require("../../static/2-1.png"),
text: "购物车"
},
{
pagePath: "/pages/merchant/user/index",
iconPath: require("../../static/3-0.png"),
selectedIconPath: require("../../static/3-1.png"),
text: "我的"
}
],
// cartNum:0
}
},
mounted() {
this.getCartNum();
},
methods: {
goRouter(item) {
var pages = getCurrentPages();
var page = (pages[pages.length - 1]).$page.fullPath;
if (item.pagePath == page) return
uni.redirectTo({
url: item.pagePath,
animationType: 'none' // 关闭默认的滑动效果
});
},
getCartNum() {
this.$store.dispatch('indexData/getCartNum')
},
}
}
</script>
<style scoped lang="scss">
.page-footer {
position: fixed;
bottom: 0;
left:0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
height: calc(100rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
height: calc(100rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
box-sizing: border-box;
border-top: solid 1rpx #F3F3F3;
background-color: #fff;
padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
padding-bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/
.foot-item {
display: flex;
width: max-content;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
padding: 0 20rpx;
&.active {
color: $primary-merchant;
}
}
.foot-item image {
height: 40rpx;
width: 40rpx;
text-align: center;
margin: 0 auto;
}
.foot-item .txt {
font-size: 20rpx;
margin-top: 6rpx;
}
}
</style>

View File

@@ -0,0 +1,11 @@
import CryptoJS from './crypto-js.js'
/**
* @word 要加密的内容
* @keyWord String 服务器随机返回的关键字
* */
export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
var key = CryptoJS.enc.Utf8.parse(keyWord);
var srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
return encrypted.toString();
}

File diff suppressed because it is too large Load Diff

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