发布v1.0.3

This commit is contained in:
kele
2022-11-22 15:45:36 +08:00
commit 01f091fcd8
525 changed files with 80922 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
<template>
<s-layout title="购物车" tabbar="/pages/index/cart" :bgStyle="{ color: '#fff' }">
<s-empty
v-if="state.list.length === 0"
text="购物车空空如也,快去逛逛吧~"
icon="/static/cart-empty.png"
/>
<!-- 头部 -->
<view class="cart-box ss-flex ss-flex-col ss-row-between" v-if="state.list.length">
<view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
<view class="header-left ss-flex ss-col-center ss-font-26">
<text class="goods-number ui-TC-Main ss-flex">{{ state.list.length }}</text>
件商品
</view>
<view class="header-right">
<button v-if="state.editMode" class="ss-reset-button" @tap="state.editMode = false">
取消
</button>
<button v-else class="ss-reset-button ui-TC-Main" @tap="state.editMode = true">
编辑
</button>
</view>
</view>
<!-- 内容 -->
<view class="cart-content ss-flex-1 ss-p-x-30 ss-m-b-40">
<view class="goods-box ss-r-10 ss-m-b-14" v-for="item in state.list" :key="item.id">
<view class="ss-flex ss-col-center">
<view class="check-box ss-flex ss-col-center ss-p-l-10" @tap="onSelectSingle(item.id)">
<radio
:checked="state.selectedIds.includes(item.id)"
color="var(--ui-BG-Main)"
style="transform: scale(0.8)"
/>
</view>
<s-goods-item
:title="item.goods.title"
:img="item.sku_price.image || item.goods.image"
:price="item.sku_price.price"
:skuText="item.sku_price.goods_sku_text"
priceColor="#FF3000"
:titleWidth="400"
>
<template v-if="!state.editMode" v-slot:tool>
<su-number-box
:min="0"
:max="item.sku_price.stock"
:step="1"
v-model="item.goods_num"
@change="onNumberChange($event, item)"
></su-number-box>
</template>
</s-goods-item>
</view>
</view>
</view>
<!-- 底部 -->
<su-fixed bottom :val="48" placeholder v-if="state.list.length > 0" :isInset="false">
<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
<view class="footer-left ss-flex ss-col-center">
<view class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
<radio
:checked="state.isAllSelected"
color="var(--ui-BG-Main)"
style="transform: scale(0.7)"
/>
<view> 全选 </view>
</view>
<text>合计</text>
<view class="text-price price-text">
{{ state.totalPriceSelected }}
</view>
</view>
<view class="footer-right">
<button
v-if="state.editMode"
class="ss-reset-button ui-BG-Main-Gradient pay-btn ui-Shadow-Main"
@tap="onDelete"
>
删除
</button>
<button
v-else
class="ss-reset-button ui-BG-Main-Gradient pay-btn ui-Shadow-Main"
@tap="onConfirm"
>
去结算
{{ state.selectedIds?.length ? `(${state.selectedIds.length})` : '' }}
</button>
</view>
</view>
</su-fixed>
</view>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { computed, reactive, unref } from 'vue';
const sys_navBar = sheep.$platform.navbar;
const cart = sheep.$store('cart');
const state = reactive({
editMode: false,
list: computed(() => cart.list),
selectedList: [],
selectedIds: computed(() => cart.selectedIds),
isAllSelected: computed(() => cart.isAllSelected),
totalPriceSelected: computed(() => cart.totalPriceSelected),
});
// 单选选中
function onSelectSingle(id) {
cart.selectSingle(id);
}
// 全选
function onSelectAll() {
cart.selectAll(!state.isAllSelected);
}
// 结算
function onConfirm() {
let goods_list = [];
state.selectedList = state.list.filter((item) => state.selectedIds.includes(item.id));
state.selectedList.map((item) => {
goods_list.push({
goods_id: item.goods_id,
goods_num: item.goods_num,
goods_sku_price_id: item.goods_sku_price_id,
});
});
if (goods_list.length === 0) {
sheep.$helper.toast('请选择商品');
return;
}
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
order_type: 'goods',
goods_list,
from: 'cart',
}),
});
}
function onNumberChange(e, cartItem) {
if (e === 0) {
cart.delete(cartItem.id);
return;
}
cart.update({
goods_id: cartItem.goods_id,
goods_num: e,
goods_sku_price_id: cartItem.goods_sku_price_id,
});
}
async function onDelete() {
cart.delete(state.selectedIds);
}
</script>
<style lang="scss" scoped>
:deep(.ui-fixed) {
height: 72rpx;
}
.cart-box {
width: 100%;
.cart-header {
height: 70rpx;
background-color: #f6f6f6;
width: 100%;
position: fixed;
left: 0;
top: v-bind('sys_navBar') rpx;
z-index: 1000;
box-sizing: border-box;
}
.cart-footer {
height: 100rpx;
background-color: #fff;
.pay-btn {
width: 180rpx;
height: 70rpx;
font-size: 28rpx;
line-height: 28rpx;
font-weight: 500;
border-radius: 40rpx;
}
}
.cart-content {
margin-top: 70rpx;
.goods-box {
background-color: #fff;
}
}
}
</style>
+250
View File
@@ -0,0 +1,250 @@
<template>
<s-layout title="分类" tabbar="/pages/index/category" :bgStyle="{ color: '#fff' }">
<view class="s-category">
<view class="three-level-wrap ss-flex ss-col-top" :style="[{ height: pageHeight + 'px' }]">
<scroll-view class="side-menu-wrap" scroll-y :style="[{ height: pageHeight + 'px' }]">
<view
class="menu-item ss-flex"
v-for="(item, index) in state.categoryList?.children"
:key="item.id"
:class="[{ 'menu-item-active': index == state.activeMenu }]"
@tap="onMenu(index)"
>
<view class="menu-title ss-line-1">
{{ item.name }}
</view>
</view>
</scroll-view>
<scroll-view
class="goods-list-box"
scroll-y
:style="[{ height: pageHeight + 'px' }]"
v-if="state.categoryList?.children?.length"
>
<image
v-if="state.categoryList.children[state.activeMenu].image"
class="banner-img"
:src="sheep.$url.cdn(state.categoryList.children[state.activeMenu].image)"
mode="widthFix"
>
</image>
<first-one
v-if="state.categoryList.style === 'first_one'"
:data="state.categoryList"
:activeMenu="state.activeMenu"
:pagination="state.pagination"
/>
<first-two
v-if="state.categoryList.style === 'first_two'"
:data="state.categoryList"
:activeMenu="state.activeMenu"
:pagination="state.pagination"
/>
<second-one
v-if="state.categoryList.style === 'second_one'"
:data="state.categoryList"
:activeMenu="state.activeMenu"
:pagination="state.pagination"
/>
<third-one
v-if="state.categoryList.style === 'third_one'"
:data="state.categoryList"
:activeMenu="state.activeMenu"
:pagination="state.pagination"
/>
<uni-load-more
v-if="
(state.categoryList.style === 'first_one' ||
state.categoryList.style === 'first_two') &&
state.pagination.total > 0
"
:status="state.loadStatus"
:content-text="{
contentdown: '点击查看更多',
}"
@tap="loadmore"
/>
</scroll-view>
</view>
</view>
</s-layout>
</template>
<script setup>
import secondOne from './components/second-one.vue';
import thirdOne from './components/third-one.vue';
import firstOne from './components/first-one.vue';
import firstTwo from './components/first-two.vue';
import sheep from '@/sheep';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { computed, reactive } from 'vue';
import _ from 'lodash';
const state = reactive({
categoryList: [],
activeMenu: '0',
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
},
loadStatus: '',
});
const { screenHeight, safeAreaInsets, screenWidth, safeArea } = sheep.$platform.device;
const pageHeight = computed(() => safeArea.height - 44 - 50);
async function getList(options) {
const { error, data } = await sheep.$api.category.list({
id: options.id,
});
if (error === 0) {
state.categoryList = data;
}
}
const onMenu = (val) => {
state.activeMenu = val;
if (state.categoryList.style === 'first_one' || state.categoryList.style === 'first_two') {
state.pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
};
getGoodsList(state.categoryList.children[val].id);
}
};
async function getGoodsList(id, page = 1, list_rows = 6) {
state.loadStatus = 'loading';
const res = await sheep.$api.goods.list({
category_id: id,
list_rows,
page,
});
if (res.error === 0) {
let couponList = _.concat(state.pagination.data, res.data.data);
state.pagination = {
...res.data,
data: couponList,
};
if (state.pagination.current_page < state.pagination.last_page) {
state.loadStatus = 'more';
} else {
state.loadStatus = 'noMore';
}
}
}
// 加载更多
function loadmore() {
if (state.loadStatus !== 'noMore') {
getGoodsList(
state.categoryList.children[state.activeMenu].id,
state.pagination.current_page + 1,
);
}
}
onLoad(async (options) => {
await getList(options);
if (state.categoryList.style === 'first_one' || state.categoryList.style === 'first_two') {
getGoodsList(state.categoryList.children[0].id);
}
});
onReachBottom(() => {
loadmore();
});
</script>
<style lang="scss" scoped>
.s-category {
:deep() {
.side-menu-wrap {
width: 200rpx;
height: 100%;
padding-left: 12rpx;
background-color: #f6f6f6;
.menu-item {
width: 100%;
height: 88rpx;
position: relative;
transition: all linear 0.2s;
.menu-title {
line-height: 32rpx;
font-size: 30rpx;
font-weight: 400;
color: #333;
margin-left: 28rpx;
position: relative;
z-index: 0;
&::before {
content: '';
width: 64rpx;
height: 12rpx;
background: linear-gradient(
90deg,
var(--ui-BG-Main-gradient),
var(--ui-BG-Main-light)
) !important;
position: absolute;
left: -64rpx;
bottom: 0;
z-index: -1;
transition: all linear 0.2s;
}
}
&.menu-item-active {
background-color: #fff;
border-radius: 20rpx 0 0 20rpx;
&::before {
content: '';
position: absolute;
right: 0;
bottom: -20rpx;
width: 20rpx;
height: 20rpx;
background: radial-gradient(circle at 0 100%, transparent 20rpx, #fff 0);
}
&::after {
content: '';
position: absolute;
top: -20rpx;
right: 0;
width: 20rpx;
height: 20rpx;
background: radial-gradient(circle at 0% 0%, transparent 20rpx, #fff 0);
}
.menu-title {
font-weight: 600;
&::before {
left: 0;
}
}
}
}
}
.goods-list-box {
background-color: #fff;
width: calc(100vw - 100px);
padding: 10px;
}
.banner-img {
width: calc(100vw - 130px);
border-radius: 5px;
margin-bottom: 20rpx;
}
}
}
</style>
+29
View File
@@ -0,0 +1,29 @@
<template>
<view class="ss-flex-col">
<view class="goods-box" v-for="item in pagination.data" :key="item.id">
<s-goods-column
size="sl"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
></s-goods-column>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
activeMenu: [Number, String],
pagination: Object,
});
</script>
<style lang="scss" scoped>
.goods-box {
width: 100%;
}
</style>
+69
View File
@@ -0,0 +1,69 @@
<!-- 页面 -->
<template>
<view>
<view class="ss-flex flex-wrap">
<view class="goods-box" v-for="item in pagination?.data" :key="item.id">
<view @click="sheep.$router.go('/pages/goods/index', { id: item.id })">
<view class="goods-img">
<image class="goods-img" :src="sheep.$url.cdn(item.image)" mode="aspectFit"></image>
</view>
<view class="goods-content">
<view class="goods-title ss-line-1 ss-m-b-28">{{ item.title }}</view>
<view class="goods-price">{{ item.price[0] }}</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
activeMenu: [Number, String],
pagination: Object,
});
</script>
<style lang="scss" scoped>
.goods-box {
width: calc((100% - 20rpx) / 2);
margin-bottom: 20rpx;
.goods-img {
width: 100%;
height: 246rpx;
border-radius: 10rpx 10rpx 0px 0px;
}
.goods-content {
width: 100%;
background: #ffffff;
box-shadow: 0px 0px 20rpx 4rpx rgba(199, 199, 199, 0.22);
padding: 20rpx 0 32rpx 16rpx;
box-sizing: border-box;
border-radius: 0 0 10rpx 10rpx;
.goods-title {
font-size: 26rpx;
font-weight: bold;
color: #333333;
}
.goods-price {
font-size: 24rpx;
font-family: OPPOSANS;
font-weight: 500;
color: #e1212b;
}
}
&:nth-child(2n + 1) {
margin-right: 20rpx;
}
}
</style>
+73
View File
@@ -0,0 +1,73 @@
<!-- 页面 -->
<template>
<view>
<view class="title-box ss-flex ss-col-center ss-row-center ss-p-b-30">
<view class="title-line-left"></view>
<view class="title-text ss-p-x-20">{{ props.data.children[activeMenu].name }}</view>
<view class="title-line-right"></view>
</view>
<view class="goods-item-box ss-flex ss-flex-wrap ss-p-b-20">
<view
class="goods-item"
v-for="item in props.data.children[activeMenu].children"
:key="item.id"
>
<image class="goods-img" :src="sheep.$url.cdn(item.image)" mode="aspectFill"></image>
<view class="ss-p-10">
<view class="goods-title ss-line-1">{{ item.name }}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
activeMenu: [Number, String],
pagination: Object,
});
</script>
<style lang="scss" scoped>
.title-box {
.title-line-left,
.title-line-right {
width: 15px;
height: 1px;
background: #d2d2d2;
}
}
.goods-item {
width: calc((100% - 20px) / 3);
margin-right: 10px;
margin-bottom: 10px;
&:nth-of-type(3n) {
margin-right: 0;
}
.goods-img {
width: calc((100vw - 140px) / 3);
height: calc((100vw - 140px) / 3);
}
.goods-title {
font-size: 26rpx;
font-weight: bold;
color: #333333;
line-height: 40rpx;
text-align: center;
}
.goods-price {
color: $red;
line-height: 40rpx;
}
}
</style>
+92
View File
@@ -0,0 +1,92 @@
<!-- 页面 -->
<template>
<view>
<view v-for="item in props.data.children[activeMenu].children" :key="item.id">
<view class="title-box ss-flex ss-col-center ss-row-between ss-p-b-30">
<view class="title-text">{{ item.name }}</view>
<button
class="ss-reset-button more-btn"
@tap="
sheep.$router.go('/pages/goods/list', {
categoryId: item.id,
})
"
>
查看更多
<text class="cicon-forward"></text>
</button>
</view>
<view class="goods-item-box ss-flex ss-flex-wrap ss-p-b-20">
<view class="goods-item" v-for="i in item.children" :key="i">
<view
@tap="
sheep.$router.go('/pages/goods/list', {
categoryId: i.id,
})
"
>
<image class="goods-img" :src="sheep.$url.cdn(i.image)" mode="aspectFill"></image>
<view class="ss-p-10">
<view class="goods-title ss-line-1">{{ i.name }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
activeMenu: [Number, String],
pagination: Object,
});
</script>
<style lang="scss" scoped>
.title-box {
.title-text {
font-size: 28rpx;
font-weight: bold;
color: #333333;
}
.more-btn {
font-size: 26rpx;
font-weight: 400;
color: #999999;
}
}
.goods-item {
width: calc((100% - 20px) / 3);
margin-right: 10px;
margin-bottom: 10px;
&:nth-of-type(3n) {
margin-right: 0;
}
.goods-img {
width: calc((100vw - 140px) / 3);
height: calc((100vw - 140px) / 3);
}
.goods-title {
font-size: 24rpx;
font-weight: 500;
color: #333333;
text-align: center;
}
.goods-price {
color: $red;
line-height: 40rpx;
}
}
</style>
+67
View File
@@ -0,0 +1,67 @@
<template>
<view>
<s-layout
title="首页"
navbar="custom"
tabbar="/pages/index/index"
:bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar"
onShareAppMessage
>
<s-block v-for="(item, index) in template.data" :key="index" :styles="item.style">
<s-block-item :type="item.type" :data="item.data" :styles="item.style" />
</s-block>
<!-- 广告模块 -->
<s-popup-image />
</s-layout>
</view>
</template>
<script setup>
import { computed } from 'vue';
import { onLoad, onPageScroll, onPullDownRefresh } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import $share from '@/sheep/platform/share';
// 隐藏原生tabBar
uni.hideTabBar();
const template = computed(() => sheep.$store('app').template.home);
onLoad((options) => {
// #ifdef MP
// 小程序识别二维码
if (options.scene) {
const sceneParams = decodeURIComponent(options.scene).split('=');
options[sceneParams[0]] = sceneParams[1];
}
// #endif
// 预览模板
if (options.templateId) {
sheep.$store('app').init(options.templateId);
}
// 解析分享信息
if (options.spm) {
$share.decryptSpm(options.spm);
}
// 进入指定页面(完整页面路径)
if (options.page) {
sheep.$router.go(decodeURIComponent(options.page));
}
});
// 下拉刷新
onPullDownRefresh(() => {
sheep.$store('app').init();
setTimeout(function () {
uni.stopPullDownRefresh();
}, 800);
});
onPageScroll(() => {});
</script>
<style></style>
+39
View File
@@ -0,0 +1,39 @@
<template>
<!-- 空登陆页 -->
<view></view>
</template>
<script setup>
import { isEmpty } from 'lodash';
import sheep from '@/sheep';
import { onLoad, onShow } from '@dcloudio/uni-app';
onLoad(async (options) => {
// #ifdef H5
let event = '';
if (options.login_code) {
event = 'login';
const { error } = await sheep.$platform.useProvider().login(options.login_code);
if (error === 0) {
sheep.$store('user').getInfo();
}
}
if (options.bind_code) {
event = 'bind';
const { error } = await sheep.$platform.useProvider().bind(options.bind_code);
}
// 检测H5登录回调
let returnUrl = uni.getStorageSync('returnUrl');
if (returnUrl) {
uni.removeStorage('returnUrl');
location.replace(returnUrl);
} else {
uni.switchTab({
url: '/',
});
}
// #endif
});
</script>
+51
View File
@@ -0,0 +1,51 @@
<template>
<s-layout
:title="page.name"
navbar="custom"
:bgStyle="page.style?.background"
:navbarStyle="page.style?.navbar"
onShareAppMessage
>
<s-block v-for="(item, index) in page.list" :key="index" :styles="item.style">
<s-block-item :type="item.type" :data="item.data" :styles="item.style" />
</s-block>
</s-layout>
</template>
<script setup>
import { computed, reactive } from 'vue';
import sheep from '@/sheep';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
const page = reactive({
name: '',
list: [],
style: {},
});
onLoad(async (options) => {
let id;
if (options.id) {
id = options.id;
}
// #ifdef MP
// 小程序预览自定义页面
if (options.scene) {
const sceneParams = decodeURIComponent(options.scene).split('=');
id = sceneParams[1];
}
// #endif
const { error, data } = await sheep.$api.app.page(id);
if (error === 0) {
page.name = data.name;
page.list = data.diypage?.page?.data;
page.style = data.diypage?.page?.style;
}
});
onPageScroll(() => {});
</script>
<style></style>
+116
View File
@@ -0,0 +1,116 @@
<template>
<s-layout class="set-wrap" title="搜索" :bgStyle="{ color: '#FFF' }">
<view class="ss-p-x-24">
<view class="ss-flex ss-col-center">
<uni-search-bar
class="ss-flex-1"
radius="33"
placeholder="请输入关键字"
cancelButton="none"
:focus="true"
@confirm="onSearch"
/>
</view>
<view class="ss-flex ss-row-between ss-col-center">
<view class="serach-history">搜索历史</view>
<button class="clean-history ss-reset-button" @tap="onDelete"> 清除搜索历史 </button>
</view>
<view class="ss-flex ss-col-center ss-row-left ss-flex-wrap">
<button
class="history-btn ss-reset-button"
@tap="onSearch(item)"
v-for="(item, index) in state.historyTag"
:key="index"
>
{{ item }}
</button>
</view>
</view>
</s-layout>
</template>
<script setup>
import { computed, reactive } from 'vue';
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
const state = reactive({
historyTag: [],
});
function onSearch(res) {
if (res.value) {
if (!state.historyTag.includes(res.value)) {
let search = getArr(state.historyTag, res.value);
uni.setStorageSync('searchHistory', search);
sheep.$router.go('/pages/goods/list', { keyword: res.value });
} else {
sheep.$router.go('/pages/goods/list', { keyword: res.value });
}
} else {
sheep.$router.go('/pages/goods/list', { keyword: res });
}
}
function getArr(list, item) {
let arr = list;
let length = 10; //队列长度
arr.length < length ? arr.unshift(item) : arr.pop();
return arr;
}
function onDelete() {
uni.showModal({
title: '提示',
content: '确认清除搜索历史吗?',
success: function (res) {
if (res.confirm) {
state.historyTag = [];
uni.removeStorageSync('search');
}
},
});
}
onLoad(() => {
uni.getStorage({
key: 'searchHistory',
success: function (res) {
state.historyTag = res.data;
},
});
});
</script>
<style lang="scss" scoped>
.serach-title {
font-size: 30rpx;
font-weight: 500;
color: #333333;
}
.uni-searchbar {
padding-left: 0;
}
.serach-history {
font-weight: bold;
color: #333333;
font-size: 30rpx;
}
.clean-history {
font-weight: 500;
color: #999999;
font-size: 28rpx;
}
.history-btn {
padding: 0 38rpx;
height: 60rpx;
background: #f5f6f8;
border-radius: 30rpx;
font-size: 28rpx;
color: #333333;
max-width: 690rpx;
margin: 0 20rpx 20rpx 0;
}
</style>
+42
View File
@@ -0,0 +1,42 @@
<template>
<s-layout
title="我的"
tabbar="/pages/index/user"
navbar="custom"
:bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar"
onShareAppMessage
:showFloatButton="true"
>
<s-block v-for="(item, index) in template.data" :key="index" :styles="item.style">
<s-block-item :type="item.type" :data="item.data" :styles="item.style" />
</s-block>
</s-layout>
</template>
<script setup>
import { computed } from 'vue';
import { onShow, onPageScroll, onPullDownRefresh } from '@dcloudio/uni-app';
import sheep from '@/sheep';
// 隐藏原生tabBar
uni.hideTabBar();
const template = computed(() => sheep.$store('app').template.user);
const isLogin = computed(() => sheep.$store('user').isLogin);
onShow(() => {
sheep.$store('user').updateUserData();
});
onPullDownRefresh(() => {
sheep.$store('user').updateUserData();
setTimeout(function () {
uni.stopPullDownRefresh();
}, 800);
});
onPageScroll(() => {});
</script>
<style></style>