Merge branch 'main' of http://192.168.195.14:3000/shang/youdas
This commit is contained in:
commit
8f790d8d1e
|
|
@ -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;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
import { getPlatformConfig } from '../server/config';
|
||||
/**
|
||||
* 多端平台抽象基类(父类)
|
||||
* 定义所有端必须实现的方法
|
||||
|
|
@ -12,10 +12,18 @@ class BasePlatform {
|
|||
this.env = ''; // 运行环境标识
|
||||
this.config = null;
|
||||
this.version = '1.0.0';
|
||||
this.getConfigPromise = null;
|
||||
}
|
||||
async getConfig() {
|
||||
|
||||
return {};
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (this.config) {
|
||||
resolve(this.config);
|
||||
} else {
|
||||
this.config = await getPlatformConfig(this.version);
|
||||
resolve(this.config);
|
||||
}
|
||||
});;
|
||||
}
|
||||
async appData() {
|
||||
|
||||
|
|
@ -50,9 +58,7 @@ class BasePlatform {
|
|||
* @param {number} amount - 支付金额(分)
|
||||
* @param {string} orderId - 订单号
|
||||
*/
|
||||
pay({
|
||||
data
|
||||
}, event) {
|
||||
async pay(data, event) {
|
||||
throw new Error('子类必须实现 pay 方法');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import HttpRequest from "../system/request";
|
||||
import { platform } from "../platform/PlatformFactory";
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
|
|
@ -8,3 +9,12 @@ export const getConfig = async () => {
|
|||
const res = await HttpRequest.getOrCache('/config');
|
||||
return res.data;
|
||||
}
|
||||
/**
|
||||
* 获取平台配置
|
||||
* @param {string} version 版本号
|
||||
* @returns
|
||||
*/
|
||||
export const getPlatformConfig = async () => {
|
||||
const res = await HttpRequest.getOrCache('/getPlatformConfig', { version: platform.version }, 500);
|
||||
return res.data;
|
||||
}
|
||||
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,10 @@ export const getAgreement = async (type) => {
|
|||
type_id = 4;
|
||||
} else if (type == "privacy") {
|
||||
type_id = 5;
|
||||
} else if (type == "product") {
|
||||
type_id = 32;
|
||||
} else {
|
||||
type_id = type;
|
||||
}
|
||||
const res = await HttpRequest.get('/getAgreement', {
|
||||
type: type_id
|
||||
|
|
|
|||
114
common/server/product.js
Normal file
114
common/server/product.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
import HttpRequest from "../system/request";
|
||||
|
||||
/**
|
||||
* 获取banner列表
|
||||
* @returns {Promise} banner列表
|
||||
*/
|
||||
export const getBannerList = async () => {
|
||||
const res = await HttpRequest.get('/get_banner_list');
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* 获取商品列表
|
||||
* @param {number} pageNo 页码
|
||||
* @param {number} pageSize 每页条数
|
||||
* @param {string} searchKeyword 搜索关键词
|
||||
* @returns {Promise} 商品列表
|
||||
*/
|
||||
export const getProductList = async (pageNo, pageSize, searchKeyword) => {
|
||||
const res = await HttpRequest.get('/get_product_list', {
|
||||
page: pageNo,
|
||||
limit: pageSize,
|
||||
title: searchKeyword
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取商品详情
|
||||
* @param {number} id 商品id
|
||||
* @returns {Promise} 商品详情
|
||||
*/
|
||||
export const getProductDetail = async (id) => {
|
||||
const res = await HttpRequest.get('/get_product_detail', {
|
||||
id: id
|
||||
});
|
||||
if (res.status == 1) {
|
||||
return res.data;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -197,11 +197,13 @@ class HttpRequest {
|
|||
*/
|
||||
static async getOrCache(url, data = {}, time = 300, showLoading = false) {
|
||||
const cacheKey = 'cache_' + url + '_' + qs.stringify(data);
|
||||
// console.log('getOrCache', cacheKey, '查询缓存');
|
||||
const cacheData = getLocalStorage(cacheKey);
|
||||
if (cacheData) {
|
||||
console.log('getOrCache', cacheKey, '缓存命中');
|
||||
return cacheData;
|
||||
}
|
||||
|
||||
const res = await HttpRequest.request(url, data, 'GET', showLoading);
|
||||
setLocalStorage(cacheKey, res, time);
|
||||
return res;
|
||||
|
|
|
|||
3
components.d.ts
vendored
3
components.d.ts
vendored
|
|
@ -14,11 +14,14 @@ 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']
|
||||
UniNavBar: typeof import('./components/uni-nav-bar/uni-nav-bar.vue')['default']
|
||||
UniStatusBar: typeof import('./components/uni-nav-bar/uni-status-bar.vue')['default']
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<template>
|
||||
<view class="content">
|
||||
<z-paging v-if="firstLoaded || isCurrentPage" ref="paging" show-refresher-update-time
|
||||
loading-more-no-more-text="我也是有底线的!" v-model="dataList" @query="queryList" :fixed="false">
|
||||
loading-more-no-more-text="我也是有底线的!" :show-loading-more-when-reload="true" v-model="dataList" @query="queryList" :fixed="false">
|
||||
<slot name="search"></slot>
|
||||
<template v-for="(item, index) in dataList">
|
||||
<view v-if="item.cover_image !== ''" class="view-data" :key="index" @click="toDetails(item.id)">
|
||||
<view class="title">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
99
components/youdas-container/text-search.vue
Normal file
99
components/youdas-container/text-search.vue
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<view class="search-container">
|
||||
<view class="search-box">
|
||||
<image src="/static/ic_search.png" class="search-icon" mode="aspectFit"></image>
|
||||
<input class="search-input" type="text" v-model="keyword" :placeholder="placeholder" confirm-type="search" @confirm="handleSearch" />
|
||||
<view class="search-btn" v-if="keyword.length > 0" @click="clearSearch">
|
||||
<text class="search-btn-text">×</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '搜索'
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'search', 'clear']);
|
||||
|
||||
const keyword = ref(props.modelValue);
|
||||
|
||||
// 监听v-model值变化
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
keyword.value = newVal;
|
||||
});
|
||||
|
||||
// 监听内部值变化
|
||||
watch(() => keyword.value, (newVal) => {
|
||||
emit('update:modelValue', newVal);
|
||||
});
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
emit('search', keyword.value);
|
||||
};
|
||||
|
||||
// 清空搜索
|
||||
const clearSearch = () => {
|
||||
keyword.value = '';
|
||||
emit('clear');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.search-container {
|
||||
width: 100%;
|
||||
padding: 20rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
background-color: #F7F7F7;
|
||||
border-radius: 35rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 25rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 70rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
.search-btn-text {
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
27
pages.json
27
pages.json
|
|
@ -95,14 +95,33 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/mall/receiving-address",
|
||||
"style" :
|
||||
{
|
||||
"path": "pages/mall/receiving-address",
|
||||
"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>
|
||||
|
|
@ -10,10 +10,20 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getConfig } from '@/common/server/config';
|
||||
import { navigateTo } from '@/common/system/router';
|
||||
import {
|
||||
defineComponent,
|
||||
ref
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app'
|
||||
import {
|
||||
getConfig, getPlatformConfig
|
||||
} from '@/common/server/config';
|
||||
|
||||
import {
|
||||
navigateTo
|
||||
} from '@/common/system/router';
|
||||
let icon = ref("/static/app-plus/icon_108.png");
|
||||
let login_icon = ref("/static/app-plus/index_login.gif");
|
||||
let tips_text = ref("正在加载中。。。");
|
||||
|
|
@ -26,9 +36,13 @@ onLoad(async () => {
|
|||
uni.onNetworkStatusChange(checkNetwork);
|
||||
return;
|
||||
}
|
||||
|
||||
navigateTo('/pages/news/news');
|
||||
|
||||
const config = await getPlatformConfig();
|
||||
console.log("config", config);
|
||||
if (config.buildVersion == "105") {
|
||||
navigateTo('/pages/news/news');
|
||||
} else {
|
||||
navigateTo('/pages/other/user-agreement');
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 检查网络状态
|
||||
|
|
@ -45,6 +59,7 @@ function checkNetwork(res) {
|
|||
tips_text.value = '请检查网络连接';
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -1,415 +1,404 @@
|
|||
<template>
|
||||
<view class="content">
|
||||
<view class="" style="width: 100%; height: 225.19rpx; background-color: white; position: relative;">
|
||||
<view class="title">
|
||||
商城
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部三个商品 -->
|
||||
<view class="top">
|
||||
|
||||
<view v-for="(item, i) in topDataList" :key="i" class="item" @click="goToDetail(item)">
|
||||
|
||||
<view class="img">
|
||||
<image v-if="item.imgUrl" :src="item.imgUrl" mode="aspectFill" class="product-image"></image>
|
||||
<z-paging-swiper>
|
||||
<template #top>
|
||||
<view class="" style="width: 100%; height: 225.19rpx; background-color: white; position: relative;">
|
||||
<view class="title">
|
||||
商城
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="item-info">
|
||||
<view class="item-name">
|
||||
{{item.name}}
|
||||
</view>
|
||||
|
||||
<view class="item-bottom">
|
||||
<view class="item-price">
|
||||
<text class="price-symbol-small">¥</text>
|
||||
<text class="price-value-small">{{item.price}}</text>
|
||||
</template>
|
||||
<z-paging ref="paging" show-refresher-update-time loading-more-no-more-text="我也是有底线的!" v-model="dataList"
|
||||
@query="queryList" :fixed="false" :show-loading-more-when-reload="true">
|
||||
<!-- 搜索 -->
|
||||
<text-search v-model="searchKeyword" placeholder="搜索商品" @search="handleSearch" @clear="clearSearch" />
|
||||
<!-- 顶部三个商品 -->
|
||||
<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">
|
||||
<image v-if="item.image" :src="item.image" mode="aspectFill" class="product-image">
|
||||
</image>
|
||||
</view>
|
||||
|
||||
<view class="item-count">
|
||||
<text class="count-text-small">{{item.num}}/1</text>
|
||||
<image src="/static/ic_box.png" class="box-icon-small" mode="aspectFit"></image>
|
||||
<view class="item-info">
|
||||
<view class="item-name">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
<view class="item-bottom">
|
||||
<view class="item-price">
|
||||
<text class="price-symbol-small">¥</text>
|
||||
<text class="price-value-small">{{ item.price }}</text>
|
||||
</view>
|
||||
|
||||
<view class="item-count">
|
||||
<text class="count-text-small">{{ item.sales }}/{{ item.stock }}</text>
|
||||
<image src="/static/ic_box.png" class="box-icon-small" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="view-list">
|
||||
<view class="product-item" v-for="(item, i) in dataList" :key="i" @click="goToDetail(item)">
|
||||
|
||||
<view class="product-image-container">
|
||||
<image v-if="item.image" :src="item.image" mode="aspectFill" class="product-image">
|
||||
</image>
|
||||
</view>
|
||||
|
||||
<view class="product-name">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
|
||||
<view class="product-count">
|
||||
<text class="count-text">{{ item.sales }}/{{ item.stock }}</text>
|
||||
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<view class="product-price">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">{{ item.price }}</text>
|
||||
</view>
|
||||
|
||||
<view class="buy-button" @click.stop="buyProduct(item)">
|
||||
<text class="buy-text">购买</text>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="view-list" scroll-y="true">
|
||||
<view class="product-item" v-for="(item, i) in dataList" :key="i" @click="goToDetail(item)">
|
||||
|
||||
<view class="product-image-container">
|
||||
<image v-if="item.imgUrl" :src="item.imgUrl" mode="aspectFill" class="product-image"></image>
|
||||
</view>
|
||||
|
||||
<view class="product-name">
|
||||
{{item.name}}
|
||||
</view>
|
||||
|
||||
<view class="product-count">
|
||||
<text class="count-text">{{item.num}}/1</text>
|
||||
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<view class="product-price">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">{{item.price}}</text>
|
||||
</view>
|
||||
|
||||
<view class="buy-button" @click.stop="buyProduct(item)">
|
||||
<text class="buy-text">购买</text>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
|
||||
<template #empty>
|
||||
<no-data />
|
||||
</template>
|
||||
<template #loading>
|
||||
<loading-data />
|
||||
</template>
|
||||
</z-paging>
|
||||
</z-paging-swiper>
|
||||
<!-- 使用支付弹窗组件 -->
|
||||
<payment-popup ref="paymentPopup_ref" :onSuccess="onPaymentSuccess" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
topDataList: [{
|
||||
id: '1',
|
||||
imgUrl: "/static/product1.png",
|
||||
name: "英雄联盟K/DA系列阿卡丽手办",
|
||||
num: "1",
|
||||
price: "69",
|
||||
stock: 10
|
||||
}, {
|
||||
id: '2',
|
||||
imgUrl: "/static/product2.png",
|
||||
name: "英雄联盟K/DA系列阿狸手办",
|
||||
num: "1",
|
||||
price: "79",
|
||||
stock: 5
|
||||
}, {
|
||||
id: '3',
|
||||
imgUrl: "/static/product3.png",
|
||||
name: "英雄联盟K/DA系列伊芙琳手办",
|
||||
num: "1",
|
||||
price: "89",
|
||||
stock: 8
|
||||
}, ],
|
||||
dataList: [{
|
||||
id: '4',
|
||||
imgUrl: "/static/product4.png",
|
||||
name: "英雄联盟K/DA系列阿卡丽手办豪华版",
|
||||
num: "1",
|
||||
price: "169",
|
||||
stock: 3
|
||||
}, {
|
||||
id: '5',
|
||||
imgUrl: "/static/product5.png",
|
||||
name: "英雄联盟K/DA系列阿狸手办豪华版",
|
||||
num: "1",
|
||||
price: "179",
|
||||
stock: 2
|
||||
}, {
|
||||
id: '6',
|
||||
imgUrl: "/static/product6.png",
|
||||
name: "英雄联盟K/DA系列伊芙琳手办豪华版",
|
||||
num: "1",
|
||||
price: "189",
|
||||
stock: 6
|
||||
}, {
|
||||
id: '7',
|
||||
imgUrl: "/static/product7.png",
|
||||
name: "英雄联盟K/DA系列卡莎手办",
|
||||
num: "1",
|
||||
price: "99",
|
||||
stock: 15
|
||||
}, {
|
||||
id: '8',
|
||||
imgUrl: "/static/product8.png",
|
||||
name: "英雄联盟K/DA系列莎拉手办",
|
||||
num: "1",
|
||||
price: "99",
|
||||
stock: 12
|
||||
}, {
|
||||
id: '9',
|
||||
imgUrl: "/static/product9.png",
|
||||
name: "英雄联盟K/DA系列套装收藏版",
|
||||
num: "1",
|
||||
price: "599",
|
||||
stock: 1
|
||||
}, ]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 跳转到商品详情页
|
||||
goToDetail(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/product-detail?id=${item.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 购买商品
|
||||
buyProduct(item) {
|
||||
// 阻止事件冒泡
|
||||
event.stopPropagation();
|
||||
|
||||
// 检查库存
|
||||
if (item.stock <= 0) {
|
||||
uni.showToast({
|
||||
title: '商品已售罄',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加到购物车或直接购买的逻辑
|
||||
uni.showToast({
|
||||
title: '已添加到购物车',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const paging = ref(null);
|
||||
import { getProductList, getBannerList } from '@/common/server/product';
|
||||
import TextSearch from '@/components/youdas-container/text-search.vue';
|
||||
import paymentPopup from '@/components/youdas-container/payment-popup.vue';
|
||||
|
||||
// 响应式数据
|
||||
const topDataList = ref([
|
||||
]);
|
||||
let isSearch = ref(false);
|
||||
const dataList = ref([]);
|
||||
const searchKeyword = ref(''); // 搜索关键词
|
||||
let paymentPopup_ref = ref(null);
|
||||
// 跳转到商品详情页
|
||||
const goToDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/product-detail?id=${item.id}`
|
||||
});
|
||||
};
|
||||
|
||||
// 购买商品
|
||||
const buyProduct = (item, event) => {
|
||||
|
||||
|
||||
// 检查库存
|
||||
if (item.stock <= 0) {
|
||||
uni.showToast({
|
||||
title: '商品已售罄',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
paymentPopup_ref.value.open(item.id);
|
||||
// 添加到购物车或直接购买的逻辑
|
||||
// uni.showToast({
|
||||
// title: '已添加到购物车',
|
||||
// icon: 'success'
|
||||
// });
|
||||
};
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
if (searchKeyword.value == '') {
|
||||
isSearch.value = false;
|
||||
} else {
|
||||
isSearch.value = true;
|
||||
}
|
||||
|
||||
paging.value.reload();
|
||||
};
|
||||
|
||||
// 清空搜索
|
||||
const clearSearch = () => {
|
||||
searchKeyword.value = '';
|
||||
isSearch.value = false;
|
||||
paging.value.reload();
|
||||
};
|
||||
|
||||
const queryList = (pageNo, pageSize) => {
|
||||
getProductList(pageNo, pageSize, searchKeyword.value).then(res => {
|
||||
dataList.value.concat(res || []);
|
||||
paging.value.complete(res || false);
|
||||
});
|
||||
};
|
||||
|
||||
onLoad(async () => {
|
||||
const bannerList = await getBannerList();
|
||||
topDataList.value = bannerList;
|
||||
});
|
||||
const onPaymentSuccess = () => {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success'
|
||||
});
|
||||
paymentPopup_ref.value.close();
|
||||
paging.value.reload();
|
||||
// 可以在这里添加支付成功后的处理逻辑,比如跳转到订单页面等
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
width: 100%;
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 32.44rpx;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
bottom: 30rpx;
|
||||
}
|
||||
|
||||
.top {
|
||||
width: 688.94rpx;
|
||||
height: 325.38rpx;
|
||||
margin: 34rpx auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
.item {
|
||||
width: 216.31rpx;
|
||||
height: 100%;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 15.27rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 32.44rpx;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
bottom: 30rpx;
|
||||
}
|
||||
|
||||
.top {
|
||||
width: 688.94rpx;
|
||||
height: 325.38rpx;
|
||||
margin: 34rpx auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
.item {
|
||||
width: 216.31rpx;
|
||||
height: 100%;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 15.27rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 216.31rpx;
|
||||
background-color: #F2F2F2;
|
||||
border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.item-info {
|
||||
width: 100%;
|
||||
height: 109.07rpx;
|
||||
position: relative;
|
||||
padding: 8rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 19.08rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 12rpx;
|
||||
left: 0;
|
||||
padding: 0 13rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.price-symbol-small {
|
||||
font-size: 15.27rpx;
|
||||
margin-top: 6rpx;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.price-value-small {
|
||||
font-size: 22.9rpx;
|
||||
font-weight: bold;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.item-count {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.count-text-small {
|
||||
font-size: 15.27rpx;
|
||||
color: #6C6C6C;
|
||||
}
|
||||
|
||||
.box-icon-small {
|
||||
width: 17.39rpx;
|
||||
height: 17.39rpx;
|
||||
margin-left: 7rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.view-list {
|
||||
width: 688.93rpx;
|
||||
height: 850rpx;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.product-item {
|
||||
width: 100%;
|
||||
height: 261.45rpx;
|
||||
background-color: #FFFFFF;
|
||||
margin-bottom: 21rpx;
|
||||
border-radius: 15.27rpx;
|
||||
position: relative;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s;
|
||||
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.product-image-container {
|
||||
width: 216.31rpx;
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 216.31rpx;
|
||||
background-color: #F2F2F2;
|
||||
border-radius: 15.27rpx;
|
||||
position: absolute;
|
||||
left: 22rpx;
|
||||
top: 22rpx;
|
||||
border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.product-name {
|
||||
width: 350rpx;
|
||||
|
||||
.item-info {
|
||||
width: 100%;
|
||||
height: 109.07rpx;
|
||||
position: relative;
|
||||
padding: 8rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
left: 269rpx;
|
||||
top: 44rpx;
|
||||
font-size: 26.72rpx;
|
||||
font-weight: 600;
|
||||
font-size: 19.08rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
|
||||
.item-bottom {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 12rpx;
|
||||
left: 0;
|
||||
padding: 0 13rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
left: 269rpx;
|
||||
top: 95rpx;
|
||||
align-items: center;
|
||||
|
||||
.count-text {
|
||||
font-size: 15.27rpx;
|
||||
color: #6C6C6C;
|
||||
}
|
||||
|
||||
.box-icon {
|
||||
width: 17.39rpx;
|
||||
height: 17.39rpx;
|
||||
margin-left: 7rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.product-price {
|
||||
position: absolute;
|
||||
|
||||
.price-symbol-small {
|
||||
font-size: 15.27rpx;
|
||||
margin-top: 6rpx;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.price-value-small {
|
||||
font-size: 22.9rpx;
|
||||
font-weight: bold;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.item-count {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
left: 269rpx;
|
||||
bottom: 44rpx;
|
||||
align-items: center;
|
||||
|
||||
.price-symbol {
|
||||
font-size: 19.08rpx;
|
||||
margin-top: 15rpx;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: 34.35rpx;
|
||||
font-weight: bold;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
}
|
||||
|
||||
.buy-button {
|
||||
width: 89.22rpx;
|
||||
height: 42rpx;
|
||||
border-radius: 20.99rpx;
|
||||
border: 1rpx solid #FF6A6A;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 38rpx;
|
||||
bottom: 38rpx;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:active {
|
||||
background-color: #FF6A6A;
|
||||
|
||||
.buy-text {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.count-text-small {
|
||||
font-size: 15.27rpx;
|
||||
color: #6C6C6C;
|
||||
}
|
||||
|
||||
.box-icon-small {
|
||||
width: 17.39rpx;
|
||||
height: 17.39rpx;
|
||||
margin-left: 7rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.product-item {
|
||||
width: 100%;
|
||||
height: 261.45rpx;
|
||||
background-color: #FFFFFF;
|
||||
margin-bottom: 21rpx;
|
||||
border-radius: 15.27rpx;
|
||||
position: relative;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.product-image-container {
|
||||
width: 216.31rpx;
|
||||
height: 216.31rpx;
|
||||
background-color: #F2F2F2;
|
||||
border-radius: 15.27rpx;
|
||||
position: absolute;
|
||||
left: 22rpx;
|
||||
top: 22rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.product-name {
|
||||
width: 350rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
left: 269rpx;
|
||||
top: 44rpx;
|
||||
font-size: 26.72rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
left: 269rpx;
|
||||
top: 95rpx;
|
||||
align-items: center;
|
||||
|
||||
.count-text {
|
||||
font-size: 15.27rpx;
|
||||
color: #6C6C6C;
|
||||
}
|
||||
|
||||
.box-icon {
|
||||
width: 17.39rpx;
|
||||
height: 17.39rpx;
|
||||
margin-left: 7rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.product-price {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
left: 269rpx;
|
||||
bottom: 44rpx;
|
||||
align-items: center;
|
||||
|
||||
.price-symbol {
|
||||
font-size: 19.08rpx;
|
||||
margin-top: 15rpx;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: 34.35rpx;
|
||||
font-weight: bold;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
}
|
||||
|
||||
.buy-button {
|
||||
width: 89.22rpx;
|
||||
height: 42rpx;
|
||||
border-radius: 20.99rpx;
|
||||
border: 1rpx solid #FF6A6A;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 38rpx;
|
||||
bottom: 38rpx;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:active {
|
||||
background-color: #FF6A6A;
|
||||
|
||||
.buy-text {
|
||||
font-size: 19.08rpx;
|
||||
color: #FF6A6A;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.buy-text {
|
||||
font-size: 19.08rpx;
|
||||
color: #FF6A6A;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
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>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 滑动切换选项卡演示(标准写法) -->
|
||||
<template>
|
||||
<page-no-container ref="pageContainer" title="我的订单" :showBack="true">
|
||||
<PageNoContainer ref="pageContainer" title="我的订单" :showBack="true">
|
||||
<!-- 使用z-paging-swiper为根节点可以免计算高度 -->
|
||||
<z-paging-swiper :fixed="false">
|
||||
<!-- 需要固定在顶部不滚动的view放在slot="top"的view中 -->
|
||||
|
|
@ -19,21 +19,22 @@
|
|||
</swiper>
|
||||
</z-paging-swiper>
|
||||
|
||||
</page-no-container>
|
||||
</PageNoContainer>
|
||||
</template>
|
||||
|
||||
<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);
|
||||
if (options.type) {
|
||||
current.value = options.type;
|
||||
current.value = Number(options.type);
|
||||
}
|
||||
});
|
||||
// tabs通知swiper切换
|
||||
|
|
@ -52,17 +53,18 @@ 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>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.swiper {
|
||||
height:90vh;
|
||||
height: 90vh;
|
||||
}
|
||||
|
||||
.swiper-item {
|
||||
}
|
||||
.swiper-item {}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,229 +1,193 @@
|
|||
<template>
|
||||
<view class="" style="width: 100%; height: 715.65rpx; background-color: #D8D8D8;">
|
||||
<z-paging ref="paging" refresher-only @onRefresh="onRefresh">
|
||||
|
||||
</view>
|
||||
<!-- 返回 -->
|
||||
<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>
|
||||
|
||||
<!-- 返回 -->
|
||||
<image src="/static/ic_back.png" @click="toBack()"
|
||||
style="width: 41.98rpx; height: 41.98rpx; position: fixed; left: 30rpx; top: 137rpx;" mode=""></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;">
|
||||
|
||||
<view class="" style="width: 100%; height: 244.27rpx; background-color: white; position: relative;">
|
||||
<view class="item-price">
|
||||
<text class="price-symbol-small">¥</text>
|
||||
<text class="price-value-small">{{ productDetail.price }}</text>
|
||||
</view>
|
||||
|
||||
<view class="item-price">
|
||||
<text class="price-symbol-small">¥</text>
|
||||
<text class="price-value-small">69</text>
|
||||
</view>
|
||||
|
||||
<view class="" style="position: absolute; left: 30.53rpx; top: 95.42rpx; font-size: 26.72rpx;">
|
||||
英雄联盟K/DA系列
|
||||
</view>
|
||||
|
||||
<view class="" style="position: absolute; left: 30.53rpx; bottom: 21rpx; font-size: 22.9rpx;">
|
||||
商品详情
|
||||
</view>
|
||||
|
||||
<view class="product-count">
|
||||
<text class="count-text">item.num/1</text>
|
||||
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 详情列表 -->
|
||||
<view class="" v-for="(item, index) in detailList"
|
||||
style="width: 100%; height: 666.03rpx; background-color: #D8D8D8;">
|
||||
{{ index }}
|
||||
</view>
|
||||
|
||||
<view class="" style="width: 100%; height: 188.94rpx; position: fixed; bottom: 0; background-color: white;">
|
||||
|
||||
<view class="" @click="bayOpen()"
|
||||
style="width: 654.58rpx; height: 80.15rpx; margin: 33rpx auto; background-color: #333333; display: flex; align-items: center; justify-content: center; border-radius: 15.27rpx;">
|
||||
<text style="color: #CDEF27; font-size: 22.9rpx;">立即购买</text>
|
||||
</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=""
|
||||
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;">新人福利第6弹-小米音箱</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;">69</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: center; 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>
|
||||
|
||||
</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 class="" style="position: absolute; left: 30.53rpx; top: 95.42rpx; font-size: 26.72rpx;">
|
||||
{{ productDetail.title }}
|
||||
</view>
|
||||
|
||||
<view class="" style="position: absolute; left: 30.53rpx; bottom: 21rpx; font-size: 22.9rpx;">
|
||||
商品详情
|
||||
</view>
|
||||
|
||||
<view class="product-count">
|
||||
<text class="count-text">{{ productDetail.sales }}/{{ productDetail.stock }}</text>
|
||||
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 详情列表 -->
|
||||
<view v-if="productDetail" class="" style="width: 100%;">
|
||||
<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"
|
||||
style="width: 654.58rpx; height: 80.15rpx; margin: 33rpx auto; background-color: #333333; display: flex; align-items: center; justify-content: center; border-radius: 15.27rpx;">
|
||||
<text style="color: #CDEF27; font-size: 22.9rpx;">立即购买</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 使用支付弹窗组件 -->
|
||||
<payment-popup ref="paymentPopup_ref" :onSuccess="onPaymentSuccess" />
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
detailList: [1, 2, 3, 4, 5],
|
||||
isCheck: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
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();
|
||||
});
|
||||
|
||||
toBack() {
|
||||
console.log("777777");
|
||||
uni.navigateBack();
|
||||
},
|
||||
|
||||
bayOpen() {
|
||||
this.$refs.bayPop.open();
|
||||
},
|
||||
closePop() {
|
||||
this.$refs.bayPop.close();
|
||||
},
|
||||
|
||||
setCheck() {
|
||||
this.isCheck = !this.isCheck;
|
||||
},
|
||||
|
||||
toAddress(){
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/receiving-address'
|
||||
});
|
||||
}
|
||||
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 toBack = () => {
|
||||
console.log("777777");
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
const bayOpen = () => {
|
||||
paymentPopup_ref.value.open(productId);
|
||||
};
|
||||
|
||||
const onPaymentSuccess = () => {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success'
|
||||
});
|
||||
paymentPopup_ref.value.close();
|
||||
queryProductDetail();
|
||||
// 可以在这里添加支付成功后的处理逻辑,比如跳转到订单页面等
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.item-price {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
left: 30.53rpx;
|
||||
top: 26.72rpx;
|
||||
.item-price {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
left: 30.53rpx;
|
||||
top: 26.72rpx;
|
||||
}
|
||||
|
||||
.price-symbol-small {
|
||||
font-size: 19.08rpx;
|
||||
margin-top: 10rpx;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
.price-value-small {
|
||||
font-size: 41.98rpx;
|
||||
font-weight: bold;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
|
||||
|
||||
.product-count {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
right: 30.53rpx;
|
||||
top: 40rpx;
|
||||
align-items: center;
|
||||
|
||||
.count-text {
|
||||
font-size: 15.27rpx;
|
||||
color: #6C6C6C;
|
||||
}
|
||||
|
||||
.price-symbol-small {
|
||||
font-size: 19.08rpx;
|
||||
margin-top: 10rpx;
|
||||
color: #FF6A6A;
|
||||
.box-icon {
|
||||
width: 17.39rpx;
|
||||
height: 17.39rpx;
|
||||
margin-left: 7rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.price-value-small {
|
||||
font-size: 41.98rpx;
|
||||
font-weight: bold;
|
||||
color: #FF6A6A;
|
||||
}
|
||||
.arrow-icon {
|
||||
width: 10.67rpx;
|
||||
height: 19.66rpx;
|
||||
right: 25rpx;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
.product-count {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
right: 30.53rpx;
|
||||
top: 40rpx;
|
||||
align-items: center;
|
||||
|
||||
.count-text {
|
||||
font-size: 15.27rpx;
|
||||
color: #6C6C6C;
|
||||
}
|
||||
|
||||
.box-icon {
|
||||
width: 17.39rpx;
|
||||
height: 17.39rpx;
|
||||
margin-left: 7rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 10.67rpx;
|
||||
height: 19.66rpx;
|
||||
right: 25rpx;
|
||||
position: absolute;
|
||||
}
|
||||
//设置图片样式
|
||||
::v-deep rich-text img {
|
||||
max-width: 95% !important;
|
||||
// border-radius: 10rpx;
|
||||
height: auto !important;
|
||||
display: block !important;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -16,20 +16,20 @@
|
|||
|
||||
<scroll-view class="" scroll-y="true" style="width: 688.93rpx; margin: 34.44rpx auto; height: 1200rpx;">
|
||||
|
||||
<view class="" v-for="(item,index) in addressList"
|
||||
<view class="" v-for="(item, index) in addressList"
|
||||
style="width: 100%; height: 227.1rpx; background-color: white; margin-bottom: 22.9rpx; border-radius: 15.27rpx; position: relative;">
|
||||
|
||||
|
||||
<view class=""
|
||||
style="display: flex; flex-direction: row; position: absolute; left: 32.44rpx; top: 30.53rpx;">
|
||||
|
||||
<text style="font-size: 22.9rpx;">{{item.name}}</text>
|
||||
<text style="font-size: 22.9rpx;">{{ item.name }}</text>
|
||||
|
||||
<text style="font-size: 22.9rpx; margin-left: 30.53rpx;">{{item.phoneNum}}</text>
|
||||
<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,79 +50,87 @@
|
|||
|
||||
</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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
addressList: [{
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, ],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toBack() {
|
||||
console.log("777777");
|
||||
uni.navigateBack();
|
||||
},
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
eventChannel: null,
|
||||
addressList: [{
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
}, {
|
||||
name: "苏家辉",
|
||||
phoneNum: "130000000",
|
||||
address: "江苏省徐州市睢宁县"
|
||||
},],
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.eventChannel = this.getOpenerEventChannel();
|
||||
|
||||
},
|
||||
methods: {
|
||||
toBack() {
|
||||
console.log("777777");
|
||||
uni.navigateBack();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 32.44rpx;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
bottom: 38.17rpx;
|
||||
}
|
||||
.title {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 32.44rpx;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
bottom: 38.17rpx;
|
||||
}
|
||||
</style>
|
||||
215
pages/me/me.vue
215
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="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-content">
|
||||
<view class="user-id">{{ userInfo.username }}</view>
|
||||
<view class="user-days">已陪你走过了{{ userInfo.days }}天</view>
|
||||
</view>
|
||||
<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,37 +90,80 @@ 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");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "商品退换货",
|
||||
onClick: (res) => {
|
||||
yds.navigateToAgreement("29");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "用户协议",
|
||||
onClick: (res) => {
|
||||
yds.navigateToAgreement("user");
|
||||
|
|
@ -113,6 +176,13 @@ const loadMenu = async () => {
|
|||
yds.navigateToAgreement("privacy");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "在线客服",
|
||||
onClick: (res) => {
|
||||
page_kefu_show.value.open();
|
||||
}
|
||||
},
|
||||
];
|
||||
if (yds.userInfo.isAccountLogin()) {
|
||||
menuList.push({
|
||||
|
|
@ -143,7 +213,7 @@ const loadMenu = async () => {
|
|||
<style lang="scss">
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F7F7F7;
|
||||
|
|
@ -175,32 +245,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 +408,4 @@ const loadMenu = async () => {
|
|||
font-size: 22.9rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 10.67rpx;
|
||||
height: 19.66rpx;
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -13,17 +13,14 @@
|
|||
</template>
|
||||
<swiper class="swiper" :current="current" @animationfinish="swiperAnimationfinish">
|
||||
<swiper-item class="swiper-item" v-for="(item, index) in tabList" :key="index">
|
||||
<view class="search-container">
|
||||
<view class="search">
|
||||
<text class="iconfont icon-search" style="margin-right: 10rpx; color: #999;"></text>
|
||||
<input type="text" v-model="searchKeywords[index]" placeholder="搜索" confirm-type="search"
|
||||
@confirm="() => onSearch(index)" />
|
||||
<text class="iconfont icon-close" v-if="searchKeywords[index]" @click="() => clearSearch(index)"
|
||||
style="margin-left: 10rpx; color: #999;"></text>
|
||||
</view>
|
||||
</view>
|
||||
<news-list-item @clickItem="onClickItem" :responseCallback="queryList" ref="listItem" :tabIndex="index"
|
||||
:currentIndex="current">
|
||||
<template #search>
|
||||
<view class="search-container">
|
||||
<text-search v-model="searchKeywords[index]" placeholder="搜索"
|
||||
@search="() => onSearch(index)" @clear="() => clearSearch(index)" />
|
||||
</view>
|
||||
</template>
|
||||
</news-list-item>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
|
@ -32,6 +29,7 @@
|
|||
|
||||
<script setup>
|
||||
import newsListItem from '@/components/youdas-container/news-list-item.vue'
|
||||
import TextSearch from '@/components/youdas-container/text-search.vue'
|
||||
import { getFeaturedNewsList, getHotNewsList, getFollowNewsList } from '@/common/server/news'
|
||||
import { navigateTo } from '@/common/system/router'
|
||||
// 响应式数据
|
||||
|
|
@ -96,23 +94,6 @@ const clearSearch = (index) => {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.search {
|
||||
height: 70rpx;
|
||||
background-color: #F7F7F7;
|
||||
border-radius: 35rpx;
|
||||
padding: 0 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ const loadData = async (type) => {
|
|||
pageTitle.value = "隐私政策";
|
||||
}
|
||||
const res = await getAgreement(type);
|
||||
console.log("res", res);
|
||||
if (res) {
|
||||
agreementContent.value = res.content;
|
||||
if (pageTitle.value == "") {
|
||||
|
|
|
|||
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>
|
||||
70
pages/other/user-agreement.nvue
Normal file
70
pages/other/user-agreement.nvue
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<view class="container">
|
||||
<view class="navbar" :style="{ 'height': statusBarHeight }"></view>
|
||||
<web-view v-if="webviewurl" ref="webview" class="webview" :src="webviewurl"
|
||||
@onPostMessage="handlePostMessage"></web-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app'
|
||||
import {
|
||||
platform
|
||||
} from '@/common/platform/PlatformFactory';
|
||||
import {
|
||||
getPlatformConfig
|
||||
} from '@/common/server/config';
|
||||
let webview = ref(null);
|
||||
let webviewurl = ref("");
|
||||
|
||||
getPlatformConfig().then(res => {
|
||||
webviewurl.value = res.userAgreement;
|
||||
});
|
||||
const windowInfo = uni.getWindowInfo();
|
||||
console.log(windowInfo);
|
||||
let statusBarHeight = windowInfo.statusBarHeight + "px";
|
||||
// webview向外部发送消息
|
||||
const handlePostMessage = async (data) => {
|
||||
console.log("接收到消息:", data, data.detail.data);
|
||||
if (data.detail.data && data.detail.data[0]) {
|
||||
let detailData = data.detail.data[0];
|
||||
if (detailData.action == "pay") {
|
||||
const res = await platform.pay(detailData.data);
|
||||
evalJs({
|
||||
action: "pay",
|
||||
data: res.isPay,
|
||||
callback: detailData.callback
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 调用 webview 内部逻辑
|
||||
const evalJs = (data) => {
|
||||
let json = JSON.stringify(data || {});
|
||||
console.log("yds_postMessage", json);
|
||||
webview.value.evalJS("window.yds_postMessage('" + json + "')");
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.container {
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
/* 竖向排列 */
|
||||
}
|
||||
|
||||
.navbar {
|
||||
height: 40px;
|
||||
/* 导航栏高度 */
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.webview {
|
||||
flex: 1;
|
||||
/* 自动占满剩余空间 */
|
||||
}
|
||||
</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 |
BIN
static/ic_search.png
Normal file
BIN
static/ic_search.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 696 B |
Loading…
Reference in New Issue
Block a user