webview
This commit is contained in:
parent
3d44b8af3f
commit
e544788855
|
|
@ -8,5 +8,20 @@ class AppPlatform extends BasePlatform {
|
|||
this.code = 'APP_ANDROID';
|
||||
this.env = 'app';
|
||||
}
|
||||
async pay(data, event) {
|
||||
console.log('pay', data, event);
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.requestPayment({
|
||||
provider: 'alipay',
|
||||
orderInfo: data,
|
||||
success: (res) => {
|
||||
resolve({ isPay: true });
|
||||
},
|
||||
fail: (err) => {
|
||||
resolve({ isPay: false });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export default AppPlatform;
|
||||
|
|
@ -50,9 +50,7 @@ class BasePlatform {
|
|||
* @param {number} amount - 支付金额(分)
|
||||
* @param {string} orderId - 订单号
|
||||
*/
|
||||
pay({
|
||||
data
|
||||
}, event) {
|
||||
async pay(data, event) {
|
||||
throw new Error('子类必须实现 pay 方法');
|
||||
}
|
||||
|
||||
|
|
|
|||
184
common/server/order.js
Normal file
184
common/server/order.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
import HttpRequest from "../system/request";
|
||||
|
||||
/**
|
||||
* 立即购买
|
||||
* @param {Number} product_id 商品id
|
||||
* @returns {Promise} 立即购买
|
||||
*/
|
||||
export const pay_by_order = async (product_id) => {
|
||||
const res = await HttpRequest.post('pay_by_order', {
|
||||
product_id: product_id
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: 'none'
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
* @param {Number} product_id 商品id
|
||||
* @param {Number} address_id 地址id
|
||||
* @param {Number} coupon_id 优惠券id
|
||||
* @returns {Promise} 创建订单
|
||||
*/
|
||||
export const pay_by_create_order = async (product_id, address_id, coupon_id) => {
|
||||
const res = await HttpRequest.post('pay_by_create_order', {
|
||||
product_id: product_id,
|
||||
address_id: address_id,
|
||||
coupon_id: coupon_id
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功
|
||||
* @param {String} order_no 订单号
|
||||
* @returns {Promise} 支付成功
|
||||
*/
|
||||
export const pay_by_pay = async (order_no) => {
|
||||
const res = await HttpRequest.post('order_pay_success', {
|
||||
order_no: order_no
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单列表
|
||||
* @param {Number} status 订单状态
|
||||
* @param {Number} page 页码
|
||||
* @param {Number} page_size 每页条数
|
||||
* @param {String} title 商品标题搜索关键词
|
||||
* @returns {Promise} 获取订单列表
|
||||
*/
|
||||
export const get_order_list = async (status, page, page_size, title = "") => {
|
||||
// 接收参数
|
||||
const res = await HttpRequest.post('get_order_list', {
|
||||
status: status,
|
||||
keyword: title,
|
||||
page: page,
|
||||
limit: page_size
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
/**
|
||||
* 订单收货
|
||||
* @param {String} order_no 订单号
|
||||
* @returns {Promise} 订单收货结果
|
||||
*/
|
||||
export const order_receive = async (order_no) => {
|
||||
const res = await HttpRequest.post('order_receive', {
|
||||
order_no: order_no
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请售后
|
||||
* @param {String} order_no 订单号
|
||||
* @param {String} extend_info 扩展信息
|
||||
* @returns {Promise} 申请售后结果
|
||||
*/
|
||||
export const apply_refund = async (order_no, extend_info = "") => {
|
||||
const res = await HttpRequest.post('apply_refund', {
|
||||
order_no: order_no,
|
||||
extend_info: extend_info
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消售后
|
||||
* @param {String} order_no 订单号
|
||||
* @returns {Promise} 取消售后结果
|
||||
*/
|
||||
export const cancel_refund = async (order_no) => {
|
||||
const res = await HttpRequest.post('cancel_refund', {
|
||||
order_no: order_no
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除订单
|
||||
* @param {String} order_no 订单号
|
||||
* @returns {Promise} 删除订单结果
|
||||
*/
|
||||
export const delete_order = async (order_no) => {
|
||||
const res = await HttpRequest.post('delete_order', {
|
||||
order_no: order_no
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
* @param {String} order_no 订单号
|
||||
* @returns {Promise} 获取订单详情
|
||||
*/
|
||||
export const get_order_detail = async (order_no) => {
|
||||
const res = await HttpRequest.post('get_order_detail', {
|
||||
order_no: order_no
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请发票
|
||||
* @param {String} order_no 订单号
|
||||
* @param {String} invoice_title 发票抬头
|
||||
* @param {String} invoice_content 发票内容
|
||||
* @param {Number} invoice_type 发票类型
|
||||
* @param {String} user_email 用户邮箱
|
||||
* @returns {Promise} 申请发票结果
|
||||
*/
|
||||
export const apply_invoice = async (order_no, invoice_title, invoice_content, invoice_type, user_email) => {
|
||||
const res = await HttpRequest.post('apply_invoice', {
|
||||
order_no: order_no,
|
||||
invoice_title: invoice_title,
|
||||
invoice_content: invoice_content,
|
||||
invoice_type: invoice_type,
|
||||
user_email: user_email
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单统计
|
||||
* @returns {Promise} 获取订单统计
|
||||
*/
|
||||
export const get_order_statistics = async () => {
|
||||
const res = await HttpRequest.post('get_order_statistics');
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ export const getAgreement = async (type) => {
|
|||
type_id = 4;
|
||||
} else if (type == "privacy") {
|
||||
type_id = 5;
|
||||
} else if (type == "product") {
|
||||
type_id = 32;
|
||||
}
|
||||
const res = await HttpRequest.get('/getAgreement', {
|
||||
type: type_id
|
||||
|
|
|
|||
|
|
@ -43,3 +43,72 @@ export const getProductDetail = async (id) => {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户收藏商品列表
|
||||
* @param {Number} page 页码
|
||||
* @param {Number} limit 每页条数
|
||||
* @returns {Promise} 收藏商品列表
|
||||
*/
|
||||
export const getFavoriteList = async (page = 1, limit = 10) => {
|
||||
const res = await HttpRequest.get('/get_favorite_list', {
|
||||
page: page,
|
||||
limit: limit
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品收藏
|
||||
* @param {Number} product_id 商品ID
|
||||
* @returns {Promise} 收藏结果
|
||||
*/
|
||||
export const addFavorite = async (product_id) => {
|
||||
const res = await HttpRequest.post('/add_favorite', {
|
||||
product_id: product_id
|
||||
});
|
||||
return res.status == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消商品收藏
|
||||
* @param {Number} product_id 商品ID
|
||||
* @returns {Promise} 取消收藏结果
|
||||
*/
|
||||
export const cancelFavorite = async (product_id) => {
|
||||
const res = await HttpRequest.post('/cancel_favorite', {
|
||||
product_id: product_id
|
||||
});
|
||||
return res.status == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量取消商品收藏
|
||||
* @param {Array} product_ids 商品ID数组
|
||||
* @returns {Promise} 批量取消收藏结果
|
||||
*/
|
||||
export const batchCancelFavorite = async (product_ids) => {
|
||||
const res = await HttpRequest.post('/batch_cancel_favorite', {
|
||||
product_ids: product_ids
|
||||
});
|
||||
return res.status == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查商品是否已收藏
|
||||
* @param {Number} product_id 商品ID
|
||||
* @returns {Promise} 是否已收藏
|
||||
*/
|
||||
export const checkIsFavorite = async (product_id) => {
|
||||
const res = await HttpRequest.get('/check_is_favorite', {
|
||||
product_id: product_id
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data.is_favorite;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
2
components.d.ts
vendored
2
components.d.ts
vendored
|
|
@ -14,9 +14,11 @@ declare module 'vue' {
|
|||
OrderListItem: typeof import('./components/youdas-container/order-list-item.vue')['default']
|
||||
PageBaseContainer: typeof import('./components/youdas-container/page-base-container.vue')['default']
|
||||
PageContainer: typeof import('./components/youdas-container/page-container.vue')['default']
|
||||
PageKefu: typeof import('./components/youdas-container/page-kefu.vue')['default']
|
||||
PageLine: typeof import('./components/youdas-container/page-line.vue')['default']
|
||||
PageNoContainer: typeof import('./components/youdas-container/page-no-container.vue')['default']
|
||||
PagePopup: typeof import('./components/youdas-container/page-popup.vue')['default']
|
||||
PaymentPopup: typeof import('./components/youdas-container/payment-popup.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
TextSearch: typeof import('./components/youdas-container/text-search.vue')['default']
|
||||
|
|
|
|||
|
|
@ -4,11 +4,55 @@
|
|||
<!-- :enable-back-to-top="currentIndex===tabIndex" 在微信小程序上可以多加这一句,因为默认是允许点击返回顶部的,但是这个页面有多个scroll-view,会全部返回顶部,所以需要控制是当前index才允许点击返回顶部 -->
|
||||
<!-- 如果当前页已经加载过数据或者当前切换到的tab是当前页,才展示当前页数据(懒加载) -->
|
||||
<z-paging v-if="firstLoaded || isCurrentPage" ref="paging" v-model="dataList" @query="queryList" :fixed="false">
|
||||
<!-- 搜索框 -->
|
||||
<text-search v-model="searchKeyword" placeholder="搜索订单" @search="onSearch" @clear="onClear" />
|
||||
|
||||
<!-- 如果希望其他view跟着页面滚动,可以放在z-paging标签内 -->
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="itemClick(item)">
|
||||
<view class="item-title">{{ item.title }}</view>
|
||||
<view class="item-detail">{{ item.detail }}</view>
|
||||
<view class="item-line"></view>
|
||||
<view class="order-item" v-for="(item, index) in dataList" :key="index" @click="itemClick(item)">
|
||||
<view class="order-header">
|
||||
<text class="order-no" @click.stop="copyOrderNo(item.order_no)">订单号:{{ item.order_no }}</text>
|
||||
<text class="order-status">{{ item.order_status_text }}</text>
|
||||
</view>
|
||||
<view class="order-content">
|
||||
<image class="product-cover" :src="item.product_cover" mode="aspectFill"></image>
|
||||
<view class="product-info">
|
||||
<text class="product-title">{{ item.product_title }}</text>
|
||||
<text class="payment-amount">¥{{ item.payment_amount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-footer">
|
||||
<text class="order-time">{{ item.payment_time }}</text>
|
||||
<view class="order-actions">
|
||||
<!-- 已发货状态 -->
|
||||
<template v-if="item.order_status === 2">
|
||||
<view class="btn default" @click.stop="applyAfterSale(item)">申请售后</view>
|
||||
<view class="btn primary" @click.stop="confirmReceive(item)">确认收货</view>
|
||||
</template>
|
||||
|
||||
<!-- 已收货状态 -->
|
||||
<template v-else-if="item.order_status === 3">
|
||||
<view class="btn default" v-if="item.is_invoice !== 1" @click.stop="applyInvoice(item)">申请发票
|
||||
</view>
|
||||
<view class="btn default" v-else>已申请发票</view>
|
||||
<view class="btn default"
|
||||
v-if="item.is_invoice !== 1 && isWithinSevenDays(item.receive_time)"
|
||||
@click.stop="applyAfterSale(item)">
|
||||
申请售后</view>
|
||||
<view class="btn default" @click.stop="deleteOrder(item)">删除订单</view>
|
||||
<view class="btn default" @click.stop="buyAgain(item)">再次购买</view>
|
||||
</template>
|
||||
|
||||
<!-- 已取消状态 -->
|
||||
<template v-else-if="item.order_status === 5">
|
||||
<view class="btn default" @click.stop="buyAgain(item)">再次购买</view>
|
||||
</template>
|
||||
|
||||
<!-- 申请售后状态 -->
|
||||
<template v-else-if="item.order_status === 6">
|
||||
<view class="btn default" @click.stop="cancelAfterSale(item)">取消售后</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template #empty>
|
||||
|
|
@ -18,12 +62,128 @@
|
|||
<loading-data />
|
||||
</template>
|
||||
</z-paging>
|
||||
|
||||
<!-- 申请发票弹窗 -->
|
||||
<view class="invoice-popup" v-if="showInvoicePopup">
|
||||
<view class="popup-mask" @click="closeInvoicePopup"></view>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">申请发票</text>
|
||||
<text class="popup-close" @click="closeInvoicePopup">×</text>
|
||||
</view>
|
||||
|
||||
<view class="product-info-box">
|
||||
<image class="product-popup-cover" :src="currentProduct.product_cover" mode="aspectFill"></image>
|
||||
<view class="product-popup-info">
|
||||
<text class="product-popup-title">{{ currentProduct.product_title }}</text>
|
||||
<text class="product-popup-price">¥{{ currentProduct.payment_amount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">发票类型</view>
|
||||
<view class="form-content radio-group">
|
||||
<view v-for="(type, index) in invoiceTypes" :key="index" class="radio-item"
|
||||
:class="{ active: invoiceForm.invoice_type === type.value }"
|
||||
@click="invoiceForm.invoice_type = type.value">
|
||||
<text>{{ type.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">发票抬头<text class="required">*</text></view>
|
||||
<view class="form-content">
|
||||
<input type="text" class="input" v-model="invoiceForm.invoice_title" placeholder="请输入发票抬头" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">发票内容<text class="required">*</text></view>
|
||||
<view class="form-content">
|
||||
<input type="text" class="input" v-model="invoiceForm.invoice_content" placeholder="请输入发票内容" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">申请邮箱<text class="required">*</text></view>
|
||||
<view class="form-content">
|
||||
<input type="text" class="input" v-model="invoiceForm.user_email" placeholder="请输入接收发票的邮箱" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-footer">
|
||||
<view class="btn default" @click="closeInvoicePopup">取消</view>
|
||||
<view class="btn primary" @click="submitInvoice">提交申请</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请售后弹窗 -->
|
||||
<view class="after-sale-popup" v-if="showAfterSalePopup">
|
||||
<view class="popup-mask" @click="closeAfterSalePopup"></view>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">申请售后</text>
|
||||
<text class="popup-close" @click="closeAfterSalePopup">×</text>
|
||||
</view>
|
||||
|
||||
<view class="product-info-box">
|
||||
<image class="product-popup-cover" :src="currentProduct.product_cover" mode="aspectFill"></image>
|
||||
<view class="product-popup-info">
|
||||
<text class="product-popup-title">{{ currentProduct.product_title }}</text>
|
||||
<text class="product-popup-price">¥{{ currentProduct.payment_amount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">售后类型</view>
|
||||
<view class="form-content radio-group">
|
||||
<view v-for="(type, index) in afterSaleTypes" :key="index" class="radio-item"
|
||||
:class="{ active: afterSaleForm.type === type.value }"
|
||||
@click="afterSaleForm.type = type.value">
|
||||
<text>{{ type.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">申请原因</view>
|
||||
<view class="form-content radio-group">
|
||||
<view v-for="(reason, index) in afterSaleReasons" :key="index" class="radio-item"
|
||||
:class="{ active: afterSaleForm.reason === reason }" @click="afterSaleForm.reason = reason">
|
||||
<text>{{ reason }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">申请说明<text class="required">*</text></view>
|
||||
<view class="form-content">
|
||||
<textarea class="input-textarea" v-model="afterSaleForm.remark" placeholder="请详细描述您的问题" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">联系电话</view>
|
||||
<view class="form-content">
|
||||
<input type="text" class="input" v-model="afterSaleForm.phone" placeholder="请输入联系电话" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-footer">
|
||||
<view class="btn default" @click="closeAfterSalePopup">取消</view>
|
||||
<view class="btn primary" @click="submitAfterSale">提交申请</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, nextTick, onMounted } from 'vue';
|
||||
|
||||
import { ref, watch, nextTick, onMounted, reactive } from 'vue';
|
||||
import { order_receive, apply_refund, cancel_refund, delete_order, apply_invoice } from '@/common/server/order';
|
||||
import TextSearch from '@/components/youdas-container/text-search.vue';
|
||||
// props定义
|
||||
const props = defineProps({
|
||||
// 当前组件的index,也就是当前组件是swiper中的第几个
|
||||
|
|
@ -41,7 +201,7 @@ const props = defineProps({
|
|||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
// tabIndex ['全部', '待发货', '待收货', '已收货', '售后']
|
||||
// 数据
|
||||
// v-model绑定的这个变量不要在分页请求结束中自己赋值!!!
|
||||
const dataList = ref([]);
|
||||
|
|
@ -51,6 +211,37 @@ const firstLoaded = ref(false);
|
|||
const isCurrentPage = ref(false);
|
||||
// ref引用
|
||||
const paging = ref(null);
|
||||
// 搜索关键词
|
||||
const searchKeyword = ref('');
|
||||
|
||||
// 售后弹窗数据
|
||||
const showAfterSalePopup = ref(false);
|
||||
const currentProduct = ref({});
|
||||
const afterSaleTypes = [
|
||||
{ label: '退货退款', value: 1 },
|
||||
{ label: '换货', value: 2 },
|
||||
{ label: '其它', value: 3 }
|
||||
];
|
||||
const afterSaleReasons = ['不想要了', '材质与商品不符', '质量问题', '发错货', '其他原因'];
|
||||
const afterSaleForm = reactive({
|
||||
type: 1,
|
||||
reason: '不想要了',
|
||||
remark: '',
|
||||
phone: ''
|
||||
});
|
||||
|
||||
// 发票弹窗数据
|
||||
const showInvoicePopup = ref(false);
|
||||
const invoiceTypes = [
|
||||
{ label: '个人', value: 1 },
|
||||
{ label: '企业', value: 2 }
|
||||
];
|
||||
const invoiceForm = reactive({
|
||||
invoice_type: 1,
|
||||
invoice_title: '',
|
||||
invoice_content: '',
|
||||
user_email: ''
|
||||
});
|
||||
|
||||
// 监听currentIndex变化
|
||||
watch(
|
||||
|
|
@ -85,12 +276,15 @@ const queryList = (pageNo, pageSize) => {
|
|||
const params = {
|
||||
pageNo: pageNo,
|
||||
pageSize: pageSize,
|
||||
type: props.tabIndex
|
||||
type: props.tabIndex,
|
||||
keyword: searchKeyword.value // 添加搜索关键词参数
|
||||
};
|
||||
|
||||
try {
|
||||
props.responseCallback(params).then(res => {
|
||||
if (paging.value) {
|
||||
console.log(res);
|
||||
|
||||
paging.value.complete(res.list || []);
|
||||
firstLoaded.value = true;
|
||||
}
|
||||
|
|
@ -108,9 +302,275 @@ const queryList = (pageNo, pageSize) => {
|
|||
}
|
||||
};
|
||||
|
||||
// 搜索处理函数
|
||||
const onSearch = (value) => {
|
||||
searchKeyword.value = value;
|
||||
// 刷新列表,重新搜索
|
||||
reload();
|
||||
};
|
||||
|
||||
// 清空搜索
|
||||
const onClear = () => {
|
||||
searchKeyword.value = '';
|
||||
// 刷新列表,显示所有数据
|
||||
reload();
|
||||
};
|
||||
|
||||
// 点击项目
|
||||
const itemClick = (item) => {
|
||||
console.log('点击了', item.title);
|
||||
yds.navigateTo("/pages/mall/order-detail?order_no=" + item.order_no);
|
||||
};
|
||||
const applyInvoice = async (item) => {
|
||||
currentProduct.value = item;
|
||||
|
||||
// 尝试从本地缓存获取上次的发票信息
|
||||
try {
|
||||
const cachedInvoiceData = uni.getStorageSync('lastInvoiceData');
|
||||
if (cachedInvoiceData) {
|
||||
// 使用缓存数据预填充表单
|
||||
invoiceForm.invoice_type = cachedInvoiceData.invoice_type || 1;
|
||||
invoiceForm.invoice_title = cachedInvoiceData.invoice_title || '';
|
||||
invoiceForm.invoice_content = cachedInvoiceData.invoice_content || '';
|
||||
invoiceForm.user_email = cachedInvoiceData.user_email || '';
|
||||
} else {
|
||||
// 无缓存数据时重置表单
|
||||
invoiceForm.invoice_type = 1;
|
||||
invoiceForm.invoice_title = '';
|
||||
invoiceForm.invoice_content = '';
|
||||
invoiceForm.user_email = '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取缓存发票数据失败', e);
|
||||
// 发生错误时重置表单
|
||||
invoiceForm.invoice_type = 1;
|
||||
invoiceForm.invoice_title = '';
|
||||
invoiceForm.invoice_content = '';
|
||||
invoiceForm.user_email = '';
|
||||
}
|
||||
|
||||
// 显示弹窗
|
||||
showInvoicePopup.value = true;
|
||||
};
|
||||
// 复制订单号
|
||||
const copyOrderNo = (orderNo) => {
|
||||
uni.setClipboardData({
|
||||
data: orderNo,
|
||||
success: function () {
|
||||
uni.showToast({
|
||||
title: '订单号已复制',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 通用确认弹窗方法
|
||||
const showConfirmDialog = (title, content) => {
|
||||
return new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title: title,
|
||||
content: content,
|
||||
confirmText: '取消',
|
||||
cancelText: '确定',
|
||||
success: function (res) {
|
||||
resolve(!res.confirm);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 通用API调用方法
|
||||
const callApiWithLoading = async (apiFunc, successMsg) => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '正在处理'
|
||||
});
|
||||
const res = await apiFunc();
|
||||
uni.hideLoading();
|
||||
|
||||
if (res) {
|
||||
uni.showToast({
|
||||
title: successMsg,
|
||||
icon: 'none'
|
||||
});
|
||||
// 刷新列表
|
||||
reload();
|
||||
return true;
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '操作失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '网络异常,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 确认收货
|
||||
const confirmReceive = async (item) => {
|
||||
const confirmed = await showConfirmDialog('确认提示', '您确定要确认收货吗?');
|
||||
if (confirmed) {
|
||||
await callApiWithLoading(() => order_receive(item.order_no), '确认收货成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 申请售后
|
||||
const applyAfterSale = (item) => {
|
||||
currentProduct.value = item;
|
||||
// 重置表单
|
||||
afterSaleForm.type = 1;
|
||||
afterSaleForm.reason = '不想要了';
|
||||
afterSaleForm.remark = '';
|
||||
afterSaleForm.phone = '';
|
||||
// 显示弹窗
|
||||
showAfterSalePopup.value = true;
|
||||
};
|
||||
|
||||
// 删除订单
|
||||
const deleteOrder = async (item) => {
|
||||
const confirmed = await showConfirmDialog('删除提示', '您确定要删除此订单吗?');
|
||||
if (confirmed) {
|
||||
await callApiWithLoading(() => delete_order(item.order_no), '删除成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 再次购买
|
||||
const buyAgain = (item) => {
|
||||
yds.navigateTo("/pages/mall/product-detail?id=" + item.product_id);
|
||||
};
|
||||
|
||||
// 判断是否在收货后7天内
|
||||
const isWithinSevenDays = (receiveTime) => {
|
||||
if (!receiveTime) return false;
|
||||
|
||||
const receiveDate = new Date(receiveTime);
|
||||
const currentDate = new Date();
|
||||
|
||||
// 计算日期差值(毫秒)
|
||||
const diffTime = currentDate - receiveDate;
|
||||
// 转换为天数
|
||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
// 如果天数差值小于等于7,返回true
|
||||
return diffDays <= 7;
|
||||
};
|
||||
|
||||
// 取消售后
|
||||
const cancelAfterSale = async (item) => {
|
||||
const confirmed = await showConfirmDialog('取消提示', '您确定要取消售后申请吗?');
|
||||
if (confirmed) {
|
||||
await callApiWithLoading(() => cancel_refund(item.order_no), '取消售后成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭售后弹窗
|
||||
const closeAfterSalePopup = () => {
|
||||
showAfterSalePopup.value = false;
|
||||
};
|
||||
|
||||
// 关闭发票弹窗
|
||||
const closeInvoicePopup = () => {
|
||||
showInvoicePopup.value = false;
|
||||
};
|
||||
|
||||
// 提交发票申请
|
||||
const submitInvoice = async () => {
|
||||
// 表单验证
|
||||
if (!invoiceForm.invoice_title) {
|
||||
uni.showToast({
|
||||
title: '请填写发票抬头',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!invoiceForm.invoice_content) {
|
||||
uni.showToast({
|
||||
title: '请填写发票内容',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!invoiceForm.user_email) {
|
||||
uni.showToast({
|
||||
title: '请填写申请邮箱',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证邮箱格式
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(invoiceForm.user_email)) {
|
||||
uni.showToast({
|
||||
title: '请输入正确的邮箱格式',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApiWithLoading(
|
||||
() => apply_invoice(
|
||||
currentProduct.value.order_no,
|
||||
invoiceForm.invoice_title,
|
||||
invoiceForm.invoice_content,
|
||||
invoiceForm.invoice_type,
|
||||
invoiceForm.user_email
|
||||
),
|
||||
'申请发票成功,发票抬头文件会在48小时内发送到您的邮箱。'
|
||||
);
|
||||
|
||||
// 如果申请成功,保存发票数据到本地存储
|
||||
if (result) {
|
||||
try {
|
||||
// 保存发票信息到本地缓存,下次使用
|
||||
uni.setStorageSync('lastInvoiceData', {
|
||||
invoice_type: invoiceForm.invoice_type,
|
||||
invoice_title: invoiceForm.invoice_title,
|
||||
invoice_content: invoiceForm.invoice_content,
|
||||
user_email: invoiceForm.user_email
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('保存发票数据到缓存失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
closeInvoicePopup();
|
||||
};
|
||||
|
||||
// 提交售后申请
|
||||
const submitAfterSale = async () => {
|
||||
// 表单验证
|
||||
if (!afterSaleForm.remark) {
|
||||
uni.showToast({
|
||||
title: '请填写申请说明',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 准备提交信息
|
||||
const extendInfo = JSON.stringify({
|
||||
type: afterSaleForm.type,
|
||||
reason: afterSaleForm.reason,
|
||||
remark: afterSaleForm.remark,
|
||||
phone: afterSaleForm.phone
|
||||
});
|
||||
|
||||
await callApiWithLoading(
|
||||
() => apply_refund(currentProduct.value.order_no, extendInfo),
|
||||
'申请售后成功,客服会在24小时内联系您处理。'
|
||||
);
|
||||
|
||||
// 关闭弹窗
|
||||
closeAfterSalePopup();
|
||||
};
|
||||
|
||||
// 暴露方法给父组件调用
|
||||
|
|
@ -119,35 +579,298 @@ defineExpose({
|
|||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="scss" scoped>
|
||||
/* 注意:父节点需要固定高度,z-paging的height:100%才会生效 */
|
||||
.content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.item {
|
||||
.order-item {
|
||||
background-color: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
margin: 20rpx 30rpx;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.order-no {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
position: relative;
|
||||
height: 150rpx;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -2rpx;
|
||||
width: 100%;
|
||||
height: 1rpx;
|
||||
background-color: #999999;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.order-status {
|
||||
font-size: 28rpx;
|
||||
color: #ff6700;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.order-content {
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.product-cover {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
flex: 1;
|
||||
padding-left: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
line-height: 40rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.payment-amount {
|
||||
font-size: 32rpx;
|
||||
color: #ff6700;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.order-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 15rpx;
|
||||
border-top: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.order-time {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.order-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
font-size: 24rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
margin-left: 16rpx;
|
||||
border-radius: 8rpx;
|
||||
text-align: center;
|
||||
transition: all 0.15s ease;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
&.default {
|
||||
background-color: #ffffff;
|
||||
color: #333333;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
background-color: #e94e42;
|
||||
color: #ffffff;
|
||||
border: 1px solid #e94e42;
|
||||
}
|
||||
}
|
||||
|
||||
/* 售后弹窗样式 */
|
||||
.after-sale-popup,
|
||||
.invoice-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0rpx 30rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.item-detail {
|
||||
padding: 5rpx 15rpx;
|
||||
border-radius: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: white;
|
||||
background-color: #007AFF;
|
||||
}
|
||||
|
||||
.item-line {
|
||||
.popup-mask {
|
||||
position: absolute;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
height: 1px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
position: relative;
|
||||
width: 92%;
|
||||
max-height: 90vh;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
font-size: 40rpx;
|
||||
color: #999;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
|
||||
.product-info-box {
|
||||
display: flex;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.product-popup-cover {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.product-popup-info {
|
||||
flex: 1;
|
||||
padding-left: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.product-popup-title {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
line-height: 36rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.product-popup-price {
|
||||
font-size: 28rpx;
|
||||
color: #ff6700;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.required {
|
||||
color: #ff4d4f;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.form-content {
|
||||
width: 100%;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -10rpx;
|
||||
}
|
||||
|
||||
.radio-item {
|
||||
margin: 10rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
|
||||
&.active {
|
||||
border-color: #ff6700;
|
||||
color: #ff6700;
|
||||
background-color: rgba(255, 103, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input-textarea {
|
||||
width: 100%;
|
||||
height: 180rpx;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 30rpx;
|
||||
|
||||
.btn {
|
||||
margin-left: 20rpx;
|
||||
min-width: 160rpx;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
88
components/youdas-container/page-kefu.vue
Normal file
88
components/youdas-container/page-kefu.vue
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<!-- 群聊弹窗 -->
|
||||
<view v-if="isShow" class="popup-mask" @click.stop>
|
||||
<view class="popup-content">
|
||||
<view class="pop-ball">
|
||||
<image show-menu-by-longpress
|
||||
src="https://image.zfunbox.cn/topic/20250418/0b40de65d2fc4801517569193bfd4cac.png" mode="aspectFit"
|
||||
style="width:80vw;height:468px;position:relative;top:-14%;left:0;">
|
||||
</image>
|
||||
</view>
|
||||
<view class="pop-ball-close" @click="close">
|
||||
<view style="width: 48rpx;height: 48rpx;border-radius: 50%;opacity: 0.5;">
|
||||
<image show-menu-by-longpress src="/static/ic_close.png" style="width: 48rpx;height: 48rpx;" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const isShow = ref(false);
|
||||
|
||||
const open = () => {
|
||||
isShow.value = true;
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
isShow.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
close
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
animation: popup-in 0.2s ease-out;
|
||||
}
|
||||
|
||||
@keyframes popup-in {
|
||||
from {
|
||||
transform: scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.pop-ball {
|
||||
width: 85vw;
|
||||
position: relative;
|
||||
border-radius: 25rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pop-ball-close {
|
||||
margin-top: 20rpx;
|
||||
width: 100%;
|
||||
height: 50rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
244
components/youdas-container/payment-popup.vue
Normal file
244
components/youdas-container/payment-popup.vue
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
<template>
|
||||
<uni-popup ref="popup" type="bottom">
|
||||
<view
|
||||
style="width: 100%; height: 965.65rpx; background-color: #F7F7F7; border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;">
|
||||
<view class="" style="width: 688.93rpx; height: 100%; margin: 0 auto;">
|
||||
<view class=""
|
||||
style="width: 100%; height: 30rpx; display: flex; flex-direction: row; align-items: center; justify-content: space-between; padding-top: 44rpx;">
|
||||
<view class="" style="width: 24.81rpx; height: 24.81rpx;"></view>
|
||||
<text style="font-size: 26.72rpx;">确认订单</text>
|
||||
<image src="/static/ic_close.png" style="width: 24.81rpx; height: 24.81rpx;" @click="close" mode="">
|
||||
</image>
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; height: 227.1rpx; background-color: white; position: relative; margin-top: 42rpx; border-radius: 15.27rpx;">
|
||||
<image :src="product.image"
|
||||
style="width: 180.12rpx; height: 180.12rpx; background-color: #D8D8D8; border-radius: 15.27rpx; position: absolute; left: 24.81rpx; top: 24.81rpx;"
|
||||
mode=""></image>
|
||||
<text style="font-size: 22.9rpx; position: absolute; left: 238.55rpx; top: 41.98rpx;">{{
|
||||
product.title }}</text>
|
||||
<text
|
||||
style="font-size: 19.08rpx; position: absolute; left: 238.55rpx; top: 91.6rpx; color: #999999;">类型:实物</text>
|
||||
<view class=""
|
||||
style="position: absolute; display: flex; flex-direction: row; left: 238.55rpx; bottom: 44rpx; align-items: center;">
|
||||
<text class=" " style="font-size: 19.08rpx; margin-top: 15rpx; color: #FF6A6A;">¥</text>
|
||||
<text class=" " style="font-size: 41.98rpx; font-weight: bold; color: #FF6A6A;">{{
|
||||
product.price }}</text>
|
||||
</view>
|
||||
<text
|
||||
style="position: absolute; right: 24.81rpx; bottom: 41.98rpx; font-size: 19.08rpx; color: #999999;">x1</text>
|
||||
</view>
|
||||
|
||||
<view class="" @click="toAddress"
|
||||
style="width: 100%; height: 82.06rpx; background-color: white; border-radius: 15.27rpx; margin-top: 28.63rpx; display: flex; align-items: center; position: relative;">
|
||||
<text style="left: 24.81rpx; font-size: 22.9rpx; position: absolute;">收货地址</text>
|
||||
<text style="font-size: 22.9rpx; position: absolute; right:50rpx;">{{ address.receiver_name || '未设置'
|
||||
}}</text>
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
</view>
|
||||
|
||||
<view class="" @click="toCoupon"
|
||||
style="width: 100%; height: 82.06rpx; background-color: white; border-radius: 15.27rpx; margin-top: 28.63rpx; display: flex; align-items: center; position: relative;">
|
||||
<text style="left: 24.81rpx; font-size: 22.9rpx; position: absolute;">优惠券</text>
|
||||
<text style="right: 45.8rpx; font-size: 19.08rpx; position: absolute; color: #999999;">未选择</text>
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
</view>
|
||||
|
||||
<view class="" @click="toAgreement('product')"
|
||||
style="width: 100%; height: 82.06rpx; background-color: #F9F8E1; border-radius: 15.27rpx; margin-top: 28.63rpx; display: flex; align-items: center; position: relative;">
|
||||
<text style="left: 24.81rpx; font-size: 22.9rpx; position: absolute;">售前·售后须知</text>
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; display: flex; flex-direction: row; align-items: center; justify-content: left; margin-top: 45.8rpx;">
|
||||
<image :src="isCheck ? '/static/ic_check_s.png' : '/static/ic_check.png'" @click="setCheck"
|
||||
style="width: 24.02rpx; height: 24.02rpx;" mode=""></image>
|
||||
<text style="font-size: 19.08rpx; color: #999999; margin-left: 11.45rpx;">我已满18岁,阅读并同意
|
||||
<text style="color: #333333;" @click="toAgreement('user')">《用户协议》</text>
|
||||
<text style="color: #333333;" @click="toAgreement('privacy')">《隐私政策》</text>
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="" @click="confirmPayment"
|
||||
style="width: 100%; height: 83.97rpx; background-color: #333333; border-radius: 15.27rpx; display: flex; align-items: center; justify-content: center; margin-top: 30.53rpx;">
|
||||
<text style="font-size: 22.9rpx; color: #CDEF27;">确认支付</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { pay_by_order, pay_by_create_order, pay_by_pay } from '@/common/server/order';
|
||||
import { platform } from '@/common/platform/PlatformFactory';
|
||||
const props = defineProps({
|
||||
onSuccess: {
|
||||
type: Function,
|
||||
default: () => { }
|
||||
}
|
||||
});
|
||||
let product = ref(null);
|
||||
|
||||
// const emit = defineEmits(['update:address']);
|
||||
|
||||
// 响应式数据
|
||||
const isCheck = ref(true);
|
||||
let address = ref('');
|
||||
let coupon = ref('');
|
||||
const popup = ref(null);
|
||||
const toAgreement = (type) => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/other/agreement?type=' + type,
|
||||
});
|
||||
};
|
||||
// 方法
|
||||
const open = async (product_id) => {
|
||||
const res = await pay_by_order(product_id);
|
||||
console.log(res);
|
||||
|
||||
if (res) {
|
||||
product.value = res;
|
||||
if (res.default_address != null) {
|
||||
address.value = res.default_address;
|
||||
}
|
||||
popup.value.open();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
|
||||
const setCheck = () => {
|
||||
isCheck.value = !isCheck.value;
|
||||
};
|
||||
|
||||
const toAddress = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/address/address-list?selsect=true',
|
||||
events: {
|
||||
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
|
||||
selectAddress: function (data) {
|
||||
console.log(data);
|
||||
address.value = data;
|
||||
|
||||
}
|
||||
},
|
||||
success: function (res) {
|
||||
// 通过eventChannel向被打开页面传送数据
|
||||
res.eventChannel.emit('acceptDataFromOpenerPage', {
|
||||
data: address.value.id
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
const toCoupon = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/other/choose-coupon',
|
||||
events: {
|
||||
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
|
||||
selectCoupon: function (data) {
|
||||
console.log(data);
|
||||
coupon.value = data;
|
||||
|
||||
}
|
||||
},
|
||||
success: function (res) {
|
||||
// 通过eventChannel向被打开页面传送数据
|
||||
res.eventChannel.emit('acceptDataFromOpenerPage', {
|
||||
data: coupon.value
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const confirmPayment = async () => {
|
||||
if (!isCheck.value) {
|
||||
uni.showToast({
|
||||
title: '请先同意用户协议和隐私政策',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (address.value == null || address.value.id == 0) {
|
||||
uni.showToast({
|
||||
title: '请选择收货地址',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 这里应该调用支付接口
|
||||
// 支付成功后调用回调
|
||||
uni.showLoading({
|
||||
title: '支付处理中'
|
||||
});
|
||||
|
||||
const order_res = await pay_by_create_order(product.value.product_id, address.value.id, coupon.value.id ?? 0);
|
||||
if (!order_res) {
|
||||
uni.showToast({
|
||||
title: '支付失败,请刷新后重试!',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log('支付成功', order_res);
|
||||
let isPaySuccess = true;
|
||||
if (order_res.user_info.is_test == 2) {
|
||||
const isTestPay = await uni.showModal({
|
||||
title: '支付提示',
|
||||
content: '检测到您是测试账号,是否直接支付完成!取消后将正常拉起支付!(测试账号购买订单将自动标记为“已发货”)',
|
||||
confirmText: "取消",
|
||||
cancelText: "确定"
|
||||
});
|
||||
if (isTestPay.cancel) {
|
||||
isPaySuccess = false;
|
||||
}
|
||||
}
|
||||
if (isPaySuccess) {
|
||||
let orderInfo = order_res.payment_data;
|
||||
|
||||
const payRes = await platform.pay(orderInfo, this);
|
||||
console.log("paypaypaypay", payRes);
|
||||
if (!payRes.isPay) {
|
||||
uni.showToast({
|
||||
title: '支付已取消',
|
||||
icon: 'none'
|
||||
});
|
||||
uni.hideLoading();
|
||||
return;
|
||||
}
|
||||
}
|
||||
const by_pay_res = await pay_by_pay(order_res.order_no);
|
||||
console.log("t", by_pay_res);
|
||||
uni.hideLoading();
|
||||
if (by_pay_res.pay_status == 2) {
|
||||
props.onSuccess && props.onSuccess();
|
||||
}
|
||||
// 模拟支付过程
|
||||
// setTimeout(() => {
|
||||
// uni.hideLoading();
|
||||
// props.onSuccess && props.onSuccess();
|
||||
// close();
|
||||
// }, 1500);
|
||||
};
|
||||
|
||||
// 对外暴露方法
|
||||
defineExpose({
|
||||
open,
|
||||
close
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.arrow-icon {
|
||||
width: 10.67rpx;
|
||||
height: 19.66rpx;
|
||||
right: 25rpx;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
23
pages.json
23
pages.json
|
|
@ -96,13 +96,32 @@
|
|||
},
|
||||
{
|
||||
"path": "pages/mall/receiving-address",
|
||||
"style" :
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/other/choose-coupon",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mall/order-detail",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/other/user-agreement",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
"usingComponents": {
|
||||
"web-view": "pages/other/user-agreement"
|
||||
},
|
||||
// "globalStyle": {
|
||||
// "navigationBarTextStyle": "black",
|
||||
// "navigationBarTitleText": "uni-app",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
<template>
|
||||
<PageContainer ref="pageContainer" title="我的地址管理" show-back :show-not-data="showNotData" :refresh="onRefresh">
|
||||
<PageContainer ref="pageContainer" :title="pageTitle" show-back :show-not-data="showNotData" :refresh="onRefresh">
|
||||
|
||||
<view class="address-list">
|
||||
|
||||
<view v-for="(item, index) in addressList" :key="index" class="address-item">
|
||||
<view class="address-content">
|
||||
<view v-if="chooseSelect" class="radio-box" @click.stop="selectAddress(item)">
|
||||
<view class="radio-circle" :class="{ 'checked': selectedAddressId === item.id }">
|
||||
<view v-if="selectedAddressId === item.id" class="radio-inner"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="address-content" @click.stop="selectAddress(item)">
|
||||
<view class="address-top">
|
||||
<text class="name">{{ item.receiver_name }}</text>
|
||||
<text class="phone">{{ item.receiver_phone }}</text>
|
||||
|
|
@ -12,32 +20,39 @@
|
|||
<text class="address-text">{{ item.detailed_address }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="edit-btn" @click="editAddress(item)">
|
||||
<view class="edit-btn" @click.stop="editAddress(item)">
|
||||
<image src="/static/app-plus/edit.png" mode="widthFix" style="width:32px;height: 32px;"></image>
|
||||
</view>
|
||||
<view class="delete-btn" @click="showDeleteConfirm(item)">
|
||||
<view class="delete-btn" @click.stop="showDeleteConfirm(item)">
|
||||
<image src="/static/app-plus/del.png" mode="widthFix" style="width: 32px;height: 32px;"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="addressList.length === 0" class="empty-tip">
|
||||
<text>暂无收货地址</text>
|
||||
<view v-if="chooseSelect" class="add-item" @click="addNewAddress">
|
||||
<view class="add-icon">+</view>
|
||||
<text class="add-text">新增地址</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="add-btn" @click="addNewAddress">
|
||||
<view v-if="!chooseSelect" class="add-btn" @click="addNewAddress">
|
||||
<text>新增地址</text>
|
||||
</view>
|
||||
<view v-if="chooseSelect" class="confirm-btn" @click="confirmAddress">
|
||||
<text>确定</text>
|
||||
</view>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, getCurrentInstance } from 'vue';
|
||||
import { getAddressList, deleteAddress } from '@/common/server/address';
|
||||
|
||||
const pageContainer = ref(null);
|
||||
const showNotData = ref(false);
|
||||
const addressList = ref([]);
|
||||
let pageTitle = ref('我的地址管理');
|
||||
let chooseSelect = ref(false);
|
||||
const selectedAddressId = ref(null);
|
||||
|
||||
// 刷新方法
|
||||
const onRefresh = async (paging) => {
|
||||
|
|
@ -47,11 +62,22 @@ const onRefresh = async (paging) => {
|
|||
onShow(() => {
|
||||
loadAddressList();
|
||||
});
|
||||
onLoad((options) => {
|
||||
if (options.selsect) {
|
||||
chooseSelect.value = true;
|
||||
pageTitle.value = '选择收货地址';
|
||||
}
|
||||
|
||||
});
|
||||
let eventChannel = null;
|
||||
onMounted(() => {
|
||||
const instance = getCurrentInstance().proxy
|
||||
eventChannel = instance.getOpenerEventChannel();
|
||||
eventChannel.on('acceptDataFromOpenerPage', (data) => {
|
||||
selectedAddressId.value = data.data;
|
||||
});
|
||||
});
|
||||
|
||||
// // 页面加载时获取地址列表
|
||||
// onMounted(() => {
|
||||
// loadAddressList();
|
||||
// });
|
||||
// 加载地址列表
|
||||
const loadAddressList = async () => {
|
||||
try {
|
||||
|
|
@ -59,6 +85,11 @@ const loadAddressList = async () => {
|
|||
if (res.status === 1 && res.data) {
|
||||
addressList.value = res.data;
|
||||
showNotData.value = addressList.value.length === 0;
|
||||
|
||||
// 如果是选择模式,默认选择第一个地址(如果有)或者选择指定ID的地址
|
||||
if (chooseSelect.value && addressList.value.length > 0 && selectedAddressId.value == null) {
|
||||
selectedAddressId.value = addressList.value[0].id;
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '获取地址列表失败',
|
||||
|
|
@ -74,6 +105,11 @@ const loadAddressList = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
// 选择地址
|
||||
const selectAddress = (item) => {
|
||||
selectedAddressId.value = item.id;
|
||||
};
|
||||
|
||||
// 编辑地址
|
||||
const editAddress = (item) => {
|
||||
uni.navigateTo({
|
||||
|
|
@ -88,6 +124,31 @@ const addNewAddress = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const confirmAddress = () => {
|
||||
if (!selectedAddressId.value) {
|
||||
uni.showToast({
|
||||
title: '请选择一个地址',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 通过ID查找完整的地址对象
|
||||
const selectedAddress = addressList.value.find(item => item.id === selectedAddressId.value);
|
||||
|
||||
if (!selectedAddress) {
|
||||
uni.showToast({
|
||||
title: '地址数据异常',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventChannel) {
|
||||
eventChannel.emit('selectAddress', selectedAddress);
|
||||
}
|
||||
uni.navigateBack();
|
||||
}
|
||||
// 显示删除确认对话框
|
||||
const showDeleteConfirm = (item) => {
|
||||
uni.showModal({
|
||||
|
|
@ -120,6 +181,11 @@ const deleteAddressItem = async (id) => {
|
|||
icon: 'success'
|
||||
});
|
||||
|
||||
// 如果删除的是当前选中地址,重置选中状态
|
||||
if (selectedAddressId.value === id) {
|
||||
selectedAddressId.value = null;
|
||||
}
|
||||
|
||||
// 重新加载地址列表
|
||||
loadAddressList();
|
||||
} else {
|
||||
|
|
@ -162,7 +228,33 @@ const deleteAddressItem = async (id) => {
|
|||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 100rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.radio-box {
|
||||
margin-right: 20rpx;
|
||||
padding: 5rpx;
|
||||
|
||||
.radio-circle {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #dddddd;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.checked {
|
||||
border-color: #1296db;
|
||||
}
|
||||
|
||||
.radio-inner {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #1296db;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address-content {
|
||||
|
|
@ -228,6 +320,43 @@ const deleteAddressItem = async (id) => {
|
|||
}
|
||||
}
|
||||
|
||||
.add-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 100rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 1rpx 5rpx rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #1296db;
|
||||
color: #fff;
|
||||
font-size: 40rpx;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 120rpx 0;
|
||||
|
|
@ -282,4 +411,34 @@ const deleteAddressItem = async (id) => {
|
|||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
position: fixed;
|
||||
bottom: 40rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 90%;
|
||||
height: 90rpx;
|
||||
background: linear-gradient(to right, #1296db, #0e80c0);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 45rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(18, 150, 219, 0.3);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: translateX(-50%) scale(0.98);
|
||||
box-shadow: 0 3rpx 8rpx rgba(18, 150, 219, 0.2);
|
||||
}
|
||||
|
||||
&::before {
|
||||
font-size: 40rpx;
|
||||
margin-right: 10rpx;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -27,7 +27,8 @@ onLoad(async () => {
|
|||
return;
|
||||
}
|
||||
|
||||
navigateTo('/pages/news/news');
|
||||
// navigateTo('/pages/news/news');
|
||||
navigateTo('/pages/other/user-agreement?type=user');
|
||||
|
||||
});
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,18 +1,182 @@
|
|||
<template>
|
||||
<PageContainer ref="pageContainer" title="收藏管理" show-back :show-not-data="showNotData" :refresh="onRefresh">
|
||||
|
||||
<view class="collect-container">
|
||||
<view v-if="favoriteList.length > 0" class="favorite-list">
|
||||
<view v-for="item in favoriteList" :key="item.id" class="favorite-item">
|
||||
<image class="product-image" :src="item.image" mode="aspectFill" />
|
||||
<view class="product-info">
|
||||
<view class="product-title">{{ item.title }}</view>
|
||||
<view class="product-price">¥{{ item.price }}</view>
|
||||
<view class="product-meta">
|
||||
<text>库存: {{ item.stock }}</text>
|
||||
</view>
|
||||
<view class="favorite-time">收藏于: {{ formatDate(item.favorite_time) }}</view>
|
||||
</view>
|
||||
<view class="product-actions">
|
||||
<view class="btn view-btn" @click="viewDetail(item)">查看</view>
|
||||
<view class="btn cancel-btn" @click="handleCancelFavorite(item)">取消收藏</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import { getFavoriteList, cancelFavorite } from '@/common/server/product';
|
||||
let pageContainer = ref(null);
|
||||
let showNotData = ref(false);
|
||||
let favoriteList = ref([]);
|
||||
let isLoading = ref(false);
|
||||
|
||||
onLoad(async () => {
|
||||
await loadFavoriteData();
|
||||
})
|
||||
|
||||
// 加载收藏数据
|
||||
const loadFavoriteData = async () => {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const result = await getFavoriteList();
|
||||
favoriteList.value = result || [];
|
||||
showNotData.value = favoriteList.value.length === 0;
|
||||
} catch (error) {
|
||||
console.error('获取收藏列表失败', error);
|
||||
showNotData.value = true;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 查看商品详情
|
||||
const viewDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/product-detail?id=${item.id}`
|
||||
});
|
||||
};
|
||||
|
||||
// 取消收藏
|
||||
const handleCancelFavorite = async (item) => {
|
||||
try {
|
||||
// 调用取消收藏API
|
||||
await cancelFavorite(item.id);
|
||||
|
||||
// 从列表中移除
|
||||
favoriteList.value = favoriteList.value.filter(i => i.id !== item.id);
|
||||
showNotData.value = favoriteList.value.length === 0;
|
||||
uni.showToast({
|
||||
title: '取消收藏成功',
|
||||
icon: 'success'
|
||||
});
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '操作失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr) => {
|
||||
return dateStr ? dateStr.substring(0, 10) : '';
|
||||
};
|
||||
|
||||
// 刷新方法
|
||||
const onRefresh = async (paging) => {
|
||||
await loadFavoriteData();
|
||||
await yds.sleep(500);
|
||||
paging.complete();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.collect-container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.favorite-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.favorite-item {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.product-price {
|
||||
font-size: 32rpx;
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.product-meta {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.favorite-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.product-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 120rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
text-align: center;
|
||||
border-radius: 30rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.view-btn {
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #ff6b00;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
<!-- 搜索 -->
|
||||
<text-search v-model="searchKeyword" placeholder="搜索商品" @search="handleSearch" @clear="clearSearch" />
|
||||
<!-- 顶部三个商品 -->
|
||||
<swiper v-if="!isSearch" :display-multiple-items="3" class="top" :duration="500">
|
||||
<swiper v-if="!isSearch && topDataList.length > 0" :display-multiple-items="3" class="top" :duration="500">
|
||||
<swiper-item v-for="(item, i) in topDataList" :key="i" @click="goToDetail(item)">
|
||||
<view class="item">
|
||||
<view class="img">
|
||||
|
|
|
|||
323
pages/mall/order-detail.vue
Normal file
323
pages/mall/order-detail.vue
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
<template>
|
||||
<PageContainer ref="pageContainer" title="订单详情" show-back :show-not-data="showNotData" :refresh="onRefresh">
|
||||
<template v-if="orderDetail">
|
||||
<!-- 订单状态 -->
|
||||
<view class="status-card" :class="orderStatusClass">
|
||||
<view class="status-text">{{ orderDetail.order_status_text }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">商品信息</view>
|
||||
<view class="product-item" @click.stop="toProductDetail(orderDetail.product_id)">
|
||||
<image class="product-image" :src="orderDetail.product_cover" mode="aspectFill"></image>
|
||||
<view class="product-info">
|
||||
<view class="product-title">{{ orderDetail.product_title }}</view>
|
||||
<view class="product-price">¥{{ orderDetail.product_price }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">订单信息</view>
|
||||
<view class="info-item">
|
||||
<text class="label">订单编号</text>
|
||||
<text class="value">{{ orderDetail.order_no }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">创建时间</text>
|
||||
<text class="value">{{ orderDetail.create_time }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">支付方式</text>
|
||||
<text class="value">{{ orderDetail.payment_type === 1 ? '微信支付' : '其他' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">支付时间</text>
|
||||
<text class="value">{{ orderDetail.payment_time || '未支付' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 配送信息 -->
|
||||
<view class="info-card" v-if="orderDetail.order_status >= 2">
|
||||
<view class="card-title">配送信息</view>
|
||||
<view class="info-item">
|
||||
<text class="label">快递公司</text>
|
||||
<text class="value">{{ orderDetail.shipping_company }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">快递单号</text>
|
||||
<text class="value">{{ orderDetail.shipping_no }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">发货时间</text>
|
||||
<text class="value">{{ orderDetail.shipping_time || '未发货' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">收货时间</text>
|
||||
<text class="value">{{ orderDetail.receive_time || '未收货' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 收货人信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">收货人信息</view>
|
||||
<view class="info-item">
|
||||
<text class="label">收货人</text>
|
||||
<text class="value">{{ orderDetail.receiver_name }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">联系电话</text>
|
||||
<text class="value">{{ orderDetail.receiver_phone }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">收货地址</text>
|
||||
<text class="value">{{ orderDetail.receiver_address }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 发票信息 -->
|
||||
<view class="info-card" v-if="orderDetail.invoice_title || orderDetail.invoice_content">
|
||||
<view class="card-title">发票信息</view>
|
||||
<view class="info-item" v-if="orderDetail.invoice_title">
|
||||
<text class="label">发票抬头</text>
|
||||
<text class="value">{{ orderDetail.invoice_title }}</text>
|
||||
</view>
|
||||
<view class="info-item" v-if="orderDetail.invoice_content">
|
||||
<text class="label">发票内容</text>
|
||||
<text class="value">{{ orderDetail.invoice_content }}</text>
|
||||
</view>
|
||||
<view class="info-item" v-if="orderDetail.invoice_type_text">
|
||||
<text class="label">发票类型</text>
|
||||
<text class="value">{{ orderDetail.invoice_type_text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 金额信息 -->
|
||||
<view class="price-card">
|
||||
<view class="price-item">
|
||||
<text>商品金额</text>
|
||||
<text>¥{{ orderDetail.product_price }}</text>
|
||||
</view>
|
||||
<view class="price-item">
|
||||
<text>运费</text>
|
||||
<text>¥{{ orderDetail.shipping_fee }}</text>
|
||||
</view>
|
||||
<view class="price-item" v-if="Number(orderDetail.discount_amount) > 0">
|
||||
<text>优惠金额</text>
|
||||
<text>-¥{{ orderDetail.discount_amount }}</text>
|
||||
</view>
|
||||
<view class="price-item total">
|
||||
<text>实付款</text>
|
||||
<text class="total-price">¥{{ orderDetail.payment_amount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { get_order_detail } from '@/common/server/order';
|
||||
import { computed } from 'vue';
|
||||
|
||||
let pageContainer = ref(null);
|
||||
let showNotData = ref(false);
|
||||
let order_no = ref(null);
|
||||
let orderDetail = ref(null);
|
||||
|
||||
onLoad((options) => {
|
||||
console.log(options);
|
||||
if (options.order_no) {
|
||||
order_no.value = options.order_no;
|
||||
queryOrderDetail();
|
||||
}
|
||||
});
|
||||
const toProductDetail = (product_id) => {
|
||||
yds.navigateTo("/pages/mall/product-detail?id=" + product_id);
|
||||
};
|
||||
const queryOrderDetail = async () => {
|
||||
const res = await get_order_detail(order_no.value);
|
||||
console.log(res);
|
||||
if (res) {
|
||||
orderDetail.value = res;
|
||||
} else {
|
||||
showNotData.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 根据订单状态计算对应的样式类名
|
||||
const orderStatusClass = computed(() => {
|
||||
if (!orderDetail.value) return '';
|
||||
|
||||
const status = orderDetail.value.order_status;
|
||||
// 根据订单状态返回不同的类名
|
||||
switch (status) {
|
||||
case 0: // 待付款/未支付
|
||||
return 'status-unpaid';
|
||||
case 1: // 待发货/已支付
|
||||
return 'status-paid';
|
||||
case 2: // 待收货/已发货
|
||||
return 'status-shipped';
|
||||
case 3: // 已完成
|
||||
return 'status-completed';
|
||||
case 4: // 已取消
|
||||
return 'status-cancelled';
|
||||
case 5: // 已退款
|
||||
case 6:
|
||||
case 7:
|
||||
return 'status-refunded';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
// 刷新方法
|
||||
const onRefresh = async (paging) => {
|
||||
await yds.sleep(500);
|
||||
await queryOrderDetail();
|
||||
paging.complete();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.status-card {
|
||||
padding: 40rpx 30rpx;
|
||||
|
||||
.status-text {
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
// 默认颜色,蓝色
|
||||
background-color: #4080ff;
|
||||
|
||||
// 待付款/未支付,橙色
|
||||
&.status-unpaid {
|
||||
background-color: #ff9500;
|
||||
}
|
||||
|
||||
// 待发货/已支付,蓝色
|
||||
&.status-paid {
|
||||
background-color: #4080ff;
|
||||
}
|
||||
|
||||
// 待收货/已发货,绿色
|
||||
&.status-shipped {
|
||||
background-color: #10b981;
|
||||
}
|
||||
|
||||
// 已完成,亮绿色
|
||||
&.status-completed {
|
||||
background-color: #52c41a;
|
||||
}
|
||||
|
||||
// 已取消,灰色
|
||||
&.status-cancelled {
|
||||
background-color: #909399;
|
||||
}
|
||||
|
||||
// 已退款,红色
|
||||
&.status-refunded {
|
||||
background-color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
.info-card {
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
|
||||
.card-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
padding-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
font-size: 26rpx;
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
max-width: 65%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.product-item {
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.product-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 8rpx;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
flex: 1;
|
||||
margin-left: 20rpx;
|
||||
|
||||
.product-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 10rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-price {
|
||||
font-size: 30rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.price-card {
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
|
||||
.price-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
|
||||
&.total {
|
||||
margin-top: 10rpx;
|
||||
padding-top: 15rpx;
|
||||
border-top: 1rpx solid #f5f5f5;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
|
||||
.total-price {
|
||||
color: #ff4d4f;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -24,11 +24,12 @@
|
|||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { get_order_list } from '@/common/server/order';
|
||||
const paging = ref(null);
|
||||
const tabs = ref(null);
|
||||
|
||||
const current = ref(0);
|
||||
const tabList = ref(['全部', '待发货', '待收货', '评价', '售后']);
|
||||
const tabList = ref(['全部', '待发货', '待收货', '已收货', '售后']);
|
||||
|
||||
onLoad((options) => {
|
||||
console.log(options);
|
||||
|
|
@ -52,8 +53,10 @@ const swiperAnimationfinish = (e) => {
|
|||
tabs.value.unlockDx();
|
||||
}
|
||||
const responseCallback = (params) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({ list: [] });
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let title = params.keyword ?? "";
|
||||
const res = await get_order_list(params.type, params.pageNo, params.pageSize, title);
|
||||
resolve({ list: res.list || [] });
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
@ -63,6 +66,5 @@ const responseCallback = (params) => {
|
|||
height: 90vh;
|
||||
}
|
||||
|
||||
.swiper-item {
|
||||
}
|
||||
.swiper-item {}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -5,12 +5,16 @@
|
|||
<image src="/static/ic_back.png" @click="toBack()"
|
||||
style="width: 41.98rpx; height: 41.98rpx; position: fixed; left: 30rpx; top: 137rpx;z-index: 1000;" mode="">
|
||||
</image>
|
||||
<image :src="favorite_src" @click.stop="favoriteAction()"
|
||||
style="width:64rpx; height: 64rpx;position: fixed;top: 137rpx;right: 30rpx;z-index: 1000;"></image>
|
||||
|
||||
<swiper v-if="productDetail" :duration="500" circular :autoplay="true" :interval="3000"
|
||||
style="width: 100%; height: 715.65rpx; background-color: #D8D8D8;">
|
||||
<swiper-item v-for="(item, i) in productDetail.detail_image" :key="i">
|
||||
<image :src="item" style="width: 100%; height: 100%;"></image>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
<view v-if="productDetail" class=""
|
||||
style="width: 100%; height: 244.27rpx; background-color: white; position: relative;">
|
||||
|
||||
|
|
@ -39,6 +43,8 @@
|
|||
<rich-text :nodes="productDetail.detail_html"></rich-text>
|
||||
</view>
|
||||
|
||||
<view class="" style="width: 100%; height:400rpx; background-color: white;"></view>
|
||||
|
||||
<view class="" style="width: 100%; height: 188.94rpx; position: fixed; bottom: 0; background-color: white;">
|
||||
|
||||
<view class="" @click="bayOpen"
|
||||
|
|
@ -47,135 +53,63 @@
|
|||
</view>
|
||||
|
||||
</view>
|
||||
<uni-popup ref="bayPop" type="bottom">
|
||||
|
||||
<view
|
||||
style="width: 100%; height: 965.65rpx; background-color: #F7F7F7; border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;">
|
||||
|
||||
<view class="" style="width: 688.93rpx; height: 100%; margin: 0 auto;">
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; height: 30rpx; display: flex; flex-direction: row; align-items: center; justify-content: space-between; padding-top: 44rpx;">
|
||||
<view class="" style="width: 24.81rpx; height: 24.81rpx;"></view>
|
||||
<text style="font-size: 26.72rpx;">确认订单</text>
|
||||
<image src="/static/ic_close.png" style="width: 24.81rpx; height: 24.81rpx;" @click="closePop"
|
||||
mode="">
|
||||
</image>
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; height: 227.1rpx; background-color: white; position: relative; margin-top: 42rpx; border-radius: 15.27rpx;">
|
||||
|
||||
<image :src="productDetail.image"
|
||||
style="width: 180.12rpx; height: 180.12rpx; background-color: #D8D8D8; border-radius: 15.27rpx; position: absolute; left: 24.81rpx; top: 24.81rpx;"
|
||||
mode=""></image>
|
||||
|
||||
<text
|
||||
style="font-size: 22.9rpx; position: absolute; left: 238.55rpx; top: 41.98rpx;">{{ productDetail.title }}</text>
|
||||
|
||||
<text
|
||||
style="font-size: 19.08rpx; position: absolute; left: 238.55rpx; top: 91.6rpx; color: #999999;">类型:明信片</text>
|
||||
|
||||
<view class=""
|
||||
style="position: absolute; display: flex; flex-direction: row; left: 238.55rpx; bottom: 44rpx; align-items: center;">
|
||||
<text class=" " style="font-size: 19.08rpx; margin-top: 15rpx; color: #FF6A6A;">¥</text>
|
||||
<text class=" "
|
||||
style="font-size: 41.98rpx; font-weight: bold; color: #FF6A6A;">{{ productDetail.price }}</text>
|
||||
</view>
|
||||
|
||||
<text
|
||||
style="position: absolute; right: 24.81rpx; bottom: 41.98rpx; font-size: 19.08rpx; color: #999999;">x1</text>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="" @click="toAddress"
|
||||
style="width: 100%; height: 82.06rpx; background-color: white; border-radius: 15.27rpx; margin-top: 28.63rpx; display: flex; align-items: center; position: relative;">
|
||||
|
||||
<text style="left: 24.81rpx; font-size: 22.9rpx; position: absolute;">地址管理</text>
|
||||
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; height: 82.06rpx; background-color: white; border-radius: 15.27rpx; margin-top: 28.63rpx; display: flex; align-items: center; position: relative;">
|
||||
|
||||
<text style="left: 24.81rpx; font-size: 22.9rpx; position: absolute;">优惠券</text>
|
||||
|
||||
<text
|
||||
style="right: 45.8rpx; font-size: 19.08rpx; position: absolute; color: #999999;">未选择</text>
|
||||
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; height: 82.06rpx; background-color: #F9F8E1; border-radius: 15.27rpx; margin-top: 28.63rpx; display: flex; align-items: center; position: relative;">
|
||||
|
||||
<text style="left: 24.81rpx; font-size: 22.9rpx; position: absolute;">售前·售后须知</text>
|
||||
|
||||
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; display: flex; flex-direction: row; align-items: center; justify-content: left; margin-top: 45.8rpx;">
|
||||
|
||||
<image :src="isCheck ? '/static/ic_check_s.png' : '/static/ic_check.png'" @click="setCheck"
|
||||
style="width: 24.02rpx; height: 24.02rpx;" mode=""></image>
|
||||
|
||||
<text
|
||||
style="font-size: 19.08rpx; color: #999999; margin-left: 11.45rpx;">我已满18岁,阅读并同意
|
||||
<text style="color: #333333;">《用户协议》</text>
|
||||
<text style="color: #333333;">《隐私政策》</text>
|
||||
</text>
|
||||
|
||||
</view>
|
||||
|
||||
<view class=""
|
||||
style="width: 100%; height: 83.97rpx; background-color: #333333; border-radius: 15.27rpx; display: flex; align-items: center; justify-content: center; margin-top: 30.53rpx;">
|
||||
<text style="font-size: 22.9rpx; color: #CDEF27;">确认支付</text>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</uni-popup>
|
||||
<!-- 使用支付弹窗组件 -->
|
||||
<payment-popup ref="paymentPopup_ref" :onSuccess="onPaymentSuccess" />
|
||||
</z-paging>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { getProductDetail } from '@/common/server/product';
|
||||
import { getProductDetail, addFavorite, cancelFavorite } from '@/common/server/product';
|
||||
import { pay_by_order } from '@/common/server/order';
|
||||
import paymentPopup from '@/components/youdas-container/payment-popup.vue';
|
||||
let is_favorite = ref(false);
|
||||
let productDetail = ref(null);
|
||||
let paging = ref(null);
|
||||
let productId = null;
|
||||
let paymentPopup_ref = ref(null);
|
||||
let favorite_src = computed(() => {
|
||||
return is_favorite.value ? "/static/app-plus/user/sc1.png" : "/static/app-plus/user/sc2.png";
|
||||
})
|
||||
onLoad(async (options) => {
|
||||
const id = options.id;
|
||||
productId = id;
|
||||
queryProductDetail();
|
||||
});
|
||||
|
||||
const onRefresh = () => {
|
||||
console.log("onRefresh");
|
||||
queryProductDetail().then(() => {
|
||||
paging.value.complete();
|
||||
});
|
||||
};
|
||||
const favoriteAction = async () => {
|
||||
if (!yds.userInfo.isAccountLogin()) {
|
||||
yds.showToast("未登录,请先登录");
|
||||
return;
|
||||
}
|
||||
if (is_favorite.value) {
|
||||
await cancelFavorite(productId);
|
||||
yds.showToast("取消收藏成功");
|
||||
is_favorite.value = false;
|
||||
|
||||
} else {
|
||||
await addFavorite(productId);
|
||||
yds.showToast("收藏成功");
|
||||
is_favorite.value = true;
|
||||
}
|
||||
};
|
||||
const queryProductDetail = async () => {
|
||||
const res = await getProductDetail(productId);
|
||||
if (res) {
|
||||
productDetail.value = res;
|
||||
console.log(productDetail.value);
|
||||
if (res.is_favorite != null) {
|
||||
is_favorite.value = res.is_favorite;
|
||||
}
|
||||
}
|
||||
};
|
||||
// 响应式数据
|
||||
const detailList = ref([1, 2, 3, 4, 5]);
|
||||
const isCheck = ref(true);
|
||||
const bayPop = ref(null);
|
||||
|
||||
// 方法
|
||||
const toBack = () => {
|
||||
|
|
@ -184,21 +118,17 @@ const toBack = () => {
|
|||
};
|
||||
|
||||
const bayOpen = () => {
|
||||
bayPop.value.open();
|
||||
paymentPopup_ref.value.open(productId);
|
||||
};
|
||||
|
||||
const closePop = () => {
|
||||
bayPop.value.close();
|
||||
};
|
||||
|
||||
const setCheck = () => {
|
||||
isCheck.value = !isCheck.value;
|
||||
};
|
||||
|
||||
const toAddress = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/receiving-address'
|
||||
const onPaymentSuccess = () => {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success'
|
||||
});
|
||||
paymentPopup_ref.value.close();
|
||||
queryProductDetail();
|
||||
// 可以在这里添加支付成功后的处理逻辑,比如跳转到订单页面等
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -255,7 +185,7 @@ const toAddress = () => {
|
|||
//设置图片样式
|
||||
::v-deep rich-text img {
|
||||
max-width: 95% !important;
|
||||
border-radius: 10rpx;
|
||||
// border-radius: 10rpx;
|
||||
height: auto !important;
|
||||
display: block !important;
|
||||
margin: 0 auto;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
<text style="font-size: 22.9rpx; margin-left: 30.53rpx;">{{ item.phoneNum }}</text>
|
||||
</view>
|
||||
|
||||
<text
|
||||
style="font-size: 20.99rpx; color: #575757; position: absolute; left: 32.44rpx; top: 91.6rpx;">{{item.address}}</text>
|
||||
<text style="font-size: 20.99rpx; color: #575757; position: absolute; left: 32.44rpx; top: 91.6rpx;">{{
|
||||
item.address }}</text>
|
||||
|
||||
|
||||
<view class=""
|
||||
|
|
@ -50,13 +50,16 @@
|
|||
|
||||
</scroll-view>
|
||||
|
||||
<view class="" style="width: 100%; height: 188.94rpx; background-color: white;">
|
||||
<view class="" style="width: 100%; height: 120rpx; background-color: white; display: flex; flex-direction: row; align-items: center; justify-content: space-around; padding: 0 30rpx;">
|
||||
|
||||
<view class=""
|
||||
style="width: 688.93rpx; height: 83.97rpx; background-color: #333333; border-radius: 15.27rpx; margin: 20.99rpx auto; display: flex; align-items: center; justify-content: center;">
|
||||
<text style="color: #CDEF27; font-size: 22.9rpx;">新增收货地址</text>
|
||||
style="width: 30%; height: 83.97rpx; background-color: #333333; border-radius: 15.27rpx; display: flex; align-items: center; justify-content: center;">
|
||||
<text style="color: #CDEF27; font-size: 22.9rpx;">新增地址</text>
|
||||
</view>
|
||||
<view class=""
|
||||
style="width: 40%; height: 83.97rpx; background-color: #333333; border-radius: 15.27rpx; display: flex; align-items: center; justify-content: center;">
|
||||
<text style="color: #CDEF27; font-size: 22.9rpx;">确定收货地址</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
|
@ -66,6 +69,7 @@
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
eventChannel: null,
|
||||
addressList: [{
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
|
|
@ -97,6 +101,10 @@
|
|||
},],
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.eventChannel = this.getOpenerEventChannel();
|
||||
|
||||
},
|
||||
methods: {
|
||||
toBack() {
|
||||
console.log("777777");
|
||||
|
|
|
|||
200
pages/me/me.vue
200
pages/me/me.vue
|
|
@ -6,37 +6,49 @@
|
|||
|
||||
<view class="main-container">
|
||||
<!-- 用户信息区域 -->
|
||||
<view class="user-info-section" v-if="userInfo" @click="navigateTo('/pages/me/account-info');">
|
||||
<view class="user-info-section login-section" v-if="userInfo"
|
||||
@click="navigateTo('/pages/me/account-info');">
|
||||
<view class="avatar">
|
||||
<image :src="userInfo.userIcon" mode="aspectFill"
|
||||
style="width: 80.15rpx;height: 80.15rpx;border-radius: 10rpx;"></image>
|
||||
</view>
|
||||
<view class="login-content">
|
||||
<view class="user-id">{{ userInfo.username }}</view>
|
||||
<view class="user-days">已陪你走过了{{ userInfo.days }}天</view>
|
||||
</view>
|
||||
<view class="user-info-section" v-else @click="navigateToAccountLogin();">
|
||||
<view class="avatar">
|
||||
<view class="login-arrow">
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="user-info-section login-section" v-else @click="navigateToAccountLogin();">
|
||||
<view class="avatar">
|
||||
<view class="default-avatar"></view>
|
||||
</view>
|
||||
<view class="login-content">
|
||||
<view class="user-id login-text">点击登录</view>
|
||||
<view class="user-days login-tip">登录后体验更多功能</view>
|
||||
</view>
|
||||
<view class="login-arrow">
|
||||
<image src="/static/ic_arrow.png" class="arrow-icon"></image>
|
||||
</view>
|
||||
<view class="user-id">点击登录</view>
|
||||
<view class="user-days"></view>
|
||||
</view>
|
||||
<!-- 订单状态区域 -->
|
||||
<view class="order-status-section">
|
||||
<view class="status-item" @click="navigateTo('/pages/mall/order-list?type=1');">
|
||||
<text class="status-count">0</text>
|
||||
<view class="status-item" @click="order_goto(1);">
|
||||
<text class="status-count">{{ orderStatistics.waiting_ship_count }}</text>
|
||||
<text class="status-label">待发货</text>
|
||||
</view>
|
||||
<view class="status-item" @click="navigateTo('/pages/mall/order-list?type=2');">
|
||||
<text class="status-count">0</text>
|
||||
<view class="status-item" @click="order_goto(2);">
|
||||
<text class="status-count">{{ orderStatistics.waiting_receive_count }}</text>
|
||||
<text class="status-label">待收货</text>
|
||||
</view>
|
||||
<view class="status-item" @click="navigateTo('/pages/mall/order-list?type=3');">
|
||||
<text class="status-count">0</text>
|
||||
<text class="status-label">待评价</text>
|
||||
<view class="status-item" @click="order_goto(3);">
|
||||
<text class="status-count">{{ orderStatistics.received_count }}</text>
|
||||
<text class="status-label">已收货</text>
|
||||
</view>
|
||||
<view class="status-item" @click="navigateTo('/pages/mall/order-list?type=4');">
|
||||
<text class="status-count">0</text>
|
||||
<text class="status-label">退款售后</text>
|
||||
<view class="status-item" @click="order_goto(4);">
|
||||
<text class="status-count">{{ orderStatistics.after_sales_count }}</text>
|
||||
<text class="status-label">申请售后</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
|
@ -50,18 +62,26 @@
|
|||
</view>
|
||||
</view>
|
||||
<page-popup ref="_pagePopup" />
|
||||
<page-kefu ref="page_kefu_show" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getUserInfo } from '@/common/server/user';
|
||||
import { get_order_statistics } from '@/common/server/order';
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { navigateTo, navigateToAccountLogin } from '@/common/system/router';
|
||||
let _pagePopup = ref(null);
|
||||
const itemList = ref([
|
||||
|
||||
]);
|
||||
|
||||
let orderStatistics = reactive({
|
||||
"waiting_ship_count": 0,
|
||||
"waiting_receive_count": 0,
|
||||
"received_count": 0,
|
||||
"after_sales_count": 0
|
||||
});
|
||||
let page_kefu_show = ref(null);
|
||||
let userInfo = ref(null);
|
||||
|
||||
onShow(async () => {
|
||||
|
|
@ -70,32 +90,68 @@ onShow(async () => {
|
|||
console.log("res", res);
|
||||
userInfo.value = res;
|
||||
loadMenu();
|
||||
await loadOrderStatistics();
|
||||
yds.hideLoading();
|
||||
|
||||
});
|
||||
const order_goto = (type) => {
|
||||
if (!yds.userInfo.IsUserLogin()) {
|
||||
return;
|
||||
}
|
||||
navigateTo(`/pages/mall/order-list?type=${type}`);
|
||||
}
|
||||
const loadOrderStatistics = async () => {
|
||||
const res = await get_order_statistics();
|
||||
console.log("res", res);
|
||||
if (res != null) {
|
||||
orderStatistics.waiting_ship_count = res.waiting_ship_count;
|
||||
orderStatistics.waiting_receive_count = res.waiting_receive_count;
|
||||
orderStatistics.received_count = res.received_count;
|
||||
orderStatistics.after_sales_count = res.after_sales_count;
|
||||
} else {
|
||||
orderStatistics.waiting_ship_count = 0;
|
||||
orderStatistics.waiting_receive_count = 0;
|
||||
orderStatistics.received_count = 0;
|
||||
orderStatistics.after_sales_count = 0;
|
||||
}
|
||||
}
|
||||
const loadMenu = async () => {
|
||||
const menuList = [
|
||||
{
|
||||
id: 1,
|
||||
title: "消费记录",
|
||||
onClick: (res) => {
|
||||
if (!yds.userInfo.IsUserLogin()) {
|
||||
return;
|
||||
}
|
||||
navigateTo("/pages/mall/order-list");
|
||||
}
|
||||
}, {
|
||||
id: 2,
|
||||
title: "我的收藏",
|
||||
onClick: (res) => {
|
||||
if (!yds.userInfo.IsUserLogin()) {
|
||||
return;
|
||||
}
|
||||
navigateTo("/pages/mall/collect");
|
||||
}
|
||||
}, {
|
||||
id: 3,
|
||||
title: "优惠券",
|
||||
onClick: (res) => {
|
||||
if (!yds.userInfo.IsUserLogin()) {
|
||||
return;
|
||||
}
|
||||
navigateTo("/pages/other/coupon");
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "收货地址管理",
|
||||
onClick: (res) => {
|
||||
if (!yds.userInfo.IsUserLogin()) {
|
||||
return;
|
||||
}
|
||||
navigateTo("/pages/address/address-list");
|
||||
}
|
||||
},
|
||||
|
|
@ -113,6 +169,13 @@ const loadMenu = async () => {
|
|||
yds.navigateToAgreement("privacy");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "在线客服",
|
||||
onClick: (res) => {
|
||||
page_kefu_show.value.open();
|
||||
}
|
||||
},
|
||||
];
|
||||
if (yds.userInfo.isAccountLogin()) {
|
||||
menuList.push({
|
||||
|
|
@ -175,32 +238,113 @@ const loadMenu = async () => {
|
|||
|
||||
// 用户信息区域样式
|
||||
.user-info-section {
|
||||
width: 100%;
|
||||
height: 80.15rpx;
|
||||
width: 95%;
|
||||
height: auto;
|
||||
min-height: 80.15rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login-section {
|
||||
position: relative;
|
||||
padding: 20rpx;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 15.27rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: auto;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.login-section:active {
|
||||
background-color: #F5F7FF;
|
||||
}
|
||||
|
||||
.login-content {
|
||||
margin-left: 23rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 80.15rpx;
|
||||
height: 80.15rpx;
|
||||
border-radius: 10rpx;
|
||||
background-color: #D8D8D8;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
position: absolute;
|
||||
left: 103rpx;
|
||||
top: 11rpx;
|
||||
font-size: 22.9rpx;
|
||||
color: #333333;
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.user-days {
|
||||
position: absolute;
|
||||
left: 103rpx;
|
||||
top: 50rpx;
|
||||
font-size: 19.08rpx;
|
||||
color: #8A8A8A;
|
||||
margin-top: 5rpx;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.login-text {
|
||||
font-weight: bold;
|
||||
color: #4A6FEA;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.login-tip {
|
||||
font-size: 19.08rpx;
|
||||
color: #8A8A8A;
|
||||
}
|
||||
|
||||
.login-arrow {
|
||||
position: absolute;
|
||||
right: 25rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 10.67rpx;
|
||||
height: 19.66rpx;
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
|
||||
.default-avatar {
|
||||
width: 80.15rpx;
|
||||
height: 80.15rpx;
|
||||
border-radius: 10rpx;
|
||||
background-color: #EAEAEA;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.default-avatar::before,
|
||||
.default-avatar::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: #BBBBBB;
|
||||
}
|
||||
|
||||
.default-avatar::before {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
top: 15rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.default-avatar::after {
|
||||
width: 50rpx;
|
||||
height: 25rpx;
|
||||
border-radius: 50% 50% 0 0;
|
||||
bottom: 10rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
// 订单状态区域样式
|
||||
|
|
@ -257,10 +401,4 @@ const loadMenu = async () => {
|
|||
font-size: 22.9rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 10.67rpx;
|
||||
height: 19.66rpx;
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
</style>
|
||||
221
pages/other/choose-coupon.vue
Normal file
221
pages/other/choose-coupon.vue
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
<template>
|
||||
<page-container ref="pageContainer" title="选择优惠卷" show-back :show-not-data="showNotData" :refresh="onRefresh"
|
||||
:showLoading="showLoading">
|
||||
<view v-if="listData.length > 0">
|
||||
<view class="list-item" v-for="(item, i) in listData" :key="i" :class="{ dis: tabList[tabCur].type == 2 }">
|
||||
<view class="money">
|
||||
¥
|
||||
<text>{{ Number(item.price) }}</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="title">满{{ item.man_price }}减{{ item.price }}</view>
|
||||
|
||||
<view class="time">{{ item.end_time }}到期</view>
|
||||
</view>
|
||||
<view class="btn">
|
||||
{{ item.mark }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="not-data">
|
||||
<NoData></NoData>
|
||||
</view>
|
||||
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getUserCoupon } from '@/common/server/user';
|
||||
//# 必须要引入
|
||||
import PageContainer from '@/components/youdas-container/page-container.vue'
|
||||
let showLoading = ref(false);
|
||||
let pageContainer = ref(null);
|
||||
|
||||
let showNotData = ref(false);
|
||||
let listData = ref([]);
|
||||
|
||||
const getList = async () => {
|
||||
showLoading.value = true;
|
||||
let res = await getUserCoupon(0, 1, 50);
|
||||
listData.value = res.data.list;
|
||||
showLoading.value = false;
|
||||
};
|
||||
// 下拉刷新方法
|
||||
const onRefresh = async (paging) => {
|
||||
await getList();
|
||||
paging.complete();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tab-list {
|
||||
display: flex;
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
margin: 20rpx 20rpx 30rpx;
|
||||
|
||||
.tab-list-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
padding: 20rpx 18rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 8rpx;
|
||||
color: #999999;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
background-color: #E6F791;
|
||||
box-shadow: 0 2rpx 8rpx rgba(230, 247, 145, 0.6);
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
bottom: -10rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10rpx solid transparent;
|
||||
border-right: 10rpx solid transparent;
|
||||
border-top: 10rpx solid #E6F791;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-item {
|
||||
width: 710rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 auto 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 8rpx;
|
||||
background: linear-gradient(to bottom, #F39205, #FFBB5C);
|
||||
}
|
||||
|
||||
.money {
|
||||
width: 180rpx;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #F39205;
|
||||
padding: 30rpx 0;
|
||||
background: rgba(243, 146, 5, 0.05);
|
||||
|
||||
text {
|
||||
font-weight: 600;
|
||||
font-size: 70rpx;
|
||||
color: #F39205;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 1rpx;
|
||||
height: 116rpx;
|
||||
background: #EEEEEE;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
padding: 30rpx 20rpx;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.time {
|
||||
margin-top: 20rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: 400;
|
||||
color: #8A8A8A;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: #E6F791;
|
||||
border-radius: 50%;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 120rpx;
|
||||
height: 60rpx;
|
||||
background: linear-gradient(to right, #E6F791, #D7E87D);
|
||||
border-radius: 30rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
margin-right: 20rpx;
|
||||
box-shadow: 0 4rpx 8rpx rgba(230, 247, 145, 0.4);
|
||||
transition: all 0.3s;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
&.dis {
|
||||
position: relative;
|
||||
opacity: 0.8;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
backdrop-filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #CCCCCC;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.not-data {
|
||||
margin-top: 200rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
12
pages/other/user-agreement.vue
Normal file
12
pages/other/user-agreement.vue
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<template>
|
||||
<web-view :src="url"></web-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
let url = ref("");
|
||||
onLoad((options) => {
|
||||
url.value = "http://testweb.zfunbox.cn/";
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
BIN
static/app-plus/user/sc1.png
Normal file
BIN
static/app-plus/user/sc1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/app-plus/user/sc2.png
Normal file
BIN
static/app-plus/user/sc2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Loading…
Reference in New Issue
Block a user