diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33cf0f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +.DS_Store +node_modules/ +/dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +/unpackage/ + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..d354d28 --- /dev/null +++ b/App.vue @@ -0,0 +1,451 @@ + + + diff --git a/README.md b/README.md index 208f2de..13b3b46 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,89 @@ # mall-app-web -mall-app-web是一个电商系统的移动端项目,基于uni-app实现。主要包括首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等功能。 +

+ 公众号 + 交流 + 后台项目 + 前端项目 + 码云 +

+ +## 前言 + +该项目为前后端分离项目的前端部分,后端项目`mall`地址:[传送门](https://github.com/macrozheng/mall)。 + +## 项目介绍 + +`mall-app-web`是一个电商系统的移动端项目,基于`uni-app`实现。主要包括首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等功能。 + +### 项目演示 + +项目在线演示地址:[http://www.macrozheng.com/app/](http://www.macrozheng.com/app/) + +![](../images/mall_app_web_preview_01.png)![](../images/mall_app_web_preview_02.png) + +![](../images/mall_app_web_preview_03.png)![](../images/mall_app_web_preview_04.png) + +![](../images/mall_app_web_preview_05.png)![](../images/mall_app_web_preview_06.png) + +![](../images/mall_app_web_preview_07.png)![](../images/mall_app_web_preview_08.png) + +### 技术选型 + +| 技术 | 说明 | 官网 | +| ------------ | ---------------- | --------------------------------------- | +| Vue | 核心前端框架 | https://vuejs.org | +| Vuex | 全局状态管理框架 | https://vuex.vuejs.org | +| uni-app | 移动端前端框架 | https://uniapp.dcloud.io | +| mix-mall | 电商项目模板 | https://ext.dcloud.net.cn/plugin?id=200 | +| luch-request | HTTP请求框架 | https://github.com/lei-mu/luch-request | + +### 项目结构 + +``` lua +src -- 源码目录 +├── api -- luch-request网络请求定义 +├── components -- 通用组件封装 +├── js_sdk -- 第三方sdk源码 +├── static -- 图片等静态资源 +├── store -- vuex的状态管理 +├── utils -- 工具类 +└── pages -- 前端页面 + ├── address -- 地址管理页 + ├── brand -- 商品品牌页 + ├── cart -- 购物车页 + ├── category -- 商品分类页 + ├── coupon -- 优惠券页 + ├── index -- 首页 + ├── money -- 支付页 + ├── notice -- 通知页 + ├── order -- 订单页 + ├── product -- 商品页 + ├── public -- 登录页 + ├── set -- 设置页 + ├── user -- 会员页 + └── userinfo -- 会员信息页 +``` + +## 搭建步骤 + +- 本项目使用了`uni-app`专用开发工具`HBuilder X`(App开发版)开发,下载地址:https://www.dcloud.io/hbuilderx.html +- 该项目为前后端分离项目,访问本地访问接口需搭建后台环境,搭建请参考后端项目[传送门](https://github.com/macrozheng/mall); +- 注意由于`mall-app-web`中的接口都在`mall-portal`模块中,所以一定要启动该模块; +- 访问在线接口无需搭建后台环境,只需将`utils/requestUtil.js`文件中的`config.baseUrl`改为线上地址即可:http://portal-api.macrozheng.com +- 克隆源代码到本地,使用`HBuilder X`打开; +- 在`HBuilder X`中使用`运行->运行到浏览器->Chrome`运行项目,运行成功后会自动打开下面地址(将浏览器改为手机模式):http://localhost:8080 +- 如果浏览器没有启动的话,可以直接访问如下地址访问:http://localhost:8080 + +## 公众号 + +学习不走弯路,关注公众号「**macrozheng**」,回复「**学习路线**」,获取mall项目专属学习路线! + +加微信群交流,公众号后台回复「**加群**」即可。 + +![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg) + +## 许可证 + +[Apache License 2.0](https://github.com/macrozheng/mall/blob/master/LICENSE) + +Copyright (c) 2020-2021 macrozheng \ No newline at end of file diff --git a/api/address.js b/api/address.js new file mode 100644 index 0000000..04053fd --- /dev/null +++ b/api/address.js @@ -0,0 +1,39 @@ +import request from '@/utils/requestUtil' + +export function fetchAddressList() { + return request({ + method: 'GET', + url: '/member/address/list' + }) +} + +export function fetchAddressDetail(id) { + return request({ + method: 'GET', + url: `/member/address/${id}` + }) +} + +export function addAddress(data) { + return request({ + method: 'POST', + url: '/member/address/add', + data:data + }) +} + +export function updateAddress(data) { + return request({ + method: 'POST', + url: `/member/address/update/${data.id}`, + data:data + }) +} + +export function deleteAddress(id) { + return request({ + method: 'POST', + url: `/member/address/delete/${id}` + }) +} + diff --git a/api/brand.js b/api/brand.js new file mode 100644 index 0000000..fe2e7c8 --- /dev/null +++ b/api/brand.js @@ -0,0 +1,24 @@ +import request from '@/utils/requestUtil' + +export function getBrandDetail(id) { + return request({ + method: 'GET', + url: `/brand/detail/${id}`, + }) +} + +export function fetchBrandProductList(params) { + return request({ + method: 'GET', + url: '/brand/productList', + params:params + }) +} + +export function fetchBrandRecommendList(params) { + return request({ + method: 'GET', + url: '/brand/recommendList', + params:params + }) +} \ No newline at end of file diff --git a/api/cart.js b/api/cart.js new file mode 100644 index 0000000..8050d18 --- /dev/null +++ b/api/cart.js @@ -0,0 +1,39 @@ +import request from '@/utils/requestUtil' + +export function addCartItem(data) { + return request({ + method: 'POST', + url: '/cart/add', + data: data + }) +} + +export function fetchCartList() { + return request({ + method: 'GET', + url: '/cart/list' + }) +} + +export function deletCartItem(params) { + return request({ + method: 'POST', + url: '/cart/delete', + params:params + }) +} + +export function updateQuantity(params) { + return request({ + method: 'GET', + url: '/cart/update/quantity', + params:params + }) +} + +export function clearCartList() { + return request({ + method: 'POST', + url: '/cart/clear' + }) +} \ No newline at end of file diff --git a/api/coupon.js b/api/coupon.js new file mode 100644 index 0000000..376ac27 --- /dev/null +++ b/api/coupon.js @@ -0,0 +1,23 @@ +import request from '@/utils/requestUtil' + +export function fetchProductCouponList(productId) { + return request({ + method: 'GET', + url: `/member/coupon/listByProduct/${productId}`, + }) +} + +export function addMemberCoupon(couponId) { + return request({ + method: 'POST', + url: `/member/coupon/add/${couponId}`, + }) +} + +export function fetchMemberCouponList(useStatus) { + return request({ + method: 'GET', + url: '/member/coupon/list', + params:{useStatus:useStatus} + }) +} \ No newline at end of file diff --git a/api/home.js b/api/home.js new file mode 100644 index 0000000..4866f5c --- /dev/null +++ b/api/home.js @@ -0,0 +1,39 @@ +import request from '@/utils/requestUtil' + +export function fetchContent() { + return request({ + method: 'GET', + url: '/home/content' + }) +} + +export function fetchRecommendProductList(params) { + return request({ + method: 'GET', + url: '/home/recommendProductList', + params:params + }) +} + +export function fetchProductCateList(parentId) { + return request({ + method: 'GET', + url: '/home/productCateList/'+parentId, + }) +} + +export function fetchNewProductList(params) { + return request({ + method: 'GET', + url: '/home/newProductList', + params:params + }) +} + +export function fetchHotProductList(params) { + return request({ + method: 'GET', + url: '/home/hotProductList', + params:params + }) +} diff --git a/api/member.js b/api/member.js new file mode 100644 index 0000000..149b24d --- /dev/null +++ b/api/member.js @@ -0,0 +1,19 @@ +import request from '@/utils/requestUtil' + +export function memberLogin(data) { + return request({ + method: 'POST', + url: '/sso/login', + header: { + 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' + }, + data: data + }) +} + +export function memberInfo() { + return request({ + method: 'GET', + url: '/sso/info' + }) +} diff --git a/api/memberBrandAttention.js b/api/memberBrandAttention.js new file mode 100644 index 0000000..b95bb6c --- /dev/null +++ b/api/memberBrandAttention.js @@ -0,0 +1,40 @@ +import request from '@/utils/requestUtil' + +export function createBrandAttention(data) { + return request({ + method: 'POST', + url: '/member/attention/add', + data: data + }) +} + +export function deleteBrandAttention(params) { + return request({ + method: 'POST', + url: '/member/attention/delete', + params: params + }) +} + +export function fetchBrandAttentionList(params) { + return request({ + method: 'GET', + url: '/member/attention/list', + params:params + }) +} + +export function brandAttentionDetail(params) { + return request({ + method: 'GET', + url: '/member/attention/detail', + params: params + }) +} + +export function clearBrandAttention() { + return request({ + method: 'POST', + url: '/member/attention/clear' + }) +} \ No newline at end of file diff --git a/api/memberProductCollection.js b/api/memberProductCollection.js new file mode 100644 index 0000000..6b16519 --- /dev/null +++ b/api/memberProductCollection.js @@ -0,0 +1,40 @@ +import request from '@/utils/requestUtil' + +export function createProductCollection(data) { + return request({ + method: 'POST', + url: '/member/productCollection/add', + data: data + }) +} + +export function deleteProductCollection(params) { + return request({ + method: 'POST', + url: '/member/productCollection/delete', + params: params + }) +} + +export function fetchProductCollectionList(params) { + return request({ + method: 'GET', + url: '/member/productCollection/list', + params:params + }) +} + +export function productCollectionDetail(params) { + return request({ + method: 'GET', + url: '/member/productCollection/detail', + params: params + }) +} + +export function clearProductCollection() { + return request({ + method: 'POST', + url: '/member/productCollection/clear' + }) +} \ No newline at end of file diff --git a/api/memberReadHistory.js b/api/memberReadHistory.js new file mode 100644 index 0000000..934bd95 --- /dev/null +++ b/api/memberReadHistory.js @@ -0,0 +1,24 @@ +import request from '@/utils/requestUtil' + +export function createReadHistory(data) { + return request({ + method: 'POST', + url: '/member/readHistory/create', + data: data + }) +} + +export function fetchReadHistoryList(params) { + return request({ + method: 'GET', + url: '/member/readHistory/list', + params: params + }) +} + +export function clearReadHistory() { + return request({ + method: 'POST', + url: '/member/readHistory/clear' + }) +} \ No newline at end of file diff --git a/api/order.js b/api/order.js new file mode 100644 index 0000000..4d34ab8 --- /dev/null +++ b/api/order.js @@ -0,0 +1,76 @@ +import request from '@/utils/requestUtil' + +export function generateConfirmOrder(data) { + return request({ + method: 'POST', + url: '/order/generateConfirmOrder', + data: data + }) +} + +export function generateOrder(data) { + return request({ + method: 'POST', + url: '/order/generateOrder', + data: data + }) +} + +export function fetchOrderList(params) { + return request({ + method: 'GET', + url: '/order/list', + params: params + }) +} + +export function payOrderSuccess(data) { + return request({ + method: 'POST', + url: '/order/paySuccess', + header: { + 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' + }, + data: data + }) +} + +export function fetchOrderDetail(orderId) { + return request({ + method: 'GET', + url: `/order/detail/${orderId}` + }) +} + +export function cancelUserOrder(data) { + return request({ + method: 'POST', + url: '/order/cancelUserOrder', + header: { + 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' + }, + data: data + }) +} + +export function confirmReceiveOrder(data) { + return request({ + method: 'POST', + url: '/order/confirmReceiveOrder', + header: { + 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' + }, + data: data + }) +} + +export function deleteUserOrder(data) { + return request({ + method: 'POST', + url: '/order/deleteOrder', + header: { + 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' + }, + data: data + }) +} \ No newline at end of file diff --git a/api/product.js b/api/product.js new file mode 100644 index 0000000..506544f --- /dev/null +++ b/api/product.js @@ -0,0 +1,23 @@ +import request from '@/utils/requestUtil' + +export function searchProductList(params) { + return request({ + method: 'GET', + url: '/product/search', + params: params + }) +} + +export function fetchCategoryTreeList() { + return request({ + method: 'GET', + url: '/product/categoryTreeList' + }) +} + +export function fetchProductDetail(id) { + return request({ + method: 'GET', + url: '/product/detail/'+id + }) +} diff --git a/components/empty.vue b/components/empty.vue new file mode 100644 index 0000000..4da4df0 --- /dev/null +++ b/components/empty.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/components/mix-list-cell.vue b/components/mix-list-cell.vue new file mode 100644 index 0000000..a60259c --- /dev/null +++ b/components/mix-list-cell.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/components/mix-loading/mix-loading.vue b/components/mix-loading/mix-loading.vue new file mode 100644 index 0000000..3c38afe --- /dev/null +++ b/components/mix-loading/mix-loading.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/components/share.vue b/components/share.vue new file mode 100644 index 0000000..074cd7d --- /dev/null +++ b/components/share.vue @@ -0,0 +1,202 @@ + + + + + diff --git a/components/uni-load-more/uni-load-more.vue b/components/uni-load-more/uni-load-more.vue new file mode 100644 index 0000000..6c43365 --- /dev/null +++ b/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,194 @@ + + + + + \ No newline at end of file diff --git a/components/uni-number-box.vue b/components/uni-number-box.vue new file mode 100644 index 0000000..8f626ac --- /dev/null +++ b/components/uni-number-box.vue @@ -0,0 +1,199 @@ + + + diff --git a/components/upload-images.vue b/components/upload-images.vue new file mode 100644 index 0000000..71bb4a3 --- /dev/null +++ b/components/upload-images.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/js_sdk/luch-request/readme.md b/js_sdk/luch-request/readme.md new file mode 100644 index 0000000..8732fd3 --- /dev/null +++ b/js_sdk/luch-request/readme.md @@ -0,0 +1,317 @@ +**插件使用说明** + +- 基于 Promise 对象实现更简单的 request 使用方式,支持请求和响应拦截 +- 支持全局挂载 +- 支持多个全局配置实例 +- 支持自定义验证器 +- 支持文件上传(如不使用可以删除class里upload 方法) +- 支持` typescript `、` javascript ` 版本(如果不使用ts版本,则可以把luch-request-ts 文件夹删除) +- 下载后把 http-request 文件夹放到项目 utils/ 目录下 + + +**Example** +--- +创建实例 + +``` javascript +const http = new Request(); +``` + +执行` GET `请求 + +``` javascript +http.get('/user/login', {params: {userName: 'name', password: '123456'}}).then(res => { + +}).catch(err => { + +}) +// 局部修改配置,局部配置优先级高于全局配置 +http.get('/user/login', { + params: {userName: 'name', password: '123456'}, /* 会加在url上 */ + header: {}, /* 会覆盖全局header */ + dataType: 'json', + // 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部) + custom: {auth: true}, // 可以加一些自定义参数,在拦截器等地方使用。比如这里我加了一个auth,可在拦截器里拿到,如果true就传token + // #ifndef MP-ALIPAY || APP-PLUS + responseType: 'text', + // #endif + // #ifdef MP-ALIPAY + timeout: 30000, // 仅支付宝小程序支持 + // #endif + // #ifdef APP-PLUS + sslVerify: true // 验证 ssl 证书 仅5+App安卓端支持(HBuilderX 2.3.3+) + // #endif +}).then(res => { + +}).catch(err => { + +}) +``` +执行` POST `请求 + +``` javascript +http.post('/user/login', {userName: 'name', password: '123456'} ).then(res => { + +}).catch(err => { + +}) +// 局部修改配置,局部配置优先级高于全局配置 +http.post('/user/login', {userName: 'name', password: '123456'}, { + params: {}, /* 会加在url上 */ + header: {}, /* 会覆盖全局header */ + dataType: 'json', + // 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部) + custom: {auth: true}, // 可以加一些自定义参数,在拦截器等地方使用。比如这里我加了一个auth,可在拦截器里拿到,如果true就传token + // #ifndef MP-ALIPAY || APP-PLUS + responseType: 'text', + // #endif + // #ifdef MP-ALIPAY + timeout: 30000, // 仅支付宝小程序支持 + // #endif + // #ifdef APP-PLUS + sslVerify: true // 验证 ssl 证书 仅5+App安卓端支持(HBuilderX 2.3.3+) + // #endif +}).then(res => { + +}).catch(err => { + +}) +``` +执行` upload `请求 + +``` javascript +http.upload('api/upload/img', { + files: [], // 仅5+App支持 + fileType:'image/video/audio', // 仅支付宝小程序,且必填。 + filePath: '', // 要上传文件资源的路径。 + // 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部) + custom: {auth: true}, // 可以加一些自定义参数,在拦截器等地方使用。比如这里我加了一个auth,可在拦截器里拿到,如果true就传token + name: 'file', // 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容 + header: {}, + formData: {}, // HTTP 请求中其他额外的 form data +}).then(res => { + +}).catch(err => { + +}) +``` +**luch-request API** +-- +``` javascript +http.request({ + method: 'POST', // 请求方法必须大写 + url: '/user/12345', + data: { + firstName: 'Fred', + lastName: 'Flintstone' + }, + params: { // 会拼接到url上 + token: '1111' + }, + // 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部) + custom: {} // 自定义参数 +}) + +具体参数说明:[uni.uploadFile](https://uniapp.dcloud.io/api/request/network-file) +http.upload('api/upload/img', { + files: [], // 仅5+App支持 + fileType:'image/video/audio', // 仅支付宝小程序,且必填。 + filePath: '', // 要上传文件资源的路径。 + name: 'file', // 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容 + header: {}, // 如填写,会覆盖全局header, + custom: {} // 自定义参数 + formData: {}, // HTTP 请求中其他额外的 form data +}) +``` + + +请求方法别名 / 实例方法 + +``` javascript +http.request(config) +http.get(url[, config]) +http.upload(url[, config]) +http.delete(url[, data[, config]]) +http.head(url[, data[, config]]) +http.post(url[, data[, config]]) +http.put(url[, data[, config]]) +http.connect(url[, data[, config]]) +http.options(url[, data[, config]]) +http.trace(url[, data[, config]]) +``` + +**全局请求配置** +-- +``` javascript +{ + baseUrl: '', + header: { + 'content-type': 'application/json;charset=UTF-8' + }, + method: 'GET', + dataType: 'json', + // #ifndef MP-ALIPAY || APP-PLUS + responseType: 'text', + // #endif + // 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部) + custom: {}, // 全局自定义参数默认值 + // #ifdef MP-ALIPAY + timeout: 30000, + // #endif + // #ifdef APP-PLUS + sslVerify: true + // #endif +} +``` + + +全局配置修改` setConfig ` + +``` javascript +/** + * @description 修改全局默认配置 + * @param {Function} +*/ +http.setConfig((config) => { /* config 为默认全局配置*/ + config.baseUrl = 'http://www.bbb.cn'; /* 根域名 */ + config.header = { + a: 1, + b: 2 + } + return config +}) +``` + +自定义验证器` validateStatus ` + +``` javascript +/** + * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject) + * @param { Number } statusCode - 请求响应体statusCode(只读) + * @return { Boolean } 如果为true,则 resolve, 否则 reject +*/ +http.validateStatus = (statusCode) => { // 默认 + return statusCode === 200 +} + +// 举个栗子 +http.validateStatus = (statusCode) => { + return statusCode && statusCode >= 200 && statusCode < 300 +} +``` + +**拦截器** +-- + +在请求之前拦截 + +``` javascript +/** + * @param { Function} cancel - 取消请求,调用cancel 会取消本次请求,但是该函数的catch() 仍会执行; 不会进入响应拦截器 + * + * @param {String} text ['handle cancel'| any] - catch((err) => {}) err.errMsg === 'handle cancel'。非必传,默认'handle cancel' + * @cancel {Object} config - catch((err) => {}) err.config === config; 非必传,默认为request拦截器修改之前的config + * function cancel(text, config) {} + */ +http.interceptor.request((config, cancel) => { /* cancel 为函数,如果调用会取消本次请求。需要注意:调用cancel,本次请求的catch仍会执行。必须return config */ + config.header = { + ...config.header, + a: 1 + } + // if (config.custom.auth) { + // config.header.token = 'token' + // } + if (!token) { // 如果token不存在,调用cancel 会取消本次请求,但是该函数的catch() 仍会执行 + cancel('token 不存在', config) // 把修改后的config传入,之后响应就可以拿到修改后的config。 如果调用了cancel但是不传修改后的config,则catch((err) => {}) err.config 为request拦截器修改之前的config + } + */ + return config; +}) +``` + +在请求之后拦截 + +``` javascript +http.interceptor.response((response) => { /* 对响应成功做点什么 (statusCode === 200),必须return response*/ + // if (response.data.code !== 200) { // 服务端返回的状态码不等于200,则reject() + // return Promise.reject(response) + // } + // if (response.config.custom.verification) { // 演示自定义参数的作用 + // return response.data + // } + console.log(response) + return response +}, (response) => { /* 对响应错误做点什么 (statusCode !== 200),必须return response*/ + console.log(response) + return response +}) +``` + +**typescript使用** +-- +在` request.ts `里还暴露了五个接口 +```javascript +{ + options, // request 方法配置参数 + handleOptions, // get/post 方法配置参数 + config, // init 全局config接口(setConfig 参数接口) + requestConfig, // 请求之前参数配置项 + response // 响应体 +} +``` + +**常见问题** +-- +1. 为什么会请求两次? + - 总有些小白问这些很那啥的问题,有两种可能,一种是‘post三次握手’(不知道的请先给个五星好评,然后打自己一巴掌,并问自己,为什么这都不知道),还有一种可能是`本地访问接口时跨域请求,所以浏览器会先发一个option 去预测能否成功,然后再发一个真正的请求`(没有自己观察请求头,Request Method,就跑来问的,请再打自己一巴掌,并问自己,为什么这都不知道,不知道也行,为什么不百度)。 +2. 如何跨域? + - 问的人不少,可以先百度了解一下。如何跨域 +3. post 怎么传不了数组的参数啊? + - uni-request
+ 可以点击看一下uni-request 的api 文档,data支持的文件类型只有Object/String/ArrayBuffer这个真跟我没啥关系 0.0 +4. 'Content-Type' 为什么要小写? + - hbuilderX 更新至‘2.3.0.20190919’ 后,uni.request post请求,如果 ‘Content-Type’ 大写,就会在后面自动拼接‘ application/json’,请求头变成 + `Content-Type: application/json;charset=UTF-8 application/json`,导致后端无法解析类型,`Status Code 415`,post 请求失败。但是小写就不会出现这个问题。至于为什么我也没有深究,我现在也不清楚这是他们的bug,还是以后就这样规范了。我能做的只有立马兼容,至于后边uni官方会不会继续变动也不清楚。 +5. 为什么不支持task? + - 一方面精力有限,另一方面违背了本人的一些意愿,具体看第6条 +6. 为什么不能配置超时时间? + - 配置超时时间,请求时需要task,并且每个请求都需要创建一个定时器,本人认为这个消耗没必要。设置超时时间可以通过manifest.json 配置进行设置。我想用的就是一个小而简单的请求插件。 + + +**tip** +-- +- 不想使用upload 可把class 里的upload 删除 + + +**issue** +-- +有任何问题或者建议可以=> issue提交,先给个五星好评QAQ!! + + +**作者想说** +-- +- 主体代码9kb +- 目前该插件已经上项目,遇到任何问题请先检查自己的代码(排除新版本发布的情况)。最近新上了` typescript ` 版本,因为本人没使用过ts,所以写的不好的地方,还请见谅~ +- 写代码很容易,为了让你们看懂写文档真的很lei 0.0 +- 最近发现有插件与我雷同,当初接触uni-app 就发现插件市场虽然有封装的不错的request库,但是都没有对多全局配置做处理,都是通过修改源码的方式配置。我首先推出通过class类,并仿照axios的api实现request请求库,并起名‘仿axios封装request网络请求库,支持拦截器全局配置’。他们虽然修改了部分代码,但是功能与性能并没有优化,反而使代码很冗余。希望能推出新的功能,和性能更加强悍的请求库。 +- 任何形式的‘参考’、‘借鉴’,请标明作者 + ```javascript + luch-request + ``` +- 关于问问题 +1. 首先请善于利用搜索引擎,不管百度,还是Google,遇到问题请先自己尝试解决。自己尝试过无法解决,再问。 +2. 不要问类似为什么我的xx无法使用这种问题。请仔细阅读文档,检查代码,或者说明运行环境,把相关代码贴至评论或者发送至我的邮箱,还可以点击上面的issue提交,在里面提问,可能我在里面已经回答了。 +3. 我的代码如果真的出现bug,或者你有好的建议、需求,可以提issue,我看到后会立即解决 +4. 不要问一些弱智问题!!! +- 如何问问题 +1. 仔细阅读文档,检查代码 +2. 说明运行环境,比如:app端 ios、android 版本号、手机机型、普遍现象还是个别现象(越详细越好) +3. 发出代码片段或者截图至邮箱(很重要) +4. 或者可以在上方的'issue提交' 里发出详细的问题描述 +5. 以上都觉得解决不了你的问题,可以加QQ:`370306150` + +**土豪赞赏** +-- + + +####创作不易,五星好评你懂得! diff --git a/js_sdk/luch-request/request.js b/js_sdk/luch-request/request.js new file mode 100644 index 0000000..17b3246 --- /dev/null +++ b/js_sdk/luch-request/request.js @@ -0,0 +1,339 @@ +/** + * Request 1.0.5 + * @Class Request + * @description luch-request 1.0.4 http请求插件 + * @Author lu-ch + * @Date 2019-12-12 + * @Email webwork.s@qq.com + * http://ext.dcloud.net.cn/plugin?id=392 + */ +export default class Request { + config = { + baseUrl: '', + header: { + 'content-type': 'application/json;charset=UTF-8' + }, + method: 'GET', + dataType: 'json', + // #ifndef MP-ALIPAY || APP-PLUS + responseType: 'text', + // #endif + custom: {}, + // #ifdef MP-ALIPAY + timeout: 30000, + // #endif + // #ifdef APP-PLUS + sslVerify: true + // #endif + } + + static posUrl (url) { /* 判断url是否为绝对路径 */ + return /(http|https):\/\/([\w.]+\/?)\S*/.test(url) + } + + static addQueryString (params) { + let paramsData = '' + Object.keys(params).forEach(function (key) { + paramsData += key + '=' + encodeURIComponent(params[key]) + '&' + }) + return paramsData.substring(0, paramsData.length - 1) + } + + /** + * @property {Function} request 请求拦截器 + * @property {Function} response 响应拦截器 + * @type {{request: Request.interceptor.request, response: Request.interceptor.response}} + */ + interceptor = { + /** + * @param {Request~requestCallback} cb - 请求之前拦截,接收一个函数(config, cancel)=> {return config}。第一个参数为全局config,第二个参数为函数,调用则取消本次请求。 + */ + request: (cb) => { + if (cb) { + this.requestBeforeFun = cb + } + }, + /** + * @param {Request~responseCallback} cb 响应拦截器,对响应数据做点什么 + * @param {Request~responseErrCallback} ecb 响应拦截器,对响应错误做点什么 + */ + response: (cb, ecb) => { + if (cb && ecb) { + this.requestComFun = cb + this.requestComFail = ecb + } + } + } + + requestBeforeFun (config) { + return config + } + + requestComFun (response) { + return response + } + + requestComFail (response) { + return response + } + + /** + * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject) + * @param { Number } statusCode - 请求响应体statusCode(只读) + * @return { Boolean } 如果为true,则 resolve, 否则 reject + */ + validateStatus (statusCode) { + return statusCode === 200 + } + + /** + * @Function + * @param {Request~setConfigCallback} f - 设置全局默认配置 + */ + setConfig (f) { + this.config = f(this.config) + } + + /** + * @Function + * @param {Object} options - 请求配置项 + * @prop {String} options.url - 请求路径 + * @prop {Object} options.data - 请求参数 + * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型 + * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse + * @prop {Object} [options.header = config.header] - 请求header + * @prop {Object} [options.method = config.method] - 请求方法 + * @returns {Promise} + */ + async request (options = {}) { + options.baseUrl = this.config.baseUrl + options.dataType = options.dataType || this.config.dataType + // #ifndef MP-ALIPAY || APP-PLUS + options.responseType = options.responseType || this.config.responseType + // #endif + // #ifdef MP-ALIPAY + options.timeout = options.timeout || this.config.timeout + // #endif + options.url = options.url || '' + options.data = options.data || {} + options.params = options.params || {} + options.header = options.header || this.config.header + options.method = options.method || this.config.method + options.custom = { ...this.config.custom, ...(options.custom || {}) } + // #ifdef APP-PLUS + options.sslVerify = options.sslVerify === undefined ? this.config.sslVerify : options.sslVerify + // #endif + return new Promise((resolve, reject) => { + let next = true + + let handleRe = {} + options.complete = (response) => { + response.config = handleRe + if (this.validateStatus(response.statusCode)) { // 成功 + response = this.requestComFun(response) + resolve(response) + } else { + response = this.requestComFail(response) + reject(response) + } + } + const cancel = (t = 'handle cancel', config = options) => { + const err = { + errMsg: t, + config: config + } + reject(err) + next = false + } + + handleRe = { ...this.requestBeforeFun(options, cancel) } + const _config = { ...handleRe } + if (!next) return + delete _config.custom + let mergeUrl = Request.posUrl(_config.url) ? _config.url : (_config.baseUrl + _config.url) + if (JSON.stringify(_config.params) !== '{}') { + const paramsH = Request.addQueryString(_config.params) + mergeUrl += mergeUrl.indexOf('?') === -1 ? `?${paramsH}` : `&${paramsH}` + } + _config.url = mergeUrl + uni.request(_config) + }) + } + + get (url, options = {}) { + return this.request({ + url, + method: 'GET', + ...options + }) + } + + post (url, data, options = {}) { + return this.request({ + url, + data, + method: 'POST', + ...options + }) + } + + // #ifndef MP-ALIPAY + put (url, data, options = {}) { + return this.request({ + url, + data, + method: 'PUT', + ...options + }) + } + + // #endif + + // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU + delete (url, data, options = {}) { + return this.request({ + url, + data, + method: 'DELETE', + ...options + }) + } + + // #endif + + // #ifdef APP-PLUS || H5 || MP-WEIXIN + connect (url, data, options = {}) { + return this.request({ + url, + data, + method: 'CONNECT', + ...options + }) + } + + // #endif + + // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU + head (url, data, options = {}) { + return this.request({ + url, + data, + method: 'HEAD', + ...options + }) + } + + // #endif + + // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU + options (url, data, options = {}) { + return this.request({ + url, + data, + method: 'OPTIONS', + ...options + }) + } + + // #endif + + // #ifdef APP-PLUS || H5 || MP-WEIXIN + trace (url, data, options = {}) { + return this.request({ + url, + data, + method: 'TRACE', + ...options + }) + } + + // #endif + + upload (url, { + // #ifdef APP-PLUS + files, + // #endif + // #ifdef MP-ALIPAY + fileType, + // #endif + filePath, + name, + header, + formData, + custom + }) { + return new Promise((resolve, reject) => { + let next = true + let handleRe = {} + const globalHeader = { ...this.config.header } + delete globalHeader['content-type'] + const pubConfig = { + baseUrl: this.config.baseUrl, + url, + // #ifdef APP-PLUS + files, + // #endif + // #ifdef MP-ALIPAY + fileType, + // #endif + filePath, + method: 'UPLOAD', + name, + header: header || globalHeader, + formData, + custom: { ...this.config.custom, ...(custom || {}) }, + complete: (response) => { + response.config = handleRe + if (response.statusCode === 200) { // 成功 + response = this.requestComFun(response) + resolve(response) + } else { + response = this.requestComFail(response) + reject(response) + } + } + } + const cancel = (t = 'handle cancel', config = pubConfig) => { + const err = { + errMsg: t, + config: config + } + reject(err) + next = false + } + + handleRe = { ...this.requestBeforeFun(pubConfig, cancel) } + const _config = { ...handleRe } + if (!next) return + delete _config.custom + _config.url = Request.posUrl(_config.url) ? _config.url : (_config.baseUrl + _config.url) + uni.uploadFile(_config) + }) + } +} + +/** + * setConfig回调 + * @return {Object} - 返回操作后的config + * @callback Request~setConfigCallback + * @param {Object} config - 全局默认config + */ +/** + * 请求拦截器回调 + * @return {Object} - 返回操作后的config + * @callback Request~requestCallback + * @param {Object} config - 全局config + * @param {Function} [cancel] - 取消请求钩子,调用会取消本次请求 + */ +/** + * 响应拦截器回调 + * @return {Object} - 返回操作后的response + * @callback Request~responseCallback + * @param {Object} response - 请求结果 response + */ +/** + * 响应错误拦截器回调 + * @return {Object} - 返回操作后的response + * @callback Request~responseErrCallback + * @param {Object} response - 请求结果 response + */ diff --git a/main.js b/main.js new file mode 100644 index 0000000..c897c41 --- /dev/null +++ b/main.js @@ -0,0 +1,37 @@ +import Vue from 'vue' +import store from './store' +import App from './App' + +const msg = (title, duration=1500, mask=false, icon='none')=>{ + //统一提示方便全局修改 + if(Boolean(title) === false){ + return; + } + uni.showToast({ + title, + duration, + mask, + icon + }); +} + +const prePage = ()=>{ + let pages = getCurrentPages(); + let prePage = pages[pages.length - 2]; + // #ifdef H5 + return prePage; + // #endif + return prePage.$vm; +} + +Vue.config.productionTip = false +Vue.prototype.$fire = new Vue(); +Vue.prototype.$store = store; +Vue.prototype.$api = {msg, prePage}; + +App.mpType = 'app' + +const app = new Vue({ + ...App +}) +app.$mount() \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..653c90d --- /dev/null +++ b/manifest.json @@ -0,0 +1,74 @@ +{ + "name" : "mall-app-web", + "appid" : "", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + "app-plus" : { + /* 5+App特有相关 */ + "usingComponents" : true, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : {}, + /* 模块配置 */ + "distribute" : { + /* 应用发布信息 */ + "android" : { + /* android打包配置 */ + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios" : {}, + /* ios打包配置 */ + "sdkConfigs" : {} + } + }, + /* SDK配置 */ + "quickapp" : {}, + /* 快应用特有相关 */ + "mp-weixin" : { + /* 小程序特有相关 */ + "usingComponents" : true, + "appid" : "", + "setting" : { + "urlCheck" : true + } + }, + "h5" : { + "devServer" : { + "https" : false, + "port" : 8060 + }, + "domain" : "localhost", + "router" : { + "base" : "" + } + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..f3f96e6 --- /dev/null +++ b/pages.json @@ -0,0 +1,292 @@ +{ + "pages": [ + + { + "path": "pages/index/index", + "style": { + // #ifdef MP + "navigationBarTitleText": "Mall商城", + //"navigationStyle": "custom", + // #endif + "enablePullDownRefresh": true, + "app-plus": { + "titleNView": { + "type": "transparent", + "searchInput": { + "backgroundColor": "rgba(231, 231, 231,.7)", + "borderRadius": "16px", + "placeholder": "请输入商品 如:手机", + "disabled": true, + "placeholderColor": "#606266" + }, + "buttons": [{ + "fontSrc": "/static/yticon.ttf", + "text": "\ue60d", + "fontSize": "26", + "color": "#303133", + "float": "left", + "background": "rgba(0,0,0,0)" + }, + { + "fontSrc": "/static/yticon.ttf", + "text": "\ue744", + "fontSize": "27", + "color": "#303133", + "background": "rgba(0,0,0,0)", + "redDot": true + } + ] + } + } + } + }, + { + "path": "pages/product/product", + "style": { + "navigationBarTitleText": "详情展示", + "app-plus": { + "titleNView": { + "type": "transparent" + } + } + } + }, { + "path": "pages/set/set", + "style": { + "navigationBarTitleText": "设置" + } + }, + + { + "path": "pages/userinfo/userinfo", + "style": { + "navigationBarTitleText": "修改资料" + } + }, { + "path": "pages/cart/cart", + "style": { + "navigationBarTitleText": "购物车" + } + }, { + "path": "pages/public/login", + "style": { + "navigationBarTitleText": "", + "navigationStyle": "custom", + "app-plus": { + "titleNView": false, + "animationType": "slide-in-bottom" + } + } + }, { + "path": "pages/user/user", + "style": { + "navigationBarTitleText": "我的", + // #ifdef MP + "navigationStyle": "custom", + // #endif + "app-plus": { + "bounce": "none", + "titleNView": { + "type": "transparent", + "buttons": [{ + "fontSrc": "/static/yticon.ttf", + "text": "\ue60f", + "fontSize": "24", + "color": "#303133", + "width": "46px", + "background": "rgba(0,0,0,0)" + }, + { + "fontSrc": "/static/yticon.ttf", + "text": "\ue744", + "fontSize": "28", + "color": "#303133", + "background": "rgba(0,0,0,0)", + "redDot": true + } + ] + } + } + } + }, { + "path": "pages/order/order", + "style": { + "navigationBarTitleText": "我的订单", + "app-plus": { + "bounce": "none" + } + } + }, { + "path": "pages/money/money", + "style": {} + }, { + "path": "pages/order/createOrder", + "style": { + "navigationBarTitleText": "创建订单" + } + }, { + "path": "pages/order/orderDetail", + "style": { + "navigationBarTitleText": "订单详情" + } + }, { + "path": "pages/address/address", + "style": { + "navigationBarTitleText": "收货地址" + } + }, { + "path": "pages/address/addressManage", + "style": { + "navigationBarTitleText": "" + } + }, { + "path": "pages/money/pay", + "style": { + "navigationBarTitleText": "支付" + } + }, + { + "path": "pages/money/paySuccess", + "style": { + "navigationBarTitleText": "支付成功" + } + }, { + "path": "pages/notice/notice", + "style": { + "navigationBarTitleText": "通知" + } + }, { + "path": "pages/category/category", + "style": { + "navigationBarTitleText": "分类", + "app-plus": { + "bounce": "none" + } + } + }, { + "path": "pages/product/list", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "商品列表" + } + }, { + "path": "pages/coupon/couponList", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "优惠券列表" + } + }, { + "path": "pages/brand/brandDetail", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "品牌详情" + } + }, { + "path": "pages/brand/list", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "推荐品牌列表" + } + }, { + "path": "pages/product/newProductList", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "新鲜好物" + } + }, { + "path": "pages/product/hotProductList", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "人气推荐" + } + }, { + "path": "pages/user/readHistory", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "我的足迹", + "app-plus": { + "titleNView": { + "buttons": [{ + "text": "清空", + "fontSize": "16", + "color": "#303133", + "width": "46px", + "background": "rgba(0,0,0,0)" + }] + } + } + } + },{ + "path": "pages/user/productCollection", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "我的收藏", + "app-plus": { + "titleNView": { + "buttons": [{ + "text": "清空", + "fontSize": "16", + "color": "#303133", + "width": "46px", + "background": "rgba(0,0,0,0)" + }] + } + } + } + },{ + "path": "pages/user/brandAttention", + "style": { + "enablePullDownRefresh": true, + "navigationBarTitleText": "我的关注", + "app-plus": { + "titleNView": { + "buttons": [{ + "text": "清空", + "fontSize": "16", + "color": "#303133", + "width": "46px", + "background": "rgba(0,0,0,0)" + }] + } + } + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "mall-app-web", + "navigationBarBackgroundColor": "#FFFFFF", + "backgroundColor": "#f8f8f8" + }, + "tabBar": { + "color": "#C0C4CC", + "selectedColor": "#fa436a", + "borderStyle": "black", + "backgroundColor": "#ffffff", + "list": [{ + "pagePath": "pages/index/index", + "iconPath": "static/tab-home.png", + "selectedIconPath": "static/tab-home-current.png", + "text": "首页" + }, + { + "pagePath": "pages/category/category", + "iconPath": "static/tab-cate.png", + "selectedIconPath": "static/tab-cate-current.png", + "text": "分类" + }, + { + "pagePath": "pages/cart/cart", + "iconPath": "static/tab-cart.png", + "selectedIconPath": "static/tab-cart-current.png", + "text": "购物车" + }, + { + "pagePath": "pages/user/user", + "iconPath": "static/tab-my.png", + "selectedIconPath": "static/tab-my-current.png", + "text": "我的" + } + ] + } +} diff --git a/pages/address/address.vue b/pages/address/address.vue new file mode 100644 index 0000000..ef26ae9 --- /dev/null +++ b/pages/address/address.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/pages/address/addressManage.vue b/pages/address/addressManage.vue new file mode 100644 index 0000000..5ac2127 --- /dev/null +++ b/pages/address/addressManage.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/pages/brand/brandDetail.vue b/pages/brand/brandDetail.vue new file mode 100644 index 0000000..4464598 --- /dev/null +++ b/pages/brand/brandDetail.vue @@ -0,0 +1,393 @@ + + + + + diff --git a/pages/brand/list.vue b/pages/brand/list.vue new file mode 100644 index 0000000..af86882 --- /dev/null +++ b/pages/brand/list.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/pages/cart/cart.vue b/pages/cart/cart.vue new file mode 100644 index 0000000..46c1f89 --- /dev/null +++ b/pages/cart/cart.vue @@ -0,0 +1,417 @@ + + + + + diff --git a/pages/category/category.vue b/pages/category/category.vue new file mode 100644 index 0000000..bf50299 --- /dev/null +++ b/pages/category/category.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/pages/coupon/couponList.vue b/pages/coupon/couponList.vue new file mode 100644 index 0000000..5f80561 --- /dev/null +++ b/pages/coupon/couponList.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..6c376b3 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,848 @@ + + + + + diff --git a/pages/money/money.vue b/pages/money/money.vue new file mode 100644 index 0000000..8183fd0 --- /dev/null +++ b/pages/money/money.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/pages/money/pay.vue b/pages/money/pay.vue new file mode 100644 index 0000000..b369d84 --- /dev/null +++ b/pages/money/pay.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/pages/money/paySuccess.vue b/pages/money/paySuccess.vue new file mode 100644 index 0000000..06ef07e --- /dev/null +++ b/pages/money/paySuccess.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/pages/notice/notice.vue b/pages/notice/notice.vue new file mode 100644 index 0000000..b8ed92a --- /dev/null +++ b/pages/notice/notice.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/pages/order/createOrder.vue b/pages/order/createOrder.vue new file mode 100644 index 0000000..590ab65 --- /dev/null +++ b/pages/order/createOrder.vue @@ -0,0 +1,751 @@ + + + + + diff --git a/pages/order/order.vue b/pages/order/order.vue new file mode 100644 index 0000000..4888764 --- /dev/null +++ b/pages/order/order.vue @@ -0,0 +1,654 @@ + + + + + diff --git a/pages/order/orderDetail.vue b/pages/order/orderDetail.vue new file mode 100644 index 0000000..c787466 --- /dev/null +++ b/pages/order/orderDetail.vue @@ -0,0 +1,775 @@ + + + + + diff --git a/pages/product/hotProductList.vue b/pages/product/hotProductList.vue new file mode 100644 index 0000000..618bb47 --- /dev/null +++ b/pages/product/hotProductList.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/pages/product/list.vue b/pages/product/list.vue new file mode 100644 index 0000000..5ea224d --- /dev/null +++ b/pages/product/list.vue @@ -0,0 +1,440 @@ + + + + + diff --git a/pages/product/newProductList.vue b/pages/product/newProductList.vue new file mode 100644 index 0000000..e6f6e74 --- /dev/null +++ b/pages/product/newProductList.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/pages/product/product.vue b/pages/product/product.vue new file mode 100644 index 0000000..ffec4ad --- /dev/null +++ b/pages/product/product.vue @@ -0,0 +1,1492 @@ + + + + + diff --git a/pages/public/login.vue b/pages/public/login.vue new file mode 100644 index 0000000..0e77f60 --- /dev/null +++ b/pages/public/login.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/pages/set/set.vue b/pages/set/set.vue new file mode 100644 index 0000000..4686133 --- /dev/null +++ b/pages/set/set.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/pages/user/brandAttention.vue b/pages/user/brandAttention.vue new file mode 100644 index 0000000..29436ff --- /dev/null +++ b/pages/user/brandAttention.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/pages/user/productCollection.vue b/pages/user/productCollection.vue new file mode 100644 index 0000000..f336e96 --- /dev/null +++ b/pages/user/productCollection.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/pages/user/readHistory.vue b/pages/user/readHistory.vue new file mode 100644 index 0000000..1afab28 --- /dev/null +++ b/pages/user/readHistory.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/pages/user/user.vue b/pages/user/user.vue new file mode 100644 index 0000000..476694b --- /dev/null +++ b/pages/user/user.vue @@ -0,0 +1,377 @@ + + + \ No newline at end of file diff --git a/pages/userinfo/userinfo.vue b/pages/userinfo/userinfo.vue new file mode 100644 index 0000000..85a3a16 --- /dev/null +++ b/pages/userinfo/userinfo.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/static/arc.png b/static/arc.png new file mode 100644 index 0000000..c7ef6df Binary files /dev/null and b/static/arc.png differ diff --git a/static/emptyCart.jpg b/static/emptyCart.jpg new file mode 100644 index 0000000..be15652 Binary files /dev/null and b/static/emptyCart.jpg differ diff --git a/static/errorImage.jpg b/static/errorImage.jpg new file mode 100644 index 0000000..7a76067 Binary files /dev/null and b/static/errorImage.jpg differ diff --git a/static/hot_product_banner.png b/static/hot_product_banner.png new file mode 100644 index 0000000..cdb42fa Binary files /dev/null and b/static/hot_product_banner.png differ diff --git a/static/icon_close.png b/static/icon_close.png new file mode 100644 index 0000000..482a9c1 Binary files /dev/null and b/static/icon_close.png differ diff --git a/static/icon_deliver.png b/static/icon_deliver.png new file mode 100644 index 0000000..85607e0 Binary files /dev/null and b/static/icon_deliver.png differ diff --git a/static/icon_finish.png b/static/icon_finish.png new file mode 100644 index 0000000..986fea4 Binary files /dev/null and b/static/icon_finish.png differ diff --git a/static/icon_flash_promotion.png b/static/icon_flash_promotion.png new file mode 100644 index 0000000..328b38a Binary files /dev/null and b/static/icon_flash_promotion.png differ diff --git a/static/icon_home_brand.png b/static/icon_home_brand.png new file mode 100644 index 0000000..dc00132 Binary files /dev/null and b/static/icon_home_brand.png differ diff --git a/static/icon_hot_product.png b/static/icon_hot_product.png new file mode 100644 index 0000000..b82e81f Binary files /dev/null and b/static/icon_hot_product.png differ diff --git a/static/icon_new_product.png b/static/icon_new_product.png new file mode 100644 index 0000000..099b204 Binary files /dev/null and b/static/icon_new_product.png differ diff --git a/static/icon_receive.png b/static/icon_receive.png new file mode 100644 index 0000000..f652e0a Binary files /dev/null and b/static/icon_receive.png differ diff --git a/static/icon_recommend_product.png b/static/icon_recommend_product.png new file mode 100644 index 0000000..a381f78 Binary files /dev/null and b/static/icon_recommend_product.png differ diff --git a/static/icon_wait.png b/static/icon_wait.png new file mode 100644 index 0000000..06e72a5 Binary files /dev/null and b/static/icon_wait.png differ diff --git a/static/missing-face.png b/static/missing-face.png new file mode 100644 index 0000000..c9be652 Binary files /dev/null and b/static/missing-face.png differ diff --git a/static/new_product_banner.png b/static/new_product_banner.png new file mode 100644 index 0000000..fcd717f Binary files /dev/null and b/static/new_product_banner.png differ diff --git a/static/recommend_brand_banner.png b/static/recommend_brand_banner.png new file mode 100644 index 0000000..f0b4336 Binary files /dev/null and b/static/recommend_brand_banner.png differ diff --git a/static/select.png b/static/select.png new file mode 100644 index 0000000..fff0c32 Binary files /dev/null and b/static/select.png differ diff --git a/static/selected.png b/static/selected.png new file mode 100644 index 0000000..1719f1b Binary files /dev/null and b/static/selected.png differ diff --git a/static/tab-cart-current.png b/static/tab-cart-current.png new file mode 100644 index 0000000..e8b1c26 Binary files /dev/null and b/static/tab-cart-current.png differ diff --git a/static/tab-cart.png b/static/tab-cart.png new file mode 100644 index 0000000..2fb3e8c Binary files /dev/null and b/static/tab-cart.png differ diff --git a/static/tab-cate-current.png b/static/tab-cate-current.png new file mode 100644 index 0000000..406a7a0 Binary files /dev/null and b/static/tab-cate-current.png differ diff --git a/static/tab-cate.png b/static/tab-cate.png new file mode 100644 index 0000000..f93cebd Binary files /dev/null and b/static/tab-cate.png differ diff --git a/static/tab-home-current.png b/static/tab-home-current.png new file mode 100644 index 0000000..92947e2 Binary files /dev/null and b/static/tab-home-current.png differ diff --git a/static/tab-home.png b/static/tab-home.png new file mode 100644 index 0000000..1b51640 Binary files /dev/null and b/static/tab-home.png differ diff --git a/static/tab-my-current.png b/static/tab-my-current.png new file mode 100644 index 0000000..c1f09b5 Binary files /dev/null and b/static/tab-my-current.png differ diff --git a/static/tab-my.png b/static/tab-my.png new file mode 100644 index 0000000..f742ffc Binary files /dev/null and b/static/tab-my.png differ diff --git a/static/temp/ad-splash.jpg b/static/temp/ad-splash.jpg new file mode 100644 index 0000000..b4256a7 Binary files /dev/null and b/static/temp/ad-splash.jpg differ diff --git a/static/temp/ad1.jpg b/static/temp/ad1.jpg new file mode 100644 index 0000000..4c9a933 Binary files /dev/null and b/static/temp/ad1.jpg differ diff --git a/static/temp/ad2.jpg b/static/temp/ad2.jpg new file mode 100644 index 0000000..9d8fe9c Binary files /dev/null and b/static/temp/ad2.jpg differ diff --git a/static/temp/ad3.jpg b/static/temp/ad3.jpg new file mode 100644 index 0000000..a28f11e Binary files /dev/null and b/static/temp/ad3.jpg differ diff --git a/static/temp/banner1.jpg b/static/temp/banner1.jpg new file mode 100644 index 0000000..52d9192 Binary files /dev/null and b/static/temp/banner1.jpg differ diff --git a/static/temp/banner2.jpg b/static/temp/banner2.jpg new file mode 100644 index 0000000..7ed865f Binary files /dev/null and b/static/temp/banner2.jpg differ diff --git a/static/temp/banner3.jpg b/static/temp/banner3.jpg new file mode 100644 index 0000000..3529b8f Binary files /dev/null and b/static/temp/banner3.jpg differ diff --git a/static/temp/banner4.jpg b/static/temp/banner4.jpg new file mode 100644 index 0000000..afb1111 Binary files /dev/null and b/static/temp/banner4.jpg differ diff --git a/static/temp/c1.png b/static/temp/c1.png new file mode 100644 index 0000000..0ca677f Binary files /dev/null and b/static/temp/c1.png differ diff --git a/static/temp/c2.png b/static/temp/c2.png new file mode 100644 index 0000000..51fc162 Binary files /dev/null and b/static/temp/c2.png differ diff --git a/static/temp/c3.png b/static/temp/c3.png new file mode 100644 index 0000000..c72f8a3 Binary files /dev/null and b/static/temp/c3.png differ diff --git a/static/temp/c4.png b/static/temp/c4.png new file mode 100644 index 0000000..e72766c Binary files /dev/null and b/static/temp/c4.png differ diff --git a/static/temp/c5.png b/static/temp/c5.png new file mode 100644 index 0000000..5ea4377 Binary files /dev/null and b/static/temp/c5.png differ diff --git a/static/temp/c6.png b/static/temp/c6.png new file mode 100644 index 0000000..23d6bc9 Binary files /dev/null and b/static/temp/c6.png differ diff --git a/static/temp/c7.png b/static/temp/c7.png new file mode 100644 index 0000000..1179641 Binary files /dev/null and b/static/temp/c7.png differ diff --git a/static/temp/c8.png b/static/temp/c8.png new file mode 100644 index 0000000..43b3839 Binary files /dev/null and b/static/temp/c8.png differ diff --git a/static/temp/cate1.jpg b/static/temp/cate1.jpg new file mode 100644 index 0000000..c2a4446 Binary files /dev/null and b/static/temp/cate1.jpg differ diff --git a/static/temp/cate10.jpg b/static/temp/cate10.jpg new file mode 100644 index 0000000..ac54ab2 Binary files /dev/null and b/static/temp/cate10.jpg differ diff --git a/static/temp/cate11.jpg b/static/temp/cate11.jpg new file mode 100644 index 0000000..feb127e Binary files /dev/null and b/static/temp/cate11.jpg differ diff --git a/static/temp/cate12.jpg b/static/temp/cate12.jpg new file mode 100644 index 0000000..9d0b876 Binary files /dev/null and b/static/temp/cate12.jpg differ diff --git a/static/temp/cate13.jpg b/static/temp/cate13.jpg new file mode 100644 index 0000000..e87708b Binary files /dev/null and b/static/temp/cate13.jpg differ diff --git a/static/temp/cate14.jpg b/static/temp/cate14.jpg new file mode 100644 index 0000000..649d7c0 Binary files /dev/null and b/static/temp/cate14.jpg differ diff --git a/static/temp/cate15.jpg b/static/temp/cate15.jpg new file mode 100644 index 0000000..22166bd Binary files /dev/null and b/static/temp/cate15.jpg differ diff --git a/static/temp/cate16.jpg b/static/temp/cate16.jpg new file mode 100644 index 0000000..3793133 Binary files /dev/null and b/static/temp/cate16.jpg differ diff --git a/static/temp/cate17.jpg b/static/temp/cate17.jpg new file mode 100644 index 0000000..e918265 Binary files /dev/null and b/static/temp/cate17.jpg differ diff --git a/static/temp/cate18.jpg b/static/temp/cate18.jpg new file mode 100644 index 0000000..46ae363 Binary files /dev/null and b/static/temp/cate18.jpg differ diff --git a/static/temp/cate19.jpg b/static/temp/cate19.jpg new file mode 100644 index 0000000..a3af0a6 Binary files /dev/null and b/static/temp/cate19.jpg differ diff --git a/static/temp/cate2.jpg b/static/temp/cate2.jpg new file mode 100644 index 0000000..f76c42e Binary files /dev/null and b/static/temp/cate2.jpg differ diff --git a/static/temp/cate20.jpg b/static/temp/cate20.jpg new file mode 100644 index 0000000..6f675cc Binary files /dev/null and b/static/temp/cate20.jpg differ diff --git a/static/temp/cate21.jpg b/static/temp/cate21.jpg new file mode 100644 index 0000000..b0b118b Binary files /dev/null and b/static/temp/cate21.jpg differ diff --git a/static/temp/cate22.jpg b/static/temp/cate22.jpg new file mode 100644 index 0000000..c2980c1 Binary files /dev/null and b/static/temp/cate22.jpg differ diff --git a/static/temp/cate23.jpg b/static/temp/cate23.jpg new file mode 100644 index 0000000..1f5efaf Binary files /dev/null and b/static/temp/cate23.jpg differ diff --git a/static/temp/cate24.jpg b/static/temp/cate24.jpg new file mode 100644 index 0000000..4278703 Binary files /dev/null and b/static/temp/cate24.jpg differ diff --git a/static/temp/cate3.jpg b/static/temp/cate3.jpg new file mode 100644 index 0000000..2a10362 Binary files /dev/null and b/static/temp/cate3.jpg differ diff --git a/static/temp/cate4.jpg b/static/temp/cate4.jpg new file mode 100644 index 0000000..71fd313 Binary files /dev/null and b/static/temp/cate4.jpg differ diff --git a/static/temp/cate5.jpg b/static/temp/cate5.jpg new file mode 100644 index 0000000..5caeb6e Binary files /dev/null and b/static/temp/cate5.jpg differ diff --git a/static/temp/cate6.jpg b/static/temp/cate6.jpg new file mode 100644 index 0000000..cc42bcb Binary files /dev/null and b/static/temp/cate6.jpg differ diff --git a/static/temp/cate7.jpg b/static/temp/cate7.jpg new file mode 100644 index 0000000..8851046 Binary files /dev/null and b/static/temp/cate7.jpg differ diff --git a/static/temp/cate8.jpg b/static/temp/cate8.jpg new file mode 100644 index 0000000..03a8c77 Binary files /dev/null and b/static/temp/cate8.jpg differ diff --git a/static/temp/cate9.jpg b/static/temp/cate9.jpg new file mode 100644 index 0000000..3387f03 Binary files /dev/null and b/static/temp/cate9.jpg differ diff --git a/static/temp/h1.png b/static/temp/h1.png new file mode 100644 index 0000000..caa6d19 Binary files /dev/null and b/static/temp/h1.png differ diff --git a/static/temp/secskill-img.jpg b/static/temp/secskill-img.jpg new file mode 100644 index 0000000..ea21ae9 Binary files /dev/null and b/static/temp/secskill-img.jpg differ diff --git a/static/temp/share_moment.png b/static/temp/share_moment.png new file mode 100644 index 0000000..6fbb733 Binary files /dev/null and b/static/temp/share_moment.png differ diff --git a/static/temp/share_qq.png b/static/temp/share_qq.png new file mode 100644 index 0000000..5cedd48 Binary files /dev/null and b/static/temp/share_qq.png differ diff --git a/static/temp/share_qqzone.png b/static/temp/share_qqzone.png new file mode 100644 index 0000000..ec4115d Binary files /dev/null and b/static/temp/share_qqzone.png differ diff --git a/static/temp/share_wechat.png b/static/temp/share_wechat.png new file mode 100644 index 0000000..f88a7a7 Binary files /dev/null and b/static/temp/share_wechat.png differ diff --git a/static/user-bg.jpg b/static/user-bg.jpg new file mode 100644 index 0000000..2b3db62 Binary files /dev/null and b/static/user-bg.jpg differ diff --git a/static/vip-card-bg.png b/static/vip-card-bg.png new file mode 100644 index 0000000..6840371 Binary files /dev/null and b/static/vip-card-bg.png differ diff --git a/static/yticon.ttf b/static/yticon.ttf new file mode 100644 index 0000000..966501e Binary files /dev/null and b/static/yticon.ttf differ diff --git a/store/index.js b/store/index.js new file mode 100644 index 0000000..3d2a508 --- /dev/null +++ b/store/index.js @@ -0,0 +1,38 @@ +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +const store = new Vuex.Store({ + state: { + hasLogin: false, + userInfo: {}, + }, + mutations: { + login(state, provider) { + + state.hasLogin = true; + state.userInfo = provider; + uni.setStorage({//缓存用户登陆状态 + key: 'userInfo', + data: provider + }) + console.log(state.userInfo); + }, + logout(state) { + state.hasLogin = false; + state.userInfo = {}; + uni.removeStorage({ + key: 'userInfo' + }); + uni.removeStorage({ + key: 'token' + }) + } + }, + actions: { + + } +}) + +export default store diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..df10aef --- /dev/null +++ b/uni.scss @@ -0,0 +1,31 @@ + +/* 页面左右间距 */ +$page-row-spacing: 30upx; +$page-color-base: #f8f8f8; +$page-color-light: #f8f6fc; +$base-color: #fa436a; + +/* 文字尺寸 */ +$font-sm: 24upx; +$font-base: 28upx; +$font-lg: 32upx; +/*文字颜色*/ +$font-color-dark: #303133; +$font-color-base: #606266; +$font-color-light: #909399; +$font-color-disabled: #C0C4CC; +$font-color-spec: #4399fc; +/* 边框颜色 */ +$border-color-dark: #DCDFE6; +$border-color-base: #E4E7ED; +$border-color-light: #EBEEF5; +/* 图片加载中颜色 */ +$image-bg-color: #eee; +/* 行为相关颜色 */ +$uni-color-primary:#fa436a; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + + + diff --git a/utils/date.js b/utils/date.js new file mode 100644 index 0000000..7c1a591 --- /dev/null +++ b/utils/date.js @@ -0,0 +1,42 @@ +// date.js +export function formatDate(date, fmt) { + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); + } + let o = { + 'M+': date.getMonth() + 1, + 'd+': date.getDate(), + 'h+': date.getHours(), + 'm+': date.getMinutes(), + 's+': date.getSeconds() + }; + for (let k in o) { + if (new RegExp(`(${k})`).test(fmt)) { + let str = o[k] + ''; + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)); + } + } + return fmt; +} + +function padLeftZero(str) { + return ('00' + str).substr(str.length); +} + +export function str2Date(dateStr, separator) { + if (!separator) { + separator = "-"; + } + let dateArr = dateStr.split(separator); + let year = parseInt(dateArr[0]); + let month; + //处理月份为04这样的情况 + if (dateArr[1].indexOf("0") == 0) { + month = parseInt(dateArr[1].substring(1)); + } else { + month = parseInt(dateArr[1]); + } + let day = parseInt(dateArr[2]); + let date = new Date(year, month - 1, day); + return date; +} diff --git a/utils/requestUtil.js b/utils/requestUtil.js new file mode 100644 index 0000000..2261509 --- /dev/null +++ b/utils/requestUtil.js @@ -0,0 +1,86 @@ +import Request from '@/js_sdk/luch-request/request.js' + +const http = new Request() + +http.setConfig((config) => { /* 设置全局配置 */ + config.baseUrl = 'http://localhost:8085' /* 根域名不同 */ + config.header = { + ...config.header + } + return config +}) + +/** + * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject) + * @param { Number } statusCode - 请求响应体statusCode(只读) + * @return { Boolean } 如果为true,则 resolve, 否则 reject + */ +http.validateStatus = (statusCode) => { + return statusCode === 200 +} + +http.interceptor.request((config, cancel) => { /* 请求之前拦截器 */ + const token = uni.getStorageSync('token'); + if(token){ + config.header = { + 'Authorization':token, + ...config.header + } + }else{ + config.header = { + ...config.header + } + } + /* + if (!token) { // 如果token不存在,调用cancel 会取消本次请求,但是该函数的catch() 仍会执行 + cancel('token 不存在') // 接收一个参数,会传给catch((err) => {}) err.errMsg === 'token 不存在' + } + */ + return config +}) + +http.interceptor.response((response) => { /* 请求之后拦截器 */ + const res = response.data; + if (res.code !== 200) { + //提示错误信息 + uni.showToast({ + title:res.message, + duration:1500 + }) + //401未登录处理 + if (res.code === 401) { + uni.showModal({ + title: '提示', + content: '你已被登出,可以取消继续留在该页面,或者重新登录', + confirmText:'重新登录', + cancelText:'取消', + success: function(res) { + if (res.confirm) { + uni.navigateTo({ + url: '/pages/public/login' + }) + } else if (res.cancel) { + console.log('用户点击取消'); + } + } + }); + } + return Promise.reject(response); + } else { + return response.data; + } +}, (response) => { + //提示错误信息 + console.log('response error', response); + uni.showToast({ + title:response.errMsg, + duration:1500 + }) + return Promise.reject(response); +}) + +export function request (options = {}) { + return http.request(options); +} + +export default request \ No newline at end of file