diff --git a/README.md b/README.md
index 6e50594..0009d1e 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,51 @@
└── uni_modules # uni-app插件模块
```
+## 分包结构说明
+
+### pages_order分包
+分包是小程序优化加载性能的重要手段,pages_order作为独立分包,包含以下模块:
+
+```
+├── auth # 认证相关页面
+│ ├── loginAndRegisterAndForgetPassword.vue # 登录注册
+│ ├── wxLogin.vue # 微信登录
+│ └── wxUserInfo.vue # 微信用户信息
+├── components # 分包内公共组件
+│ ├── address/ # 地址选择组件
+│ ├── areaSelector/ # 区域选择器
+│ └── product/ # 商品相关组件
+├── home # 首页相关
+│ ├── addEnterprise.vue # 添加企业
+│ ├── contact.vue # 联系我们
+│ ├── introduce.vue # 介绍页面
+│ ├── journalism.vue # 新闻资讯
+│ └── notice.vue # 公告
+├── mine # 我的模块
+│ ├── address.vue # 收货地址
+│ ├── balance.vue # 余额
+│ ├── commission.vue # 佣金
+│ ├── coupon.vue # 优惠券
+│ ├── memberCenter.vue # 会员中心
+│ └── more... # 更多功能页面
+├── order # 订单模块
+│ ├── createOrder.vue # 创建订单
+│ ├── orderDetail.vue # 订单详情
+│ └── giftList.vue # 礼品列表
+├── product # 商品模块
+│ └── productDetail.vue # 商品详情
+└── static # 分包静态资源
+ ├── address/ # 地址相关图片
+ ├── auth/ # 认证相关图片
+ ├── coupon/ # 优惠券图片
+ └── more... # 其他静态资源
+```
+
+**分包特点:**
+- 静态资源就近原则:分包相关的图片等静态资源存放在分包目录下,避免主包体积过大
+- 模块化组织:按功能模块划分目录,便于维护和管理
+- 组件复用:分包内的通用组件集中管理,提高代码复用性
+
## 核心模块详解
### 1. Mixins 混入
@@ -99,14 +144,17 @@ export default {
create: {
url: '/api/product/create',
method: 'POST',
- loading: true
+ loading: true // 显示加载提示
+ auth : true,//效验登录
+ debounce : 1000,//接口防抖,1s
+ limit : 500,//接口限流,0.5s
},
}
```
**调用接口示例:**
```javascript
-// 1. 基础列表查询
+// 第一种写法:callback方式处理响应
this.$api('product.list', {
pageNo: 1,
pageSize: 10,
@@ -115,13 +163,13 @@ this.$api('product.list', {
// 处理列表数据
})
-// 2. 创建商品
+// 第二种写法:Promise方式处理响应
this.$api('product.create', {
name: '商品名称',
price: 99.99,
description: '商品描述'
-}, res => {
- if (res.code === 0) {
+}).then(res => {
+ if (res.code === 200) {
// 创建成功
uni.showToast({ title: '创建成功' })
}
@@ -140,6 +188,13 @@ this.$api('product.create', {
**使用示例:**
```javascript
+
+// 授权处理
+async preservationImg(img) {
+ await this.$authorize('scope.writePhotosAlbum')
+ //在执行$authorize之后,await下面的代码都是确保授权完成的情况下执行
+},
+
// 时间格式化
const formattedTime = this.$timeUtils.formatTime(new Date())
@@ -179,11 +234,6 @@ export default {
data() {
return {
mixinsListApi: 'product.list',
- queryParams: {
- pageNo: 1,
- pageSize: 10,
- categoryId: ''
- }
}
},
methods: {
@@ -239,51 +289,6 @@ export default {
- 确认网络请求是否正常
- 查看请求参数格式是否正确
-## 分包结构说明
-
-### pages_order分包
-分包是小程序优化加载性能的重要手段,pages_order作为独立分包,包含以下模块:
-
-```
-├── auth # 认证相关页面
-│ ├── loginAndRegisterAndForgetPassword.vue # 登录注册
-│ ├── wxLogin.vue # 微信登录
-│ └── wxUserInfo.vue # 微信用户信息
-├── components # 分包内公共组件
-│ ├── address/ # 地址选择组件
-│ ├── areaSelector/ # 区域选择器
-│ └── product/ # 商品相关组件
-├── home # 首页相关
-│ ├── addEnterprise.vue # 添加企业
-│ ├── contact.vue # 联系我们
-│ ├── introduce.vue # 介绍页面
-│ ├── journalism.vue # 新闻资讯
-│ └── notice.vue # 公告
-├── mine # 我的模块
-│ ├── address.vue # 收货地址
-│ ├── balance.vue # 余额
-│ ├── commission.vue # 佣金
-│ ├── coupon.vue # 优惠券
-│ ├── memberCenter.vue # 会员中心
-│ └── more... # 更多功能页面
-├── order # 订单模块
-│ ├── createOrder.vue # 创建订单
-│ ├── orderDetail.vue # 订单详情
-│ └── giftList.vue # 礼品列表
-├── product # 商品模块
-│ └── productDetail.vue # 商品详情
-└── static # 分包静态资源
- ├── address/ # 地址相关图片
- ├── auth/ # 认证相关图片
- ├── coupon/ # 优惠券图片
- └── more... # 其他静态资源
-```
-
-**分包特点:**
-- 静态资源就近原则:分包相关的图片等静态资源存放在分包目录下,避免主包体积过大
-- 模块化组织:按功能模块划分目录,便于维护和管理
-- 组件复用:分包内的通用组件集中管理,提高代码复用性
-
## 配置文件说明
### config.js
diff --git a/api/api.js b/api/api.js
index 349142f..d566315 100644
--- a/api/api.js
+++ b/api/api.js
@@ -22,8 +22,8 @@ export function api(key, data, callback, loadingTitle) {
let req = config[key]
if (!req) {
- console.error('无效key--------' + key);
- return
+ console.error('无效key' + key);
+ return Promise.reject()
}
if (typeof callback == 'string') {
@@ -40,7 +40,7 @@ export function api(key, data, callback, loadingTitle) {
let storageKey = req.url
let storage = limit[storageKey]
if (storage && new Date().getTime() - storage < req.limit) {
- return
+ return Promise.reject()
}
limit[storageKey] = new Date().getTime()
}
@@ -49,8 +49,8 @@ export function api(key, data, callback, loadingTitle) {
if (req.auth) {
if (!uni.getStorageSync('token')) {
utils.toLogin()
- console.error('需要登录')
- return
+ console.error('需要登录', req.url)
+ return Promise.reject()
}
}
@@ -74,19 +74,22 @@ export function api(key, data, callback, loadingTitle) {
loadingTitle || req.showLoading, loadingTitle || req.loadingTitle)
}, req.debounce)
- return
+ return Promise.reject()
}
- http.http(req.url, data, callback, req.method,
+ return http.http(req.url, data, callback, req.method,
loadingTitle || req.showLoading, loadingTitle || req.loadingTitle)
}
-
function addApiModel(model, key){
for(let k in model){
if(config[`${k}`]){
console.error(`重名api------model=${key},key=${k}`);
+ uni.showModal({
+ title: `重名api`,
+ content: `model=${key},key=${k}`
+ })
continue
}
config[`${k}`] = model[k]
@@ -98,4 +101,5 @@ models.forEach(key => {
addApiModel(require(`./model/${key}.js`).default, key)
})
+
export default api
\ No newline at end of file
diff --git a/api/http.js b/api/http.js
index 8f2e8b8..6c3da63 100644
--- a/api/http.js
+++ b/api/http.js
@@ -1,7 +1,7 @@
import Vue from 'vue'
import utils from '../utils/utils.js'
-
+import store from '../store/store.js'
function http(uri, data, callback, method = 'GET', showLoading, title) {
@@ -11,16 +11,23 @@ function http(uri, data, callback, method = 'GET', showLoading, title) {
});
}
+ let reject, resolve;
+
+ let promise = new Promise((res, rej) => {
+ reject = rej
+ resolve = res
+ })
+
uni.request({
url: Vue.prototype.$config.baseUrl + uri,
- data: enhanceData(data),
+ data,
method: method,
header: {
'X-Access-Token': uni.getStorageSync('token'),
'Content-Type' : 'application/x-www-form-urlencoded'
},
success: (res) => {
-
+ // console.log(res,'res')
if(showLoading){
uni.hideLoading();
}
@@ -28,7 +35,7 @@ function http(uri, data, callback, method = 'GET', showLoading, title) {
if(res.statusCode == 401 ||
res.data.message == '操作失败,token非法无效!' ||
res.data.message == '操作失败,用户不存在!'){
- uni.removeStorageSync('token')
+ store.commit('logout')
console.error('登录过期');
utils.toLogin()
}
@@ -42,10 +49,13 @@ function http(uri, data, callback, method = 'GET', showLoading, title) {
icon:'none'
});
}
- callback(res.data)
+
+ callback && callback(res.data)
+ resolve(res.data)
},
fail: () => {
+ reject('api fail')
uni.showLoading({})
setTimeout(()=>{
uni.hideLoading()
@@ -57,79 +67,11 @@ function http(uri, data, callback, method = 'GET', showLoading, title) {
}
}
});
+
+ return promise
}
-function deleted(uri, data, callback) {
- http(uri, data, callback, 'DELETE')
-}
-
-function post(uri, data, callback) {
- http(uri, data, callback, 'POST')
-}
-
-function get(uri, data, callback) {
- http(uri, data, callback, 'GET')
-}
-
-function enhanceData(data) {
- const userid = uni.getStorageSync("userid")
- if (!data) {
- data = {}
- }
- if (userid) {
- data.userid = userid
- }
- return data
-}
-
-
-
-
-
-function sync(method, uri, data) {
- return new Promise((resolve, reject) => {
- uni.request({
- url: uri,
- data: data,
- method: method,
- header: {
- 'auth': '1AS9F1HPC4FBC9EN00J7KX2L5RJ99XHZ'
- },
- success: (res) => {
- resolve(res.data)
- },
- fail: (err) => {
- reject(err);
- }
- })
- })
-}
-
-
-let cache = null
-
-function async (method, uri, data) {
- const promise = sync(method, uri, data).then(res => {
- cache = res
- }).catch(err => {
-
- })
-}
-
-
-function syncHttp(uri, data, method = 'GET') {
- async (method, uri, data)
-}
-
-
-
-
-
export default {
http: http,
- delete: deleted,
- post: post,
- get: get,
- syncHttp: syncHttp
}
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index 3c43639..dc7e3c5 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,6 +1,6 @@
{
"name" : "unapp模板",
- "appid" : "__UNI__FB049D5",
+ "appid" : "__UNI__197A38F",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
diff --git a/mixins/list.js b/mixins/list.js
index a6aa6e9..23bb70e 100644
--- a/mixins/list.js
+++ b/mixins/list.js
@@ -1,22 +1,21 @@
-
-
-
+/**
+ * 处理查询参数
+ * @param {Object} self - 组件实例
+ * @param {Object} queryParams - 额外的查询参数
+ * @returns {Object} 合并后的查询参数
+ */
function query(self, queryParams){
- // return (self.beforeGetData && self.beforeGetData()) ||
- // queryParams || self.queryParams
-
// 深度合并对象
return self.$utils.deepMergeObject(
-
- self.$utils.deepMergeObject(self.queryParams,
-
- (self.beforeGetData && self.beforeGetData()) || {}),
-
- queryParams)
+ self.$utils.deepMergeObject(self.queryParams,
+ (self.beforeGetData && self.beforeGetData()) || {}),
+ queryParams)
}
-
-
+/**
+ * 列表数据加载混入
+ * 提供列表数据的加载、分页、下拉刷新、上拉加载更多等功能
+ */
export default {
data() {
return {
@@ -28,16 +27,24 @@ export default {
list : [],
}
},
+ // 下拉刷新
onPullDownRefresh() {
this.getData()
},
+ // 上拉加载更多
onReachBottom() {
this.loadMoreData()
},
+ // 页面显示时加载数据
onShow() {
this.getData()
},
methods: {
+ /**
+ * 获取列表数据
+ * @param {Object} queryParams - 查询参数
+ * @returns {Promise} 返回Promise对象
+ */
getData(queryParams){
return new Promise((success, error) => {
if(!this.mixinsListApi){
@@ -47,20 +54,21 @@ export default {
query(this, queryParams), res => {
uni.stopPullDownRefresh()
if(res.code == 200){
-
success(res.result)
-
+ // 更新列表数据
this[this.mixinsListKey || 'list'] = res.result.records || res.result
-
+ // 更新总数
this.total = res.result.total || res.result.length
-
+ // 调用数据加载完成的回调
this.getDataThen && this.getDataThen(res.result.records, res.result.total, res.result)
}
})
})
},
+ /**
+ * 加载更多数据
+ */
loadMoreData(){
- console.log('loadMoreData----', this.queryParams.pageSize < this.total);
if(this.queryParams.pageSize < this.total){
this.queryParams.pageSize += 10
this.getData()
diff --git a/pages.json b/pages.json
index 009084e..05f4c9f 100644
--- a/pages.json
+++ b/pages.json
@@ -134,6 +134,12 @@
},
{
"path": "mine/updateUser"
+ },
+ {
+ "path": "order/instantGift"
+ },
+ {
+ "path": "order/giftList"
}
]
}],
diff --git a/pages/index/center.vue b/pages/index/center.vue
index 5f2b011..4d5d93b 100644
--- a/pages/index/center.vue
+++ b/pages/index/center.vue
@@ -137,6 +137,10 @@
我的地址
+
+
+ 礼包列表
+
退出登录
diff --git a/pages/index/order.vue b/pages/index/order.vue
index 3bcff02..161dcdc 100644
--- a/pages/index/order.vue
+++ b/pages/index/order.vue
@@ -182,6 +182,8 @@
.status {
font-weight: 600;
color: #FFAC2F;
+ flex-shrink: 0;
+ margin-left: 20rpx;
}
}
diff --git a/pages_order/order/giftList.vue b/pages_order/order/giftList.vue
new file mode 100644
index 0000000..92ae702
--- /dev/null
+++ b/pages_order/order/giftList.vue
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+ {{ item.state === 0 ? '待领取' : '已领取' }}
+
+
+
+
+
+
+
+
+
+
+ 赠送人:{{item.senderName}}
+
+
+ 赠送时间:{{item.createTime}}
+
+
+ 祝福语:{{item.message}}
+
+
+
+
+
+
+
+ 礼包价值:
+ ¥
+ {{item.price}}
+ 元
+
+
+
+ 立即领取
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages_order/order/instantGift.vue b/pages_order/order/instantGift.vue
new file mode 100644
index 0000000..b4c1d48
--- /dev/null
+++ b/pages_order/order/instantGift.vue
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+ 送祝福给TA
+
+
+
+
+
+
+
+ 距离礼包失效:{{countdownText}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages_order/order/receiveGift.vue b/pages_order/order/receiveGift.vue
new file mode 100644
index 0000000..5d4e4b5
--- /dev/null
+++ b/pages_order/order/receiveGift.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{giftInfo.name}}
+
+ 礼品价值:
+ ¥{{giftInfo.price}}
+
+
+
+
+
+
+ 来自
+ {{giftInfo.senderName}}
+ 的祝福
+
+
+ {{giftInfo.message}}
+
+
+
+
+
+ 距离礼包失效:{{countdownText}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages_order/product/productDetail.vue b/pages_order/product/productDetail.vue
index abdbd49..cc76241 100644
--- a/pages_order/product/productDetail.vue
+++ b/pages_order/product/productDetail.vue
@@ -96,7 +96,11 @@
-
+
@@ -142,6 +146,9 @@
this.$utils.navigateTo('/pages_order/order/createOrder')
},
+ toSend(){
+ this.$utils.navigateTo('/pages_order/order/instantGift')
+ },
// 获取商品
getRiceProductDetail() {
this.$api('getRiceProductDetail', {
diff --git a/store/store.js b/store/store.js
index d0cb825..d07d3ce 100644
--- a/store/store.js
+++ b/store/store.js
@@ -124,7 +124,6 @@ const store = new Vuex.Store({
success(r) {
if (r.confirm) {
state.userInfo = {}
- state.role = false
uni.removeStorageSync('token')
uni.reLaunch({
url: '/pages/index/index'
diff --git a/utils/pay.js b/utils/pay.js
index 9f97091..a41698d 100644
--- a/utils/pay.js
+++ b/utils/pay.js
@@ -3,26 +3,35 @@
import jWeixin from './lib/jweixin-module.js'
// #endif
+/**
+ * 调用微信支付
+ * @param {Object} res - 支付参数对象,包含appId、timeStamp、nonceStr等必要信息
+ * @param {Function} successCallback - 支付成功的回调函数
+ * @param {Function} failCallback - 支付失败的回调函数
+ * @param {Function} optionCallback - 配置失败的回调函数
+ */
export function wxPay(res, successCallback, failCallback, optionCallback) {
+ // 配置微信JSSDK
jWeixin.config({
debug: false,
- appId: res.result.appId, //必填
- jsApiList: ['chooseWXPay']
+ appId: res.result.appId, //必填,公众号的唯一标识
+ jsApiList: ['chooseWXPay'] //必填,需要使用的JS接口列表
});
+ // JSSDK配置成功后的回调
jWeixin.ready(function() {
+ // 调用微信支付接口
jWeixin.chooseWXPay({
appId: res.result.appId,
- timestamp: res.result
- .timeStamp, // 支付签名时间戳,注意微信 jssdk 中的所有使用 timestamp 字段均为小写。但最新版的支付后台生成签名使用的 timeStamp 字段名需大写其中的 S 字符
- nonceStr: res.result.nonceStr, // 支付签名随机串,不长于 32 位
- package: res.result.packageValue, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
- signType: res.result.signType, // 微信支付V3的传入 RSA ,微信支付V2的传入格式与V2统一下单的签名格式保持一致
+ timestamp: res.result.timeStamp, // 支付签名时间戳
+ nonceStr: res.result.nonceStr, // 支付签名随机串
+ package: res.result.packageValue, // 统一支付接口返回的prepay_id参数值
+ signType: res.result.signType, // 签名类型,默认为MD5
paySign: res.result.paySign, // 支付签名
- success: function() { // 支付成功取消处理
+ success: function() {
successCallback && successCallback();
},
- fail: function(error) { // 支付失败或取消处理
+ fail: function(error) {
failCallback && failCallback();
},
cancel : function(){
@@ -31,9 +40,8 @@ export function wxPay(res, successCallback, failCallback, optionCallback) {
});
});
+ // JSSDK配置失败处理
jWeixin.error(function(res) {
- // 配置失败处理
optionCallback && optionCallback()
});
-
-}
\ No newline at end of file
+}
diff --git a/utils/utils.js b/utils/utils.js
index 2b07dde..2dd6729 100644
--- a/utils/utils.js
+++ b/utils/utils.js
@@ -1,3 +1,8 @@
+/**
+ * 将数据转换为数组格式
+ * @param {any} data - 需要转换的数据
+ * @returns {Array} 转换后的数组
+ */
function toArray(data) {
if (!data) return []
if (data instanceof Array){
@@ -7,6 +12,10 @@ function toArray(data) {
}
}
+/**
+ * 生成UUID
+ * @returns {string} 生成的UUID字符串
+ */
function generateUUID() {
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
@@ -15,6 +24,10 @@ function generateUUID() {
});
}
+/**
+ * 生成随机颜色
+ * @returns {string} 生成的十六进制颜色值
+ */
function generateRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
@@ -24,6 +37,10 @@ function generateRandomColor() {
return color;
}
+/**
+ * 生成浅色系的随机颜色
+ * @returns {string} 生成的RGB格式颜色值
+ */
function generateLightRandomColor() {
const min = 150;
const range = 105;
@@ -34,6 +51,12 @@ function generateLightRandomColor() {
return color;
}
+/**
+ * 表单数据验证
+ * @param {Object} data - 需要验证的表单数据
+ * @param {Object} msg - 验证失败时的提示信息
+ * @returns {boolean} 验证结果,true表示验证失败,false表示验证通过
+ */
function verificationAll(data, msg){
if (!msg){
@@ -57,39 +80,14 @@ function verificationAll(data, msg){
return true
}
}
-
-
- // let Msgs = {
- // default : msg || '表单数据未填写'
- // }
-
- // if(typeof msg == 'object'){
- // Msgs = {
- // default : '表单数据未填写',
- // ...msg,
- // }
- // }
-
- // if (!data){
- // uni.showToast({
- // title: Msgs.default,
- // icon: "none"
- // })
- // return true
- // }
- // for (let key in data) {
- // if (!data[key] || data[key] === "") {
- // uni.showToast({
- // title: (Msgs[key] || Msgs.default),
- // icon: "none"
- // })
- // return true
- // }
- // }
return false
}
-//验证手机号是否合法
+/**
+ * 验证手机号是否合法
+ * @param {string} phone - 需要验证的手机号
+ * @returns {boolean} 验证结果,true表示合法,false表示不合法
+ */
function verificationPhone(phone){
if(!/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(phone)){
return false
@@ -98,6 +96,11 @@ function verificationPhone(phone){
}
//获取url中参数的方法
+/**
+ * 获取URL中指定参数的值
+ * @param {string} name - 参数名称
+ * @returns {string} 参数值,如果不存在则返回空字符串
+ */
export function getHrefParams(name) {
var url = window.location.href;
try {
@@ -114,8 +117,12 @@ export function getHrefParams(name) {
}
}
-
-//深度对比合并两个对象,相同属性b会覆盖a
+/**
+ * 深度合并两个对象,相同属性b会覆盖a
+ * @param {Object} a - 目标对象
+ * @param {Object} b - 源对象
+ * @returns {Object} 合并后的新对象
+ */
export function deepMergeObject(a, b){
let data = JSON.parse(JSON.stringify(a))
function mergeObject(obj1, obj2){
@@ -131,7 +138,10 @@ export function deepMergeObject(a, b){
return mergeObject(data, b)
}
-//复制内容
+/**
+ * 复制文本到剪贴板
+ * @param {string} content - 要复制的内容
+ */
export function copyText(content) {
uni.setClipboardData({
data: content,
@@ -144,12 +154,21 @@ export function copyText(content) {
})
}
-// 将字符串中的文本格式化html
+/**
+ * 将字符串中的文本格式化为HTML
+ * @param {string} str - 需要格式化的字符串
+ * @returns {string} 格式化后的HTML字符串
+ */
export function stringFormatHtml(str){
return str && str.replace(/\n/gi, '
')
.replace(/ /gi, ' ')
}
+/**
+ * 处理页面导航参数
+ * @param {string|Object} url - 页面路径或导航参数对象
+ * @returns {Object} 处理后的导航参数对象
+ */
function params(url){
if(typeof url == 'object'){
return url
@@ -166,18 +185,34 @@ function params(url){
return data
}
-
+/**
+ * 页面导航方法
+ * @param {...any} args - 导航参数
+ */
export function navigateTo(...args){
uni.navigateTo(params(...args))
}
+/**
+ * 返回上一页
+ * @param {number} num - 返回的页面数,默认为-1
+ */
export function navigateBack(num = -1){
uni.navigateBack(num)
}
+/**
+ * 重定向到指定页面
+ * @param {...any} args - 导航参数
+ */
export function redirectTo(...args){
uni.redirectTo(params(...args))
}
+
+/**
+ * 登录跳转函数,防止短时间内多次调用
+ * @returns {Function} 节流处理后的登录跳转函数
+ */
export const toLogin = function(){
let time = 0
return () => {