清空代码-初始化yudao

pull/29/head
落日晚风 2023-12-18 14:02:47 +08:00
parent aad925ed51
commit 4cb256af6c
102 changed files with 4959 additions and 7836 deletions

1429
pages.json

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
<!-- 页面 -->
<template>
<s-layout title="积分商城">
<view class="ss-p-20">
<view v-for="item in state.pagination.data" :key="item.id" class="ss-m-b-20">
<s-score-card
size="sl"
:data="item"
priceColor="#FF3000"
@tap="sheep.$router.go('/pages/goods/score', { id: item.id })"
></s-score-card>
</view>
</view>
<s-empty
v-if="state.pagination.total === 0"
icon="/static/goods-empty.png"
text="暂无积分商品"
></s-empty>
<uni-load-more
v-if="state.pagination.total > 0"
:status="state.loadStatus"
:content-text="{
contentdown: '上拉加载更多',
}"
@tap="loadmore"
/>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import _ from 'lodash';
const state = reactive({
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
},
loadStatus: '',
});
async function getData(page = 1, list_rows = 5) {
state.loadStatus = 'loading';
let res = await sheep.$api.app.scoreShop.list({
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') {
getData(state.pagination.current_page + 1);
}
}
//
onReachBottom(() => {
loadmore();
});
onLoad(() => {
getData();
});
</script>

View File

@ -1,350 +1,378 @@
<!-- 优惠券详情 -->
<template>
<s-layout title="优惠券详情">
<view class="bg-white">
<!-- 详情卡片 -->
<view class="detail-wrap ss-p-20">
<view class="detail-box">
<view class="tag-box ss-flex ss-col-center ss-row-center">
<image class="tag-image" :src="sheep.$url.static('/static/img/shop/app/coupon_icon.png')"
mode="aspectFit"></image>
</view>
<view class="top ss-flex-col ss-col-center">
<view class="title ss-m-t-50 ss-m-b-20 ss-m-x-20">{{ state.list.name }}</view>
<view class="subtitle ss-m-b-50">{{ state.list.enough }}{{ state.list.amount }}</view>
<!-- (state.list.get_status != 'can_get' && state.list.get_status != 'can_use') ||
state.userCouponId -->
<button class="ss-reset-button ss-m-b-30" :class="
state.list.get_status == 'can_get' || state.list.get_status == 'can_use'
? 'use-btn'
: 'disable-btn' " :disabled="state.list.status_text=='已过期'" @click="getCoupon">
<!-- {{ state.list.get_status_text }} -->
立即使用
</button>
<view class="time ss-m-y-30" v-if="
state.list.get_status == 'can_get' ||
state.list.get_status == 'cannot_get' ||
state.list.get_status == 'get_over'
">
领取时间{{ state.list.get_start_time }}{{ state.list.get_end_time }}
</view>
<view class="time ss-m-y-30" v-else>
有效期{{ state.list.use_start_time }}{{ state.list.use_end_time }}
</view>
<view class="coupon-line ss-m-t-14"></view>
</view>
<view class="bottom">
<view class="type ss-flex ss-col-center ss-row-between ss-p-x-30">
<view>优惠券类型</view>
<view>{{ state.list.type_text }}</view>
</view>
<uni-collapse>
<uni-collapse-item title="优惠券说明" v-if="state.list.description">
<view class="content ss-p-b-20">
<text class="des ss-p-l-30">{{ state.list.description }}</text>
</view>
</uni-collapse-item>
</uni-collapse>
</view>
</view>
</view>
<!-- 适用商品 -->
<view class="all-user ss-flex ss-row-center ss-col-center" v-if="state.list.use_scope == 'all_use'">
{{ state.list.use_scope_text }}
</view>
<s-layout title="优惠券详情">
<view class="bg-white">
<!-- 详情卡片 -->
<view class="detail-wrap ss-p-20">
<view class="detail-box">
<view class="tag-box ss-flex ss-col-center ss-row-center">
<image
class="tag-image"
:src="sheep.$url.static('/static/img/shop/app/coupon_icon.png')"
mode="aspectFit"
/>
</view>
<view class="top ss-flex-col ss-col-center">
<view class="title ss-m-t-50 ss-m-b-20 ss-m-x-20">{{ state.coupon.name }}</view>
<view class="subtitle ss-m-b-50">
{{ fen2yuan(state.coupon.usePrice) }}
{{ state.coupon.discountType === 1
? '减 ' + fen2yuan(state.coupon.discountPrice) + ' 元'
: '打 ' + state.coupon.discountPercent / 10.0 + ' 折' }}
</view>
<button
class="ss-reset-button ss-m-b-30"
:class="state.coupon.canTake || state.coupon.status === 1
? 'use-btn' // 使
: 'disable-btn'
"
:disabled="!state.coupon.canTake"
@click="getCoupon"
>
<text v-if="state.id > 0">{{ state.coupon.canTake ? '' : '' }}</text>
<text v-else>
{{ state.coupon.status === 1 ? '立即使用' : state.coupon.status === 2 ? '已使用' : '已过期' }}
</text>
</button>
<view class="time ss-m-y-30" v-if="state.coupon.validityType === 2">
有效期领取后 {{ state.coupon.fixedEndTerm }} 天内可用
</view>
<view class="time ss-m-y-30" v-else>
有效期: {{ sheep.$helper.timeFormat(state.coupon.validStartTime, 'yyyy-mm-dd') }}
{{ sheep.$helper.timeFormat(state.coupon.validEndTime, 'yyyy-mm-dd') }}
</view>
<view class="coupon-line ss-m-t-14"></view>
</view>
<view class="bottom">
<view class="type ss-flex ss-col-center ss-row-between ss-p-x-30">
<view>优惠券类型</view>
<view>{{ state.coupon.discountType === 1 ? '满减券' : '折扣券' }}</view>
</view>
<!-- TODO 芋艿可优化增加优惠劵的描述 -->
<uni-collapse>
<uni-collapse-item title="优惠券说明" v-if="state.coupon.description">
<view class="content ss-p-b-20">
<text class="des ss-p-l-30">{{ state.coupon.description }}</text>
</view>
</uni-collapse-item>
</uni-collapse>
</view>
</view>
</view>
<su-sticky v-else bgColor="#fff">
<view class="goods-title ss-p-20">{{ state.list.use_scope_text }}</view>
<su-tabs :scrollable="true" :list="state.tabMaps" @change="onTabsChange" :current="state.currentTab"
v-if="state.list.use_scope == 'category'"></su-tabs>
</su-sticky>
<view v-if="state.list.use_scope == 'goods' || state.list.use_scope == 'disabled_goods'">
<view v-for="(item, index) in state.list.items_value" :key="index">
<s-goods-column class="ss-m-20" size="lg" :data="item"
:titleColor="props.goodsFieldsStyle?.title?.color"
:subTitleColor="props.goodsFieldsStyle?.subtitle?.color"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })" :goodsFields="{
<!-- 适用商品 -->
<view
class="all-user ss-flex ss-row-center ss-col-center"
v-if="state.coupon.productScope === 1"
>
全场通用
</view>
<su-sticky v-else bgColor="#fff">
<view class="goods-title ss-p-20">
{{ state.coupon.productScope === 2 ? '指定商品可用' : '指定分类可用' }}
</view>
<su-tabs
:scrollable="true"
:list="state.tabMaps"
@change="onTabsChange"
:current="state.currentTab"
v-if="state.coupon.productScope === 3"
/>
</su-sticky>
<!-- 指定商品 -->
<view v-if="state.coupon.productScope === 2">
<view v-for="(item, index) in state.pagination.list" :key="index">
<s-goods-column
class="ss-m-20"
size="lg"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
:goodsFields="{
title: { show: true },
subtitle: { show: true },
price: { show: true },
original_price: { show: true },
sales: { show: true },
stock: { show: false },
}" :buttonShow="state.list.use_scope != 'disabled_goods'"></s-goods-column>
</view>
</view>
<view v-if="state.list.use_scope == 'category'">
<view v-for="(item, index) in state.pagination.data" :key="index">
<s-goods-column class="ss-m-20" size="lg" :data="item"
:titleColor="props.goodsFieldsStyle?.title?.color"
:subTitleColor="props.goodsFieldsStyle?.subtitle?.color"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })" :goodsFields="{
}"
/>
</view>
</view>
<!-- 指定分类 -->
<view v-if="state.coupon.productScope === 3">
<view v-for="(item, index) in state.pagination.list" :key="index">
<s-goods-column
class="ss-m-20"
size="lg"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
:goodsFields="{
title: { show: true },
subtitle: { show: true },
price: { show: true },
original_price: { show: true },
sales: { show: true },
stock: { show: false },
}" :buttonShow="state.list.use_scope != 'disabled_goods'"></s-goods-column>
</view>
</view>
<uni-load-more v-if="state.pagination.total > 0 && state.list.use_scope == 'category'"
:status="state.loadStatus" :content-text="{
}"
></s-goods-column>
</view>
</view>
<uni-load-more
v-if="state.pagination.total > 0 && state.coupon.productScope === 3"
:status="state.loadStatus"
:content-text="{
contentdown: '上拉加载更多',
}" @tap="loadmore" />
<s-empty v-if="state.list.use_scope == 'category' && state.pagination.total === 0" paddingTop="0"
icon="/static/soldout-empty.png" text="暂无商品">
</s-empty>
</view>
</s-layout>
}"
@tap="loadMore"
/>
<s-empty
v-if="state.coupon.productScope === 3 && state.pagination.total === 0"
paddingTop="0"
icon="/static/soldout-empty.png"
text="暂无商品"
/>
</view>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import {
reactive
} from 'vue';
import _ from 'lodash';
import sheep from '@/sheep';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import _ from 'lodash';
import CouponApi from '@/sheep/api/promotion/coupon';
import { fen2yuan } from '@/sheep/hooks/useGoods';
import SpuApi from '@/sheep/api/product/spu';
import CategoryApi from '@/sheep/api/product/category';
import { resetPagination } from '@/sheep/util';
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
};
const state = reactive({
list: {},
couponId: 0,
userCouponId: 0,
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
},
tabMaps: [],
loadStatus: '',
categoryId: 0,
});
const state = reactive({
id: 0, // templateId
couponId: 0, // couponId
coupon: {}, //
//
const props = defineProps({
includes: {
type: Array,
default () {
return [];
},
},
list: {
type: Array,
default: () => [],
},
goodsFieldsStyle: {
type: Object,
default () {},
},
buyData: {
type: Object,
default () {},
},
});
pagination: {
list: [],
total: 0,
pageNo: 1,
pageSize: 1,
},
categoryId: 0, //
tabMaps: [], // tab
currentTab: 0, // tabMaps
loadStatus: '',
});
function onTabsChange(e) {
state.pagination = pagination;
state.currentTab = e.index;
state.categoryId = e.value;
getGoodsList(state.categoryId);
}
async function getGoodsList(categoryId, page = 1, list_rows = 5) {
state.loadStatus = 'loading';
const res = await sheep.$api.goods.list({
category_id: categoryId,
list_rows,
page,
is_category_deep: false,
});
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';
}
}
}
async function getCoupon() {
const {
error,
msg
} = await sheep.$api.coupon.get(state.couponId);
if (error === 0) {
uni.showToast({
title: msg,
});
setTimeout(() => {
getCouponContent(state.couponId, state.userCouponId);
}, 1000);
}
}
async function getCouponContent(id, c) {
const {
data
} = await sheep.$api.coupon.detail(id, c);
state.list = data;
data.items_value.forEach((i) => {
state.tabMaps.push({
name: i.name,
value: i.id
});
});
state.pagination = pagination;
if (state.list.use_scope == 'category') {
getGoodsList(state.tabMaps[0].value);
}
}
//
function loadmore() {
if (state.loadStatus !== 'noMore') {
getGoodsList(state.categoryId, state.pagination.current_page + 1);
}
}
onLoad((options) => {
if (options.data) {
let data = JSON.parse(options.data);
console.log(data);
state.list = data;
return;
}
state.couponId = options.id;
state.userCouponId = options.user_coupon_id;
getCouponContent(state.couponId, state.userCouponId);
});
//
onReachBottom(() => {
loadmore();
});
function onTabsChange(e) {
resetPagination(state.pagination);
state.currentTab = e.index;
state.categoryId = e.value;
getGoodsListByCategory();
}
async function getGoodsListByCategory() {
state.loadStatus = 'loading';
const { code, data } = await SpuApi.getSpuPage({
categoryId: state.categoryId,
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize
});
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
//
async function getGoodsListById() {
const { data, code } = await SpuApi.getSpuListByIds(state.coupon.productScopeValues.join(','));
if (code !== 0) {
return;
}
state.pagination.list = data;
}
//
async function getCategoryList() {
const { data, code } = await CategoryApi.getCategoryListByIds(state.coupon.productScopeValues.join(','));
if (code !== 0) {
return;
}
state.tabMaps = data.map((category) => ({ name: category.name, value: category.id }));
//
if (state.tabMaps.length > 0) {
state.categoryId = state.tabMaps[0].value;
await getGoodsListByCategory();
}
}
//
async function getCoupon() {
const { code } = await CouponApi.takeCoupon(state.id);
if (code !== 0) {
return;
}
uni.showToast({
title: '领取成功',
});
setTimeout(() => {
getCouponContent();
}, 1000);
}
//
async function getCouponContent() {
const { code, data } = state.id > 0 ? await CouponApi.getCouponTemplate(state.id)
: await CouponApi.getCoupon(state.couponId);
if (code !== 0) {
return;
}
state.coupon = data;
//
if (state.coupon.productScope === 2) {
await getGoodsListById();
} else if (state.coupon.productScope === 3) {
await getCategoryList();
}
}
//
function loadMore() {
if (state.loadStatus === 'noMore') {
return;
}
state.pagination.pageNo++;
getGoodsListByCategory();
}
onLoad((options) => {
state.id = options.id;
state.couponId = options.couponId;
getCouponContent(state.id, state.couponId);
});
//
onReachBottom(() => {
loadMore();
});
</script>
<style lang="scss" scoped>
.goods-title {
font-size: 34rpx;
font-weight: bold;
color: #333333;
}
.goods-title {
font-size: 34rpx;
font-weight: bold;
color: #333333;
}
.detail-wrap {
background: linear-gradient(180deg,
var(--ui-BG-Main),
var(--ui-BG-Main-gradient),
var(--ui-BG-Main),
#fff);
}
.detail-wrap {
background: linear-gradient(
180deg,
var(--ui-BG-Main),
var(--ui-BG-Main-gradient),
var(--ui-BG-Main),
#fff
);
}
.detail-box {
// background-color: var(--ui-BG);
border-radius: 6rpx;
position: relative;
margin-top: 100rpx;
.detail-box {
// background-color: var(--ui-BG);
border-radius: 6rpx;
position: relative;
margin-top: 100rpx;
.tag-box {
width: 140rpx;
height: 140rpx;
background: var(--ui-BG);
border-radius: 50%;
position: absolute;
top: -70rpx;
left: 50%;
z-index: 6;
transform: translateX(-50%);
.tag-box {
width: 140rpx;
height: 140rpx;
background: var(--ui-BG);
border-radius: 50%;
position: absolute;
top: -70rpx;
left: 50%;
z-index: 6;
transform: translateX(-50%);
.tag-image {
width: 104rpx;
height: 104rpx;
border-radius: 50%;
}
}
.tag-image {
width: 104rpx;
height: 104rpx;
border-radius: 50%;
}
}
.top {
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
-webkit-mask: radial-gradient(circle at 16rpx 100%, #0000 16rpx, red 0) -16rpx;
padding: 110rpx 0 0 0;
position: relative;
z-index: 5;
.top {
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
-webkit-mask: radial-gradient(circle at 16rpx 100%, #0000 16rpx, red 0) -16rpx;
padding: 110rpx 0 0 0;
position: relative;
z-index: 5;
.title {
font-size: 40rpx;
color: #333;
font-weight: bold;
}
.title {
font-size: 40rpx;
color: #333;
font-weight: bold;
}
.subtitle {
font-size: 28rpx;
color: #333333;
}
.subtitle {
font-size: 28rpx;
color: #333333;
}
.use-btn {
width: 386rpx;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
border-radius: 40rpx;
color: $white;
}
.use-btn {
width: 386rpx;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
border-radius: 40rpx;
color: $white;
}
.disable-btn {
width: 386rpx;
height: 80rpx;
line-height: 80rpx;
background: #e5e5e5;
border-radius: 40rpx;
color: $white;
}
.disable-btn {
width: 386rpx;
height: 80rpx;
line-height: 80rpx;
background: #e5e5e5;
border-radius: 40rpx;
color: $white;
}
.time {
font-size: 26rpx;
font-weight: 400;
color: #999999;
}
.time {
font-size: 26rpx;
font-weight: 400;
color: #999999;
}
.coupon-line {
width: 95%;
border-bottom: 2rpx solid #eeeeee;
}
}
.coupon-line {
width: 95%;
border-bottom: 2rpx solid #eeeeee;
}
}
.bottom {
background-color: #fff;
border-radius: 0 0 20rpx 20rpx;
-webkit-mask: radial-gradient(circle at 16rpx 0%, #0000 16rpx, red 0) -16rpx;
padding: 40rpx 30rpx;
.bottom {
background-color: #fff;
border-radius: 0 0 20rpx 20rpx;
-webkit-mask: radial-gradient(circle at 16rpx 0%, #0000 16rpx, red 0) -16rpx;
padding: 40rpx 30rpx;
.type {
height: 96rpx;
border-bottom: 2rpx solid #eeeeee;
}
}
.type {
height: 96rpx;
border-bottom: 2rpx solid #eeeeee;
}
}
.des {
font-size: 24rpx;
font-weight: 400;
color: #666666;
}
}
.des {
font-size: 24rpx;
font-weight: 400;
color: #666666;
}
}
.all-user {
width: 100%;
height: 300rpx;
font-size: 34rpx;
font-weight: bold;
color: #333333;
}
</style>
.all-user {
width: 100%;
height: 300rpx;
font-size: 34rpx;
font-weight: bold;
color: #333333;
}
</style>

View File

@ -1,265 +1,222 @@
<!-- 优惠券中心 -->
<template>
<s-layout title="优惠券" :bgStyle="{ color: '#f2f2f2' }">
<su-sticky bgColor="#fff">
<su-tabs :list="tabMaps" :scrollable="false" @change="onTabsChange" :current="state.currentTab"></su-tabs>
</su-sticky>
<s-empty v-if="state.pagination.total === 0" icon="/static/coupon-empty.png" text="暂无优惠券"></s-empty>
<template v-if="state.currentTab == '0'">
<view v-for="item in state.pagination.list" :key="item.id">
<s-coupon-list :data="item" @tap="
sheep.$router.go('/pages/coupon/detail', {
data: JSON.stringify(item),
})">
<s-layout title="优惠券" :bgStyle="{ color: '#f2f2f2' }">
<su-sticky bgColor="#fff">
<su-tabs
:list="tabMaps"
:scrollable="false"
@change="onTabsChange"
:current="state.currentTab"
/>
</su-sticky>
<s-empty
v-if="state.pagination.total === 0"
icon="/static/coupon-empty.png"
text="暂无优惠券"
/>
<!-- 情况一领劵中心 -->
<template v-if="state.currentTab === '0'">
<view v-for="item in state.pagination.list" :key="item.id">
<s-coupon-list
:data="item"
@tap="sheep.$router.go('/pages/coupon/detail', { id: item.id })"
>
<template #default>
<button
class="ss-reset-button card-btn ss-flex ss-row-center ss-col-center"
:class="!item.canTake ? 'border-btn' : ''"
@click.stop="getBuy(item.id)"
:disabled="!item.canTake"
>
{{ item.canTake ? '立即领取' : '已领取' }}
</button>
</template>
</s-coupon-list>
</view>
</template>
<!-- 情况二我的优惠劵 -->
<template v-else>
<view v-for="item in state.pagination.list" :key="item.id">
<s-coupon-list
:data="item"
type="user"
@tap="
sheep.$router.go('/pages/coupon/detail', {
data: JSON.stringify(item),
})
"
>
<template #default>
<button
class="ss-reset-button card-btn ss-flex ss-row-center ss-col-center"
:class=" item.status !== 1 ? 'disabled-btn': ''"
:disabled="item.status !== 1"
@click.stop="sheep.$router.go('/pages/coupon/detail', { couponId: item.id })"
>
{{ item.status === 1 ? '立即使用' : item.status === 2 ? '已使用' : '已过期' }}
</button>
</template>
</s-coupon-list>
</view>
</template>
<template #default>
<button class="ss-reset-button card-btn ss-flex ss-row-center ss-col-center"
:class="item.get_status != 'can_get' ? 'border-btn' : ''" @click.stop="getBuy(item.id)"
:disabled="item.get_status != 'can_get'">
<!-- {{ item.status_text }} -->
{{item.status_text|| '立即使用' }}
</button>
</template>
</s-coupon-list>
</view>
</template>
<template v-else>
<view v-for="item in state.pagination.list" :key="item.id">
<s-coupon-list :data="item" type="user" @tap="
sheep.$router.go('/pages/coupon/detail', {
data: JSON.stringify(item),
})
">
<template #default>
<button class="ss-reset-button card-btn ss-flex ss-row-center ss-col-center" :class="
item.status == 'can_get' || item.status == 'can_use'
? ''
: item.status == 'used' || item.status == 'expired'
? 'disabled-btn'
: 'border-btn'
" :disabled="item.status != 'can_get' && item.status != 'can_use'" @click.stop="
sheep.$router.go('/pages/coupon/detail', {
id: item.coupon_id,
user_coupon_id: item.id,
})
">
<!-- {{ item.status_text }} -->
{{item.status_text|| '立即使用' }}
</button>
</template>
</s-coupon-list>
</view>
</template>
<!-- <uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
contentdown: '上拉加载更多',
}" @tap="loadmore" /> -->
</s-layout>
}" @tap="loadMore" />
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import {
computed,
reactive
} from 'vue';
import _ from 'lodash';
import sheep from '@/sheep';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import _ from 'lodash';
import { resetPagination } from '@/sheep/util';
import CouponApi from '@/sheep/api/promotion/coupon';
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
};
//
const state = reactive({
currentTab: 0,
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
},
loadStatus: '',
type: '1',
});
//
const state = reactive({
currentTab: 0, // tab
type: '1',
pagination: {
list: [],
total: 0,
pageNo: 1,
pageSize: 5
},
loadStatus: '',
});
const tabMaps = [
// {
// name: '',
// value: 'all',
// },
{
name: '已领取',
value: '1',
},
{
name: '已使用',
value: '2',
},
{
name: '已失效',
value: '3',
},
];
const tabMaps = [
{
name: '领券中心',
value: 'all',
},
{
name: '已领取',
value: '1',
},
{
name: '已使用',
value: '2',
},
{
name: '已失效',
value: '3',
},
];
function onTabsChange(e) {
state.pagination = pagination
state.currentTab = e.index;
state.type = e.value;
// if (state.currentTab == 0) {
// getData();
// } else {
getCoupon();
// }
}
async function getData(page = 1, list_rows = 5) {
state.loadStatus = 'loading';
const res = await sheep.$api.coupon.list({
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';
}
}
}
// TODO yunai:
function onTabsChange(e) {
state.currentTab = e.index;
state.type = e.value;
resetPagination(state.pagination)
if (state.currentTab === 0) {
getData();
} else {
getCoupon();
}
}
async function getCoupon(page = 1, list_rows = 5) {
state.loadStatus = 'loading';
let res = await sheep.$api.coupon.userCoupon({
status: state.type,
pageSize: list_rows,
pageNo: page
});
if (res.code === 0) {
//
let obj = {
1: '可用',
2: '已用',
3: '过期'
}
let obj2 = {
1: '满减',
2: '折扣'
}
res.data.list = res.data.list.map(item => {
return {
...item,
enough: (item.usePrice / 100).toFixed(2),
amount: (item.discountPrice / 100).toFixed(2),
use_start_time: sheep.$helper.timeFormat(item.validStartTime, 'yyyy-mm-dd hh:MM:ss'),
use_end_time: sheep.$helper.timeFormat(item.validEndTime, 'yyyy-mm-dd hh:MM:ss'),
status_text: obj[item.status],
type_text: obj2[item.discountType]
}
});
if (page >= 2) {
let couponlist = _.concat(state.pagination.data, res.data.list);
//
async function getData() {
state.loadStatus = 'loading';
const { data, code } = await CouponApi.getCouponTemplatePage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
});
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
state.pagination = {
...res.data,
data: couponlist,
};
console.log(state.pagination, '拿到的优惠券数据');
} else {
state.pagination = res.data;
console.log(state.pagination, '拿到的优惠券数据');
}
// if (state.pagination.current_page < state.pagination.last_page) {
// state.loadStatus = 'more';
// } else {
// state.loadStatus = 'noMore';
// }
}
}
async function getBuy(id) {
const {
error,
msg
} = await sheep.$api.coupon.get(id);
if (error === 0) {
uni.showToast({
title: msg,
});
setTimeout(() => {
state.pagination = pagination
getData();
}, 1000);
}
}
//
async function getCoupon() {
state.loadStatus = 'loading';
const { data, code } = await CouponApi.getCouponPage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
status: state.type
});
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
//
function loadmore() {
if (state.loadStatus !== 'noMore') {
if (state.currentTab == 0) {
getData(state.pagination.current_page + 1);
} else {
getCoupon(state.pagination.current_page + 1);
}
}
}
onLoad((Option) => {
// if (Option.type === 'all' || !Option.type) {
// getData();
// } else {
// state.type = Option.type;
// Option.type === 'geted' ?
// () :
// Option.type === 'used' ?
// (state.currentTab = 1 && state.type = 2) :
// (state.currentTab = 2 && state.type = 3);
//
async function getBuy(id) {
const { code } = await CouponApi.takeCoupon(id);
if (code !== 0) {
return;
}
uni.showToast({
title: '领取成功',
});
setTimeout(() => {
resetPagination(state.pagination);
getData();
}, 1000);
}
if (Option.type == 'geted') {
state.currentTab = 0
state.type = 1
} else if (Option.type == 'used') {
state.currentTab = 1
state.type = 2
} else {
state.currentTab = 2
state.type = 3
}
getCoupon();
// }
});
onReachBottom(() => {
loadmore();
});
//
function loadMore() {
if (state.loadStatus === 'noMore') {
return;
}
state.pagination.pageNo++;
if (state.currentTab === 0) {
getData();
} else {
getCoupon();
}
}
onLoad((Option) => {
//
if (Option.type === 'all' || !Option.type) {
getData();
//
} else {
state.type = Option.type;
Option.type === 'geted'
? (state.currentTab = 1)
: Option.type === 'used'
? (state.currentTab = 2)
: (state.currentTab = 3);
getCoupon();
}
});
onReachBottom(() => {
loadMore();
});
</script>
<style lang="scss" scoped>
.card-btn {
// width: 144rpx;
padding: 0 16rpx;
height: 50rpx;
border-radius: 40rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: #ffffff;
font-size: 24rpx;
font-weight: 400;
}
.card-btn {
// width: 144rpx;
padding: 0 16rpx;
height: 50rpx;
border-radius: 40rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: #ffffff;
font-size: 24rpx;
font-weight: 400;
}
.border-btn {
background: linear-gradient(90deg, var(--ui-BG-Main-opacity-4), var(--ui-BG-Main-light));
color: #fff !important;
}
.border-btn {
background: linear-gradient(90deg, var(--ui-BG-Main-opacity-4), var(--ui-BG-Main-light));
color: #fff !important;
}
.disabled-btn {
background: #cccccc;
background-color: #cccccc !important;
color: #fff !important;
}
</style>
.disabled-btn {
background: #cccccc;
background-color: #cccccc !important;
color: #fff !important;
}
</style>

View File

@ -3,35 +3,34 @@
<s-layout title="评价">
<view>
<view v-for="(item, index) in state.orderInfo.items" :key="item.id">
<view v-if="item.btns.includes('comment')">
<view>
<view class="commont-from-wrap">
<!-- 评价商品 -->
<s-goods-item :img="item.goods_image" :title="item.goods_title" :skuText="item.goods_sku_text"
:price="item.goods_price" :num="item.goods_num"></s-goods-item>
<s-goods-item
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.payPrice"
:num="item.count"
/>
</view>
<view class="form-item">
<!-- 评分 -->
<view class="star-box ss-flex ss-col-center">
<view class="star-title ss-m-r-40">
<!-- {{ rateMap[state.commentList[index].level] }} -->
商品质量
</view>
<uni-rate v-model="state.commentList[index].level" />
<view class="star-title ss-m-r-40">商品质量</view>
<uni-rate v-model="state.commentList[index].descriptionScores" />
</view>
<view class="star-box ss-flex ss-col-center">
<view class="star-title ss-m-r-40">
<!-- {{ rateMap[state.commentList[index].level] }} -->
服务态度
</view>
<uni-rate v-model="state.commentList[index].level2" />
<view class="star-title ss-m-r-40">服务态度</view>
<uni-rate v-model="state.commentList[index].benefitScores" />
</view>
<!-- 评价 -->
<view class="area-box">
<uni-easyinput :inputBorder="false" type="textarea" maxlength="120" autoHeight
v-model="state.commentList[index].content"
placeholder="宝贝满足你的期待吗?说说你的使用心得,分享给想买的他们吧~"></uni-easyinput>
placeholder="宝贝满足你的期待吗?说说你的使用心得,分享给想买的他们吧~" />
<!-- TODO 芋艿文件上传 -->
<view class="img-box">
<s-uploader v-model:url="state.commentList[index].images" fileMediatype="image"
limit="9" mode="grid" :imageStyles="{ width: '168rpx', height: '168rpx' }" />
@ -41,6 +40,7 @@
</view>
</view>
</view>
<!-- TODO 芋艿是否匿名 -->
<su-fixed bottom placeholder>
<view class="foot_box ss-flex ss-row-center ss-col-center">
@ -54,113 +54,49 @@
<script setup>
import sheep from '@/sheep';
import {
onLoad
} from '@dcloudio/uni-app';
import {
computed,
reactive
} from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import OrderApi from '@/sheep/api/trade/order';
const state = reactive({
orderInfo: {},
commentList: [],
orderId: null
id: null
});
const rateMap = {
1: '糟糕',
2: '差评',
3: '一般',
4: '良好',
5: '好评',
};
async function onSubmit() {
//
// console.log(state.orderInfo);
// return;
let obj = {
anonymous: false,
benefitScores: state.commentList[0].level2,
content: state.commentList[0].content,
descriptionScores: state.commentList[0].level,
orderItemId: state.commentList[0].item_id,
picUrls: 'https://t7.baidu.com/it/u=2531125946,3055766435&fm=193&f=GIF'
}
const {
code
} = await sheep.$api.order.comment(obj);
if (code === 0) {
sheep.$router.back();
}
//
for (const comment of state.commentList) {
await OrderApi.createOrderItemComment(comment);
}
//
sheep.$router.back();
}
onLoad(async (options) => {
let id = '';
if (options.orderSN) {
id = options.orderSN;
}
if (options.id) {
id = options.id;
}
if (options.orderId) {
state.orderId = options.orderId
}
if (!options.id) {
sheep.$helper.toast(`缺少订单信息,请检查`);
return
}
state.id = options.id;
const res = await sheep.$api.order.detail(id);
if (res.code === 0) {
let obj = {
10: ['待发货', '等待买家付款', ["apply_refund"]],
30: ['待评价', '等待买家评价', ["express", "comment"]]
}
res.data.status_text = obj[res.data.status][0];
res.data.status_desc = obj[res.data.status][1];
res.data.btns = obj[res.data.status][2];
res.data.address = {
province_name: res.data.receiverAreaName.split(' ')[0],
district_name: res.data.receiverAreaName.split(' ')[2],
city_name: res.data.receiverAreaName.split(' ')[1],
address: res.data.receiverDetailAddress,
consignee: res.data.receiverName,
mobile: res.data.receiverMobile,
}
res.data.pay_fee = res.data.payPrice / 100
res.data.create_time = sheep.$helper.timeFormat(res.data.createTime, 'yyyy-mm-dd hh:MM:ss')
res.data.order_sn = res.data.no
res.data.id = res.data.id
res.data.goods_amount = res.data.totalPrice / 100
res.data.dispatch_amount = res.data.deliveryPrice / 100
res.data.pay_types_text = res.data.payChannelName.split(',')
res.data.items = res.data.items.map(ite => {
return {
...ite,
btns: obj[res.data.status][2],
goods_title: ite.spuName,
goods_num: ite.count,
goods_price: ite.price / 100,
goods_image: ite.picUrl,
goods_sku_text: ite.properties.reduce((it0, it1) => it0 + it1.valueName + ' ', '')
}
})
if (res.data.btns.includes('comment')) {
state.orderInfo = res.data;
state.orderInfo.items.forEach((item) => {
if (item.btns.includes('comment')) {
state.commentList.push({
item_id: item.id,
level: 5,
content: '',
images: [],
});
}
});
console.log(state.orderInfo.items, '循环')
return;
}
}
sheep.$helper.toast('无待评价订单');
const { code, data } = await sheep.$api.order.detail(state.id);
if (code !== 0) {
sheep.$helper.toast('无待评价订单');
return
}
//
data.items.forEach((item) => {
state.commentList.push({
anonymous: false,
orderItemId: item.id,
descriptionScores: 5,
benefitScores: 5,
content: '',
picUrls: []
});
});
state.orderInfo = data;
});
</script>

View File

@ -1,115 +0,0 @@
<template>
<view>
<detail-cell
v-if="modelValue.length > 0"
label="参数"
:value="state.paramsTitle"
@click="state.show = true"
></detail-cell>
<su-popup :show="state.show" round="10" :showClose="true" @close="close">
<view class="ss-modal-box bg-white">
<view class="modal-header">产品参数</view>
<scroll-view
class="modal-content ss-p-t-50"
scroll-y="true"
:scroll-with-animation="true"
:show-scrollbar="false"
@touchmove.stop
>
<view class="sale-item ss-flex ss-col-top" v-for="item in modelValue" :key="item.title">
<view class="item-title">{{ item.title }}</view>
<view class="item-value">{{ item.content }}</view>
</view>
</scroll-view>
<view class="modal-footer ss-flex ss-row-center ss-m-b-20">
<button class="ss-reset-button save-btn ui-Shadow-Main" @tap="state.show = false"
>确定</button
>
</view>
</view>
</su-popup>
</view>
</template>
<script setup>
import { reactive, computed } from 'vue';
import detailCell from './detail-cell.vue';
const props = defineProps({
modelValue: {
type: Object,
default() {
return [];
},
},
});
const state = reactive({
show: false,
paramsTitle: computed(() => {
let titleArray = [];
props.modelValue.map((item) => {
titleArray.push(item.title);
});
return titleArray.join(' · ');
}),
});
function close() {
state.show = false;
}
</script>
<style lang="scss" scoped>
.ss-modal-box {
border-radius: 30rpx 30rpx 0 0;
max-height: 730rpx;
.modal-header {
position: relative;
padding: 30rpx 20rpx 40rpx;
font-size: 36rpx;
font-weight: bold;
}
.modal-content {
padding: 0 30rpx;
max-height: 500rpx;
box-sizing: border-box;
.sale-item {
margin-bottom: 24rpx;
padding-bottom: 24rpx;
border-bottom: 2rpx solid rgba(#dfdfdf, 0.4);
.item-title {
font-size: 28rpx;
font-weight: 500;
line-height: 42rpx;
width: 120rpx;
white-space: normal;
}
.item-value {
font-size: 26rpx;
font-weight: 400;
color: $dark-9;
line-height: 42rpx;
flex: 1;
margin-left: 20rpx;
}
}
}
.modal-footer {
height: 120rpx;
.save-btn {
width: 710rpx;
height: 80rpx;
border-radius: 40rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: $white;
}
}
}
</style>

View File

@ -1,121 +0,0 @@
<template>
<view>
<detail-cell
v-if="modelValue.length > 0"
label="保障"
:value="state.paramsTitle"
@click="state.show = true"
>
</detail-cell>
<su-popup :show="state.show" round="10" :showClose="true" @close="state.show = false">
<view class="ss-modal-box">
<view class="modal-header">服务保障</view>
<scroll-view
class="modal-content"
scroll-y="true"
:scroll-with-animation="true"
:show-scrollbar="false"
@touchmove.stop
>
<view class="sale-item ss-flex ss-col-top" v-for="item in modelValue" :key="item.id">
<image
class="title-icon ss-m-r-14"
:src="sheep.$url.cdn(item.image)"
mode="aspectFill"
></image>
<view class="title-box">
<view class="item-title ss-m-b-20">{{ item.name }}</view>
<view class="item-value">{{ item.description }}</view>
</view>
</view>
</scroll-view>
<view class="modal-footer ss-flex ss-row-center ss-m-b-20">
<button class="ss-reset-button save-btn ui-Shadow-Main" @tap="state.show = false"
>确定</button
>
</view>
</view>
</su-popup>
</view>
</template>
<script setup>
import { reactive, computed } from 'vue';
import sheep from '@/sheep';
import detailCell from './detail-cell.vue';
const props = defineProps({
modelValue: {
type: Object,
default() {},
},
});
const state = reactive({
show: false,
paramsTitle: computed(() => {
let nameArray = [];
props.modelValue.map((item) => {
nameArray.push(item.name);
});
return nameArray.join(' · ');
}),
});
</script>
<style lang="scss" scoped>
.ss-modal-box {
border-radius: 30rpx 30rpx 0 0;
max-height: 730rpx;
.modal-header {
position: relative;
padding: 30rpx 20rpx 40rpx;
font-size: 36rpx;
font-weight: bold;
}
.modal-content {
padding: 0 30rpx;
max-height: 500rpx;
box-sizing: border-box;
.sale-item {
margin-bottom: 44rpx;
.title-icon {
width: 36rpx;
height: 36rpx;
}
.title-box{
flex: 1;
}
.item-title {
font-size: 28rpx;
font-weight: 500;
line-height: normal;
}
.item-value {
font-size: 26rpx;
font-weight: 400;
color: $dark-9;
line-height: 42rpx;
}
}
}
.modal-footer {
height: 120rpx;
background-color: #fff;
.save-btn {
width: 710rpx;
height: 80rpx;
border-radius: 40rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: $white;
}
}
}
</style>

View File

@ -1,3 +1,4 @@
<!-- 商品详情cell 组件 -->
<template>
<view class="detail-cell-wrap ss-flex ss-col-center ss-row-between" @tap="onClick">
<view class="label-text">{{ label }}</view>
@ -13,7 +14,6 @@
* 详情 cell
*
*/
const props = defineProps({
label: {
type: String,

View File

@ -1,3 +1,4 @@
<!-- 商品详情描述卡片 -->
<template>
<view class="detail-content-card bg-white ss-m-x-20 ss-p-t-20">
<view class="card-header ss-flex ss-col-center ss-m-b-30 ss-m-l-20">
@ -5,7 +6,7 @@
<view class="title ss-m-l-20 ss-m-r-20">详情</view>
</view>
<view class="card-content">
<mp-html :content="content"></mp-html>
<mp-html :content="content" />
</view>
</view>
</template>

View File

@ -1,3 +1,4 @@
<!-- 商品详情商品/评价/详情的 nav -->
<template>
<su-fixed alway :bgStyles="{ background: '#fff' }" :val="0" noNav opacity :placeholder="false">
<su-status-bar />

View File

@ -1,3 +1,4 @@
<!-- 秒杀商品抢购进度 -->
<template>
<view class="ss-flex ss-col-center">
<view class="progress-title ss-m-r-10"> 已抢{{ percent }}% </view>

View File

@ -1,3 +1,4 @@
<!-- 商品详情的底部导航 -->
<template>
<su-fixed bottom placeholder bg="bg-white">
<view class="ui-tabbar-box">
@ -12,7 +13,7 @@
class="item-icon"
:src="sheep.$url.static('/static/img/shop/goods/collect_1.gif')"
mode="aspectFit"
></image>
/>
<view class="item-title">已收藏</view>
</block>
<block v-else>
@ -20,7 +21,7 @@
class="item-icon"
:src="sheep.$url.static('/static/img/shop/goods/collect_0.png')"
mode="aspectFit"
></image>
/>
<view class="item-title">收藏</view>
</block>
</view>
@ -33,7 +34,7 @@
class="item-icon"
:src="sheep.$url.static('/static/img/shop/goods/message.png')"
mode="aspectFit"
></image>
/>
<view class="item-title">客服</view>
</view>
<view
@ -45,7 +46,7 @@
class="item-icon"
:src="sheep.$url.static('/static/img/shop/goods/share.png')"
mode="aspectFit"
></image>
/>
<view class="item-title">分享</view>
</view>
<slot></slot>
@ -63,13 +64,11 @@
* @property {String} ui - 自定义样式Class
* @property {Boolean} noFixed - 是否定位
* @property {Boolean} topRadius - 上圆角
*
*
*/
import { computed, reactive } from 'vue';
import { reactive } from 'vue';
import sheep from '@/sheep';
import { showShareModal } from '@/sheep/hooks/useModal';
import FavoriteApi from '@/sheep/api/product/favorite';
//
const state = reactive({});
@ -114,25 +113,24 @@
default: true,
},
});
const elStyles = computed(() => {
return {
'border-top-left-radius': props.topRadius + 'rpx',
'border-top-right-radius': props.topRadius + 'rpx',
overflow: 'hidden',
};
});
const tabbarheight = (e) => {
uni.setStorageSync('tabbar', e);
};
async function onFavorite() {
const { error } = await sheep.$api.user.favorite.do(props.modelValue.id);
if (error === 0) {
if (props.modelValue.favorite) {
props.modelValue.favorite = 0;
} else {
props.modelValue.favorite = 1;
//
if (props.modelValue.favorite) {
const { code } = await FavoriteApi.deleteFavorite(props.modelValue.id);
if (code !== 0) {
return
}
sheep.$helper.toast('取消收藏');
props.modelValue.favorite = false;
//
} else {
const { code } = await FavoriteApi.createFavorite(props.modelValue.id);
if (code !== 0) {
return
}
sheep.$helper.toast('收藏成功');
props.modelValue.favorite = true;
}
}

View File

@ -1,4 +1,4 @@
<!-- 页面 -->
<!-- 页面暂时没用到 -->
<template>
<view class="list-goods-card ss-flex-col" @tap="onClick">
<view class="md-img-box">

View File

@ -1,3 +1,4 @@
<!-- 页面暂时没用到 -->
<template>
<su-fixed
alway

View File

@ -86,10 +86,6 @@
:skus="state.goodsInfo.skus"
@tap="state.showSelectSku = true"
/>
<!-- 服务 -->
<detail-cell-service v-model="state.goodsInfo.service" />
<!-- 参数 -->
<detail-cell-params v-model="state.goodsInfo.params" />
<!-- 玩法 -->
<detail-cell
v-if="state.goodsInfo.activity.richtext_id > 0"
@ -173,15 +169,13 @@
</template>
<script setup>
import { reactive, getCurrentInstance, computed, ref } from 'vue';
import { reactive, computed, ref } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { isEmpty } from 'lodash';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCell from './components/detail/detail-cell.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailCellService from './components/detail/detail-cell-service.vue';
import detailCellParams from './components/detail/detail-cell-params.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
import detailSkeleton from './components/detail/detail-skeleton.vue';
import detailCommentCard from './components/detail/detail-comment-card.vue';
@ -209,7 +203,7 @@
grouponId: 0, // ID
grouponType: '', //
grouponNum: 0, //
grouponAction: 'create', //
grouponAction: 'create', //
});
//

View File

@ -56,9 +56,6 @@
<view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku v-model="state.selectedSku.goods_sku_text" :sku="state.selectedSku"
@tap="state.showSelectSku = true" />
<!-- TODO 芋艿可能暂时不考虑使用 -->
<detail-cell-service v-if="state.goodsInfo.service" v-model="state.goodsInfo.service" />
<detail-cell-params v-if="state.goodsInfo.params" v-model="state.goodsInfo.params" />
</view>
<!-- 规格与数量弹框 -->
@ -91,11 +88,11 @@
<!-- 优惠劵弹窗 -->
<s-coupon-get v-model="state.couponInfo" :show="state.showModel" @close="state.showModel = false"
@get="onGet" />
@get="onGet" />
<!-- 满减送/限时折扣活动弹窗 -->
<s-activity-pop v-model="state.activityInfo" :show="state.showActivityModel"
@close="state.showActivityModel = false" />
@close="state.showActivityModel = false" />
</block>
</s-layout>
</view>
@ -113,23 +110,16 @@
import sheep from '@/sheep';
import CouponApi from '@/sheep/api/promotion/coupon';
import ActivityApi from '@/sheep/api/promotion/activity';
import {
formatSales,
formatGoodsSwiper,
fen2yuan,
} from '@/sheep/hooks/useGoods';
import FavoriteApi from '@/sheep/api/product/favorite';
import { formatSales, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailCellService from './components/detail/detail-cell-service.vue';
import detailCellParams from './components/detail/detail-cell-params.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
import detailSkeleton from './components/detail/detail-skeleton.vue';
import detailCommentCard from './components/detail/detail-comment-card.vue';
import detailContentCard from './components/detail/detail-content-card.vue';
import detailActivityTip from './components/detail/detail-activity-tip.vue';
import {
isEmpty
} from 'lodash';
import { isEmpty } from 'lodash';
onPageScroll(() => {});
@ -153,21 +143,30 @@
// TODO
function onAddCart(e) {
if (!e.id) {
sheep.$helper.toast('请选择商品规格');
return;
}
sheep.$store('cart').add(e);
}
// TODO
//
function onBuy(e) {
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
order_type: 'goods',
goods_list: [{
goods_id: e.goods_id,
goods_num: e.goods_num,
goods_sku_price_id: e.id,
}, ],
}),
});
if (!state.selectedSku.id) {
sheep.$helper.toast('请选择商品规格');
return;
}
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
items: [{
skuId: state.selectedSku.id,
count: 1
}],
// TODO 2
deliveryType: 1,
pointStatus: false,
}),
});
}
// TODO
@ -178,18 +177,16 @@
// TODO
async function onGet(id) {
const {
error,
msg
} = await sheep.$api.coupon.get(id);
if (error === 0) {
uni.showToast({
title: msg,
});
setTimeout(() => {
getCoupon();
}, 1000);
}
const { code } = await CouponApi.takeCoupon(id);
if (code !== 0) {
return;
}
uni.showToast({
title: '领取成功',
});
setTimeout(() => {
getCoupon();
}, 1000);
}
// TODO
@ -213,7 +210,14 @@
}, );
});
onLoad(async (options) => {
async function getCoupon() {
const { code, data } = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10);
if (code === 0) {
state.couponInfo = data;
}
}
onLoad((options) => {
//
if (!options.id) {
state.goodsInfo = null;
@ -230,15 +234,18 @@
//
state.skeletonLoading = false;
state.goodsInfo = res.data;
//
FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => {
if (res.code !== 0) {
return;
}
state.goodsInfo.favorite = res.data;
});
});
// 2.
CouponApi.getCouponTemplateList(state.goodsId, 2, 10).then((res) => {
if (res.code !== 0) {
return;
}
state.couponInfo = res.data;
});
getCoupon();
// 3.
ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => {

View File

@ -6,11 +6,11 @@
<view class="ss-flex">
<view class="ss-flex-1">
<su-tabs :list="state.tabList" :scrollable="false" @change="onTabsChange"
:current="state.currentTab"></su-tabs>
:current="state.currentTab" />
</view>
<view class="list-icon" @tap="state.iconStatus = !state.iconStatus">
<text v-if="state.iconStatus" class="sicon-goods-list"></text>
<text v-else class="sicon-goods-card"></text>
<text v-if="state.iconStatus" class="sicon-goods-list" />
<text v-else class="sicon-goods-card" />
</view>
</view>
</su-sticky>
@ -20,38 +20,59 @@
:zIndex="10" @close="state.showFilter = false">
<view class="filter-list-box">
<view class="filter-item" v-for="(item, index) in state.tabList[state.currentTab].list"
:key="item.value" :class="[{ 'filter-item-active': index == state.curFilter }]"
:key="item.value" :class="[{ 'filter-item-active': index === state.curFilter }]"
@tap="onFilterItem(index)">
{{ item.label }}
</view>
</view>
</su-popup>
<!-- 情况一单列布局 -->
<view v-if="state.iconStatus && state.pagination.total > 0" class="goods-list ss-m-t-20">
<view class="ss-p-l-20 ss-p-r-20 ss-m-b-20" v-for="item in state.pagination.data" :key="item.id">
<s-goods-column class="" size="lg" :data="item" :topRadius="10" :bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"></s-goods-column>
<view class="ss-p-l-20 ss-p-r-20 ss-m-b-20" v-for="item in state.pagination.list" :key="item.id">
<s-goods-column
class=""
size="lg"
:data="item"
:topRadius="10"
:bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
/>
</view>
</view>
<view v-if="!state.iconStatus && state.pagination.total > 0"
<!-- 情况二双列布局 -->
<view v-if="!state.iconStatus && state.pagination.total > 0"
class="ss-flex ss-flex-wrap ss-p-x-20 ss-m-t-20 ss-col-top">
<view class="goods-list-box">
<view class="left-list" v-for="item in state.leftGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :data="item" :topRadius="10" :bottomRadius="10"
<s-goods-column
class="goods-md-box"
size="md"
:data="item"
:topRadius="10"
:bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'left')">
@getHeight="mountMasonry($event, 'left')"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn"> </button>
<button class="ss-reset-button cart-btn" />
</template>
</s-goods-column>
</view>
</view>
<view class="goods-list-box">
<view class="right-list" v-for="item in state.rightGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :topRadius="10" :bottomRadius="10" :data="item"
<s-goods-column
class="goods-md-box"
size="md"
:topRadius="10"
:bottomRadius="10"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'right')">
@getHeight="mountMasonry($event, 'right')"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn"> </button>
<button class="ss-reset-button cart-btn" />
</template>
</s-goods-column>
</view>
@ -59,54 +80,43 @@
</view>
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
contentdown: '上拉加载更多',
}" @tap="loadmore" />
<s-empty v-if="state.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无商品">
</s-empty>
}" @tap="loadMore" />
<s-empty v-if="state.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无商品" />
</s-layout>
</template>
<script setup>
import {
reactive
} from 'vue';
import { reactive } from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import _ from 'lodash';
import { resetPagination } from '@/sheep/util';
const sys_navBar = sheep.$platform.navbar;
const emits = defineEmits(['close', 'change']);
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
};
const state = reactive({
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
list: [],
total: 0,
pageNo: 1,
pageSize: 6,
},
// currentSort: 'weigh',
// currentOrder: 'desc',
currentTab: 0,
filterParams: {},
curFilter: 0,
currentSort: undefined,
currentOrder: undefined,
currentTab: 0, // tab
curFilter: 0, // list
showFilter: false,
iconStatus: false,
categoryId: 0,
iconStatus: false, // true - false -
keyword: '',
categoryId: 0,
tabList: [{
name: '综合推荐',
// value: '',
list: [{
label: '综合推荐',
// sort: '',
// order: true,
label: '综合推荐'
},
{
label: '价格升序',
@ -123,18 +133,17 @@
{
name: '销量',
sort: 'salesCount',
order: false,
// value: 'salesCount',
order: false
},
{
name: '新品优先',
// value: 'create_time',
value: 'createTime',
order: false
},
],
loadStatus: '',
keyword: '',
leftGoodsList: [],
rightGoodsList: [],
leftGoodsList: [], // -
rightGoodsList: [], // -
});
//
@ -142,8 +151,11 @@
let leftHeight = 0;
let rightHeight = 0;
// leftGoodsList + rightGoodsList
function mountMasonry(height = 0, where = 'left') {
if (!state.pagination.data[count]) return;
if (!state.pagination.list[count]) {
return;
}
if (where === 'left') {
leftHeight += height;
@ -151,110 +163,110 @@
rightHeight += height;
}
if (leftHeight <= rightHeight) {
state.leftGoodsList.push(state.pagination.data[count]);
state.leftGoodsList.push(state.pagination.list[count]);
} else {
state.rightGoodsList.push(state.pagination.data[count]);
state.rightGoodsList.push(state.pagination.list[count]);
}
count++;
}
//
function emptyList() {
state.pagination = pagination
state.leftGoodsList = [];
resetPagination(state.pagination);
state.leftGoodsList = [];
state.rightGoodsList = [];
count = 0;
leftHeight = 0;
rightHeight = 0;
}
//
//
function onSearch(e) {
state.keyword = e;
emptyList();
getList(state.currentSort, state.currentOrder, state.categoryId, e);
getList(state.currentSort, state.currentOrder);
}
//
function onTabsChange(e) {
//
if (state.tabList[e.index].list) {
state.currentTab = e.index;
state.showFilter = !state.showFilter;
return;
} else {
state.showFilter = false;
}
state.showFilter = false;
// tab
if (e.index === state.currentTab) {
return;
} else {
state.currentTab = e.index;
}
state.currentTab = e.index;
state.currentSort = e.sort;
state.currentOrder = e.order;
emptyList();
console.log(e, '6666')
getList(e.sort, e.order, state.categoryId, state.keyword);
getList(e.sort, e.order);
}
//
// tab list
const onFilterItem = (val) => {
console.log(val)
if (
state.currentSort === state.tabList[0].list[val].sort &&
state.currentOrder === state.tabList[0].list[val].order
) {
//
// tabList[0] list
if (state.currentSort === state.tabList[0].list[val].sort
&& state.currentOrder === state.tabList[0].list[val].order) {
state.showFilter = false;
return;
}
state.showFilter = false;
//
state.curFilter = val;
state.tabList[0].name = state.tabList[0].list[val].label;
state.currentSort = state.tabList[0].list[val].sort;
state.currentOrder = state.tabList[0].list[val].order;
emptyList();
getList(state.currentSort, state.currentOrder, state.categoryId, state.keyword);
state.showFilter = false;
};
// +
emptyList();
getList();
}
async function getList(Sort, Order, categoryId, keyword, page = 1, list_rows = 6) {
async function getList() {
state.loadStatus = 'loading';
const res = await sheep.$api.goods.list({
sortField: Sort,
sortAsc: Order,
category_id: !keyword ? categoryId : '',
pageSize: list_rows,
keyword: keyword,
pageNo: page,
const { code, data } = await sheep.$api.goods.list({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
sortField: state.currentSort,
sortAsc: state.currentOrder,
categoryId: state.categoryId,
keyword: state.keyword,
});
if (res.code === 0) {
let couponList = _.concat(state.pagination.data, res.data.list);
state.pagination = {
...res.data,
data: couponList,
};
mountMasonry();
if (state.pagination.current_page < state.pagination.last_page) {
state.loadStatus = 'more';
} else {
state.loadStatus = 'noMore';
}
}
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list)
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
mountMasonry();
}
//
function loadmore() {
if (state.loadStatus !== 'noMore') {
getList(
state.currentSort,
state.currentOrder,
state.categoryId,
state.keyword,
state.pagination.current_page + 1,
);
}
function loadMore() {
if (state.loadStatus === 'noMore') {
return;
}
state.pagination.pageNo++;
getList(state.currentSort, state.currentOrder);
}
onLoad((options) => {
state.categoryId = options.categoryId;
state.keyword = options.keyword;
getList(state.currentSort, state.currentOrder, state.categoryId, state.keyword);
getList(state.currentSort, state.currentOrder);
});
//
onReachBottom(() => {
loadmore();
loadMore();
});
</script>

View File

@ -1,368 +0,0 @@
<template>
<view>
<s-layout :onShareAppMessage="state.shareInfo" navbar="goods">
<!-- 标题栏 -->
<detailNavbar />
<detailSkeleton v-if="state.skeletonLoading" />
<!-- 空置页 -->
<s-empty
v-else-if="state.goodsInfo === null"
text="商品不存在或已下架"
icon="/static/soldout-empty.png"
showAction
actionText="再逛逛"
actionUrl="/pages/goods/list"
/>
<block v-else>
<!-- 商品轮播图 -->
<su-swiper
class="ss-m-b-14 detail-swiper-selector"
isPreview
:list="state.goodsSwiper"
dotStyle="tag"
imageMode="widthFix"
dotCur="bg-mask-40"
:seizeHeight="750"
/>
<!-- 价格+标题 -->
<view class="title-card detail-card ss-p-y-40 ss-p-x-20">
<view class="ss-flex ss-row-between ss-col-center ss-m-b-18">
<view class="price-box ss-flex ss-col-bottom">
<view v-if="goodsPrice.price > 0" class="price-text"> {{ goodsPrice.price }} </view>
<text v-if="goodsPrice.price > 0 && goodsPrice.score > 0">+</text>
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
></image>
<view class="score-text ss-m-r-16">
{{ goodsPrice.score }}
</view>
</view>
<view class="sales-text">
{{ formatExchange(state.goodsInfo.sales_show_type, state.goodsInfo.sales) }}
</view>
</view>
<view class="origin-price-text ss-m-b-60" v-if="state.goodsInfo.original_price">
原价{{ state.selectedSkuPrice.original_price || state.goodsInfo.original_price }}
</view>
<view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.title }}</view>
<view class="subtitle-text ss-line-1">{{ state.goodsInfo.subtitle }}</view>
</view>
<!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku
v-model="state.selectedSkuPrice.goods_sku_text"
:skus="state.goodsInfo.skus"
@tap="state.showSelectSku = true"
/>
<detail-cell-service v-model="state.goodsInfo.service" />
<detail-cell-params v-model="state.goodsInfo.params" />
</view>
<!-- 规格与数量弹框 -->
<s-select-sku
:goodsInfo="state.goodsInfo"
:show="state.showSelectSku"
:isScore="true"
@addCart="onAddCart"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
<!-- 评价 -->
<view class="detail-comment-selector">
<detail-comment-card :goodsId="state.goodsId" />
</view>
<!-- 详情 -->
<view class="detail-content-selector"></view>
<detail-content-card :content="state.goodsInfo.content" />
<!-- 详情tabbar -->
<detail-tabbar v-model="state.goodsInfo" :shareIcon="false" :collectIcon="false">
<!-- TODO: 缺货中 已售罄 判断 设计-->
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0">
<button class="ss-reset-button buy-btn" @tap="state.showSelectSku = true">
立即兑换
</button>
</view>
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-else>
<button class="ss-reset-button disabled-btn" disabled> 已兑完 </button>
</view>
</detail-tabbar>
</block>
</s-layout>
</view>
</template>
<script setup>
import { reactive, computed } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { isEmpty } from 'lodash';
import { formatExchange, formatGoodsSwiper } from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailCellService from './components/detail/detail-cell-service.vue';
import detailCellParams from './components/detail/detail-cell-params.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
import detailSkeleton from './components/detail/detail-skeleton.vue';
import detailCommentCard from './components/detail/detail-comment-card.vue';
import detailContentCard from './components/detail/detail-content-card.vue';
const headerBg = sheep.$url.css('/static/img/shop/goods/score-bg.png');
const seckillBg = sheep.$url.css('/static/img/shop/goods/seckill-tip-bg.png');
const grouponBg = sheep.$url.css('/static/img/shop/goods/seckill-tip-bg.png');
onPageScroll(() => {});
const state = reactive({
goodsId: 0,
skeletonLoading: true,
goodsInfo: {},
showSelectSku: false,
goodsSwiper: [],
selectedSkuPrice: {},
shareInfo: {},
showModel: false,
total: 0,
couponInfo: [],
});
const goodsPrice = computed(() => {
let price, score;
if (isEmpty(state.selectedSkuPrice)) {
price = state.goodsInfo.price[0];
score = state.goodsInfo.score || 0;
} else {
price = state.selectedSkuPrice.price;
score = state.selectedSkuPrice.score || 0;
}
return { price, score };
});
//
function onSkuChange(e) {
state.selectedSkuPrice = e;
}
//
function formatPrice(e) {
if (Number(e[0]) > 0) {
return e.length === 1 ? e[0] : e.join('~');
} else {
return '';
}
}
//
function onAddCart(e) {
sheep.$store('cart').add(e);
}
//
function onBuy(e) {
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
order_type: 'score',
goods_list: [
{
goods_id: e.goods_id,
goods_num: e.goods_num,
goods_sku_price_id: e.id,
},
],
}),
});
}
onLoad((options) => {
//
if (!options.id) {
state.goodsInfo = null;
return;
}
state.goodsId = options.id;
//
sheep.$api.app.scoreShop.detail(state.goodsId).then((res) => {
state.skeletonLoading = false;
if (res.error === 0) {
state.goodsInfo = res.data;
state.goodsSwiper = formatGoodsSwiper(state.goodsInfo.images);
} else {
//
state.goodsInfo = null;
}
});
});
</script>
<style lang="scss" scoped>
.detail-card {
background-color: #ffff;
margin: 14rpx 20rpx;
border-radius: 10rpx;
overflow: hidden;
}
//
.title-card {
width: 710rpx;
box-sizing: border-box;
background-size: 100% 100%;
border-radius: 10rpx;
background-image: v-bind(headerBg);
background-repeat: no-repeat;
.price-box {
.score-img {
width: 36rpx;
height: 36rpx;
margin: 0 4rpx;
}
.score-text {
font-size: 42rpx;
font-weight: 500;
color: #ff3000;
line-height: 36rpx;
font-family: OPPOSANS;
}
.price-text {
font-size: 42rpx;
font-weight: 500;
color: #ff3000;
line-height: 36rpx;
font-family: OPPOSANS;
}
}
.origin-price-text {
font-size: 26rpx;
font-weight: 400;
text-decoration: line-through;
color: $gray-c;
font-family: OPPOSANS;
}
.sales-text {
font-size: 26rpx;
font-weight: 500;
color: $gray-c;
}
.discounts-box {
.discounts-tag {
padding: 4rpx 10rpx;
font-size: 24rpx;
font-weight: 500;
border-radius: 4rpx;
color: var(--ui-BG-Main);
// background: rgba(#2aae67, 0.05);
background: var(--ui-BG-Main-tag);
}
.discounts-title {
font-size: 24rpx;
font-weight: 500;
color: var(--ui-BG-Main);
line-height: normal;
}
.cicon-forward {
color: var(--ui-BG-Main);
font-size: 24rpx;
line-height: normal;
margin-top: 4rpx;
}
}
.title-text {
font-size: 30rpx;
font-weight: bold;
line-height: 42rpx;
}
.subtitle-text {
font-size: 26rpx;
font-weight: 400;
color: $dark-9;
line-height: 42rpx;
}
}
//
.buy-box {
.buy-btn {
width: 630rpx;
height: 80rpx;
border-radius: 40rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: $white;
}
.disabled-btn {
width: 630rpx;
height: 80rpx;
border-radius: 40rpx;
background: #999999;
color: $white;
}
}
//
.seckill-box {
background: v-bind(seckillBg) no-repeat;
background-size: 100% 100%;
}
.groupon-box {
background: v-bind(grouponBg) no-repeat;
background-size: 100% 100%;
}
//
.activity-box {
width: 100%;
height: 80rpx;
box-sizing: border-box;
margin-bottom: 10rpx;
.activity-title {
font-size: 26rpx;
font-weight: 500;
color: #ffffff;
line-height: 42rpx;
.activity-icon {
width: 38rpx;
height: 38rpx;
}
}
.activity-go {
width: 70rpx;
height: 32rpx;
background: #ffffff;
border-radius: 16rpx;
font-weight: 500;
color: #ff6000;
font-size: 24rpx;
line-height: normal;
}
}
.model-box {
height: 60vh;
.model-content {
height: 56vh;
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333333;
}
.subtitle {
font-size: 26rpx;
font-weight: 500;
color: #333333;
}
}
</style>

View File

@ -73,8 +73,6 @@
:skus="state.goodsInfo.skus"
@tap="state.showSelectSku = true"
/>
<detail-cell-service v-model="state.goodsInfo.service" />
<detail-cell-params v-model="state.goodsInfo.params" />
</view>
<!-- 规格与数量弹框 -->
<s-select-seckill-sku
@ -145,8 +143,6 @@
import { useDurationTime, formatGoodsSwiper, formatPrice } from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailCellService from './components/detail/detail-cell-service.vue';
import detailCellParams from './components/detail/detail-cell-params.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
import detailSkeleton from './components/detail/detail-skeleton.vue';
import detailCommentCard from './components/detail/detail-comment-card.vue';

View File

@ -71,9 +71,6 @@
if (options.page) {
sheep.$router.go(decodeURIComponent(options.page));
}
// TODO
sheep.$api.app.test();
});
//

View File

@ -1,3 +1,4 @@
<!-- 搜索界面 -->
<template>
<s-layout class="set-wrap" title="搜索" :bgStyle="{ color: '#FFF' }">
<view class="ss-p-x-24">
@ -33,14 +34,18 @@
import { reactive } from 'vue';
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
const state = reactive({
historyList: [],
});
//
function onSearch(keyword) {
if (!keyword) return;
if (!keyword) {
return;
}
saveSearchHistory(keyword);
//
sheep.$router.go('/pages/goods/list', { keyword });
}
@ -53,7 +58,7 @@
//
state.historyList.unshift(keyword);
// 10
// 10
if (state.historyList.length >= 10) {
state.historyList.length = 10;
}
@ -72,6 +77,7 @@
},
});
}
onLoad(() => {
state.historyList = uni.getStorageSync('searchHistory') || [];
});

View File

@ -1,11 +1,15 @@
<!-- 订单详情 -->
<!-- 售后申请 -->
<template>
<s-layout title="申请售后">
<!-- 售后商品 -->
<view class="goods-box">
<s-goods-item :img="state.goodsItem.goods_image" :title="state.goodsItem.goods_title"
:skuText="state.goodsItem.goods_sku_text" :price="state.goodsItem.goods_price"
:num="state.goodsItem.goods_num"></s-goods-item>
<s-goods-item
:img="state.item.picUrl"
:title="state.item.spuName"
:skuText="state.item.properties?.map((property) => property.valueName).join(' ')"
:price="state.item.price"
:num="state.item.count"
/>
</view>
<uni-forms ref="form" v-model="formData" :rules="rules" label-position="top">
@ -14,69 +18,104 @@
<view class="item-title ss-m-b-20">售后类型</view>
<view class="ss-flex-col">
<radio-group @change="onRefundChange">
<label class="ss-flex ss-col-center ss-p-y-10" v-for="(item, index) in state.refundTypeList" :key="index">
<radio :checked="formData.type === item.value" color="var(--ui-BG-Main)" style="transform: scale(0.8)"
:value="item.value" />
<label
class="ss-flex ss-col-center ss-p-y-10"
v-for="(item, index) in state.wayList"
:key="index"
>
<radio
:checked="formData.type === item.value"
color="var(--ui-BG-Main)"
style="transform: scale(0.8)"
:value="item.value"
/>
<view class="item-value ss-m-l-8">{{ item.text }}</view>
</label>
</radio-group>
</view>
</view>
<!-- 退款金额 -->
<view class="refund-item ss-flex ss-col-center ss-row-between" @tap="state.showModal = true">
<text class="item-title">退款金额</text>
<view class="ss-flex refund-cause ss-col-center">
<text class="ss-m-r-20">{{ fen2yuan(state.item.payPrice) }}</text>
</view>
</view>
<!-- 申请原因 -->
<view class="refund-item ss-flex ss-col-center ss-row-between" @tap="state.showModal = true">
<text class="item-title">申请原因</text>
<view class="ss-flex refund-cause ss-col-center">
<text class="ss-m-r-20" v-if="formData.reason">{{ formData.reason }}</text>
<text class="ss-m-r-20" v-if="formData.applyReason">{{ formData.applyReason }}</text>
<text class="ss-m-r-20" v-else>~</text>
<!-- <text class="ss-iconfont _icon-forward" style="color: #666"></text> -->
<text class="cicon-forward" style="height: 28rpx"></text>
</view>
</view>
<view class="refund-item u-m-b-20">
<view class="item-title ss-m-b-20">联系方式</view>
<view class="input-box u-flex">
<uni-easyinput :inputBorder="false" type="number" v-model="formData.mobile" placeholder="请输入您的联系电话"
paddingLeft="10" />
</view>
</view>
<!-- 留言 -->
<view class="refund-item">
<view class="item-title ss-m-b-20">相关描述</view>
<view class="describe-box">
<uni-easyinput :inputBorder="false" class="describe-content" type="textarea" maxlength="120" autoHeight
v-model="formData.content" placeholder="客官~请描述您遇到的问题,建议上传照片"></uni-easyinput>
<uni-easyinput
:inputBorder="false"
class="describe-content"
type="textarea"
maxlength="120"
autoHeight
v-model="formData.applyDescription"
placeholder="客官~请描述您遇到的问题,建议上传照片"
/>
<!-- TODO 芋艿上传的测试 -->
<view class="upload-img">
<s-uploader v-model:url="formData.images" fileMediatype="image" limit="9" mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx' }" />
<s-uploader
v-model:url="formData.images"
fileMediatype="image"
limit="9"
mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx' }"
/>
</view>
</view>
</view>
</uni-forms>
<!-- 底部按钮 -->
<su-fixed bottom placeholder>
<view class="foot-wrap">
<view class="foot_box ss-flex ss-col-center ss-row-between ss-p-x-30">
<button class="ss-reset-button contcat-btn" @tap="sheep.$router.go('/pages/chat/index')"></button>
<button class="ss-reset-button contcat-btn" @tap="sheep.$router.go('/pages/chat/index')">
联系客服
</button>
<button class="ss-reset-button ui-BG-Main-Gradient sub-btn" @tap="submit"></button>
</view>
</view>
</su-fixed>
<!-- 申请原因弹窗 -->
<!-- 申请原因弹窗 -->
<su-popup :show="state.showModal" round="10" :showClose="true" @close="state.showModal = false">
<view class="modal-box page_box">
<view class="modal-head item-title head_box ss-flex ss-row-center ss-col-center">申请原因</view>
<view class="modal-head item-title head_box ss-flex ss-row-center ss-col-center">
申请原因
</view>
<view class="modal-content content_box">
<radio-group @change="onChange">
<label class="radio ss-flex ss-col-center" v-for="item in state.refundReasonList" :key="item.value">
<view class="ss-flex-1 ss-p-20">{{ item.title }}</view>
<radio :value="item.value" color="var(--ui-BG-Main)" :checked="item.value === state.currentValue" />
<label
class="radio ss-flex ss-col-center"
v-for="item in state.reasonList"
:key="item"
>
<view class="ss-flex-1 ss-p-20">{{ item }}</view>
<radio
:value="item"
color="var(--ui-BG-Main)"
:checked="item === state.currentValue"
/>
</label>
</radio-group>
</view>
<view class="modal-foot foot_box ss-flex ss-row-center ss-col-center">
<button class="ss-reset-button close-btn ui-BG-Main-Gradient" @tap="onReason"></button>
<button class="ss-reset-button close-btn ui-BG-Main-Gradient" @tap="onReason">
确定
</button>
</view>
</view>
</su-popup>
@ -84,235 +123,235 @@
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { reactive, ref, unref } from 'vue';
const form = ref(null);
const state = reactive({
showModal: false,
currentValue: 0,
goodsItem: {},
reasonText: '',
//
refundTypeList: [
{
text: '仅退款',
value: 'refund',
},
{
text: '退/换货',
value: 'return',
},
{
text: '其他',
value: 'other',
},
],
refundReasonList: [
{
value: '1',
title: '卖家发错货了',
},
{
value: '2',
title: '退运费',
},
{
value: '3',
title: '大小/重量与商品描述不符',
},
{
value: '4',
title: '生产日期/保质期与商品描述不符',
},
{
value: '5',
title: '质量问题',
},
{
value: '6',
title: '我不想要了',
},
],
});
const formData = reactive({
type: '',
reason: '',
mobile: '',
content: '',
images: [],
});
const rules = reactive({});
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { reactive, ref } from 'vue';
import OrderApi from '@/sheep/api/trade/order';
import TradeConfigApi from '@/sheep/api/trade/config';
import { fen2yuan } from '@/sheep/hooks/useGoods';
import AfterSaleApi from '@/sheep/api/trade/afterSale';
//
async function submit() {
// #ifdef MP
sheep.$platform.useProvider('wechat').subscribeMessage('order_aftersale_change');
// #endif
let data = {
...formData,
order_id: state.goodsItem.order_id,
order_item_id: state.goodsItem.id,
};
const res = await sheep.$api.order.aftersale.apply(data);
if (res.error === 0) {
uni.showToast({
title: res.msg,
});
sheep.$router.go('/pages/order/aftersale/list');
}
}
const form = ref(null);
const state = reactive({
orderId: 0, //
itemId: 0, //
order: {}, //
item: {}, //
config: {}, //
//
function onRefundChange(e) {
formData.type = e.detail.value;
}
//
function onChange(e) {
state.currentValue = e.detail.value;
state.refundReasonList.forEach((item) => {
if (item.value === e.detail.value) {
state.reasonText = item.title;
}
//
wayList: [
{
text: '仅退款',
value: '10',
},
{
text: '退款退货',
value: '20',
},
],
reasonList: [], //
showModal: false, //
currentValue: '' //
});
}
//
function onReason() {
formData.reason = state.reasonText;
state.showModal = false;
}
const formData = reactive({
way: '',
applyReason: '',
applyDescription: '',
images: [],
});
const rules = reactive({});
function onTitle(e, title) {
state.currentValue = e;
state.reasonText = title;
}
onLoad((options) => {
state.goodsItem = JSON.parse(options.item);
});
//
async function submit() {
// #ifdef MP
sheep.$platform.useProvider('wechat').subscribeMessage('order_aftersale_change');
// #endif
let data = {
orderItemId: state.itemId,
refundPrice: state.item.payPrice,
...formData,
};
const { code } = await AfterSaleApi.createAfterSale(data);
if (code === 0) {
uni.showToast({
title: '申请成功',
});
sheep.$router.go('/pages/order/aftersale/list');
}
}
//
function onRefundChange(e) {
formData.way = e.detail.value;
//
state.reasonList =
formData.way === '10'
? state.config.afterSaleRefundReasons || []
: state.config.afterSaleReturnReasons || [];
formData.applyReason = '';
state.currentValue = '';
}
//
function onChange(e) {
state.currentValue = e.detail.value;
}
//
function onReason() {
formData.applyReason = state.currentValue;
state.showModal = false;
}
onLoad(async (options) => {
//
if (!options.orderId || !options.itemId) {
sheep.$helper.toast(`缺少订单信息,请检查`);
return;
}
state.orderId = options.orderId;
state.itemId = parseInt(options.itemId);
//
const { code, data } = await OrderApi.getOrder(state.orderId);
if (code !== 0) {
return;
}
state.order = data;
state.item = data.items.find((item) => item.id === state.itemId) || {};
//
if (state.order.status === 10) {
state.wayList.splice(1, 1);
}
//
state.config = (await TradeConfigApi.getTradeConfig()).data;
});
</script>
<style lang="scss" scoped>
.item-title {
font-size: 30rpx;
font-weight: bold;
color: rgba(51, 51, 51, 1);
// margin-bottom: 20rpx;
}
//
.refund-item {
background-color: #fff;
border-bottom: 1rpx solid #f5f5f5;
padding: 30rpx;
&:last-child {
border: none;
}
//
.describe-box {
width: 690rpx;
background: rgba(249, 250, 251, 1);
padding: 30rpx;
box-sizing: border-box;
border-radius: 20rpx;
.describe-content {
height: 200rpx;
font-size: 24rpx;
font-weight: 400;
color: #333;
}
}
//
.input-box {
height: 84rpx;
background: rgba(249, 250, 251, 1);
border-radius: 20rpx;
}
}
.goods-box {
background: #fff;
padding: 20rpx;
margin-bottom: 20rpx;
}
.foot-wrap {
height: 100rpx;
width: 100%;
}
.foot_box {
height: 100rpx;
background-color: #fff;
.sub-btn {
width: 336rpx;
line-height: 74rpx;
border-radius: 38rpx;
color: rgba(#fff, 0.9);
font-size: 28rpx;
}
.contcat-btn {
width: 336rpx;
line-height: 74rpx;
background: rgba(238, 238, 238, 1);
border-radius: 38rpx;
font-size: 28rpx;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
}
.modal-box {
width: 750rpx;
// height: 680rpx;
border-radius: 30rpx 30rpx 0 0;
background: #fff;
.modal-head {
height: 100rpx;
.item-title {
font-size: 30rpx;
font-weight: bold;
color: rgba(51, 51, 51, 1);
// margin-bottom: 20rpx;
}
.modal-content {
font-size: 28rpx;
}
//
.refund-item {
background-color: #fff;
border-bottom: 1rpx solid #f5f5f5;
padding: 30rpx;
.modal-foot {
.close-btn {
width: 710rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: rgba(#fff, 0.9);
&:last-child {
border: none;
}
//
.describe-box {
width: 690rpx;
background: rgba(249, 250, 251, 1);
padding: 30rpx;
box-sizing: border-box;
border-radius: 20rpx;
.describe-content {
height: 200rpx;
font-size: 24rpx;
font-weight: 400;
color: #333;
}
}
//
.input-box {
height: 84rpx;
background: rgba(249, 250, 251, 1);
border-radius: 20rpx;
}
}
}
.success-box {
width: 600rpx;
padding: 90rpx 0 64rpx 0;
.cicon-check-round {
font-size: 96rpx;
color: #04b750;
.goods-box {
background: #fff;
padding: 20rpx;
margin-bottom: 20rpx;
}
.success-title {
font-weight: 500;
color: #333333;
font-size: 32rpx;
.foot-wrap {
height: 100rpx;
width: 100%;
}
.success-btn {
width: 492rpx;
height: 70rpx;
background: linear-gradient(90deg, var(--ui-BG-Main-gradient), var(--ui-BG-Main));
border-radius: 35rpx;
.foot_box {
height: 100rpx;
background-color: #fff;
.sub-btn {
width: 336rpx;
line-height: 74rpx;
border-radius: 38rpx;
color: rgba(#fff, 0.9);
font-size: 28rpx;
}
.contcat-btn {
width: 336rpx;
line-height: 74rpx;
background: rgba(238, 238, 238, 1);
border-radius: 38rpx;
font-size: 28rpx;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
}
.modal-box {
width: 750rpx;
// height: 680rpx;
border-radius: 30rpx 30rpx 0 0;
background: #fff;
.modal-head {
height: 100rpx;
font-size: 30rpx;
}
.modal-content {
font-size: 28rpx;
}
.modal-foot {
.close-btn {
width: 710rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: rgba(#fff, 0.9);
}
}
}
.success-box {
width: 600rpx;
padding: 90rpx 0 64rpx 0;
.cicon-check-round {
font-size: 96rpx;
color: #04b750;
}
.success-title {
font-weight: 500;
color: #333333;
font-size: 32rpx;
}
.success-btn {
width: 492rpx;
height: 70rpx;
background: linear-gradient(90deg, var(--ui-BG-Main-gradient), var(--ui-BG-Main));
border-radius: 35rpx;
}
}
}
</style>

View File

@ -3,26 +3,22 @@
<s-layout title="售后详情" :navbar="!isEmpty(state.info) && state.loading ? 'inner' : 'normal'">
<view class="content_box" v-if="!isEmpty(state.info) && state.loading">
<!-- 步骤条 -->
<!-- 这个没找到替换方案 -->
<view class="steps-box ss-flex" :style="[
{
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
paddingTop: Number(statusBarHeight + 88) + 'rpx',
},
]">
<!-- <uni-steps :options="state.list" :active="state.active" active-color="#fff" /> -->
<view class="ss-flex">
<view class="steps-item" v-for="(item, index) in state.list" :key="index">
<view class="ss-flex">
<text class="sicon-circleclose" v-if="
(state.list.length - 1 == index && state.info.aftersale_status === -2) ||
(state.list.length - 1 == index && state.info.aftersale_status === -1)
"></text>
<text class="sicon-circleclose"
v-if="state.list.length - 1 === index && [61, 62, 63].includes(state.info.status)" />
<text class="sicon-circlecheck" v-else
:class="state.active >= index ? 'activity-color' : 'info-color'"></text>
:class="state.active >= index ? 'activity-color' : 'info-color'" />
<view v-if="state.list.length - 1 != index" class="line"
:class="state.active >= index ? 'activity-bg' : 'info-bg'"></view>
<view v-if="state.list.length - 1 !== index" class="line"
:class="state.active >= index ? 'activity-bg' : 'info-bg'" />
</view>
<view class="steps-item-title" :class="state.active >= index ? 'activity-color' : 'info-color'">
{{ item.title }}
@ -32,28 +28,33 @@
</view>
<!-- 服务状态 -->
<!-- <view class="status-box ss-flex ss-col-center ss-row-between ss-m-x-20"
@tap="sheep.$router.go('/pages/order/aftersale/log', { id: state.aftersaleId })">
<view class="status-box ss-flex ss-col-center ss-row-between ss-m-x-20"
@tap="sheep.$router.go('/pages/order/aftersale/log', { id: state.id })">
<view class="">
<view class="status-text">{{ state.info.aftersale_status_desc }}</view>
<view class="status-time">{{ state.info.update_time }}</view>
<view class="status-text">
{{ formatAfterSaleStatusDescription(state.info) }}
</view>
<view class="status-time">
{{ sheep.$helper.timeFormat(state.info.updateTime, 'yyyy-mm-dd hh:MM:ss') }}
</view>
</view>
<text class="ss-iconfont _icon-forward" style="color: #666"></text>
</view> -->
<text class="ss-iconfont _icon-forward" style="color: #666" />
</view>
<!-- 退款金额 -->
<view class="aftersale-money ss-flex ss-col-center ss-row-between">
<view class="aftersale-money--title">退款总额</view>
<view class="aftersale-money--num">{{ state.info.refundPrice/100 }}</view>
<view class="aftersale-money--num">{{ fen2yuan(state.info.refundPrice) }}</view>
</view>
<!-- 服务商品 -->
<view class="order-shop">
<!-- <s-goods-item :title="state.info.goods_title" :price="state.info.goods_price"
:img="state.info.goods_image" priceColor="#333333" :titleWidth="480"
:skuText="state.info.goods_sku_text" :num="state.info.goods_num"></s-goods-item> -->
<s-goods-item :img=" state.info.picUrl" :title=" state.info.spuName" priceColor="#333333"
:titleWidth="480" :skuText=" state.info.properties.reduce((a,b)=>a+b.valueName+' ','')"
:price=" state.info.refundPrice/100" :num=" state.info.count"></s-goods-item>
<s-goods-item
:img=" state.info.picUrl"
:title=" state.info.spuName"
:titleWidth="480"
:skuText="state.info.properties.map((property) => property.valueName).join(' ')"
:num=" state.info.count"
/>
</view>
<!-- 服务内容 -->
@ -71,7 +72,7 @@
</view>
<view class="aftersale-item ss-flex ss-col-center">
<view class="item-title">售后类型</view>
<view class="item-content">{{ status2[state.info.way] }}</view>
<view class="item-content">{{ state.info.way === 10 ? '仅退款' : '退款退货' }}</view>
</view>
<view class="aftersale-item ss-flex ss-col-center">
<view class="item-title">申请原因</view>
@ -83,114 +84,97 @@
</view>
</view>
</view>
<!-- 操作区 -->
<s-empty v-if="isEmpty(state.info) && state.loading" icon="/static/order-empty.png" text="暂无该订单售后详情" />
<!-- <su-fixed bottom placeholder bg="bg-white" v-if="!isEmpty(state.info)">
<su-fixed bottom placeholder bg="bg-white" v-if="!isEmpty(state.info)">
<view class="foot_box">
<button class="ss-reset-button btn" v-if="state.info.btns?.includes('cancel')"
@tap="onApply(state.info.id)">取消申请</button>
<button class="ss-reset-button btn" v-if="state.info.btns?.includes('delete')"
@tap="onDelete(state.info.id)">删除</button>
<button class="ss-reset-button contcat-btn btn"
@tap="sheep.$router.go('/pages/chat/index')">联系客服</button>
<!-- TODO 功能缺失填写退货信息 -->
<button class="ss-reset-button btn" v-if="state.info.buttons?.includes('cancel')"
@tap="onApply(state.info.id)">
取消申请
</button>
<button class="ss-reset-button contcat-btn btn" @tap="sheep.$router.go('/pages/chat/index')">
联系客服
</button>
</view>
</su-fixed> -->
</su-fixed>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import {
onLoad
} from '@dcloudio/uni-app';
import {
reactive
} from 'vue';
import {
isEmpty
} from 'lodash';
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import { isEmpty } from 'lodash';
import { fen2yuan, formatAfterSaleStatusDescription, handleAfterSaleButtons } from '@/sheep/hooks/useGoods';
import AfterSaleApi from '@/sheep/api/trade/afterSale';
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const headerBg = sheep.$url.css('/static/img/shop/order/order_bg.png');
const state = reactive({
active: 0,
aftersaleId: 0,
info: {},
list: [{
title: '提交申请',
},
{
title: '处理中',
},
],
id: 0, //
info: {}, //
loading: false,
active: 0, // list
list: [{
title: '提交申请',
}, {
title: '处理中',
}, {
title: '完成'
}], //
});
const status2 = {
10: '仅退款',
20: '退货退款'
}
function onApply(orderId) {
function onApply(id) {
uni.showModal({
title: '提示',
content: '确定要取消此申请吗?',
success: async function(res) {
if (res.confirm) {
const {
error
} = await sheep.$api.order.aftersale.cancel(orderId);
if (error === 0) {
getDetail(state.aftersaleId);
}
if (!res.confirm) {
return;
}
const { code } = await AfterSaleApi.cancelAfterSale(id);
if (code === 0) {
await getDetail(id);
}
},
});
}
function onDelete(orderId) {
uni.showModal({
title: '提示',
content: '确定要删除吗?',
success: async function(res) {
if (res.confirm) {
const {
error
} = await sheep.$api.order.aftersale.delete(orderId);
if (error === 0) {
sheep.$router.back();
}
}
},
});
}
const onCopy = () => {
sheep.$helper.copyText(state.info.aftersale_sn);
//
const onCopy = () => {
sheep.$helper.copyText(state.info.no);
};
async function getDetail(id) {
const {
code,
data
} = await sheep.$api.order.aftersale.detail(id);
state.loading = true;
if (code === 0) {
state.info = data;
if (state.info.aftersale_status === -2 || state.info.aftersale_status === -1) {
state.list.push({
title: state.info.aftersale_status_text
});
state.active = 2;
} else {
state.list.push({
title: '完成'
});
state.active = state.info.aftersale_status;
}
} else {
state.info = null;
}
state.loading = true;
const { code, data } = await AfterSaleApi.getAfterSale(id);
if (code !== 0) {
state.info = null;
return;
}
state.info = data;
handleAfterSaleButtons(state.info);
//
if ([10].includes(state.info.status)) {
state.active = 0;
} else if ([20, 30].includes(state.info.status)) {
state.active = 1;
} else if ([40, 50].includes(state.info.status)) {
state.active = 2;
} else if ([61, 62, 63].includes(state.info.status)) {
state.active = 2;
}
}
onLoad((options) => {
state.aftersaleId = options.id;
if (!options.id) {
sheep.$helper.toast(`缺少订单信息,请检查`);
return
}
state.id = options.id;
getDetail(options.id);
});
</script>

View File

@ -3,92 +3,73 @@
<s-layout title="售后列表">
<!-- tab -->
<su-sticky bgColor="#fff">
<su-tabs :list="tabMaps" :scrollable="false" @change="onTabsChange" :current="state.currentTab"></su-tabs>
<su-tabs :list="tabMaps" :scrollable="false" @change="onTabsChange" :current="state.currentTab" />
</su-sticky>
<s-empty v-if="state.pagination.total === 0" icon="/static/data-empty.png" text="暂无数据">
</s-empty>
<s-empty v-if="state.pagination.total === 0" icon="/static/data-empty.png" text="暂无数据" />
<!-- 列表 -->
<view v-if="state.pagination.total > 0">
<view class="list-box ss-m-y-20" v-for="order in state.pagination.data" :key="order.id"
<view class="list-box ss-m-y-20" v-for="order in state.pagination.list" :key="order.id"
@tap="sheep.$router.go('/pages/order/aftersale/detail', { id: order.id })">
<view class="order-head ss-flex ss-col-center ss-row-between">
<text class="no">服务单号{{ order.no }}</text>
<text class="state">{{ status[order.status] }}</text>
<text class="state">{{ formatAfterSaleStatus(order) }}</text>
</view>
<s-goods-item :img="order.picUrl" :title="order.spuName"
:skuText="order.properties.reduce((a,b)=>a+b.valueName+' ','')" :price="order.refundPrice/100"
:num="order.count"></s-goods-item>
<s-goods-item
:img="order.picUrl"
:title="order.spuName"
:skuText="order.properties.map((property) => property.valueName).join(' ')"
:price="order.refundPrice"
/>
<view class="apply-box ss-flex ss-col-center ss-row-between border-bottom ss-p-x-20">
<view class="ss-flex ss-col-center">
<!-- 此处需修改 -->
<view class="title ss-m-r-20">{{ status2[order.way] }}</view>
<!-- <view class="value">{{ order.aftersale_status_desc }}</view> -->
<view class="value">{{ order.applyReason }}</view>
<view class="title ss-m-r-20">{{ order.way === 10 ? '仅退款' : '退款退货' }}</view>
<view class="value">{{ formatAfterSaleStatusDescription(order) }}</view>
</view>
<text class="_icon-forward"></text>
</view>
<!-- <view class="tool-btn-box ss-flex ss-col-center ss-row-right ss-p-r-20">
<view class="tool-btn-box ss-flex ss-col-center ss-row-right ss-p-r-20">
<!-- TODO 功能缺失填写退货信息 -->
<view>
<button class="ss-reset-button tool-btn" @tap.stop="onApply(order.id)"
v-if="order.btns.includes('cancel')">取消申请</button>
v-if="order?.buttons.includes('cancel')">取消申请</button>
</view>
<view>
<button class="ss-reset-button tool-btn" @tap.stop="onDelete(order.id)"
v-if="order.btns.includes('delete')">删除</button>
</view>
</view> -->
</view>
</view>
</view>
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
contentdown: '上拉加载更多',
}" @tap="loadmore" />
}" @tap="loadMore" />
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import {
computed,
reactive
} from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import _ from 'lodash';
import { formatAfterSaleStatus, formatAfterSaleStatusDescription, handleAfterSaleButtons } from '@/sheep/hooks/useGoods';
import AfterSaleApi from '@/sheep/api/trade/afterSale';
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
const paginationNull = {
list: [],
total: 0,
pageNo: 1,
pageSize: 10
};
const state = reactive({
currentTab: 0,
showApply: false,
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
list: [],
total: 0,
pageNo: 1,
pageSize: 10
},
loadStatus: '',
});
//
const status = {
10: '申请售后',
20: '商品待退货',
30: '商家待收货',
40: '等待退款',
50: '退款成功',
61: '买家取消',
62: '商家拒绝',
63: '商家拒收货'
}
const status2 = {
10: '仅退款',
20: '退货退款'
}
// TODO
const tabMaps = [{
name: '全部',
value: 'all',
@ -110,38 +91,29 @@
// value: 'refuse',
// },
];
//
function onTabsChange(e) {
state.pagination = pagination
state.pagination = paginationNull
state.currentTab = e.index;
getOrderList();
}
//
async function getOrderList(page = 1, list_rows = 5) {
pagination.current_page = page;
async function getOrderList() {
state.loadStatus = 'loading';
let res = await sheep.$api.order.aftersale.list({
let { data, code } = await sheep.$api.order.aftersale.list({
// type: tabMaps[state.currentTab].value,
pageSize: list_rows,
pageNo: page,
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
});
console.log(res, '未处理前售后列表数据')
if (res.code === 0) {
let orderList = _.concat(state.pagination.data, res.data.list);
state.pagination = {
total: res.data.total,
...res.data,
data: orderList,
};
console.log(state.pagination, '售后订单数据')
// if (state.pagination.current_page < state.pagination.last_page) {
state.loadStatus = 'more';
// } else {
// state.loadStatus = 'noMore';
// }
if (code !== 0) {
return;
}
data.list.forEach(order => handleAfterSaleButtons(order));
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
function onApply(orderId) {
@ -149,33 +121,14 @@
title: '提示',
content: '确定要取消此申请吗?',
success: async function(res) {
if (res.confirm) {
const {
error
} = await sheep.$api.order.aftersale.cancel(orderId);
if (error === 0) {
state.pagination = pagination
getOrderList();
}
}
},
});
}
function onDelete(orderId) {
uni.showModal({
title: '提示',
content: '确定要删除吗?',
success: async function(res) {
if (res.confirm) {
const {
error
} = await sheep.$api.order.aftersale.delete(orderId);
if (error === 0) {
state.pagination = pagination
getOrderList();
}
if (!res.confirm) {
return;
}
const { code } = await AfterSaleApi.cancelAfterSale(orderId);
if (code === 0) {
state.pagination = paginationNull
await getOrderList();
}
},
});
}
@ -184,19 +137,21 @@
if (options.type) {
state.currentTab = options.type;
}
getOrderList();
await getOrderList();
});
//
function loadmore() {
// if (state.loadStatus !== 'noMore') {
getOrderList(pagination.current_page + 1);
// }
function loadMore() {
if (state.loadStatus === 'noMore') {
return
}
state.pagination.pageNo++;
getOrderList();
}
//
onReachBottom(() => {
loadmore();
loadMore();
});
</script>

View File

@ -1,57 +1,35 @@
<!-- 售后日志的每一项展示 -->
<template>
<view class="log-item ss-flex">
<view class="log-icon ss-flex-col ss-col-center ss-m-r-20">
<text class="cicon-title" :class="index === 0 ? 'activity-color' : ''"></text>
<view v-if="data.length - 1 != index" class="line"></view>
<text class="cicon-title" :class="index === 0 ? 'activity-color' : ''" />
<view v-if="data.length - 1 !== index" class="line" />
</view>
<view>
<view class="text">{{ item.log_type_text }}</view>
<mp-html class="richtext" :content="item.content"></mp-html>
<view class="" v-if="item.images?.length">
<scroll-view class="scroll-box" scroll-x scroll-anchoring>
<view class="ss-flex">
<view v-for="i in item.images" :key="i" class="ss-m-r-20">
<su-image
class="content-img"
isPreview
:previewList="state.commentImages"
:current="index"
:src="i"
:height="120"
:width="120"
mode="aspectFit"
></su-image>
</view>
</view>
</scroll-view>
<view class="text">{{ item.content }}</view>
<view class="date">
{{ sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}
</view>
<view class="date">{{ item.create_time }}</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
import { reactive } from 'vue';
const props = defineProps({
item: {
type: Object,
type: Object, //
default() {},
},
index: {
type: Number,
type: Number, // item data
default: 0,
},
data: {
type: Object,
type: Object, //
default() {},
},
});
const state = reactive({
commentImages: [],
});
props.item.images?.forEach((i) => {
state.commentImages.push(sheep.$url.cdn(i));
});
</script>
<style lang="scss" scoped>
.log-item {

View File

@ -1,45 +1,29 @@
<!-- 售后进度 -->
<!-- 售后日志列表 -->
<template>
<s-layout title="售后进度">
<view class="log-box">
<view v-for="(item, index) in state.info" :key="item.title">
<log-item :item="item" :index="index" :data="state.info"></log-item>
<view v-for="(item, index) in state.list" :key="item.id">
<log-item :item="item" :index="index" :data="state.list" />
</view>
</view>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { computed, reactive } from 'vue';
import { reactive } from 'vue';
import logItem from './log-item.vue';
import AfterSaleApi from '@/sheep/api/trade/afterSale';
const state = reactive({
active: 1,
list: [
{
title: '买家下单',
desc: '2018-11-11',
},
{
title: '卖家发货',
desc: '2018-11-12',
},
{
title: '买家签收',
desc: '2018-11-13',
},
{
title: '交易完成',
desc: '2018-11-14',
},
],
list: [],
});
async function getDetail(id) {
const { data } = await sheep.$api.order.aftersale.detail(id);
state.info = data.logs;
const { data } = await AfterSaleApi.getAfterSaleLogList(id);
state.list = data;
}
onLoad((options) => {
state.aftersaleId = options.id;
getDetail(options.id);

View File

@ -1,414 +1,388 @@
<template>
<s-layout title="确认订单">
<!-- v-if="state.orderInfo.need_address === 1" -->
<!-- 这个判断先删除 -->
<view class="bg-white address-box ss-m-b-14 ss-r-b-10" @tap="onSelectAddress">
<s-address-item :item="state.addressInfo" :hasBorderBottom="false">
<view class="ss-rest-button"><text class="_icon-forward"></text></view>
</s-address-item>
</view>
<view class="order-card-box ss-m-b-14">
<s-goods-item v-for="item in state.orderInfo.goods_list" :key="item.goods_id"
:img="item.current_sku_price.image || item.goods.image" :title="item.goods.title"
:skuText="item.current_sku_price?.goods_sku_text" :price="item.current_sku_price.price"
:num="item.goods_num" marginBottom="10">
<template #top>
<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white">
<view class="item-title">配送方式</view>
<view class="ss-flex ss-col-center">
<text class="item-value">{{ item.dispatch_type_text }}</text>
</view>
</view>
</template>
</s-goods-item>
<s-layout title="确认订单">
<!-- TODO这个判断先删除 v-if="state.orderInfo.need_address === 1" -->
<view class="bg-white address-box ss-m-b-14 ss-r-b-10" @tap="onSelectAddress">
<s-address-item :item="state.addressInfo" :hasBorderBottom="false">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</s-address-item>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
<view class="item-title">订单备注</view>
<view class="ss-flex ss-col-center">
<uni-easyinput maxlength="20" placeholder="建议留言前先与商家沟通" v-model="state.orderPayload.remark"
:inputBorder="false" :clearable="false"></uni-easyinput>
</view>
</view>
</view>
<!-- 合计 -->
<view class="bg-white total-card-box ss-p-20 ss-m-b-14 ss-r-10">
<view class="total-box-content border-bottom">
<view class="order-item ss-flex ss-col-center ss-row-between">
<view class="item-title">商品金额</view>
<view class="ss-flex ss-col-center">
<text class="item-value ss-m-r-24">{{ state.orderInfo.goods_amount }}</text>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderPayload.order_type === 'score'">
<view class="item-title">扣除积分</view>
<view class="ss-flex ss-col-center">
<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img"></image>
<text class="item-value ss-m-r-24">{{ state.orderInfo.score_amount }}</text>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between">
<view class="item-title">运费</view>
<view class="ss-flex ss-col-center">
<text class="item-value ss-m-r-24">+{{ state.orderInfo.dispatch_amount }}</text>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderPayload.order_type != 'score'">
<!-- <view v-if="state.orderInfo.coupon_discount_fee > 0" class="order-item ss-flex ss-col-center ss-row-between"> -->
<view class="item-title">优惠券</view>
<view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
<text class="item-value text-red"
v-if="state.orderPayload.coupon_id">-{{ state.orderInfo.coupon_discount_fee }}</text>
<text class="item-value"
:class="state.couponInfo.can_use?.length > 0 ? 'text-red' : 'text-disabled'" v-else>{{
state.couponInfo.can_use?.length > 0
? state.couponInfo.can_use?.length + '张可用'
: '暂无可用优惠券'
}}</text>
<!-- 商品信息 -->
<view class="order-card-box ss-m-b-14">
<s-goods-item
v-for="item in state.orderInfo.items"
:key="item.skuId"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
marginBottom="10"
/>
<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
<view class="item-title">订单备注</view>
<view class="ss-flex ss-col-center">
<uni-easyinput
maxlength="20"
placeholder="建议留言前先与商家沟通"
v-model="state.orderPayload.remark"
:inputBorder="false"
:clearable="false"
/>
</view>
</view>
</view>
<text class="_icon-forward item-icon"></text>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.promo_infos?.length">
<!-- <view v-if="state.orderInfo.promo_discount_fee > 0" class="order-item ss-flex ss-col-center ss-row-between"> -->
<view class="item-title">活动优惠</view>
<view class="ss-flex ss-col-center" @tap="state.showDiscount = true">
<text class="item-value text-red"> -{{ state.orderInfo.promo_discount_fee }} </text>
<text class="_icon-forward item-icon"></text>
</view>
</view>
</view>
<view class="total-box-footer ss-font-28 ss-flex ss-row-right ss-col-center ss-m-r-28">
<view class="total-num ss-m-r-20">{{ state.totalNumber }}</view>
<view>合计</view>
<view class="total-num text-red"> {{ state.orderInfo.pay_fee }} </view>
<view class="ss-flex" v-if="state.orderPayload.order_type === 'score'">
<view class="total-num ss-font-30 text-red ss-m-l-4"> + </view>
<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img"></image>
<view class="total-num ss-font-30 text-red">{{ state.orderInfo.score_amount }}</view>
</view>
</view>
</view>
<!-- 发票 -->
<view class="bg-white ss-p-20 ss-r-20">
<view class="order-item ss-flex ss-col-center ss-row-between">
<view class="item-title">发票申请</view>
<view class="ss-flex ss-col-center" @tap="onSelectInvoice">
<text class="item-value">{{ state.invoiceInfo.name || '无需开具发票' }}</text>
<text class="_icon-forward item-icon"></text>
</view>
</view>
</view>
<!-- 选择优惠券弹框 -->
<s-coupon-select v-model="state.couponInfo" :show="state.showCoupon" @confirm="onSelectCoupon"
@close="state.showCoupon = false" />
<!-- 满额折扣弹框 -->
<s-discount-list v-model="state.orderInfo" :show="state.showDiscount" @close="state.showDiscount = false" />
<!-- 底部 -->
<su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200">
<view class="footer-box border-top ss-flex ss-row-between ss-p-x-20 ss-col-center">
<view class="total-box-footer ss-flex ss-col-center">
<view class="total-num ss-font-30 text-red"> {{ state.orderInfo.pay_fee }} </view>
<view v-if="state.orderPayload.order_type === 'score'" class="ss-flex">
<view class="total-num ss-font-30 text-red ss-m-l-4">+</view>
<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img"></image>
<view class="total-num ss-font-30 text-red">{{ state.orderInfo.score_amount }}</view>
</view>
</view>
<!-- 价格信息 -->
<view class="bg-white total-card-box ss-p-20 ss-m-b-14 ss-r-10">
<view class="total-box-content border-bottom">
<view class="order-item ss-flex ss-col-center ss-row-between">
<view class="item-title">商品金额</view>
<view class="ss-flex ss-col-center">
<text class="item-value ss-m-r-24">
{{ fen2yuan(state.orderInfo.price.totalPrice) }}
</text>
</view>
</view>
<!-- TODO 芋艿接入积分 -->
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderPayload.order_type === 'score'"
>
<view class="item-title">扣除积分</view>
<view class="ss-flex ss-col-center">
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
/>
<text class="item-value ss-m-r-24">{{ state.orderInfo.score_amount }}</text>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between">
<view class="item-title">运费</view>
<view class="ss-flex ss-col-center">
<text class="item-value ss-m-r-24">
+{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
</text>
</view>
</view>
<!-- 优惠劵只有 type = 0 普通订单非拼团秒杀砍价才可以使用优惠劵 -->
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
>
<view class="item-title">优惠券</view>
<view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
<text class="item-value text-red" v-if="state.orderPayload.couponId > 0">
-{{ fen2yuan(state.orderInfo.price.couponPrice) }}
</text>
<text
class="item-value"
:class="state.couponInfo.length > 0 ? 'text-red' : 'text-disabled'"
v-else
>
{{
state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
}}
</text>
<text class="_icon-forward item-icon" />
</view>
</view>
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.discountPrice > 0"
>
<view class="item-title">活动优惠</view>
<view class="ss-flex ss-col-center">
<!-- @tap="state.showDiscount = true" TODO 芋艿后续要把优惠信息打进去 -->
<text class="item-value text-red">
-{{ fen2yuan(state.orderInfo.price.discountPrice) }}
</text>
<text class="_icon-forward item-icon" />
</view>
</view>
</view>
<view class="total-box-footer ss-font-28 ss-flex ss-row-right ss-col-center ss-m-r-28">
<view class="total-num ss-m-r-20">
{{ state.orderInfo.items.reduce((acc, item) => acc + item.count, 0) }}
</view>
<view>合计</view>
<view class="total-num text-red"> {{ fen2yuan(state.orderInfo.price.payPrice) }} </view>
</view>
</view>
<button class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main" @tap="onConfirm">
{{ exchangeNow ? '立即兑换' : '提交订单' }}
</button>
</view>
</su-fixed>
</s-layout>
<!-- 选择优惠券弹框 -->
<s-coupon-select
v-model="state.couponInfo"
:show="state.showCoupon"
@confirm="onSelectCoupon"
@close="state.showCoupon = false"
/>
<!-- 满额折扣弹框 TODO 芋艿后续要把优惠信息打进去 -->
<s-discount-list
v-model="state.orderInfo"
:show="state.showDiscount"
@close="state.showDiscount = false"
/>
<!-- 底部 -->
<su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200">
<view class="footer-box border-top ss-flex ss-row-between ss-p-x-20 ss-col-center">
<view class="total-box-footer ss-flex ss-col-center">
<view class="total-num ss-font-30 text-red">
{{ fen2yuan(state.orderInfo.price.payPrice) }}
</view>
</view>
<button
class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main"
@tap="onConfirm"
>
提交订单
</button>
</view>
</su-fixed>
</s-layout>
</template>
<script setup>
import {
reactive,
computed
} from 'vue';
import {
onLoad,
onPageScroll,
onShow
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import {
isEmpty
} from 'lodash';
import { reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { isEmpty } from 'lodash';
import OrderApi from '@/sheep/api/trade/order';
import CouponApi from '@/sheep/api/promotion/coupon';
import { fen2yuan } from '@/sheep/hooks/useGoods';
const state = reactive({
orderPayload: {},
orderInfo: {},
addressInfo: {},
invoiceInfo: {},
totalNumber: 0,
showCoupon: false,
couponInfo: [],
showDiscount: false,
});
const state = reactive({
orderPayload: {},
orderInfo: {
items: [], //
price: {}, //
},
addressInfo: {}, //
showCoupon: false, //
couponInfo: [], //
showDiscount: false, //
});
// ()
const exchangeNow = computed(
() => state.orderPayload.order_type === 'score' && state.orderInfo.pay_fee == 0,
);
//
function onSelectAddress() {
uni.$once('SELECT_ADDRESS', (e) => {
changeConsignee(e.addressInfo);
});
sheep.$router.go('/pages/user/address/list');
}
//
function onSelectAddress() {
uni.$once('SELECT_ADDRESS', (e) => {
changeConsignee(e.addressInfo);
});
sheep.$router.go('/pages/user/address/list');
}
// &
async function changeConsignee(addressInfo = {}) {
if (!isEmpty(addressInfo)) {
state.addressInfo = addressInfo;
}
await getOrderInfo();
}
// &
async function changeConsignee(addressInfo = {}) {
if (isEmpty(addressInfo)) {
const {
code,
data
} = await sheep.$api.user.address.default();
console.log(data, '默认收货地址');
if (code === 0 && !isEmpty(data)) {
console.log('执行赋值')
addressInfo = data;
}
}
if (!isEmpty(addressInfo)) {
state.addressInfo = addressInfo;
state.orderPayload.address_id = state.addressInfo.id;
}
getOrderInfo();
}
//
async function onSelectCoupon(couponId) {
state.orderPayload.couponId = couponId || 0;
await getOrderInfo();
state.showCoupon = false;
}
//
async function onSelectCoupon(e) {
state.orderPayload.coupon_id = e || 0;
getOrderInfo();
state.showCoupon = false;
}
//
function onConfirm() {
if (!state.addressInfo.id) {
sheep.$helper.toast('请选择收货地址');
return;
}
submitOrder();
}
//
function onSelectInvoice() {
uni.$once('SELECT_INVOICE', (e) => {
state.invoiceInfo = e.invoiceInfo;
state.orderPayload.invoice_id = e.invoiceInfo.id || 0;
});
sheep.$router.go('/pages/user/invoice/list');
}
// &
async function submitOrder() {
const { code, data } = await OrderApi.createOrder({
items: state.orderPayload.items,
couponId: state.orderPayload.couponId,
addressId: state.addressInfo.id,
deliveryType: 1, // TODO
pointStatus: false, // TODO
});
if (code !== 0) {
return;
}
//
if (state.orderPayload.items[0].cartId > 0) {
sheep.$store('cart').getList();
}
//
sheep.$router.redirect('/pages/pay/index', {
id: data.payOrderId,
});
}
// /
function onConfirm() {
if (!state.orderPayload.address_id && state.orderInfo.need_address === 1) {
sheep.$helper.toast('请选择收货地址');
return;
}
// &
async function getOrderInfo() {
//
const { data, code } = await OrderApi.settlementOrder({
items: state.orderPayload.items,
couponId: state.orderPayload.couponId,
addressId: state.addressInfo.id,
deliveryType: 1, // TODO
pointStatus: false, // TODO
});
if (code !== 0) {
return;
}
state.orderInfo = data;
//
if (state.orderInfo.address) {
state.addressInfo = state.orderInfo.address;
}
}
if (exchangeNow.value) {
uni.showModal({
title: '提示',
content: '确定使用积分立即兑换?',
cancelText: '再想想',
success: async function(res) {
if (res.confirm) {
submitOrder();
}
},
});
} else {
submitOrder();
}
}
//
async function getCoupons() {
const { code, data } = await CouponApi.getMatchCouponList(
state.orderInfo.price.payPrice,
state.orderInfo.items.map((item) => item.spuId),
state.orderPayload.items.map((item) => item.skuId),
state.orderPayload.items.map((item) => item.categoryId),
);
if (code === 0) {
state.couponInfo = data;
}
}
// &
async function submitOrder() {
const {
error,
data
} = await sheep.$api.order.create(state.orderPayload);
if (error === 0) {
//
if (state.orderPayload.from === 'cart') {
sheep.$store('cart').getList();
}
if (exchangeNow.value) {
sheep.$router.redirect('/pages/pay/result', {
orderSN: data.order_sn,
});
} else {
sheep.$router.redirect('/pages/pay/index', {
orderSN: data.order_sn,
});
}
}
}
// &
async function getOrderInfo() {
console.log(state.orderPayload, '计算价格传参')
// let {code, data} = await sheep.$api.order.calc(state.orderPayload);
// let data = await sheep.$api.order.calc(state.orderPayload);
console.log(state.orderPayload.items)
let data = await sheep.$api.order.calc({
deliveryType: 1,
pointStatus: false,
items: state.orderPayload.items
});
console.log(data, '修改后的获取订单详细数据')
return;
if (error === 0) {
state.totalNumber = 0;
state.orderInfo = data;
state.orderInfo.goods_list.forEach((item) => {
state.totalNumber += item.goods_num;
});
}
}
//
async function getCoupons() {
const {
error,
data
} = await sheep.$api.order.coupons(state.orderPayload);
if (error === 0) {
state.couponInfo = data;
}
}
onLoad(async (options) => {
console.log(options)
if (options.data) {
state.orderPayload = JSON.parse(options.data);
changeConsignee();
if (state.orderPayload.order_type !== 'score') {
getCoupons();
}
}
});
onLoad(async (options) => {
if (!options.data) {
sheep.$helper.toast('参数不正确,请检查!');
return;
}
state.orderPayload = JSON.parse(options.data);
await getOrderInfo();
await getCoupons();
});
</script>
<style lang="scss" scoped>
:deep() {
.uni-input-wrapper {
width: 320rpx;
}
:deep() {
.uni-input-wrapper {
width: 320rpx;
}
.uni-easyinput__content-input {
font-size: 28rpx;
height: 72rpx;
text-align: right !important;
padding-right: 0 !important;
.uni-easyinput__content-input {
font-size: 28rpx;
height: 72rpx;
text-align: right !important;
padding-right: 0 !important;
.uni-input-input {
font-weight: 500;
color: #333333;
font-size: 26rpx;
height: 32rpx;
margin-top: 4rpx;
}
}
.uni-input-input {
font-weight: 500;
color: #333333;
font-size: 26rpx;
height: 32rpx;
margin-top: 4rpx;
}
}
.uni-easyinput__content {
display: flex !important;
align-items: center !important;
justify-content: right !important;
}
}
.uni-easyinput__content {
display: flex !important;
align-items: center !important;
justify-content: right !important;
}
}
.score-img {
width: 36rpx;
height: 36rpx;
margin: 0 4rpx;
}
.score-img {
width: 36rpx;
height: 36rpx;
margin: 0 4rpx;
}
.order-item {
height: 80rpx;
.order-item {
height: 80rpx;
.item-title {
font-size: 28rpx;
font-weight: 400;
}
.item-title {
font-size: 28rpx;
font-weight: 400;
}
.item-value {
font-size: 28rpx;
font-weight: 500;
font-family: OPPOSANS;
}
.item-value {
font-size: 28rpx;
font-weight: 500;
font-family: OPPOSANS;
}
.text-disabled {
color: #bbbbbb;
}
.text-disabled {
color: #bbbbbb;
}
.item-icon {
color: $dark-9;
}
.item-icon {
color: $dark-9;
}
.remark-input {
text-align: right;
}
.remark-input {
text-align: right;
}
.item-placeholder {
color: $dark-9;
font-size: 26rpx;
text-align: right;
}
}
.item-placeholder {
color: $dark-9;
font-size: 26rpx;
text-align: right;
}
}
.total-box-footer {
height: 90rpx;
.total-box-footer {
height: 90rpx;
.total-num {
color: #333333;
font-family: OPPOSANS;
}
}
.total-num {
color: #333333;
font-family: OPPOSANS;
}
}
.footer-box {
height: 100rpx;
.footer-box {
height: 100rpx;
.submit-btn {
width: 240rpx;
height: 70rpx;
font-size: 28rpx;
font-weight: 500;
.submit-btn {
width: 240rpx;
height: 70rpx;
font-size: 28rpx;
font-weight: 500;
.goto-pay-text {
line-height: 28rpx;
}
}
.goto-pay-text {
line-height: 28rpx;
}
}
.cancel-btn {
width: 240rpx;
height: 80rpx;
font-size: 26rpx;
background-color: #e5e5e5;
color: $dark-9;
}
}
.cancel-btn {
width: 240rpx;
height: 80rpx;
font-size: 26rpx;
background-color: #e5e5e5;
color: $dark-9;
}
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333333;
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333333;
}
.subtitle {
font-size: 28rpx;
color: #999999;
}
.subtitle {
font-size: 28rpx;
color: #999999;
}
.cicon-checkbox {
font-size: 36rpx;
color: var(--ui-BG-Main);
}
.cicon-checkbox {
font-size: 36rpx;
color: var(--ui-BG-Main);
}
.cicon-box {
font-size: 36rpx;
color: #999999;
}
</style>
.cicon-box {
font-size: 36rpx;
color: #999999;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -1,84 +0,0 @@
<template>
<s-layout title="发货内容">
<view class="order-card ss-m-x-20 ss-r-20">
<s-goods-item
:img="state.data.goods_image"
:title="state.data.goods_title"
:skuText="state.data.goods_sku_text"
:price="state.data.goods_price"
:num="state.data.goods_num"
radius="20"
>
<template #priceSuffix>
<button class="ss-reset-button tag-btn" v-if="state.data.status_text">
{{ state.data.status_text }}
</button>
</template>
</s-goods-item>
</view>
<view class="bg-white ss-p-20 ss-m-x-20 ss-r-20">
<view class="title ss-m-b-26">发货信息</view>
<view v-if="state.data.ext?.dispatch_content_type === 'params'">
<view class="desc ss-m-b-20" v-for="item in state.data.ext.dispatch_content" :key="item">
{{ item.title }}: {{ item.content }}
</view>
</view>
<view class="desc" v-else>{{ state.data.ext?.dispatch_content }}</view>
</view>
</s-layout>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import sheep from '@/sheep';
const state = reactive({
data: [],
});
async function getDetail(id, item_id) {
const { error, data } = await sheep.$api.order.itemDetail(id,item_id);
if (error === 0) {
state.data = data;
}
}
onLoad((options) => {
getDetail(options.id, options.item_id);
});
</script>
<style lang="scss" scoped>
.order-card {
padding: 20rpx 0;
.order-sku {
font-size: 24rpx;
font-weight: 400;
color: rgba(153, 153, 153, 1);
width: 450rpx;
margin-bottom: 20rpx;
.order-num {
margin-right: 10rpx;
}
}
.tag-btn {
margin-left: 16rpx;
font-size: 24rpx;
height: 36rpx;
color: var(--ui-BG-Main);
border: 2rpx solid var(--ui-BG-Main);
border-radius: 14rpx;
padding: 0 4rpx;
}
}
.title {
font-size: 28rpx;
font-weight: bold;
color: #333333;
}
.desc {
font-size: 26rpx;
font-weight: 400;
color: #333333;
}
</style>

View File

@ -1,104 +0,0 @@
<!-- 物流包裹-->
<template>
<s-layout title="物流包裹">
<view class="express-wrap">
<su-sticky bgColor="#FFE2B6">
<view class="header ss-flex ss-p-l-24">{{ state.list.length }}个包裹已派送</view>
</su-sticky>
<view
class="express-box"
v-for="item in state.list"
:key="item.type"
@tap="sheep.$router.go('/pages/order/express/log', { id: item.id, orderId: state.orderId })"
>
<view class="express-box-header ss-flex ss-row-between">
<view class="express-box-header-type">{{ item.status_text }}</view>
<view class="express-box-header-num">{{
item.express_name + ' : ' + item.express_no
}}</view>
</view>
<view class="express-box-content">
<view class="content-address">{{ item.logs[0]?.content }}</view>
<view class="" v-if="item.items?.length">
<scroll-view class="scroll-box" scroll-x scroll-anchoring>
<view class="ss-flex">
<view v-for="i in item.items" :key="i" class="ss-m-r-20"
><image class="content-img" :src="sheep.$url.static(i.goods_image)" />
</view>
</view>
</scroll-view>
</view>
</view>
<view class="express-box-foot">{{ item.items.length }}件商品</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { computed, reactive } from 'vue';
const state = reactive({
list: [],
orderId: '',
});
async function getExpressList(id) {
const { data } = await sheep.$api.order.express(id, '');
state.list = data;
}
onLoad((Option) => {
state.orderId = Option.orderId;
getExpressList(state.orderId);
});
</script>
<style lang="scss" scoped>
.header {
height: 84rpx;
font-size: 30rpx;
font-weight: 500;
color: #a8700d;
}
.express-box {
background: #fff;
padding-bottom: 30rpx;
box-sizing: border-box;
margin-bottom: 20rpx;
.express-box-header {
height: 76rpx;
padding: 0 24rpx;
border-bottom: 2rpx solid rgba(#dfdfdf, 0.5);
.express-box-header-type {
font-size: 26rpx;
font-weight: 500;
color: #999;
}
.express-box-header-num {
font-size: 26rpx;
font-weight: 400;
color: #999999;
}
}
.express-box-content {
padding: 20rpx 24rpx;
.content-address {
font-size: 28rpx;
font-weight: 400;
color: #333333;
line-height: normal;
margin-bottom: 20rpx;
}
.content-img {
width: 180rpx;
height: 180rpx;
}
}
.express-box-foot {
padding: 0 24rpx;
font-size: 24rpx;
font-weight: 400;
color: #999999;
}
}
</style>

View File

@ -2,65 +2,46 @@
<template>
<s-layout title="物流追踪">
<view class="log-wrap">
<!-- 商品信息 -->
<view class="log-card ss-flex ss-m-20 ss-r-10" v-if="goodsImages.length > 0">
<uni-swiper-dot :info="goodsImages" :current="state.current" mode="round">
<swiper class="swiper-box" @change="change">
<swiper class="swiper-box">
<swiper-item v-for="(item, index) in goodsImages" :key="index">
<image class="log-card-img" :src="sheep.$url.static(item.image)"></image>
<image class="log-card-img" :src="sheep.$url.static(item.image)" />
</swiper-item>
</swiper>
</uni-swiper-dot>
<view class="log-card-msg">
<view class="ss-flex ss-m-b-8">
<view>物流状态</view>
<view class="warning-color">{{ state.info.status_text }}</view>
</view>
<view class="ss-m-b-8">快递单号{{ state.info.express_no }}</view>
<view>快递公司{{ state.info.express_name }}</view>
<!-- TODO 芋艿优化点展示状态 -->
<!-- <view class="ss-flex ss-m-b-8">-->
<!-- <view>物流状态</view>-->
<!-- <view class="warning-color">{{ state.info.status_text }}</view>-->
<!-- </view>-->
<view class="ss-m-b-8">快递单号{{ state.info.logisticsNo }}</view>
<view>快递公司{{ state.info.logisticsName }}</view>
</view>
</view>
<!-- 物流轨迹 -->
<view class="log-content ss-m-20 ss-r-10">
<view
class="log-content-box ss-flex"
v-for="(item, index) in state.info.logs"
v-for="(item, index) in state.tracks"
:key="item.title"
>
<view class="log-icon ss-flex-col ss-col-center ss-m-r-20">
<text
v-if="state.info.logs[index].status === state.info.logs[index - 1]?.status"
class="cicon-title"
></text>
<text
v-if="state.info.logs[index].status != state.info.logs[index - 1]?.status"
:class="[
index === 0 ? 'activity-color' : 'info-color',
item.status === 'transport'
? 'sicon-transport'
: item.status === 'delivery'
? 'sicon-delivery'
: item.status === 'collect'
? 'sicon-a-collectmaterials'
: item.status === 'fail' || item.status === 'back' || item.status === 'refuse'
? 'sicon-circleclose'
: item.status === 'signfor'
? 'sicon-circlecheck'
: 'sicon-warning-outline',
]"
></text>
<view v-if="state.info.logs.length - 1 != index" class="line"></view>
<text class="cicon-title" />
<view v-if="state.tracks.length - 1 !== index" class="line" />
</view>
<view class="log-content-msg">
<view
v-if="
item.status_text &&
state.info.logs[index].status != state.info.logs[index - 1]?.status
"
class="log-msg-title ss-m-b-20"
>{{ item.status_text }}</view
>
<!-- TODO 芋艿优化点展示状态 -->
<!-- <view class="log-msg-title ss-m-b-20">-->
<!-- {{ item.status_text }}-->
<!-- </view>-->
<view class="log-msg-desc ss-m-b-16">{{ item.content }}</view>
<view class="log-msg-date ss-m-b-40">{{ item.change_date }}</view>
<view class="log-msg-date ss-m-b-40">
{{ sheep.$helper.timeFormat(item.time, 'yyyy-mm-dd hh:MM:ss') }}
</view>
</view>
</view>
</view>
@ -72,31 +53,38 @@
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { computed, reactive } from 'vue';
import OrderApi from '@/sheep/api/trade/order';
const state = reactive({
info: [],
current: 0,
tracks: [],
});
const goodsImages = computed(() => {
let array = [];
if (state.info.items) {
state.info.items.forEach((item) => {
array.push({
image: item.goods_image,
image: item.picUrl,
});
});
}
return array;
});
function change(e) {
state.current = e.detail.current;
async function getExpressDetail(id) {
const { data } = await OrderApi.getOrderExpressTrackList(id);
state.tracks = data.reverse();
}
async function getExpressdetail(id, orderId) {
const { data } = await sheep.$api.order.express(id, orderId);
async function getOrderDetail(id) {
const { data } = await OrderApi.getOrder(id)
state.info = data;
}
onLoad((Option) => {
getExpressdetail(Option.id, Option.orderId);
onLoad((options) => {
getExpressDetail(options.id);
getOrderDetail(options.id);
});
</script>

View File

@ -1,329 +0,0 @@
<!-- 订单详情 -->
<template>
<s-layout title="发票详情" class="invoice-wrap" navbar="inner">
<view
class="invoice-heard ss-flex-col ss-row-right ss-col-center"
:style="[
{
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
paddingTop: Number(statusBarHeight + 88) + 'rpx',
},
]"
>
<view class="ss-flex ss-m-t-32 ss-m-b-32">
<text
class="sicon-warning-line"
v-if="state.data.status === 'waiting' || state.data.status === 'unpaid'"
></text>
<text class="sicon-check-line" v-if="state.data.status === 'finish'"></text>
<view class="invoice-heard-title">{{ state.data.status_text }}</view>
</view>
<view class="ss-flex ss-m-b-52">
<view class="ss-m-r-20 invoice-heard-desc">预计可开发票金额</view>
<view class="invoice-heard-price">{{ state.data.amount }}</view>
</view>
</view>
<view class="invoice-content ss-flex-col ss-col-center">
<view class="ss-m-t-50 ss-m-b-42 invoice-content-title">增值税电子普通发票</view>
<view class="ss-flex ss-m-b-64">
<view v-for="(item, index) in state.info" :key="item.title">
<view class="log-icon ss-flex">
<text class="sicon-circlecheck" v-if="statusNum >= index"></text>
<text class="sicon-unchecked" v-else></text>
<view
v-if="state.info.length - 1 != index"
class="line"
:class="statusNum >= index ? 'activity-color' : ''"
></view>
</view>
<view class="log-title">{{ item.title }}</view>
</view>
</view>
<view class="invoice-content-list ss-flex ss-row-between ss-col-top">
<view class="">
<view class="ss-flex">
<view class="list-title">发票类型</view>
<view class="list-desc">{{ state.data.type_text }}</view>
</view>
<view class="ss-flex">
<view class="list-title">发票抬头</view>
<view class="list-desc">{{ state.data.name }}</view>
</view>
<view class="ss-flex" v-if="state.data.type === 'company'">
<view class="list-title">发票税号</view>
<view class="list-desc">{{ state.data.tax_no }}</view>
</view>
<view class="ss-flex" v-if="state.data.status === 'finish'">
<view class="list-title">实开金额</view>
<view class="list-desc">{{ state.data.invoice_amount }}</view>
</view>
<view class="ss-flex" v-if="state.data.status === 'finish'">
<view class="list-title">开票时间</view>
<view class="list-desc">{{ state.data.finish_time }}</view>
</view>
<view class="ss-flex">
<view class="list-title">申请时间</view>
<view class="list-desc">{{ state.data.create_time }}</view>
</view>
</view>
<view
class="invoice-content-img ss-flex-col ss-col-center"
v-if="state.data.status === 'finish'"
>
<su-image
class="invoice-img"
isPreview
:previewList="state.jointImage"
:current="0"
:src="sheep.$url.static('/static/img/shop/order/invoice_thumb.png')"
:height="110"
mode="scaleToFill"
v-if="state.jointImage[0].substr(-4) != '.pdf'"
></su-image>
<!-- TODO: 发票为多个pdf时 -->
<view v-if="state.jointImage[0].substr(-4) == '.pdf'" @tap="onInvoice">
<image
:src="sheep.$url.static('/static/img/shop/order/invoice_thumb.png')"
class="invoice-img"
></image>
</view>
<view class="invoice-img-num">{{ state.numImage }}</view>
<view class="invoice-img-title">点击预览发票</view>
</view>
</view>
</view>
<view class="invoice-order ss-m-t-20">
<view class="goods-box" v-for="item in state.data.order_items" :key="item.id">
<s-goods-item
:img="item.goods_image"
:title="item.goods_title"
:skuText="item.goods_sku_text"
:price="item.goods_price"
:num="item.goods_num"
/>
</view>
<view class="invoice-order-list">
<view class="ss-flex">
<view class="list-title">订单状态</view>
<view class="list-desc">{{ state.data.order?.status_text }}</view>
</view>
<view class="ss-flex">
<view class="list-title">订单编号</view>
<view class="list-desc">{{ state.data.order?.order_sn }}</view>
</view>
<view class="ss-flex">
<view class="list-title">下单时间</view>
<view class="list-desc">{{ state.data.order?.create_time }}</view>
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { computed, reactive } from 'vue';
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const headerBg = sheep.$url.css('/static/img/shop/order/invoice_bg.png');
const state = reactive({
info: [
{
title: '订单提交',
},
{
title: '等待开票',
},
{
title: '开票完成',
},
],
data: {},
jointImage: [],
numImage: 0,
});
const statusNum = computed(() => {
if (state.data.status === 'finish') {
return 2;
} else if (state.data.status === 'waiting') {
return 1;
} else {
return 0;
}
});
function onInvoice() {
// #ifdef H5
window.open(state.jointImage);
// #endif
// #ifdef MP || APP-PLUS
uni.downloadFile({
url: state.jointImage[0],
success: function (res) {
var filePath = res.tempFilePath;
uni.openDocument({
filePath: filePath,
showMenu: true,
success: function (res) {
console.log('打开文档成功');
},
});
},
});
// #endif
}
async function getInvoiceDetail(id) {
const { data } = await sheep.$api.order.invoice(id);
state.data = data;
state.data.download_urls?.forEach((i, index) => {
state.numImage = index + 1;
if (i.substr(-4) != '.pdf') {
state.jointImage.push(sheep.$url.static(i));
} else {
state.jointImage.push(sheep.$url.static(i));
}
});
}
onLoad((options) => {
getInvoiceDetail(options.invoiceId);
});
</script>
<style lang="scss" scoped>
.invoice-heard {
width: 100%;
box-sizing: border-box;
background: v-bind(headerBg) no-repeat,
linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
background-size: 750rpx 100%;
.sicon-warning-line {
color: #fff;
font-size: 34rpx;
}
.sicon-check-line {
color: #fff;
font-size: 34rpx;
}
.invoice-heard-title {
font-size: 34rpx;
font-weight: 500;
color: #ffffff;
margin-left: 8rpx;
line-height: normal;
}
.invoice-heard-desc {
font-size: 24rpx;
font-weight: 500;
color: #ffffff;
}
.invoice-heard-price {
font-size: 28rpx;
font-family: OPPOSANS;
font-weight: 500;
color: #ffffff;
}
}
.invoice-content {
width: 100%;
position: relative;
z-index: 3;
background: #ffffff;
border-radius: 20rpx;
margin-top: -16rpx;
.invoice-content-title {
font-size: 30rpx;
font-weight: 500;
color: #333333;
}
.log-icon {
.sicon-unchecked {
color: #c2bec2;
font-size: 44rpx;
}
.sicon-circlecheck {
color: #e60a00;
font-size: 44rpx;
}
.line {
width: 158rpx;
height: 6rpx;
background: #f2f2f2;
border: 2rpx solid #ffffff;
}
.activity-color {
background: #e60a00;
}
}
.log-title {
font-size: 26rpx;
font-weight: 500;
color: #333333;
margin-left: -26rpx;
margin-top: 30rpx;
}
.invoice-content-list {
width: 100%;
padding: 0 46rpx 0 30rpx;
box-sizing: border-box;
}
.list-title {
font-size: 26rpx;
font-weight: 500;
color: #999999;
margin-right: 44rpx;
margin-bottom: 36rpx;
}
.list-desc {
font-size: 26rpx;
font-weight: 500;
color: #333333;
margin-bottom: 36rpx;
}
.invoice-img {
width: 200rpx;
height: 110rpx;
}
.invoice-img-num {
width: 216rpx;
height: 40rpx;
background: rgba(#000000, 0.45);
font-size: 24rpx;
font-weight: 500;
color: #ffffff;
text-align: center;
margin-top: -30rpx;
z-index: 1;
}
.invoice-img-title {
font-size: 24rpx;
font-weight: 500;
color: #999999;
}
}
.invoice-order {
width: 100%;
padding-top: 30rpx;
box-sizing: border-box;
background: #fff;
border-radius: 20rpx;
}
.goods-box {
border-bottom: 2rpx solid #dfdfdf;
}
.invoice-order-list {
padding: 40rpx 24rpx 0 24rpx;
.list-title {
font-size: 26rpx;
font-weight: 500;
color: #999999;
margin-right: 44rpx;
margin-bottom: 36rpx;
}
.list-desc {
font-size: 26rpx;
font-weight: 500;
color: #333333;
margin-bottom: 36rpx;
}
}
</style>

View File

@ -1,153 +1,71 @@
<!-- 页面 -->
<!-- 订单列表 -->
<template>
<s-layout title="我的订单">
<su-sticky bgColor="#fff">
<su-tabs :list="tabMaps" :scrollable="false" @change="onTabsChange" :current="state.currentTab"></su-tabs>
<su-tabs :list="tabMaps" :scrollable="false" @change="onTabsChange" :current="state.currentTab" />
</su-sticky>
<s-empty v-if="state.pagination.total === 0" icon="/static/order-empty.png" text="暂无订单"></s-empty>
<s-empty v-if="state.pagination.total === 0" icon="/static/order-empty.png" text="暂无订单" />
<view v-if="state.pagination.total > 0">
<view class="bg-white order-list-card-box ss-r-10 ss-m-t-14 ss-m-20" v-for="order in state.pagination.data"
:key="order.id" @tap="onOrderDetail(order.id)">
<view class="bg-white order-list-card-box ss-r-10 ss-m-t-14 ss-m-20" v-for="order in state.pagination.list"
:key="order.id" @tap="onOrderDetail(order.id)">
<view class="order-card-header ss-flex ss-col-center ss-row-between ss-p-x-20">
<view class="order-no">订单号{{ order.no }}</view>
<view class="order-state ss-font-26" :class="formatOrderColor(order.status_code)">{{
order.status
}}</view>
<view class="order-state ss-font-26" :class="formatOrderColor(order)">
{{ formatOrderStatus(order) }}
</view>
</view>
<view class="border-bottom" v-for="item in order.items" :key="item.id">
<s-goods-item :img="item.picUrl" :title="item.spuName"
:skuText="item.properties.length>1? item.properties.reduce((items2,items)=>items2.valueName+' '+items.valueName):item.properties[0].valueName"
:price="item.price/100" :score="order.score_amount" :num="item.count">
<template #tool>
<view class="ss-flex">
<!-- <button class="ss-reset-button apply-btn" v-if="item.btns.includes('aftersale')"
@tap.stop="
sheep.$router.go('/pages/order/aftersale/apply', {
item: JSON.stringify(item),
})
">
申请售后
</button>
<button class="ss-reset-button apply-btn" v-if="item.btns.includes('re_aftersale')"
@tap.stop="
sheep.$router.go('/pages/order/aftersale/apply', {
item: JSON.stringify(item),
})
">
重新售后
</button>
<button class="ss-reset-button apply-btn" v-if="item.btns.includes('aftersale_info')"
@tap.stop="
sheep.$router.go('/pages/order/aftersale/detail', {
id: item.ext.aftersale_id,
})
">
售后详情
</button>
<button class="ss-reset-button apply-btn" v-if="item.btns.includes('buy_again')"
@tap.stop="
sheep.$router.go('/pages/goods/index', {
id: item.goods_id,
})
">
再次购买
</button> -->
</view>
</template>
</s-goods-item>
<s-goods-item
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
/>
</view>
<view class="pay-box ss-m-t-30 ss-flex ss-row-right ss-p-r-20">
<!-- <view v-if="order.total_discount_fee > 0" class="ss-flex ss-col-center ss-m-r-8">
<view class="discounts-title">优惠:</view>
<view class="discounts-money">{{ order.total_discount_fee }}</view>
</view> -->
<!-- <view class="ss-flex ss-col-center ss-m-r-8">
<view class="discounts-title">运费:</view>
<view class="discounts-money">{{ order.dispatch_amount }}</view>
</view> -->
<view class="ss-flex ss-col-center">
<view class="discounts-title pay-color">{{count}}件商品,总金额:</view>
<view class="discounts-money pay-color" v-if="Number(order.payPrice) > 0">
{{ order.payPrice/100 }}</view>
<view v-if="order.score_amount && Number(order.payPrice) > 0">+</view>
<view class="discounts-money pay-color ss-flex ss-col-center" v-if="order.score_amount">
<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img">
</image>
<view>{{ order.score_amount }}</view>
</view>
<view class="discounts-title pay-color"> {{ order.productCount }} 件商品,总金额:</view>
<view class="discounts-money pay-color">
{{ fen2yuan(order.payPrice) }}
</view>
</view>
</view>
<!-- :class="order.btns.length > 3 ? 'ss-row-between' : 'ss-row-right'" -->
<view class="order-card-footer ss-flex ss-col-center ss-p-x-20">
<!-- <su-popover>
<button class="more-btn ss-reset-button" @click.stop>更多</button>
<template #content>
<view class="more-item-box">
<view class="more-item ss-flex ss-col-center ss-reset-button">
<view class="item-title">删除订单</view>
</view>
<view class="more-item ss-flex ss-col-center ss-reset-button">
<view class="item-title">查看发票</view>
</view>
<view class="more-item ss-flex ss-col-center ss-reset-button">
<view class="item-title">评价晒单</view>
</view>
</view>
</template>
</su-popover> -->
<view class="order-card-footer ss-flex ss-col-center ss-p-x-20"
:class="order.buttons.length > 3 ? 'ss-row-between' : 'ss-row-right'">
<view class="ss-flex ss-col-center">
<!-- <button v-if="order.btns.includes('groupon')" class="tool-btn ss-reset-button"
<button v-if="order.buttons.includes('combination')" class="tool-btn ss-reset-button"
@tap.stop="onOrderGroupon(order)">
{{ order.status_code === 'groupon_ing' ? '邀请拼团' : '拼团详情' }}
拼团详情
</button>
<button v-if="order.btns.includes('invoice')" class="tool-btn ss-reset-button"
@tap.stop="onOrderInvoice(order.invoice?.id)">
查看发票
<button v-if="order.buttons.length === 0" class="tool-btn ss-reset-button"
@tap.stop="onOrderDetail(order.id)">
查看详情
</button>
<button v-if="order.btns.length === 0" class="tool-btn ss-reset-button"
@tap.stop="onOrderDetail(order.order_sn)">
查看详情
<button v-if="order.buttons.includes('confirm')" class="tool-btn ss-reset-button"
@tap.stop="onConfirm(order)">
确认收货
</button>
<button v-if="order.btns.includes('confirm')" class="tool-btn ss-reset-button"
@tap.stop="onConfirm(order)">
确认收货
</button>
<button v-if="order.btns.includes('express')" class="tool-btn ss-reset-button"
@tap.stop="onExpress(order.id)">
<button v-if="order.buttons.includes('express')" class="tool-btn ss-reset-button"
@tap.stop="onExpress(order.id)">
查看物流
</button>
<button v-if="order.btns.includes('apply_refund')" class="tool-btn ss-reset-button"
@tap.stop="onRefund(order.id)">
申请退款
</button>
<button v-if="order.btns.includes('re_apply_refund')" class="tool-btn ss-reset-button"
@tap.stop="onRefund(order.id)">
重新退款
</button>
<button v-if="order.btns.includes('cancel')" class="tool-btn ss-reset-button"
@tap.stop="onCancel(order.id)">
<button v-if="order.buttons.includes('cancel')" class="tool-btn ss-reset-button"
@tap.stop="onCancel(order.id)">
取消订单
</button>
<button v-if="order.btns.includes('comment')" class="tool-btn ss-reset-button"
@tap.stop="onComment(order.order_sn)">
评价晒单
<button v-if="order.buttons.includes('comment')" class="tool-btn ss-reset-button"
@tap.stop="onComment(order.id)">
评价
</button>
<button v-if="order.btns.includes('delete')" class="delete-btn ss-reset-button"
@tap.stop="onDelete(order.id)">
<button v-if="order.buttons.includes('delete')" class="delete-btn ss-reset-button"
@tap.stop="onDelete(order.id)">
删除订单
</button>
<button v-if="order.btns.includes('pay')" class="tool-btn ss-reset-button ui-BG-Main-Gradient"
@tap.stop="onPay(order.order_sn)">
<button v-if="order.buttons.includes('pay')" class="tool-btn ss-reset-button ui-BG-Main-Gradient"
@tap.stop="onPay(order.payOrderId)">
继续支付
</button> -->
</button>
</view>
</view>
</view>
@ -156,52 +74,45 @@
<!-- 加载更多 -->
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
contentdown: '上拉加载更多',
}" @tap="loadmore" />
}" @tap="loadMore" />
</s-layout>
</template>
<script setup>
import {
computed,
reactive
} from 'vue';
import {
onLoad,
onReachBottom,
onPullDownRefresh
} from '@dcloudio/uni-app';
import {
formatOrderColor
} from '@/sheep/hooks/useGoods';
import { reactive } from 'vue';
import { onLoad, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app';
import {
fen2yuan,
formatOrderColor, formatOrderStatus, handleOrderButtons,
} from '@/sheep/hooks/useGoods';
import sheep from '@/sheep';
import _ from 'lodash';
import {
isEmpty
} from 'lodash';
import OrderApi from '@/sheep/api/trade/order';
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
const paginationNull = {
list: [],
total: 0,
pageNo: 1,
pageSize: 5,
};
//
const state = reactive({
currentTab: 0,
currentTab: 0, // tabMaps
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
list: [],
total: 0,
pageNo: 1,
pageSize: 5,
},
loadStatus: '',
deleteOrderId: 0,
error: 0,
loadStatus: ''
});
const tabMaps = [{
name: '全部',
// value: 'all',
name: '全部'
},
{
name: '待付款',
@ -223,53 +134,47 @@
//
function onTabsChange(e) {
if (state.currentTab === e.index) return;
state.pagination = pagination;
if (state.currentTab === e.index) {
return;
}
//
state.pagination = paginationNull;
state.currentTab = e.index;
getOrderList();
}
//
function onOrderDetail(orderSN) {
function onOrderDetail(id) {
sheep.$router.go('/pages/order/detail', {
orderSN,
id,
});
}
//
// TODO
function onOrderGroupon(order) {
sheep.$router.go('/pages/activity/groupon/detail', {
id: order.ext.groupon_id,
});
}
//
function onOrderInvoice(invoiceId) {
sheep.$router.go('/pages/order/invoice', {
invoiceId,
});
}
//
function onPay(orderSN) {
function onPay(payOrderId) {
sheep.$router.go('/pages/pay/index', {
orderSN,
id: payOrderId,
});
}
//
function onComment(orderSN) {
function onComment(id) {
sheep.$router.go('/pages/goods/comment/add', {
orderSN,
id,
});
}
//
// TODO
async function onConfirm(order, ignore = false) {
//
// todo:
// todo:
// 1.return
// 2.mpConfirm,App.vueshow
let isOpenBusinessView = true;
@ -284,18 +189,15 @@
}
//
const {
error
} = await sheep.$api.order.confirm(order.id);
if (error === 0) {
state.pagination = pagination;
getOrderList();
const { code } = await OrderApi.receiveOrder(order.id);
if (code === 0) {
state.pagination = paginationNull;
await getOrderList();
}
}
// #ifdef MP-WEIXIN
//
// TODO
function mpConfirm(order) {
if (!wx.openBusinessView) {
sheep.$helper.toast(`请升级微信版本`);
@ -327,9 +229,9 @@
// #endif
//
async function onExpress(orderId) {
sheep.$router.go('/pages/order/express/list', {
orderId,
async function onExpress(id) {
sheep.$router.go('/pages/order/express/log', {
id,
});
}
@ -339,16 +241,17 @@
title: '提示',
content: '确定要取消订单吗?',
success: async function(res) {
if (res.confirm) {
const {
error,
data
} = await sheep.$api.order.cancel(orderId);
if (error === 0) {
let index = state.pagination.data.findIndex((order) => order.id === orderId);
state.pagination.data[index] = data;
}
if (!res.confirm) {
return;
}
const { code } = await OrderApi.cancelOrder(orderId);
if (code === 0) {
//
let index = state.pagination.list.findIndex((order) => order.id === orderId);
const orderInfo = state.pagination.list[index];
orderInfo.status = 40;
handleOrderButtons(orderInfo);
}
},
});
}
@ -360,36 +263,11 @@
content: '确定要删除订单吗?',
success: async function(res) {
if (res.confirm) {
const {
error,
data
} = await sheep.$api.order.delete(orderId);
if (error === 0) {
let index = state.pagination.data.findIndex((order) => order.id === orderId);
state.pagination.data.splice(index, 1);
}
}
},
});
}
// 退
async function onRefund(orderId) {
uni.showModal({
title: '提示',
content: '确定要申请退款吗?',
success: async function(res) {
if (res.confirm) {
// #ifdef MP
sheep.$platform.useProvider('wechat').subscribeMessage('order_refund');
// #endif
const {
error,
data
} = await sheep.$api.order.applyRefund(orderId);
if (error === 0) {
let index = state.pagination.data.findIndex((order) => order.id === orderId);
state.pagination.data[index] = data;
const { code } = await OrderApi.deleteOrder(orderId);
if (code === 0) {
//
let index = state.pagination.list.findIndex((order) => order.id === orderId);
state.pagination.list.splice(index, 1);
}
}
},
@ -397,52 +275,47 @@
}
//
async function getOrderList(page = 1, list_rows = 5) {
async function getOrderList() {
state.loadStatus = 'loading';
let res = await sheep.$api.order.list({
status: tabMaps[state.currentTab].value,
pageSize: list_rows,
pageNo: page,
commentStatus: tabMaps[state.currentTab].value == 30 ? false : null
let { code, data } = await OrderApi.getOrderPage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
status: tabMaps[state.currentTab].value,
commentStatus: tabMaps[state.currentTab].value === 30 ? false : null
});
state.error = res.code;
if (res.code === 0) {
let orderList = _.concat(state.pagination.data, res.data.list);
state.pagination = {
...res.data,
data: orderList,
};
console.log(state.pagination)
if (state.pagination.data.length < state.pagination.total) {
state.loadStatus = 'more';
} else {
state.loadStatus = 'noMore';
}
}
}
if (code !== 0) {
return;
}
data.list.forEach(order => handleOrderButtons(order));
state.pagination.list = _.concat(state.pagination.list, data.list)
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
onLoad(async (options) => {
if (options.type) {
state.currentTab = options.type;
}
getOrderList();
await getOrderList();
});
//
function loadmore() {
if (state.loadStatus !== 'noMore') {
getOrderList(parseInt((state.pagination.data.length / 5) + 1));
function loadMore() {
if (state.loadStatus === 'noMore') {
return
}
}
state.pagination.pageNo++;
getOrderList();
}
//
onReachBottom(() => {
loadmore();
loadMore();
});
//
//
onPullDownRefresh(() => {
state.pagination = pagination;
state.pagination = paginationNull;
getOrderList();
setTimeout(function() {
uni.stopPullDownRefresh();

View File

@ -2,14 +2,17 @@
<template>
<s-layout title="收银台">
<view class="bg-white ss-modal-box ss-flex-col">
<!-- 订单信息 -->
<view class="modal-header ss-flex-col ss-col-center ss-row-center">
<view class="money-box ss-m-b-20">
<text class="money-text">{{ state.orderInfo.pay_fee }}</text>
<text class="money-text">{{ fen2yuan(state.orderInfo.price) }}</text>
</view>
<view class="time-text">
<text>{{ payDescText }}</text>
</view>
</view>
<!-- 支付方式 -->
<view class="modal-content ss-flex-1">
<view class="pay-title ss-p-l-30 ss-m-y-30">选择支付方式</view>
<radio-group @change="onTapPay">
@ -17,7 +20,6 @@
<view
class="pay-item ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom"
:class="{ 'disabled-pay-item': item.disabled }"
v-if="allowedPayment.includes(item.value)"
>
<view class="ss-flex ss-col-center">
<image
@ -25,25 +27,19 @@
v-if="item.disabled"
:src="sheep.$url.static('/static/img/shop/pay/cod_disabled.png')"
mode="aspectFit"
></image>
/>
<image
class="pay-icon"
v-else
:src="sheep.$url.static(item.icon)"
mode="aspectFit"
></image>
/>
<text class="pay-title">{{ item.title }}</text>
</view>
<view class="check-box ss-flex ss-col-center ss-p-l-10">
<view class="userInfo-money ss-m-r-10" v-if="item.value == 'money'">
<view class="userInfo-money ss-m-r-10" v-if="item.value === 'wallet'">
余额: {{ userInfo.money }}
</view>
<view
class="userInfo-money ss-m-r-10"
v-if="item.value == 'offline' && item.disabled"
>
部分商品不支持
</view>
<radio
:value="item.value"
color="var(--ui-BG-Main)"
@ -56,6 +52,7 @@
</label>
</radio-group>
</view>
<!-- 工具 -->
<view class="modal-footer ss-flex ss-row-center ss-col-center ss-m-t-80 ss-m-b-40">
<button v-if="state.payStatus === 0" class="ss-reset-button past-due-btn">
@ -81,95 +78,49 @@
import { computed, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { useDurationTime } from '@/sheep/hooks/useGoods';
import { fen2yuan, useDurationTime } from '@/sheep/hooks/useGoods';
import PayOrderApi from '@/sheep/api/pay/order';
import PayChannelApi from '@/sheep/api/pay/channel';
import { getPayMethods } from '@/sheep/platform/pay';
const userInfo = computed(() => sheep.$store('user').userInfo);
//
const state = reactive({
orderType: 'goods',
payment: '',
orderInfo: {},
orderType: 'goods', // ; goods - , recharge -
orderInfo: {}, //
payStatus: 0, // 0=, -2= -1= 1=2=
payMethods: [],
payMethods: [], //
payment: '', //
});
const allowedPayment = computed(() => {
if(state.orderType === 'recharge') {
return sheep.$store('app').platform.recharge_payment
}
return sheep.$store('app').platform.payment
});
const payMethods = [
{
icon: '/static/img/shop/pay/wechat.png',
title: '微信支付',
value: 'wechat',
disabled: false,
},
{
icon: '/static/img/shop/pay/alipay.png',
title: '支付宝支付',
value: 'alipay',
disabled: false,
},
{
icon: '/static/img/shop/pay/wallet.png',
title: '余额支付',
value: 'money',
disabled: false,
},
{
icon: '/static/img/shop/pay/apple.png',
title: 'Apple Pay',
value: 'apple',
disabled: false,
},
{
icon: '/static/img/shop/pay/cod.png',
title: '货到付款',
value: 'offline',
disabled: false,
},
];
const onPay = () => {
if (state.payment === '') {
sheep.$helper.toast('请选择支付方式');
return;
}
if (state.payment === 'money') {
if (state.payment === 'wallet') {
uni.showModal({
title: '提示',
content: '确定要支付吗?',
success: function (res) {
if (res.confirm) {
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.order_sn);
}
},
});
} else if (state.payment === 'offline') {
uni.showModal({
title: '提示',
content: '确定要下单吗?',
success: function (res) {
if (res.confirm) {
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.order_sn);
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.id);
}
},
});
} else {
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.order_sn);
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.id);
}
};
//
const payDescText = computed(() => {
if (state.payStatus === 2) {
return '该订单已支付';
}
if (state.payStatus === 1 && state.orderInfo.ext.expired_time !== 0) {
const time = useDurationTime(state.orderInfo.ext.expired_time);
if (state.payStatus === 1) {
const time = useDurationTime(state.orderInfo.expireTime);
if (time.ms <= 0) {
state.payStatus = -1;
return '';
@ -179,86 +130,65 @@
if (state.payStatus === -2) {
return '未查询到支付单信息';
}
return '';
});
// payOrder.status => payStatus
function checkPayStatus() {
if (state.orderInfo.status === 'unpaid') {
state.payStatus = 1;
if (state.orderInfo.status === 10
|| state.orderInfo.status === 20 ) { //
state.payStatus = 2;
return;
}
if (state.orderInfo.status === 'closed') {
if (state.orderInfo.status === 30) { //
state.payStatus = -1;
return;
}
state.payStatus = 2;
state.payStatus = 1; //
}
//
function onTapPay(e) {
state.payment = e.detail.value;
}
async function setRechargeOrder(id) {
const { data, error } = await sheep.$api.trade.order(id);
if (error === 0) {
state.orderInfo = data;
state.payMethods = payMethods;
checkPayStatus();
} else {
//
async function setOrder(id) {
//
const { data, code } = await PayOrderApi.getOrder(id);
if (code !== 0 || !data) {
state.payStatus = -2;
return;
}
state.orderInfo = data;
//
await setPayMethods();
//
checkPayStatus();
}
async function setGoodsOrder(id) {
const { data, error } = await sheep.$api.order.detail(id);
if (error === 0) {
state.orderInfo = data;
if (state.orderInfo.ext.offline_status === 'none') {
payMethods.forEach((item, index, array) => {
if (item.value === 'offline') {
array.splice(index, 1);
}
});
} else if (state.orderInfo.ext.offline_status === 'disabled') {
payMethods.forEach((item) => {
if (item.value === 'offline') {
item.disabled = true;
}
});
}
state.payMethods = payMethods;
checkPayStatus();
} else {
state.payStatus = -2;
//
async function setPayMethods() {
const { data, code } = await PayChannelApi.getEnableChannelCodeList(state.orderInfo.appId)
if (code !== 0) {
return
}
state.payMethods = getPayMethods(data)
}
onLoad((options) => {
if (
sheep.$platform.name === 'WechatOfficialAccount' &&
sheep.$platform.os === 'ios' &&
!sheep.$platform.landingPage.includes('pages/pay/index')
) {
if (sheep.$platform.name === 'WechatOfficialAccount'
&& sheep.$platform.os === 'ios'
&& !sheep.$platform.landingPage.includes('pages/pay/index')) {
location.reload();
return;
}
let id = '';
if (options.orderSN) {
id = options.orderSN;
}
if (options.id) {
id = options.id;
}
if (options.type === 'recharge') {
state.orderType = 'recharge';
//
setRechargeOrder(id);
} else {
state.orderType = 'goods';
//
setGoodsOrder(id);
//
let id = options.id;
if (options.orderType) {
state.orderType = options.orderType;
}
setOrder(id);
});
</script>

View File

@ -2,34 +2,27 @@
<template>
<s-layout title="支付结果" :bgStyle="{ color: '#FFF' }">
<view class="pay-result-box ss-flex-col ss-row-center ss-col-center">
<view class="pay-waiting ss-m-b-30" v-if="payResult === 'waiting'"> </view>
<!-- 信息展示 -->
<view class="pay-waiting ss-m-b-30" v-if="payResult === 'waiting'" />
<image
class="pay-img ss-m-b-30"
v-if="payResult === 'success'"
:src="sheep.$url.static('/static/img/shop/order/order_pay_success.gif')"
></image>
/>
<image
class="pay-img ss-m-b-30"
v-if="['failed', 'closed'].includes(payResult)"
:src="sheep.$url.static('/static/img/shop/order/order_paty_fail.gif')"
></image>
<view class="tip-text ss-m-b-30" v-if="payResult == 'success'">{{
state.orderInfo.pay_mode === 'offline' ? '下单成功' : '支付成功'
}}</view>
<view class="tip-text ss-m-b-30" v-if="payResult == 'failed'"></view>
<view class="tip-text ss-m-b-30" v-if="payResult == 'closed'"></view>
<view class="tip-text ss-m-b-30" v-if="payResult == 'waiting'">...</view>
/>
<view class="tip-text ss-m-b-30" v-if="payResult === 'success'"></view>
<view class="tip-text ss-m-b-30" v-if="payResult === 'failed'"></view>
<view class="tip-text ss-m-b-30" v-if="payResult === 'closed'"></view>
<view class="tip-text ss-m-b-30" v-if="payResult === 'waiting'">...</view>
<view class="pay-total-num ss-flex" v-if="payResult === 'success'">
<view v-if="Number(state.orderInfo.pay_fee) > 0">{{ state.orderInfo.pay_fee }}</view>
<view v-if="state.orderInfo.score_amount && Number(state.orderInfo.pay_fee) > 0">+</view>
<view class="price-text ss-flex ss-col-center" v-if="state.orderInfo.score_amount">
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
></image>
<view>{{ state.orderInfo.score_amount }}</view>
</view>
<view>{{ fen2yuan(state.orderInfo.price) }}</view>
</view>
<!-- 操作区 -->
<view class="btn-box ss-flex ss-row-center ss-m-t-50">
<button class="back-btn ss-reset-button" @tap="sheep.$router.go('/pages/index/index')">
返回首页
@ -37,30 +30,29 @@
<button
class="check-btn ss-reset-button"
v-if="payResult === 'failed'"
@tap="sheep.$router.redirect('/pages/pay/index', { orderSN: state.orderId })"
@tap="
sheep.$router.redirect('/pages/pay/index', { id: state.id, orderType: state.orderType })
"
>
重新支付
</button>
<button class="check-btn ss-reset-button" v-if="payResult === 'success'" @tap="onOrder">
查看订单
</button>
<!-- TODO 芋艿拼团接入 -->
<button
class="check-btn ss-reset-button"
v-if="
payResult === 'success' &&
['groupon', 'groupon_ladder'].includes(state.orderInfo.activity_type)
"
v-if="payResult === 'success' && state.tradeOrder.type === 3"
@tap="sheep.$router.redirect('/pages/activity/groupon/order')"
>
我的拼团
</button>
</view>
<!-- TODO 芋艿订阅 -->
<!-- #ifdef MP -->
<view class="subscribe-box ss-flex ss-m-t-44">
<image
class="subscribe-img"
:src="sheep.$url.static('/static/img/shop/order/cargo.png')"
></image>
<image class="subscribe-img" :src="sheep.$url.static('/static/img/shop/order/cargo.png')" />
<view class="subscribe-title ss-m-r-48 ss-m-l-16">获取实时发货信息与订单状态</view>
<view class="subscribe-start" @tap="subscribeMessage"></view>
</view>
@ -74,15 +66,20 @@
import { reactive, computed } from 'vue';
import { isEmpty } from 'lodash';
import sheep from '@/sheep';
import PayOrderApi from '@/sheep/api/pay/order';
import { fen2yuan } from '../../sheep/hooks/useGoods';
import OrderApi from '@/sheep/api/trade/order';
const state = reactive({
orderId: 0,
orderType: 'goods',
id: 0, //
orderType: 'goods', //
result: 'unpaid', //
orderInfo: {}, //
orderInfo: {}, //
tradeOrder: {}, // orderType goods
counter: 0, //
});
// result => payResult
const payResult = computed(() => {
if (state.result === 'unpaid') {
return 'waiting';
@ -93,57 +90,65 @@
if (state.result === 'failed') {
return 'failed';
}
if (state.result === 'closed') {
return 'closed';
}
});
async function getOrderInfo(orderId) {
let checkPayResult;
//
async function getOrderInfo(id) {
state.counter++;
if (state.orderType === 'recharge') {
checkPayResult = sheep.$api.trade.order;
} else {
checkPayResult = sheep.$api.order.detail;
}
const { data, error } = await checkPayResult(orderId);
if (error === 0) {
// 1.
const { data, code } = await PayOrderApi.getOrder(id);
if (code === 0) {
state.orderInfo = data;
if (state.orderInfo.status === 'closed') {
if (!state.orderInfo || state.orderInfo.status === 30) {
//
state.result = 'closed';
return;
}
if (state.orderInfo.status !== 'unpaid') {
if (state.orderInfo.status !== 0) {
// 退
state.result = 'paid';
// #ifdef MP
subscribeMessage();
// #endif
//
if (state.orderType === 'goods') {
const { data, code } = await OrderApi.getOrder(state.orderInfo.merchantOrderId);
if (code === 0) {
state.tradeOrder = data;
}
}
return;
}
}
// 2.1
if (state.counter < 3 && state.result === 'unpaid') {
setTimeout(() => {
getOrderInfo(orderId);
getOrderInfo(id);
}, 1500);
}
//
// 2.2
if (state.counter >= 3) {
state.result = 'failed';
}
}
function onOrder() {
if ((state.orderType === 'recharge')) {
// TODO
if (state.orderType === 'recharge') {
sheep.$router.redirect('/pages/pay/recharge-log');
} else {
sheep.$router.redirect('/pages/order/list');
}
}
// TODO
// #ifdef MP
function subscribeMessage() {
let event = ['order_dispatched'];
if (['groupon', 'groupon_ladder'].includes(state.orderInfo.activity_type)) {
if (state.tradeOrder.type === 3) {
event.push('groupon_finish');
event.push('groupon_fail');
}
@ -152,18 +157,13 @@
// #endif
onLoad(async (options) => {
let id = '';
//
if (options.orderSN) {
id = options.orderSN;
}
if (options.id) {
id = options.id;
state.id = options.id;
}
state.orderId = id;
if (options.orderType === 'recharge') {
state.orderType = 'recharge';
//
if (options.orderType) {
state.orderType = options.orderType;
}
//
@ -171,14 +171,16 @@
state.result = 'failed';
} else {
//
getOrderInfo(state.orderId);
await getOrderInfo(state.id);
}
});
onShow(() => {
if(isEmpty(state.orderInfo)) return;
getOrderInfo(state.orderId);
})
if (isEmpty(state.orderInfo)) {
return;
}
getOrderInfo(state.id);
});
onHide(() => {
state.result = 'unpaid';

View File

@ -1,3 +1,4 @@
<!-- 错误界面 -->
<template>
<view class="error-page">
<s-empty
@ -8,7 +9,7 @@
actionText="重新连接"
@clickAction="onReconnect"
buttonColor="#ff3000"
></s-empty>
/>
<s-empty
v-else-if="errCode === 'TemplateError'"
icon="/static/internet-empty.png"
@ -17,7 +18,7 @@
actionText="重新加载"
@clickAction="onReconnect"
buttonColor="#ff3000"
></s-empty>
/>
<s-empty
v-else-if="errCode !== ''"
icon="/static/internet-empty.png"
@ -26,7 +27,7 @@
actionText="重新加载"
@clickAction="onReconnect"
buttonColor="#ff3000"
></s-empty>
/>
</view>
</template>
@ -37,16 +38,18 @@
const errCode = ref('');
const errMsg = ref('');
onLoad((options) => {
errCode.value = options.errCode;
errMsg.value = options.errMsg;
});
//
async function onReconnect() {
uni.reLaunch({
url: '/pages/index/index',
});
ShoproInit();
await ShoproInit();
}
</script>

View File

@ -1,226 +0,0 @@
<template>
<s-layout class="set-wrap" title="问题反馈">
<uni-forms ref="form" :modelValue="state.formData" border>
<view class="bg-white type-box ss-p-x-20 ss-p-y-30">
<view class="title ss-m-b-44">请选择类型</view>
<view class="ss-m-l-12">
<radio-group @change="radioChange">
<label
class="ss-flex ss-col-center ss-m-b-40"
v-for="item in state.radioList"
:key="item.type"
>
<radio :value="item.type" color="var(--ui-BG-Main)" style="transform: scale(0.8)" />
<view class="radio-subtitle">{{ item.type }}</view>
</label>
</radio-group>
</view>
</view>
<view class="bg-white ss-p-x-20 ss-p-y-30 ss-m-t-20">
<view class="title ss-m-b-30"> 相关描述 </view>
<view class="textarea">
<uni-easyinput
:inputBorder="false"
type="textarea"
v-model="state.formData.content"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
placeholder="客官~请描述您遇到的问题,建议上传照片"
clearable
></uni-easyinput>
<s-uploader
v-model:url="state.formData.images"
fileMediatype="image"
limit="9"
mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx' }"
></s-uploader>
</view>
</view>
<view class="bg-white ss-p-x-20 ss-p-y-30 ss-m-t-20">
<view class="title ss-m-b-30"> 联系方式 </view>
<view class="mobile-box">
<uni-easyinput
:inputBorder="false"
type="number"
v-model="state.formData.phone"
paddingLeft="10"
placeholder="请输入您的联系电话"
/>
</view>
</view>
</uni-forms>
<su-fixed bottom placeholder>
<view class="ss-flex ss-row-between ss-p-x-30 ss-p-y-10">
<button class="kefu-btn ss-reset-button" @tap="sheep.$router.go('/pages/chat/index')">
联系客服
</button>
<button class="submit-btn ss-reset-button ui-BG-Main ui-Shadow-Main" @tap="onSubmit">
提交
</button>
</view>
</su-fixed>
</s-layout>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { computed, reactive, ref, unref } from 'vue';
import sheep from '@/sheep';
const filesRef = ref(null);
const state = reactive({
radioList: [
{
type: '产品功能问题反馈',
},
{
type: '建议及意见反馈',
},
{
type: '投诉客服其他问题',
},
],
formData: {
content: '',
phone: '',
images: [],
type: '',
},
imageFiles: [],
current: 0,
});
async function onSubmit() {
if (!state.formData.type) {
sheep.$helper.toast('请选择类型');
return;
}
if (!state.formData.content) {
sheep.$helper.toast('请描述您遇到的问题');
return;
}
if (!state.formData.phone) {
sheep.$helper.toast('请输入您的联系方式');
return;
}
const { error } = await sheep.$api.app.feedback(state.formData);
if (error === 0) {
sheep.$router.back();
}
}
function radioChange(e) {
state.formData.type = e.detail.value;
}
</script>
<style lang="scss" scoped>
.type-box {
border-top: 2rpx solid #f9fafb;
}
.uni-forms {
width: 100%;
}
.title {
font-size: 30rpx;
font-weight: bold;
color: #333333;
line-height: normal;
}
:deep() {
.uni-easyinput__placeholder-class {
color: #bbbbbb !important;
font-size: 28rpx !important;
font-weight: 400 !important;
line-height: normal !important;
}
.uni-forms-item__label .label-text {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
}
.uni-list-item__content-title {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
}
.uni-easyinput__content-textarea {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
margin-top: 4rpx !important;
padding-left: 20rpx !important;
}
.uni-icons {
font-size: 40rpx !important;
}
.icon-del-box {
width: 32rpx;
height: 32rpx;
top: 0;
right: 0;
.icon-del {
width: 24rpx;
}
}
}
.radio-subtitle {
font-size: 28rpx;
font-weight: 500;
color: #333333;
line-height: 42rpx;
}
.textarea {
min-height: 322rpx;
background: #f9fafb;
border-radius: 20rpx;
padding: 20rpx;
margin: 30rpx 20rpx 46rpx 0;
.area {
height: 238rpx;
font-size: 26rpx;
font-weight: 500;
color: #333;
line-height: 50rpx;
width: 100%;
}
.pl-style {
font-size: 24rpx;
color: #b1b3c7;
font-weight: 500;
}
}
.mobile-box {
background: #f9fafb;
border-radius: 20rpx;
}
.submit-btn {
width: 334rpx;
height: 74rpx;
border-radius: 37rpx;
}
.kefu-btn {
width: 334rpx;
height: 74rpx;
border-radius: 37rpx;
background: #eeeeee;
color: #333333;
}
</style>

View File

@ -19,22 +19,15 @@
:border="false"
class="list-border"
@tap="onCheckUpdate"
></uni-list-item>
/>
<uni-list-item
title="本地缓存"
:rightText="storageSize"
showArrow
:border="false"
class="list-border"
></uni-list-item>
<uni-list-item
title="意见反馈"
showArrow
clickable
:border="false"
class="list-border"
@tap="sheep.$router.go('/pages/public/feedback')"
></uni-list-item>
/>
<!-- TODO 芋艿统一的配置界面 -->
<uni-list-item
title="关于我们"
showArrow
@ -47,8 +40,8 @@
title: appInfo.about_us.title,
})
"
></uni-list-item>
<!-- 为了过审 只有iOS-App有注销账号功能 -->
/>
<!-- 为了过审 只有 iOS-App 有注销账号功能 -->
<uni-list-item
v-if="isLogin && sheep.$platform.os === 'ios' && sheep.$platform.name === 'App'"
title="注销账号"
@ -58,10 +51,10 @@
:border="false"
class="list-border"
@click="onLogoff"
></uni-list-item>
/>
</uni-list>
</view>
<!-- TODO 芋艿统一的配置界面 -->
<view class="set-footer ss-flex-col ss-row-center ss-col-center">
<view class="agreement-box ss-flex ss-col-center ss-m-b-40">
<view class="ss-flex ss-col-center ss-m-b-10">
@ -124,32 +117,36 @@
// H5
// App 1. 2. 3.
}
//
function onLogoff() {
uni.showModal({
title: '提示',
content: '确认注销账号?',
success: async function (res) {
if (res.confirm) {
const { error } = await sheep.$api.user.logoff();
if (error === 0) {
sheep.$store('user').logout();
sheep.$router.go('/pages/index/user');
}
if (!res.confirm) {
return;
}
const result = await sheep.$store('user').logout();
if (result) {
sheep.$router.go('/pages/index/user');
}
},
});
}
// 退
function onLogout() {
uni.showModal({
title: '提示',
content: '确认退出账号?',
success: async function (res) {
if (res.confirm) {
const result = await sheep.$store('user').logout();
if (result) {
sheep.$router.go('/pages/index/user');
}
if (!res.confirm) {
return;
}
const result = await sheep.$store('user').logout();
if (result) {
sheep.$router.go('/pages/index/user');
}
},
});

View File

@ -1,5 +1,8 @@
<!-- 网页加载 -->
<template>
<view><web-view :src="url"></web-view></view>
<view>
<web-view :src="url" />
</view>
</template>
<script setup>

View File

@ -1,10 +1,11 @@
<!-- 收货地址的新增/编辑 -->
<template>
<s-layout :title="state.model.id ? '编辑地址' : '新增地址'">
<uni-forms ref="addressFormRef" v-model="state.model" :rules="state.rules" validateTrigger="bind"
<uni-forms ref="addressFormRef" v-model="state.model" :rules="rules" validateTrigger="bind"
labelWidth="160" labelAlign="left" border :labelStyle="{ fontWeight: 'bold' }">
<view class="bg-white form-box ss-p-x-30">
<uni-forms-item name="consignee" label="收货人" class="form-item">
<uni-easyinput v-model="state.model.consignee" placeholder="请填写收货人姓名" :inputBorder="false"
<uni-forms-item name="name" label="收货人" class="form-item">
<uni-easyinput v-model="state.model.name" placeholder="请填写收货人姓名" :inputBorder="false"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal" />
</uni-forms-item>
@ -13,178 +14,160 @@
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal">
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="region" label="省市区" @tap="state.showRegion = true" class="form-item">
<uni-easyinput v-model="state.model.region" disabled :inputBorder="false"
<uni-forms-item name="areaName" label="省市区" @tap="state.showRegion = true" class="form-item">
<uni-easyinput v-model="state.model.areaName" disabled :inputBorder="false"
:styles="{ disableColor: '#fff', color: '#333' }"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
placeholder="请选择省市区">
<template v-slot:right>
<uni-icons type="right"></uni-icons>
<uni-icons type="right" />
</template>
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="address" label="详细地址" :formItemStyle="{ alignItems: 'flex-start' }"
<uni-forms-item name="detailAddress" label="详细地址" :formItemStyle="{ alignItems: 'flex-start' }"
:labelStyle="{ lineHeight: '5em' }" class="textarea-item">
<uni-easyinput :inputBorder="false" type="textarea" v-model="state.model.address"
<uni-easyinput :inputBorder="false" type="textarea" v-model="state.model.detailAddress"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
placeholder="请输入详细地址" clearable></uni-easyinput>
placeholder="请输入详细地址" clearable />
</uni-forms-item>
</view>
<view class="ss-m-y-20 bg-white ss-p-x-30 ss-flex ss-row-between ss-col-center default-box">
<view class="default-box-title"> 设为默认地址 </view>
<su-switch style="transform: scale(0.8)" v-model="state.model.is_default"></su-switch>
<su-switch style="transform: scale(0.8)" v-model="state.model.defaultStatus" />
</view>
</uni-forms>
<su-fixed bottom :opacity="false" bg="" placeholder :noFixed="false" :index="10">
<view class="footer-box ss-flex-col ss-row-between ss-p-20">
<view class="ss-m-b-20"><button class="ss-reset-button save-btn ui-Shadow-Main"
@tap="onSave">保存</button></view>
<view class="ss-m-b-20">
<button class="ss-reset-button save-btn ui-Shadow-Main" @tap="onSave"></button>
</view>
<button v-if="state.model.id" class="ss-reset-button cancel-btn" @tap="onDelete">
删除
</button>
</view>
</su-fixed>
<!-- 省市区弹窗 -->
<su-region-picker :show="state.showRegion" @cancel="state.showRegion = false" @confirm="onRegionConfirm">
</su-region-picker>
<su-region-picker :show="state.showRegion" @cancel="state.showRegion = false" @confirm="onRegionConfirm" />
</s-layout>
</template>
<script setup>
import {
computed,
watch,
ref,
reactive,
unref
} from 'vue';
import { ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import {
onLoad,
onPageScroll
} from '@dcloudio/uni-app';
import { onLoad } from '@dcloudio/uni-app';
import _ from 'lodash';
import {
consignee,
mobile,
address,
region
} from '@/sheep/validate/form';
import { mobile } from '@/sheep/validate/form';
import AreaApi from '@/sheep/api/system/area';
import AddressApi from '@/sheep/api/member/address';
const addressFormRef = ref(null);
const state = reactive({
showRegion: false,
model: {
consignee: '',
name: '',
mobile: '',
address: '',
is_default: false,
region: '',
},
rules: {
consignee,
mobile,
address,
region,
detailAddress: '',
defaultStatus: false,
areaName: '',
},
rules: {},
});
watch(
() => state.model.province_name,
(newValue) => {
if (newValue) {
state.model.region =
`${state.model.province_name}-${state.model.city_name}-${state.model.district_name}`;
}
}, {
deep: true,
},
);
const rules = {
name: {
rules: [
{
required: true,
errorMessage: '请输入收货人姓名',
},
],
},
mobile,
detailAddress: {
rules: [{
required: true,
errorMessage: '请输入详细地址',
}]
},
areaName: {
rules: [{
required: true,
errorMessage: '请选择您的位置'
}]
},
};
//
const onRegionConfirm = (e) => {
console.log(e);
state.model = {
...state.model,
...e,
};
state.model.areaName = `${e.province_name} ${e.city_name} ${e.district_name}`
state.model.areaId = e.district_id;
state.showRegion = false;
};
//
const getAreaData = () => {
if (_.isEmpty(uni.getStorageSync('areaData'))) {
sheep.$api.data.area().then((res) => {
if (res.code === 0) {
uni.setStorageSync('areaData', res.data);
}
});
AreaApi.getAreaTree().then((res) => {
if (res.code === 0) {
uni.setStorageSync('areaData', res.data);
}
});
}
};
//
const onSave = async () => {
//
const validate = await unref(addressFormRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
if (!validate) {
return;
}
let res = null;
if (state.model.id) {
res = await sheep.$api.user.address.update({
id: state.model.id,
areaId: state.model.district_id,
defaultStatus: state.model.is_default,
detailAddress: state.model.address,
mobile: state.model.mobile,
name: state.model.consignee
});
} else {
res = await sheep.$api.user.address.create({
areaId: state.model.district_id,
defaultStatus: state.model.is_default,
detailAddress: state.model.address,
mobile: state.model.mobile,
name: state.model.consignee
});
}
if (res.code === 0) {
//
const formData = {
...state.model
}
const {code } = state.model.id > 0 ? await AddressApi.updateAddress(formData)
: await AddressApi.createAddress(formData);
if (code === 0) {
sheep.$router.back();
}
};
//
const onDelete = () => {
uni.showModal({
title: '提示',
content: '确认删除此收货地址吗?',
success: async function(res) {
if (res.confirm) {
const {
code
} = await sheep.$api.user.address.delete(state.model.id);
if (code === 0) {
sheep.$router.back();
}
if (!res.confirm) {
return;
}
const { code } = await AddressApi.deleteAddress(state.model.id);
if (code === 0) {
sheep.$router.back();
}
},
});
};
onLoad(async (options) => {
getAreaData();
if (options.id) {
let res = await sheep.$api.user.address.detail(options.id);
if (res.code === 0) {
state.model = {
...state.model,
district_id: res.data.areaId,
is_default: res.data.defaultStatus,
address: res.data.detailAddress,
mobile: res.data.mobile,
consignee: res.data.name,
id: res.data.id,
province_name: res.data.areaName.split(' ')[0],
city_name: res.data.areaName.split(' ')[1],
district_name: res.data.areaName.split(' ')[2]
};
}
}
onLoad(async (options) => {
//
getAreaData();
// id
if (options.id) {
let { code, data} = await AddressApi.getAddress(options.id);
if (code !== 0) {
return;
}
state.model = data;
}
// TODO
if (options.data) {
let data = JSON.parse(options.data);
const areaData = uni.getStorageSync('areaData');

View File

@ -1,9 +1,9 @@
<!-- 收件地址列表 -->
<template>
<s-layout title="收货地址" :bgStyle="{ color: '#FFF' }">
<view v-if="state.list.length">
<s-address-item hasBorderBottom v-for="item in state.list" :key="item.id" :item="item"
@tap="onSelect(item)">
</s-address-item>
@tap="onSelect(item)" />
</view>
<su-fixed bottom placeholder>
@ -26,20 +26,15 @@
</template>
<script setup>
import {
reactive,
onBeforeMount
} from 'vue';
import {
onShow
} from '@dcloudio/uni-app';
import { reactive, onBeforeMount } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import {
isEmpty
} from 'lodash';
import { isEmpty } from 'lodash';
import AreaApi from '@/sheep/api/system/area';
import AddressApi from '@/sheep/api/member/address';
const state = reactive({
list: [],
list: [], //
loading: true,
});
@ -52,6 +47,7 @@
};
//
// TODO
function importWechatAddress() {
let wechatAddress = {};
// #ifdef MP
@ -102,7 +98,7 @@
}
onShow(async () => {
state.list = (await sheep.$api.user.address.list()).data;
state.list = (await AddressApi.getAddressList()).data;
state.loading = false;
});
@ -111,8 +107,8 @@
return;
}
//
sheep.$api.data.area().then((res) => {
if (res.error === 0) {
AreaApi.getAreaTree().then((res) => {
if (res.code === 0) {
uni.setStorageSync('areaData', res.data);
}
});

View File

@ -1,12 +1,11 @@
<!-- 我的商品收藏 -->
<template>
<s-layout title="商品收藏">
<view class="cart-box ss-flex ss-flex-col ss-row-between">
<!-- 头部 -->
<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.pagination.total }}</text>
件商品
<text class="goods-number ui-TC-Main ss-flex">{{ state.pagination.total }}</text> 件商品
</view>
<view class="header-right">
<button
@ -20,15 +19,16 @@
v-if="!state.editMode && state.pagination.total"
class="ss-reset-button ui-TC-Main"
@tap="state.editMode = true"
>编辑</button
>
编辑
</button>
</view>
</view>
<!-- 内容 -->
<view class="cart-content">
<view
class="goods-box ss-r-10 ss-m-b-14"
v-for="item in state.pagination.data"
v-for="item in state.pagination.list"
:key="item.id"
>
<view class="ss-flex ss-col-center">
@ -44,12 +44,10 @@
@tap.stop="onSelect(item.spuId)"
/>
</label>
<!-- :skuText="item.goods.subtitle" -->
<s-goods-item
:title="item.spuName"
:img="item.picUrl"
:price="item.price"
priceColor="#FF3000"
:titleWidth="400"
@tap="
@ -57,11 +55,11 @@
id: item.spuId,
})
"
>
</s-goods-item>
/>
</view>
</view>
</view>
<!-- 底部 -->
<su-fixed bottom :val="0" placeholder v-show="state.editMode">
<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
@ -79,9 +77,9 @@
<view class="footer-right">
<button
class="ss-reset-button ui-BG-Main-Gradient pay-btn ss-font-28 ui-Shadow-Main"
@tap="onCancel"
>取消收藏</button
>
@tap="onCancel">
取消收藏
</button>
</view>
</view>
</su-fixed>
@ -92,7 +90,7 @@
:content-text="{
contentdown: '上拉加载更多',
}"
@tap="loadmore"
@tap="loadMore"
/>
<s-empty v-if="state.pagination.total === 0" text="暂无收藏" icon="/static/collect-empty.png" />
</s-layout>
@ -103,98 +101,89 @@
import { reactive } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import _ from 'lodash';
import FavoriteApi from '@/sheep/api/product/favorite';
import { resetPagination } from '@/sheep/util';
const sys_navBar = sheep.$platform.navbar;
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
};
const state = reactive({
pagination: {
data: [],
current_page: 1,
total: 1,
last_page: 1,
list: [],
total: 0,
pageNo: 1,
pageSize: 6,
},
loadStatus: '',
editMode: false,
selectedCollectList: [],
selectedCollectList: [], // SPU
selectAll: false,
});
async function getData(page = 1, list_rows = 6) {
async function getData() {
state.loadStatus = 'loading';
let res = await sheep.$api.user.favorite.list({
pageSize:list_rows,
pageNo:page,
const { code, data } = await FavoriteApi.getFavoritePage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
});
if (res.code === 0) {
console.log('yudao收藏列表',res)
let orderList = _.concat(state.pagination.data, res.data.list);
state.pagination = {
...res.data,
data: orderList,
};
//
if (state.pagination.current_page < state.pagination.last_page) {
state.loadStatus = 'more';
} else {
state.loadStatus = 'noMore';
}
if (code !== 0) {
return;
}
}
//
function formatPrice(e) {
return e.length === 1 ? e[0] : e.join('~');
state.pagination.list = _.concat(state.pagination.list, data.list)
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
//
const onSelect = (id) => {
if (!state.selectedCollectList.includes(id)) {
state.selectedCollectList.push(id);
const onSelect = (spuId) => {
if (!state.selectedCollectList.includes(spuId)) {
state.selectedCollectList.push(spuId);
} else {
state.selectedCollectList.splice(state.selectedCollectList.indexOf(id), 1);
state.selectedCollectList.splice(state.selectedCollectList.indexOf(spuId), 1);
}
state.selectAll = state.selectedCollectList.length === state.pagination.data.length;
state.selectAll = state.selectedCollectList.length === state.pagination.list.length;
};
//
const onSelectAll = () => {
state.selectAll = !state.selectAll;
if (!state.selectAll) {
state.selectedCollectList = [];
} else {
state.pagination.data.forEach((item) => {
if (state.selectedCollectList.includes(item.goods_id)) {
state.selectedCollectList.splice(state.selectedCollectList.indexOf(item.goods_id), 1);
}
state.selectedCollectList.push(item.goods_id);
});
state.selectedCollectList = state.pagination.list.map((item) => item.spuId);
}
};
async function onCancel() {
if (state.selectedCollectList) {
state.selectedCollectList = state.selectedCollectList.toString();
const { code } = await sheep.$api.user.favorite.cancel(state.selectedCollectList);
if (code === 0) {
state.editMode = false;
state.selectedCollectList = [];
state.selectAll = false;
state.pagination = pagination;
getData();
}
if (!state.selectedCollectList) {
return;
}
//
for (const spuId of state.selectedCollectList) {
await FavoriteApi.deleteFavorite(spuId);
}
// +
state.editMode = false;
state.selectedCollectList = [];
state.selectAll = false;
resetPagination(state.pagination);
await getData();
}
//
function loadmore() {
if (state.loadStatus !== 'noMore') {
getData(state.pagination.current_page + 1);
function loadMore() {
if (state.loadStatus === 'noMore') {
return
}
state.pagination.pageNo++;
getData();
}
onReachBottom(() => {
loadmore();
loadMore();
});
onLoad(() => {
getData();
});

View File

@ -1,3 +1,4 @@
<!-- 用户信息 -->
<template>
<s-layout title="用户信息" class="set-userinfo-wrap">
<uni-forms
@ -7,26 +8,27 @@
border
class="form-box"
>
<!-- 头像 -->
<view class="ss-flex ss-row-center ss-col-center ss-p-t-60 ss-p-b-0 bg-white">
<view class="header-box-content">
<su-image
class="content-img"
isPreview
:current="0"
:src="sheep.$url.cdn(state.model.avatar)"
:src="state.model?.avatar"
:height="160"
:width="160"
:radius="80"
mode="scaleToFill"
></su-image>
/>
<view class="avatar-action">
<!-- #ifdef MP -->
<button
class="ss-reset-button avatar-action-btn"
open-type="chooseAvatar"
@chooseavatar="onChooseAvatar"
>修改</button
>
@chooseavatar="onChooseAvatar">
修改
</button>
<!-- #endif -->
<!-- #ifndef MP -->
<button class="ss-reset-button avatar-action-btn" @tap="onChangeAvatar"></button>
@ -36,25 +38,7 @@
</view>
<view class="bg-white ss-p-x-30">
<!-- <uni-forms-item name="username" label="用户名" @tap="onChangeUsername" class="label-box">
<uni-easyinput
v-model="userInfo.username"
disabled
:inputBorder="false"
:styles="{ disableColor: '#fff' }"
placeholder="设置用户名"
:clearable="false"
:placeholderStyle="placeholderStyle"
>
<template v-slot:right>
<su-radio class="ss-flex" v-if="userInfo.verification?.username" :modelValue="true" />
<button v-else class="ss-reset-button">
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx"></text>
</button>
</template>
</uni-easyinput>
</uni-forms-item> -->
<!-- 昵称 + 性别 -->
<uni-forms-item name="nickname" label="昵称">
<uni-easyinput
v-model="state.model.nickname"
@ -64,24 +48,23 @@
:placeholderStyle="placeholderStyle"
/>
</uni-forms-item>
<!-- <uni-forms-item name="gender" label="性别">
<uni-forms-item name="sex" label="性别">
<view class="ss-flex ss-col-center ss-h-100">
<radio-group @change="onChangeGender" class="ss-flex ss-col-center">
<label class="radio" v-for="item in genderRadioMap" :key="item.value">
<label class="radio" v-for="item in sexRadioMap" :key="item.value">
<view class="ss-flex ss-col-center ss-m-r-32">
<radio
:value="item.value"
color="var(--ui-BG-Main)"
style="transform: scale(0.8)"
:checked="item.value == state.model.gender"
:checked="parseInt(item.value) === state.model?.sex"
/>
<view class="gender-name">{{ item.name }}</view>
</view>
</label>
</radio-group>
</view>
</uni-forms-item> -->
</uni-forms-item>
<uni-forms-item name="mobile" label="手机号" @tap="onChangeMobile">
<uni-easyinput
@ -107,7 +90,7 @@
<uni-forms-item name="password" label="登录密码" @tap="onSetPassword">
<uni-easyinput
v-model="userInfo.password"
:placeholder="userInfo.verification?.password ? '修改登录密码' : '点击设置登录密码'"
placeholder="点击修改登录密码"
:inputBorder="false"
:styles="{ disableColor: '#fff' }"
disabled
@ -121,9 +104,8 @@
v-if="userInfo.verification?.password"
:modelValue="true"
/>
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx"></text>
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx" />
</button>
</view>
</template>
@ -140,15 +122,7 @@
showArrow
:border="false"
class="list-border"
></uni-list-item>
<uni-list-item
clickable
@tap="sheep.$router.go('/pages/user/invoice/list')"
title="发票管理"
showArrow
:border="false"
class="list-border"
></uni-list-item>
/>
</uni-list>
</view>
</uni-forms>
@ -209,82 +183,74 @@
</template>
<script setup>
import { computed, ref, reactive, onBeforeMount, unref } from 'vue';
import { computed, ref, reactive, onBeforeMount } from 'vue';
import { mobile, password, username } from '@/sheep/validate/form';
import sheep from '@/sheep';
import { clone } from 'lodash';
import { showAuthModal } from '@/sheep/hooks/useModal';
import FileApi from '@/sheep/api/infra/file';
const state = reactive({
model: {},
model: {}, //
rules: {},
thirdOauthInfo: null,
});
const placeholderStyle = 'color:#BBBBBB;font-size:28rpx;line-height:normal';
const genderRadioMap = [
{
const sexRadioMap = [{
name: '男',
value: '1',
},
{
name: '女',
value: '2',
},
{
name: '未知',
value: '0',
},
}
];
const userInfo = computed(() => sheep.$store('user').userInfo);
//
// TODO
function onChangeGender(e) {
state.model.gender = e.detail.value;
state.model.sex = e.detail.value;
}
//
const onChangeUsername = () => {
!state.model.verification?.username && showAuthModal('changeUsername');
};
//
// TODO
const onChangeMobile = () => {
showAuthModal('changeMobile');
};
// TODO
function onChooseAvatar(e) {
const tempUrl = e.detail.avatarUrl || '';
uploadAvatar(tempUrl);
}
//
//
function onChangeAvatar() {
uni.chooseImage({
success: async (chooseImageRes) => {
const tempUrl = chooseImageRes.tempFilePaths[0];
uploadAvatar(tempUrl);
await uploadAvatar(tempUrl);
},
});
}
//
async function uploadAvatar(tempUrl) {
if (!tempUrl) return;
let { path } = await sheep.$api.app.upload(tempUrl, 'ugc');
state.model.avatar = path;
}
// /
function onSetPassword() {
if (state.model.verification.password) {
showAuthModal('changePassword');
} else {
showAuthModal('resetPassword');
if (!tempUrl) {
return;
}
let { data } = await FileApi.uploadFile(tempUrl);
state.model.avatar = data;
}
//
// TODO
function onSetPassword() {
showAuthModal('changePassword');
}
// TODO
async function bindThirdOauth() {
let result = await sheep.$platform.useProvider('wechat').bind();
if (result) {
@ -292,7 +258,7 @@
}
}
//
// TODO
function unBindThirdOauth() {
uni.showModal({
title: '解绑提醒',
@ -312,28 +278,26 @@
//
async function onSubmit() {
// const { error, data } = await sheep.$api.user.update({
// avatar: state.model.avatar,
// nickname: state.model.nickname,
// gender: state.model.gender,
// });
const { code, data } = await sheep.$api.user.update({
const { code } = await sheep.$api.user.update({
avatar: state.model.avatar,
nickname: state.model.nickname,
// gender: state.model.gender,
sex: state.model.sex,
});
if (code === 0) {
getUserInfo();
await getUserInfo();
}
}
//
const getUserInfo = async () => {
//
const userInfo = await sheep.$store('user').getInfo();
state.model = clone(userInfo);
// TODO
if (sheep.$platform.name !== 'H5') {
return;
// ,,
return;
// ,,
let { data, error } = await sheep.$api.user.thirdOauthInfo();
if (error === 0) {
state.thirdOauthInfo = data;
@ -341,7 +305,7 @@
}
};
onBeforeMount(async () => {
onBeforeMount(() => {
getUserInfo();
});
</script>

View File

@ -1,277 +0,0 @@
<template>
<s-layout :title="state.model.id ? '编辑发票' : '添加发票'">
<uni-forms
ref="invoiceFormRef"
v-model="state.model"
:rules="state.rules"
validateTrigger="bind"
labelWidth="160"
labelAlign="left"
border
:labelStyle="{ fontWeight: 'bold' }"
>
<view class="bg-white form-box ss-p-x-30">
<uni-forms-item name="type" label="发票类型">
<view class="ss-flex ss-col-center ss-h-100">
<radio-group @change="onChange" class="ss-flex ss-col-center">
<label class="radio" v-for="item in invoiceTypeList" :key="item.value">
<view class="ss-flex ss-col-center ss-m-r-32">
<radio
:value="item.value"
color="var(--ui-BG-Main)"
style="transform: scale(0.8)"
:checked="item.value === state.model.type"
/>
<view class="radio-name">
{{ item.name }}
</view>
</view>
</label>
</radio-group>
</view>
</uni-forms-item>
<view v-if="state.model.type === 'person'">
<uni-forms-item name="name" label="姓名">
<uni-easyinput
v-model="state.model.name"
type="text"
placeholder="请输入您的姓名(必填)"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="mobile" label="手机号">
<uni-easyinput
v-model="state.model.mobile"
type="number"
placeholder="请输入手机号(必填)"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
</view>
<view v-if="state.model.type === 'company'">
<uni-forms-item name="name" label="单位名称">
<uni-easyinput
v-model="state.model.name"
type="text"
placeholder="请输入单位名称(必填)"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="mobile" label="手机号">
<uni-easyinput
v-model="state.model.mobile"
type="number"
placeholder="请输入手机号(必填)"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="tax_no" label="税号">
<uni-easyinput
v-model="state.model.tax_no"
type="text"
placeholder="请输入单位税号(必填)"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="bank_name" label="开户银行">
<uni-easyinput
v-model="state.model.bank_name"
type="text"
placeholder="请输入对公账户开户银行"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="bank_no" label="银行账号">
<uni-easyinput
v-model="state.model.bank_no"
type="text"
placeholder="请输入对公账户银行账号"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item
name="address"
label="详细地址"
:formItemStyle="{ alignItems: 'flex-start' }"
:labelStyle="{ lineHeight: '5em' }"
class="textarea-item"
>
<uni-easyinput
:inputBorder="false"
type="textarea"
v-model="state.model.address"
placeholderStyle="color:#BBBBBB;font-size:30rpx;font-weight:400;line-height:normal"
placeholder="请输入详细地址"
clearable
></uni-easyinput>
</uni-forms-item>
</view>
</view>
</uni-forms>
<su-fixed bottom :opacity="false" bg="" placeholder :noFixed="false" :index="10">
<view class="footer-box ss-flex-col ss-row-between ss-p-20">
<view class="ss-m-b-20">
<button class="ss-reset-button save-btn ui-Shadow-Main" @tap="onSave"></button>
</view>
<button v-if="state.model.id" class="ss-reset-button cancel-btn" @tap="onDelete">
删除
</button>
</view>
</su-fixed>
</s-layout>
</template>
<script setup>
import { computed, watch, ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import _ from 'lodash';
import { realName, mobile, taxNo, taxName } from '@/sheep/validate/form';
const invoiceFormRef = ref(null);
const invoiceTypeList = [
{
name: '个人',
value: 'person',
},
{
name: '企/事业单位',
value: 'company',
},
];
const state = reactive({
model: {
type: '',
name: '',
mobile: '',
tax_no: '',
bank_name: '',
bank_no: '',
address: '',
},
rules: {
name: taxName,
mobile,
tax_no: taxNo,
},
});
//
function onChange(e) {
state.model.type = e.detail.value;
}
const onSave = async () => {
const validate = await unref(invoiceFormRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
let res = null;
if (state.model.id) {
res = await sheep.$api.user.invoice.update(state.model.id, state.model);
} else {
res = await sheep.$api.user.invoice.create(state.model);
}
if (res.error === 0) {
sheep.$router.back();
}
};
const onDelete = () => {
uni.showModal({
title: '提示',
content: '确认删除此发票信息吗?',
success: async function (res) {
if (res.confirm) {
const { error } = await sheep.$api.user.invoice.delete(state.model.id);
if (res.error === 0) {
sheep.$router.back();
}
}
},
});
};
onLoad(async (options) => {
if (options.id) {
let res = await sheep.$api.user.invoice.detail(options.id);
if (res.error === 0) {
state.model = {
...state.model,
...res.data,
};
}
} else {
state.model.type = 'person';
}
if (options.data) {
let data = JSON.parse(options.data);
state.model = {
...state.model,
...data,
};
}
});
</script>
<style lang="scss" scoped>
:deep() {
.uni-forms-item__label .label-text {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
}
.uni-easyinput__content-input {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
padding-left: 0 !important;
}
.uni-easyinput__content-textarea {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
margin-top: 4rpx;
}
.uni-icons {
font-size: 40rpx !important;
}
.is-textarea-icon {
margin-top: 14rpx;
}
.is-disabled {
color: #333333;
}
}
.footer-box {
.save-btn {
width: 710rpx;
height: 80rpx;
border-radius: 40rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: $white;
}
.cancel-btn {
width: 710rpx;
height: 80rpx;
border-radius: 40rpx;
background: var(--ui-BG);
}
}
</style>

View File

@ -1,82 +0,0 @@
<template>
<s-layout title="发票管理" :bgStyle="{ color: '#FFF' }">
<view v-if="state.list.length">
<s-invoice-item
v-for="item in state.list"
hasBorderBottom
:key="item.id"
:item="item"
:isDefault="item.is_default"
@tap="onSelect(item)"
></s-invoice-item>
</view>
<su-fixed bottom placeholder>
<view class="footer-box ss-flex ss-row-between ss-p-20">
<button
class="add-btn ss-reset-button ui-Shadow-Main"
@tap="sheep.$router.go('/pages/user/invoice/edit')"
>
新增发票抬头
</button>
</view>
</su-fixed>
<s-empty
v-if="state.list.length === 0 && !state.loading"
text="暂无发票"
icon="/static/data-empty.png"
/>
</s-layout>
</template>
<script setup>
import { reactive } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import _ from 'lodash';
const state = reactive({
list: [],
loading: true,
});
const onSelect = (invoiceInfo) => {
uni.$emit('SELECT_INVOICE', {
invoiceInfo,
});
sheep.$router.back();
};
onShow(async () => {
state.list = (await sheep.$api.user.invoice.list()).data;
state.loading = false;
});
</script>
<style lang="scss" scoped>
// page{
// background-color: red;
// }
.footer-box {
.add-btn {
flex: 1;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
border-radius: 80rpx;
font-size: 30rpx;
font-weight: 500;
line-height: 80rpx;
color: $white;
position: relative;
z-index: 1;
}
.sync-wxaddress {
flex: 1;
line-height: 80rpx;
background: $white;
border-radius: 80rpx;
font-size: 30rpx;
font-weight: 500;
color: $dark-6;
margin-right: 16rpx;
}
}
</style>

View File

@ -1,88 +0,0 @@
<template>
<s-layout class="set-wrap" title="编辑资料">
<view class="header-box ss-flex-col ss-row-center ss-col-center">
<image
class="logo-img ss-m-b-40"
src="/static/img/shop/tabbar/find2.png"
mode="aspectFit"
></image>
<view class="name ss-m-b-24">SHEEP商城</view>
<view class="version">V1.3.0</view>
</view>
<uni-list :border="true">
<uni-list-item title="清除缓存" rightText="2M" showArrow></uni-list-item>
<uni-list-item title="当前版本" rightText="V1.3.1" showArrow></uni-list-item>
<uni-list-item title="意见反馈" showArrow></uni-list-item>
<uni-list-item title="关于我们" showArrow></uni-list-item>
</uni-list>
<view class="set-footer ss-flex-col ss-row-center ss-col-center">
<view class="agreement-box ss-flex ss-col-center ss-m-b-30">
<view class="ss-flex ss-col-center ss-m-b-10">
<view class="tcp-text">用户协议</view>
<view class="agreement-text"></view>
<view class="tcp-text">隐私协议</view>
</view>
</view>
<view class="copyright-text ss-m-b-10">******版权所有</view>
<view class="copyright-text">Copyright© 2018-2022</view>
</view>
</s-layout>
</template>
<script setup></script>
<style lang="scss" scoped>
.set-title {
margin: 0 30rpx;
}
.header-box {
padding: 100rpx 0;
.logo-img {
width: 160rpx;
height: 160rpx;
}
.name {
font-size: 42rpx;
line-height: 42rpx;
font-weight: bold;
color: $dark-3;
}
.version {
font-size: 32rpx;
font-weight: 500;
line-height: 32rpx;
color: $gray-b;
}
}
.set-footer {
margin: 200rpx 0;
.copyright-text {
font-size: 22rpx;
font-weight: 500;
color: $gray-c;
line-height: 30rpx;
}
.agreement-box {
margin: 80rpx auto 0;
.tcp-text {
color: var(--ui-BG-Main);
}
.agreement-text {
font-size: 26rpx;
font-weight: 500;
color: $dark-9;
}
}
}
</style>

View File

@ -1,345 +1,370 @@
<!-- 我的钱包 -->
<template>
<s-layout class="wallet-wrap" title="钱包">
<!-- 钱包卡片 -->
<view class="header-box ss-flex ss-row-center ss-col-center">
<view class="card-box ui-BG-Main ui-Shadow-Main">
<view class="card-head ss-flex ss-col-center">
<view class="card-title ss-m-r-10">钱包余额</view>
<view @tap="state.showMoney = !state.showMoney" class="ss-eye-icon"
:class="state.showMoney ? 'cicon-eye' : 'cicon-eye-off'"></view>
</view>
<view class="ss-flex ss-row-between ss-col-center ss-m-t-64">
<view class="money-num">{{ state.showMoney ? userInfo.money : '*****' }}</view>
<button class="ss-reset-button topup-btn" @tap="sheep.$router.go('/pages/pay/recharge')">
充值
</button>
</view>
</view>
</view>
<s-layout class="wallet-wrap" title="钱包">
<!-- 钱包卡片 -->
<view class="header-box ss-flex ss-row-center ss-col-center">
<view class="card-box ui-BG-Main ui-Shadow-Main">
<view class="card-head ss-flex ss-col-center">
<view class="card-title ss-m-r-10">钱包余额</view>
<view
@tap="state.showMoney = !state.showMoney"
class="ss-eye-icon"
:class="state.showMoney ? 'cicon-eye' : 'cicon-eye-off'"
/>
</view>
<view class="ss-flex ss-row-between ss-col-center ss-m-t-64">
<view class="money-num">{{ state.showMoney ? fen2yuan(userInfo.money) : '*****' }}</view>
<button class="ss-reset-button topup-btn" @tap="sheep.$router.go('/pages/pay/recharge')">
充值
</button>
</view>
</view>
</view>
<su-sticky>
<!-- 统计 -->
<view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
<!-- <uni-datetime-picker v-model="state.data" type="daterange" @change="onChangeTime" :end="state.today">
<button class="ss-reset-button date-btn">
<text>{{ dateFilterText }}</text>
<text class="cicon-drop-down ss-seldate-icon"></text>
</button>
</uni-datetime-picker> -->
<su-sticky>
<!-- 统计 -->
<view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
<uni-datetime-picker v-model="state.data" type="daterange" @change="onChangeTime" :end="state.today">
<button class="ss-reset-button date-btn">
<text>{{ dateFilterText }}</text>
<text class="cicon-drop-down ss-seldate-icon"></text>
</button>
</uni-datetime-picker>
<view class="total-box">
<view class="ss-m-b-10">总收入{{ fen2yuan(state.summary.totalIncome) }}</view>
<view>总支出{{ fen2yuan(state.summary.totalExpense) }}</view>
</view>
</view>
<su-tabs
:list="tabMaps"
@change="onChange"
:scrollable="false"
:current="state.currentTab"
></su-tabs>
</su-sticky>
<s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
<view class="total-box">
<!-- state.pagination.income.toFixed(2) -->
<!-- <view class="ss-m-b-10">总收入{{ }}</view>
<view>总支出{{ }}</view> -->
<!-- (-state.pagination.expense).toFixed(2) -->
</view>
</view>
<su-tabs :list="tabMaps" @change="onChange" :scrollable="false" :current="state.currentTab"></su-tabs>
</su-sticky>
<s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
<!-- 钱包记录 -->
<view v-if="state.pagination.total > 0">
<view class="wallet-list ss-flex border-bottom" v-for="item in state.pagination.data" :key="item.id">
<view class="list-content">
<view class="title-box ss-flex ss-row-between ss-m-b-20">
<!-- <text class="title ss-line-1">{{ item.event_text }}{{ item.memo ? '-' + item.memo : '' }}</text> -->
<text class="title ss-line-1">{{ item.title }}</text>
<view class="money">
<text v-if="(item.amount >= 0||item.price>=0)"
class="add">+{{ item.amount||item.price }}</text>
<text v-else class="minus">{{ item.price }}</text>
</view>
</view>
<text class="time">{{ item.createTime }}</text>
</view>
</view>
</view>
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
<!-- 钱包记录 -->
<view v-if="state.pagination.total > 0">
<view
class="wallet-list ss-flex border-bottom"
v-for="item in state.pagination.list"
:key="item.id"
>
<view class="list-content">
<view class="title-box ss-flex ss-row-between ss-m-b-20">
<text class="title ss-line-1">
{{ item.title }}
</text>
<view class="money">
<text v-if="item.price >= 0" class="add">+{{ fen2yuan(item.price) }}</text>
<text v-else class="minus">{{ fen2yuan(item.price) }}</text>
</view>
</view>
<text class="time">
{{ sheep.$helper.timeFormat(state.createTime, 'yyyy-mm-dd hh:MM:ss') }}
</text>
</view>
</view>
</view>
<uni-load-more
v-if="state.pagination.total > 0"
:status="state.loadStatus"
:content-text="{
contentdown: '上拉加载更多',
}" />
</s-layout>
}"
/>
</s-layout>
</template>
<script setup>
import {
computed,
watch,
reactive
} from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import dayjs from 'dayjs';
import _ from 'lodash';
import { computed, reactive } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import dayjs from 'dayjs';
import _ from 'lodash';
import PayWalletApi from '@/sheep/api/pay/wallet';
import { fen2yuan } from '@/sheep/hooks/useGoods';
import { resetPagination } from '@/sheep/util';
const headerBg = sheep.$url.css('/static/img/shop/user/wallet_card_bg.png');
const headerBg = sheep.$url.css('/static/img/shop/user/wallet_card_bg.png');
const pagination = {
data: [],
current_page: 1,
total: 1,
last_page: 1,
expense: 0,
income: 0,
};
//
const state = reactive({
showMoney: false,
date: [],
currentTab: 0,
pagination,
loadStatus: '',
today: '',
});
//
const state = reactive({
showMoney: false,
date: [], //
currentTab: 0,
pagination: {
list: [],
total: 0,
pageNo: 1,
pageSize: 8
},
summary: {
totalIncome: 0,
totalExpense: 0,
},
loadStatus: '',
today: '',
});
const tabMaps = [{
name: '全部',
// value: 'all',
},
{
name: '收入',
value: '1',
},
{
name: '支出',
value: '2',
},
];
const userInfo = computed(() => sheep.$store('user').userInfo);
console.log(userInfo)
const dateFilterText = computed(() => {
if (state.date[0] === state.date[1]) {
return state.date[0];
} else {
return state.date.join('~');
}
});
const tabMaps = [
{
name: '全部',
value: '',
},
{
name: '收入',
value: '1',
},
{
name: '支出',
value: '2',
},
];
const userInfo = computed(() => sheep.$store('user').userInfo);
async function getLogList(page = 1, list_rows = 8) {
// state.loadStatus = 'loading';
let res = await sheep.$api.user.wallet.log({
// type: 'money',
type: tabMaps[state.currentTab].value,
pageSize: list_rows,
pageNo: page,
// date: appendTimeHMS(state.date),
});
if (res.code === 0) {
let list = _.concat(state.pagination.data, res.data.list);
state.pagination = {
...res.data,
data: list,
income: res.data.income,
expense: res.data.expense,
};
console.log('交易数据', state.pagination)
if (state.pagination.current_page < state.pagination.last_page) {
state.loadStatus = 'more';
} else {
state.loadStatus = 'noMore';
}
}
}
onLoad(async (options) => {
state.today = dayjs().format('YYYY-MM-DD');
state.date = [state.today, state.today];
getLogList();
});
//
const dateFilterText = computed(() => {
if (state.date[0] === state.date[1]) {
return state.date[0];
} else {
return state.date.join('~');
}
});
function onChange(e) {
state.pagination = pagination;
state.currentTab = e.index;
getLogList();
}
//
async function getLogList() {
state.loadStatus = 'loading';
const { data, code } = await PayWalletApi.getWalletTransactionPage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
type: tabMaps[state.currentTab].value,
'createTime[0]': state.date[0] + ' 00:00:00',
'createTime[1]': state.date[1] + ' 23:59:59',
});
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
}
function onChangeTime(e) {
state.date[0] = e[0];
state.date[1] = e[e.length - 1];
state.pagination = pagination;
getLogList();
}
//
async function getSummary() {
const { data, code } = await PayWalletApi.getWalletTransactionSummary({
'createTime': [state.date[0] + ' 00:00:00', state.date[1] + ' 23:59:59'],
});
if (code !== 0) {
return;
}
state.summary = data;
}
function appendTimeHMS(arr) {
return [arr[0] + ' 00:00:00', arr[1] + ' 23:59:59'];
}
onLoad(() => {
state.today = dayjs().format('YYYY-MM-DD');
state.date = [state.today, state.today];
getLogList();
getSummary();
});
onReachBottom(() => {
if (state.loadStatus !== 'noMore') {
getLogList(state.pagination.current_page + 1);
}
});
// tab
function onChange(e) {
state.currentTab = e.index;
//
resetPagination(state.pagination);
getLogList();
getSummary();
}
//
function onChangeTime(e) {
state.date[0] = e[0];
state.date[1] = e[e.length - 1];
//
resetPagination(state.pagination);
getLogList();
getSummary();
}
onReachBottom(() => {
if (state.loadStatus === 'noMore') {
return;
}
state.pagination.pageNo++;
getLogList();
});
</script>
<style lang="scss" scoped>
//
.header-box {
background-color: $white;
padding: 30rpx;
//
.header-box {
background-color: $white;
padding: 30rpx;
.card-box {
width: 100%;
min-height: 300rpx;
padding: 40rpx;
background-size: 100% 100%;
border-radius: 30rpx;
overflow: hidden;
position: relative;
z-index: 1;
box-sizing: border-box;
.card-box {
width: 100%;
min-height: 300rpx;
padding: 40rpx;
background-size: 100% 100%;
border-radius: 30rpx;
overflow: hidden;
position: relative;
z-index: 1;
box-sizing: border-box;
&::after {
content: '';
display: block;
width: 100%;
height: 100%;
z-index: 2;
position: absolute;
top: 0;
left: 0;
background: v-bind(headerBg) no-repeat;
pointer-events: none;
}
&::after {
content: '';
display: block;
width: 100%;
height: 100%;
z-index: 2;
position: absolute;
top: 0;
left: 0;
background: v-bind(headerBg)
no-repeat;
pointer-events: none;
}
.card-head {
color: $white;
font-size: 30rpx;
}
.card-head {
color: $white;
font-size: 30rpx;
}
.ss-eye-icon {
font-size: 40rpx;
color: $white;
}
.ss-eye-icon {
font-size: 40rpx;
color: $white;
}
.money-num {
font-size: 70rpx;
line-height: 70rpx;
font-weight: 500;
color: $white;
font-family: OPPOSANS;
}
.money-num {
font-size: 70rpx;
line-height: 70rpx;
font-weight: 500;
color: $white;
font-family: OPPOSANS;
}
.reduce-num {
font-size: 26rpx;
font-weight: 400;
color: $white;
}
.reduce-num {
font-size: 26rpx;
font-weight: 400;
color: $white;
}
.topup-btn {
width: 120rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30px;
font-size: 26rpx;
font-weight: 500;
background-color: $white;
color: var(--ui-BG-Main);
}
}
}
.topup-btn {
width: 120rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30px;
font-size: 26rpx;
font-weight: 500;
background-color: $white;
color: var(--ui-BG-Main);
}
}
}
//
//
.filter-box {
height: 114rpx;
background-color: $bg-page;
.filter-box {
height: 114rpx;
background-color: $bg-page;
.total-box {
font-size: 24rpx;
font-weight: 500;
color: $dark-9;
}
.total-box {
font-size: 24rpx;
font-weight: 500;
color: $dark-9;
}
.date-btn {
background-color: $white;
line-height: 54rpx;
border-radius: 27rpx;
padding: 0 20rpx;
font-size: 24rpx;
font-weight: 500;
color: $dark-6;
.date-btn {
background-color: $white;
line-height: 54rpx;
border-radius: 27rpx;
padding: 0 20rpx;
font-size: 24rpx;
font-weight: 500;
color: $dark-6;
.ss-seldate-icon {
font-size: 50rpx;
color: $dark-9;
}
}
}
.ss-seldate-icon {
font-size: 50rpx;
color: $dark-9;
}
}
}
.tabs-box {
background: $white;
border-bottom: 2rpx solid #eeeeee;
}
.tabs-box {
background: $white;
border-bottom: 2rpx solid #eeeeee;
}
// tab
.wallet-tab-card {
.tab-item {
height: 80rpx;
position: relative;
// tab
.wallet-tab-card {
.tab-item {
height: 80rpx;
position: relative;
.tab-title {
font-size: 30rpx;
}
.tab-title {
font-size: 30rpx;
}
.cur-tab-title {
font-weight: $font-weight-bold;
}
.cur-tab-title {
font-weight: $font-weight-bold;
}
.tab-line {
width: 60rpx;
height: 6rpx;
border-radius: 6rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 2rpx;
background-color: var(--ui-BG-Main);
}
}
}
.tab-line {
width: 60rpx;
height: 6rpx;
border-radius: 6rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 2rpx;
background-color: var(--ui-BG-Main);
}
}
}
//
.wallet-list {
padding: 30rpx;
background-color: #ffff;
//
.wallet-list {
padding: 30rpx;
background-color: #ffff;
.head-img {
width: 70rpx;
height: 70rpx;
border-radius: 50%;
background: $gray-c;
}
.head-img {
width: 70rpx;
height: 70rpx;
border-radius: 50%;
background: $gray-c;
}
.list-content {
justify-content: space-between;
align-items: flex-start;
flex: 1;
.list-content {
justify-content: space-between;
align-items: flex-start;
flex: 1;
.title {
font-size: 28rpx;
color: $dark-3;
width: 400rpx;
}
.title {
font-size: 28rpx;
color: $dark-3;
width: 400rpx;
}
.time {
color: $gray-c;
font-size: 22rpx;
}
}
.time {
color: $gray-c;
font-size: 22rpx;
}
}
.money {
font-size: 28rpx;
font-weight: bold;
font-family: OPPOSANS;
.money {
font-size: 28rpx;
font-weight: bold;
font-family: OPPOSANS;
.add {
color: var(--ui-BG-Main);
}
.add {
color: var(--ui-BG-Main);
}
.minus {
color: $dark-3;
}
}
}
</style>
.minus {
color: $dark-3;
}
}
}
</style>

View File

@ -1,19 +1,6 @@
import request from '@/sheep/request';
import { baseUrl } from '@/sheep/config';
export default {
// TODO 芋艿:测试
test: () =>
request({
url: '/app-api/promotion/decorate/list',
params: {
page: 1
},
custom: {
showError: false,
showLoading: false,
},
}),
// 系统初始化
init: (templateId) =>
request({
@ -39,50 +26,12 @@ export default {
showLoading: false,
},
}),
// 发送短信
sendSms: (data) =>
request({
url: 'sendSms',
method: 'POST',
data,
custom: {
showSuccess: true,
loadingMsg: '发送中',
},
}),
//意见反馈
feedback: (data) =>
request({
url: 'feedback',
method: 'POST',
data,
}),
// 自定义页面
page: (id) =>
request({
url: 'page/' + id,
method: 'GET',
}),
//积分商城
scoreShop: {
list: (params) =>
request({
url: 'app/scoreShop',
method: 'GET',
params,
}),
ids: (params = {}) =>
request({
url: 'app/scoreShop/ids',
method: 'GET',
params,
}),
detail: (id) =>
request({
url: 'app/scoreShop/' + id,
method: 'GET',
}),
},
//小程序直播
mplive: {
getRoomList: (ids) =>
@ -99,48 +48,4 @@ export default {
method: 'GET'
}),
},
//上传
upload: (file, group = 'ugc', callback) => {
const token = uni.getStorageSync('token');
uni.showLoading({
title: '上传中',
});
return new Promise((resolve, reject) => {
// 此处先换成yudao
uni.uploadFile({
url: 'http://api-dashboard.yudao.iocoder.cn' + '/app-api/infra/file/upload',
filePath: file,
name: 'file',
formData: {
group,
},
header: {
// Accept: 'text/json',
// Authorization: token,
Accept : '*/*',
'tenant-id' :'1',
Authorization: 'Bearer test247',
},
success: (uploadFileRes) => {
let result = JSON.parse(uploadFileRes.data);
if (result.error === 1) {
uni.showToast({
icon: 'none',
title: result.msg,
});
} else {
return resolve(result.data);
}
},
fail: (error) => {
console.log('上传失败:', error);
return resolve(false);
},
complete: () => {
uni.hideLoading();
},
});
});
},
};

View File

@ -12,18 +12,7 @@ export default {
showLoading: false,
},
}),
userCoupon: (params) =>
request2({
url: 'promotion/coupon/page',
method: 'GET',
params,
}),
// userCoupon: (params) =>
// request({
// url: 'user/coupon',
// method: 'GET',
// params,
// }),
detail: (id, user_coupon_id) =>
request({
url: 'coupon/' + id,
@ -37,9 +26,4 @@ export default {
url: 'coupon/get/' + id,
method: 'POST',
}),
listByGoods: (id) =>
request({
url: 'coupon/listByGoods/' + id,
method: 'GET',
}),
};

View File

@ -7,4 +7,7 @@ Object.keys(files).forEach((key) => {
};
});
export default api;
// TODO 芋艿:直接在 useModal 引入 AuthUtil 会报错,所以采用这用这方式先
api.AuthUtil = import.meta.globEager('./member/auth.js')['./member/auth.js'].default;
export default api;

49
sheep/api/infra/file.js Normal file
View File

@ -0,0 +1,49 @@
import request2 from '@/sheep/request2';
const FileApi = {
// 上传文件
uploadFile: (file) => {
const token = uni.getStorageSync('token');
uni.showLoading({
title: '上传中',
});
return new Promise((resolve, reject) => {
// 此处先换成yudao
// TODO 芋艿:后续搞下
uni.uploadFile({
// url: 'http://api-dashboard.yudao.iocoder.cn' + '/app-api/infra/file/upload',
url: 'http://127.0.0.1:48080' + '/app-api/infra/file/upload',
filePath: file,
name: 'file',
header: {
// Accept: 'text/json',
// Authorization: token,
Accept : '*/*',
'tenant-id' :'1',
Authorization: 'Bearer test247',
},
success: (uploadFileRes) => {
debugger
let result = JSON.parse(uploadFileRes.data);
if (result.error === 1) {
uni.showToast({
icon: 'none',
title: result.msg,
});
} else {
return resolve(result);
}
},
fail: (error) => {
console.log('上传失败:', error);
return resolve(false);
},
complete: () => {
uni.hideLoading();
},
});
});
},
};
export default FileApi;

View File

@ -0,0 +1,45 @@
import request2 from '@/sheep/request2';
const AddressApi = {
// 获得用户收件地址列表
getAddressList: () => {
return request2({
url: '/app-api/member/address/list',
method: 'GET'
});
},
// 创建用户收件地址
createAddress: (data) => {
return request2({
url: '/app-api/member/address/create',
method: 'POST',
data
});
},
// 更新用户收件地址
updateAddress: (data) => {
return request2({
url: '/app-api/member/address/update',
method: 'PUT',
data
});
},
// 获得用户收件地址
getAddress: (id) => {
return request2({
url: '/app-api/member/address/get',
method: 'GET',
params: { id }
});
},
// 删除用户收件地址
deleteAddress: (id) => {
return request2({
url: '/app-api/member/address/delete',
method: 'DELETE',
params: { id }
});
},
};
export default AddressApi;

42
sheep/api/member/auth.js Normal file
View File

@ -0,0 +1,42 @@
import request from '@/sheep/request';
const AuthUtil = {
// 使用手机 + 验证码登录
smsLogin: (data) => {
return request({
url: '/app-api/member/auth/sms-login',
method: 'POST',
data,
custom: {
showSuccess: true,
loadingMsg: '登录中',
successMsg: '登录成功',
},
});
},
// 发送手机验证码
sendSmsCode: (mobile, scene) => {
return request({
url: '/app-api/member/auth/send-sms-code',
method: 'POST',
data: {
mobile,
scene,
},
custom: {
loadingMsg: '发送中',
showSuccess: true,
successMsg: '发送成功',
},
});
},
// 登出系统
logout: () => {
return request({
url: '/app-api/member/auth/logout',
method: 'POST',
});
},
};
export default AuthUtil;

32
sheep/api/member/user.js Normal file
View File

@ -0,0 +1,32 @@
import request from '@/sheep/request2';
const UserApi = {
// 修改密码
updateUserPassword: (data) => {
return request({
url: '/app-api/member/user/update-password',
method: 'PUT',
data,
custom: {
loadingMsg: '验证中',
showSuccess: true,
successMsg: '修改成功'
},
});
},
// 重置密码
resetUserPassword: (data) => {
return request({
url: '/app-api/member/user/reset-password',
method: 'PUT',
data,
custom: {
loadingMsg: '验证中',
showSuccess: true,
successMsg: '修改成功'
}
});
},
};
export default UserApi;

View File

@ -15,12 +15,6 @@ export default {
// method: 'GET',
// params,
// }),
// 发票详情
invoice: (id) =>
request({
url: 'order/invoice/' + id,
method: 'GET',
}),
// 获取支付结果
payResult: (id) =>
request({

14
sheep/api/pay/channel.js Normal file
View File

@ -0,0 +1,14 @@
import request from '@/sheep/request';
const PayChannelApi = {
// 获得指定应用的开启的支付渠道编码列表
getEnableChannelCodeList: (appId) => {
return request({
url: '/app-api/pay/channel/get-enable-code-list',
method: 'GET',
params: { appId }
});
},
};
export default PayChannelApi;

22
sheep/api/pay/order.js Normal file
View File

@ -0,0 +1,22 @@
import request from '@/sheep/request';
const PayOrderApi = {
// 获得支付订单
getOrder: (id) => {
return request({
url: '/app-api/pay/order/get',
method: 'GET',
params: { id }
});
},
// 提交支付订单
submitOrder: (data) => {
return request({
url: '/app-api/pay/order/submit',
method: 'POST',
data
});
}
};
export default PayOrderApi;

26
sheep/api/pay/wallet.js Normal file
View File

@ -0,0 +1,26 @@
import request from '@/sheep/request';
const PayWalletApi = {
// 获得钱包流水分页
getWalletTransactionPage: (params) => {
const queryString = Object.keys(params)
.map((key) => encodeURIComponent(key) + '=' + params[key])
.join('&');
return request({
url: `/app-api/pay/wallet-transaction/page?${queryString}`,
method: 'GET'
});
},
// 获得钱包流水统计
getWalletTransactionSummary: (params) => {
const queryString = `createTime=${params.createTime[0]}&createTime=${params.createTime[1]}`
return request({
url: `/app-api/pay/wallet-transaction/get-summary?${queryString}`,
// url: `/app-api/pay/wallet-transaction/get-summary`,
method: 'GET',
// params: params
});
},
};
export default PayWalletApi;

View File

@ -1,12 +1,21 @@
import request from '@/sheep/request';
const CategoryApi = {
// 查询分类列表
getCategoryList: () => {
return request({
url: '/app-api/product/category/list',
method: 'GET'
});
}
// 查询分类列表
getCategoryList: () => {
return request({
url: '/app-api/product/category/list',
method: 'GET',
});
},
// 查询分类列表,指定编号
getCategoryListByIds: (ids) => {
return request({
url: '/app-api/product/category/list-by-ids',
method: 'GET',
params: { ids },
});
},
};
export default CategoryApi;

View File

@ -0,0 +1,44 @@
import request from '@/sheep/request';
const FavoriteApi = {
// 获得商品收藏分页
getFavoritePage: (data) => {
return request({
url: '/app-api/product/favorite/page',
method: 'GET',
params: data
});
},
// 检查是否收藏过商品
isFavoriteExists: (spuId) => {
return request({
url: '/app-api/product/favorite/exits',
method: 'GET',
params: {
spuId
}
});
},
// 添加商品收藏
createFavorite: (spuId) => {
return request({
url: '/app-api/product/favorite/create',
method: 'POST',
data: {
spuId
}
});
},
// 取消商品收藏
deleteFavorite: (spuId) => {
return request({
url: '/app-api/product/favorite/delete',
method: 'DELETE',
data: {
spuId
}
});
}
};
export default FavoriteApi;

View File

@ -1,6 +1,6 @@
import request from '@/sheep/request';
export default {
const CouponApi = {
// 获得优惠劵模板列表
getCouponTemplateListByIds: (ids) => {
return request({
@ -17,4 +17,46 @@ export default {
params: { spuId, productScope, count },
});
},
// 获得优惠劵模版分页
getCouponTemplatePage: (params) => {
return request({
url: '/app-api/promotion/coupon-template/page',
method: 'GET',
params,
});
},
// 获得优惠劵模版
getCouponTemplate: (id) => {
return request({
url: '/app-api/promotion/coupon-template/get',
method: 'GET',
params: { id },
});
},
// 我的优惠劵列表
getCouponPage: (params) => {
return request({
url: '/app-api/promotion/coupon/page',
method: 'GET',
params,
});
},
// 领取优惠券
takeCoupon: (templateId) => {
return request({
url: '/app-api/promotion/coupon/take',
method: 'POST',
data: { templateId },
});
},
// 获得优惠劵
getCoupon: (id) => {
return request({
url: '/app-api/promotion/coupon/get',
method: 'GET',
params: { id },
});
},
};
export default CouponApi;

13
sheep/api/system/area.js Normal file
View File

@ -0,0 +1,13 @@
import request2 from '@/sheep/request2';
const AreaApi = {
// 获得地区树
getAreaTree: () => {
return request2({
url: '/app-api/system/area/tree',
method: 'GET'
});
},
};
export default AreaApi;

View File

@ -0,0 +1,45 @@
import request2 from '@/sheep/request2';
import request from '@/sheep/request';
const AfterSaleApi = {
// 创建售后
createAfterSale: (data) => {
return request2({
url: `/app-api/trade/after-sale/create`,
method: 'POST',
data,
});
},
// 获得售后
getAfterSale: (id) => {
return request2({
url: `/app-api/trade/after-sale/get`,
method: 'GET',
params: {
id,
},
});
},
// 取消售后
cancelAfterSale: (id) => {
return request2({
url: `/app-api/trade/after-sale/cancel`,
method: 'DELETE',
params: {
id,
},
});
},
// 获得售后日志列表
getAfterSaleLogList: (afterSaleId) => {
return request2({
url: `/app-api/trade/after-sale-log/list`,
method: 'GET',
params: {
afterSaleId,
},
});
}
};
export default AfterSaleApi;

47
sheep/api/trade/cart.js Normal file
View File

@ -0,0 +1,47 @@
import request2 from '@/sheep/request2';
const CartApi = {
addCart: (data) => {
return request2({
url: '/app-api/trade/cart/add',
method: 'POST',
data: data,
// TODO 芋艿:这里没提示
custom: {
showSuccess: true,
successMsg: '已添加到购物车~',
}
});
},
updateCartCount: (data) => {
return request2({
url: '/app-api/trade/cart/update-count',
method: 'PUT',
data: data
});
},
updateCartSelected: (data) => {
return request2({
url: '/app-api/trade/cart/update-selected',
method: 'PUT',
data: data
});
},
deleteCart: (ids) => {
return request2({
url: '/app-api/trade/cart/delete',
method: 'DELETE',
params: {
ids
}
});
},
getCartList: () => {
return request2({
url: '/app-api/trade/cart/list',
method: 'GET',
});
},
};
export default CartApi;

14
sheep/api/trade/config.js Normal file
View File

@ -0,0 +1,14 @@
import request2 from '@/sheep/request2';
import request from '@/sheep/request';
const TradeConfigApi = {
// 获得交易配置
getTradeConfig: () => {
return request2({
url: `/app-api/trade/config/get`,
method: 'GET',
});
},
};
export default TradeConfigApi;

103
sheep/api/trade/order.js Normal file
View File

@ -0,0 +1,103 @@
import request2 from '@/sheep/request2';
import request from '@/sheep/request';
const OrderApi = {
// 计算订单信息
settlementOrder: (data) => {
const data2 = {
...data,
};
// 移除多余字段
if (!(data.couponId > 0)) {
delete data2.couponId;
}
if (!(data.addressId > 0)) {
delete data2.addressId;
}
// 解决 SpringMVC 接受 List<Item> 参数的问题
delete data2.items;
for (let i = 0; i < data.items.length; i++) {
data2[encodeURIComponent('items[' + i + '' + '].skuId')] = data.items[i].skuId + '';
data2[encodeURIComponent('items[' + i + '' + '].count')] = data.items[i].count + '';
if (data.items[i].cartId) {
data2[encodeURIComponent('items[' + i + '' + '].cartId')] = data.items[i].cartId + '';
}
}
const queryString = Object.keys(data2)
.map((key) => key + '=' + data2[key])
.join('&');
return request2({
url: `trade/order/settlement?${queryString}`,
method: 'GET',
});
},
// 创建订单
createOrder: (data) => {
return request2({
url: `trade/order/create`,
method: 'POST',
data,
});
},
// 获得订单
getOrder: (id) => {
return request2({
url: `trade/order/get-detail`,
method: 'GET',
params: {
id,
},
});
},
// 订单列表
getOrderPage: (params) => {
return request({
url: '/app-api/trade/order/page',
method: 'GET',
params,
custom: {
showLoading: false,
},
});
},
// 确认收货
receiveOrder: (id) => {
return request2({
url: `/app-api/trade/order/receive`,
method: 'PUT',
params: {
id,
},
});
},
// 取消订单
cancelOrder: (id) => {
return request2({
url: `/app-api/trade/order/cancel`,
method: 'DELETE',
params: {
id,
},
});
},
// 删除订单
deleteOrder: (id) => {
return request2({
url: `/app-api/trade/order/delete`,
method: 'DELETE',
params: {
id,
},
});
},
// 创建单个评论
createOrderItemComment: (data) => {
return request2({
url: `/app-api/trade/order/item/create-comment`,
method: 'POST',
data,
});
},
};
export default OrderApi;

View File

@ -92,29 +92,6 @@ export default {
loadingMsg: '正在注册',
},
}),
// 重置密码
resetPassword: (data) =>
request({
url: '/user/api/user/resetPassword',
method: 'POST',
data,
custom: {
showSuccess: true,
loadingMsg: '验证中',
},
}),
// 修改密码
changePassword: (data) =>
request({
url: '/user/api/user/changePassword',
method: 'POST',
data,
custom: {
showSuccess: true,
loadingMsg: '验证中',
},
}),
// 绑定、更换手机号
changeMobile: (data) =>
@ -128,18 +105,6 @@ export default {
},
}),
// 修改用户名
changeUsername: (data) =>
request({
url: '/user/api/user/changeUsername',
method: 'POST',
data,
custom: {
showSuccess: true,
loadingMsg: '验证中',
},
}),
// 更新小程序信息
updateMpUserInfo: (data) =>
request({
@ -218,12 +183,6 @@ export default {
method: 'GET',
custom: {},
}),
// list: () =>
// request({
// url: 'user/address',
// method: 'GET',
// custom: {},
// }),
create: (data) =>
request2({
url: 'member/address/create',
@ -233,15 +192,6 @@ export default {
showSuccess: true,
},
}),
// create: (data) =>
// request({
// url: 'user/address',
// method: 'POST',
// data,
// custom: {
// showSuccess: true,
// },
// }),
update: (data) =>
request2({
url: 'member/address/update',
@ -251,71 +201,16 @@ export default {
showSuccess: true,
},
}),
// update: (id, data) =>
// request({
// url: 'user/address/' + id,
// method: 'PUT',
// data,
// custom: {
// showSuccess: true,
// },
// }),
detail: (id) =>
request2({
url: 'member/address/get?id=' + id,
method: 'GET',
}),
// detail: (id) =>
// request({
// url: 'user/address/' + id,
// method: 'GET',
// }),
delete: (id) =>
request2({
url: 'member/address/delete?id=' + id,
method: 'DELETE',
}),
// delete: (id) =>
// request({
// url: 'user/address/' + id,
// method: 'DELETE',
// }),
},
invoice: {
list: () =>
request({
url: 'user/invoice',
method: 'GET',
custom: {},
}),
create: (data) =>
request({
url: 'user/invoice',
method: 'POST',
data,
custom: {
showSuccess: true,
},
}),
update: (id, data) =>
request({
url: 'user/invoice/' + id,
method: 'PUT',
data,
custom: {
showSuccess: true,
},
}),
detail: (id) =>
request({
url: 'user/invoice/' + id,
method: 'GET',
}),
delete: (id) =>
request({
url: 'user/invoice/' + id,
method: 'DELETE',
}),
},
favorite: {
list: (params) =>
@ -398,13 +293,6 @@ export default {
params,
custom: {},
}),
// log: (params) =>
// request({
// url: '/user/api/walletLog',
// method: 'GET',
// params,
// custom: {},
// }),
},
account: {
info: (params) =>

View File

@ -1,3 +1,4 @@
<!-- 地址卡片 -->
<template>
<view
class="address-item ss-flex ss-row-between ss-col-center"
@ -11,18 +12,23 @@
custom-style="background-color: var(--ui-BG-Main); border-color: var(--ui-BG-Main); color: #fff;"
v-if="props.item.defaultStatus"
text="默认"
></uni-tag>
/>
{{ props.item.areaName }}
<!-- {{ props.item.city_name }} {{ props.item.district_name }} -->
</view>
<view class="address-text">{{ props.item.detailAddress }}</view>
<view class="person-text">{{ props.item.name }} {{ props.item.mobile }}</view>
<view class="address-text">
{{ props.item.detailAddress }}
</view>
<view class="person-text">
{{ props.item.name }} {{ props.item.mobile }}
</view>
</view>
<view v-else>
<view class="address-text ss-m-b-10">请选择收货地址</view>
</view>
<view v-else><view class="address-text ss-m-b-10">请选择收货地址</view></view>
<slot>
<button class="ss-reset-button edit-btn" @tap.stop="onEdit">
<view class="edit-icon ss-flex ss-row-center ss-col-center">
<image :src="sheep.$url.static('/static/img/shop/user/address/edit.png')"></image>
<image :src="sheep.$url.static('/static/img/shop/user/address/edit.png')" />
</view>
</button>
</slot>

View File

@ -4,10 +4,10 @@
<!-- 标题栏 -->
<view class="head-box ss-m-b-60 ss-flex-col">
<view class="ss-flex ss-m-b-20">
<view class="head-title ss-m-r-40 head-title-animation">账号登录</view>
<view class="head-title-active head-title-line" @tap="showAuthModal('smsLogin')">
短信登录
</view>
<view class="head-title ss-m-r-40 head-title-animation">账号登录</view>
</view>
<view class="head-subtitle">如果未设置过密码请点击忘记密码</view>
</view>

View File

@ -1,4 +1,4 @@
<!-- 修改密码 - changePassword -->
<!-- 修改密码登录时 -->
<template>
<view>
<!-- 标题栏 -->
@ -16,29 +16,32 @@
labelWidth="140"
labelAlign="center"
>
<uni-forms-item name="oldPassword" label="旧密码">
<uni-forms-item name="code" label="验证码">
<uni-easyinput
placeholder="请输入旧密码"
v-model="state.model.oldPassword"
type="text"
placeholder="请输入验证码"
v-model="state.model.code"
type="number"
maxlength="4"
:inputBorder="false"
/>
>
<template v-slot:right>
<button
class="ss-reset-button code-btn code-btn-start"
:disabled="state.isMobileEnd"
:class="{ 'code-btn-end': state.isMobileEnd }"
@tap="getSmsCode('changePassword')"
>
{{ getSmsTimer('resetPassword') }}
</button>
</template>
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="newPassword" label="新密码">
<uni-forms-item name="reNewPassword" label="密码">
<uni-easyinput
type="password"
placeholder="请输入新密码"
v-model="state.model.newPassword"
:inputBorder="false"
/>
</uni-forms-item>
<uni-forms-item name="reNewPassword" label="确认密码">
<uni-easyinput
type="password"
placeholder="请重新输入您的新密码"
v-model="state.model.reNewPassword"
placeholder="请输入密码"
v-model="state.model.password"
:inputBorder="false"
>
<template v-slot:right>
@ -50,69 +53,51 @@
</uni-forms-item>
</uni-forms>
<view class="editPwd-btn-box ss-m-t-80">
<button class="ss-reset-button forgot-btn" @tap="showAuthModal('resetPassword')">
忘记密码
</button>
</view>
<button class="ss-reset-button type-btn" @tap="closeAuthModal">
取消修改
</button>
</view>
</template>
<script setup>
import { computed, watch, ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import { password } from '@/sheep/validate/form';
import { showAuthModal, closeAuthModal } from '@/sheep/hooks/useModal';
import { ref, reactive, unref } from 'vue';
import { code, password } from '@/sheep/validate/form';
import { closeAuthModal, getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
import UserApi from '@/sheep/api/member/user';
const changePasswordRef = ref(null);
//
const state = reactive({
isMobileEnd: false, //
model: {
oldPassword: '', //
newPassword: '', //
reNewPassword: '', //
mobile: '', //
code: '', //
password: '', //
},
rules: {
oldPassword: password,
newPassword: password,
reNewPassword: {
rules: [
{
required: true,
errorMessage: '请确认密码',
},
{
validateFunction: function (rule, value, data, callback) {
if (value !== state.model.newPassword) {
callback('两次输入的密码不一致');
}
if (value === state.model.oldPassword) {
callback('新密码不能与旧密码相同');
}
return true;
},
},
],
},
code,
password,
},
});
// 6.
//
async function changePasswordSubmit() {
//
const validate = await unref(changePasswordRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
sheep.$api.user.changePassword(state.model).then((res) => {
if (res.error === 0) {
sheep.$store('user').getInfo();
closeAuthModal();
}
});
if (!validate) {
return;
}
//
const { code } = await UserApi.updateUserPassword(state.model);
if (code !== 0) {
return;
}
//
closeAuthModal();
}
</script>

View File

@ -1,72 +0,0 @@
<!-- 修改用户名 changeUsername -->
<template>
<view>
<!-- 标题栏 -->
<view class="head-box ss-m-b-60">
<view class="head-title ss-m-b-20">修改用户名</view>
<view class="head-subtitle">用户名仅限修改一次</view>
</view>
<!-- 表单项 -->
<uni-forms
ref="formRef"
v-model="state.model"
:rules="state.rules"
validateTrigger="bind"
labelWidth="140"
labelAlign="center"
>
<uni-forms-item name="username" label="用户名">
<uni-easyinput
placeholder="请输入用户名"
v-model="state.model.username"
:inputBorder="false"
></uni-easyinput>
</uni-forms-item>
<view class="editPwd-btn-box ss-m-t-80">
<button class="ss-reset-button save-btn ui-Shadow-Main" @tap="changeUsernameSubmit">
保存
</button>
</view>
</uni-forms>
</view>
</template>
<script setup>
import { computed, watch, ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import { username } from '@/sheep/validate/form';
import { showAuthModal, closeAuthModal } from '@/sheep/hooks/useModal';
const formRef = ref(null);
//
const state = reactive({
model: {
username: '',
},
rules: {
username,
},
});
// 7.
async function changeUsernameSubmit() {
const validate = await unref(formRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
sheep.$api.user.changeUsername(state.model).then((res) => {
if (res.error === 0) {
sheep.$store('user').getInfo();
closeAuthModal();
}
});
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

View File

@ -1,4 +1,4 @@
<!-- 重置密码 - resetPassword-- -->
<!-- 重置密码未登录时 -->
<template>
<view>
<!-- 标题栏 -->
@ -43,7 +43,7 @@
type="number"
maxlength="4"
:inputBorder="false"
></uni-easyinput>
/>
</uni-forms-item>
<uni-forms-item name="password" label="密码">
@ -69,10 +69,11 @@
</template>
<script setup>
import { computed, watch, ref, reactive, unref } from 'vue';
import { computed, ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import { code, mobile, password } from '@/sheep/validate/form';
import { showAuthModal, closeAuthModal, getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
import UserApi from '@/sheep/api/member/user';
const resetPasswordRef = ref(null);
const isLogin = computed(() => sheep.$store('user').isLogin);
@ -81,9 +82,9 @@
const state = reactive({
isMobileEnd: false, //
model: {
mobile: '', //
code: '', //
password: '', //
mobile: '', //
code: '', //
password: '', //
},
rules: {
code,
@ -92,20 +93,24 @@
},
});
// 4.
//
const resetPasswordSubmit = async () => {
//
const validate = await unref(resetPasswordRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
sheep.$api.user.resetPassword(state.model).then((res) => {
if (res.error === 0) {
sheep.$store('user').getInfo();
closeAuthModal();
}
});
if (!validate) {
return;
}
//
const { code } = await UserApi.resetUserPassword(state.model);
if (code !== 0) {
return;
}
//
showAuthModal('accountLogin')
};
</script>

View File

@ -4,12 +4,12 @@
<!-- 标题栏 -->
<view class="head-box ss-m-b-60">
<view class="ss-flex ss-m-b-20">
<view class="head-title-active ss-m-r-40" @tap="showAuthModal('accountLogin')"
>账号登录</view
>
<view class="head-title head-title-line head-title-animation">短信登录</view>
<view class="head-title-active ss-m-r-40" @tap="showAuthModal('accountLogin')">
账号登录
</view>
</view>
<view class="head-subtitle">未注册手机号请先点击下方立即注册</view>
<view class="head-subtitle">未注册的手机号验证后自动注册账号</view>
</view>
<!-- 表单项 -->
@ -59,10 +59,11 @@
</template>
<script setup>
import { computed, watch, ref, reactive, unref } from 'vue';
import { ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import { code, mobile } from '@/sheep/validate/form';
import { showAuthModal, closeAuthModal, getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
import AuthUtil from '@/sheep/api/member/auth';
const smsLoginRef = ref(null);
@ -89,22 +90,25 @@
},
});
// 2.
//
async function smsLoginSubmit() {
//
const validate = await unref(smsLoginRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
if (!validate) {
return;
}
if (!props.agreeStatus) {
emits('onConfirm', true)
sheep.$helper.toast('请勾选同意');
return;
}
const { error } = await sheep.$api.user.smsLogin(state.model);
if (error === 0) {
//
const { code } = await AuthUtil.smsLogin(state.model);
if (code === 0) {
closeAuthModal();
}
}

View File

@ -1,130 +0,0 @@
<!-- 短信注册 - smsRegister -->
<template>
<view>
<!-- 标题栏 -->
<view class="head-box ss-m-b-60">
<view class="head-title ss-m-b-20">注册</view>
<view class="head-subtitle">请使用本人手机号完成注册</view>
</view>
<!-- 表单项 -->
<uni-forms
ref="smsRegisterRef"
v-model="state.model"
:rules="state.rules"
validateTrigger="bind"
labelWidth="140"
labelAlign="center"
>
<uni-forms-item name="mobile" label="手机号">
<uni-easyinput
placeholder="请输入手机号"
v-model="state.model.mobile"
type="number"
:inputBorder="false"
>
<template v-slot:right>
<button
class="ss-reset-button code-btn code-btn-start"
:disabled="state.isMobileEnd"
:class="{ 'code-btn-end': state.isMobileEnd }"
@tap="getSmsCode('smsRegister', state.model.mobile)"
>
{{ getSmsTimer('smsRegister') }}
</button>
</template>
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="code" label="验证码">
<uni-easyinput
placeholder="请输入验证码"
v-model="state.model.code"
:inputBorder="false"
type="number"
maxlength="4"
></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="password" label="密码">
<uni-easyinput
type="password"
placeholder="请输入密码"
v-model="state.model.password"
:inputBorder="false"
>
<template v-slot:right>
<button class="ss-reset-button login-btn-start" @tap="smsRegisterSubmit"> </button>
</template>
</uni-easyinput>
</uni-forms-item>
</uni-forms>
<button class="ss-reset-button type-btn" @tap="showAuthModal('accountLogin')">
返回登录
</button>
</view>
</template>
<script setup>
import { computed, ref, reactive, unref } from 'vue';
import sheep from '@/sheep';
import { code, mobile, password } from '@/sheep/validate/form';
import { showAuthModal, closeAuthModal, getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
const props = defineProps({
agreeStatus: {
type: Boolean,
default: false,
},
});
const smsRegisterRef = ref(null);
const isLogin = computed(() => sheep.$store('user').isLogin);
const emits = defineEmits(['onConfirm']);
//
const state = reactive({
isMobileEnd: false, //
model: {
mobile: '', //
code: '', //
password: '', //
},
rules: {
code,
mobile,
password,
},
});
// 3.
async function smsRegisterSubmit() {
const validate = await unref(smsRegisterRef)
.validate()
.catch((error) => {
console.log('error: ', error);
});
if (!validate) return;
if (!props.agreeStatus) {
emits('onConfirm',true);
sheep.$helper.toast('请勾选同意');
return;
}
const { error } = await sheep.$api.user.smsRegister({
...state.model,
shareInfo: uni.getStorageSync('shareLog') || {},
});
if (error === 0) {
closeAuthModal();
}
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

View File

@ -12,13 +12,6 @@
<!-- 2.短信登录 smsLogin -->
<sms-login v-if="authType === 'smsLogin'" :agreeStatus="state.protocol" @onConfirm="onConfirm" />
<!-- 3.短信注册 smsRegister-->
<sms-register
v-if="authType === 'smsRegister'"
:agreeStatus="state.protocol"
@onConfirm="onConfirm"
/>
<!-- 4.忘记密码 resetPassword-->
<reset-password v-if="authType === 'resetPassword'" />
@ -26,10 +19,7 @@
<change-mobile v-if="authType === 'changeMobile'" />
<!-- 6.修改密码 changePassword-->
<change-passwrod v-if="authType === 'changePassword'" />
<!-- 7.修改用户名 changeUsername-->
<change-username v-if="authType === 'changeUsername'" />
<changePassword v-if="authType === 'changePassword'" />
<!-- 8.微信小程序授权 changeUsername-->
<mp-authorization v-if="authType === 'mpAuthorization'" />
@ -42,22 +32,13 @@
<!-- 立即注册&快捷登录 TextButton -->
<view v-if="sheep.$platform.name === 'WechatMiniProgram'" class="ss-flex register-box">
<view class="register-title">还没有账号?</view>
<button class="ss-reset-button register-btn" @tap="showAuthModal('smsRegister')"
>立即注册</button
<button class="ss-reset-button register-btn" @tap="showAuthModal('smsRegister')"></button
>
<view class="or-title"></view>
<button class="ss-reset-button login-btn" @tap="thirdLogin('wechat')"></button>
<view class="circle"></view>
</view>
<button
v-if="sheep.$platform.name !== 'WechatMiniProgram'"
class="ss-reset-button type-btn"
@tap="showAuthModal('smsRegister')"
>
立即注册
</button>
<!-- 公众号|App微信登录 -->
<button
v-if="
@ -126,11 +107,9 @@
import sheep from '@/sheep';
import accountLogin from './components/account-login.vue';
import smsLogin from './components/sms-login.vue';
import smsRegister from './components/sms-register.vue';
import resetPassword from './components/reset-password.vue';
import changeMobile from './components/change-mobile.vue';
import changePasswrod from './components/change-password.vue';
import changeUsername from './components/change-username.vue';
import changePassword from './components/change-password.vue';
import mpAuthorization from './components/mp-authorization.vue';
import { closeAuthModal, showAuthModal } from '@/sheep/hooks/useModal';

View File

@ -20,7 +20,7 @@
<!-- 图文组件图片轮播 -->
<s-image-banner v-if="type === 'Carousel'" :data="data" :styles="styles" />
<!-- 基础组件标题栏 -->
<s-title-block v-if="type === 'titleBlock'" :data="data" :styles="styles" />
<s-title-block v-if="type === 'TitleBar'" :data="data" :styles="styles" />
<!-- 图文组件广告魔方 -->
<s-image-cube v-if="type === 'MagicCube'" :data="data" :styles="styles" />
<!-- 图文组件视频播放 -->
@ -28,7 +28,7 @@
<!-- 基础组件分割线 -->
<s-line-block v-if="type === 'Divider'" :data="data" />
<!-- 图文组件热区 -->
<s-hotzone-block v-if="type === 'hotzone'" :data="data" :styles="styles" />
<s-hotzone-block v-if="type === 'HotZone'" :data="data" :styles="styles" />
<!-- 商品组件商品卡片 -->
<s-goods-card v-if="type === 'ProductCard'" :data="data" :styles="styles" />
@ -39,8 +39,6 @@
<s-groupon-block v-if="type === 'PromotionCombination'" :data="data" :styles="styles" />
<!-- 营销组件秒杀 -->
<s-seckill-block v-if="type === 'PromotionSeckill'" :data="data" :styles="styles" />
<!-- 营销组件积分商城模式不一样无法适配 -->
<s-score-block v-if="type === 'PromotionPoint'" :data="data" :styles="styles" />
<!-- 营销组件小程序直播暂时没有这个功能 -->
<s-live-block v-if="type === 'MpLive'" :data="data" :styles="styles" />
<!-- 营销组件优惠券 -->

View File

@ -1,3 +1,4 @@
<!-- 商品详情 - 优惠劵领取 -->
<template>
<su-popup
:show="show"
@ -21,13 +22,11 @@
<template #default>
<button
class="ss-reset-button card-btn ss-flex ss-row-center ss-col-center"
:class="
item.get_status != 'can_get' && item.get_status != 'can_use' ? 'boder-btn' : ''
"
:class="!item.canTake ? 'boder-btn' : ''"
@click.stop="getBuy(item.id)"
:disabled="item.get_status != 'can_get' && item.get_status != 'can_use'"
:disabled="!item.canTake"
>
{{ item.get_status_text }}
{{ item.canTake ? '立即领取' : '已领取' }}
</button>
</template>
</s-coupon-list>
@ -38,6 +37,7 @@
</template>
<script setup>
import { computed, reactive } from 'vue';
const props = defineProps({
modelValue: {
type: Object,
@ -48,16 +48,17 @@
default: false,
},
});
const emits = defineEmits(['get', 'close']);
const state = reactive({
couponInfo: computed(() => props.modelValue),
currentValue: -1,
couponId: '',
couponInfo: computed(() => props.modelValue)
});
//
const getBuy = (id) => {
emits('get', id);
};
//
</script>
<style lang="scss" scoped>
.model-box {

View File

@ -1,195 +1,205 @@
<template>
<view class="ss-m-20" :style="{ opacity: disabled ? '0.5' : '1' }">
<view class="content">
<!-- <view
<view class="ss-m-20" :style="{ opacity: disabled ? '0.5' : '1' }">
<view class="content">
<view
class="tag ss-flex ss-row-center"
:class="
data.status == 'expired' || data.status == 'used' ? 'disabled-bg-color' : 'info-bg-color'
"
>{{ data.type_text }}</view
> -->
<view class="title ss-m-x-30 ss-p-t-18">
<view class="ss-flex ss-row-between">
<view class="value-text ss-flex-1 ss-m-r-10" :class="
data.status == 'expired' || data.status == 'used' ? 'disabled-color' : 'info-color'
">{{ data.name }}</view>
<view>
<view class="ss-flex ss-col-bottom" :class="
data.status != 'expired' && data.status != 'used' ? 'price-text' : 'disabled-color'
">
<view class="value-reduce ss-m-b-10" v-if="data.type === 'reduce'"></view>
<view class="value-price">{{ data.amount }}</view>
<view class="value-discount ss-m-b-10 ss-m-l-4" v-if="data.type === 'discount'"></view>
</view>
</view>
</view>
<view class="ss-flex ss-row-between ss-m-t-16">
<view class="sellby-text" :class="
data.status == 'expired' || data.status == 'used'
? 'disabled-color'
: 'subtitle-color'
">
{{'有效期:' + data.use_start_time.substring(0, 11) }}
{{ data.use_end_time.substring(0, 11) }}
<!-- {{
type === 'user'
? '有效期:' + data.use_start_time.substring(0, 11)
: '领取时间:' + data.get_start_time.substring(0, 11)
}}
{{
type === 'user'
? data.use_end_time.substring(0, 11)
: data.get_end_time.substring(0, 11)
}} -->
</view>
<view class="value-enough" :class="
data.status == 'expired' || data.status == 'used'
? 'disabled-color'
: 'subtitle-color'
">{{ data.enough }}可用</view>
</view>
</view>
</view>
:class="isDisable ? 'disabled-bg-color' : 'info-bg-color'"
>
{{ data.discountType === 1 ? '满减券' : '折扣券' }}
</view>
<view class="title ss-m-x-30 ss-p-t-18">
<view class="ss-flex ss-row-between">
<view
class="value-text ss-flex-1 ss-m-r-10"
:class="isDisable ? 'disabled-color' : 'info-color'"
>
{{ data.name }}
</view>
<view>
<view
class="ss-flex ss-col-bottom"
:class="isDisable ? 'disabled-color' : 'price-text'"
>
<view class="value-reduce ss-m-b-10" v-if="data.discountType === 1"></view>
<view class="value-price">
{{
data.discountType === 1
? fen2yuan(data.discountPrice)
: data.discountPercent / 10.0
}}
</view>
<view class="value-discount ss-m-b-10 ss-m-l-4" v-if="data.discountType === 2"
></view
>
</view>
</view>
</view>
<view class="ss-flex ss-row-between ss-m-t-16">
<view
class="sellby-text"
:class=" isDisable ? 'disabled-color' : 'subtitle-color'"
v-if="data.validityType === 2"
>
有效期领取后 {{ data.fixedEndTerm }} 天内可用
</view>
<view
class="sellby-text"
:class=" isDisable ? 'disabled-color' : 'subtitle-color'"
v-else
>
有效期: {{ sheep.$helper.timeFormat(data.validStartTime, 'yyyy-mm-dd') }}
{{ sheep.$helper.timeFormat(data.validEndTime, 'yyyy-mm-dd') }}
</view>
<view
class="value-enough"
:class="isDisable ? 'disabled-color' : 'subtitle-color'"
>
{{ fen2yuan(data.usePrice) }} 可用
</view>
</view>
</view>
</view>
<view class="desc ss-flex ss-row-between">
<view>
<view class="desc-title">
{{ data.description }}
</view>
<view>
<slot name="reason">
</slot>
</view>
</view>
<view>
<slot></slot>
</view>
</view>
</view>
<!-- TODO 芋艿可优化增加优惠劵的描述 -->
<view class="desc ss-flex ss-row-between">
<view>
<view class="desc-title">{{ data.description }}</view>
<view>
<slot name="reason" />
</view>
</view>
<view>
<slot />
</view>
</view>
</view>
</template>
<script setup>
import {
reactive
} from 'vue';
import sheep from '@/sheep';
const state = reactive({
stateMap: {
0: '立即领取',
1: '去使用',
},
});
//
const props = defineProps({
data: {
type: Object,
default: {},
},
disabled: {
type: Boolean,
default: false,
},
type: {
type: String,
default: 'coupon',
},
});
import { computed, reactive } from 'vue';
import { fen2yuan } from '../../hooks/useGoods';
import sheep from '../../index';
const state = reactive({});
const isDisable = computed(() => {
if (props.type === 'coupon') {
return false;
}
return props.data.status !== 1;
});
//
const props = defineProps({
data: {
type: Object,
default: {},
},
disabled: {
type: Boolean,
default: false,
},
type: {
type: String,
default: 'coupon', // coupon user
},
});
</script>
<style lang="scss" scoped>
.info-bg-color {
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
}
.info-bg-color {
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
}
.disabled-bg-color {
background: #999;
}
.disabled-bg-color {
background: #999;
}
.info-color {
color: #333;
}
.info-color {
color: #333;
}
.subtitle-color {
color: #666;
}
.subtitle-color {
color: #666;
}
.disabled-color {
color: #999;
}
.disabled-color {
color: #999;
}
.content {
width: 100%;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
-webkit-mask: radial-gradient(circle at 12rpx 100%, #0000 12rpx, red 0) -12rpx;
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.04);
.content {
width: 100%;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
-webkit-mask: radial-gradient(circle at 12rpx 100%, #0000 12rpx, red 0) -12rpx;
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.04);
.tag {
width: 100rpx;
.tag {
width: 100rpx;
color: #fff;
height: 40rpx;
font-size: 24rpx;
border-radius: 20rpx 0 20rpx 0;
}
color: #fff;
height: 40rpx;
font-size: 24rpx;
border-radius: 20rpx 0 20rpx 0;
}
.title {
padding-bottom: 22rpx;
border-bottom: 2rpx dashed #d3d3d3;
.title {
padding-bottom: 22rpx;
border-bottom: 2rpx dashed #d3d3d3;
.value-text {
font-size: 32rpx;
font-weight: 600;
}
.value-text {
font-size: 32rpx;
font-weight: 600;
}
.sellby-text {
font-size: 24rpx;
font-weight: 400;
}
.sellby-text {
font-size: 24rpx;
font-weight: 400;
}
.value-price {
font-size: 64rpx;
font-weight: 500;
line-height: normal;
font-family: OPPOSANS;
}
.value-price {
font-size: 64rpx;
font-weight: 500;
line-height: normal;
font-family: OPPOSANS;
}
.value-reduce {
line-height: normal;
font-size: 32rpx;
}
.value-reduce {
line-height: normal;
font-size: 32rpx;
}
.value-discount {
line-height: normal;
font-size: 28rpx;
}
.value-discount {
line-height: normal;
font-size: 28rpx;
}
.value-enough {
font-size: 24rpx;
font-weight: 400;
font-family: OPPOSANS;
}
}
}
.value-enough {
font-size: 24rpx;
font-weight: 400;
font-family: OPPOSANS;
}
}
}
.desc {
width: 100%;
background: #fff;
-webkit-mask: radial-gradient(circle at 12rpx 0%, #0000 12rpx, red 0) -12rpx;
box-shadow: rgba(#000, 0.1);
box-sizing: border-box;
padding: 24rpx 30rpx;
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.04);
border-radius: 0 0 20rpx 20rpx;
.desc {
width: 100%;
background: #fff;
-webkit-mask: radial-gradient(circle at 12rpx 0%, #0000 12rpx, red 0) -12rpx;
box-shadow: rgba(#000, 0.1);
box-sizing: border-box;
padding: 24rpx 30rpx;
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.04);
border-radius: 0 0 20rpx 20rpx;
.desc-title {
font-size: 24rpx;
color: #999;
font-weight: 400;
}
}
.desc-title {
font-size: 24rpx;
color: #999;
font-weight: 400;
}
}
.price-text {
color: #ff0000;
}
.price-text {
color: #ff0000;
}
</style>

View File

@ -25,19 +25,7 @@
const props = defineProps({
data: {
type: Object,
default() {
return {
// horizontal vertical
direction: 'vertical',
showText: true,
list: [{
imgUrl: 'http://localhost/logo.gif',
url: '',
text: '客服',
textColor: '',
}],
}
},
default() {},
}
})

View File

@ -29,7 +29,7 @@
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? data.price[0] : data.price }}
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
</view>
</view>
@ -55,7 +55,7 @@
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? data.price[0] : data.price }}
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
</view>
</view>
@ -102,7 +102,7 @@
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? data.price[0] : data.price }}
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
@ -111,7 +111,7 @@
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ data.original_price||data.marketPrice }}</view>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
@ -122,7 +122,7 @@
<slot name="cart">
<view class="cart-box ss-flex ss-col-center ss-row-center">
<image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode=""></image>
<image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode="" />
</view>
</slot>
</view>
@ -174,7 +174,7 @@
:style="[{ color: goodsFields.price.color }]"
>
<text class="ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? data.price[0] : data.price }}
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="(goodsFields.original_price?.show||goodsFields.marketPrice?.show) &&( data.original_price > 0|| data.marketPrice > 0)"
@ -182,7 +182,7 @@
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ data.original_price||data.marketPrice }}</view>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
@ -191,11 +191,11 @@
</view>
</view>
<slot name="cart"
><view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"
>去购买</view
></slot
>
<slot name="cart">
<view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow">
去购买
</view>
</slot>
</view>
<!-- sl卡片竖向型一行放一个图片上内容下边 -->
@ -238,7 +238,7 @@
<view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
<view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? data.price[0] : data.price }}
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="(goodsFields.original_price?.show||goodsFields.marketPrice?.show) &&( data.original_price > 0|| data.marketPrice > 0)"
@ -246,7 +246,7 @@
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ data.original_price||data.marketPrice }}</view>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
<view class="ss-m-t-16 ss-flex ss-flex-wrap">
@ -293,7 +293,7 @@
*/
import { computed, reactive, getCurrentInstance, onMounted, nextTick } from 'vue';
import sheep from '@/sheep';
import { formatSales } from '@/sheep/hooks/useGoods';
import { fen2yuan, formatSales } from '@/sheep/hooks/useGoods';
import { formatStock } from '@/sheep/hooks/useGoods';
import goodsCollectVue from '@/pages/user/goods-collect.vue';
import { isArray } from 'lodash';
@ -307,6 +307,7 @@
type: [Array, Object],
default() {
return {
// TODO @
//
title: { show: true },
//

View File

@ -26,15 +26,7 @@
:style="[{ color: priceColor }]"
v-if="price && Number(price) > 0"
>
{{ price }}
</view>
<view v-if="score && Number(price) > 0">+</view>
<view class="price-text ss-flex ss-col-center" v-if="score">
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
></image>
<view>{{ score }}</view>
{{ fen2yuan(price) }}
</view>
<view v-if="num" class="total-text ss-flex ss-col-center">x {{ num }}</view>
<slot name="priceSuffix"></slot>
@ -54,6 +46,7 @@
<script setup>
import sheep from '@/sheep';
import { computed } from 'vue';
import { fen2yuan } from '@/sheep/hooks/useGoods';
/**
* 订单卡片
*

View File

@ -1,3 +1,4 @@
<!-- 商品组 - 横向滚动商品目前暂时没用到 -->
<template>
<view class="goods-scroll-box">
<scroll-view class="scroll-box" scroll-x scroll-anchoring>
@ -8,7 +9,7 @@
size="sm"
:data="item"
:titleWidth="200 - marginLeft - marginRight"
></s-goods-column>
/>
</view>
</view>
</scroll-view>

View File

@ -1,16 +1,16 @@
<template>
<view class="hotzone-wrap">
<image :src="sheep.$url.cdn(data.src)" style="width: 100%" mode="widthFix"></image>
<image :src="sheep.$url.cdn(data.imgUrl)" style="width: 100%" mode="widthFix"></image>
<view
class="hotzone-box"
v-for="item in data.list"
:key="item.width"
v-for="(item, index) in data.list"
:key="index"
:style="[
{
top: item.top + 'rpx',
left: item.left + 'rpx',
width: item.width + 'rpx',
height: item.height + 'rpx',
top: `${item.top}px`,
left: `${item.left}px`,
width: `${item.width}px`,
height: `${item.height}px`,
},
]"
@tap.stop="sheep.$router.go(item.url)"

View File

@ -1,96 +0,0 @@
<template>
<view
class="address-item ss-flex ss-row-between ss-col-center"
:class="[{ 'border-bottom': props.hasBorderBottom }]"
>
<view class="item-left" v-if="!_.isEmpty(props.item)">
<view class="address-text">{{ props.item.name }}</view>
<view class="person-text">{{ props.item.mobile }}</view>
</view>
<view v-else>
<view class="address-text">请选择收货地址</view>
</view>
<slot>
<button class="ss-reset-button edit-btn" @tap.stop="onEdit">
<view class="edit-icon ss-flex ss-row-center ss-col-center">
<image :src="sheep.$url.static('/static/img/shop/user/address/edit.png')"></image>
</view>
</button>
</slot>
</view>
</template>
<script setup>
/**
* 基础组件 - 地址卡片
*
* @param {String} icon = _icon-edit - icon
*
* @event {Function()} click - 点击
* @event {Function()} actionClick - 点击工具栏
*
* @slot - 默认插槽
*/
import sheep from '@/sheep';
import _ from 'lodash';
const props = defineProps({
item: {
type: Object,
default() {},
},
hasBorderBottom: {
type: Boolean,
defult: true,
},
});
const onEdit = () => {
sheep.$router.go('/pages/user/invoice/edit', {
id: props.item.id,
});
};
</script>
<style lang="scss" scoped>
.address-item {
padding: 30rpx;
.item-left {
width: 600rpx;
}
.area-text {
font-size: 26rpx;
font-weight: 400;
color: $dark-9;
}
.address-text {
font-size: 32rpx;
font-weight: 600;
color: #333333;
line-height: 48rpx;
}
.person-text {
font-size: 28rpx;
font-weight: 400;
color: $dark-9;
}
}
.edit-btn {
width: 44rpx;
height: 44rpx;
background: $gray-f;
border-radius: 50%;
.edit-icon {
width: 24rpx;
height: 24rpx;
}
}
image {
width: 100%;
height: 100%;
}
</style>

View File

@ -197,7 +197,7 @@
},
iconSize: {
type: Number,
default: 96,
default: 80,
},
color: {
type: String,
@ -264,13 +264,13 @@
.menu-icon {
transform: translate(0, 0);
width: 98rpx;
height: 98rpx;
width: 80rpx;
height: 80rpx;
padding-bottom: 10rpx;
}
.menu-title {
font-size: 30rpx;
font-size: 24rpx;
color: #333;
}
}

View File

@ -1,3 +1,4 @@
<!-- 全局 - 快捷入口 -->
<template>
<su-popup :show="show" type="top" round="20" backgroundColor="#F0F0F0" @close="closeMenuTools">
<su-status-bar />
@ -10,7 +11,7 @@
class="ss-reset-button list-image ss-flex ss-row-center ss-col-center"
@tap="onClick(item)"
>
<image v-if="show" :src="sheep.$url.static(item.icon)" class="list-icon"></image>
<image v-if="show" :src="sheep.$url.static(item.icon)" class="list-icon" />
</button>
<view class="list-title ss-m-t-20">{{ item.title }}</view>
</view>
@ -63,11 +64,6 @@
icon: '/static/img/shop/tools/collect.png',
title: '我的收藏',
},
{
url: '/pages/public/feedback',
icon: '/static/img/shop/tools/feedback.png',
title: '意见反馈',
},
{
url: '/pages/chat/index',
icon: '/static/img/shop/tools/service.png',

View File

@ -32,7 +32,7 @@
<style lang="scss" scoped>
.notice-wrap {
.icon-img {
height: 60rpx;
height: 56rpx;
}
}
</style>

View File

@ -1,202 +0,0 @@
<template>
<view>
<view
v-if="mode === 1 && state.scoreList.length"
class="goods-md-wrap ss-flex ss-flex-wrap ss-col-top"
>
<view class="goods-list-box">
<view
class="left-list"
:style="[{ paddingRight: data.space + 'rpx', marginBottom: data.space + 'px' }]"
v-for="item in state.leftScoreList"
:key="item.id"
>
<s-score-card
class="goods-md-box"
size="md"
:goodsFields="goodsFields"
:data="item"
:titleColor="goodsFields.title?.color"
:subTitleColor="goodsFields.subtitle.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
:titleWidth="330 - marginLeft - marginRight"
@click="sheep.$router.go('/pages/goods/score', { id: item.id })"
@getHeight="mountMasonry($event, 'left')"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ buyNowStyle.mode === 1 ? buyNowStyle.text : '' }}
</button>
</template>
</s-score-card>
</view>
</view>
<view class="goods-list-box">
<view
class="right-list"
:style="[{ paddingLeft: data.space + 'rpx', marginBottom: data.space + 'px' }]"
v-for="item in state.rightScoreList"
:key="item.id"
>
<s-score-card
class="goods-md-box"
size="md"
:goodsFields="goodsFields"
:data="item"
:titleColor="goodsFields.title?.color"
:subTitleColor="goodsFields.subtitle.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
:titleWidth="330 - marginLeft - marginRight"
@click="sheep.$router.go('/pages/goods/score', { id: item.id })"
@getHeight="mountMasonry($event, 'right')"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ buyNowStyle.mode === 1 ? buyNowStyle.text : '' }}
</button>
</template>
</s-score-card>
</view>
</view>
<!-- <view class="goods-hack" v-if="state.scoreList.length % 2 == 1" style="width: 345rpx"></view> -->
</view>
<view v-if="mode === 2 && state.scoreList.length" class="goods-lg-box">
<view
class="goods-box"
:style="[{ marginBottom: data.space + 'px' }]"
v-for="item in state.scoreList"
:key="item.id"
>
<s-score-card
class="goods-card"
size="lg"
:goodsFields="goodsFields"
:data="item"
:titleColor="goodsFields.title?.color"
:subTitleColor="goodsFields.subtitle.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
@tap="sheep.$router.go('/pages/goods/score', { id: item.id })"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ buyNowStyle.mode === 1 ? buyNowStyle.text : '' }}
</button>
</template>
</s-score-card>
</view>
</view>
</view>
</template>
<script setup>
import { computed, reactive, onMounted } from 'vue';
import sheep from '@/sheep';
const state = reactive({
scoreList: [],
leftScoreList: [],
rightScoreList: [],
});
const props = defineProps({
data: {
type: Object,
default() {},
},
styles: {
type: Object,
default() {},
},
});
const { mode, buyNowStyle, goodsFields, goodsIds } = props.data ?? {};
const { marginLeft, marginRight } = props.styles ?? {};
async function getScoreListByIds(ids) {
let { data } = await sheep.$api.app.scoreShop.ids({ ids });
return data;
}
onMounted(async () => {
state.scoreList = await getScoreListByIds(goodsIds.join(','));
if (mode === 1) {
mountMasonry();
}
});
//
let count = 0;
let leftHeight = 0;
let rightHeight = 0;
function mountMasonry(height = 0, where = 'left') {
if (!state.scoreList[count]) return;
if (where === 'left') leftHeight += height;
if (where === 'right') rightHeight += height;
if (leftHeight <= rightHeight) {
state.leftScoreList.push(state.scoreList[count]);
} else {
state.rightScoreList.push(state.scoreList[count]);
}
count++;
}
//
const buyStyle = computed(() => {
if (buyNowStyle.mode == 1) {
// button
return {
background: `linear-gradient(to right, ${buyNowStyle.color1}, ${buyNowStyle.color2})`,
};
}
if (buyNowStyle.mode == 2) {
// image
return {
width: '54rpx',
height: '54rpx',
background: `url(${sheep.$url.cdn(buyNowStyle.src)}) no-repeat`,
backgroundSize: '100% 100%',
};
}
});
</script>
<style lang="scss" scoped>
.goods-md-wrap {
width: 100%;
}
.goods-list-box {
width: 50%;
box-sizing: border-box;
.left-list {
&:nth-last-child(1) {
margin-bottom: 0 !important;
}
}
}
.goods-box {
&:nth-last-of-type(1) {
margin-bottom: 0 !important;
}
}
.goods-md-box,
.goods-sl-box,
.goods-lg-box {
position: relative;
.cart-btn {
position: absolute;
bottom: 10rpx;
right: 20rpx;
z-index: 11;
height: 50rpx;
line-height: 50rpx;
padding: 0 20rpx;
border-radius: 25rpx;
font-size: 24rpx;
color: #fff;
}
}
</style>

View File

@ -1,459 +0,0 @@
<template>
<view>
<!-- md卡片竖向一行放两个图上内容下 -->
<view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
<image
class="md-img-box"
:src="sheep.$url.cdn(data.image)"
mode="widthFix"
@load="calculatePanelHeight"
></image>
<view
class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
:id="elId"
>
<view
v-if="goodsFields.title?.show"
class="md-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
{{ data.title }}
</view>
<view
v-if="goodsFields.subtitle?.show"
class="md-goods-subtitle ss-m-t-16 ss-line-1"
:style="[{ color: subTitleColor }]"
>
{{ data.subtitle }}
</view>
<view class="ss-col-bottom">
<view
v-if="goodsFields.score_price?.show"
class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10 ss-flex"
:style="[{ color: goodsFields.score_price.color }]"
>
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
></image>
{{ data.score }}
</view>
<view
v-if="goodsFields.price?.show && data.original_price > 0"
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ data.original_price }}</view>
</view>
</view>
<view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
<slot name="cart">
<view class="cart-box ss-flex ss-col-center ss-row-center">
<image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode=""></image>
</view>
</slot>
</view>
<!-- lg卡片横向型一行放一个图片左内容右边 -->
<view
v-if="size === 'lg'"
class="lg-goods-card ss-flex ss-col-stretch"
:style="[elStyles]"
@tap="onClick"
>
<image class="lg-img-box" :src="sheep.$url.cdn(data.image)" mode="aspectFill"></image>
<view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
<view class="ss-m-r-20">
<view
v-if="goodsFields.title?.show"
class="lg-goods-title ss-line-2"
:style="[{ color: titleColor }]"
>
{{ data.title }}
</view>
<view
v-if="goodsFields.subtitle?.show"
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
:style="[{ color: subTitleColor }]"
>
{{ data.subtitle }}
</view>
</view>
<view>
<view class="ss-m-t-10">
<view
v-if="goodsFields.score_price?.show"
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: goodsFields.score_price.color }]"
>
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
></image>
{{ data.score }}
</view>
<view
v-if="goodsFields.price?.show && data.original_price > 0"
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ data.original_price }}</view>
</view>
</view>
<view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
</view>
<slot name="cart"
><view class="buy-box ss-flex ss-col-center ss-row-center">去兑换</view></slot
>
</view>
<!-- sl卡片竖向型一行放一个图片上内容下边 -->
<view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" @tap="onClick">
<image class="sl-img-box" :src="sheep.$url.cdn(data.image)" mode="aspectFill"></image>
<view class="sl-goods-content ss-flex-col ss-row-between ss-p-b-20 ss-p-t-20">
<view class="ss-m-b-20">
<view class="sl-goods-title ss-line-1 ss-p-l-16 ss-p-r-16">
{{ data.title }}
</view>
<view v-if="data.subtitle" class="sl-goods-subtitle ss-p-l-16 ss-p-r-16 ss-m-t-16">
{{ data.subtitle }}
</view>
</view>
<view>
<slot name="activity">
<view
v-if="data.promos?.length"
class="tag-box ss-flex ss-col-center ss-flex-wrap ss-p-l-16 ss-p-r-16"
>
<view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
{{ item.title }}
</view>
</view>
</slot>
<view class="ss-flex ss-col-bottom ss-p-l-16 ss-p-r-16 font-OPPOSANS">
<view class="sl-goods-price ss-m-r-12 ss-flex">
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
></image>
<view>{{ data.score ? data.score : '' }}</view>
</view>
<view
v-if="data.original_price > 0"
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
>
<text class="price-unit ss-font-20"></text>
<view class="ss-m-l-8">{{ data.original_price }}</view>
</view>
</view>
<view class="ss-p-l-16 ss-p-r-16 ss-m-t-16 ss-flex ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
</view>
<slot name="cart"
><view class="buy-box ss-flex ss-col-center ss-row-center">去兑换</view></slot
>
</view>
</view>
</template>
<script setup>
import { computed, getCurrentInstance } from 'vue';
import sheep from '@/sheep';
import { formatSales } from '@/sheep/hooks/useGoods';
import { formatStock } from '@/sheep/hooks/useGoods';
import goodsCollectVue from '@/pages/user/goods-collect.vue';
/**
* 订单卡片
*
* @property {String} img - 图片
* @property {String} title - 标题
* @property {Number} titleWidth = 0 - 标题宽度默认0单位rpx
* @property {String} skuText - 规格
* @property {String | Number} score - 积分
* @property {String | Number} price - 价格
* @property {String | Number} originalPrice - 单购价
* @property {String} priceColor - 价格颜色
* @property {Number | String} num - 数量
*
*/
const props = defineProps({
goodsFields: {
type: [Array, Object],
default() {
return {
title: { show: true },
subtitle: { show: true },
price: { show: true },
original_price: { show: true },
sales: { show: true },
stock: { show: true },
};
},
},
tagStyle: {
type: Object,
default: {},
},
data: {
type: Object,
default: {},
},
size: {
type: String,
default: 'sl',
},
background: {
type: String,
default: '',
},
topRadius: {
type: Number,
default: 0,
},
bottomRadius: {
type: Number,
default: 0,
},
titleWidth: {
type: Number,
default: 0,
},
titleColor: {
type: String,
default: '#333',
},
priceUnit: {
type: String,
default: '¥',
},
subTitleColor: {
type: String,
default: '#999999',
},
});
//
const elStyles = computed(() => {
return {
background: props.background,
'border-top-left-radius': props.topRadius + 'px',
'border-top-right-radius': props.topRadius + 'px',
'border-bottom-left-radius': props.bottomRadius + 'px',
'border-bottom-right-radius': props.bottomRadius + 'px',
};
});
const emits = defineEmits(['click', 'getHeight']);
const onClick = () => {
emits('click');
};
//
const salesAndStock = computed(() => {
let text = [];
text.push(formatSales(props.data.sales_show_type, props.data.sales));
text.push(formatStock(props.data.stock_show_type, props.data.stock));
return text.join(' | ');
});
//
const { proxy } = getCurrentInstance();
const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
function calculatePanelHeight(e) {
if (props.size === 'md') {
const view = uni.createSelectorQuery().in(proxy);
view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
view.exec((data) => {
const goodsPriceCard = data[0];
const card = {
width: goodsPriceCard.width,
height: (goodsPriceCard.width / e.detail.width) * e.detail.height + goodsPriceCard.height,
};
emits('getHeight', card.height);
});
}
}
</script>
<style lang="scss" scoped>
.price-unit {
margin-right: -4px;
}
.sales-text {
display: table;
font-size: 24rpx;
transform: scale(0.8);
margin-left: -16rpx;
color: #c4c4c4;
}
// md
.md-goods-card {
overflow: hidden;
width: 100%;
position: relative;
z-index: 1;
background-color: $white;
position: relative;
.md-img-box {
width: 100%;
}
.md-goods-title {
font-size: 26rpx;
color: #333;
width: 100%;
}
.md-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
}
.md-goods-price {
font-size: 30rpx;
color: $red;
line-height: 36rpx;
}
.cart-box {
width: 54rpx;
height: 54rpx;
background: linear-gradient(90deg, #fe8900, #ff5e00);
border-radius: 50%;
position: absolute;
bottom: 50rpx;
right: 20rpx;
z-index: 2;
.cart-icon {
width: 30rpx;
height: 30rpx;
}
}
}
// lg
.lg-goods-card {
overflow: hidden;
position: relative;
z-index: 1;
background-color: $white;
height: 280rpx;
.lg-img-box {
width: 280rpx;
height: 280rpx;
margin-right: 20rpx;
}
.lg-goods-title {
font-size: 28rpx;
font-weight: 500;
color: #333333;
// line-height: 36rpx;
// width: 410rpx;
}
.lg-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
line-height: 30rpx;
// width: 410rpx;
}
.lg-goods-price {
font-size: 30rpx;
color: $red;
line-height: 36rpx;
}
.buy-box {
position: absolute;
bottom: 20rpx;
right: 20rpx;
z-index: 2;
width: 120rpx;
height: 50rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
border-radius: 25rpx;
font-size: 24rpx;
color: #ffffff;
}
.tag-box {
width: 100%;
}
}
.sl-goods-card {
overflow: hidden;
position: relative;
z-index: 1;
width: 100%;
background-color: $white;
.sl-img-box {
width: 100%;
height: 360rpx;
}
.sl-goods-title {
font-size: 26rpx;
color: #333;
width: 100%;
box-sizing: border-box;
}
.sl-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
line-height: 30rpx;
width: 100%;
box-sizing: border-box;
}
.sl-goods-price {
font-size: 30rpx;
color: $red;
}
.buy-box {
position: absolute;
bottom: 20rpx;
right: 20rpx;
z-index: 2;
width: 148rpx;
height: 50rpx;
background: linear-gradient(90deg, #fe8900, #ff5e00);
border-radius: 25rpx;
font-size: 24rpx;
color: #ffffff;
}
}
.goods-origin-price {
font-size: 20rpx;
color: #c4c4c4;
text-decoration: line-through;
}
.score-img {
width: 36rpx;
height: 36rpx;
margin: 0 4rpx;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<view class="status_bar"></view>
<view class="status_bar" />
</template>
<style>

View File

@ -2,36 +2,29 @@
<template>
<view
class="ss-title-wrap ss-flex ss-col-center"
:class="[state.typeMap[data.location]]"
:class="[state.typeMap[data.textAlign]]"
:style="[elStyles]"
>
<view class="title-content">
<view v-if="data.title.text" class="title-text" :style="[titleStyles]">{{
data.title.text
}}</view>
<view v-if="data.subtitle.text" :style="[subtitleStyles]" class="sub-title-text">
{{ data.subtitle.text }}
</view>
<!-- 主标题 -->
<view v-if="data.title" class="title-text" :style="[titleStyles]">{{ data.title }}</view>
<!-- 副标题 -->
<view v-if="data.description" :style="[descStyles]" class="sub-title-text">{{ data.description }}</view>
</view>
<view v-if="data.more.show" class="more-box ss-flex ss-col-center" @tap="sheep.$router.go(data.more.url)">
<view class="more-text">查看更多</view>
<text class="_icon-forward"></text>
<!-- 查看更多 -->
<view v-if="data.more?.show" class="more-box ss-flex ss-col-center" @tap="sheep.$router.go(data.more.url)"
:style="{color: data.descriptionColor}">
<view class="more-text" v-if="data.more.type !== 'icon'">{{ data.more.text }} </view>
<text class="_icon-forward" v-if="data.more.type !== 'text'"></text>
</view>
</view>
</template>
<script setup>
/**
*
* 标题栏
*
* @property {String} title - 标题
* @property {String} subTitle - 副标题
* @property {Number} height - 高度
* @property {String} Type = [left | right | center | between] - 样式
*
*/
import { computed, reactive } from 'vue';
import { reactive } from 'vue';
import sheep from '@/sheep';
//
@ -52,35 +45,28 @@
type: Object,
default() {},
},
height: {
type: Number,
default: 100,
},
});
//
const elStyles = {
background: `url(${sheep.$url.cdn(props.data.src)}) no-repeat top center / 100% auto`,
height: props.styles.height + 'px',
fontStyle: props.data.title.other.includes('italic') ? 'italic' : 'normal',
fontWeight: props.data.title.other.includes('bold') ? 'bold' : '',
background: `url(${sheep.$url.cdn(props.data.bgImgUrl)}) no-repeat top center / 100% auto`,
fontSize: `${props.data.titleSize}px`,
fontWeight: `${props.data.titleWeight}px`,
};
//
const titleStyles = {
color: props.data.title.color,
fontSize: props.data.title.textFontSize + 'px',
textAlign: props.data.location,
marginLeft: props.data.skew + 'px',
color: props.data.titleColor,
fontSize: `${props.data.titleSize}px`,
textAlign: props.data.textAlign
};
//
const subtitleStyles = {
color: props.data.subtitle.color,
fontSize: props.data.subtitle.textFontSize + 'px',
textAlign: props.data.location,
fontStyle: props.data.subtitle.other.includes('italic') ? 'italic' : 'normal',
fontWeight: props.data.subtitle.other.includes('bold') ? 'bold' : '',
const descStyles = {
color: props.data.descriptionColor,
textAlign: props.data.textAlign,
fontSize: `${props.data.descriptionSize}px`,
fontWeight: `${props.data.descriptionWeight}px`,
};
</script>

View File

@ -1,6 +1,7 @@
import { ref } from 'vue';
import dayjs from 'dayjs';
import $url from '@/sheep/url';
import { formatDate } from '@/sheep/util';
/**
* 格式化销量
@ -9,7 +10,7 @@ import $url from '@/sheep/url';
* @return {string} 格式化后的销量字符串
*/
export function formatSales(type, num) {
let prefix = type!=='exact' && num<10 ? '销量': '已售';
let prefix = type !== 'exact' && num < 10 ? '销量' : '已售';
return formatNum(prefix, type, num)
}
@ -65,6 +66,7 @@ export function formatPrice(e) {
// 视频格式后缀列表
const VIDEO_SUFFIX_LIST = ['.avi', '.mp4']
/**
* 转换商品轮播的链接列表根据链接的后缀判断是视频链接还是图片链接
*
@ -74,7 +76,7 @@ const VIDEO_SUFFIX_LIST = ['.avi', '.mp4']
export function formatGoodsSwiper(urlList) {
return urlList.map((url, key) => {
const isVideo = VIDEO_SUFFIX_LIST.some(suffix => url.includes(suffix));
const type = isVideo ? 'video' :'image'
const type = isVideo ? 'video' : 'image'
const src = $url.cdn(url);
return { type, src }
});
@ -82,26 +84,182 @@ export function formatGoodsSwiper(urlList) {
/**
* 格式化订单状态的颜色
* @param type 订单类型
*
* @param order 订单
* @return {string} 颜色的 class 名称
*/
export function formatOrderColor(type) {
switch (type) {
case 'apply_refund':
case 'groupon_ing':
case 'nocomment':
case 'noget':
case 'nosend':
return 'warning-color';
case 'closed':
case 'groupon_invalid':
case 'cancel':
case 'refund_agree':
return 'danger-color';
case 'completed':
return 'success-color';
case 'unpaid':
return 'info-color';
export function formatOrderColor(order) {
if (order.status === 0) {
return 'info-color';
}
if (order.status === 10
|| order.status === 20
|| (order.status === 30 && !order.commentStatus)) {
return 'warning-color';
}
if (order.status === 30 && order.commentStatus) {
return 'success-color';
}
return 'danger-color';
}
/**
* 格式化订单状态
*
* @param order 订单
*/
export function formatOrderStatus(order) {
if (order.status === 0) {
return '待付款';
}
if (order.status === 10 && order.deliveryType === 1) {
return '待发货';
}
if (order.status === 10 && order.deliveryType === 2) {
return '待核销';
}
if (order.status === 20) {
return '待收货';
}
if (order.status === 30 && !order.commentStatus) {
return '待评价';
}
if (order.status === 30 && order.commentStatus) {
return '已完成';
}
return '已关闭';
}
/**
* 格式化订单状态的描述
*
* @param order 订单
*/
export function formatOrderStatusDescription(order) {
if (order.status === 0) {
return `请在 ${ formatDate(orderInfo.payExpireTime) } 前完成支付`;
}
if (order.status === 10) {
return '商家未发货,请耐心等待';
}
if (order.status === 20) {
return '商家已发货,请耐心等待';
}
if (order.status === 30 && !order.commentStatus) {
return '已收货,快去评价一下吧';
}
if (order.status === 30 && order.commentStatus) {
return '交易完成,感谢您的支持';
}
return '交易关闭';
}
/**
* 处理订单的 button 操作按钮数组
*
* @param order 订单
*/
export function handleOrderButtons(order) {
order.buttons = []
if (order.type === 3) { // 查看拼团
order.buttons.push('combination');
}
if (order.status === 20) { // 确认收货
order.buttons.push('confirm');
}
if (order.logisticsId > 0) { // 查看物流
order.buttons.push('express');
}
if (order.status === 0) { // 取消订单 / 发起支付
order.buttons.push('cancel');
order.buttons.push('pay');
}
if (order.status === 30 && !order.commentStatus) { // 发起评价
order.buttons.push('comment');
}
if (order.status === 40) { // 删除订单
order.buttons.push('delete');
}
}
/**
* 格式化售后状态
*
* @param afterSale 售后
*/
export function formatAfterSaleStatus(afterSale) {
if (afterSale.status === 10) {
return '申请售后';
}
if (afterSale.status === 20) {
return '商品待退货';
}
if (afterSale.status === 30) {
return '商家待收货';
}
if (afterSale.status === 40) {
return '等待退款';
}
if (afterSale.status === 50) {
return '退款成功';
}
if (afterSale.status === 61) {
return '买家取消';
}
if (afterSale.status === 62) {
return '商家拒绝';
}
if (afterSale.status === 63) {
return '商家拒收货';
}
return '未知状态';
}
/**
* 格式化售后状态的描述
*
* @param afterSale 售后
*/
export function formatAfterSaleStatusDescription(afterSale) {
if (afterSale.status === 10) {
return '退款申请待商家处理';
}
if (afterSale.status === 20) {
return '请退货并填写物流信息';
}
if (afterSale.status === 30) {
return '退货退款申请待商家处理';
}
if (afterSale.status === 40) {
return '等待退款';
}
if (afterSale.status === 50) {
return '退款成功';
}
if (afterSale.status === 61) {
return '退款关闭';
}
if (afterSale.status === 62) {
return `商家不同意退款申请,拒绝原因:${afterSale.auditReason}`;
}
if (afterSale.status === 63) {
return `商家拒绝收货,不同意退款,拒绝原因:${afterSale.auditReason}`;
}
return '未知状态';
}
/**
* 处理售后的 button 操作按钮数组
*
* @param afterSale 售后
*/
export function handleAfterSaleButtons(afterSale) {
afterSale.buttons = [];
if ([10, 20, 30].includes(afterSale.status)) { // 取消订单
afterSale.buttons.push('cancel');
}
if (afterSale.status === 20) { // 退货信息
afterSale.buttons.push('delivery');
}
}

View File

@ -6,7 +6,7 @@ import test from '@/sheep/helper/test.js';
import $api from '@/sheep/api';
// 打开授权弹框
export function showAuthModal(type = 'accountLogin') {
export function showAuthModal(type = 'smsLogin') {
const modal = $store('modal');
if (modal.auth !== '') {
closeAuthModal();
@ -58,10 +58,9 @@ export function closeMenuTools() {
}
// 发送短信验证码 60秒
export function getSmsCode(event, mobile = '') {
export function getSmsCode(event, mobile) {
const modalStore = $store('modal');
const lastSendTimer = modalStore.lastTimer[event];
if (typeof lastSendTimer === 'undefined') {
$helper.toast('短信发送事件错误');
return;
@ -69,26 +68,36 @@ export function getSmsCode(event, mobile = '') {
const duration = dayjs().unix() - lastSendTimer;
const canSend = duration >= 60;
if (!canSend) {
$helper.toast('请稍后再试');
return;
}
if (!test.mobile(mobile)) {
// 只有 mobile 非空时才校验。因为部分场景(修改密码),不需要输入手机
if (mobile && !test.mobile(mobile)) {
$helper.toast('手机号码格式不正确');
return;
}
// 发送验证码 + 更新上次发送验证码时间
$api.app.sendSms({ mobile, event }).then((res) => {
if (res.error === 0) {
let scene = -1;
switch (event) {
case 'resetPassword':
scene = 4;
break;
case 'changePassword':
scene = 3;
break;
case 'smsLogin':
scene = 1;
break;
}
$api.AuthUtil.sendSmsCode(mobile, scene).then((res) => {
if (res.code === 0) {
modalStore.$patch((state) => {
state.lastTimer[event] = dayjs().unix();
});
}
});
}
// 获取短信验证码倒计时 -- 60秒

View File

@ -3,19 +3,20 @@ import sheep from '@/sheep';
import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
// #endif
import { getRootUrl } from '@/sheep/helper';
import PayOrderApi from '@/sheep/api/pay/order';
/**
* 支付
*
* @param {String} payment = ['wechat','alipay','wallet','offline'] - 支付方式
* @param {String} orderType = ['goods','recharge','groupon'] - 订单类型
* @param {String} orderSN - 订单号
* @param {String} id - 订单号
*/
export default class SheepPay {
constructor(payment, orderType, orderSN) {
constructor(payment, orderType, id) {
this.payment = payment;
this.orderSN = orderSN;
this.id = id;
this.orderType = orderType;
this.payAction();
}
@ -29,8 +30,8 @@ export default class SheepPay {
alipay: () => {
this.redirectPay(); // 现在公众号可以直接跳转支付宝页面
},
money: () => {
this.moneyPay();
wallet: () => {
this.walletPay();
},
offline: () => {
this.offlinePay();
@ -43,8 +44,8 @@ export default class SheepPay {
alipay: () => {
this.copyPayLink();
},
money: () => {
this.moneyPay();
wallet: () => {
this.walletPay();
},
offline: () => {
this.offlinePay();
@ -57,8 +58,8 @@ export default class SheepPay {
alipay: () => {
this.alipay();
},
money: () => {
this.moneyPay();
wallet: () => {
this.walletPay();
},
offline: () => {
this.offlinePay();
@ -71,8 +72,8 @@ export default class SheepPay {
alipay: () => {
this.redirectPay();
},
money: () => {
this.moneyPay();
wallet: () => {
this.walletPay();
},
offline: () => {
this.offlinePay();
@ -83,18 +84,21 @@ export default class SheepPay {
}
// 预支付
prepay() {
prepay(channel) {
return new Promise((resolve, reject) => {
let data = {
order_sn: this.orderSN,
payment: this.payment,
id: this.id,
channelCode: channel,
channelExtras: {}
};
if (uni.getStorageSync('openid')) {
data.openid = uni.getStorageSync('openid');
}
sheep.$api.pay.prepay(data).then((res) => {
res.error === 0 && resolve(res);
if (res.error === -1 && res.msg === 'miss_openid') {
PayOrderApi.submitOrder(data).then((res) => {
// 成功时
res.code === 0 && resolve(res);
// 失败时
if (res.code !== 0 && res.msg === 'miss_openid') {
uni.showModal({
title: '微信支付',
content: '请先绑定微信再使用微信支付',
@ -109,7 +113,7 @@ export default class SheepPay {
});
}
// #ifdef H5
// 微信公众号JSSDK支付
// 微信公众号JSSDK支付 TODO 芋艿:待接入
async wechatOfficialAccountPay() {
let that = this;
let { error, data, msg } = await this.prepay();
@ -130,21 +134,21 @@ export default class SheepPay {
});
}
//浏览器微信H5支付
//浏览器微信H5支付 TODO 芋艿:待接入
async wechatWapPay() {
const { error, data } = await this.prepay();
if (error === 0) {
const redirect_url = `${getRootUrl()}pages/pay/result?orderSN=${this.orderSN}&payment=${this.payment
const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment
}&orderType=${this.orderType}`;
location.href = `${data.pay_data.h5_url}&redirect_url=${encodeURIComponent(redirect_url)}`;
}
}
// 支付链接
// 支付链接 TODO 芋艿:待接入
async redirectPay() {
let { error, data } = await this.prepay();
if (error === 0) {
const redirect_url = `${getRootUrl()}pages/pay/result?orderSN=${this.orderSN}&payment=${this.payment
const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment
}&orderType=${this.orderType}`;
location.href = data.pay_data + encodeURIComponent(redirect_url);
}
@ -152,7 +156,7 @@ export default class SheepPay {
// #endif
// 微信小程序支付
// 微信小程序支付 TODO 芋艿:待接入
async wechatMiniProgramPay() {
let that = this;
let result = await this.prepay();
@ -173,18 +177,18 @@ export default class SheepPay {
}
// 余额支付
async moneyPay() {
const { error } = await this.prepay();
error === 0 && this.payResult('success');
async walletPay() {
const { code } = await this.prepay('wallet');
code === 0 && this.payResult('success');
}
// 货到付款
// 货到付款 TODO 芋艿:待接入
async offlinePay() {
const { error } = await this.prepay();
error === 0 && this.payResult('success');
}
// 支付宝复制链接支付
// 支付宝复制链接支付 TODO 芋艿:待接入
async copyPayLink() {
let that = this;
let { error, data } = await this.prepay();
@ -203,7 +207,7 @@ export default class SheepPay {
}
}
// 支付宝支付
// 支付宝支付 TODO 芋艿:待接入
async alipay() {
let that = this;
const { error, data } = await this.prepay();
@ -225,7 +229,7 @@ export default class SheepPay {
}
}
// 微信支付
// 微信支付 TODO 芋艿:待接入
async wechatAppPay() {
let that = this;
let { error, data } = await this.prepay();
@ -246,10 +250,72 @@ export default class SheepPay {
// 支付结果跳转,success:成功fail:失败
payResult(resultType) {
sheep.$router.redirect('/pages/pay/result', {
orderSN: this.orderSN,
payment: this.payment, //重新支付的时候使用
payState: resultType,
id: this.id,
orderType: this.orderType,
payState: resultType
});
}
}
export function getPayMethods(channels) {
const payMethods = [
{
icon: '/static/img/shop/pay/wechat.png',
title: '微信支付',
value: 'wechat',
disabled: true,
},
{
icon: '/static/img/shop/pay/alipay.png',
title: '支付宝支付',
value: 'alipay',
disabled: true,
},
{
icon: '/static/img/shop/pay/wallet.png',
title: '余额支付',
value: 'wallet',
disabled: true,
},
{
icon: '/static/img/shop/pay/apple.png',
title: 'Apple Pay',
value: 'apple',
disabled: true,
},
{
icon: '/static/img/shop/pay/wallet.png',
title: '模拟支付',
value: 'mock',
disabled: true,
}
];
const platform = sheep.$platform.name
// 1. 处理【微信支付】
const wechatMethod = payMethods[0];
if ((platform === 'WechatOfficialAccount' && channels.includes('wx_pub'))
|| platform === 'WechatMiniProgram' && channels.includes('wx_lite')
|| platform === 'App' && channels.includes('wx_app')) {
wechatMethod.disabled = false;
}
// 2. 处理【支付宝支付】
const alipayMethod = payMethods[1];
if ((platform === 'WechatOfficialAccount' && channels.includes('alipay_wap'))
|| platform === 'WechatMiniProgram' && channels.includes('alipay_wap')
|| platform === 'App' && channels.includes('alipay_app')) {
alipayMethod.disabled = false;
}
// 3. 处理【余额支付】
const walletMethod = payMethods[2];
if (channels.includes('wallet')) {
walletMethod.disabled = false;
}
// 4. 处理【苹果支付】TODO 芋艿:未来接入
// 5. 处理【模拟支付】
const mockMethod = payMethods[4];
if (channels.includes('mock')) {
mockMethod.disabled = false;
}
return payMethods;
}

View File

@ -94,6 +94,7 @@ http.interceptors.request.use(
if (config.url.indexOf('/app-api/') !== -1) {
config.header['Accept'] = '*/*'
config.header['tenant-id'] = '1';
config.header['terminal'] = '20';
config.header['Authorization'] = 'Bearer test247';
}
return config;
@ -112,9 +113,10 @@ http.interceptors.response.use(
if (response.header.authorization || response.header.Authorization) {
$store('user').setToken(response.header.authorization || response.header.Authorization);
}
// TODO 芋艿:如果是登录的 API则自动设置 token
response.config.custom.showLoading && closeLoading();
if (response.data.error !== 0) {
if (response.data.error !== 0 && response.data.code !== 0) {
if (response.config.custom.showError)
uni.showToast({
title: response.data.msg || '服务器开小差啦,请稍后再试~',
@ -123,9 +125,10 @@ http.interceptors.response.use(
});
return Promise.resolve(response.data);
}
// 成功时的提示
if (
response.data.error === 0 &&
response.data.msg !== '' &&
(response.data.error === 0 || response.data.code === 0) &&
( response.data.msg !== '' || response.config.custom.successMsg !== '' ) &&
response.config.custom.showSuccess
) {
uni.showToast({
@ -212,8 +215,8 @@ const request = (config) => {
}
// TODO 芋艿:额外拼接
if (config.url.indexOf('/app-api/') >= 0) {
config.url = 'http://api-dashboard.yudao.iocoder.cn' + config.url; // 调用【云端】
// config.url = 'http://127.0.0.1:48080' + config.url; // 调用【本地】
// config.url = 'http://api-dashboard.yudao.iocoder.cn' + config.url; // 调用【云端】
config.url = 'http://127.0.0.1:48080' + config.url; // 调用【本地】
}
return http.middleware(config);
};

View File

@ -95,7 +95,8 @@ http.interceptors.request.use(
if (config.url.indexOf('/app-api/') !== -1) {
config.header['Accept'] = '*/*'
config.header['tenant-id'] = '1';
config.header['Authorization'] = 'Bearer test247';
config.header['terminal'] = '20';
config.header['Authorization'] = 'Bearer test247';
}
return config;
},
@ -214,9 +215,9 @@ const request = (config) => {
// TODO 芋艿:额外拼接
if (config.url.indexOf('/app-api/') >= 0) {
// 设置接口地址
config.url = 'http://api-dashboard.yudao.iocoder.cn' + config.url; // 调用【云端】
// config.url = 'http://api-dashboard.yudao.iocoder.cn' + config.url; // 调用【云端】
// config.url = 'https://app.test.huizhizao.vip/prod-api' + config.url; // 调用【云端】
// config.url = 'http://127.0.0.1:48080' + config.url; // 调用【本地】
config.url = 'http://127.0.0.1:48080' + config.url; // 调用【本地】
}
return http.middleware(config);
};

View File

@ -1,98 +1,93 @@
import { defineStore } from 'pinia';
import cartApi from '@/sheep/api/cart';
import CartApi from '@/sheep/api/trade/cart';
const cart = defineStore({
id: 'cart',
state: () => ({
list: [], // 购物车列表
selectedIds: [], // 已选列表
isAllSelected: false, //是否全选
cartSelectedTotalPrice: '0.00', // 选中项总金额
isAllSelected: false, // 是否全选
totalPriceSelected: 0, // 选中项总金额
}),
getters: {
totalPriceSelected: (state) => {
let price = 0;
if (!state.selectedIds.length) return price.toFixed(2);
state.list.forEach((item) => {
price += state.selectedIds.includes(item.id)
? Number(item.sku.price/100) * item.count
: 0;
});
return price.toFixed(2);
},
},
actions: {
// 获取购物车列表
async getList() {
const { data, code } = await cartApi.list();
const { data, code } = await CartApi.getCartList();
if (code === 0) {
this.list = data.validList;
// 计算各种关联属性
this.selectedIds = [];
this.isAllSelected = true;
this.totalPriceSelected = 0;
this.list.forEach((item) => {
if (item.selected) {
this.selectedIds.push(item.id);
this.totalPriceSelected += item.count * item.sku.price;
} else {
this.isAllSelected = false;
}
});
}
},
// 添加购物车
async add(goodsInfo) {
const { error } = await cartApi.append({
goods_id: goodsInfo.goods_id,
goods_num: goodsInfo.goods_num,
goods_sku_price_id: goodsInfo.id,
// 添加购物项
const { code } = await CartApi.addCart({
skuId: goodsInfo.id,
count: goodsInfo.goods_num,
});
if (error === 0) {
this.getList();
// 刷新购物车列表
if (code === 0) {
await this.getList();
}
},
// 更新购物车
async update(goodsInfo) {
const { error } = await cartApi.update({
const { code } = await CartApi.updateCartCount({
id: goodsInfo.goods_id,
count: goodsInfo.goods_num,
goods_sku_price_id: goodsInfo.goods_sku_price_id,
});
if (error === 0) {
// this.getList();
if (code === 0) {
await this.getList();
}
},
// 移除购物车
async delete(ids) {
if (typeof ids === 'array') {
ids = ids.join(',');
}
const { code } = await cartApi.delete(ids);
const { code } = await CartApi.deleteCart(ids.join(','));
if (code === 0) {
this.selectAll(false);
this.getList();
await this.getList();
}
},
// 选择购物车商品
selectSingle(goodsId) {
if (!this.selectedIds.includes(goodsId)) {
this.selectedIds.push(goodsId);
} else {
this.selectedIds.splice(this.selectedIds.indexOf(goodsId), 1);
// 单选购物车商品
async selectSingle(goodsId) {
const { code } = await CartApi.updateCartSelected({
ids: [goodsId],
selected: !this.selectedIds.includes(goodsId), // 取反
});
if (code === 0) {
await this.getList();
}
this.isAllSelected = this.selectedIds.length === this.list.length;
},
// 全选
selectAll(flag) {
this.isAllSelected = flag;
if (!flag) {
this.selectedIds = [];
} else {
this.list.forEach((item) => {
this.selectedIds.push(item.id);
});
// 全选购物车商品
async selectAll(flag) {
const { code } = await CartApi.updateCartSelected({
ids: this.list.map((item) => item.id),
selected: flag
});
if (code === 0) {
await this.getList();
}
},
// 清空购物车
emptyList() {
this.list = [];
this.selectedIds = [];
this.isAllSelected = false;
this.cartSelectedTotalPrice = '0.00';
async emptyList() {
await this.delete(this.list.map((item) => item.id));
},
},
persist: {

View File

@ -13,10 +13,11 @@ const modal = defineStore({
smsRegister: 0,
changeMobile: 0,
resetPassword: 0,
changePassword: 0,
}
}),
persist: {
enabled: true,
enabled: true,
strategies: [
{
key: 'modal-store',

View File

@ -14,6 +14,7 @@ import app from './app';
import {
showAuthModal
} from '@/sheep/hooks/useModal';
import AuthUtil from '@/sheep/api/member/auth';
// 默认用户信息
const defaultUserInfo = {
@ -51,6 +52,7 @@ const user = defineStore({
actions: {
// 获取个人信息
// TODO 芋艿:整理下;
async getInfo() {
const {
code,
@ -58,20 +60,21 @@ const user = defineStore({
} = await userApi.profile();
// 为了兼容 获取用户余额 可能还会用到其他参数
// 优惠券数量,积分数量 应该在这里
// 优惠券数量,积分数量 应该在这里
const {
code: code2,
data: data2
} = await userApi.balance();
if (code !== 0 || code2 != 0) return;
data.money = data2.balance / 100;
data.money = data2.balance;
this.userInfo = data;
console.log(data2, '信息')
return Promise.resolve(data);
},
// 获取分销商信息
async getAgentInfo() {
// TODO 芋艿:整理下;
async getAgentInfo() {
const res = await commissionApi.agent();
if (res.error === 0) {
this.agentInfo = res.data;
@ -80,7 +83,8 @@ const user = defineStore({
},
// 获取订单、优惠券等其他资产信息
async getNumData() {
// TODO 芋艿:整理下;
async getNumData() {
const {
code,
data
@ -103,7 +107,8 @@ const user = defineStore({
},
// 添加分享记录
async addShareLog(params) {
// TODO 芋艿:整理下;
async addShareLog(params) {
const {
error
} = await userApi.addShareLog(params);
@ -111,7 +116,8 @@ const user = defineStore({
},
// 设置token
setToken(token = '') {
// TODO 芋艿:整理下;
setToken(token = '') {
if (token === '') {
this.isLogin = false;
uni.removeStorageSync('token');
@ -124,7 +130,8 @@ const user = defineStore({
},
// 更新用户相关信息 (手动限流 5秒之内不刷新)
async updateUserData() {
// TODO 芋艿:整理下;
async updateUserData() {
if (!this.isLogin) {
this.resetUserData();
return;
@ -138,7 +145,8 @@ const user = defineStore({
},
// 重置用户默认数据
resetUserData() {
// TODO 芋艿:整理下;
resetUserData() {
this.setToken();
this.userInfo = clone(defaultUserInfo);
this.numData = cloneDeep(defaultNumData);
@ -147,7 +155,8 @@ const user = defineStore({
},
// 登录后
async loginAfter() {
// TODO 芋艿:整理下;
async loginAfter() {
await this.updateUserData();
cart().getList();
// 登录后设置全局分享参数
@ -158,7 +167,8 @@ const user = defineStore({
// }
// 添加分享记录
const shareLog = uni.getStorageSync('shareLog');
// TODO 芋艿:整理下;
const shareLog = uni.getStorageSync('shareLog');
if (!isEmpty(shareLog)) {
this.addShareLog({
...shareLog,
@ -167,12 +177,11 @@ const user = defineStore({
},
// 登出
async logout(force = false) {
// TODO 芋艿:整理下;
async logout(force = false) {
if (!force) {
const {
error
} = await userApi.logout();
if (error === 0) {
const { code } = AuthUtil.logout();
if (code === 0) {
this.resetUserData();
}
}

View File

@ -1,3 +1,4 @@
<!-- 省市区选择弹窗 -->
<template>
<su-popup :show="show" @close="onCancel" round="20">
<view class="ui-region-picker">
@ -9,7 +10,7 @@
title="选择区域"
@cancel="onCancel"
@confirm="onConfirm('confirm')"
></su-toolbar>
/>
<view class="ui-picker-body">
<picker-view
:value="state.currentIndex"

Some files were not shown because too many files have changed in this diff Show More