Browse Source

移动端工程代码v3.2版本

master
dy-hu 3 years ago
commit
8287d78d59
  1. 16
      .gitignore
  2. 11
      .hbuilderx/launch.json
  3. 97
      App.vue
  4. 153
      api/activity.js
  5. 73
      api/admin.js
  6. 17
      api/live.js
  7. 150
      api/order.js
  8. 108
      api/public.js
  9. 183
      api/store.js
  10. 436
      api/user.js
  11. 2
      assets/css/base.css
  12. 1
      assets/css/base.css.map
  13. 180
      assets/css/base.less
  14. 2
      assets/css/reset.css
  15. 1
      assets/css/reset.css.map
  16. 43
      assets/css/reset.less
  17. 9372
      assets/css/style.less
  18. 661
      assets/iconfont/iconfont.css
  19. 77
      components/AddressWindow.vue
  20. 210
      components/Adv.vue
  21. 289
      components/CitySelect.vue
  22. 104
      components/CountDown.vue
  23. 122
      components/CouponListWindow.vue
  24. 75
      components/CouponPop.vue
  25. 88
      components/CouponWindow.vue
  26. 24
      components/DataFormat.vue
  27. 24
      components/DataFormatT.vue
  28. 65
      components/Footer.vue
  29. 49
      components/GoodList.vue
  30. 59
      components/Home.vue
  31. 21
      components/Loading.vue
  32. 74
      components/Mask.vue
  33. 155
      components/Menu.vue
  34. 45
      components/OrderGoods.vue
  35. 202
      components/Payment.vue
  36. 133
      components/PriceChange.vue
  37. 71
      components/ProductConSwiper.vue
  38. 140
      components/ProductWindow.vue
  39. 214
      components/PromotionGood.vue
  40. 82
      components/Recommend.vue
  41. 40
      components/ShareInfo.vue
  42. 43
      components/ShareRedPackets.vue
  43. 324
      components/ShopLiveCard.vue
  44. 223
      components/StorePoster.vue
  45. 155
      components/SwitchWindow.vue
  46. 52
      components/UserEvaluation.vue
  47. 127
      components/WriteOff.vue
  48. 184
      components/colorui/animation.css
  49. 70
      components/colorui/components/cu-custom.vue
  50. 1226
      components/colorui/icon.css
  51. 4040
      components/colorui/main.css
  52. 40
      components/sh-activity-goods.vue
  53. 217
      components/sh-adv.vue
  54. 197
      components/sh-groupon.vue
  55. 495
      components/tui-button/tui-button.vue
  56. 103
      components/tui-divider/tui-divider.vue
  57. 354
      components/tui-tag/tui-tag.vue
  58. 132
      components/uni-icons/icons.js
  59. 67
      components/uni-icons/uni-icons.vue
  60. 395
      components/uni-notice-bar/uni-notice-bar.vue
  61. 22
      components/uni-popup/message.js
  62. 25
      components/uni-popup/popup.js
  63. 243
      components/uni-popup/uni-popup-dialog.vue
  64. 116
      components/uni-popup/uni-popup-message.vue
  65. 165
      components/uni-popup/uni-popup-share.vue
  66. 294
      components/uni-popup/uni-popup.vue
  67. 279
      components/uni-transition/uni-transition.vue
  68. 8
      config/index.js
  69. BIN
      icons/1024x1024.png
  70. BIN
      icons/120x120.png
  71. BIN
      icons/144x144.png
  72. BIN
      icons/152x152.png
  73. BIN
      icons/167x167.png
  74. BIN
      icons/180x180.png
  75. BIN
      icons/192x192.png
  76. BIN
      icons/20x20.png
  77. BIN
      icons/29x29.png
  78. BIN
      icons/40x40.png
  79. BIN
      icons/58x58.png
  80. BIN
      icons/60x60.png
  81. BIN
      icons/72x72.png
  82. BIN
      icons/76x76.png
  83. BIN
      icons/80x80.png
  84. BIN
      icons/87x87.png
  85. BIN
      icons/96x96.png
  86. 51
      libs/chat.js
  87. 227
      libs/order.js
  88. 396
      libs/wechat.js
  89. 121
      main.js
  90. 181
      manifest.json
  91. 27
      mixins/SendVerifyCode.js
  92. 1327
      package-lock.json
  93. 25
      package.json
  94. 475
      pages.json
  95. 116
      pages/Loading/index.vue
  96. 55
      pages/NotDefined/index.vue
  97. 131
      pages/activity/BargainRecord/index.vue
  98. 645
      pages/activity/DargainDetails/index.vue
  99. 84
      pages/activity/GoodsBargain/index.vue
  100. 101
      pages/activity/GoodsGroup/children/activity-card.vue

16
.gitignore

@ -0,0 +1,16 @@
.DS_Store
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.keystore
unpackage/
assets/css/style.css
assets/css/style.css.map

11
.hbuilderx/launch.json

@ -0,0 +1,11 @@
{ // launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"type": "uniCloud",
"default": {
"launchtype": "remote"
}
}
]
}

97
App.vue

@ -0,0 +1,97 @@
<script>
import Vue from 'vue'
// #ifdef H5
var VConsole = require('@/utils/vconsole.min.js');
// #endif
export default {
onLaunch: function() {
const updateManager = uni.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
//
console.log(res.hasUpdate)
})
//
updateManager.onUpdateReady(function () {
uni.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
//
updateManager.applyUpdate()
}
}
})
})
//
updateManager.onUpdateFailed(function (res) {
//
uni.showModal({
title: '已经有新版本了哟~',
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
})
})
},
onShow: function () {
console.log("App Show");
},
onHide: function () {
console.log("App Hide");
},
mounted() {
// #ifdef H5
var vConsole = new VConsole();
console.log('开启调试');
// #endif
this.setAppInfo()
},
methods: {
//
async setAppInfo() {
let that = this;
return new Promise((resolve, reject) => {
uni.getSystemInfo({
success: function (e) {
Vue.prototype.StatusBar = e.statusBarHeight;
// #ifdef H5
Vue.prototype.CustomBar = e.statusBarHeight + 45;
// #endif
// #ifdef APP-PLUS
if (e.platform == "android") {
Vue.prototype.CustomBar = e.statusBarHeight + 50;
} else {
Vue.prototype.CustomBar = e.statusBarHeight + 45;
}
// #endif
// #ifdef MP-WEIXIN
let custom = wx.getMenuButtonBoundingClientRect();
Vue.prototype.Custom = custom;
Vue.prototype.CustomBar =
custom.bottom + custom.top - e.statusBarHeight;
// #endif
},
});
});
},
//
async autoLogin(data) {
},
},
};
</script>
<style lang="less">
/*每个页面公共css */
@import "animate.css";
@import "./assets/iconfont/iconfont.css";
@import "./assets/css/base.less";
@import "./assets/css/reset.less";
@import "./assets/css/style.less";
</style>

153
api/activity.js

@ -0,0 +1,153 @@
import request from "@/utils/request";
/**
* 拼团列表
*/
export function getCombinationList(data) {
return request.get("/combination/list", data, { login: false });
}
/**
* 拼团产品详情
* @param {*} id
*/
export function getCombinationDetail(id) {
return request.get("/combination/detail/" + id, {}, { login: true });
}
/**
* 拼团 开团
* @param {*} id
*/
export function getCombinationPink(id) {
return request.get("/combination/pink/" + id);
}
/**
* 拼团 取消开团
*/
export function getCombinationRemove(data) {
return request.post("/combination/remove", data);
}
/**
* 拼团海报
* @param {*} id
*/
export function getCombinationPoster(data) {
return request.post("/combination/poster", data);
}
/**
* 秒杀列表配置
*/
export function getSeckillConfig() {
return request.get("/seckill/index", {}, { login: false });
}
/**
* 秒杀列表
*/
export function getSeckillList(time, data) {
return request.get("/seckill/list/" + time, data, { login: false });
}
/**
* 秒杀产品详情
*/
export function getSeckillDetail(id) {
return request.get("/seckill/detail/" + id, {}, { login: true });
}
/**
* 砍价列表
* @param {*} data
*/
export function getBargainList(data) {
return request.get("/bargain/list", data, { login: false });
}
/**
* 砍价产品详情
*/
export function getBargainDetail(id) {
return request.get("/bargain/detail/" + id);
}
/**
* 砍价 观看/分享/参与次数
*/
export function getBargainShare(data) {
return request.post("/bargain/share", data);
}
/**
* 砍价开启
* @param {*} data
*/
export function getBargainStart(data) {
return request.post("/bargain/start", data);
}
/**
* 砍价 帮助好友砍价
* @param {*} data
*/
export function getBargainHelp(data) {
return request.post("/bargain/help", data);
}
/**
* 砍价 砍掉金额
* @param {*} data
*/
export function getBargainHelpPrice(data) {
return request.post("/bargain/help/price", data);
}
/**
* 砍价 砍价帮总人数剩余金额进度条已经砍掉的价格
* @param {*} data
*/
export function getBargainHelpCount(data) {
return request.post("/bargain/help/count", data);
}
/**
* 砍价 开启砍价用户信息
* @param {*} data
*/
export function getBargainStartUser(data) {
return request.post("/bargain/start/user", data);
}
/**
* 砍价 砍价帮
* @param {*} data
*/
export function getBargainHelpList(data) {
return request.post("/bargain/help/list", data);
}
/**
* 砍价海报
* @param {*} data
*/
export function getBargainPoster(data) {
return request.post("/bargain/poster", data);
}
/**
* 砍价列表(已参与)
* @param {*} data
*/
export function getBargainUserList(data) {
return request.get("/bargain/user/list", data);
}
/**
* 砍价取消
*/
export function getBargainUserCancel(data) {
return request.post("/bargain/user/cancel", data);
}

73
api/admin.js

@ -0,0 +1,73 @@
import request from "@/utils/request";
/**
* 统计数据
*/
export function getStatisticsInfo() {
return request.get("/admin/order/statistics", {}, { login: true });
}
/**
* 订单月统计
*/
export function getStatisticsMonth(where) {
return request.get("/admin/order/data", where, { login: true });
}
/**
* 订单月统计
*/
export function getAdminOrderList(where) {
return request.get("/admin/order/list", where, { login: true });
}
/**
* 订单改价
*/
export function setAdminOrderPrice(data) {
return request.post("/admin/order/price", data, { login: true });
}
/**
* 订单备注
*/
export function setAdminOrderRemark(data) {
return request.post("/admin/order/remark", data, { login: true });
}
/**
* 订单详情
*/
export function getAdminOrderDetail(orderId) {
return request.get("/admin/order/detail/" + orderId, {}, { login: true });
}
/**
* 订单发货信息获取
*/
export function getAdminOrderDelivery(orderId) {
return request.get(
"/admin/order/detail/" + orderId,
{},
{ login: true }
);
}
/**
* 订单发货保存
*/
export function setAdminOrderDelivery(data) {
return request.post("/admin/order/delivery/keep", data, { login: true });
}
/**
* 订单统计图
*/
export function getStatisticsTime(data) {
return request.get("/admin/order/time", data, { login: true });
}
/**
* 线下付款订单确认付款
*/
export function setOfflinePay(data) {
return request.post("/admin/order/offline", data, { login: true });
}
/**
* 订单确认退款
*/
export function setOrderRefund(data) {
return request.post("/admin/order/refund", data, { login: true });
}

17
api/live.js

@ -0,0 +1,17 @@
import request from "@/utils/request";
/**
* 查询所有直播间
*/
export function yxWechatLive(data) {
return request.get("/yxWechatLive", data, { login: true });
}
/**
* 获取直播回放
*/
export function getLiveReplay(id, data) {
return request.get("/yxWechatLive/getLiveReplay/" + id, data, { login: false });
}

150
api/order.js

@ -0,0 +1,150 @@
/*
* 订单确认
* */
import request from "@/utils/request";
/**
* 通过购物车 id 获取订单信息
* @param cartId
* @returns {*}
*/
export function postOrderConfirm(cartId) {
return request.post("/order/confirm", {
cartId
});
}
/**
* 计算订单金额
* @param key
* @param data
* @returns {*}
*/
export function postOrderComputed(key, data) {
return request.post("/order/computed/" + key, data);
}
/**
* 获取指定金额可用优惠券
* @param price
* @returns {*}
*/
export function getOrderCoupon(cartId) {
return request.get("/coupons/order/" + cartId);
}
/**
* 生成订单
* @param key
* @param data
* @returns {*}
*/
export function createOrder(key, data) {
return request.post("/order/create/" + key, data || {});
}
/**
* 订单统计数据
* @returns {*}
*/
export function getOrderData() {
return request.get("/order/data");
}
/**
* 订单列表
* @returns {*}
*/
export function getOrderList(data) {
return request.get("/order/list", data);
}
/**
* 取消订单
* @returns {*}
*/
export function cancelOrder(id) {
return request.post("/order/cancel", {
id
});
}
/**
* 订单详情
* @returns {*}
*/
export function orderDetail(id) {
return request.get("/order/detail/" + id);
}
/**
* 退款理由
* @returns {*}
*/
export function getRefundReason() {
return request.get("/order/refund/reason");
}
/**
* 提交退款
* @returns {*}
*/
export function postOrderRefund(data) {
return request.post("/order/refund/verify", data);
}
/**
* 确认收货
* @returns {*}
*/
export function takeOrder(uni) {
return request.post("/order/take", {
uni
});
}
/**
* 删除订单
* @returns {*}
*/
export function delOrder(uni) {
return request.post("/order/del", {
uni
});
}
/**
* 订单查询物流信息
* @returns {*}
*/
export function express(params) {
return request.post("order/express", params);
}
/**
* 订单查询物流信息
* @returns {*}
*/
export function payOrder(uni, paytype, from) {
return request.post("order/pay", {
uni,
paytype,
from
});
}
/**
* 订单核销
* @returns {*}
*/
export function orderVerific(verifyCode, isConfirm) {
return request.post("order/order_verific", { verifyCode, isConfirm });
}
/**
* 获取订阅消息ID
* @param price
* @returns {*}
*/
export function getSubscribeTemplate() {
return request.get("/order/getSubscribeTemplate");
}

108
api/public.js

@ -0,0 +1,108 @@
import request from "@/utils/request";
/**
* 首页
* @returns {*}
*/
export function getHomeData() {
return request.get("index", {}, { login: false });
}
/**
* 首页
* @returns {*}
*/
export function getCanvas() {
return request.get("/getCanvas?terminal=3", {}, { login: false });
}
/**
* 文章 轮播列表
* @returns {*}
*/
export function getArticleBanner() {
return request.get("/article/banner/list", {}, { login: false });
}
/**
* 文章分类列表
* @returns {*}
*/
export function getArticleCategory() {
return request.get("/article/category/list", {}, { login: false });
}
/**
* 文章 热门列表
* @returns {*}
*/
export function getArticleHotList() {
return request.get("/article/hot/list", {}, { login: false });
}
/**
* 文章列表
* @returns {*}
*/
export function getArticleList(q) {
return request.get("/article/list/", q, { login: false });
}
/**
* 分享
* @returns {*}
*/
export function getShare() {
return request.get("/share", {}, { login: false });
}
/**
* 文章详情
* @returns {*}
*/
export function getArticleDetails(id) {
return request.get("/article/details/" + id, {}, { login: false });
}
/**
* 获取微信sdk配置
* @returns {*}
*/
export function getWechatConfig() {
return request.get(
"/wechat/config",
{ url: location.href },
{ login: false }
);
}
/**
* 获取微信sdk配置
* @returns {*}
*/
export function wechatAuth(code, spread, login_type) {
return request.get(
"/wechat/auth",
{ code, spread, login_type },
{ login: false }
);
}
/**
* 获取快递公司
* @returns {*}
*/
export function getLogistics() {
return request.get("/logistics", {}, { login: false });
}
/**
* 获取图片base64
* @retins {*}
* */
export function imageBase64(image, code) {
return request.post(
"/image_base64",
{ image: image, code: code },
{ login: false }
);
}

183
api/store.js

@ -0,0 +1,183 @@
import request from "@/utils/request";
/*
* 商品分类
* */
export function getCategory() {
return request.get("/category", {}, {
login: false
});
}
/*
* 商品详情
* */
export function getProductDetail(id, data) {
return request.get("/product/detail/" + id, data, {
login: true
});
}
/*
* 商品分销二维码
* */
export function getProductCode(id) {
return request.get("/product/code/" + id, {}, {
login: true
});
}
/*
* 商品列表
* */
export function getProducts(q) {
return request.get("/products", q, {
login: false
});
}
/*
* 积分商品列表
* */
export function getProductsIntegral(q) {
return request.get("/products/integral", q, {
login: false
});
}
/*
* 购物车数量
* */
export function getCartNum() {
return request.get("/cart/count");
}
/*
* 添加收藏
* */
export function toCollect(id, category) {
return request.get("/collect/add/" + id + "/" + category);
}
/*
* 为你推荐
* */
export function getHostProducts(page, limit) {
return request.get(
"/product/hot", {
page: page,
limit: limit
}, {
login: false
}
);
}
/*
* 精品热门首发列表
* */
export function getGroomList(type) {
return request.get("/groom/list/" + type, {}, {
login: true
});
}
/*
* 获取商品海报
* */
export function getProductPoster(id, data) {
return request.get("/product/poster/" + id, data, {
login: true
});
}
/*
* 购物车 添加
* */
export function postCartAdd(data) {
return request.post("/cart/add", data);
}
/*
* 购物车列表
* */
export function getCartList() {
return request.get("/cart/list");
}
/*
* 购物车 删除
* */
export function postCartDel(ids) {
return request.post("/cart/del", {
ids
});
}
/*
* 购物车 获取数量
* */
export function getCartCount(data) {
return request.get("/cart/count", data);
}
/*
* 购物车 修改商品数量
* */
export function changeCartNum(id, number) {
return request.post("/cart/num", {
id,
number
});
}
/**
* 搜索推荐关键字
*/
export function getSearchKeyword() {
return request.get("/search/keyword", {}, {
login: false
});
}
/**
* 产品评论列表
*/
export function getReplyList(id, q) {
return request.get("/reply/list/" + id, q, {
login: true
});
}
/**
* 产品评价数量和好评度
*/
export function getReplyConfig(id) {
return request.get("/reply/config/" + id, {}, {
login: true
});
}
/**
* 评价页面获取单个产品详情
*/
export function postOrderProduct(unique) {
return request.post("/order/product", {
unique
}, {
login: true
});
}
/**
* 提交评价页面
*/
export function postOrderComment(data) {
return request.post("/order/comment", data, {
login: true
});
}
export function storeListApi(data) {
return request.get("store_list", data, {
login: false
});
}

436
api/user.js

@ -0,0 +1,436 @@
import request from '@/utils/request'
/**
* 省市区
*/
export function getCity(data) {
return request.get('/city_list', data, {
// return request.get("/citys", data, {
login: false,
})
}
export function district(data) {
// return request.get("/city_list", data, {
return request.get('/citys', data, {
login: false,
})
}
/**
* 用户登录
* @param data object 用户账号密码
*/
export function login(data) {
return request.post('/login', data, {
login: false,
})
}
/**
* 用户手机号登录
* @param data object 用户手机号 也只能
*/
export function loginMobile(data) {
return request.post('/login/mobile', data, {
login: false,
})
}
/**
* 用户发送验证码
* @param data object 用户手机号
*/
export function registerVerify(data) {
return request.post('/register/verify', data, {
login: false,
})
}
/**
* 用户手机号注册
* @param data object 用户手机号 验证码 密码
*/
export function register(data) {
return request.post('/register', data, {
login: false,
})
}
/**
* 用户手机号修改密码
* @param data object 用户手机号 验证码 密码
*/
export function registerReset(data) {
return request.post('/register/reset', data, {
login: false,
})
}
/*
* 领取优惠券列表
* */
export function getCoupon(q) {
return request.get('/coupons', q, {
login: true,
})
}
/*
* 点击领取优惠券
* */
export function getCouponReceive(id) {
return request.post(
'/coupon/receive',
{
couponId: id,
},
{
login: true,
}
)
}
/*
* 批量领取优惠券
* */
export function couponReceiveBatch(couponId) {
return request.post('/coupon/receive/batch', {
couponId,
})
}
/*
* 我的优惠券
* */
export function getCouponsUser(type) {
return request.get('/coupons/user/' + type)
}
/*
* 个人中心
* */
export function getUser() {
return request.get('/user')
}
/*
* 用户信息
* */
export function getUserInfo() {
return request.get('/userinfo', {
login: true,
})
}
/*
* 小程序登陆
* */
export function wxappAuth(data) {
return request.post('/wxapp/auth', data, {
login: false,
})
}
/*
* 个人中心(功能列表)
* */
export function getMenuUser() {
return request.get('/menu/user')
}
/*
* 地址列表
* */
export function getAddressList(data) {
return request.get('/address/list', data || {})
}
/*
* 删除地址
* */
export function getAddressRemove(id) {
return request.post('/address/del', {
id: id,
})
}
/*
* 设置默认地址
* */
export function getAddressDefaultSet(id) {
return request.post('/address/default/set', {
id: id,
})
}
/*
* 获取默认地址
* */
export function getAddressDefault() {
return request.get('/address/default')
}
/*
* 获取单个地址
* */
export function getAddress(id) {
return request.get('/address/detail/' + id)
}
/*
* 修改 添加地址
* */
export function postAddress(data) {
return request.post('/address/edit', data)
}
/*
* 获取收藏产品
* */
export function getCollectUser(page, limit, type) {
return request.get('/collect/user', {
page: page,
limit: limit,
type,
})
}
/*
* 删除收藏产品
* */
export function getCollectDel(id, category) {
return request.post('/collect/del', {
id: id,
category: category,
})
}
/*
* 批量收藏产品
* */
export function postCollectAll(data) {
return request.post('/collect/all', data)
}
/*
* 添加收藏产品
* */
export function getCollectAdd(id, category) {
return request.post('collect/add', {
id: id,
category: category,
})
}
/*
* 签到配置
* */
export function getSignConfig() {
return request.get('/sign/config')
}
/*
* 签到里的签到列表
* */
export function getSignList(page, limit) {
return request.get('/sign/list', {
page: page,
limit: limit,
})
}
/*
* 签到列表
* */
export function getSignMonth(page, limit) {
return request.get('/sign/month', {
page: page,
limit: limit,
})
}
/*
* 签到用户信息
* */
export function postSignUser(sign) {
return request.post('/sign/user', sign)
}
/*
* 签到
* */
export function postSignIntegral(sign) {
return request.post('/sign/integral', sign)
}
/*
* 推广数据
* */
export function getSpreadInfo() {
return request.get('/commission')
}
/*
* 推广人列表
* */
export function getSpreadUser(screen) {
return request.post('/spread/people', screen)
}
/*
* 推广人订单
* */
export function getSpreadOrder(where) {
return request.post('/spread/order', where)
}
/*
* 资金明细types|0=全部,1=消费,2=充值,3=返佣,4=提现
* */
export function getCommissionInfo(q, types) {
return request.get('/spread/commission/' + types, q)
}
/*
* 积分记录
* */
export function getIntegralList(q) {
return request.get('/integral/list', q)
}
/*
* 提现银行
* */
export function getBank() {
return request.get('/extract/bank')
}
/*
* 提现申请
* */
export function postCashInfo(cash) {
return request.post('/extract/cash', cash)
}
/*
* 会员中心
* */
export function getVipInfo() {
return request.get('/user/level/grade')
}
/*
* 会员等级任务
* */
export function getVipTask(id) {
return request.get('/user/level/task/' + id)
}
/*
* 资金统计
* */
export function getBalance() {
return request.get('/user/balance')
}
/*
* 活动状态
* */
export function getActivityStatus() {
return request.get(
'/user/activity',
{},
{
login: false,
}
)
}
/*
* 活动状态
* */
export function getSpreadImg(data) {
return request.get('/spread/banner', data)
}
/*
* 用户修改信息
* */
export function postUserEdit(data) {
return request.post('/user/edit', data)
}
/*
* 用户修改信息
* */
export function getChatRecord(to_uid, data) {
return request.get('user/service/record/' + to_uid, data)
}
/*
* 用户修改信息
* */
export function serviceList() {
return request.get('user/service/list')
}
/*
* 公众号充值
* */
export function rechargeWechat(data) {
return request.post('/recharge/wechat', data)
}
/*
* 退出登录
* */
export function getLogout() {
return request.post('/auth/logout')
}
/*
* 小程序绑定手机号
* */
export function bindingPhone(data) {
return request.post('/binding', data)
}
/*
* 绑定手机号
* */
export function wxappBindingPhone(data) {
return request.post('wxapp/binding', data)
}
/*
* h5切换公众号登陆
* */
export function switchH5Login() {
return request.post('switch_h5', {
from: 'wechat',
})
}
/*
* 获取推广人排行
* */
export function getRankList(q) {
return request.get('rank', q)
}
/*
* 获取佣金排名
* */
export function getBrokerageRank(q) {
return request.get('brokerage_rank', q)
}
/**
* 检测会员等级
*/
export function setDetection() {
return request.get('user/level/detection')
}
export function getRechargeApi() {
return request.get('recharge/index')
}

2
assets/css/base.css

@ -0,0 +1,2 @@
@charset "UTF-8";.font-color-red{color:#eb3729 !important}.bg-color-red{background-color:#eb3729 !important}.icon-color{color:#eb3729}.cart-color{color:#eb3729 !important;border:1px solid #eb3729 !important}.padding20{padding:20rpx}.pad20{padding:0 20rpx}.padding30{padding:30rpx}.pad30{padding:0 30rpx}.acea-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.acea-row.row-middle{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.acea-row.row-top{-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start}.acea-row.row-bottom{-webkit-box-align:end;-webkit-align-items:flex-end;-ms-flex-align:end;align-items:flex-end}.acea-row.row-center{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.acea-row.row-right{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.acea-row.row-left{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.acea-row.row-between{-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.acea-row.row-around{-webkit-justify-content:space-around;-ms-flex-pack:distribute;justify-content:space-around}.acea-row.row-column-around{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-justify-content:space-around;-ms-flex-pack:distribute;justify-content:space-around}.acea-row.row-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.acea-row.row-column-between{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.acea-row.row-center-wrapper{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.acea-row.row-between-wrapper{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.slider-banner{position:relative;width:100%;overflow:hidden}.slider-banner .swiper-container{height:100%}.slider-banner image{display:block;width:100%;height:100%}.start{width:122rpx;height:30rpx;background-image:url("https://wx.yixiang.co/static/images/start.png");background-repeat:no-repeat;-webkit-background-size:122rpx auto;background-size:122rpx auto}.start.star5{background-position:0 3rpx}.start.star4{background-position:0 -30rpx}.start.star3{background-position:0 -70rpx}.start.star2{background-position:0 -105rpx}.start.star1{background-position:0 -140rpx}.start.star0{background-position:0 -175rpx}.checkbox-wrapper{position:relative}.checkbox-wrapper input{display:none}.checkbox-wrapper .icon{position:absolute;left:0;top:50%;display:inline-block;width:18px;height:18px;border:1px solid #cccccc;-webkit-border-radius:50%;border-radius:50%;-webkit-transform:translate(0, -50%);-ms-transform:translate(0, -50%);transform:translate(0, -50%)}.checkbox-wrapper input:checked+.icon{background-color:#e93323;border-color:#e93323;background-image:url("https://wx.yixiang.co/static/images/enter.png");-webkit-background-size:21rpx 15rpx;background-size:21rpx 15rpx;background-repeat:no-repeat;background-position:center center}.Loads{height:80rpx;font-size:25rpx;color:#000}.Loads .iconfont{font-size:30rpx;margin-right:10rpx;height:32rpx;line-height:32rpx}@-webkit-keyframes load{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.loadingpic{-webkit-animation:load 3s linear 1s infinite;animation:load 3s linear 1s infinite}.loading{-webkit-animation:load linear 1s infinite;animation:load linear 1s infinite}
/*# sourceMappingURL=./base.css.map */

1
assets/css/base.css.map

@ -0,0 +1 @@
{"version":3,"sources":["base.less"],"names":[],"mappings":"AAAA,iBAIA,gBACE,wBAAA,CAEF,cACE,mCAAA,CAEF,YACE,aAAA,CAEF,YACE,yBACA,mCAAA,CAGF,WACE,aAAA,CAGF,OACE,eAAA,CAGF,WACE,aAAA,CAGF,OACE,eAAA,CAGF,UACE,oBACA,AADA,qBACA,AADA,oBACA,AADA,aACA,uBAAA,mBAAA,cAAA,CAGF,qBACE,yBAAA,2BAAA,sBAAA,kBAAA,CAEF,kBACE,wBAAA,+BAAA,qBAAA,sBAAA,CAEF,qBACE,sBAAA,6BAAA,mBAAA,oBAAA,CAEF,qBACE,wBAAA,+BAAA,qBAAA,sBAAA,CAEF,oBACE,qBAAA,iCAAA,kBAAA,wBAAA,CAEF,mBACE,uBAAA,mCAAA,oBAAA,0BAAA,CAEF,sBACE,yBAAA,sCAAA,sBAAA,6BAAA,CAEF,qBACE,qCAAA,yBAAA,4BAAA,CAEF,4BACE,4BACA,AADA,6BACA,AADA,8BACA,AADA,0BACA,AADA,sBACA,qCAAA,yBAAA,4BAAA,CAEF,qBACE,4BAAA,6BAAA,8BAAA,0BAAA,qBAAA,CAEF,6BACE,4BACA,AADA,6BACA,AADA,8BACA,AADA,0BACA,AADA,sBACA,yBAAA,sCAAA,sBAAA,6BAAA,CAGF,6BACE,yBACA,AADA,2BACA,AADA,sBACA,AADA,mBACA,wBAAA,+BAAA,qBAAA,sBAAA,CAGF,8BACE,yBACA,AADA,2BACA,AADA,sBACA,AADA,mBACA,yBAAA,sCAAA,sBAAA,6BAAA,CAIF,eACE,kBACA,WAEA,eAAA,CAKF,iCACE,WAAA,CAEF,qBACE,cACA,WACA,WAAA,CAEF,OACE,aACA,aACA,sEACA,4BACA,oCAAA,2BAAA,CAEF,aACE,0BAAA,CAEF,aACE,4BAAA,CAEF,aACE,4BAAA,CAEF,aACE,6BAAA,CAEF,aACE,6BAAA,CAEF,aACE,6BAAA,CAGF,kBACE,iBAAA,CAEF,wBACE,YAAA,CAEF,wBACE,kBACA,OACA,QACA,qBACA,WACA,YACA,yBACA,0BACA,AADA,kBACA,qCAAW,AAAX,iCAAW,AAAX,4BAAW,CAEb,sCACE,yBACA,qBACA,sEACA,oCACA,AADA,4BACA,4BACA,iCAAA,CAEF,OACE,aACA,gBACA,UAAA,CAEF,iBACE,gBACA,mBACA,aACA,iBAAA,CAGF,wBACE,KACE,+BAAW,AAAX,sBAAW,CAEb,GACE,iCAAW,AAAX,wBAAW,CAAA,CAGf,AARA,gBACE,KACE,+BAAW,AAAX,sBAAW,CAEb,GACE,iCAAW,AAAX,wBAAW,CAAA,CAGf,YACE,6CAAA,oCAAA,CAEF,SACE,0CAAA,iCAAA,CAAA","file":"to.css","sourcesContent":[null]}

180
assets/css/base.less

@ -0,0 +1,180 @@
@charset "UTF-8";
/**
*相关初始化
*/
.font-color-red {
color: #eb3729 !important;
}
.bg-color-red {
background-color: #eb3729 !important;
}
.icon-color {
color: #eb3729;
}
.cart-color {
color: #eb3729 !important;
border: 1px solid #eb3729 !important;
}
/* padding20 */
.padding20 {
padding: 0.2*100rpx;
}
/* pad20 */
.pad20 {
padding: 0 0.2*100rpx;
}
/* padding30 */
.padding30 {
padding: 0.3*100rpx;
}
/*pad30 */
.pad30 {
padding: 0 0.3*100rpx;
}
/* layout */
.acea-row {
display: flex;
flex-wrap: wrap;
/* 辅助类 */
}
.acea-row.row-middle {
align-items: center;
}
.acea-row.row-top {
align-items: flex-start;
}
.acea-row.row-bottom {
align-items: flex-end;
}
.acea-row.row-center {
justify-content: center;
}
.acea-row.row-right {
justify-content: flex-end;
}
.acea-row.row-left {
justify-content: flex-start;
}
.acea-row.row-between {
justify-content: space-between;
}
.acea-row.row-around {
justify-content: space-around;
}
.acea-row.row-column-around {
flex-direction: column;
justify-content: space-around;
}
.acea-row.row-column {
flex-direction: column;
}
.acea-row.row-column-between {
flex-direction: column;
justify-content: space-between;
}
/* 上下左右垂直居中 */
.acea-row.row-center-wrapper {
align-items: center;
justify-content: center;
}
/* 上下两边居中对齐 */
.acea-row.row-between-wrapper {
align-items: center;
justify-content: space-between;
}
/* 轮播图 */
.slider-banner {
position: relative;
width: 100%;
/* height:750rpx; */
overflow: hidden;
}
.slider-banner{
}
.slider-banner .swiper-container {
height: 100%;
}
.slider-banner image{
display: block;
width: 100%;
height: 100%;
}
.start {
width: 1.22*100rpx;
height: 0.3*100rpx;
background-image: url("https://wx.yixiang.co/static/images/start.png");
background-repeat: no-repeat;
background-size: 1.22*100rpx auto;
}
.start.star5 {
background-position: 0 0.03*100rpx;
}
.start.star4 {
background-position: 0 -0.3*100rpx;
}
.start.star3 {
background-position: 0 -0.7*100rpx;
}
.start.star2 {
background-position: 0 -1.05*100rpx;
}
.start.star1 {
background-position: 0 -1.4*100rpx;
}
.start.star0 {
background-position: 0 -1.75*100rpx;
}
/* 单选框和多选框 */
.checkbox-wrapper {
position: relative;
}
.checkbox-wrapper input {
display: none;
}
.checkbox-wrapper .icon {
position: absolute;
left: 0;
top: 50%;
display: inline-block;
width: 18px;
height: 18px;
border: 1px solid #cccccc;
border-radius: 50%;
transform: translate(0, -50%);
}
.checkbox-wrapper input:checked + .icon {
background-color: #e93323;
border-color: #e93323;
background-image: url("https://wx.yixiang.co/static/images/enter.png");
background-size: 0.21*100rpx 0.15*100rpx;
background-repeat: no-repeat;
background-position: center center;
}
.Loads {
height: 0.8*100rpx;
font-size: 0.25*100rpx;
color: #000;
}
.Loads .iconfont {
font-size: 0.3*100rpx;
margin-right: 0.1*100rpx;
height: 0.32*100rpx;
line-height: 0.32*100rpx;
}
/*加载动画*/
@keyframes load {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loadingpic {
animation: load 3s linear 1s infinite;
}
.loading {
animation: load linear 1s infinite;
}

2
assets/css/reset.css

@ -0,0 +1,2 @@
input{line-height:normal;-webkit-box-sizing:border-box;box-sizing:border-box}@font-face{font-family:'GuildfordProBook 5';src:url('https://wx.yixiang.co/static/iconfont/GuildfordProBook5.otf')}[v-cloak]{display:none}.iconfont{font-size:36rpx}@media (-webkit-min-device-pixel-ratio:1.5),(min-device-pixel-ratio:1.5){.border-1px::after{-webkit-transform:scaleY(.7);-ms-transform:scaleY(.7);transform:scaleY(.7)}.border-1px::before{-webkit-transform:scaleY(.7);-ms-transform:scaleY(.7);transform:scaleY(.7)}}@media (-webkit-min-device-pixel-ratio:2),(min-device-pixel-ratio:2){.border-1px::after{-webkit-transform:scaleY(.5);-ms-transform:scaleY(.5);transform:scaleY(.5)}.border-1px::before{-webkit-transform:scaleY(.5);-ms-transform:scaleY(.5);transform:scaleY(.5)}}@media (-webkit-min-device-pixel-ratio:3),(min-device-pixel-ratio:3){.border-1px::after{-webkit-transform:scaleY(.33);-ms-transform:scaleY(.33);transform:scaleY(.33)}.border-1px::before{-webkit-transform:scaleY(.33);-ms-transform:scaleY(.33);transform:scaleY(.33)}}.line1{overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;width:100%}.line2{word-break:break-all;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.mask{position:fixed;top:0;left:0;right:0;bottom:0;z-index:55;background-color:rgba(0,0,0,0.5)}
/*# sourceMappingURL=./reset.css.map */

1
assets/css/reset.css.map

@ -0,0 +1 @@
{"version":3,"sources":["reset.less"],"names":[],"mappings":"AAAA,MAAM,mBAAqB,8BAAA,qBAAA,CAC3B,WACE,iCACA,sEAAS,CAEX,UACE,YAAA,CAEF,UACE,eAAA,CAGF,yEACE,mBACE,6BAAW,AAAX,yBAAW,AAAX,oBAAW,CAEb,oBACE,6BAAW,AAAX,yBAAW,AAAX,oBAAW,CAAA,CAGf,qEACE,mBACE,6BAAW,AAAX,yBAAW,AAAX,oBAAW,CAEb,oBACE,6BAAW,AAAX,yBAAW,AAAX,oBAAW,CAAA,CAGf,qEACE,mBACE,8BAAW,AAAX,0BAAW,AAAX,qBAAW,CAEb,oBACE,8BAAW,AAAX,0BAAW,AAAX,qBAAW,CAAA,CAGf,OAAO,gBAAgB,0BAAuB,AAAvB,uBAAuB,mBAAmB,UAAA,CACjE,OAAO,qBAAqB,oBAAoB,qBAAqB,4BAA4B,eAAA,CACjG,MAAM,eAAe,MAAM,OAAO,QAAQ,SAAS,WAAW,gCAAA,CAAA","file":"to.css","sourcesContent":[null]}

43
assets/css/reset.less

@ -0,0 +1,43 @@
input{line-height: normal; box-sizing:border-box;}
@font-face {
font-family: 'GuildfordProBook 5';
src: url('https://wx.yixiang.co/static/iconfont/GuildfordProBook5.otf');
}
[v-cloak] {
display: none;
}
.iconfont{
font-size: .36*100rpx;
}
/* 一像素边框 */
@media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) {
.border-1px::after {
transform: scaleY(0.7);
}
.border-1px::before {
transform: scaleY(0.7);
}
}
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
.border-1px::after {
transform: scaleY(0.5);
}
.border-1px::before {
transform: scaleY(0.5);
}
}
@media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
.border-1px::after {
transform: scaleY(0.33);
}
.border-1px::before {
transform: scaleY(0.33);
}
}
.line1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width: 100%;}
.line2{word-break:break-all;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.mask{position:fixed;top:0;left:0;right:0;bottom:0;z-index:55;background-color:rgba(0,0,0,0.5);}

9372
assets/css/style.less
File diff suppressed because it is too large
View File

661
assets/iconfont/iconfont.css
File diff suppressed because it is too large
View File

77
components/AddressWindow.vue

@ -0,0 +1,77 @@
<template>
<view>
<view class="address-window" :class="value === true ? 'on' : ''">
<view class="title">
选择地址
<text class="iconfont icon-guanbi" @click="closeAddress"></text>
</view>
<view class="list" v-if="addressList.length">
<view
class="item acea-row row-between-wrapper"
:class="item.id === checked ? 'font-color-red' : ''"
v-for="(item, addressIndex) in addressList"
@click="tapAddress(addressIndex)"
:key="addressIndex"
>
<text class="iconfont icon-ditu" :class="item.id === checked ? 'font-color-red' : ''"></text>
<view class="addressTxt">
<view class="name" :class="item.id === checked ? 'font-color-red' : ''">
{{ item.realName }}
<text class="phone">{{ item.phone }}</text>
</view>
<view class="line1">
{{ item.province }}{{ item.city }}{{ item.district
}}{{ item.detail }}
</view>
</view>
<text class="iconfont icon-complete" :class="item.id === checked ? 'font-color-red' : ''"></text>
</view>
</view>
<view class="pictrue" v-if="addressList.length < 1">
<image src="@/static/images/noAddress.png" class="image" />
</view>
<view class="addressBnt bg-color-red" @click="goAddressPages">新加地址</view>
</view>
<view class="mask" @touchmove.prevent :hidden="value === false" @click="closeAddress"></view>
</view>
</template>
<script>
import { getAddressList } from "@/api/user";
export default {
name: "AddressWindow",
props: {
value: Boolean,
checked: Number
},
data: function() {
return {
addressList: [],
current: 0,
cartId: 0,
pinkId: 0,
couponId: 0
};
},
mounted: function() {},
methods: {
getAddressList: function() {
let that = this;
getAddressList().then(res => {
that.addressList = res.data;
});
},
closeAddress() {
this.$emit("input", false);
},
goAddressPages: function() {
this.$yrouter.push({ path: "/pages/user/address/AddAddress/index" });
this.$emit("redirect");
},
tapAddress: function(index) {
this.$emit("checked", this.addressList[index]);
this.$emit("input", false);
}
}
};
</script>

210
components/Adv.vue

@ -0,0 +1,210 @@
<template>
<view class="adv-box mx20 mb10">
<!-- 模板1-->
<view class="x-f" v-if="detail.style == 1">
<image style="width: 710rpx; height: 220rpx" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
</view>
<!-- 模板2-->
<view class="type1 x-f" v-if="detail.style == 2">
<image class="type1-img" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type1-img" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<!-- 模板3-->
<view class="type2 x-bc" v-if="detail.style == 3">
<image class="type2-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<view class="y-f type2-box">
<image class="type2-img2" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill" style="border-bottom: 1rpx solid #f6f6f6"></image>
<image class="type2-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
</view>
</view>
<!-- 模板4-->
<view class="type3 x-bc" v-if="detail.style == 4">
<view class="type3-box y-f">
<image class="type3-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type3-img1" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<image class="type3-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
</view>
<!-- 模板5-->
<view class="type4 y-f" v-if="detail.style == 5">
<view class="type4-box x-f">
<image class="type4-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type4-img1" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<image class="type4-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
</view>
<!-- 模板6-->
<view class="type5 y-f" v-if="detail.style == 6">
<image class="type5-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<view class="type5-box x-bc">
<image class="type5-img2" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill" style="border-bottom: 1rpx solid #f6f6f6"></image>
<image class="type5-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
</view>
</view>
<!-- 模板7-->
<view class="type6 y-f" v-if="detail.style == 7">
<view class="x-f type6-box1">
<image class="type6-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type6-img1" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<view class="x-f type6-box2">
<image class="type6-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
<image class="type6-img2" @tap="jump(detail.list[3])" :src="detail.list[3].image" mode="aspectFill"></image>
<image class="type6-img2" @tap="jump(detail.list[4])" :src="detail.list[4].image" mode="aspectFill"></image>
</view>
</view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {}
},
props: {
detail: Object,
},
computed: {},
created() {},
methods: {
//
jump(item) {
console.log(item)
if (item) {
this.$yrouter.push(path)
}
},
},
}
</script>
<style lang="scss">
.adv-box {
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
.type1 {
.type1-img {
flex: 1;
height: 220rpx;
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
.type2 {
.type2-img1 {
width: (710rpx/2);
height: 340rpx;
border-right: 1rpx solid #f6f6f6;
}
.type2-box {
flex: 1;
height: 340rpx;
width: (710rpx/2);
.type2-img2 {
height: (340rpx/2);
}
}
}
.type3 {
.type3-box {
width: (710rpx/2);
border-right: 1rpx solid #f6f6f6;
.type3-img1 {
flex: 1;
height: (340rpx/2);
&:first-child {
border-bottom: 1rpx solid #f6f6f6;
}
}
}
.type3-img2 {
flex: 1;
height: 340rpx;
width: (710rpx/2);
}
}
.type4 {
.type4-box {
border-bottom: 1rpx solid #f6f6f6;
.type4-img1 {
flex: 1;
height: (340rpx/2);
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
.type4-img2 {
flex: 1;
height: (340rpx/2);
width: 710rpx;
}
}
.type5 {
.type5-img1 {
width: 710rpx;
height: (340rpx/2);
border-bottom: 1rpx solid #f6f6f6;
}
.type5-box {
flex: 1;
height: (340rpx/2);
width: 710rpx;
.type5-img2 {
height: (340rpx/2);
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
}
.type6 {
.type6-box1 {
.type6-img1 {
width: (710rpx/2);
height: (340rpx/2);
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
.type6-box2 {
border-top: 1rpx solid #f6f6f6;
.type6-img2 {
width: (710rpx/3);
height: (340rpx/2);
border-right: 1rpx solid #f6f6f6;
&:last-child {
border-right: 0;
}
}
}
}
image {
// background-color: #ccc;
}
}
</style>

289
components/CitySelect.vue

@ -0,0 +1,289 @@
<template>
<view>
<text class="uni-input" @tap="open">{{value}}</text>
<uni-popup ref="popup" type="bottom">
<view class="cityselect">
<view class="cityselect-header">
<view class="cityselect-title">
<text>请选择地址</text>
</view>
<view class="cityselect-nav">
<view class="item" v-if="provinceActive" @tap="changeNav(0)">
<text>{{provinceActive.n}}</text>
</view>
<view class="item" v-if="cityActive" @tap="changeNav(1)">
<text>{{cityActive.n}}</text>
</view>
<view class="item" v-if="districtActive" @tap="changeNav(2)">
<text>{{districtActive.n}}</text>
</view>
<view class="item active" v-else>
<text>请选择</text>
</view>
</view>
</view>
<view class="cityselect-content">
<swiper class="swiper" disable-touch="true" touchable="false" :current="current">
<swiper-item>
<scroll-view scroll-y class="cityScroll">
<view>
<view
class="cityselect-item"
v-for="(item,index) in province"
:key="index"
@tap="selectProvince(index)"
>
<view class="cityselect-item-box">
<text>{{item.n}}</text>
</view>
</view>
</view>
</scroll-view>
</swiper-item>
<swiper-item>
<scroll-view scroll-y class="cityScroll">
<view>
<view
class="cityselect-item"
v-for="(item,index) in city"
:key="index"
@tap="selectCity(index)"
>
<view class="cityselect-item-box">
<text>{{item.n}}</text>
</view>
</view>
</view>
</scroll-view>
</swiper-item>
<swiper-item>
<scroll-view scroll-y class="cityScroll">
<view>
<view
class="cityselect-item"
v-for="(item,index) in district"
:key="index"
@tap="selectDistrict(index)"
>
<view class="cityselect-item-box">
<text>{{item.n}}</text>
</view>
</view>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</view>
</uni-popup>
</view>
</template>
<script type="text/babel">
import uniPopup from "./uni-popup/uni-popup.vue";
import uniPopupMessage from "./uni-popup/uni-popup-message.vue";
import uniPopupDialog from "./uni-popup/uni-popup-dialog.vue";
export default {
name: "CitySelect",
components: {
uniPopup,
uniPopupMessage,
uniPopupDialog
},
props: ["callback", "items", "defaultValue"],
data() {
return {
value: "请选择",
show: this.value,
province: [],
provinceActive: null,
city: [],
cityActive: null,
district: [],
districtActive: null,
current: 0
};
},
watch: {
items(nextItem) {
this.province = nextItem;
},
defaultValue(next){
this.value=next
}
},
mounted() {
console.log(this);
if (this.value) {
this.value = this.value;
}
this.province = this.items;
},
methods: {
open() {
this.province = this.items;
this.provinceActive = null;
this.cityActive = null;
this.districtActive = null;
this.city = [];
this.district = [];
this.current = 0;
this.$refs.popup.open();
},
changeNav(index) {
if (index == 0) {
this.provinceActive = null;
}
if (index == 1) {
this.cityActive = null;
}
if (index == 2) {
this.districtActive = null;
}
this.current = index;
},
selectProvince(index) {
this.provinceActive = this.province[index];
this.city = this.province[index].c;
this.current = 1;
},
selectCity(index) {
this.cityActive = this.city[index];
this.district = this.city[index].c;
this.current = 2;
},
selectDistrict(index) {
this.districtActive = this.district[index];
this.value = `${this.provinceActive.n} ${this.cityActive.n} ${this.districtActive.n}`;
// this.callback({
// province: {
// id: this.provinceActive.v,
// name: this.provinceActive.n
// },
// city: {
// id: this.cityActive.v,
// name: this.cityActive.n
// },
// district: {
// id: this.districtActive.v,
// name: this.districtActive.n
// }
// });
this.$emit("callback", {
province: {
id: this.provinceActive.v,
name: this.provinceActive.n
},
city: {
id: this.cityActive.v,
name: this.cityActive.n
},
district: {
id: this.districtActive.v,
name: this.districtActive.n
}
});
this.$refs.popup.close();
}
}
};
</script>
<style lang="less">
.cityselect {
width: 100%;
height: 75%;
background-color: #fff;
z-index: 1502;
position: relative;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.cityScroll {
height: 100%;
}
.swiper {
height: 800rpx;
}
}
.cityselect-header {
width: 100%;
z-index: 1;
}
.cityselect-title {
width: 100%;
font-size: 30rpx;
text-align: center;
height: 95rpx;
line-height: 95rpx;
position: relative;
&:cityselect-title:after {
height: 1px;
position: absolute;
z-index: 0;
bottom: 0;
left: 0;
content: "";
width: 100%;
background-image: linear-gradient(0deg, #ececec 50%, transparent 0);
}
}
.cityselect-nav {
width: 100%;
padding-left: 20rpx;
overflow: hidden;
display: flex;
align-items: center;
justify-content: flex-start;
.item {
font-size: 26rpx;
color: #222;
display: block;
height: 80rpx;
line-height: 92rpx;
padding: 0 16rpx;
position: relative;
margin-right: 30rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 40%;
&.active {
color: #f23030 !important;
border-bottom: 1rpx solid #f23030;
}
}
}
.cityselect-content {
height: 100%;
width: 100%;
}
.cityselect-item {
.cityselect-item-box {
display: block;
padding: 0 40rpx;
position: relative;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
text-overflow: ellipsis;
line-height: 64rpx;
max-height: 65rpx;
font-size: 26rpx;
color: #333;
&:after {
content: "";
height: 1rpx;
position: absolute;
z-index: 0;
bottom: 0;
left: 0;
width: 100%;
background-image: linear-gradient(0deg, #ececec 50%, transparent 0);
}
}
}
</style>

104
components/CountDown.vue

@ -0,0 +1,104 @@
<template>
<view class="time">
{{ tipText }}
<text class="styleAll" v-if="isDay === true">{{ day }}</text>
<text class="timeTxt">{{ dayText }}</text>
<text class="styleAll">{{ hour }}</text>
<text class="timeTxt">{{ hourText }}</text>
<text class="styleAll">{{ minute }}</text>
<text class="timeTxt">{{ minuteText }}</text>
<text class="styleAll">{{ second }}</text>
<text class="timeTxt">{{ secondText }}</text>
</view>
</template>
<script>
export default {
name: "CountDown",
props: {
//
tipText: {
type: String,
default: "倒计时"
},
dayText: {
type: String,
default: "天"
},
hourText: {
type: String,
default: "时"
},
minuteText: {
type: String,
default: "分"
},
secondText: {
type: String,
default: "秒"
},
datatime: {
type: Number,
default: 0
},
isDay: {
type: Boolean,
default: true
}
},
data: function () {
return {
day: "00",
hour: "00",
minute: "00",
second: "00"
};
},
created: function () {
this.show_time();
},
mounted: function () {},
methods: {
show_time: function () {
let that = this;
function runTime() {
//
let intDiff = that.datatime - Date.parse(new Date()) / 1000; //
let day = 0,
hour = 0,
minute = 0,
second = 0;
if (intDiff > 0) {
//
if (that.isDay === true) {
day = Math.floor(intDiff / (60 * 60 * 24));
} else {
day = 0;
}
hour = Math.floor(intDiff / (60 * 60)) - day * 24;
minute = Math.floor(intDiff / 60) - day * 24 * 60 - hour * 60;
second =
Math.floor(intDiff) -
day * 24 * 60 * 60 -
hour * 60 * 60 -
minute * 60;
if (hour <= 9) hour = "0" + hour;
if (minute <= 9) minute = "0" + minute;
if (second <= 9) second = "0" + second;
that.day = day;
that.hour = hour;
that.minute = minute;
that.second = second;
} else {
that.day = "00";
that.hour = "00";
that.minute = "00";
that.second = "00";
}
}
runTime();
setInterval(runTime, 1000);
}
}
};
</script>

122
components/CouponListWindow.vue

@ -0,0 +1,122 @@
<template>
<view>
<view class="coupon-list-window" :class="value === true ? 'on' : ''">
<view class="title">
优惠券
<text class="iconfont icon-guanbi" @click="close"></text>
</view>
<view v-if="couponList.length > 0">
<view class="coupon-list">
<div
class="item acea-row row-center-wrapper"
v-for="coupon in couponList"
:key="coupon.id"
@click="click(coupon)"
>
<div class="money">
<div>
<span class="num">{{ coupon.couponPrice }}</span>
</div>
<div class="pic-num">{{ coupon.useMinPrice }}元可用</div>
</div>
<div class="text">
<div class="condition line1">{{ coupon.couponTitle }}</div>
<div class="data acea-row row-between-wrapper">
<div v-if="coupon.endTime === 0">不限时</div>
<div v-else>截止:{{ coupon.endTime }}</div>
<div
class="iconfont icon-xuanzhong1 font-color-red"
v-if="checked === coupon.id"
></div>
<div class="iconfont icon-weixuanzhong" v-else></div>
</div>
</div>
</div>
</view>
<view class="couponNo bg-color-red" @click="couponNo">不使用优惠券</view>
</view>
<view v-if="!couponList.length && loaded">
<view class="pictrue">
<image src="@/static/images/noCoupon.png" class="image" />
</view>
</view>
</view>
<view class="mask" @touchmove.prevent :hidden="value === false" @click="close"></view>
</view>
</template>
<style scoped lang="less">
.coupon-list-window .iconfont {
font-size: 40rpx;
}
.couponNo {
font-size: 30rpx;
font-weight: bold;
color: #fff;
width: 690rpx;
height: 86rpx;
border-radius: 43rpx;
text-align: center;
line-height: 86rpx;
margin: 60rpx auto;
}
</style>
<script>
import { getOrderCoupon } from "@/api/order";
import DataFormatT from "@/components/DataFormatT";
export default {
name: "CouponListWindow",
components: {
DataFormatT
},
props: {
value: Boolean,
checked: Number,
price: {
type: [Number, String],
default: undefined
},
cartid: {
type: String,
default: ""
}
},
data: function() {
return {
couponList: [],
loaded: false
};
},
watch: {
price(n) {
if (n === undefined || n == null) return;
this.getCoupon();
},
cartid(n) {
if (n === undefined || n == null) return;
this.getCoupon();
}
},
mounted: function() {},
methods: {
close: function() {
this.$emit("input", false);
this.$emit("close");
},
getCoupon() {
getOrderCoupon(this.cartid).then(res => {
this.couponList = res.data;
this.loaded = true;
});
},
click(coupon) {
this.$emit("checked", coupon);
this.$emit("input", false);
},
couponNo: function() {
this.$emit("checked", null);
this.$emit("input", false);
}
}
};
</script>

75
components/CouponPop.vue

@ -0,0 +1,75 @@
<template>
<view>
<view class="coupon-list-window" :class="coupon.coupon === true ? 'on' : ''">
<view class="title">
优惠券
<text class="iconfont icon-guanbi" @click="close"></text>
</view>
<view class="coupon-list" v-if="coupon.list.length > 0">
<view
class="item acea-row row-center-wrapper"
v-for="(item, couponpopIndex) in coupon.list"
:key="couponpopIndex"
@click="getCouponUser(couponpopIndex, item.id)"
>
<view class="money">
<text class="num">{{ item.couponPrice }}</text>
</view>
<view class="text">
<view class="condition line1">购物满{{ item.useMinPrice }}元可用</view>
<view class="data acea-row row-between-wrapper">
<view v-if="item.end_time === 0">不限时</view>
<view v-else>{{ item.startTime }}-{{ item.endTime }}</view>
<view
class="bnt acea-row row-center-wrapper"
:class="!item.isUse ? 'bg-color-red' : 'gray'"
>{{ !item.isUse ? "立即领取" : "已领取" }}</view>
</view>
</view>
</view>
</view>
<!--无优惠券-->
<view class="pictrue" v-else>
<image src="@/static/images/noCoupon.png" class="image" />
</view>
</view>
<view class="mask" @touchmove.prevent :hidden="coupon.coupon === false" @click="close"></view>
</view>
</template>
<script>
import { getCouponReceive } from "@/api/user";
export default {
name: "CouponPop",
props: {
coupon: {
type: Object,
default: () => {}
}
},
data: function() {
return {};
},
mounted: function() {},
methods: {
close: function() {
this.$emit("changeFun", { action: "changecoupon", value: false }); //$emit():
},
getCouponUser: function(index, id) {
let that = this,
list = that.coupon.list;
if (list[index].is_use === true) return;
getCouponReceive(id).then(function() {
uni.showToast({
title: "已领取",
icon: "none",
duration: 2000
});
that.$set(list[index], "is_use", true);
that.$emit("changefun", { action: "currentcoupon", value: index });
that.$emit("changeFun", { action: "changecoupon", value: false });
});
}
}
};
</script>

88
components/CouponWindow.vue

@ -0,0 +1,88 @@
<template>
<view v-if="couponList.length > 0">
<view class="coupon-window" :class="value ? 'on' : ''">
<view class="couponWinList">
<view class="item acea-row row-between-wrapper" v-for="(item, couponwindiwIndex) in couponList" :key="couponwindiwIndex">
<view class="money font-color-red">
<text class="num">{{ item.coupon_price }}</text>
</view>
<view class="text">
<view class="name">
购物买{{ item.use_min_price }}{{ item.coupon_price }}
</view>
<view v-if="item.end_time">
{{ item.start_time }}-{{ item.end_time }}
</view>
</view>
</view>
<view style="height:120rpx"></view>
</view>
<view class="lid">
<view class="bnt font-color-red" @click="checked">立即领取</view>
<view class="iconfont icon-guanbi3" @click="close"></view>
</view>
</view>
<view class="mask" @touchmove.prevent :hidden="!value"></view>
</view>
</template>
<script>
import {
mapGetters
} from "vuex";
import {handleLoginFailure} from "@/utils";
import {
couponReceiveBatch
} from "@/api/user";
export default {
name: "CouponWindow",
props: {
couponList: {
type: Array,
default: () => []
}
},
computed: mapGetters(["isLogin"]),
data: function() {
return {
value: true
};
},
mounted: function() {},
methods: {
checked() {
const isLogin = this.isLogin;
if (!isLogin) return handleLoginFailure();
const ids = this.couponList.reduce((initial, coupon) => {
initial.push(coupon.id);
return initial;
}, []);
couponReceiveBatch(ids)
.then(() => {
this.$emit("success");
uni.showToast({
title: '领取成功',
icon: 'success',
duration: 2000
});
})
.catch(() => {
uni.showToast({
title: '已领取',
icon: 'none',
duration: 2000
});
});
if (isLogin) {
this.value = false;
this.$emit("checked");
}
},
close: function() {
this.value = false;
this.$emit("close");
}
}
};
</script>

24
components/DataFormat.vue

@ -0,0 +1,24 @@
<template>
<text>{{time}}</text>
</template>
<script>
import { dataFormat } from "@/utils";
export default {
name: "DataFormat",
props: ["date"],
data: function() {
return {
time: ""
};
},
mounted() {
this.time = dataFormat(this.date);
},
watch: {
"$props.date"(props) {
this.time = dataFormat(this.date);
}
}
};
</script>

24
components/DataFormatT.vue

@ -0,0 +1,24 @@
<template>
<text>{{time}}</text>
</template>
<script>
import { dateFormatT } from "@/utils";
export default {
name: "DataFormatT",
props: ["date"],
data: function() {
return {
time: ""
};
},
mounted() {
this.time = dateFormatT(this.date);
},
watch: {
"$props.date"(props) {
this.time = dateFormatT(this.date);
}
}
};
</script>

65
components/Footer.vue

@ -0,0 +1,65 @@
<template>
<view>
<view class="footer-bg"></view>
<view id="footer" :class="[isIpx ? 'iphonex-footer' : '', 'acea-row row-middle'] ">
<view
class="item"
:class="{ on: footerIndex == tabtarIndex }"
v-for="(item, footerIndex) in footerList"
:key="footerIndex"
>
<view
class="iconfont"
:class="item.icon1 + ' ' + (footerIndex == tabtarIndex ? item.icon2 : '')"
></view>
<view>{{ item.name }}</view>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapMutations, mapActions } from "vuex";
export default {
name: "Footer",
props: {},
data: function() {
return {
footerList: [
{
name: "首页",
icon1: "icon-shouye-xianxing",
icon2: "icon-shouye",
url: "/pages/home/index"
},
{
name: "分类",
icon1: "icon-yingyongchengxu-xianxing",
icon2: "icon-yingyongchengxu",
url: "/pages/shop/GoodsClass/index"
},
{
name: "购物车",
icon1: "icon-caigou-xianxing",
icon2: "icon-caigou",
url: "/pages/shop/ShoppingCart/index"
},
{
name: "我的",
icon1: "icon-yonghu-xianxing",
icon2: "icon-yonghu",
url: "/pages/user/User/index"
}
],
isIpx: false
};
},
computed: {
...mapState(["tabtarIndex"])
},
methods: {
},
mounted() {
}
};
</script>

49
components/GoodList.vue

@ -0,0 +1,49 @@
<template>
<view class="goodList">
<view @click="routerGo(item)" class="item acea-row row-between-wrapper" v-for="(item, goodlistIndex) in goodList" :key="goodlistIndex">
<view class="pictrue">
<image :src="item.image" class="image" />
<image src="@/static/images/one.png" class="numPic" v-if="isSort === true && index === 0" />
<image src="@/static/images/two.png" class="numPic" v-if="isSort === true && index === 1" />
<image src="@/static/images/three.png" class="numPic" v-if="isSort === true && index === 2" />
</view>
<view class="underline">
<view class="text">
<view class="line1">{{ item.storeName }}</view>
<view class="money font-color-red">
<text class="num">{{ item.price }}</text>
</view>
<view class="vip-money acea-row row-middle">
<view class="vip">{{ item.otPrice || 0 }}</view>
<text class="num">已售{{ item.sales }}{{ item.unitName }}</text>
</view>
</view>
</view>
<!-- <view class="iconfont icon-gouwuche cart-color acea-row row-center-wrapper"></view> -->
</view>
</view>
</template>
<script>
export default {
name: "GoodList",
props: {
goodList: {
type: Array,
default: () => []
},
isSort: {
type: Boolean,
default: true
}
},
data: function() {
return {};
},
methods:{
routerGo(item) {
this.$yrouter.push({ path: '/pages/shop/GoodsCon/index', query: { id: item.id } });
}
}
};
</script>

59
components/Home.vue

@ -0,0 +1,59 @@
<template>
<view class="home" :style="{ top: top + 'px' }" style="position:fixed;" id="right-nav" @touchmove="touchmove($event)">
<view class="homeCon bg-color-red1" :class="homeActive === true ? 'on' : ''">
<view @click="homeGo()" class="iconfont icon-shouye-xianxing " style="color: green;"></view>
<view @click="shoppingCartGo()" class="iconfont icon-caigou-xianxing" style="color: green;"></view>
<!--<view @click="userGo()" class="iconfont icon-yonghu1"></view>-->
</view>
</view>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'Home',
props: {},
data: function() {
return {
top: '',
homeActive: true
};
},
computed: mapGetters(['homeActive']),
methods: {
userGo() {
this.$yrouter.push('/pages/user/User/index');
},
homeGo() {
this.$yrouter.switchTab('/pages/home/index');
},
shoppingCartGo() {
this.$yrouter.switchTab('/pages/shop/ShoppingCart/index');
},
touchmove(event) {
// event.preventDefault();
// let top =
// event.touches[0].pageY -
// (document.documentElement.scrollTop || document.body.scrollTop) -
// this.$el.clientHeight;
// if (top > 390) top = 390;
// else if (top < 55) top = 55;
this.top = 55;
},
}
};
</script>
<style scoped lang="less">
.mystyl {
display: inline-block;
width: 64rpx;
height: 64rpx;
margin-top:12rpx;
box-sizing: border-box;
border: 1px solid #e1e1e1;
border-radius: 50%;
background-size: 124rpx auto;
background-repeat: no-repeat;
background-color: rgba(255, 255, 255, 0.9);
}
</style>

21
components/Loading.vue

@ -0,0 +1,21 @@
<template>
<view class="Loads acea-row row-center-wrapper" v-if="loading || !loaded" style="margin-top: 20rpx;">
<template v-if="loading">
<view class="iconfont icon-jiazai loading acea-row row-center-wrapper"></view>
正在加载中
</template>
<template v-if="!loading">
上拉加载更多
</template>
</view>
</template>
<script>
export default {
name: "Loading",
props: {
loaded: Boolean,
loading: Boolean
}
};
</script>

74
components/Mask.vue

@ -0,0 +1,74 @@
<template>
<div
:class="show?'yd-mask g-fix-ios-overflow-scrolling-bug':'yd-mask' "
ref="scrollView"
:style="styles"
>
<slot></slot>
</div>
</template>
<script type="text/babel">
export default {
name: "yd-mask",
data() {
return {
show: this.value
};
},
props: {
value: {
type: Boolean,
default: false
},
bgcolor: {
type: String,
default: "#000"
},
zindex: {
default: 1500
},
opacity: {
default: 0.5
},
animated: {
type: Boolean,
default: true
}
},
computed: {
styles() {
const style = {
"z-index": this.zindex,
"background-color": this.bgcolor
};
if (this.show) {
style["opacity"] = this.opacity;
style["pointer-events"] = "auto";
}
return style;
}
},
mounted() {}
};
</script>
<style lang="less">
@css-prefix: yd;
.@{css-prefix} {
&-mask {
position: fixed;
bottom: 0;
right: 0;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
transition: opacity 0.2s ease-in;
opacity: 0;
}
}
</style>

155
components/Menu.vue

@ -0,0 +1,155 @@
<template>
<!-- 产品分类导航 -->
<view class="menu-category-box mb10" v-if="carousel" :style="list.length <= menu ? `height:200rpx` : `height:360rpx`">
<swiper
class="menu-swiper-box"
:style="list.length <= menu ? `height:160rpx` : `height:320rpx`"
@change="onSwiper"
circular
:autoplay="false"
:interval="3000"
:duration="1000"
>
<swiper-item class="menu-swiper-item" v-for="(itemList, index) in carousel" :key="index" :style="list.length <= menu ? `height:200rpx` : `height:340rpx`">
<view class="menu-tab-box">
<view class="tab-list y-f" :style="{ width: 690 / menu + 'rpx' }" v-for="item in itemList" :key="item.name" @tap="routerTo(item)">
<image class="tab-img Shop-selector-circular" :style="{ width: imgW + 'rpx', height: imgW + 'rpx' }" :src="item.pic"></image>
<text class="Shop-selector-rect">{{ item.name }}</text>
</view>
</view>
</swiper-item>
</swiper>
<view class="menu-category-dots" v-if="carousel.length > 1">
<text :class="categoryCurrent === index ? 'category-dot-active' : 'category-dot'" v-for="(dot, index) in carousel.length" :key="index"></text>
</view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {
categoryCurrent: 0 //
};
},
props: {
list: {
type: Array,
default: []
},
menu: {
default: 4
},
imgW: {
type: Number,
default: 88
}
},
computed: {
carousel() {
if (this.list) {
let list = this.sortData(this.list, this.menu * 2);
return list;
}
}
},
created() {},
methods: {
//
sortData(oArr, length) {
let arr = [];
let minArr = [];
oArr.forEach(c => {
if (minArr.length === length) {
minArr = [];
}
if (minArr.length === 0) {
arr.push(minArr);
}
minArr.push(c);
});
return arr;
},
//
onSwiper(e) {
this.categoryCurrent = e.detail.current;
},
//
routerTo(item) {
this.$yrouter.push(item.uniapp_url);
}
}
};
</script>
<style lang="scss">
//
.y-f {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.menu-category-box {
padding: 30rpx 30rpx 0 30rpx;
background: #fff;
box-sizing: border-box;
}
.menu-category-box,
.menu-swiper-box {
position: relative;
background: #fff;
.menu-swiper-item {
background: #fff;
height: 100%;
width: 100%;
}
.menu-tab-box {
display: flex;
flex-wrap: wrap;
.tab-list {
font-size: 22rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(51, 51, 51, 1);
padding-bottom: 30rpx;
.tab-img {
border-radius: 25rpx;
margin-bottom: 10rpx;
}
}
}
.menu-category-dots {
display: flex;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 20rpx;
.category-dot {
width: 40rpx;
height: 3rpx;
background: #eeeeee;
margin-right: 10rpx;
}
.category-dot-active {
width: 40rpx;
height: 3rpx;
background: #a8700d;
margin-right: 10rpx;
}
}
}
</style>

45
components/OrderGoods.vue

@ -0,0 +1,45 @@
<template>
<view class="orderGoods">
<view class="total">{{ cartInfo.length }}件商品</view>
<view class="goodWrapper">
<view class="item acea-row row-between-wrapper" v-for="cart in cartInfo" :key="cart.id">
<view class="pictrue">
<image :src="cart.productInfo.image" class="image" />
</view>
<view class="text">
<view class="acea-row row-between-wrapper">
<view class="name line1">{{ cart.productInfo.storeName }}</view>
<view class="num">x {{ cart.cartNum }}</view>
</view>
<view class="attr line1" v-if="cart.productInfo.attrInfo">{{ cart.productInfo.attrInfo.sku }}</view>
<view class="money font-color-red">{{ cart.truePrice }}</view>
<view class="evaluate" v-if="evaluate == 3 && cart.isReply == 0" @click="routerGo(cart)">评价</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'OrderGoods',
props: {
evaluate: Number,
cartInfo: {
type: Array,
default: () => [],
},
},
data: function() {
return {}
},
mounted: function() {},
methods: {
routerGo(cart) {
this.$yrouter.push({
path: '/pages/shop/GoodsEvaluate/index',
query: { id: cart.unique },
})
},
},
}
</script>

202
components/Payment.vue

@ -0,0 +1,202 @@
<template>
<view>
<view class="payment" :class="value === true ? 'on' : ''">
<view class="title acea-row row-center-wrapper">
选择付款方式<text class="iconfont icon-guanbi" @click="close"></text>
</view>
<view
class="item acea-row row-between-wrapper"
v-if="types.indexOf('weixin') !== -1"
@click="checked('weixin')"
>
<view class="left acea-row row-between-wrapper">
<view class="iconfont icon-weixinzhifu"></view>
<view class="text">
<view class="name">微信支付</view>
<view class="info">使用微信快捷支付</view>
</view>
</view>
<view class="iconfont icon-xiangyou"></view>
</view>
<!-- <view
class="item acea-row row-between-wrapper"
v-if="types.indexOf('alipay') !== -1"
@click="checked('alipay')"
>
<view class="left acea-row row-between-wrapper">
<view class="iconfont icon-zhifubao"></view>
<view class="text">
<view class="name">支付宝支付</view>
<view class="info">使用线上支付宝支付</view>
</view>
</view>
<view class="iconfont icon-xiangyou"></view>
</view> -->
<view
class="item acea-row row-between-wrapper"
v-if="types.indexOf('yue') !== -1"
@click="checked('yue')"
>
<view class="left acea-row row-between-wrapper">
<view class="iconfont icon-yuezhifu"></view>
<view class="text">
<view class="name">余额支付</view>
<view class="info">
当前可用余额<text class="money">{{ balance }}</text>
</view>
</view>
</view>
<view class="iconfont icon-xiangyou"></view>
</view>
<!-- <view
class="item acea-row row-between-wrapper"
v-if="types.indexOf('offline') !== -1"
@click="checked('offline')"
>
<view class="left acea-row row-between-wrapper">
<view class="iconfont icon-yuezhifu1"></view>
<view class="text">
<view class="name">线下支付</view>
<view class="info">选择线下付款方式</view>
</view>
</view>
<view class="iconfont icon-xiangyou"></view>
</view> -->
</view>
<view class="mask" v-show="value" @click="close"></view>
</view>
</template>
<script>
export default {
name: "Payment",
props: {
value: {
type: Boolean,
default: false
},
balance: {
type: [Number, String],
default: 0
},
types: {
type: Array,
default: () => ["weixin", "alipay", "yue", "offline"]
}
},
data: function() {
return {};
},
mounted: function() {},
methods: {
checked: function(type) {
this.$emit("checked", type);
this.close();
},
close: function() {
this.$emit("input", false);
}
}
};
</script>
<style scoped lang="less" lang="less">
.payment {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
border-radius: 0.16*100rpx 0.16*100rpx 0 0;
background-color: #fff;
padding-bottom: 0.6*100rpx;
z-index: 99;
transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
-webkit-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
-moz-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
-o-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
transform: translate3d(0, 100%, 0);
-webkit-transform: translate3d(0, 100%, 0);
-ms-transform: translate3d(0, 100%, 0);
-moz-transform: translate3d(0, 100%, 0);
-o-transform: translate3d(0, 100%, 0);
}
.payment.on {
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
}
.payment .title {
text-align: center;
height: 1.23*100rpx;
font-size: 0.32*100rpx;
color: #282828;
font-weight: bold;
padding-right: 0.3*100rpx;
margin-left: 0.3*100rpx;
position: relative;
border-bottom: 0.01*100rpx solid #eee;
}
.payment .title .iconfont {
position: absolute;
right: 0.3*100rpx;
top: 50%;
transform: translateY(-50%);
font-size: 0.43*100rpx;
color: #8a8a8a;
font-weight: normal;
}
.payment .item {
border-bottom: 0.01*100rpx solid #eee;
height: 1.3*100rpx;
margin-left: 0.3*100rpx;
padding-right: 0.3*100rpx;
}
.payment .item .left {
width: 6.1*100rpx;
}
.payment .item .left .text {
width: 5.4*100rpx;
}
.payment .item .left .text .name {
font-size: 0.32*100rpx;
color: #282828;
}
.payment .item .left .text .info {
font-size: 0.24*100rpx;
color: #999;
}
.payment .item .left .text .info .money {
color: #ff9900;
}
.payment .item .left .iconfont {
font-size: 0.45*100rpx;
color: #09bb07;
}
.payment .item .left .iconfont.icon-zhifubao {
color: #00aaea;
}
.payment .item .left .iconfont.icon-yuezhifu {
color: #ff9900;
}
.payment .item .left .iconfont.icon-yuezhifu1 {
color: #eb6623;
}
.payment .item .iconfont {
font-size: 0.3*100rpx;
color: #999;
}
</style>

133
components/PriceChange.vue

@ -0,0 +1,133 @@
<template>
<view>
<view class="priceChange" :class="change === true ? 'on' : ''">
<view class="priceTitle">
<text v-if="status==0">
<text v-if="orderInfo.refundStatus == 1">立即退款</text>
<text v-if="orderInfo.refundStatus != 1">一键改价</text>
</text>
<text v-if="status!=0">订单备注</text>
<text class="iconfont icon-guanbi" @click="close"></text>
</view>
<view class="listChange" v-if="status == 0">
<view class="item acea-row row-between-wrapper" v-if="orderInfo.refundStatus === 0">
<view>商品总价(¥)</view>
<view class="money">
{{ orderInfo.totalPrice }}
<text class="iconfont icon-suozi"></text>
</view>
</view>
<view class="item acea-row row-between-wrapper" v-if="orderInfo.refundStatus === 0">
<view>原始邮费(¥)</view>
<view class="money">
{{ orderInfo.payPostage }}
<text class="iconfont icon-suozi"></text>
</view>
</view>
<view class="item acea-row row-between-wrapper" v-if="orderInfo.refundStatus === 0">
<view>实际支付(¥)</view>
<view class="money">
<input
type="text"
v-model="price"
:class="focus === true ? 'on' : ''"
@focus="priceChange"
/>
</view>
</view>
<view class="item acea-row row-between-wrapper" v-if="orderInfo.refundStatus === 1">
<view>实际支付(¥)</view>
<view class="money">
{{ orderInfo.payPrice }}
<text class="iconfont icon-suozi"></text>
</view>
</view>
<view class="item acea-row row-between-wrapper" v-if="orderInfo.refundStatus === 1">
<view>退款金额(¥)</view>
<view class="money">
<input
type="text"
v-model="refund_price"
:class="focus === true ? 'on' : ''"
@focus="priceChange"
/>
</view>
</view>
</view>
<view class="listChange" v-else>
<textarea
:placeholder="'请填写备注信息...'"
v-model="remark"
></textarea>
</view>
<view class="modify" @click="save">{{ orderInfo.refundStatus === 0 ? "立即修改" : "确认退款" }}</view>
<view class="modify1" @click="refuse" v-if="orderInfo.refundStatus === 1">拒绝退款</view>
</view>
<view class="mask" @touchmove.prevent v-show="change === true"></view>
</view>
</template>
<style scoped lang="less" >
.priceChange .listChange textarea {
border: 1px solid #eee;
width: 100%;
height: 200rpx;
margin-top: 50rpx;
border-radius: 10rpx;
color: #333;
padding: 20rpx;
}
</style>
<script>
export default {
name: "PriceChange",
components: {},
props: {
change: Boolean,
orderInfo: Object,
status: String
},
data: function() {
return {
focus: false,
price: 0,
refund_price: 0,
remark: ""
};
},
watch: {
orderInfo: function() {
this.price = this.orderInfo.payPrice;
this.refund_price = this.orderInfo.payPrice;
this.remark = "";
}
},
mounted: function() {},
methods: {
priceChange: function() {
this.focus = true;
},
close: function() {
this.price = this.orderInfo.payPrice;
this.$emit("closechange", false);
},
save: function() {
let that = this;
that.$emit("savePrice", {
price: that.price,
refund_price: that.refund_price,
type: 1,
remark: that.remark
});
},
refuse: function() {
let that = this;
that.$emit("savePrice", {
price: that.price,
refund_price: that.refund_price,
type: 2,
remark: that.remark
});
}
}
};
</script>

71
components/ProductConSwiper.vue

@ -0,0 +1,71 @@
<template>
<view class="slider-banner product-bg">
<swiper
class="swiper-wrapper"
@change="handleChange"
v-if="imgUrls.length > 0"
>
<block v-for="(item, imgUrlsIndex) in imgUrls" :key="imgUrlsIndex">
<swiper-item>
<image :src="item" @tap="previewImage(imgUrlsIndex)" class="slide-image" />
</swiper-item>
</block>
</swiper>
<!-- <swiper class="swiper-wrapper" :options="ProductConSwiper" v-if="imgUrls.length > 0">
<swiperSlide class="swiper-slide" v-for="item in imgUrls" :key="item" ref="goodSwiper">
<image :src="item" class="slide-image" />
</swiperSlide>
</swiper>-->
<view class="pages">{{ currents || 1 }}/{{ imgUrls.length || 1 }}</view>
</view>
</template>
<script>
// import { swiper, swiperSlide } from "vue-awesome-swiper";
export default {
name: "ProductConSwiper",
components: {
// swiper,
// swiperSlide
},
props: {
imgUrls: {
type: Array,
default: () => [],
},
},
data: function () {
let that = this;
return {
currents: 1,
ProductConSwiper: {
autoplay: {
disableOnInteraction: false,
delay: 2000,
},
loop: true,
speed: 1000,
observer: true,
observeParents: true,
on: {
slideChangeTransitionStart: function () {
that.currents = this.realIndex + 1;
},
},
},
};
},
mounted: function () {},
methods: {
handleChange(event) {
this.currents = event.mp.detail.current + 1;
},
previewImage(current) {
uni.previewImage({
current,
urls: this.imgUrls,
});
},
},
};
</script>

140
components/ProductWindow.vue

@ -0,0 +1,140 @@
<template>
<view>
<view class="product-window" :class="attr.cartAttr === true ? 'on' : ''">
<view class="textpic acea-row row-between-wrapper">
<view class="pictrue">
<image @tap="previewImage" :src="attr.productSelect.image" class="image" />
</view>
<view class="text">
<view class="line1">{{ attr.productSelect.store_name }}</view>
<view class="money font-color-red" v-if="!isIntegral">
<text class="num">{{ attr.productSelect.price }}</text>
<text class="stock">库存: {{ attr.productSelect.stock }}</text>
</view>
<view class="money font-color-red" v-if="isIntegral">
<text class="num">{{ attr.productSelect.integral }}积分</text>
<text class="stock">库存: {{ attr.productSelect.stock }}</text>
</view>
</view>
<view class="iconfont icon-guanbi" @click="closeAttr"></view>
</view>
<view class="productWinList">
<view
class="item"
v-for="(item, indexw) in attr.productAttr"
:key="indexw"
>
<view class="title">{{ item.attrName }}</view>
<view class="listn acea-row row-middle">
<view
class="itemn"
:class="item.index == indexn ? 'on' : ''"
v-for="(itemn, indexn) in item.attrValue"
@click="tapAttr(indexw, indexn)"
:key="indexn"
>{{ itemn.attr }}</view
>
</view>
</view>
</view>
<view class="cart">
<view class="title">数量</view>
<view class="carnum acea-row row-left">
<view
class="item reduce"
:class="cartNum <= 1 ? 'on' : ''"
@click="CartNumDes"
>-</view
>
<view class="item num">{{ cartNum }}</view>
<view
class="item plus"
:class="cartNum >= attr.productSelect.stock ? 'on' : ''"
@click="CartNumAdd"
>+</view
>
</view>
</view>
</view>
<view
class="mask"
@touchmove.prevent
:hidden="attr.cartAttr === false"
@click="closeAttr"
></view>
</view>
</template>
<script>
export default {
name: "ProductWindow",
props: {
isIntegral:Boolean,
attr: {
type: Object,
default: () => {},
},
cartNum: {
type: Number,
default: () => 1,
},
},
data: function () {
return {};
},
mounted: function () {
console.log(this);
},
watch: {
attr(nextAttr) {
},
},
methods: {
closeAttr: function () {
this.$emit("changeFun", { action: "changeattr", value: false });
},
CartNumDes: function () {
this.$emit("changeFun", { action: "ChangeCartNum", value: false });
},
CartNumAdd: function () {
this.$emit("changeFun", { action: "ChangeCartNum", value: 1 });
},
tapAttr: function (indexw, indexn) {
//
// H5attrH5
// props
//
this.attr.productAttr[indexw].index = indexn;
let that = this;
let value = that.getCheckedValue().sort().join(",");
that.$emit("changeFun", {
action: "ChangeAttr",
value: {
value,
indexw,
indexn,
},
});
},
//
getCheckedValue: function () {
let productAttr = this.attr.productAttr;
let value = [];
for (let i = 0; i < productAttr.length; i++) {
for (let j = 0; j < productAttr[i].attrValueArr.length; j++) {
if (productAttr[i].index === j) {
value.push(productAttr[i].attrValueArr[j]);
}
}
}
return value;
},
previewImage() {
uni.previewImage({
current: 0,
urls: [this.attr.productSelect.image],
});
},
},
};
</script>

214
components/PromotionGood.vue

@ -0,0 +1,214 @@
<template>
<view>
<view class="sh-title-card mb10">
<view class="title-box">
<image class="title-bg" src="@/static/images/title1.png" mode="aspectFill"></image>
<view class="title-text">为你推荐</view>
<!-- <view class="title-text" :style="{ color: detail.color }">为你推荐</view> -->
</view>
</view>
<view class="hot-goods mx20 mb10" v-if="benefit.length">
<view class="goods-list x-f">
<view class="goods-item" v-for="(item, promotionGoodIndex) in benefit" :key="promotionGoodIndex">
<view class="goods-box" @tap="routerGo(item)">
<view class="img-box">
<!-- <image class="tag-img" :src="item.image" mode=""></image> -->
<image class="img" :src="item.image" lazy-load mode="aspectFill"></image>
</view>
<view class="tip one-t">{{ item.storeName }}</view>
<view class="title more-t">{{ item.storeName }}</view>
<view class="price-box">
<view class="flex x-bc align-end">
<view class="current">{{ item.activity_type === 'groupon' ? item.price : item.otPrice }}
</view>
<view class="sales miso-font">仅剩{{ item.stock }}{{ item.unitName }}</view>
</view>
<view class="x-f tag-box">
<!-- <view class="discount">新人礼</view>
<view class="discount">满100减60</view> -->
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'PromotionGood',
props: ['benefit'],
data: function () {
return {};
},
methods: {
routerGo(item) {
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: {
id: item.id
}
});
}
},
mounted() {}
};
</script>
<style lang="scss">
.sh-title-card {
width: 750rpx;
}
.title-box {
width: 710rpx;
height: 88rpx;
margin: 0 auto;
position: relative;
border-radius: 30rpx;
.title-bg {
width: 100%;
height: 100%;
}
.title-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
}
}
.goods-box {
width: 345rpx;
background: #fff;
padding-bottom: 20rpx;
border-radius: 20rpx;
overflow: hidden;
.img-box {
width: 345rpx;
height: 345rpx;
overflow: hidden;
position: relative;
.tag-img {
position: absolute;
left: 0;
top: 0;
z-index: 2;
width: 80rpx;
height: 40rpx;
}
.img {
width: 345rpx;
height: 345rpx;
background-color: #ccc;
}
}
.tip {
width: 346rpx;
line-height: 56rpx;
background: rgba(246, 242, 234, 1);
font-size: 22rpx;
font-family: PingFang SC;
font-weight: 400;
color: rgba(168, 112, 13, 1);
padding: 0 20rpx;
}
.title {
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
line-height: 36rpx;
height: 72rpx;
margin: 20rpx 20rpx 10rpx;
}
.price-box {
padding: 10rpx 20rpx 0;
width: 344rpx;
box-sizing: border-box;
.sales {
font-size: 20rpx;
font-family: PingFang SC;
font-weight: 400;
color: rgba(153, 153, 153, 1);
line-height: 20rpx;
margin-bottom: 20rpx;
}
.current {
font-size: 30rpx;
font-weight: 500;
color: rgba(225, 33, 43, 1);
line-height: 30rpx;
margin-bottom: 20rpx;
&:before {
content: '¥';
font-size: 26rpx;
}
}
.original {
font-size: 22rpx;
font-weight: 400;
text-decoration: line-through;
color: rgba(153, 153, 153, 1);
margin-left: 14rpx;
line-height: 22rpx;
margin-bottom: 10rpx;
&:before {
content: '¥';
font-size: 20rpx;
}
}
.tag-box {
.discount {
line-height: 28rpx;
border: 1rpx solid rgba(225, 33, 43, 1);
border-radius: 8rpx;
font-size: 18rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(225, 33, 43, 1);
padding: 0 8rpx;
margin-right: 10rpx;
}
}
}
}
//
.hot-goods {
// background: linear-gradient(#fff 200rpx, #f6f6f6 500rpx, #f6f6f6);
// border-radius: 20rpx;
.goods-list {
flex-wrap: wrap;
width: 710rpx;
.goods-item {
margin-right: 20rpx;
margin-bottom: 20rpx;
width: 345rpx;
box-shadow: 0px 0px 10rpx 4rpx rgba(199, 199, 199, 0.22);
border-radius: 20rpx;
&:nth-child(2n) {
margin-right: 0;
}
}
}
}
</style>

82
components/Recommend.vue

@ -0,0 +1,82 @@
<template>
<view class="recommend" ref="container">
<view class="title acea-row row-center-wrapper">
<text class="iconfont icon-zhuangshixian"></text>
<text class="name">为你推荐</text>
<text class="iconfont icon-zhuangshixian lefticon"></text>
</view>
<view class="recommendList acea-row row-between-wrapper">
<view @click="routerGo(item)" class="item" v-for="(item, recommendIndex) in hostProduct"
:key="recommendIndex">
<view class="pictrue">
<image :src="item.image" class="image" />
</view>
<view class="name line1">{{ item.storeName }}</view>
<view class="money font-color-red">
<text class="num">{{ item.price }}</text>
</view>
</view>
</view>
<Loading :loaded="loadend" :loading="loading"></Loading>
</view>
</template>
<script>
import {
getHostProducts
} from '@/api/store';
import Loading from '@/components/Loading';
export default {
name: 'Recommend',
props: {
recommendLoading: Boolean
},
components: {
Loading
},
watch: {
recommendLoading(nextLoading) {
if (nextLoading) {
this.hostProducts()
}
}
},
data: function () {
return {
hostProduct: [],
page: 1,
limit: 20,
loadTitle: '',
loading: false,
loadend: false
};
},
mounted: function () {
this.hostProducts();
},
methods: {
routerGo(item) {
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: {
id: item.id
}
});
},
hostProducts: function () {
let that = this;
if (that.loading) return; //false
if (that.loadend) return; //false
that.loading = true;
getHostProducts(that.page, that.limit).then(res => {
that.loading = false;
//apply();js;
that.hostProduct.push.apply(that.hostProduct, res.data);
that.loadend = res.data.length < that.limit; //
that.page = that.page + 1;
this.$emit('changeRecommendLoading', false)
});
}
},
};
</script>

40
components/ShareInfo.vue

@ -0,0 +1,40 @@
<template>
<view v-if="shareInfoStatus" class="poster-first">
<view class="mask-share">
<!-- <image src="@/static/images/share-info.png" @click="shareInfoClose" /> -->
</view>
</view>
</template>
<style scoped lang="less">
.poster-first {
overscroll-behavior: contain;
}
.mask-share {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
}
.mask-share image{
width: 100%;
}
</style>
<script>
export default {
name: "ShareInfo",
props: {
shareInfoStatus: Boolean
},
data: function() {
return {};
},
mounted: function() {},
methods: {
shareInfoClose: function() {
this.$emit("setShareInfoStatus");
}
}
};
</script>

43
components/ShareRedPackets.vue

@ -0,0 +1,43 @@
<template>
<view class="sharing-packets" :class="state === true ? 'on' : ''">
<view
class="iconfont icon-guanbi acea-row row-center-wrapper"
@click="closeShare"
></view>
<view class="line"></view>
<view class="sharing-con" @click="goShare">
<image src="@/static/images/red-packets.png" class="image" />
<view class="text font-color-red">
<view>会员分享返</view>
<view class="money"><text class="label"></text>{{ priceName }}</view>
<view class="tip">下单即返佣金</view>
<view class="shareBut">立即分享</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "ShareRedPackets",
props: {
priceName: {
type: [String, Number],
default: ""
}
},
data: function() {
return {
state: false
};
},
mounted: function() {},
methods: {
goShare: function() {
this.$emit("changeFun", { action: "shareCode", value: false });
},
closeShare: function() {
this.state = true;
}
}
};
</script>

324
components/ShopLiveCard.vue

@ -0,0 +1,324 @@
<template>
<view class="sp-live-card" :style="{ width: wh + 'rpx' }">
<view class="live-content" @tap="goRoom" :style="{ width: wh + 'rpx' }">
<image class="item-cover" :src="detail.shareImge" mode="aspectFill"></image>
<view class="item-status">
<image class="status-img" :src="liveStatus[detail.liveStatus].img" mode=""></image>
<text class="status-text">{{ liveStatus[detail.liveStatus].title }}</text>
</view>
<view class="item-title" :style="{ width: wh + 'rpx' }">{{ detail.name }}</view>
</view>
<view class="live-bottom" :style="{ width: wh + 'rpx' }">
<view class="live-info">
<view class="info-box">
<view class="info-name">{{ detail.anchorName }}</view>
</view>
</view>
<slot name="liveGoods">
<view class="live-goods" v-if="detail.product.length">
<view class="live-goods__item" v-for="(goods, index) in detail.product" :key="goods.goodsId"
v-if="index < 3">
<image class="live-goods__img" :src="goods.coverImgeUrl" mode=""></image>
<view class="live-goods__price" v-if="index < 2">{{ goods.price }}</view>
<view class="live-goods__mark" v-else>
<text>{{ detail.product.length }}+</text>
</view>
</view>
</view>
</slot>
</view>
</view>
</template>
<script>
import {
dataFormatL
} from "@/utils";
let HAS_LIVE = false
// #ifdef MP-WEIXIN
HAS_LIVE = true
let livePlayer = null;
if (HAS_LIVE) {
livePlayer = requirePlugin('live-player-plugin');
}
// #endif
let timer = null;
export default {
name: 'shopLiveCard',
components: {},
data() {
return {
liveStatus: {
'101': {
img: 'https://wx.yixiang.co/static/images/live.png',
title: '直播中'
},
'102': {
img: 'https://wx.yixiang.co/static/images/prevue.png',
title: '未开始'
},
'103': {
img: 'https://wx.yixiang.co/static/images/playback.png',
title: '已结束'
},
'104': {
img: 'https://wx.yixiang.co/static/images/104.png',
title: '禁播'
},
'105': {
img: 'https://wx.yixiang.co/static/images/105.png',
title: '暂停中'
},
'106': {
img: 'https://wx.yixiang.co/static/images/106.png',
title: '异常'
},
'107': {
img: 'https://wx.yixiang.co/static/images/past.png',
title: '已过期'
}
}
};
},
props: {
detail: {
type: Object,
default: null
},
wh: {
type: Number,
default: 345
}
},
computed: {},
created() {
this.getLiveStatus();
},
mounted() {
let that = this;
timer = setInterval(() => {
that.getLiveStatus();
}, 60000);
},
beforeDestroy() {
timer = null;
},
methods: {
goRoom() {
let that = this;
wx.navigateTo({
url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${that.detail.roomId}`
});
},
dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), //
"m+": (date.getMonth() + 1).toString(), //
"d+": date.getDate().toString(), //
"H+": date.getHours().toString(), //
"M+": date.getMinutes().toString(), //
"S+": date.getSeconds().toString() //
//
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
},
// liveStatus
getLiveStatus() {
if (HAS_LIVE) {
let that = this;
let date = '';
if (that.detail.liveStatus == 102) {
date = this.dateFormat('mm-dd HH:MM', new Date(that.detail.startTime * 1000)).replace('-','/');
that.liveStatus['102'].title = '预告 ' + date;
}
// livePlayer
// .getLiveStatus({
// room_id: that.detail.roomId
// })
// .then(res => {
// // 101: , 102: , 103: , 104: , 105: , 106: 107
// that.detail.liveStatus = res.liveStatus;
// })
// .catch(err => {
// console.log('get live status', err);
// });
}
}
}
};
</script>
<style lang="scss">
.sp-live-card {
width: 344rpx;
box-shadow: 0px 0px 10rpx 4rpx rgba(199, 199, 199, 0.22);
border-radius: 20rpx;
height: 100%;
overflow: auto;
margin-bottom: 20rpx;
}
.live-content {
position: relative;
width: 344rpx;
height: 344rpx;
overflow: hidden;
.item-cover {
background-color: #eee;
width: 100%;
height: 100%;
border-radius: 20rpx 20rpx 0 0;
}
.item-status {
position: absolute;
top: 20rpx;
left: 10rpx;
height: 40rpx;
background: rgba(0, 0, 0, 0.4);
border-radius: 20rpx;
display: flex;
justify-content: center;
align-items: center;
.status-img {
width: 40rpx;
height: 40rpx;
}
.status-text {
font-size: 22rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(255, 255, 255, 1);
padding: 0 10rpx;
}
}
.item-title {
width: 345rpx;
position: absolute;
bottom: 0;
line-height: 60rpx;
padding: 0 20rpx;
font-size: 26rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(255, 255, 255, 1);
background: linear-gradient(transparent, rgba(#000, 0.5));
padding-right: 60rpx;
}
.like-img {
position: absolute;
bottom: 20rpx;
right: 10rpx;
width: 60rpx;
height: 130rpx;
}
}
.live-bottom {
background-color: #fff;
padding: 20rpx;
width: 345rpx;
.live-info {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.info-box {
display: flex;
align-items: center;
}
.info-avatar {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
margin-right: 10rpx;
background: #eee;
}
.info-name {
width: 150rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(51, 51, 51, 1);
}
.views {
font-size: 20rpx;
font-family: PingFang SC;
font-weight: 400;
color: rgba(153, 153, 153, 1);
}
}
.live-goods {
display: flex;
align-items: center;
margin-top: 20rpx;
&__item {
position: relative;
width: 96rpx;
height: 96rpx;
border: 1rpx solid rgba(238, 238, 238, 1);
border-radius: 10rpx;
overflow: hidden;
margin-right: 8rpx;
&:nth-child(3n) {
margin-right: 0;
}
}
&__img {
background: #eee;
width: 100%;
height: 100%;
}
&__price {
position: absolute;
bottom: 0;
line-height: 40rpx;
width: 100%;
background: linear-gradient(transparent, rgba(#000, 0.5));
font-size: 20rpx;
color: #fff;
}
&__mark {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
background: rgba(#000, 0.3);
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(255, 255, 255, 1);
}
}
}
</style>

223
components/StorePoster.vue

@ -0,0 +1,223 @@
<template>
<view v-if="posterImageStatus" class="poster-first">
<div class="posterCanvasWarp">
<canvas class="posterCanvas" canvas-id="myCanvas"></canvas>
</div>
<!-- <view class="poster-pop" v-show="!canvasStatus">
<image
src="@/static/images/poster-close.png"
class="close"
@click="posterImageClose"
/>
<view class="canvas" ref="poster">
<image class="image" :src="posterData.image" alt="商品图片" />
<view class="text black">
<text v-text="posterData.title"></text>
</view>
<view class="text rad">
<text v-text="'¥' + posterData.price"></text>
</view>
<view class="code">
<view class="code-img">
<image :src="posterData.code" show-menu-by-longpress mode="widthFix" alt="二维码" />
</view>
<view class="code-text">
<text>长按识别二维码 立即购买</text>
</view>
</view>
</view>
<view class="save-poster" @click="savePosterPath">生成图片</view>
</view>-->
<view class="poster-pop" v-show="canvasStatus">
<img src="@/static/images/poster-close.png" class="close" @click="posterImageClose" mode="widthFix" />
<image :src="posterImage" alt="tp" class="poster-image" show-menu-by-longpress mode="widthFix" />
<view class="keep">长按图片可以保存到手机</view>
</view>
<view class="mask"></view>
</view>
</template>
<script>
// import html2canvas from "html2canvas";
import {
PosterCanvas
} from "@/utils";
import {
getProductPoster
} from "@/api/store";
export default {
name: "StorePoster",
props: {
posterImageStatus: Boolean,
posterData: Object,
goodId: String
},
data: function () {
return {
canvasStatus: false,
posterImage: ""
};
},
watch: {
posterImageStatus: function () {
var that = this;
if (that.posterImageStatus === true) {
that.$nextTick(function () {
that.savePosterPath();
});
}
}
},
mounted: function () {},
methods: {
posterImageClose: function () {
this.posterImageStatus = false;
this.canvasStatus = false;
this.$emit("setPosterImageStatus");
},
savePosterPath: function () {
const that = this;
uni.showLoading({
title: "海报生成中",
mask: true
});
getProductPoster(this.goodId, {
from: this.$deviceType == 'weixin' || this.$deviceType == 'weixinh5' ? 'uniappH5' : this.$deviceType
})
.then(res => {
this.canvasStatus = true;
this.posterImage = res.data;
})
.finally(() => {
uni.hideLoading();
});
// return;
// //
// that.posterImage = "";
// uni.showLoading({ title: "", mask: true });
// console.log(this);
// var prodId = that.$yrouter.currentRoute.query.id;
// uni.downloadFile({
// url:
// this.$VUE_APP_API_URL +
// "/shareImg/" +
// prodId +
// "?shareImgName=" +
// this.posterData.code,
// fail: function(res) {},
// success: function(res) {
// that.canvasStatus = true;
// that.posterImage = res.tempFilePath;
// uni.hideLoading();
// }
// });
}
}
};
</script>
<style scoped lang="less" lang="less">
.poster-first {
overscroll-behavior: contain;
}
.poster-pop {
width: 4.5 * 100rpx;
height: 8 * 100rpx;
position: fixed;
left: 50%;
transform: translateX(-50%);
z-index: 99;
top: 50%;
margin-top: -4.6 * 100rpx;
}
.poster-pop .canvas {
background-color: #ffffff;
height: 8 * 100rpx;
}
.poster-pop .poster-image {
width: 100%;
height: auto;
}
.poster-pop .canvas .image {
width: 4.5 * 100rpx;
height: 4.5 * 100rpx;
display: block;
}
.poster-pop .canvas .text {
text-align: center;
color: #000000;
margin-top: 0.32 * 100rpx;
}
.poster-pop .canvas .text.black {
height: 0.68 * 100rpx;
}
.poster-pop .canvas .text.rad {
color: #ff0000;
}
.poster-pop .canvas .code {
height: 1.4 * 100rpx;
display: flex;
}
.poster-pop .canvas .code .code-img {
width: 33%;
padding: 0.06 * 100rpx;
}
.poster-pop .canvas .code .code-img image {
width: 100%;
}
.poster-pop .canvas .code .code-text {
width: 60%;
font-size: 0.12 * 100rpx;
line-height: 1.64 * 100rpx;
}
.poster-pop .close {
width: 0.46 * 100rpx;
height: 0.75 * 100rpx;
position: fixed;
right: 0;
top: -0.73 * 100rpx;
display: block;
}
.poster-pop .save-poster {
background-color: #df2d0a;
font-size: 0.22 * 100rpx;
color: #fff;
text-align: center;
height: 0.76 * 100rpx;
line-height: 0.76 * 100rpx;
width: 100%;
margin-top: -0.04 * 100rpx;
}
.poster-pop .keep {
color: #fff;
text-align: center;
font-size: 0.25 * 100rpx;
margin-top: 0.1 * 100rpx;
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
z-index: 9;
}
</style>

155
components/SwitchWindow.vue

@ -0,0 +1,155 @@
<template>
<view>
<view class="switchWindow" :class="switchActive === true ? 'on' : ''">
<view class="pictrue">
</view>
<!-- 是否选择切换到小程序账户 -->
<view class="info">
<text>是否选择切换到</text>
<text class="font-color" v-if="login_type === 'h5'">微信账号</text>
<text class="font-color" v-else>手机用户</text>
<text></text>
</view>
<view class="switchBnt" @click="switchH5">
<text>切换</text>
</view>
<view class="switchBnt cancelBnt" @click="switchClose">
<text>取消</text>
</view>
</view>
<view class="mask" @touchmove.prevent v-show="switchActive === true" @click="switchClose"></view>
</view>
</template>
<style lang="less">
.switchWindow {
width: 5.6*100rpx;
border-radius: 0.2*100rpx;
-webkit-border-radius: 0.2*100rpx;
background-color: #fff;
position: fixed;
top: 50%;
left: 50%;
margin-left: -2.8*100rpx;
margin-top: -3*100rpx;
z-index: 99;
padding: 0.5*100rpx 0.3*100rpx 0.4*100rpx 0.3*100rpx;
text-align: center;
box-sizing: border-box;
-webkit-box-sizing: border-box;
transition: all 0.3s ease-in-out 0s;
-webkit-transition: all 0.3s ease-in-out 0s;
-moz-transition: all 0.3s ease-in-out 0s;
-o-transition: all 0.3s ease-in-out 0s;
opacity: 0;
transform: scale(0);
}
.switchWindow.on {
opacity: 1;
transform: scale(1);
-webkit-transform: scale(1);
-ms-transform: scale(1);
-moz-transform: scale(1);
-o-transform: scale(1);
}
.switchWindow .pictrue {
width: 2.36*100rpx;
height: 2.36*100rpx;
margin: 0 auto;
}
.switchWindow .pictrue image {
width: 100%;
height: 100%;
display: block;
}
.switchWindow .info {
font-size: 0.32*100rpx;
color: #282828;
margin-top: 0.44*100rpx;
font-weight: bold;
}
.switchWindow .switchBnt {
font-size: 0.32*100rpx;
color: #fff;
width: 3.6*100rpx;
height: 0.82*100rpx;
border-radius: 0.41*100rpx;
-webkit-border-radius: 0.41*100rpx;
margin: 0.57*100rpx auto 0 auto;
line-height: 0.82*100rpx;
background-image: linear-gradient(to right, #f67a38 0%, #f11b09 100%);
background-image: -webkit-linear-gradient(to right, #f67a38 0%, #f11b09 100%);
background-image: -moz-linear-gradient(to right, #f67a38 0%, #f11b09 100%);
}
.switchWindow .switchBnt.cancelBnt {
background-color: #fff;
color: #999;
background-image: none;
margin-top: 0.1*100rpx;
}
</style>
<script>
import { switchH5Login } from "@/api/user";
import cookie from "@/utils/store/cookie";
import store from "@//store";
import dayjs from "dayjs";
export default {
name: "SwitchWindow",
props: {
switchActive: {
type: Boolean,
default: false
},
login_type: {
type: String,
default: ""
}
},
data: function() {
return {};
},
mounted: function() {},
methods: {
switchClose: function() {
this.$emit("changeswitch", false); //$emit():
},
switchH5() {
let that = this;
uni.showLoading({
title: "正在切换中"
});
if (that.login_type === "h5") {
cookie.set("loginType", "wechat", 60);
uni.hideLoading();
this.$store.commit("logout");
this.$emit("changeswitch", false);
location.reload();
} else {
switchH5Login()
.then(({ data }) => {
uni.hideLoading();
const expires_time = dayjs(data.expires_time);
store.commit("login", data.token, expires_time);
this.$emit("changeswitch", false);
location.reload();
})
.catch(err => {
uni.hideLoading();
uni.showToast({
title: err.msg || err.response.data.msg|| err.response.data.message,
icon: "none",
duration: 2000
});
});
}
}
}
};
</script>

52
components/UserEvaluation.vue

@ -0,0 +1,52 @@
<template>
<view class="evaluateWtapper" v-if="reply&&reply.length>0">
<view v-for="(item, evaluateWtapperIndex) in reply" :key="evaluateWtapperIndex">
<view class="evaluateItem" v-if="item">
<view class="pic-text acea-row row-middle">
<view class="pictrue">
<image :src="item.avatar" class="image" />
</view>
<view class="acea-row row-middle">
<view class="name line1">{{ item.nickname }}</view>
<view class="start" :class="'star' + item.star"></view>
</view>
</view>
<view class="time">{{ item.createTime }} {{ item.sku||'' }}</view>
<view class="evaluate-infor">{{ item.comment }}</view>
<view class="imgList acea-row">
<view class="pictrue" v-for="(itemn, eq) in item.picturesArr" :key="eq">
<image :src="itemn" class="image" />
</view>
</view>
<view class="reply" v-if="item.merchantReplyContent">
<span class="font-color-red">yshop店员</span>
{{item.merchantReplyContent}}
</view>
</view>
</view>
</view>
</template>
<script>
import {
dataFormat
} from "@/utils";
export default {
name: "UserEvaluation",
props: {
reply: {
type: Array,
default: () => []
}
},
data: function () {
return {};
},
mounted: function () {
console.log(this)
},
methods: {
dataFormat
}
};
</script>

127
components/WriteOff.vue

@ -0,0 +1,127 @@
<template>
<view v-show="iShidden === false">
<view class="WriteOff">
<view class="num acea-row row-center-wrapper">
{{ orderInfo.orderId }}
</view>
<view class="tip">确定要核销此订单吗</view>
<view class="sure" @click="confirm">确定核销</view>
<view class="sure cancel" @click="cancel">取消</view>
</view>
<view class="mask" @touchmove.prevent></view>
</view>
</template>
<style scoped lang="less">
.WriteOff {
width: 5.6*100rpx;
height: 5*100rpx;
background-color: #fff;
border-radius: 0.2*100rpx;
position: fixed;
top: 50%;
left: 50%;
margin-top: -4*100rpx;
margin-left: -2.8*100rpx;
padding-top: 0.55*100rpx;
z-index: 99999;
}
.WriteOff .pictrue {
width: 3.4*100rpx;
height: 3.4*100rpx;
margin: 0 auto;
}
.WriteOff .pictrue image{
width: 100%;
height: 100%;
display: block;
border-radius: 0.1*100rpx;
}
.WriteOff .num {
font-size: 0.3*100rpx;
color: #666;
margin: 0.28*100rpx 0 0.3*100rpx 0;
}
.WriteOff .num .see {
font-size: 0.16*100rpx;
color: #fff;
border-radius: 0.04*100rpx;
background-color: #c68937;
padding-left: 0.05*100rpx;
margin-left: 0.12*100rpx;
}
.WriteOff .num .see .iconfont {
font-size: 0.15*100rpx;
}
.WriteOff .tip {
font-size: 0.36*100rpx;
color: #282828;
text-align: center;
border-top: 1px dashed #ccc;
padding-top: 0.4*100rpx;
position: relative;
}
.WriteOff .tip:after {
content: "";
position: absolute;
width: 0.25*100rpx;
height: 0.25*100rpx;
border-radius: 50%;
background-color: #7f7f7f;
right: -0.125*100rpx;
top: -0.125*100rpx;
}
.WriteOff .tip:before {
content: "";
position: absolute;
width: 0.25*100rpx;
height: 0.25*100rpx;
border-radius: 50%;
background-color: #7f7f7f;
left: -0.125*100rpx;
top: -0.125*100rpx;
}
.WriteOff .sure {
font-size: 0.32*100rpx;
color: #fff;
text-align: center;
line-height: 0.82*100rpx;
height: 0.82*100rpx;
width: 4.6*100rpx;
border-radius: 0.41*100rpx;
margin: 0.4*100rpx auto 0 auto;
background-image: linear-gradient(to right, #f67a38 0%, #f11b09 100%);
background-image: -webkit-linear-gradient(to right, #f67a38 0%, #f11b09 100%);
background-image: -moz-linear-gradient(to right, #f67a38 0%, #f11b09 100%);
}
.WriteOff .sure.cancel {
background-image: none;
color: #999;
margin-top: 0.1*100rpx;
}
</style>
<script>
export default {
name: "WriteOff",
props: {
iShidden: {
type: Boolean,
default: true
},
orderInfo: {
type: Object
}
},
data: function() {
return {};
},
mounted: function() {},
methods: {
cancel: function() {
this.$emit("cancel", true);
},
confirm: function() {
this.$emit("confirm", true);
}
}
};
</script>

184
components/colorui/animation.css

@ -0,0 +1,184 @@
/*
Animation 微动画
基于ColorUI组建库的动画模块 by 文晓港 2019年3月26日19:52:28
*/
/* css 滤镜 控制黑白底色gif的 */
.gif-black{
mix-blend-mode: screen;
}
.gif-white{
mix-blend-mode: multiply;
}
/* Animation css */
[class*=animation-] {
animation-duration: .5s;
animation-timing-function: ease-out;
animation-fill-mode: both
}
.animation-fade {
animation-name: fade;
animation-duration: .8s;
animation-timing-function: linear
}
.animation-scale-up {
animation-name: scale-up
}
.animation-scale-down {
animation-name: scale-down
}
.animation-slide-top {
animation-name: slide-top
}
.animation-slide-bottom {
animation-name: slide-bottom
}
.animation-slide-left {
animation-name: slide-left
}
.animation-slide-right {
animation-name: slide-right
}
.animation-shake {
animation-name: shake
}
.animation-reverse {
animation-direction: reverse
}
@keyframes fade {
0% {
opacity: 0
}
100% {
opacity: 1
}
}
@keyframes scale-up {
0% {
opacity: 0;
transform: scale(.2)
}
100% {
opacity: 1;
transform: scale(1)
}
}
@keyframes scale-down {
0% {
opacity: 0;
transform: scale(1.8)
}
100% {
opacity: 1;
transform: scale(1)
}
}
@keyframes slide-top {
0% {
opacity: 0;
transform: translateY(-100%)
}
100% {
opacity: 1;
transform: translateY(0)
}
}
@keyframes slide-bottom {
0% {
opacity: 0;
transform: translateY(100%)
}
100% {
opacity: 1;
transform: translateY(0)
}
}
@keyframes shake {
0%,
100% {
transform: translateX(0)
}
10% {
transform: translateX(-9px)
}
20% {
transform: translateX(8px)
}
30% {
transform: translateX(-7px)
}
40% {
transform: translateX(6px)
}
50% {
transform: translateX(-5px)
}
60% {
transform: translateX(4px)
}
70% {
transform: translateX(-3px)
}
80% {
transform: translateX(2px)
}
90% {
transform: translateX(-1px)
}
}
@keyframes slide-left {
0% {
opacity: 0;
transform: translateX(-100%)
}
100% {
opacity: 1;
transform: translateX(0)
}
}
@keyframes slide-right {
0% {
opacity: 0;
transform: translateX(100%)
}
100% {
opacity: 1;
transform: translateX(0)
}
}

70
components/colorui/components/cu-custom.vue

@ -0,0 +1,70 @@
<template>
<view class="cu-custom" :style="[{height:CustomBar + 'px'}]">
<view class="cu-bar fixed" :style="style" :class="[bgImage!=''?'none-bg text-white bg-img':'',bgColor]">
<view class="action" @tap="BackPage" v-if="isBack">
<text class="cuIcon-back"></text>
<slot name="backText"></slot>
</view>
<view class="content" :style="[{top:StatusBar + 'px'}]">
<slot name="content"></slot>
</view>
<slot name="right"></slot>
</view>
</view>
</template>
<script>
export default {
data() {
return {
StatusBar: this.StatusBar,
CustomBar: this.CustomBar
};
},
name: 'cu-custom',
computed: {
style() {
var StatusBar = this.StatusBar;
var CustomBar = this.CustomBar;
var bgImage = this.bgImage;
var style = `height:${CustomBar}px;padding-top:${StatusBar}px;background:${this.bgColor} ;`;
if (this.bgImage) {
style = `${style}background-image:url(${bgImage});`;
}
return style
}
},
props: {
bgColor: {
type: String,
default: ''
},
isBack: {
type: [Boolean, String],
default: false
},
bgImage: {
type: String,
default: ''
},
},
methods: {
BackPage() {
uni.navigateBack({
delta: 1
});
}
}
}
</script>
<style>
.fixed{
position: fixed;
top:0;
left:0;
right:0;
z-index: 99;
}
</style>

1226
components/colorui/icon.css
File diff suppressed because it is too large
View File

4040
components/colorui/main.css
File diff suppressed because it is too large
View File

40
components/sh-activity-goods.vue

@ -0,0 +1,40 @@
<template>
<view class="min-goods" @tap="jump('/pages/activity/GroupDetails/index', { id: detail.id })">
<view class="img-box">
<view class="tag" >{{ detail.people}}人团</view>
<image class="img" :src="detail.image" mode="widthFix"></image>
</view>
<view class="price-box">
<view class="y-f">
<text class="seckill-current">{{ detail.price }}</text>
<text class="original">销量{{ detail.sales }}{{detail.unitName}}</text>
</view>
</view>
<view class="title"><slot name="titleText"></slot></view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {};
},
props: {
detail: Object
},
computed: {},
methods: {
//
jump(path, query) {
this.$yrouter.push({
path,
query
});
}
}
};
</script>
<style lang="scss">
</style>

217
components/sh-adv.vue

@ -0,0 +1,217 @@
<template>
<view class="adv-box mx20 mb10">
<!-- 模板1-->
<view class="x-f" v-if="detail.style == 1">
<image style="width: 710rpx; height: 220rpx" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
</view>
<!-- 模板2-->
<view class="type1 x-f" v-if="detail.style == 2">
<image class="type1-img" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"> </image>
<image class="type1-img" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"> </image>
</view>
<!-- 模板3-->
<view class="type2 x-bc" v-if="detail.style == 3">
<image class="type2-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"> </image>
<view class="y-f type2-box">
<image class="type2-img2" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill" style="border-bottom: 1rpx solid #f6f6f6"></image>
<image class="type2-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
</view>
</view>
<!-- 模板4-->
<view class="type3 x-bc" v-if="detail.style == 4">
<view class="type3-box y-f">
<image class="type3-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type3-img1" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<image class="type3-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"> </image>
</view>
<!-- 模板5-->
<view class="type4 y-f" v-if="detail.style == 5">
<view class="type4-box x-f">
<image class="type4-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type4-img1" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<image class="type4-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"> </image>
</view>
<!-- 模板6-->
<view class="type5 y-f" v-if="detail.style == 6">
<image class="type5-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"> </image>
<view class="type5-box x-bc">
<image class="type5-img2" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill" style="border-bottom: 1rpx solid #f6f6f6"></image>
<image class="type5-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
</view>
</view>
<!-- 模板7-->
<view class="type6 y-f" v-if="detail.style == 7">
<view class="x-f type6-box1">
<image class="type6-img1" @tap="jump(detail.list[0])" :src="detail.list[0].image" mode="aspectFill"></image>
<image class="type6-img1" @tap="jump(detail.list[1])" :src="detail.list[1].image" mode="aspectFill"></image>
</view>
<view class="x-f type6-box2">
<image class="type6-img2" @tap="jump(detail.list[2])" :src="detail.list[2].image" mode="aspectFill"></image>
<image class="type6-img2" @tap="jump(detail.list[3])" :src="detail.list[3].image" mode="aspectFill"></image>
<image class="type6-img2" @tap="jump(detail.list[4])" :src="detail.list[4].image" mode="aspectFill"></image>
</view>
</view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {}
},
props: {
detail: Object,
},
computed: {},
created() {},
mounted() {
console.log(this)
},
methods: {
//
jump(item) {
if (item.uniapp_url) {
this.$yrouter.push(item.uniapp_url)
}
},
},
}
</script>
<style lang="scss">
.adv-box {
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
image {
width: 100%;
}
.type1 {
.type1-img {
flex: 1;
height: 220rpx;
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
.type2 {
.type2-img1 {
width: (710rpx/2);
height: 340rpx;
border-right: 1rpx solid #f6f6f6;
}
.type2-box {
flex: 1;
height: 340rpx;
width: (710rpx/2);
.type2-img2 {
height: (340rpx/2);
}
}
}
.type3 {
.type3-box {
width: (710rpx/2);
border-right: 1rpx solid #f6f6f6;
.type3-img1 {
flex: 1;
height: (340rpx/2);
&:first-child {
border-bottom: 1rpx solid #f6f6f6;
}
}
}
.type3-img2 {
flex: 1;
height: 340rpx;
width: (710rpx/2);
}
}
.type4 {
.type4-box {
border-bottom: 1rpx solid #f6f6f6;
.type4-img1 {
flex: 1;
height: (340rpx/2);
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
.type4-img2 {
flex: 1;
height: (340rpx/2);
width: 710rpx;
}
}
.type5 {
.type5-img1 {
width: 710rpx;
height: (340rpx/2);
border-bottom: 1rpx solid #f6f6f6;
}
.type5-box {
flex: 1;
height: (340rpx/2);
width: 710rpx;
.type5-img2 {
height: (340rpx/2);
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
}
.type6 {
.type6-box1 {
.type6-img1 {
width: (710rpx/2);
height: (340rpx/2);
&:first-child {
border-right: 1rpx solid #f6f6f6;
}
}
}
.type6-box2 {
border-top: 1rpx solid #f6f6f6;
.type6-img2 {
width: (710rpx/3);
height: (340rpx/2);
border-right: 1rpx solid #f6f6f6;
&:last-child {
border-right: 0;
}
}
}
}
image {
// background-color: #ccc;
}
}
</style>

197
components/sh-groupon.vue

@ -0,0 +1,197 @@
<template>
<!-- 今日必拼 -->
<view class="group-goods pa20 mx20 mb10">
<view class="title-box x-bc" @tap="jump('/pages/activity/GoodsGroup/index')">
<text class="title">超值拼团</text>
<view class="group-people x-f">
<text class="tip">更多</text>
<text class="cuIcon-right"></text>
</view>
</view>
<view class="goods-box swiper-box x-f">
<swiper class="carousel" circular @change="swiperChange" :autoplay="true" duration="2000">
<swiper-item v-for="(goods, index) in goodsList" :key="index" class="carousel-item">
<view class="goods-list-box x-f">
<block v-for="mgoods in goods" :key="mgoods.id">
<sh-activity-goods :detail="mgoods" class="goods-item">
<!-- <block slot="titleText">立减8.5</block> -->
</sh-activity-goods>
</block>
</view>
</swiper-item>
</swiper>
<view class="swiper-dots" v-if="goodsList.length > 1">
<text :class="swiperCurrent === index ? 'dot-active' : 'dot'" v-for="(dot, index) in goodsList.length"
:key="index"></text>
</view>
</view>
</view>
</template>
<script>
import shActivityGoods from './sh-activity-goods.vue';
export default {
name: 'shGroupon',
components: {
shActivityGoods
},
data() {
return {
goodsList: [],
swiperCurrent: 0
};
},
props: {
detail: Array
},
computed: {},
created() {},
watch: {
detail(next) {
this.goodsList = this.sortData(next, 4);
}
},
methods: {
swiperChange(e) {
this.swiperCurrent = e.detail.current;
},
//
sortData(oArr, length) {
let arr = [];
let minArr = [];
oArr.forEach(c => {
if (minArr.length === length) {
minArr = [];
}
if (minArr.length === 0) {
arr.push(minArr);
}
minArr.push(c);
});
return arr;
},
jump(path, query) {
this.$yrouter.push({
path,
query,
});
},
}
};
</script>
<style lang="scss">
.swiper-box,
.carousel {
width: 700rpx;
height: 240upx;
position: relative;
border-radius: 20rpx;
.carousel-item {
width: 100%;
height: 100%;
// padding: 0 28upx;
overflow: hidden;
}
.swiper-image {
width: 100%;
height: 100%;
// border-radius: 10upx;
background: #ccc;
}
}
.swiper-dots {
display: flex;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0rpx;
z-index: 66;
.dot {
width: 45rpx;
height: 3rpx;
background: #eee;
border-radius: 50%;
margin-right: 10rpx;
}
.dot-active {
width: 45rpx;
height: 3rpx;
background: #a8700d;
border-radius: 50%;
margin-right: 10rpx;
}
}
// +
.group-goods {
background: #fff;
border-radius: 20rpx;
overflow: hidden;
.title-box {
padding-bottom: 20rpx;
.title {
font-size: 32rpx;
font-weight: bold;
}
.group-people {
.time-box {
font-size: 26rpx;
color: #edbf62;
.count-text-box {
width: 30rpx;
height: 34rpx;
background: #edbf62;
text-align: center;
line-height: 34rpx;
font-size: 24rpx;
border-radius: 6rpx;
color: rgba(#fff, 0.9);
margin: 0 8rpx;
}
}
.head-box {
.head-img {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: #ccc;
}
}
.tip {
font-size: 28rpx;
padding-left: 30rpx;
color: #666;
}
.cuIcon-right {
font-size: 30rpx;
line-height: 28rpx;
color: #666;
}
}
}
.goods-box {
.goods-item {
margin-right: 22rpx;
&:nth-child(4n) {
margin-right: 0;
}
}
}
}
</style>

495
components/tui-button/tui-button.vue

@ -0,0 +1,495 @@
<template>
<button class="tui-btn" :class="[plain ? 'tui-' + type + '-outline' : 'tui-btn-' + (type || 'primary'), getDisabledClass(disabled, type, plain), getShapeClass(shape, plain), getShadowClass(type, shadow, plain), bold ? 'tui-text-bold' : '', link ? 'tui-btn__link' : '']" :hover-class="getHoverClass(disabled, type, plain)" :style="{ width: width, height: height, lineHeight: height, fontSize: size + 'rpx', margin: margin }" :loading="loading" :form-type="formType" :open-type="openType" @getuserinfo="bindgetuserinfo" @getphonenumber="bindgetphonenumber" @contact="bindcontact" @error="binderror" :disabled="disabled" @tap="handleClick">
<slot></slot>
</button>
</template>
<script>
export default {
name: 'tui-button',
props: {
// primary, white, danger, warning, green,blue, grayblack,brown,gray-primary,gray-danger,gray-warning,gray-green
type: {
type: String,
default: 'primary',
},
//
shadow: {
type: Boolean,
default: false,
},
// rpx %
width: {
type: String,
default: '100%',
},
// rpx
height: {
type: String,
default: '96rpx',
},
// rpx
size: {
type: Number,
default: 32,
},
bold: {
type: Boolean,
default: false,
},
margin: {
type: String,
default: '0',
},
// circle(), square()rightAngle()
shape: {
type: String,
default: 'square',
},
plain: {
type: Boolean,
default: false,
},
//linkplain使
link: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// button
disabledGray: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
formType: {
type: String,
default: '',
},
openType: {
type: String,
default: '',
},
index: {
type: [Number, String],
default: 0,
},
//200ms
preventClick: {
type: Boolean,
default: false,
},
},
data() {
return {
time: 0,
}
},
methods: {
handleClick() {
if (this.disabled) return
if (this.preventClick) {
if (new Date().getTime() - this.time <= 200) return
this.time = new Date().getTime()
setTimeout(() => {
this.time = 0
}, 200)
}
this.$emit('click', {
index: Number(this.index),
})
},
bindgetuserinfo({ detail = {} } = {}) {
this.$emit('getuserinfo', detail)
},
bindcontact({ detail = {} } = {}) {
this.$emit('contact', detail)
},
bindgetphonenumber({ detail = {} } = {}) {
this.$emit('getphonenumber', detail)
},
binderror({ detail = {} } = {}) {
this.$emit('error', detail)
},
getShadowClass: function(type, shadow, plain) {
let className = ''
if (shadow && type != 'white' && !plain) {
className = 'tui-shadow-' + type
}
return className
},
getDisabledClass: function(disabled, type, plain) {
let className = ''
if (disabled && type != 'white' && type.indexOf('-') == -1) {
let classVal = this.disabledGray ? 'tui-gray-disabled' : 'tui-dark-disabled'
className = plain ? 'tui-dark-disabled-outline' : classVal
}
return className
},
getShapeClass: function(shape, plain) {
let className = ''
if (shape == 'circle') {
className = plain ? 'tui-outline-fillet' : 'tui-fillet'
} else if (shape == 'rightAngle') {
className = plain ? 'tui-outline-rightAngle' : 'tui-rightAngle'
}
return className
},
getHoverClass: function(disabled, type, plain) {
let className = ''
if (!disabled) {
className = plain ? 'tui-outline-hover' : 'tui-' + (type || 'primary') + '-hover'
}
return className
},
},
}
</script>
<style scoped>
.tui-btn-primary {
background: #5677fc !important;
color: #fff;
}
.tui-shadow-primary {
box-shadow: 0 10rpx 14rpx 0 rgba(86, 119, 252, 0.2);
}
.tui-btn-danger {
background: #eb0909 !important;
color: #fff;
}
.tui-shadow-danger {
box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.2);
}
.tui-btn-warning {
background: #fc872d !important;
color: #fff;
}
.tui-shadow-warning {
box-shadow: 0 10rpx 14rpx 0 rgba(252, 135, 45, 0.2);
}
.tui-btn-green {
background: #07c160 !important;
color: #fff;
}
.tui-shadow-green {
box-shadow: 0 10rpx 14rpx 0 rgba(7, 193, 96, 0.2);
}
.tui-btn-blue {
background: #007aff !important;
color: #fff;
}
.tui-shadow-blue {
box-shadow: 0 10rpx 14rpx 0 rgba(0, 122, 255, 0.2);
}
.tui-btn-white {
background: #fff !important;
color: #333 !important;
}
.tui-btn-gray {
background: #bfbfbf !important;
color: #fff !important;
}
.tui-btn-black {
background: #333 !important;
color: #fff !important;
}
.tui-btn-brown {
background: #ac9157 !important;
color: #fff !important;
}
.tui-btn-gray-black {
background: #f2f2f2 !important;
color: #333;
}
.tui-btn-gray-primary {
background: #f2f2f2 !important;
color: #5677fc !important;
}
.tui-gray-primary-hover {
background: #d9d9d9 !important;
}
.tui-btn-gray-green {
background: #f2f2f2 !important;
color: #07c160 !important;
}
.tui-gray-green-hover {
background: #d9d9d9 !important;
}
.tui-btn-gray-danger {
background: #f2f2f2 !important;
color: #eb0909 !important;
}
.tui-gray-danger-hover {
background: #d9d9d9 !important;
}
.tui-btn-gray-warning {
background: #f2f2f2 !important;
color: #fc872d !important;
}
.tui-gray-warning-hover {
background: #d9d9d9 !important;
}
.tui-shadow-gray {
box-shadow: 0 10rpx 14rpx 0 rgba(191, 191, 191, 0.2);
}
.tui-hover-gray {
background: #f7f7f9 !important;
}
.tui-black-hover {
background: #555 !important;
color: #e5e5e5 !important;
}
.tui-brown-hover {
background: #a37f49 !important;
color: #e5e5e5 !important;
}
/* button start*/
.tui-btn {
width: 100%;
position: relative;
border: 0 !important;
border-radius: 6rpx;
padding-left: 0;
padding-right: 0;
overflow: visible;
}
.tui-btn::after {
content: '';
position: absolute;
width: 200%;
height: 200%;
transform-origin: 0 0;
transform: scale(0.5, 0.5) translateZ(0);
box-sizing: border-box;
left: 0;
top: 0;
border-radius: 12rpx;
border: 0;
}
.tui-text-bold {
font-weight: bold;
}
.tui-btn-white::after {
border: 1px solid #bfbfbf;
}
.tui-white-hover {
background: #e5e5e5 !important;
color: #2e2e2e !important;
}
.tui-dark-disabled {
opacity: 0.6 !important;
color: #fafbfc !important;
}
.tui-dark-disabled-outline {
opacity: 0.5 !important;
}
.tui-gray-disabled {
background: #f3f3f3 !important;
color: #919191 !important;
box-shadow: none;
}
.tui-outline-hover {
opacity: 0.5;
}
.tui-primary-hover {
background: #4a67d6 !important;
color: #e5e5e5 !important;
}
.tui-primary-outline::after {
border: 1px solid #5677fc !important;
}
.tui-primary-outline {
color: #5677fc !important;
background: transparent;
}
.tui-danger-hover {
background: #c80808 !important;
color: #e5e5e5 !important;
}
.tui-danger-outline {
color: #eb0909 !important;
background: transparent;
}
.tui-danger-outline::after {
border: 1px solid #eb0909 !important;
}
.tui-warning-hover {
background: #d67326 !important;
color: #e5e5e5 !important;
}
.tui-warning-outline {
color: #fc872d !important;
background: transparent;
}
.tui-warning-outline::after {
border: 1px solid #fc872d !important;
}
.tui-green-hover {
background: #06ad56 !important;
color: #e5e5e5 !important;
}
.tui-green-outline {
color: #07c160 !important;
background: transparent;
}
.tui-green-outline::after {
border: 1px solid #07c160 !important;
}
.tui-blue-hover {
background: #0062cc !important;
color: #e5e5e5 !important;
}
.tui-blue-outline {
color: #007aff !important;
background: transparent;
}
.tui-blue-outline::after {
border: 1px solid #007aff !important;
}
/* #ifndef APP-NVUE */
.tui-btn-gradual {
background: linear-gradient(90deg, rgb(255, 89, 38), rgb(240, 14, 44)) !important;
color: #fff !important;
}
.tui-shadow-gradual {
box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.15);
}
/* #endif */
.tui-gray-hover {
background: #a3a3a3 !important;
color: #898989;
}
/* #ifndef APP-NVUE */
.tui-gradual-hover {
background: linear-gradient(90deg, #d74620, #cd1225) !important;
color: #fff !important;
}
/* #endif */
.tui-gray-outline {
color: #999 !important;
background: transparent !important;
}
.tui-white-outline {
color: #fff !important;
background: transparent !important;
}
.tui-black-outline {
background: transparent !important;
color: #333 !important;
}
.tui-gray-outline::after {
border: 1px solid #ccc !important;
}
.tui-white-outline::after {
border: 1px solid #fff !important;
}
.tui-black-outline::after {
border: 1px solid #333 !important;
}
.tui-brown-outline {
color: #ac9157 !important;
background: transparent;
}
.tui-brown-outline::after {
border: 1px solid #ac9157 !important;
}
/*圆角 */
.tui-fillet {
border-radius: 50rpx;
}
.tui-btn-white.tui-fillet::after {
border-radius: 98rpx;
}
.tui-outline-fillet::after {
border-radius: 98rpx;
}
/*平角*/
.tui-rightAngle {
border-radius: 0;
}
.tui-btn-white.tui-rightAngle::after {
border-radius: 0;
}
.tui-outline-rightAngle::after {
border-radius: 0;
}
.tui-btn__link::after {
border: 0 !important;
}
</style>

103
components/tui-divider/tui-divider.vue

@ -0,0 +1,103 @@
<template>
<view class="tui-divider" :style="{ height: height + 'rpx' }">
<view class="tui-divider-line" :style="{ width: width, background: getBgColor(gradual, gradualColor, dividerColor) }"></view>
<view
class="tui-divider-text"
:style="{ color: color, fontSize: size + 'rpx', lineHeight: size + 'rpx', backgroundColor: backgroundColor, fontWeight: bold ? 'bold' : 'normal' }"
>
<slot></slot>
</view>
</view>
</template>
<script>
export default {
name: 'tuiDivider',
props: {
//divider
height: {
type: Number,
default: 100
},
//divider400rpx
width: {
type: String,
default: '100%'
},
//divider线
dividerColor: {
type: String,
default: '#e5e5e5'
},
//
color: {
type: String,
default: '#999'
},
// rpx
size: {
type: Number,
default: 24
},
bold: {
type: Boolean,
default: false
},
//
backgroundColor: {
type: String,
default: '#fafafa'
},
//线truedivideColor
gradual: {
type: Boolean,
default: false
},
//to right
gradualColor: {
type: Array,
default: function() {
return ['#eee', '#ccc'];
}
}
},
methods: {
getBgColor: function(gradual, gradualColor, dividerColor) {
let bgColor = dividerColor;
if (gradual) {
bgColor = 'linear-gradient(to right,' + gradualColor[0] + ',' + gradualColor[1] + ',' + gradualColor[1] + ',' + gradualColor[0] + ')';
}
return bgColor;
}
}
};
</script>
<style scoped>
.tui-divider {
width: 100%;
position: relative;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
overflow: hidden;
}
.tui-divider-line {
position: absolute;
height: 1rpx;
top: 50%;
left: 50%;
-webkit-transform: scaleY(0.5) translateX(-50%) translateZ(0);
transform: scaleY(0.5) translateX(-50%) translateZ(0);
}
.tui-divider-text {
position: relative;
text-align: center;
padding: 0 18rpx;
z-index: 1;
}
</style>

354
components/tui-tag/tui-tag.vue

@ -0,0 +1,354 @@
<template>
<view class="tui-tag" :hover-class="hover ? 'tui-tag-opcity' : ''" :hover-stay-time="150" :class="[originLeft ? 'tui-origin-left' : '', originRight ? 'tui-origin-right' : '', getClassName(shape, plain), getTypeClass(type, plain)]"
:style="{ transform: `scale(${scaleMultiple})`, padding: padding, margin: margin, fontSize: size, lineHeight: size }"
@tap="handleClick">
<slot></slot>
</view>
</template>
<script>
export default {
name: 'tuiTag',
props: {
type: {
type: String,
default: 'primary'
},
//padding
padding: {
type: String,
default: '16rpx 26rpx'
},
margin: {
type: String,
default: '0'
},
// rpx
size: {
type: String,
default: '28rpx'
},
// circle, squarecircleLeftcircleRight
shape: {
type: String,
default: 'square'
},
//
plain: {
type: Boolean,
default: false
},
//
hover: {
type: Boolean,
default: false
},
//
scaleMultiple: {
type: Number,
default: 1
},
originLeft: {
type: Boolean,
default: false
},
originRight: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
methods: {
handleClick() {
this.$emit('click', {
index: this.index
});
},
getTypeClass: function(type, plain) {
return plain ? 'tui-' + type + '-outline' : 'tui-' + type;
},
getClassName: function(shape, plain) {
//circle, squarecircleLeftcircleRight
var className = plain ? 'tui-tag-outline ' : '';
if (shape != 'square') {
if (shape == 'circle') {
className = className + (plain ? 'tui-tag-outline-fillet' : 'tui-tag-fillet');
} else if (shape == 'circleLeft') {
className = className + 'tui-tag-fillet-left';
} else if (shape == 'circleRight') {
className = className + 'tui-tag-fillet-right';
}
}
return className;
}
}
};
</script>
<style scoped>
/* color start*/
.tui-primary {
background-color: #5677fc !important;
color: #fff;
}
.tui-light-primary {
background-color: #5c8dff !important;
color: #fff;
}
.tui-dark-primary {
background-color: #4a67d6 !important;
color: #fff;
}
.tui-dLight-primary {
background-color: #4e77d9 !important;
color: #fff;
}
.tui-danger {
background-color: #ed3f14 !important;
color: #fff;
}
.tui-red {
background-color: #ff201f !important;
color: #fff;
}
.tui-warning {
background-color: #ff7900 !important;
color: #fff;
}
.tui-green {
background-color: #19be6b !important;
color: #fff;
}
.tui-high-green {
background-color: #52dcae !important;
color: #52dcae;
}
.tui-black {
background-color: #000 !important;
color: #fff;
}
.tui-white {
background-color: #fff !important;
color: #333 !important;
}
.tui-translucent {
background-color: rgba(0, 0, 0, 0.7);
}
.tui-light-black {
background-color: #333 !important;
}
.tui-gray {
background-color: #ededed !important;
}
.tui-phcolor-gray {
background-color: #ccc !important;
}
.tui-divider-gray {
background-color: #eaeef1 !important;
}
.tui-btn-gray {
background-color: #ededed !important;
color: #999 !important;
}
.tui-hover-gray {
background-color: #f7f7f9 !important;
}
.tui-bg-gray {
background-color: #fafafa !important;
}
.tui-light-blue {
background-color: #ecf6fd;
color: #4dabeb !important;
}
.tui-light-brownish {
background-color: #fcebef;
color: #8a5966 !important;
}
.tui-light-orange {
background-color: #fef5eb;
color: #faa851 !important;
}
.tui-light-green {
background-color: #e8f6e8;
color: #44cf85 !important;
}
.tui-primary-outline::after {
border: 1px solid #5677fc !important;
}
.tui-primary-outline {
color: #5677fc !important;
background-color: none;
}
.tui-danger-outline {
color: #ed3f14 !important;
background-color: none;
}
.tui-danger-outline::after {
border: 1px solid #ed3f14 !important;
}
.tui-red-outline {
color: #ff201f !important;
background-color: none;
}
.tui-red-outline::after {
border: 1px solid #ff201f !important;
}
.tui-warning-outline {
color: #ff7900 !important;
background-color: none;
}
.tui-warning-outline::after {
border: 1px solid #ff7900 !important;
}
.tui-green-outline {
color: #44cf85 !important;
background-color: none;
}
.tui-green-outline::after {
border: 1px solid #44cf85 !important;
}
.tui-high-green-outline {
color: #52dcae !important;
background-color: none;
}
.tui-high-green-outline::after {
border: 1px solid #52dcae !important;
}
.tui-gray-outline {
color: #999 !important;
background-color: none;
}
.tui-gray-outline::after {
border: 1px solid #ccc !important;
}
.tui-black-outline {
color: #333 !important;
background-color: none;
}
.tui-black-outline::after {
border: 1px solid #333 !important;
}
.tui-white-outline {
color: #fff !important;
background-color: none;
}
.tui-white-outline::after {
border: 1px solid #fff !important;
}
/* color end*/
/* tag start*/
.tui-tag {
display: flex;
align-items: center;
justify-content: center;
border-radius: 6rpx;
flex-shrink: 0;
}
.tui-tag-outline {
position: relative;
background-color: none;
color: #5677fc;
}
.tui-tag-outline::after {
content: ' ';
position: absolute;
width: 200%;
height: 200%;
transform: scale(0.5) translateZ(0);
transform-origin: 0 0;
box-sizing: border-box;
left: 0;
top: 0;
border-radius: 12rpx;
}
.tui-tag-fillet {
border-radius: 50rpx;
}
.tui-white.tui-tag-fillet::after {
border-radius: 80rpx;
}
.tui-tag-outline-fillet::after {
border-radius: 80rpx;
}
.tui-tag-fillet-left {
border-radius: 50rpx 0 0 50rpx;
}
.tui-tag-fillet-right {
border-radius: 0 50rpx 50rpx 0;
}
.tui-tag-fillet-left.tui-tag-outline::after {
border-radius: 100rpx 0 0 100rpx;
}
.tui-tag-fillet-right.tui-tag-outline::after {
border-radius: 0 100rpx 100rpx 0;
}
/* tag end*/
.tui-origin-left {
transform-origin: 0 center;
}
.tui-origin-right {
transform-origin: 100% center;
}
.tui-tag-opcity {
opacity: 0.5;
}
</style>

132
components/uni-icons/icons.js

@ -0,0 +1,132 @@
export default {
"pulldown": "\ue588",
"refreshempty": "\ue461",
"back": "\ue471",
"forward": "\ue470",
"more": "\ue507",
"more-filled": "\ue537",
"scan": "\ue612",
"qq": "\ue264",
"weibo": "\ue260",
"weixin": "\ue261",
"pengyouquan": "\ue262",
"loop": "\ue565",
"refresh": "\ue407",
"refresh-filled": "\ue437",
"arrowthindown": "\ue585",
"arrowthinleft": "\ue586",
"arrowthinright": "\ue587",
"arrowthinup": "\ue584",
"undo-filled": "\ue7d6",
"undo": "\ue406",
"redo": "\ue405",
"redo-filled": "\ue7d9",
"bars": "\ue563",
"chatboxes": "\ue203",
"camera": "\ue301",
"chatboxes-filled": "\ue233",
"camera-filled": "\ue7ef",
"cart-filled": "\ue7f4",
"cart": "\ue7f5",
"checkbox-filled": "\ue442",
"checkbox": "\ue7fa",
"arrowleft": "\ue582",
"arrowdown": "\ue581",
"arrowright": "\ue583",
"smallcircle-filled": "\ue801",
"arrowup": "\ue580",
"circle": "\ue411",
"eye-filled": "\ue568",
"eye-slash-filled": "\ue822",
"eye-slash": "\ue823",
"eye": "\ue824",
"flag-filled": "\ue825",
"flag": "\ue508",
"gear-filled": "\ue532",
"reload": "\ue462",
"gear": "\ue502",
"hand-thumbsdown-filled": "\ue83b",
"hand-thumbsdown": "\ue83c",
"hand-thumbsup-filled": "\ue83d",
"heart-filled": "\ue83e",
"hand-thumbsup": "\ue83f",
"heart": "\ue840",
"home": "\ue500",
"info": "\ue504",
"home-filled": "\ue530",
"info-filled": "\ue534",
"circle-filled": "\ue441",
"chat-filled": "\ue847",
"chat": "\ue263",
"mail-open-filled": "\ue84d",
"email-filled": "\ue231",
"mail-open": "\ue84e",
"email": "\ue201",
"checkmarkempty": "\ue472",
"list": "\ue562",
"locked-filled": "\ue856",
"locked": "\ue506",
"map-filled": "\ue85c",
"map-pin": "\ue85e",
"map-pin-ellipse": "\ue864",
"map": "\ue364",
"minus-filled": "\ue440",
"mic-filled": "\ue332",
"minus": "\ue410",
"micoff": "\ue360",
"mic": "\ue302",
"clear": "\ue434",
"smallcircle": "\ue868",
"close": "\ue404",
"closeempty": "\ue460",
"paperclip": "\ue567",
"paperplane": "\ue503",
"paperplane-filled": "\ue86e",
"person-filled": "\ue131",
"contact-filled": "\ue130",
"person": "\ue101",
"contact": "\ue100",
"images-filled": "\ue87a",
"phone": "\ue200",
"images": "\ue87b",
"image": "\ue363",
"image-filled": "\ue877",
"location-filled": "\ue333",
"location": "\ue303",
"plus-filled": "\ue439",
"plus": "\ue409",
"plusempty": "\ue468",
"help-filled": "\ue535",
"help": "\ue505",
"navigate-filled": "\ue884",
"navigate": "\ue501",
"mic-slash-filled": "\ue892",
"search": "\ue466",
"settings": "\ue560",
"sound": "\ue590",
"sound-filled": "\ue8a1",
"spinner-cycle": "\ue465",
"download-filled": "\ue8a4",
"personadd-filled": "\ue132",
"videocam-filled": "\ue8af",
"personadd": "\ue102",
"upload": "\ue402",
"upload-filled": "\ue8b1",
"starhalf": "\ue463",
"star-filled": "\ue438",
"star": "\ue408",
"trash": "\ue401",
"phone-filled": "\ue230",
"compose": "\ue400",
"videocam": "\ue300",
"trash-filled": "\ue8dc",
"download": "\ue403",
"chatbubble-filled": "\ue232",
"chatbubble": "\ue202",
"cloud-download": "\ue8e4",
"cloud-upload-filled": "\ue8e5",
"cloud-upload": "\ue8e6",
"cloud-download-filled": "\ue8e9",
"headphones":"\ue8bf",
"shop":"\ue609"
}

67
components/uni-icons/uni-icons.vue
File diff suppressed because it is too large
View File

395
components/uni-notice-bar/uni-notice-bar.vue

@ -0,0 +1,395 @@
<template>
<view v-if="show" class="uni-noticebar" :style="{ backgroundColor: backgroundColor }" @click="onClick">
<!-- #ifdef MP-ALIPAY -->
<view v-if="showClose === true || showClose === 'true'" class="uni-noticebar-close" @click="close">
<uni-icons type="closeempty" :color="color" size="12" />
</view>
<view v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon">
<uni-icons type="sound" :color="color" size="14" />
</view>
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<uni-icons v-if="showClose === true || showClose === 'true'" class="uni-noticebar-close" type="closeempty" :color="color"
size="12" @click="close" />
<uni-icons v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon" type="sound" :color="color"
size="14" />
<!-- #endif -->
<view ref="textBox" class="uni-noticebar__content-wrapper" :class="{'uni-noticebar__content-wrapper--scrollable':scrollable, 'uni-noticebar__content-wrapper--single':!scrollable && (single || moreText)}">
<view :id="elIdBox" class="uni-noticebar__content" :class="{'uni-noticebar__content--scrollable':scrollable, 'uni-noticebar__content--single':!scrollable && (single || moreText)}">
<text :id="elId" ref="animationEle" class="uni-noticebar__content-text" :class="{'uni-noticebar__content-text--scrollable':scrollable,'uni-noticebar__content-text--single':!scrollable && (single || moreText)}"
:style="{color:color, width:wrapWidth+'px', 'animationDuration': animationDuration, '-webkit-animationDuration': animationDuration ,animationPlayState: webviewHide?'paused':animationPlayState,'-webkit-animationPlayState':webviewHide?'paused':animationPlayState, animationDelay: animationDelay, '-webkit-animationDelay':animationDelay}">{{text}}</text>
</view>
</view>
<view v-if="showGetMore === true || showGetMore === 'true'" class="uni-noticebar__more" @click="clickMore">
<text v-if="moreText" :style="{ color: moreColor }" class="uni-noticebar__more-text">{{ moreText }}</text>
<uni-icons type="arrowright" :color="moreColor" size="14" />
</view>
</view>
</template>
<script>
import uniIcons from '../uni-icons/uni-icons.vue'
// #ifdef APP-NVUE
const dom = weex.requireModule('dom');
const animation = weex.requireModule('animation');
// #endif
/**
* NoticeBar 自定义导航栏
* @description 通告栏组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=30
* @property {Number} speed 文字滚动的速度默认100px/
* @property {String} text 显示文字
* @property {String} backgroundColor 背景颜色
* @property {String} color 文字颜色
* @property {String} moreColor 查看更多文字的颜色
* @property {String} moreText 设置查看更多的文本
* @property {Boolean} single = [true|false] 是否单行
* @property {Boolean} scrollable = [true|false] 是否滚动为true时NoticeBar为单行
* @property {Boolean} showIcon = [true|false] 是否显示左侧喇叭图标
* @property {Boolean} showClose = [true|false] 是否显示左侧关闭按钮
* @property {Boolean} showGetMore = [true|false] 是否显示右侧查看更多图标为true时NoticeBar为单行
* @event {Function} click 点击 NoticeBar 触发事件
* @event {Function} close 关闭 NoticeBar 触发事件
* @event {Function} getmore 点击查看更多时触发事件
*/
export default {
name: 'UniNoticeBar',
components: {
uniIcons
},
props: {
text: {
type: String,
default: ''
},
moreText: {
type: String,
default: ''
},
backgroundColor: {
type: String,
default: '#fffbe8'
},
speed: {
// 1s100px
type: Number,
default: 100
},
color: {
type: String,
default: '#de8c17'
},
moreColor: {
type: String,
default: '#999999'
},
single: {
//
type: [Boolean, String],
default: false
},
scrollable: {
//
type: [Boolean, String],
default: false
},
showIcon: {
// icon
type: [Boolean, String],
default: false
},
showGetMore: {
//
type: [Boolean, String],
default: false
},
showClose: {
//
type: [Boolean, String],
default: false
}
},
data() {
const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
const elIdBox = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
return {
textWidth: 0,
boxWidth: 0,
wrapWidth: '',
webviewHide: false,
// #ifdef APP-NVUE
stopAnimation: false,
// #endif
elId: elId,
elIdBox: elIdBox,
show: true,
animationDuration: 'none',
animationPlayState: 'paused',
animationDelay: '0s'
}
},
mounted() {
// #ifdef APP-PLUS
var pages = getCurrentPages();
var page = pages[pages.length - 1];
var currentWebview = page.$getAppWebview();
currentWebview.addEventListener('hide',()=>{
this.webviewHide = true
})
currentWebview.addEventListener('show',()=>{
this.webviewHide = false
})
// #endif
this.$nextTick(() => {
this.initSize()
})
},
// #ifdef APP-NVUE
beforeDestroy() {
this.stopAnimation = true
},
// #endif
methods: {
initSize() {
if (this.scrollable) {
// #ifndef APP-NVUE
let query = [],
boxWidth = 0,
textWidth = 0;
let textQuery = new Promise((resolve, reject) => {
uni.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this)
// #endif
.select(`#${this.elId}`)
.boundingClientRect()
.exec(ret => {
this.textWidth = ret[0].width
resolve()
})
})
let boxQuery = new Promise((resolve, reject) => {
uni.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this)
// #endif
.select(`#${this.elIdBox}`)
.boundingClientRect()
.exec(ret => {
this.boxWidth = ret[0].width
resolve()
})
})
query.push(textQuery)
query.push(boxQuery)
Promise.all(query).then(() => {
this.animationDuration = `${this.textWidth / this.speed}s`
this.animationDelay = `-${this.boxWidth / this.speed}s`
setTimeout(() => {
this.animationPlayState = 'running'
}, 1000)
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['animationEle'], (res) => {
let winWidth = uni.getSystemInfoSync().windowWidth
this.textWidth = res.size.width
animation.transition(this.$refs['animationEle'], {
styles: {
transform: `translateX(-${winWidth}px)`
},
duration: 0,
timingFunction: 'linear',
delay: 0
}, () => {
if (!this.stopAnimation) {
animation.transition(this.$refs['animationEle'], {
styles: {
transform: `translateX(-${this.textWidth}px)`
},
timingFunction: 'linear',
duration: (this.textWidth - winWidth) / this.speed * 1000,
delay: 1000
}, () => {
if (!this.stopAnimation) {
this.loopAnimation()
}
});
}
});
})
// #endif
}
// #ifdef APP-NVUE
if (!this.scrollable && (this.single || this.moreText)) {
dom.getComponentRect(this.$refs['textBox'], (res) => {
this.wrapWidth = res.size.width
})
}
// #endif
},
loopAnimation() {
// #ifdef APP-NVUE
animation.transition(this.$refs['animationEle'], {
styles: {
transform: `translateX(0px)`
},
duration: 0
}, () => {
if (!this.stopAnimation) {
animation.transition(this.$refs['animationEle'], {
styles: {
transform: `translateX(-${this.textWidth}px)`
},
duration: this.textWidth / this.speed * 1000,
timingFunction: 'linear',
delay: 0
}, () => {
if (!this.stopAnimation) {
this.loopAnimation()
}
});
}
});
// #endif
},
clickMore() {
this.$emit('getmore')
},
close() {
this.show = false;
this.$emit('close')
},
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
.uni-noticebar {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
padding: 6px 12px;
margin-bottom: 10px;
}
.uni-noticebar-close {
margin-right: 5px;
}
.uni-noticebar-icon {
margin-right: 5px;
}
.uni-noticebar__content-wrapper {
flex: 1;
flex-direction: column;
overflow: hidden;
}
.uni-noticebar__content-wrapper--single {
/* #ifndef APP-NVUE */
line-height: 18px;
/* #endif */
}
.uni-noticebar__content-wrapper--single,
.uni-noticebar__content-wrapper--scrollable {
flex-direction: row;
}
/* #ifndef APP-NVUE */
.uni-noticebar__content-wrapper--scrollable {
position: relative;
height: 18px;
}
/* #endif */
.uni-noticebar__content--scrollable {
/* #ifdef APP-NVUE */
flex: 0;
/* #endif */
/* #ifndef APP-NVUE */
flex: 1;
display: block;
overflow: hidden;
/* #endif */
}
.uni-noticebar__content--single {
/* #ifndef APP-NVUE */
display: flex;
flex: none;
width: 100%;
justify-content: center;
/* #endif */
}
.uni-noticebar__content-text {
font-size: 14px;
line-height: 18px;
/* #ifndef APP-NVUE */
word-break: break-all;
/* #endif */
}
.uni-noticebar__content-text--single {
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
/* #ifndef APP-NVUE */
display: block;
width: 100%;
white-space: nowrap;
/* #endif */
overflow: hidden;
text-overflow: ellipsis;
}
.uni-noticebar__content-text--scrollable {
/* #ifdef APP-NVUE */
lines: 1;
padding-left: 750rpx;
/* #endif */
/* #ifndef APP-NVUE */
position: absolute;
display: block;
height: 18px;
line-height: 18px;
white-space: nowrap;
padding-left: 100%;
animation: notice 10s 0s linear infinite both;
animation-play-state: paused;
/* #endif */
}
.uni-noticebar__more {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
padding-left: 5px;
}
.uni-noticebar__more-text {
font-size: 14px;
}
@keyframes notice {
100% {
transform: translate3d(-100%, 0, 0);
}
}
</style>

22
components/uni-popup/message.js

@ -0,0 +1,22 @@
export default {
created() {
if (this.type === 'message') {
// 不显示遮罩
this.maskShow = false
// 获取子组件对象
this.childrenMsg = null
}
},
methods: {
customOpen() {
if (this.childrenMsg) {
this.childrenMsg.open()
}
},
customClose() {
if (this.childrenMsg) {
this.childrenMsg.close()
}
}
}
}

25
components/uni-popup/popup.js

@ -0,0 +1,25 @@
import message from './message.js';
// 定义 type 类型:弹出类型:top/bottom/center
const config = {
// 顶部弹出
top:'top',
// 底部弹出
bottom:'bottom',
// 居中弹出
center:'center',
// 消息提示
message:'top',
// 对话框
dialog:'center',
// 分享
share:'bottom',
}
export default {
data(){
return {
config:config
}
},
mixins: [message],
}

243
components/uni-popup/uni-popup-dialog.vue

@ -0,0 +1,243 @@
<template>
<view class="uni-popup-dialog">
<view class="uni-dialog-title">
<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
</view>
<view class="uni-dialog-content">
<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="close">
<text class="uni-dialog-button-text">取消</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">确定</text>
</view>
</view>
</view>
</template>
<script>
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} mode = [base|input] 模式
* @value base 基础对话框
* @value input 可输入对话框
* @property {String} content 对话框内容
* @property {Boolean} beforeClose 是否拦截取消事件
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
*/
export default {
name: "uniPopupDialog",
props: {
value: {
type: [String, Number],
default: ''
},
placeholder: {
type: [String, Number],
default: '请输入内容'
},
/**
* 对话框主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: 'error'
},
/**
* 对话框模式 base/input
*/
mode: {
type: String,
default: 'base'
},
/**
* 对话框标题
*/
title: {
type: String,
default: '提示'
},
/**
* 对话框内容
*/
content: {
type: String,
default: ''
},
/**
* 拦截取消事件 如果拦截取消事件必须监听close事件执行 done()
*/
beforeClose: {
type: Boolean,
default: false
}
},
data() {
return {
dialogType: 'error',
focus: false,
val: ""
}
},
inject: ['popup'],
watch: {
type(val) {
this.dialogType = val
},
mode(val) {
if (val === 'input') {
this.dialogType = 'info'
}
},
value(val) {
this.val = val
}
},
created() {
//
this.popup.mkclick = false
if (this.mode === 'input') {
this.dialogType = 'info'
this.val = this.value
} else {
this.dialogType = this.type
}
},
mounted() {
this.focus = true
},
methods: {
/**
* 点击确认按钮
*/
onOk() {
this.$emit('confirm', () => {
this.popup.close()
if (this.mode === 'input') this.val = this.value
}, this.mode === 'input' ? this.val : '')
},
/**
* 点击取消按钮
*/
close() {
if (this.beforeClose) {
this.$emit('close', () => {
this.popup.close()
})
return
}
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-dialog {
width: 300px;
border-radius: 15px;
background-color: #fff;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 15px;
padding-bottom: 5px;
}
.uni-dialog-title-text {
font-size: 16px;
font-weight: 500;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px 15px 15px 15px;
}
.uni-dialog-content-text {
font-size: 14px;
color: #6e6e6e;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
border-top-color: #f5f5f5;
border-top-style: solid;
border-top-width: 1px;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 45px;
}
.uni-border-left {
border-left-color: #f0f0f0;
border-left-style: solid;
border-left-width: 1px;
}
.uni-dialog-button-text {
font-size: 14px;
}
.uni-button-color {
color: $uni-color-primary;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
}
.uni-popup__success {
color: $uni-color-success;
}
.uni-popup__warn {
color: $uni-color-warning;
}
.uni-popup__error {
color: $uni-color-error;
}
.uni-popup__info {
color: #909399;
}
</style>

116
components/uni-popup/uni-popup-message.vue

@ -0,0 +1,116 @@
<template>
<view class="uni-popup-message" :class="'uni-popup__'+[type]">
<text class="uni-popup-message-text" :class="'uni-popup__'+[type]+'-text'">{{message}}</text>
</view>
</template>
<script>
/**
* PopUp 弹出层-消息提示
* @description 弹出层-消息提示
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} message 消息提示文字
* @property {String} duration 显示时间设置为 0 则不会自动关闭
*/
export default {
name: 'UniPopupMessage',
props: {
/**
* 主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: 'success'
},
/**
* 消息文字
*/
message: {
type: String,
default: ''
},
/**
* 显示时间设置为 0 则不会自动关闭
*/
duration: {
type: Number,
default: 3000
}
},
inject: ['popup'],
data() {
return {}
},
created() {
this.popup.childrenMsg = this
},
methods: {
open() {
if (this.duration === 0) return
clearTimeout(this.popuptimer)
this.popuptimer = setTimeout(() => {
this.popup.close()
}, this.duration)
},
close() {
clearTimeout(this.popuptimer)
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-message {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
background-color: #e1f3d8;
padding: 10px 15px;
border-color: #eee;
border-style: solid;
border-width: 1px;
}
.uni-popup-message-text {
font-size: 14px;
padding: 0;
}
.uni-popup__success {
background-color: #e1f3d8;
}
.uni-popup__success-text {
color: #67C23A;
}
.uni-popup__warn {
background-color: #faecd8;
}
.uni-popup__warn-text {
color: #E6A23C;
}
.uni-popup__error {
background-color: #fde2e2;
}
.uni-popup__error-text {
color: #F56C6C;
}
.uni-popup__info {
background-color: #F2F6FC;
}
.uni-popup__info-text {
color: #909399;
}
</style>

165
components/uni-popup/uni-popup-share.vue

@ -0,0 +1,165 @@
<template>
<view class="uni-popup-share">
<view class="uni-share-title"><text class="uni-share-title-text">{{title}}</text></view>
<view class="uni-share-content">
<view class="uni-share-content-box">
<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
<text class="uni-share-text">{{item.text}}</text>
</view>
</view>
</view>
<view class="uni-share-button-box">
<button class="uni-share-button" @click="close">取消</button>
</view>
</view>
</template>
<script>
export default {
name: 'UniPopupShare',
props: {
title: {
type: String,
default: '分享到'
}
},
inject: ['popup'],
data() {
return {
bottomData: [{
text: '微信',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-2.png',
name: 'wx'
},
{
text: '支付宝',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-8.png',
name: 'wx'
},
{
text: 'QQ',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/gird-3.png',
name: 'qq'
},
{
text: '新浪',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-1.png',
name: 'sina'
},
{
text: '百度',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-7.png',
name: 'copy'
},
{
text: '其他',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-5.png',
name: 'more'
}
]
}
},
created() {},
methods: {
/**
* 选择内容
*/
select(item, index) {
this.$emit('select', {
item,
index
}, () => {
this.popup.close()
})
},
/**
* 关闭窗口
*/
close() {
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-share {
background-color: #fff;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 40px;
}
.uni-share-title-text {
font-size: 14px;
color: #666;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 10px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
width: 360px;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3B4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 10px 15px;
}
.uni-share-button {
flex: 1;
border-radius: 50px;
color: #666;
font-size: 16px;
}
.uni-share-button::after {
border-radius: 50px;
}
</style>

294
components/uni-popup/uni-popup.vue

@ -0,0 +1,294 @@
<template>
<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans"
@click="onTap" />
<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
<view class="uni-popup__wrapper-box" @click.stop="clear">
<slot />
</view>
</uni-transition>
</view>
</template>
<script>
import uniTransition from '../uni-transition/uni-transition.vue'
import popup from './popup.js'
/**
* PopUp 弹出层
* @description 弹出层组件为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @value message 消息提示
* @value dialog 对话框
* @value share 底部分享示例
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
* @event {Function} change 打开关闭弹窗触发e={show: false}
*/
export default {
name: 'UniPopup',
components: {
uniTransition
},
props: {
//
animation: {
type: Boolean,
default: true
},
// top: bottomcenter
// message: ; dialog :
type: {
type: String,
default: 'center'
},
// maskClick
maskClick: {
type: Boolean,
default: true
}
},
provide() {
return {
popup: this
}
},
mixins: [popup],
watch: {
/**
* 监听type类型
*/
type: {
handler: function(newVal) {
this[this.config[newVal]]()
},
immediate: true
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick(val) {
this.mkclick = val
}
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
maskClass: {
'position': 'fixed',
'bottom': 0,
'top': 0,
'left': 0,
'right': 0,
'backgroundColor': 'rgba(0, 0, 0, 0.4)'
},
transClass: {
'position': 'fixed',
'left': 0,
'right': 0,
},
maskShow: true,
mkclick: true,
popupstyle: 'top'
}
},
created() {
this.mkclick = this.maskClick
if (this.animation) {
this.duration = 300
} else {
this.duration = 0
}
},
methods: {
clear(e) {
// TODO nvue
e.stopPropagation()
},
open() {
this.showPopup = true
this.$nextTick(() => {
new Promise(resolve => {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.showTrans = true
// fixed by mehaotian app
this.$nextTick(() => {
resolve();
})
}, 50);
}).then(res => {
//
clearTimeout(this.msgtimer)
this.msgtimer = setTimeout(() => {
this.customOpen && this.customOpen()
}, 100)
this.$emit('change', {
show: true,
type: this.type
})
})
})
},
close(type) {
this.showTrans = false
this.$nextTick(() => {
this.$emit('change', {
show: false,
type: this.type
})
clearTimeout(this.timer)
//
this.customOpen && this.customClose()
this.timer = setTimeout(() => {
this.showPopup = false
}, 300)
})
},
onTap() {
if (!this.mkclick) return
this.close()
},
/**
* 顶部弹出样式处理
*/
top() {
this.popupstyle = 'top'
this.ani = ['slide-top']
this.transClass = {
'position': 'fixed',
'left': 0,
'right': 0,
}
},
/**
* 底部弹出样式处理
*/
bottom() {
this.popupstyle = 'bottom'
this.ani = ['slide-bottom']
this.transClass = {
'position': 'fixed',
'left': 0,
'right': 0,
'bottom': 0
}
},
/**
* 中间弹出样式处理
*/
center() {
this.popupstyle = 'center'
this.ani = ['zoom-out', 'fade']
this.transClass = {
'position': 'fixed',
/* #ifndef APP-NVUE */
'display': 'flex',
'flexDirection': 'column',
/* #endif */
'bottom': 0,
'left': 0,
'right': 0,
'top': 0,
'justifyContent': 'center',
'alignItems': 'center'
}
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-popup__mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
opacity: 0;
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.uni-top-mask {
opacity: 1;
}
.uni-bottom-mask {
opacity: 1;
}
.uni-center-mask {
opacity: 1;
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
}
.top {
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
}
.bottom {
bottom: 0;
}
.uni-popup__wrapper-box {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
/* #endif */
}
.content-ani {
// transition: transform 0.3s;
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.uni-top-content {
transform: translateY(0);
}
.uni-bottom-content {
transform: translateY(0);
}
.uni-center-content {
transform: scale(1);
opacity: 1;
}
</style>

279
components/uni-transition/uni-transition.vue

@ -0,0 +1,279 @@
<template>
<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
@click="change">
<slot></slot>
</view>
</template>
<script>
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation');
// #endif
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式 css 样式注意带-连接符的属性需要使用小驼峰写法如`backgroundColor:red`
*/
export default {
name: 'uniTransition',
props: {
show: {
type: Boolean,
default: false
},
modeClass: {
type: Array,
default () {
return []
}
},
duration: {
type: Number,
default: 300
},
styles: {
type: Object,
default () {
return {}
}
}
},
data() {
return {
isShow: false,
transform: '',
ani: { in: '',
active: ''
}
};
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.open()
} else {
this.close()
}
},
immediate: true
}
},
computed: {
stylesObject() {
let styles = {
...this.styles,
'transition-duration': this.duration / 1000 + 's'
}
let transfrom = ''
for (let i in styles) {
let line = this.toLine(i)
transfrom += line + ':' + styles[i] + ';'
}
return transfrom
}
},
created() {
// this.timer = null
// this.nextTick = (time = 50) => new Promise(resolve => {
// clearTimeout(this.timer)
// this.timer = setTimeout(resolve, time)
// return this.timer
// });
},
methods: {
change() {
this.$emit('click', {
detail: this.isShow
})
},
open() {
clearTimeout(this.timer)
this.isShow = true
this.transform = ''
this.ani.in = ''
for (let i in this.getTranfrom(false)) {
if (i === 'opacity') {
this.ani.in = 'fade-in'
} else {
this.transform += `${this.getTranfrom(false)[i]} `
}
}
this.$nextTick(() => {
setTimeout(() => {
this._animation(true)
}, 50)
})
},
close(type) {
clearTimeout(this.timer)
this._animation(false)
},
_animation(type) {
let styles = this.getTranfrom(type)
// #ifdef APP-NVUE
if(!this.$refs['ani']) return
animation.transition(this.$refs['ani'].ref, {
styles,
duration: this.duration, //ms
timingFunction: 'ease',
needLayout: false,
delay: 0 //ms
}, () => {
if (!type) {
this.isShow = false
}
this.$emit('change', {
detail: this.isShow
})
})
// #endif
// #ifndef APP-NVUE
this.transform = ''
for (let i in styles) {
if (i === 'opacity') {
this.ani.in = `fade-${type?'out':'in'}`
} else {
this.transform += `${styles[i]} `
}
}
this.timer = setTimeout(() => {
if (!type) {
this.isShow = false
}
this.$emit('change', {
detail: this.isShow
})
}, this.duration)
// #endif
},
getTranfrom(type) {
let styles = {
transform: ''
}
this.modeClass.forEach((mode) => {
switch (mode) {
case 'fade':
styles.opacity = type ? 1 : 0
break;
case 'slide-top':
styles.transform += `translateY(${type?'0':'-100%'}) `
break;
case 'slide-right':
styles.transform += `translateX(${type?'0':'100%'}) `
break;
case 'slide-bottom':
styles.transform += `translateY(${type?'0':'100%'}) `
break;
case 'slide-left':
styles.transform += `translateX(${type?'0':'-100%'}) `
break;
case 'zoom-in':
styles.transform += `scale(${type?1:0.8}) `
break;
case 'zoom-out':
styles.transform += `scale(${type?1:1.2}) `
break;
}
})
return styles
},
_modeClassArr(type) {
let mode = this.modeClass
if (typeof(mode) !== "string") {
let modestr = ''
mode.forEach((item) => {
modestr += (item + '-' + type + ',')
})
return modestr.substr(0, modestr.length - 1)
} else {
return mode + '-' + type
}
},
// getEl(el) {
// console.log(el || el.ref || null);
// return el || el.ref || null
// },
toLine(name) {
return name.replace(/([A-Z])/g, "-$1").toLowerCase();
}
}
}
</script>
<style>
.uni-transition {
transition-timing-function: ease;
transition-duration: 0.3s;
transition-property: transform, opacity;
}
.fade-in {
opacity: 0;
}
.fade-active {
opacity: 1;
}
.slide-top-in {
/* transition-property: transform, opacity; */
transform: translateY(-100%);
}
.slide-top-active {
transform: translateY(0);
/* opacity: 1; */
}
.slide-right-in {
transform: translateX(100%);
}
.slide-right-active {
transform: translateX(0);
}
.slide-bottom-in {
transform: translateY(100%);
}
.slide-bottom-active {
transform: translateY(0);
}
.slide-left-in {
transform: translateX(-100%);
}
.slide-left-active {
transform: translateX(0);
opacity: 1;
}
.zoom-in-in {
transform: scale(0.8);
}
.zoom-out-active {
transform: scale(1);
}
.zoom-out-in {
transform: scale(1.2);
}
</style>

8
config/index.js

@ -0,0 +1,8 @@
// export const VUE_APP_API_URL = 'http://natapp.xinxintuan.co/api';
export const VUE_APP_API_URL = 'https://wxapi.yixiang.co/api';
// export const VUE_APP_API_URL = 'http://192.168.31.223:8008/api';
// export const VUE_APP_API_URL = 'http://natapp.xinxintuan.co/api';
// export const VUE_APP_API_URL = 'https://tapi.xinxintuan.co/api'
// export const VUE_APP_API_URL = 'https://h5api.xinxintuan.co/api';
// export const VUE_APP_API_URL = 'https://h5api.xinxintuan.co/api';
export const VUE_APP_RESOURCES_URL = 'https://wx.yixiang.co/static'

BIN
icons/1024x1024.png

After

Width: 1024  |  Height: 1024  |  Size: 304 KiB

BIN
icons/120x120.png

After

Width: 120  |  Height: 120  |  Size: 4.1 KiB

BIN
icons/144x144.png

After

Width: 144  |  Height: 144  |  Size: 5.1 KiB

BIN
icons/152x152.png

After

Width: 152  |  Height: 152  |  Size: 5.4 KiB

BIN
icons/167x167.png

After

Width: 167  |  Height: 167  |  Size: 5.9 KiB

BIN
icons/180x180.png

After

Width: 180  |  Height: 180  |  Size: 6.6 KiB

BIN
icons/192x192.png

After

Width: 192  |  Height: 192  |  Size: 7.0 KiB

BIN
icons/20x20.png

After

Width: 20  |  Height: 20  |  Size: 470 B

BIN
icons/29x29.png

After

Width: 29  |  Height: 29  |  Size: 778 B

BIN
icons/40x40.png

After

Width: 40  |  Height: 40  |  Size: 1.1 KiB

BIN
icons/58x58.png

After

Width: 58  |  Height: 58  |  Size: 1.7 KiB

BIN
icons/60x60.png

After

Width: 60  |  Height: 60  |  Size: 1.7 KiB

BIN
icons/72x72.png

After

Width: 72  |  Height: 72  |  Size: 2.2 KiB

BIN
icons/76x76.png

After

Width: 76  |  Height: 76  |  Size: 2.3 KiB

BIN
icons/80x80.png

After

Width: 80  |  Height: 80  |  Size: 2.5 KiB

BIN
icons/87x87.png

After

Width: 87  |  Height: 87  |  Size: 2.8 KiB

BIN
icons/96x96.png

After

Width: 96  |  Height: 96  |  Size: 3.2 KiB

51
libs/chat.js

@ -0,0 +1,51 @@
import $store from "@//store";
import { VUE_APP_WS_URL } from "@/utils";
const Socket = function() {
this.ws = new WebSocket(VUE_APP_WS_URL);
this.ws.onopen = this.onOpen.bind(this);
this.ws.onerror = this.onError.bind(this);
this.ws.onmessage = this.onMessage.bind(this);
this.ws.onclose = this.onClose.bind(this);
};
Socket.prototype = {
vm(vm) {
this.vm = vm;
},
close() {
clearInterval(this.timer);
this.ws.close();
},
onOpen: function() {
this.init();
this.send({
type: "login",
data: $store.state.token
});
this.vm.$emit("socket_open");
},
init: function() {
var that = this;
this.timer = setInterval(function() {
that.send({ type: "ping" });
}, 10000);
},
send: function(data) {
return this.ws.send(JSON.stringify(data));
},
onMessage: function(res) {
const { type, data = {} } = JSON.parse(res.data);
this.vm.$emit(type, data);
},
onClose: function() {
clearInterval(this.timer);
},
onError: function(e) {
this.vm.$emit("socket_error", e);
}
};
Socket.prototype.constructor = Socket;
export default Socket;

227
libs/order.js

@ -0,0 +1,227 @@
import {
cancelOrder,
takeOrder,
delOrder,
payOrder,
getSubscribeTemplate
} from "@/api/order";
import dialog from "@/utils/dialog";
import {
weappPay
} from "@/libs/wechat";
import {
_router
} from '@/utils'
export function cancelOrderHandle(orderId) {
return new Promise((resolve, reject) => {
uni.showModal({
title: '提示',
content: '确认取消该订单?',
success(res) {
if (res.confirm) {
cancelOrder(orderId)
.then(res => {
uni.showToast({
title: '取消成功',
icon: 'success',
duration: 2000
});
resolve(res);
})
.catch(err => {
uni.showToast({
title: '取消失败',
icon: 'none',
duration: 2000
});
reject(err);
});
} else if (res.cancel) {}
}
})
});
}
export function takeOrderHandle(orderId) {
return new Promise((resolve, reject) => {
takeOrder(orderId)
.then(res => {
uni.showToast({
title: '收货成功',
icon: 'success',
duration: 2000
});
resolve(res);
})
.catch(err => {
uni.showToast({
title: '收货失败',
icon: 'none',
duration: 2000
});
reject(err);
});
});
}
export function delOrderHandle(orderId) {
return new Promise((resolve, reject) => {
dialog.confirm({
mes: "确认删除该订单?",
opts() {
delOrder(orderId)
.then(res => {
uni.showToast({
title: '删除成功',
icon: 'success',
duration: 2000
});
resolve(res);
})
.catch(err => {
uni.showToast({
title: '删除失败',
icon: 'none',
duration: 2000
});
reject(err);
});
}
});
});
}
// 使用订单号进行支付
export async function payOrderHandle(orderId, type, from) {
return new Promise((resolve, reject) => {
uni.showLoading({
title: "支付中",
mask: true
});
payOrder(orderId, type, from)
.then(async res => {
console.log(res)
await handleOrderPayResults(res.data, type)
resolve()
})
.catch(err => {
reject()
uni.hideLoading()
uni.showToast({
title: err.msg || err.response.data.msg || err.response.data.message || '订单支付失败',
icon: "none",
duration: 2000,
});
});
});
}
// 处理调用支付接口的逻辑
// @type create(创建订单)||pay(支付订单)
export function handleOrderPayResults(data, type, payType) {
return new Promise((resolve, reject) => {
uni.hideLoading()
switch (data.status) {
// 订单号已存在
case "ORDER_EXIST":
resolve()
break;
// 取消支付
case "EXTEND_ORDER":
uni.showToast({
title: data.msg,
icon: "none",
duration: 2000,
});
resolve()
goOrderDetails(data.result.orderId, type)
break;
case "PAY_DEFICIENCY":
break;
// 支付出错
case "PAY_ERROR":
uni.showToast({
title: data.msg,
icon: "none",
duration: 2000,
});
reject()
goOrderDetails(data.result.orderId, type)
break;
// 未传递支付环境
case "SUCCESS":
uni.showToast({
title: data.msg || data.payMsg,
icon: "none",
duration: 2000,
});
resolve()
goOrderDetails(data.result.orderId, type)
break;
// H5支付
case "WECHAT_H5_PAY":
goOrderDetails(data.result.orderId, type)
console.log(data)
setTimeout(() => {
resolve()
// #ifdef H5
// "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx15171343713577e9f3a418b0865ef90000&package=2547890641"
// location.href = data.result.jsConfig.mweb_url;
// #endif
}, 100);
break;
// 小程序支付
case "WECHAT_PAY":
weappPay(data.result.jsConfig).finally(() => {
resolve()
goOrderDetails(data.result.orderId, type)
}).then(res => {
// #ifdef MP-WEIXIN
subscribeMessage()
// #endif
})
break;
// APP支付
case "WECHAT_APP_PAY":
weappPay(data.result.jsConfig).finally(() => {
resolve()
goOrderDetails(data.result.orderId, type)
})
break;
}
})
}
export function subscribeMessage() {
// 调用订阅
console.log('调用订阅')
getSubscribeTemplate()
.then(res => {
uni.requestSubscribeMessage({
tmplIds: res.data,
success(res) {
console.log(res)
},
fail(error) {
console.log(error)
}
})
})
.catch(err => {});
}
export function goOrderDetails(id, type) {
// 创建订单时跳转到详情
if (type == 'create') {
console.log(_router)
_router.replace({
path: "/pages/order/OrderDetails/index",
query: {
id
},
});
}
}

396
libs/wechat.js

@ -0,0 +1,396 @@
import { subscribeMessage } from "@/libs/order";
import { getProvider } from "@/utils";
import WechatJSSDK from "wechat-jssdk/dist/client.umd";
import { getWechatConfig, wechatAuth } from "@/api/public";
import { parseQuery } from "@/utils";
import cookie from "@/utils/store/cookie";
import store from "@/store";
import dayjs from "dayjs";
// 支付模块
export const weappPay = (option) => {
return new Promise((resolve, reject) => {
if (store.state.$deviceType == 'weixinh5') {
setTimeout(() => {
location.href = option.mweb_url;
}, 100);
resolve()
return
}
if (store.state.$deviceType == 'weixin') {
pay(option).then(() => {
uni.showToast({
title: '支付成功', icon: 'success', duration: 5000,
});
resolve()
})
.finally(res => {
//if(typeof(res) == "undefined") return
})
.catch(function () {
uni.showToast({ title: '支付失败', icon: 'none', duration: 5000 });
reject()
});
return
}
// 吊起微信支付
// getProvider('payment').then(provider => {
let orderInfo = {
appid: option.appid,
noncestr: option.noncestr,
package: option.package,
partnerid: option.partnerid,
prepayid: option.prepayid,
sign: option.sign,
timestamp: option.timestamp + '',
}
// 调用只接口
uni.requestPayment({
provider: 'wxpay',
...option,
timestamp: orderInfo.timestamp,
orderInfo,
success: (success) => {
console.log(success)
uni.showToast({
title: '支付成功', icon: 'success', duration: 5000,
});
let time = setTimeout(() => {
clearTimeout(time)
resolve(success)
}, 3000)
// #ifdef MP-WEIXIN
subscribeMessage()
// #endif
},
fail: (error) => {
console.log(error)
if (error.errMsg == 'requestPayment:fail cancel') {
uni.showToast({ title: '已取消支付', icon: 'none', duration: 5000 });
} else {
uni.showToast({ title: error || error.msg, icon: 'none', duration: 5000 });
}
reject(error)
}
})
// })
})
}
const STATE_KEY = "wx_authorize_state";
const WX_AUTH = "wx_auth";
const BACK_URL = "login_back_url";
const LOGINTYPE = "loginType";
let instance;
let wechatObj;
let appId
let wechatLoading = false
export function wechat() {
console.log('初始化微信配置')
wechatLoading = false
return new Promise((resolve, reject) => {
if (instance) return resolve(instance);
getWechatConfig()
.then(res => {
console.log(res.data)
const _wx = WechatJSSDK(res.data);
console.log(_wx)
appId = res.data.appId
wechatObj = _wx;
_wx
.initialize()
.then(() => {
instance = _wx.wx;
instance.initConfig = res.data;
resolve(instance);
})
.catch(error => {
console.log(error)
uni.showToast({
title: error,
icon: "none",
duration: 2000
});
reject()
});
})
.catch(err => {
console.log(err);
reject();
});
});
}
export function clearAuthStatus() {
cookie.remove(WX_AUTH);
cookie.remove(STATE_KEY);
}
export async function oAuth() {
console.log('处理微信授权')
console.log(store)
console.log(store.state)
return new Promise((resolve, reject) => {
// if (cookie.has(WX_AUTH)) {
if (cookie.has(WX_AUTH) && store.state.token) {
reject()
return;
}
const { code } = parseQuery();
if (!code) {
toAuth();
return
} else {
auth(code)
}
resolve()
}).catch(error => {
console.log(error)
})
}
export async function auth(code) {
console.log('获取微信授权')
return new Promise((resolve, reject) => {
let loginType = cookie.get(LOGINTYPE);
let spread = cookie.get('spread');
console.log('微信授权登录前获取spread', spread)
wechatAuth(code, spread, loginType)
.then(({ data }) => {
console.log(data)
const expires_time = dayjs(data.expires_time);
const newTime = Math.round(new Date() / 1000);
store.commit("login", data.token, expires_time - newTime);
cookie.set(WX_AUTH, code, expires_time);
cookie.remove(STATE_KEY);
loginType && cookie.remove(LOGINTYPE);
console.log('微信公众号授权登录,获取用户信息')
store.dispatch('getUser').finally(() => {
resolve();
})
})
.catch(reject);
}).catch(error => {
console.log(error)
})
}
export async function toAuth() {
if (wechatLoading) {
return
}
wechatLoading = true
wechat().then(wx => {
location.href = getAuthUrl(appId);
});
}
function getAuthUrl(appId) {
// const redirect_uri = encodeURIComponent(window.location.href);
// const redirect_uri = encodeURIComponent(`${location.origin}/pages/Loading/index`);
// #ifdef H5
// #endif
cookie.set('redirect', window.location.href)
const redirect_uri = encodeURIComponent(`${location.origin}/pages/Loading/index`);
// const redirect_uri = encodeURIComponent(`${location.origin}/pages/Loading/index?path=${encodeURIComponent(window.location.href)}`);
// const redirect_uri = encodeURIComponent(`${window.location.origin}${window.location.pathname}`)
// const redirect_uri = encodeURIComponent(`${location.origin}`)
cookie.remove(BACK_URL);
const state = 'STATE'
// const state = encodeURIComponent(("" + Math.random()).split(".")[1] + "authorizestate");
cookie.set(STATE_KEY, state);
return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`;
}
function toPromise(fn, config = {}) {
return new Promise((resolve, reject) => {
fn({
...config,
success(res) {
resolve(res);
},
fail(err) {
reject(err);
},
complete(err) {
reject(err);
},
cancel(err) {
reject(err);
}
});
});
}
export function pay(config) {
console.log(instance)
return toPromise(instance.chooseWXPay, config);
}
export function openAddress() {
return new Promise((resolve, reject) => {
wechatEvevt("openAddress", {})
.then(res => {
resolve(res);
})
.catch(res => {
if (res.is_ready) {
res.wx.openAddress({
fail(res) {
reject(res);
},
success(res) {
resolve(res);
}
});
} else {
reject(res);
}
});
});
}
export function openShareAll(config) {
config || {};
config.type = config.type == undefined ? "link" : config.type;
return new Promise(resolve => {
getWechatConfig().then(res => {
wechatObj.signSignature({
nonceStr: res.data.nonceStr,
signature: res.data.signature,
timestamp: res.data.timestamp
});
instance = wechatObj.getOriginalWx();
instance.ready(() => {
instance.updateAppMessageShareData(config);
instance.updateTimelineShareData(config);
resolve();
});
});
});
}
export function openShareAppMessage(config) {
instance.updateAppMessageShareData(config);
instance.onMenuShareAppMessage && instance.onMenuShareAppMessage(config);
}
export function openShareTimeline(config) {
instance.updateTimelineShareData(config);
instance.onMenuShareTimeline && instance.onMenuShareTimeline(config);
}
export function wechatEvevt(name, config) {
return new Promise((resolve, reject) => {
let wx;
let configDefault = {
fail(res) {
if (wx) return reject({ is_ready: true, wx: wx });
getWechatConfig().then(res => {
wechatObj.signSignature({
nonceStr: res.data.nonceStr,
signature: res.data.signature,
timestamp: res.data.timestamp
});
wx = wechatObj.getOriginalWx();
reject({ is_ready: true, wx: wx });
});
},
success(res) {
resolve(res);
}
};
Object.assign(configDefault, config);
if (typeof instance !== "undefined") {
instance.ready(() => {
if (typeof name === "object") {
name.forEach(item => {
instance[item] && instance[item](configDefault);
});
} else instance[name] && instance[name](configDefault);
});
} else {
getWechatConfig().then(res => {
const _wx = WechatJSSDK(res.data);
_wx.initialize().then(() => {
instance = _wx.getOriginalWx();
instance.ready(() => {
if (typeof name === "object") {
name.forEach(item => {
instance[item] && instance[item](configDefault);
});
} else instance[name] && instance[name](configDefault);
});
});
});
}
});
}
export function ready() {
return new Promise(resolve => {
if (typeof instance !== "undefined") {
instance.ready(() => {
resolve(instance);
});
} else {
getWechatConfig().then(res => {
const _wx = WechatJSSDK(res.data);
_wx.initialize().then(() => {
instance = _wx.wx;
instance.ready(() => {
resolve(instance);
});
});
});
}
});
}
export function wxShowLocation() {
return new Promise(() => {
wechatEvevt("getLocation", { type: "wgs84" })
.then(res => {
let latitude = res.latitude; // 纬度
let longitude = res.longitude; // 经度
cookie.set(LATITUDE, latitude);
cookie.set(LONGITUDE, longitude);
})
.catch(res => {
if (res.is_ready) {
res.wx.getLocation({
success(res) {
let latitude = res.latitude; // 纬度
let longitude = res.longitude; // 经度
cookie.set(LATITUDE, latitude);
cookie.set(LONGITUDE, longitude);
},
cancel() {
cookie.remove(LATITUDE);
cookie.remove(LONGITUDE);
uni.showToast({
title: "取消获取位置",
icon: "none",
duration: 2000,
});
},
fail() {
cookie.remove(LATITUDE);
cookie.remove(LONGITUDE);
uni.showToast({
title: "授权失败",
icon: "none",
duration: 2000,
});
}
});
}
});
});
}

121
main.js

@ -0,0 +1,121 @@
import Vue from 'vue'
import App from './App'
// import router from "./router";
import store from './store'
import schema from 'async-validator'
import dialog from './utils/dialog'
import cookie from '@/utils/store/cookie'
import cuCustom from '@/components/colorui/components/cu-custom.vue'
import { parseRoute, _router, parseQuery } from '@/utils'
import { VUE_APP_RESOURCES_URL, VUE_APP_API_URL } from '@/config'
Vue.component('cu-custom', cuCustom)
Vue.config.productionTip = false
Vue.config.devtools = process.env.NODE_ENV !== 'production'
Vue.prototype.$validator = function(rule) {
return new schema(rule)
}
Vue.config.productionTip = false
App.mpType = 'app'
Vue.prototype.$store = store
const app = new Vue(App)
Vue.mixin({
onLoad() {
const { $mp } = this.$root
this._route = parseRoute($mp)
// this.$VUE_APP_RESOURCES_URL = VUE_APP_RESOURCES_URL;
this._data.$VUE_APP_RESOURCES_URL = VUE_APP_RESOURCES_URL
},
onShow() {
_router.app = this
_router.currentRoute = this._route
},
})
Object.defineProperty(Vue.prototype, '$yrouter', {
get() {
return _router
},
})
Object.defineProperty(Vue.prototype, '$yroute', {
get() {
return this._route
},
})
Vue.prototype.$VUE_APP_RESOURCES_URL = VUE_APP_RESOURCES_URL
Vue.prototype.$VUE_APP_API_URL = VUE_APP_API_URL
Vue.component('cu-custom', cuCustom)
// #ifdef APP-PLUS
// App平台编译的代码
Vue.prototype.$deviceType = 'app'
store.commit('updateDevicetype', 'app')
Vue.prototype.$platform = uni.getSystemInfoSync().platform
// #endif
// #ifdef MP-WEIXIN
// 微信小程序编译的代码
Vue.prototype.$deviceType = 'routine'
store.commit('updateDevicetype', 'routine')
// #endif
// !!! ps 不建议在 template 中使用 $deviceType 去判断当前环境,很有可能出现 $deviceType 为 undefined 导致判断出错的问题,可以在 script 模块中正常使用
// 建议通过 store 去获取 $deviceType 可以保证 template 中取到的值有效
// import { mapState, mapMutations, mapActions } from 'vuex';
// computed: {
// ...mapState(['$deviceType'])
// },
// #ifdef H5
// H5编译的代码
import { wechat, clearAuthStatus, oAuth, auth, toAuth, pay, openAddress, openShareAll, openShareAppMessage, openShareTimeline, wechatEvevt, ready, wxShowLocation } from '@/libs/wechat'
import { isWeixin } from '@/utils'
const CACHE_KEY = 'clear_0.0.1'
if (!cookie.has(CACHE_KEY)) {
cookie.clearAll()
cookie.set(CACHE_KEY, 1)
}
var urlSpread = parseQuery()['spread']
if (urlSpread) {
cookie.set('spread', urlSpread)
}
// #endif
async function init() {
// #ifdef H5
// H5编译的代码
// 判断是否是微信浏览器
if (isWeixin()) {
Vue.prototype.$deviceType = 'weixin'
store.commit('updateDevicetype', 'weixin')
let wechatInit = await wechat()
console.log(wechatInit)
if (wechatInit) {
await oAuth()
app.$mount()
}
} else {
Vue.prototype.$deviceType = 'weixinh5'
store.commit('updateDevicetype', 'weixinh5')
app.$mount()
}
// #endif
// #ifndef H5
app.$mount()
// #endif
}
init()

181
manifest.json

@ -0,0 +1,181 @@
{
"name" : "yshopmall",
"appid" : "__UNI__C7A519E",
"description" : "",
"versionName" : "1.0.1",
"versionCode" : 1,
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : false,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {
"OAuth" : {},
"Payment" : {},
"Share" : {},
"Geolocation" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {
"oauth" : {
"weixin" : {
"appid" : "wx7c84ede33062d1e4",
"appsecret" : "c47ef66d3311194da44e60387d5c1abd",
"UniversalLinks" : "https://yixiang.co/app/"
}
},
"payment" : {
"weixin" : {
"appid" : "wx7c84ede33062d1e4",
"UniversalLinks" : "https://yixiang.co/app/"
}
},
"share" : {
"weixin" : {
"appid" : "wx7c84ede33062d1e4",
"UniversalLinks" : "https://yixiang.co/app/"
}
},
"ad" : {},
"geolocation" : {}
},
"splashscreen" : {
"ios" : {
"iphone" : {
"portrait-896h@3x" : "splash/1242+2688.png",
"portrait-896h@2x" : "splash/828+1792.png",
"iphonex" : "splash/1125+2436.png",
"retina55" : "splash/1142+2208.png",
"retina47" : "splash/750+1334.png",
"retina40" : "splash/640+1136.png",
"retina35" : "splash/640+960.png"
}
},
"android" : {
"hdpi" : "splash/480+762.png",
"xhdpi" : "splash/720+1242.png",
"xxhdpi" : "splash/1080+1882.png"
},
"iosStyle" : "common"
},
"icons" : {
"android" : {
"hdpi" : "icons/72x72.png",
"xhdpi" : "icons/96x96.png",
"xxhdpi" : "icons/144x144.png",
"xxxhdpi" : "icons/192x192.png"
},
"ios" : {
"appstore" : "icons/1024x1024.png",
"ipad" : {
"app" : "icons/76x76.png",
"app@2x" : "icons/152x152.png",
"notification" : "icons/20x20.png",
"notification@2x" : "icons/40x40.png",
"proapp@2x" : "icons/167x167.png",
"settings" : "icons/29x29.png",
"settings@2x" : "icons/58x58.png",
"spotlight" : "icons/40x40.png",
"spotlight@2x" : "icons/80x80.png"
},
"iphone" : {
"app@2x" : "icons/120x120.png",
"app@3x" : "icons/180x180.png",
"notification@2x" : "icons/40x40.png",
"notification@3x" : "icons/60x60.png",
"settings@2x" : "icons/58x58.png",
"settings@3x" : "icons/87x87.png",
"spotlight@2x" : "icons/80x80.png",
"spotlight@3x" : "icons/120x120.png"
}
}
}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "wx604d2ea4702620d2",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于小程序位置接口的效果展示"
}
},
"plugins" : {
// #ifdef MP-WEIXIN
"live-player-plugin" : {
"version" : "1.2.8",
"provider" : "wx2b03c6e691cd7370"
}
}
},
// #endif
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"h5" : {
"title" : "yshop",
"devServer" : {
"disableHostCheck" : true
},
"router" : {
"mode" : "history"
},
"sdkConfigs" : {
"maps" : {
"qqmap" : {
"key" : ""
}
}
},
"domain" : "h5.yixiang.co"
}
}

27
mixins/SendVerifyCode.js

@ -0,0 +1,27 @@
export default {
data() {
return {
disabled: false,
text: "获取验证码"
};
},
methods: {
sendCode() {
if (this.disabled) return;
this.disabled = true;
let n = 60;
this.text = "剩余 " + n + "s";
const run = setInterval(() => {
n = n - 1;
if (n < 0) {
clearInterval(run);
}
this.text = "剩余 " + n + "s";
if (this.text < "剩余 " + 0 + "s") {
this.disabled = false;
this.text = "重新获取";
}
}, 1000);
}
}
};

1327
package-lock.json
File diff suppressed because it is too large
View File

25
package.json

@ -0,0 +1,25 @@
{
"name": "yshopmall_uni",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"animate.css": "^3.7.2",
"async-validator": "^3.2.4",
"dayjs": "^1.8.22",
"jweixin-module": "^1.6.0",
"miniapp-color-thief": "^1.0.5",
"vconsole": "^3.3.4",
"wechat-jssdk": "^5.0.4"
},
"devDependencies": {
"@types/html5plus": "^1.0.1",
"@types/uni-app": "^1.4.3"
}
}

475
pages.json

@ -0,0 +1,475 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/Loading/index",
"style": {
"navigationBarTitleText": "yshop商城"
}
},
{
"path": "pages/authorization/index",
"style": {
"navigationBarTitleText": "微信授权"
}
},
{
"path": "pages/user/Login/index",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/user/Register/index",
"style": {
"navigationBarTitleText": "注册"
}
},
{
"path": "pages/user/RetrievePassword/index",
"style": {
"navigationBarTitleText": "重置密码"
}
},
{
"path": "pages/launch/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/home/index",
"style": {
"navigationBarTitleText": "yshop商城",
"navigationBarTextStyle": "white",
"navigationStyle": "custom"
}
},
{
"path": "pages/shop/GoodSearch/index",
"style": {
"navigationBarTitleText": "搜索商品"
}
},
{
"path": "pages/shop/GoodsClass/index",
"style": {
"navigationBarTitleText": "商品分类"
}
},
{
"path": "pages/shop/ShoppingCart/index",
"style": {
"navigationBarTitleText": "购物车"
}
},
{
"path": "pages/shop/StoreList/index",
"style": {
"navigationBarTitleText": "商家列表"
}
},
{
"path": "pages/shop/GoodsList/index",
"style": {
"navigationBarTitleText": "商品列表"
}
},
{
"path": "pages/NotDefined/index",
"style": {
"navigationBarTitleText": "404"
}
},
{
"path": "pages/user/User/index",
"style": {
"navigationBarTitleText": "我的"
}
},
{
"path": "pages/shop/GoodsCollection/index",
"style": {
"navigationBarTitleText": "商品收藏"
}
},
{
"path": "pages/shop/GoodsFoot/index",
"style": {
"navigationBarTitleText": "我的足迹"
}
},
{
"path": "pages/shop/news/NewsDetail/index",
"style": {
"navigationBarTitleText": "新闻详情"
}
},
{
"path": "pages/shop/news/NewsList/index",
"style": {
"navigationBarTitleText": "新闻列表"
}
},
{
"path": "pages/shop/EvaluateList/index",
"style": {
"navigationBarTitleText": "评价列表"
}
},
{
"path": "pages/shop/GoodsEvaluate/index",
"style": {
"navigationBarTitleText": "商品评价"
}
},
{
"path": "pages/shop/GoodsPromotion/index",
"style": {
"navigationBarTitleText": "促销商品"
}
},
{
"path": "pages/shop/HotNewGoods/index",
"style": {
"navigationBarTitleText": "热门商品"
}
},
{
"path": "pages/shop/GoodsCon/index",
"style": {
"navigationBarTitleText": "商品详情"
}
},
{
"path": "pages/shop/IntegralGoodsCon/index",
"style": {
"navigationBarTitleText": "积分商品详情"
}
},
{
"path": "pages/user/BindingPhone/index",
"style": {
"navigationBarTitleText": "绑定手机号"
}
},
{
"path": "pages/user/address/AddAddress/index",
"style": {
"navigationBarTitleText": "新增收货地址"
}
},
{
"path": "pages/user/UserAccount/index",
"style": {
"navigationBarTitleText": "账户余额"
}
},
{
"path": "pages/user/address/AddressManagement/index",
"style": {
"navigationBarTitleText": "收货地址"
}
},
{
"path": "pages/user/promotion/Poster/index",
"style": {
"navigationBarTitleText": "推广名片"
}
},
{
"path": "pages/user/signIn/Sign/index",
"style": {
"navigationBarTitleText": "签到"
}
},
{
"path": "pages/user/signIn/SignRecord/index",
"style": {
"navigationBarTitleText": "签到记录"
}
},
{
"path": "pages/user/promotion/CashAudit/index",
"style": {
"navigationBarTitleText": "提现结果"
}
},
{
"path": "pages/user/promotion/PromoterOrder/index",
"style": {
"navigationBarTitleText": "分销详情"
}
},
{
"path": "pages/user/promotion/PromoterList/index",
"style": {
"navigationBarTitleText": "分销列表"
}
},
{
"path": "pages/user/promotion/UserPromotion/index",
"style": {
"navigationBarTitleText": "佣金"
}
},
{
"path": "pages/user/UserBill/index",
"style": {
"navigationBarTitleText": "账单记录"
}
},
{
"path": "pages/user/promotion/CashRecord/index",
"style": {
"navigationBarTitleText": "提现记录"
}
},
{
"path": "pages/user/promotion/CommissionDetails/index",
"style": {
"navigationBarTitleText": "佣金明细"
}
},
{
"path": "pages/user/signIn/Integral/index",
"style": {
"navigationBarTitleText": "我的积分"
}
},
{
"path": "pages/user/UserVip/index",
"style": {
"navigationBarTitleText": "用户vip"
}
},
{
"path": "pages/user/PersonalData/index",
"style": {
"navigationBarTitleText": "个人资料"
}
},
{
"path": "pages/user/coupon/UserCoupon/index",
"style": {
"navigationBarTitleText": "优惠券"
}
},
{
"path": "pages/user/coupon/GetCoupon/index",
"style": {
"navigationBarTitleText": "领取优惠券"
}
},
{
"path": "pages/user/promotion/UserCash/index",
"style": {
"navigationBarTitleText": "提现"
}
},
{
"path": "pages/user/CustomerList/index",
"style": {
"navigationBarTitleText": "客服列表"
}
},
{
"path": "pages/user/Recharge/index",
"style": {
"navigationBarTitleText": "充值"
}
},
{
"path": "pages/order/MyOrder/index",
"style": {
"navigationBarTitleText": "我的订单"
}
},
{
"path": "pages/order/Logistics/index",
"style": {
"navigationBarTitleText": "查看物流"
}
},
{
"path": "pages/order/OrderDetails/index",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "pages/order/OrderSubmission/index",
"style": {
"navigationBarTitleText": "提交订单"
}
},
{
"path": "pages/order/PaymentStatus/index",
"style": {
"navigationBarTitleText": "支付状态"
}
},
{
"path": "pages/order/GoodsReturn/index",
"style": {
"navigationBarTitleText": "商品退货"
}
},
{
"path": "pages/order/ReturnList/index",
"style": {
"navigationBarTitleText": "退货列表"
}
},
{
"path": "pages/orderAdmin/OrderIndex/index",
"style": {
"navigationBarTitleText": "商家订单统计"
}
},
{
"path": "pages/orderAdmin/AdminOrderList/index",
"style": {
"navigationBarTitleText": "订单"
}
},
{
"path": "pages/orderAdmin/GoodsDeliver/index",
"style": {
"navigationBarTitleText": "发货"
}
},
{
"path": "pages/orderAdmin/AdminOrder/index",
"style": {
"navigationBarTitleText": "商家订单列表"
}
},
{
"path": "pages/orderAdmin/Statistics/index",
"style": {
"navigationBarTitleText": "商家统计数据"
}
},
{
"path": "pages/orderAdmin/OrderCancellation/index",
"style": {
"navigationBarTitleText": "商家核销订单"
}
},
{
"path": "pages/activity/Poster/index",
"style": {
"navigationBarTitleText": "推广海报"
}
},
{
"path": "pages/activity/DargainDetails/index",
"style": {
"navigationBarTitleText": "帮砍价"
}
},
{
"path": "pages/activity/GoodsBargain/index",
"style": {
"navigationBarTitleText": "砍价列表"
}
},
{
"path": "pages/activity/BargainRecord/index",
"style": {
"navigationBarTitleText": "砍价记录"
}
},
{
"path": "pages/activity/GoodsGroup/index",
"style": {
"navigationBarTitleText": "团购商品列表"
}
},
{
"path": "pages/activity/GroupDetails/index",
"style": {
"navigationBarTitleText": "团购商品详情"
}
},
{
"path": "pages/activity/GroupRule/index",
"style": {
"navigationBarTitleText": "团购规则"
}
},
{
"path": "pages/activity/GoodsSeckill/index",
"style": {
"navigationBarTitleText": "秒杀"
}
},
{
"path": "pages/activity/SeckillDetails/index",
"style": {
"navigationBarTitleText": "秒杀详情"
}
},
{
"path": "pages/map/index",
"style": {
"navigationBarTitleText": "地图"
}
},
{
"path": "pages/shop/Live/LiveList/index",
"style": {
"navigationBarTitleText": "直播列表"
}
}
],
"easycom": {
"autoscan": true,
"custom": {
"tui-(.*)": "@/components/tui-$1/tui-$1.vue"
}
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "Yshop",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"navigationStyle": "default"
},
"tabBar": {
"color": "#282828",
"selectedColor": "#eb3729",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"height": "50px",
"fontSize": "10px",
"iconWidth": "24px",
"spacing": "3px",
"list": [
{
"pagePath": "pages/home/index",
"iconPath": "static/icon-home.png",
"selectedIconPath": "static/icon-home-hot.png",
"text": "首页"
},
{
"pagePath": "pages/shop/GoodsClass/index",
"iconPath": "static/icon-class.png",
"selectedIconPath": "static/icon-class-hot.png",
"text": "分类"
},
{
"pagePath": "pages/shop/ShoppingCart/index",
"iconPath": "static/icon-cart.png",
"selectedIconPath": "static/icon-cart-hot.png",
"text": "购物车"
},
{
"pagePath": "pages/user/User/index",
"iconPath": "static/icon-user.png",
"selectedIconPath": "static/icon-user-hot.png",
"text": "我的"
}
]
}
}

116
pages/Loading/index.vue

@ -0,0 +1,116 @@
<template>
<view class="lottie-bg">
<view id="lottie">
<image src="../../static/images/live-logo.gif" rel="preload" mode="widthFix" style="width: 100%;" />
</view>
</view>
</template>
<script>
import {
mapState,
mapMutations,
mapActions
} from "vuex";
//
// import request from "@//api/request";
import {
wxappAuth,
} from "@/api/user";
import dayjs from "dayjs";
import store from "@/store";
import cookie from "@/utils/store/cookie";
import {
parseQuery,
login,
handleQrCode,
getCurrentPageUrl,
handleUrlParam,
getCurrentPageUrlWithArgs
} from "@/utils";
export default {
name: "Loading",
data() {
return {};
},
onShow() {
console.log('getUser')
var url = handleQrCode();
if (!url) {
url = handleUrlParam(getCurrentPageUrlWithArgs())
}
console.log(url)
console.log('判断是否是分销')
//
if (url) {
let urlSpread = parseInt(url.spread);
if (urlSpread) {
cookie.set("spread", urlSpread);
}
}
if (this.$deviceType == "app" || this.$deviceType == "weixinh5") {
this.$yrouter.switchTab({
path: "/pages/home/index"
});
return;
}
if (this.$store.getters.token) {
// token
console.log('登录状态存在,直接进页面')
this.toLaunch();
return;
}
console.log('进行登录操作')
login().finally(() => {
this.$yrouter.switchTab({
path: "/pages/home/index"
});
});
},
methods: {
...mapActions(["changeAuthorization", "setUserInfo", "getUser"]),
toLaunch() {
console.log("loading home");
this.changeAuthorization(false);
let redirect = cookie.get('redirect').replace(/\ /g, '')
if (redirect && redirect.indexOf('/pages') != -1) {
this.$yrouter.replace({
path: '/pages' + redirect.split('/pages')[1],
});
cookie.remove('redirect');
} else {
this.$yrouter.switchTab({
path: "/pages/home/index"
});
}
}
}
};
</script>
<style scoped lang="less">
.lottie-bg {
position: fixed;
left: 0;
top: 0;
background-color: #fff;
width: 100%;
height: 100%;
z-index: 999;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
}
#lottie {
width: 35%;
display: block;
overflow: hidden;
transform: translate3d(0, 0, 0);
margin: auto;
}
</style>

55
pages/NotDefined/index.vue

@ -0,0 +1,55 @@
<template>
<view class="not-defined">
<image src="@/static/images/404.png" />
<view class="content">
<h3 class="title">页面未找到</h3>
<text>抱歉您访问的页面不存在请返回上一级或点击下方按钮返回首页...</text>
</view>
<view class="btn" @click="homeGo()">
返回首页
</view>
</view>
</template>
<script>
export default {
name: "NotDefined",
methods: {
homeGo() {
this.$yrouter.switchTab('/pages/home/index');
},
},
};
</script>
<style scoped lang="less">
.not-defined image{
width: 100%;
margin-top: 18%;
}
.content {
padding: 0 1*100rpx;
text-align: center;
color: #44405e;
font-size: 15px;
}
.title {
margin-bottom: 0.6*100rpx;
color: #302c48;
font-size: 20px;
}
.btn {
color: #fff;
background-color: #ef4c4c;
font-size: 16px;
padding: 0.16*100rpx;
border-radius: 25px;
text-align: center;
width: 2.4*100rpx;
margin: 0 auto;
margin-top: 1*100rpx;
}
</style>

131
pages/activity/BargainRecord/index.vue

@ -0,0 +1,131 @@
<template>
<view class="bargain-record" ref="container">
<view class="item" v-for="(item, bargainrecordIndex) in bargain" :key="bargainrecordIndex">
<view class="picTxt acea-row row-between-wrapper">
<view class="pictrue">
<image :src="item.image" />
</view>
<view class="text acea-row row-column-around">
<view class="line1">{{ item.title }}</view>
<count-down
:isDay="true"
:tipText="'倒计时 '"
:dayText="' 天 '"
:hourText="' 时 '"
:minuteText="' 分 '"
:secondText="' 秒'"
:datatime="item.datatime/1000"
></count-down>
<view class="money font-color-red">
已砍至
<text class="symbol"></text>
<text class="num">{{ item.residuePrice }}</text>
</view>
</view>
</view>
<view class="bottom acea-row row-between-wrapper">
<view class="purple" v-if="item.status === 1">活动进行中</view>
<view class="success" v-else-if="item.status === 3">砍价成功</view>
<view class="end" v-else>活动已结束</view>
<view class="acea-row row-middle row-right">
<view
class="bnt cancel"
v-if="item.status === 1"
@click="getBargainUserCancel(item.bargainId)"
>取消活动</view>
<view
class="bnt bg-color-red"
v-if="item.status === 1"
@click="goDetail(item.bargainId)"
>继续砍价</view>
<view class="bnt bg-color-red" v-else @click="goList">重开一个</view>
</view>
</view>
</view>
<Loading :loaded="status" :loading="loadingList"></Loading>
</view>
</template>
<script>
import CountDown from "@/components/CountDown";
import { getBargainUserList, getBargainUserCancel } from "@/api/activity";
import Loading from "@/components/Loading";
export default {
name: "BargainRecord",
components: {
CountDown,
Loading
},
props: {},
data: function() {
return {
bargain: [],
status: false, // false true
loadingList: false, // false true
page: 1, //
limit: 20 //
};
},
mounted: function() {
this.getBargainUserList();
},
onReachBottom() {
!this.loadingList && this.getBargainUserList();
},
methods: {
goDetail: function(id) {
this.$yrouter.push({
path: "/pages/activity/DargainDetails/index",
query: { id, partake: 0 }
});
},
goList: function() {
this.$yrouter.push({
path: "/pages/activity/GoodsBargain/index"
});
},
getBargainUserList: function() {
var that = this;
if (that.loadingList) return;
if (that.status) return;
getBargainUserList({ page: that.page, limit: that.limit })
.then(res => {
that.status = res.data.length < that.limit;
that.bargain.push.apply(that.bargain, res.data);
that.page++;
that.loadingList = false;
})
.catch(res => {
uni.showToast({
title: res.msg,
icon: "none",
duration: 2000
});
});
},
getBargainUserCancel: function(bargainId) {
var that = this;
getBargainUserCancel({ bargainId: bargainId })
.then(res => {
uni.showToast({
title: res.msg,
icon: "success",
duration: 2000
});
that.status = false;
that.loadingList = false;
that.page = 1;
that.bargain = [];
that.getBargainUserList();
})
.catch(res => {
uni.showToast({
title: res.msg,
icon: "none",
duration: 2000
});
});
}
}
};
</script>

645
pages/activity/DargainDetails/index.vue

@ -0,0 +1,645 @@
<template>
<view class="bargain on">
<!-- 在header上加 on 为请求支援 -->
<!-- 当前登录的用户和url上携带的用户id不一致视为被邀请砍价 -->
<view class="wrapper bargain-box on user" v-if="bargainUserInfo && bargainUid != userInfo.uid">
<!-- <view class="people">
{{ bargainShare.lookCount }}人查看 {{ bargainShare.shareCount }}人分享 {{ bargainShare.userCount }}人参与
</view> -->
<!-- 帮助砍价帮砍成功-->
<view class="pictxt acea-row row-center-wrapper ">
<div class="bargain-header">
<view class="pictrue"><image :src="bargainUserInfo.avatar" /></view>
<view class="text">
{{ bargainUserInfo.nickname }}
<text>邀请您帮忙砍价</text>
</view>
</div>
</view>
</view>
<view class="wrapper bargain-box time on">
<div class="pictxt ">
<count-down
:isDay="true"
:tipText="'倒计时 '"
:dayText="' 天 '"
:hourText="' 时 '"
:minuteText="' 分 '"
:secondText="' 秒'"
:datatime="goodsDetail.stopTime"
></count-down>
</div>
</view>
<view class="wrapper bargain-box bargain-product">
<view class="pictxt acea-row row-between-wrapper" @click="openAlone">
<view class="pictrue">
<image :src="goodsDetail.image" />
<view class="bargain_view">
查看商品
<view class="iconfont icon-jiantou iconfonts"></view>
</view>
</view>
<view class="text acea-row row-column-around">
<view class="line2" v-text="goodsDetail.title"></view>
<view class="money font-color-red">
已砍至:
<text class="num" v-text="bargainHelpCount.remainingPrice"></text>
</view>
<view class="acea-row row-middle">
<view class="successNum" v-text="'原价' + goodsDetail.price"></view>
<view class="successNum" v-text="'已有' + bargainSumCount + '人砍价成功'"></view>
</view>
</view>
</view>
<!-- 砍价进度条 -->
<view class="cu-progress acea-row row-middle round margin-top">
<view class="acea-row row-middle bg-red" :style="{ width: bargainHelpCount.pricePercent + '%' }"></view>
</view>
<!-- 砍价进度条下的金额 -->
<view class="balance acea-row row-between-wrapper">
<view v-text="'已砍' + bargainHelpCount.alreadyPrice + '元'"></view>
<view v-if="bargainHelpCount.price === 0">砍价成功</view>
<view v-else v-text="'还剩' + bargainHelpCount.price + '元'"></view>
</view>
<!-- 砍价成功-->
<!--
surplusPrice 砍价剩余金额为0
bargainUid 砍价人为发起砍价用户
userBargainStatus 砍价状态为
-->
<view class="bargainSuccess" v-if="pay">
<span class="iconfont icon-xiaolian"></span>
恭喜您砍价成功快去支付吧~
</view>
<!-- 参与砍价按钮 同一人-->
<view v-if="participate" class="bargainBnt" @click="goParticipate">立即发起砍价</view>
<!-- 邀请好友按钮 -->
<view v-if="inviteFriends" class="bargainBnt" @click="goPoster">邀请好友帮砍价</view>
<!-- 帮砍好友砍按钮 -->
<view v-if="helpFriendsBargain" class="bargainBnt" @click="getBargainHelp">帮好友砍一刀</view>
<!-- 发起砍价按钮 非同一人-->
<view v-if="bargain" class="bargainBnt" @click="getBargainStart">我也要砍价</view>
<!-- 支付按钮 -->
<view class="bargainBnt" @click="goPay" v-if="pay">立即支付</view>
<view class="bargainBnt on" @click="goList">抢更多商品</view>
<view class="tip">
已有
<span class="font-color-red" v-text="bargainHelpCount.count"></span>
位好友成功帮您砍价
</view>
<view class="lock"></view>
</view>
<view class="bargainGang bargain-box">
<view class="title font-color-red acea-row row-center-wrapper">
<view class="pictrue"><image src="@/static/images/left.png" /></view>
<view class="titleCon">砍价帮</view>
<view class="pictrue on"><image src="@/static/images/left.png" /></view>
</view>
<view class="list">
<view class="item acea-row row-between-wrapper" v-for="(item, bargainHelpListIndex) in bargainHelpList" :key="bargainHelpListIndex">
<view class="pictxt acea-row row-between-wrapper">
<view class="pictrue"><image :src="item.avatar" /></view>
<view class="text">
<view class="name line1" v-text="item.nickname"></view>
<view class="line1" v-text="item.add_time"></view>
</view>
</view>
<view class="money font-color-red">
<text class="iconfont icon-kanjia"></text>
砍掉{{ item.price }}
</view>
</view>
</view>
<view class="load font-color-red" v-if="!helpListStatus" @click="getBargainHelpList">点击加载更多</view>
<view class="lock"></view>
</view>
<view class="goodsDetails bargain-box">
<view class="title font-color-red acea-row row-center-wrapper">
<view class="pictrue"><image src="@/static/images/left.png" /></view>
<view class="titleCon">商品详情</view>
<view class="pictrue on"><image src="@/static/images/left.png" /></view>
</view>
<view class="conter" v-html="goodsDetail.description"></view>
<view class="lock"></view>
</view>
<view class="goodsDetails bargain-box">
<view class="title font-color-red acea-row row-center-wrapper">
<view class="pictrue"><image src="@/static/images/left.png" /></view>
<view class="titleCon">活动规则</view>
<view class="pictrue on"><image src="@/static/images/left.png" /></view>
</view>
<view class="conter" v-html="goodsDetail.rule"></view>
</view>
<view class="bargainTip" :class="active === true ? 'on' : ''">
<view class="cutOff" v-if="bargainUid === userInfo.uid">
您已砍掉
<text class="font-color-red" v-text="bargainHelpPrice"></text>
听说分享次数越多砍价成功的机会越大哦
</view>
<view class="cutOff on" v-else>
<view class="help font-color-red" v-text="'成功帮砍' + bargainHelpPrice + '元'"></view>
您也可以砍价低价拿哦快去挑选心仪的商品吧~
</view>
<view class="tipBnt" @click="goPoster" v-if="bargainUid === userInfo.uid">邀请好友帮砍价</view>
<view class="tipBnt" @click="getBargainStart" v-else>我也要参与</view>
</view>
<view class="mask" @touchmove.prevent :hidden="active === false" @click="close"></view>
</view>
</template>
<script>
import CountDown from '@/components/CountDown';
import {
getBargainDetail,
getBargainShare,
getBargainStart,
getBargainHelp,
getBargainHelpPrice,
getBargainHelpList,
getBargainHelpCount,
getBargainStartUser
} from '@/api/activity';
import { postCartAdd } from '@/api/store';
import { mapGetters } from 'vuex';
import {} from '@/libs/wechat';
import { isWeixin, parseQuery, handleQrCode } from '@/utils/index';
const NAME = 'DargainDetails';
export default {
name: 'DargainDetails',
components: {
CountDown
},
props: {},
data: function() {
return {
bargainId: 0, //
bargainSumCount: 0, //
activeMsg: '',
active: false,
bargainHelpPrice: 0, //
bargainHelpList: [],
helpListStatus: false, // false true
page: 1, //
limit: 2, //
pricePercent: 0, //
bargainShare: {}, //
bargainHelpCount: {}, //
goodsDetail: {}, //
bargainUserInfo: [], //
bargainUid: 0, //
pay: false, //
bargain: false, //
participate: false, //
inviteFriends: false, //
helpFriendsBargain: false, //
bargainSuccess: false, //
mainBargainSuccess: false //
};
},
computed: mapGetters(['userInfo', 'isLogin']),
mounted: function() {
this.mountedStart();
},
methods: {
//
mountedStart: function() {
var that = this;
let url = handleQrCode();
// bargainId id
// bargainUid
if (url) {
//
that.bargainId = url.bargainId;
that.bargainUid = url.partake;
} else {
//
that.bargainId = that.$yroute.query.id;
that.bargainUid = that.$yroute.query.partake;
}
if (this.bargainUid == 0 || !this.bargainUid) {
// urluiduid
that.bargainUid = that.userInfo.uid;
}
console.log(this);
//
that.getBargainDetail();
//
that.getBargainShare(0);
if (that.bargainUid !== that.userInfo.uid) {
that.getBargainStartUser();
}
},
//
goParticipate() {
//
if (this.bargainUid === this.userInfo.uid) {
//
this.getBargainStart();
} else {
//
this.getBargainStartUser();
}
this.getBargainHelpCount();
},
//
openAlone: function() {
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: {
id: this.goodsDetail.productId
}
});
},
//
goPay: function() {
var data = {};
var that = this;
data.productId = that.goodsDetail.productId;
data.cartNum = that.goodsDetail.num;
data.uniqueId = '';
data.bargainId = that.bargainId;
data.new = 1;
postCartAdd(data)
.then(res => {
that.$yrouter.push({
path: '/pages/order/OrderSubmission/index',
query: {
id: res.data.cartId
}
});
})
.catch(err => {
uni.showToast({
title: err.msg || err.response.data.msg || err.response.data.message,
icon: 'none',
duration: 2000
});
});
},
//
goPoster: function() {
var that = this;
that.getBargainShare(that.bargainId);
this.$yrouter.push({
path: '/pages/activity/Poster/index',
query: {
id: that.bargainId,
type: 2
}
});
},
//
goList: function() {
this.$yrouter.push({
path: '/pages/activity/GoodsBargain/index'
});
},
//
//bargainId 0
//bargainId
getBargainShare: function(bargainId) {
var that = this;
getBargainShare({
bargainId: bargainId
}).then(res => {
that.bargainShare = res.data;
});
},
//
getBargainDetail: function() {
var that = this;
uni.showLoading({
title: '加载中',
mask: true
});
getBargainDetail(that.bargainId)
.then(res => {
uni.hideLoading();
that.goodsDetail = res.data.bargain;
that.goodsDetail.description = that.goodsDetail.description.replace(/\<img/gi, '<img style="max-width:100%;height:auto;"');
that.goodsDetail.rule = that.goodsDetail.rule.replace(/\<img/gi, '<img style="max-width:100%;height:auto;"');
that.goodsDetail.stopTime = that.goodsDetail.stopTime / 1000;
that.getBargainHelpCount();
})
.catch(res => {
uni.hideLoading();
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
});
},
// -
getBargainStart: function() {
var that = this;
getBargainStart({
bargainId: that.bargainId
})
.then(() => {
that.bargainUid = that.userInfo.uid;
that.getBargainHelp();
that.getBargainHelpCount();
})
.catch(res => {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
});
},
//
getBargainHelp: function() {
var that = this;
if (this.bargainHelpCount.price === 0 && that.bargainUid !== that.userInfo.uid) {
return uni.showToast({
title: '好友已经砍价成功',
icon: 'success',
duration: 2000
});
}
var data = {
bargainId: that.bargainId,
bargainUserUid: that.bargainUid
};
getBargainHelp(data)
.then(res => {
that.activeMsg = res.data.status;
if (res.data.status === 'SUCCESSFUL' && that.bargainUid !== that.userInfo.uid) {
uni.showToast({
title: '您已经砍过了',
icon: 'none',
duration: 2000
});
return;
}
that.helpListStatus = false;
that.page = 1;
that.bargainHelpList = [];
that.getBargainHelpPrice();
})
.catch(res => {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
});
},
//
getBargainHelpPrice: function() {
var that = this;
getBargainHelpPrice({
bargainId: that.bargainId,
bargainUserUid: that.bargainUid
})
.then(res => {
that.bargainHelpPrice = res.data.price;
that.getBargainHelpCount();
that.getBargainHelpList();
switch (that.activeMsg) {
case 'SUCCESSFUL':
break;
case 'SUCCESS':
that.active = true;
break;
}
})
.catch(res => {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
});
},
//
getBargainHelpList: function() {
var that = this;
if (that.helpListStatus === true) return;
getBargainHelpList({
bargainId: that.bargainId,
bargainUserUid: that.bargainUid,
page: that.page,
limit: that.limit
})
.then(res => {
that.helpListStatus = res.data.length < that.limit;
that.page++;
if (res.data) {
that.bargainHelpList.push.apply(that.bargainHelpList, res.data);
}
})
.catch(err => {
if (!err.msg) {
return;
}
uni.showToast({
title: err.msg || err.response.data.msg || err.response.data.message,
icon: 'none',
duration: 2000
});
});
},
//
getBargainHelpCount: function() {
getBargainHelpCount({
bargainId: this.bargainId,
bargainUserUid: this.bargainUid
})
.then(res => {
// ** 使 = -
let remainingPrice = (this.goodsDetail.price - res.data.alreadyPrice).toFixed(2);
this.bargainHelpCount = {
...res.data,
remainingPrice
};
this.handleButtonStatus();
})
.catch(err => {
if (!err.msg) {
return;
}
uni.showToast({
title: err.msg || err.response.data.msg || err.response.data.message,
icon: 'none',
duration: 2000
});
});
},
//
handleButtonStatus() {
//
// 1. ==> &&
if (this.bargainUid === this.userInfo.uid && this.bargainHelpCount.status == 0) {
this.participate = true;
} else {
this.participate = false;
}
// 2. ==> && && >0
if (this.bargainUid === this.userInfo.uid && this.bargainHelpCount.status == 1 && this.bargainHelpCount.price > 0) {
this.inviteFriends = true;
} else {
this.inviteFriends = false;
}
// 3. ==> && && >0 &&
if (
this.bargainUid != this.userInfo.uid &&
this.bargainHelpCount.status == 1 &&
// this.bargainHelpCount.userBargainStatus &&
this.bargainHelpCount.price > 0
) {
this.helpFriendsBargain = true;
} else {
this.helpFriendsBargain = false;
}
// 4. ==> && && <=0
if (this.bargainUid === this.userInfo.uid && this.bargainHelpCount.status == 1 && this.bargainHelpCount.price <= 0) {
this.pay = true;
} else {
this.pay = false;
}
// 5. ==> &&
if (this.bargainUid != this.userInfo.uid) {
this.bargain = true;
} else {
this.bargain = false;
}
//
// 1. ==> &&
// 2. ==> &&
// 3. ==> && true
},
//
//
getBargainStartUser: function() {
var that = this;
getBargainStartUser({
bargainId: that.bargainId,
bargainUserUid: that.bargainUid
})
.then(res => {
that.bargainUserInfo = res.data;
that.getBargainHelpList();
})
.catch(res => {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
});
},
//
close: function() {
this.active = false;
},
//
onShareAppMessage: function() {
return {
title: this.storeInfo.title,
imageUrl: this.storeInfo.image,
path: 'pages/activity/DargainDetails/index?id=' + this.storeInfo.id + '&spread=' + uni.getStorageSync('uid'),
success(res) {
uni.showToast({
title: '分享成功'
});
},
fail(res) {
uni.showToast({
title: '分享失败',
icon: 'none'
});
}
};
}
},
onShareAppMessage() {
return {
path: `/pages/activity/DargainDetails/index/?id=${this.$yroute.query.id}&partake=${this.userInfo.uid}`
};
}
};
</script>
<style lang="less">
.bargain {
&.on {
.bargain-box {
background: #fff;
width: auto;
margin: 0 20rpx;
border: 0;
}
.header {
height: auto;
text-align: left;
.time {
text-align: left;
font-size: 24rpx;
margin: 0;
padding: 0;
padding: 20rpx;
width: auto;
height: auto;
}
}
}
}
page {
background-color: #f5f5f5 !important;
}
.bargainBnt_hui {
font-size: 0.3 * 100rpx;
font-weight: bold;
color: #fff;
width: 6 * 100rpx;
height: 0.8 * 100rpx;
border-radius: 0.4 * 100rpx;
background: #bbb;
text-align: center;
line-height: 0.8 * 100rpx;
margin-top: 0.32 * 100rpx;
}
.bargain_view {
left: 0;
right: 0;
height: 0.48 * 100rpx;
background: rgba(0, 0, 0, 0.5);
opacity: 1;
border-radius: 0 0 0.06 * 100rpx 0.06 * 100rpx;
position: absolute;
bottom: 0;
font-size: 0.22 * 100rpx;
color: #fff;
text-align: center;
line-height: 0.48 * 100rpx;
}
.iconfonts {
font-size: 0.22 * 100rpx;
}
</style>

84
pages/activity/GoodsBargain/index.vue

@ -0,0 +1,84 @@
<template>
<view class="bargain-list">
<!-- <view class="header">
<image src="@/static/images/cut-bg.png" alt="">
</view>-->
<view class="list" v-if="bargainLis.length > 0">
<view
class="item acea-row row-between-wrapper"
v-for="(item, bargainLisIndex) in bargainLis"
:key="bargainLisIndex"
>
<view class="pictrue">
<image :src="item.image" />
</view>
<view class="text acea-row row-column-around">
<view class="line1" v-text="item.title"></view>
<view class="num">
<text class="iconfont icon-pintuan"></text>
{{ item.people }}人正在参与
</view>
<view class="money font-color-red">
可砍至:
<text class="price">{{item.minPrice}}</text>
</view>
</view>
<view class="cutBnt bg-color-red" @click="goDetail(item.id)">
<text class="iconfont icon-kanjia"></text>参与砍价
</view>
</view>
<view class="load font-color-red" v-if="!status" @click="getBargainList">点击加载更多</view>
</view>
<!-- <view class="noCommodity" style="background-color: #fff;" v-if="bargainLis.length === 0">
<view class="noPictrue">
<image src="@/static/images/noGood.png" class="image" />
</view>
</view> -->
</view>
</template>
<script>
import { getBargainList } from "@/api/activity";
export default {
name: "GoodsBargain",
components: {},
props: {},
data: function() {
return {
bargainLis: [], //
status: false, // false true
loading: false, // false true
page: 1, //
limit: 20 //
};
},
mounted: function() {
this.getBargainList();
},
methods: {
getBargainList: function() {
var that = this;
if (that.loading) return;
if (that.status) return;
that.loading = true;
getBargainList({ page: that.page, limit: that.limit }).then(res => {
that.status = res.data.length < that.limit;
that.bargainLis.push.apply(that.bargainLis, res.data);
that.page++;
that.loading = false;
});
},
goDetail: function(id) {
this.$yrouter.push({
path: "/pages/activity/DargainDetails/index",
query: { id, partake: 0 }
});
}
}
};
</script>
<style >
page{
background-color: rgb(245, 245, 245);
}
</style>

101
pages/activity/GoodsGroup/children/activity-card.vue

@ -0,0 +1,101 @@
<template>
<view class="activity-goods-box x-bc" @tap="jump('/pages/activity/GroupDetails/index', { id: cid })">
<view class="img-box">
<slot name="tag"></slot>
<image class="img" :src="img" mode="aspectFill"></image>
</view>
<view class="goods-right y-bc">
<view class="title one-t">{{ title }}</view>
<view class="tip one-t">{{ info }}</view>
<view class="slod-end"><slot name="sell"></slot></view>
<view class=" price-box">
<view class="x-f">
<view class="current">{{ price }}</view>
<view class="original">{{ productPrice }}</view>
</view>
</view>
<slot name="btn"></slot>
</view>
</view>
</template>
<script>
export default {
name: 'activityCard',
components: {},
data() {
return {};
},
props: {
cid: 0,
img: '',
title: '',
info: '',
price: '',
productPrice: ''
},
computed: {},
created() {},
methods: {
//
jump(path, parmas) {
this.$yrouter.push({ path: path, query: parmas });
}
}
};
</script>
<style lang="scss">
.activity-goods-box {
padding: 40rpx 20rpx;
background: #fff;
.img-box {
margin-right: 20rpx;
width: 200rpx;
height: 200rpx;
overflow: hidden;
position: relative;
.img {
width: 200rpx;
height: 200rpx;
background-color: #ccc;
}
}
.goods-right {
width: 450rpx;
min-height: 200rpx;
align-items: flex-start;
position: relative;
.title {
font-size: 28rpx;
line-height: 28rpx;
width: 450rpx;
}
.tip {
font-size: 22rpx;
color: #a8700d;
width: 500rpx;
}
.price-box {
.current {
font-size: 28rpx;
font-weight: 500;
color: rgba(225, 33, 43, 1);
}
.original {
font-size: 22rpx;
font-weight: 400;
text-decoration: line-through;
color: rgba(153, 153, 153, 1);
margin-left: 14rpx;
}
}
}
}
</style>

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

Loading…
Cancel
Save