|
@@ -1,820 +1,835 @@
|
|
|
<template>
|
|
|
- <view class="app-container">
|
|
|
- <view class="fixed-container">
|
|
|
- <view class="top-container">
|
|
|
- <scroll-view
|
|
|
- :scroll-x="true"
|
|
|
- :scroll-left="scrollLeft"
|
|
|
- scroll-with-animation
|
|
|
- :show-scrollbar="false"
|
|
|
- class="tabs-view"
|
|
|
- ref="tabs-view">
|
|
|
- <view class="tab">
|
|
|
- <block v-for="(item, index) in tabList" :key='index'>
|
|
|
- <view class="item" :ref="`tabs-item-${index}`" :class="[`tabs-item-${index}`, item.categoryId == tabCurrent ? 'current':'']" @tap="changeTab(item.categoryId)">{{item.name}}</view>
|
|
|
- </block>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
- <view class="search-container">
|
|
|
- <view class="search">
|
|
|
- <image src="/static/icon/search.png" class=""></image>
|
|
|
- <input type="text" confirm-type="search" placeholder="搜索商品名称" v-model="keyword" @confirm="searchSubmit">
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="banner-container" v-if="bannerUrl">
|
|
|
- <image :src="bannerUrl" mode="widthFix"></image>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="list-container">
|
|
|
- <block v-for="(item, index) in dataList" :key='index'>
|
|
|
- <div class="item" @tap="toGoodsDetail(item.goodsId)">
|
|
|
- <image :src="item.goodsImgSrc" mode="aspectFill"></image>
|
|
|
- <view class="right">
|
|
|
- <view class="title ellipsis-2">{{item.goodsName}}</view>
|
|
|
- <view class="des ellipsis-2">{{item.describeText ? item.describeText : ''}}</view>
|
|
|
- <view class="stock-sales">
|
|
|
- <view class="stock">
|
|
|
- <text>剩余{{item.stock}}件</text>
|
|
|
- <view class="progress-box">
|
|
|
- <!-- 库存 / 总数 * 100 = 剩余百分比 -->
|
|
|
- <progress :percent="item.stock / (item.stock+100) * 100" activeColor="#FF3F42" active stroke-width="6" />
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="sales">销量:{{item.saleNum || '0'}}</view>
|
|
|
- </view>
|
|
|
- <view class="bottom">
|
|
|
- <view class="price">
|
|
|
- <view class="price-1">¥{{item.groupPrice | numToFixed}}</view>
|
|
|
- <view class="price-2">¥{{item.orgGoodsPrice | numToFixed}}</view>
|
|
|
- </view>
|
|
|
- <view class="btn">去拼团</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </div>
|
|
|
- </block>
|
|
|
- </view>
|
|
|
- <no-data v-if="!dataList.length" :showText="'暂无数据'"></no-data>
|
|
|
- <loading-text v-if="dataList.length" :loading="loading" :noMore="noMore" ></loading-text>
|
|
|
-
|
|
|
- <view class="share-container" :style="{top: top+'px'}" v-if="dataList.length">
|
|
|
- <button @tap="clickShare">
|
|
|
- <image src="@/static/icon/share.png"></image>
|
|
|
- <text>分享</text>
|
|
|
- </button>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="global-mask" v-show="isShareDialog" @tap="isShareDialog = false"></view>
|
|
|
- <view class="sharelist-container" v-show="isShareDialog">
|
|
|
- <button class="item" open-type="share" @tap="isShareDialog = false">
|
|
|
- <image src="@/static/icon/wechat.png"></image>
|
|
|
- <text>分享给微信好友</text>
|
|
|
- </button>
|
|
|
-
|
|
|
- <view class="item" @tap="markImage">
|
|
|
- <image src="@/static/icon/image.png"></image>
|
|
|
- <text>生成图片分享</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="global-mask" v-show="isShowCanvas" @tap="closeCanvas"></view>
|
|
|
- <view class="canvas-container" v-show="isShowCanvas">
|
|
|
- <view class="content">
|
|
|
- <canvas style="width: 340px; height: 340px;" canvas-id="myCanvas" id="myCanvas"></canvas>
|
|
|
- </view>
|
|
|
- <view class="button"><text @tap="saveImage">保存图片</text></view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- <drag-button :isDock="true" :customBar="true" ref="dragButton"></drag-button> -->
|
|
|
- </view>
|
|
|
+ <view class="app-container">
|
|
|
+ <view class="fixed-container">
|
|
|
+ <view class="top-container">
|
|
|
+ <scroll-view
|
|
|
+ :scroll-x="true"
|
|
|
+ :scroll-left="scrollLeft"
|
|
|
+ scroll-with-animation
|
|
|
+ :show-scrollbar="false"
|
|
|
+ class="tabs-view"
|
|
|
+ ref="tabs-view"
|
|
|
+ >
|
|
|
+ <view class="tab">
|
|
|
+ <block v-for="(item, index) in tabList" :key="index">
|
|
|
+ <view
|
|
|
+ class="item"
|
|
|
+ :ref="`tabs-item-${index}`"
|
|
|
+ :class="[`tabs-item-${index}`, item.categoryId == tabCurrent ? 'current' : '']"
|
|
|
+ @tap="changeTab(item.categoryId)"
|
|
|
+ >{{ item.name }}</view
|
|
|
+ >
|
|
|
+ </block>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+ <view class="search-container">
|
|
|
+ <view class="search">
|
|
|
+ <image src="/static/icon/search.png" class=""></image>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ confirm-type="search"
|
|
|
+ placeholder="搜索商品名称"
|
|
|
+ v-model="keyword"
|
|
|
+ @confirm="searchSubmit"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="banner-container" v-if="bannerUrl">
|
|
|
+ <image :src="bannerUrl" mode="widthFix"></image>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="list-container">
|
|
|
+ <block v-for="(item, index) in dataList" :key="index">
|
|
|
+ <div class="item" @tap="toGoodsDetail(item.goodsId)">
|
|
|
+ <image :src="item.goodsImgSrc" mode="aspectFill"></image>
|
|
|
+ <view class="right">
|
|
|
+ <view class="title ellipsis-2">{{ item.goodsName }}</view>
|
|
|
+ <view class="des ellipsis-2">{{ item.describeText ? item.describeText : '' }}</view>
|
|
|
+ <view class="stock-sales">
|
|
|
+ <view class="stock">
|
|
|
+ <text>剩余{{ item.stock }}件</text>
|
|
|
+ <view class="progress-box">
|
|
|
+ <!-- 库存 / 总数 * 100 = 剩余百分比 -->
|
|
|
+ <progress
|
|
|
+ :percent="(item.stock / (item.stock + 100)) * 100"
|
|
|
+ activeColor="#FF3F42"
|
|
|
+ active
|
|
|
+ stroke-width="6"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="sales">销量:{{ item.saleNum || '0' }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="bottom">
|
|
|
+ <view class="price">
|
|
|
+ <view class="price-1">¥{{ item.groupPrice | numToFixed }}</view>
|
|
|
+ <view class="price-2">¥{{ item.orgGoodsPrice | numToFixed }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="btn">去拼团</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </div>
|
|
|
+ </block>
|
|
|
+ </view>
|
|
|
+ <no-data v-if="!dataList.length" :showText="'暂无数据'"></no-data>
|
|
|
+ <loading-text v-if="dataList.length" :loading="loading" :noMore="noMore"></loading-text>
|
|
|
+
|
|
|
+ <view class="share-container" :style="{ top: top + 'px' }" v-if="dataList.length">
|
|
|
+ <button @tap="clickShare">
|
|
|
+ <image src="@/static/icon/share.png"></image>
|
|
|
+ <text>分享</text>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="global-mask" v-show="isShareDialog" @tap="isShareDialog = false"></view>
|
|
|
+ <view class="sharelist-container" v-show="isShareDialog">
|
|
|
+ <button class="item" open-type="share" @tap="isShareDialog = false">
|
|
|
+ <image src="@/static/icon/wechat.png"></image>
|
|
|
+ <text>分享给微信好友</text>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <view class="item" @tap="markImage">
|
|
|
+ <image src="@/static/icon/image.png"></image>
|
|
|
+ <text>生成图片分享</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="global-mask" v-show="isShowCanvas" @tap="closeCanvas"></view>
|
|
|
+ <view class="canvas-container" v-show="isShowCanvas">
|
|
|
+ <view class="content">
|
|
|
+ <canvas style="width: 340px; height: 340px" canvas-id="myCanvas" id="myCanvas"></canvas>
|
|
|
+ </view>
|
|
|
+ <view class="button"><text @tap="saveImage">保存图片</text></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- <drag-button :isDock="true" :customBar="true" ref="dragButton"></drag-button> -->
|
|
|
+ </view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
- import {mapState} from 'vuex';
|
|
|
- // import dragButton from '@/components/drag-button.vue';
|
|
|
-
|
|
|
- export default {
|
|
|
- // components:{
|
|
|
- // dragButton
|
|
|
- // },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- configInfo: {},
|
|
|
- dataList: [], // 优惠券列表
|
|
|
- pageNum: 1,
|
|
|
- pageSize: 8,
|
|
|
- noMore: false,
|
|
|
- loading: false,
|
|
|
- isShareDialog: false, // 是否显示分享弹窗
|
|
|
- isShowCanvas: false, // 是否显示海报弹窗
|
|
|
- isFinishCanvas: false, // 是否已完成海报
|
|
|
- codeUrl: '',
|
|
|
- bgUrl: '',
|
|
|
- headUrl: '',
|
|
|
- top: 300,
|
|
|
- tabList: [], // 分类列表
|
|
|
- tabCurrent: '', // 分类当前值
|
|
|
- keyword: '',
|
|
|
-
|
|
|
- scrollLeft: 50,
|
|
|
- scrollViewWidth: 0,
|
|
|
- tabsRect: {
|
|
|
- left: 0
|
|
|
- },
|
|
|
-
|
|
|
- bannerUrl: '',
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- watch: {
|
|
|
- tabList() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.resize()
|
|
|
- })
|
|
|
- },
|
|
|
- },
|
|
|
-
|
|
|
- computed:{
|
|
|
- ...mapState(['userInfo', 'isLogin', 'userId'])
|
|
|
- },
|
|
|
-
|
|
|
- onShow() {
|
|
|
- // this.$refs.dragButton.init();
|
|
|
-
|
|
|
- this.top = this.$getStorage('top') < 200 ? this.$getStorage('top') : this.$getStorage('top') - 124;
|
|
|
- },
|
|
|
-
|
|
|
- async onLoad() {
|
|
|
- this.getTabList();
|
|
|
- this.getBanner();
|
|
|
- this.configInfo = await this.$getConfigInfo();
|
|
|
- },
|
|
|
-
|
|
|
- onShow() {
|
|
|
- this.crossPage.$on('hanbleShare', () => {
|
|
|
- this.clickShare();
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- onHide() {
|
|
|
- this.crossPage.$off('hanbleShare');
|
|
|
- },
|
|
|
-
|
|
|
- // 下拉刷新
|
|
|
- onPullDownRefresh() {
|
|
|
- this.pageNum = 1;
|
|
|
- this.getList();
|
|
|
- },
|
|
|
-
|
|
|
- // 上拉加载
|
|
|
- onReachBottom() {
|
|
|
- this.getList(1);
|
|
|
- },
|
|
|
-
|
|
|
- onShareAppMessage(options) {
|
|
|
- if (options && options.from == 'button') {
|
|
|
- // 来自页面内的转发按钮
|
|
|
- } else {
|
|
|
- // 点击微信右上角的分享按钮
|
|
|
- }
|
|
|
- return {
|
|
|
- title: `${this.userInfo.nickName}向你推荐了${this.configInfo.minAppName}的团购活动`,
|
|
|
- // imageUrl: this.detail.imgUrl,
|
|
|
- path: '/pages/index/index?serviceId=' + this.userId + '&otherType=groupbuyList',
|
|
|
- query: {
|
|
|
- // id: this.goodsId,
|
|
|
- },
|
|
|
- success: function(res) {
|
|
|
- if(res.errMsg == 'shareAppMessage:ok'){
|
|
|
- this.$successToast('分享完成');
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- methods: {
|
|
|
- getList(loadMore) {
|
|
|
- if(this.noMore && loadMore)return;
|
|
|
- this.noMore = false
|
|
|
- if(!loadMore){
|
|
|
- this.pageNum = 1;
|
|
|
- }else{
|
|
|
- this.loading = true;
|
|
|
- }
|
|
|
- this.$axios({
|
|
|
- url: '/goods/promotion/group/list',
|
|
|
- method: 'get',
|
|
|
- params: {
|
|
|
- pageNo: this.pageNum,
|
|
|
- pageSize: this.pageSize,
|
|
|
- userId: this.userId,
|
|
|
- goodsCategoryId: this.tabCurrent,
|
|
|
- keyword: this.keyword,
|
|
|
- },
|
|
|
- isLoading: !loadMore
|
|
|
- }).then(res => {
|
|
|
- let _list = res.data.records;
|
|
|
- let pageTotal = res.data.pages;
|
|
|
- if(this.pageNum >= pageTotal){
|
|
|
- this.noMore = true;
|
|
|
- }
|
|
|
- if (_list.length) {
|
|
|
- this.pageNum += 1
|
|
|
- }
|
|
|
- if (loadMore) {
|
|
|
- this.dataList = this.dataList.concat(_list);
|
|
|
- this.loading = false;
|
|
|
- } else {
|
|
|
- this.dataList = _list;
|
|
|
- }
|
|
|
-
|
|
|
- uni.stopPullDownRefresh();
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- // 获取一级菜单
|
|
|
- getTabList() {
|
|
|
- this.$axios({
|
|
|
- url: '/goods/category/list',
|
|
|
- method: 'get',
|
|
|
- params: {}
|
|
|
- }).then(res => {
|
|
|
- res.data.unshift({name: "全部", categoryId: ""})
|
|
|
- this.tabList = res.data;
|
|
|
- this.tabCurrent = res.data.length > 0 ? res.data[0].categoryId : 0;
|
|
|
- this.getList();
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- // 切换一级菜单
|
|
|
- changeTab(current) {
|
|
|
- this.pageNum = 1;
|
|
|
- this.tabCurrent = current;
|
|
|
- this.resize();
|
|
|
- this.getList();
|
|
|
- },
|
|
|
-
|
|
|
- searchSubmit() {
|
|
|
- this.pageNum = 1;
|
|
|
- this.getList();
|
|
|
- },
|
|
|
-
|
|
|
- setScrollLeft() {
|
|
|
- // 当前活动tab的布局信息,有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
|
|
|
- const index = this.findElem(this.tabList, 'categoryId', this.tabCurrent);
|
|
|
- const tabRect = this.tabList[index]
|
|
|
- // 累加得到当前item到左边的距离
|
|
|
- const offsetLeft = this.tabList
|
|
|
- .slice(0, index)
|
|
|
- .reduce((total, curr) => {
|
|
|
- return total + curr.rect.width
|
|
|
- }, 0)
|
|
|
- // 此处为屏幕宽度
|
|
|
- const res = uni.getSystemInfoSync();
|
|
|
- const windowWidth = res.windowWidth;
|
|
|
- // 将活动的tabs-item移动到屏幕正中间,实际上是对scroll-view的移动
|
|
|
- let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect.right) / 2 + this.tabsRect.left / 2
|
|
|
-
|
|
|
- // 这里做一个限制,限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度
|
|
|
- scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width)
|
|
|
- this.scrollLeft = Math.max(0, scrollLeft)
|
|
|
- },
|
|
|
- // 获取所有标签的尺寸
|
|
|
- resize() {
|
|
|
- // 如果不存在list,则不处理
|
|
|
- if(this.tabList.length === 0) {
|
|
|
- return
|
|
|
- }
|
|
|
- Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
|
|
|
- this.tabsRect = tabsRect
|
|
|
- this.scrollViewWidth = 0
|
|
|
- itemRect.map((item, index) => {
|
|
|
- // 计算scroll-view的宽度,这里
|
|
|
- this.scrollViewWidth += item.width
|
|
|
- // 另外计算每一个item的中心点X轴坐标
|
|
|
- this.tabList[index].rect = item
|
|
|
- })
|
|
|
- // 获取了tabs的尺寸之后,设置滑块的位置
|
|
|
- this.setScrollLeft()
|
|
|
- })
|
|
|
- },
|
|
|
- // 获取导航菜单的尺寸
|
|
|
- getTabsRect() {
|
|
|
- return new Promise(resolve => {
|
|
|
- this.queryRect('tabs-view').then(size => resolve(size))
|
|
|
- })
|
|
|
- },
|
|
|
- // 获取所有标签的尺寸
|
|
|
- getAllItemRect() {
|
|
|
- return new Promise(resolve => {
|
|
|
- const promiseAllArr = this.tabList.map((item, index) => this.queryRect(
|
|
|
- `tabs-item-${index}`, true))
|
|
|
- Promise.all(promiseAllArr).then(sizes => resolve(sizes))
|
|
|
- })
|
|
|
- },
|
|
|
- // 获取各个标签的尺寸
|
|
|
- queryRect(el, item) {
|
|
|
- const query = uni.createSelectorQuery().in(this);
|
|
|
- return new Promise(resolve => {
|
|
|
- query.select(`.${el}`).boundingClientRect(data => {
|
|
|
- resolve(data)
|
|
|
- }).exec();
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- findElem(array, attr, val) {
|
|
|
- for (var i = 0; i < array.length; i++) {
|
|
|
- if (array[i][attr] == val) {
|
|
|
- return i; //返回当前索引值
|
|
|
- }
|
|
|
- }
|
|
|
- return -1;
|
|
|
- },
|
|
|
-
|
|
|
- // 进入商品详情
|
|
|
- toGoodsDetail(id) {
|
|
|
- if(!id) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- uni.navigateTo({
|
|
|
- url: '/packageGoods/pages/detail?id=' + id
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- // 获取海报图
|
|
|
- getBanner() {
|
|
|
- this.$axios({
|
|
|
- url: '/goods/promotion/share/qrcode',
|
|
|
- method: 'get',
|
|
|
- params: {
|
|
|
- userId: this.userId,
|
|
|
- }
|
|
|
- }).then(res => {
|
|
|
- this.bannerUrl = res.data.posterImgUrl;
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- // 点击分享
|
|
|
- clickShare() {
|
|
|
- if(!this.isLogin) {
|
|
|
- return uni.navigateTo({
|
|
|
- url: '/pages/login/index'
|
|
|
- })
|
|
|
- }
|
|
|
- this.getCode();
|
|
|
- this.isShareDialog = true;
|
|
|
- },
|
|
|
-
|
|
|
- // 获取二维码
|
|
|
- getCode() {
|
|
|
- let that = this;
|
|
|
- this.$axios({
|
|
|
- url: '/goods/promotion/share/qrcode',
|
|
|
- method: 'get',
|
|
|
- params: {
|
|
|
- userId: this.userId,
|
|
|
- }
|
|
|
- }).then(res => {
|
|
|
- if(res.data) {
|
|
|
- // this.codeUrl = res.data.qrcode;
|
|
|
- // this.bgUrl = res.data.promotionImgUrl;
|
|
|
- if(!this.isFinishCanvas) {
|
|
|
- uni.downloadFile({
|
|
|
- url: res.data.promotionImgUrl,
|
|
|
- success: function (fileRes) {
|
|
|
- that.bgUrl = fileRes.tempFilePath;
|
|
|
- }
|
|
|
- })
|
|
|
- uni.downloadFile({
|
|
|
- url: res.data.qrcode,
|
|
|
- success: function (fileRes) {
|
|
|
- that.codeUrl = fileRes.tempFilePath;
|
|
|
- }
|
|
|
- })
|
|
|
- uni.downloadFile({
|
|
|
- url: that.userInfo.avatar.indexOf('http') >= 0 ? that.userInfo.avatar : (that.$imageUrl + that.userInfo.avatar),
|
|
|
- success: function (fileRes) {
|
|
|
- that.headUrl = fileRes.tempFilePath;
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- // 生成图片
|
|
|
- markImage() {
|
|
|
- if(!this.bgUrl || !this.codeUrl || !this.headUrl) {
|
|
|
- this.getCode();
|
|
|
- return this.$toast('生成失败,请重新操作');
|
|
|
- }
|
|
|
-
|
|
|
- let that = this;
|
|
|
- this.isShareDialog = false;
|
|
|
- this.isShowCanvas = true;
|
|
|
-
|
|
|
- if(this.isFinishCanvas) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- uni.showLoading({
|
|
|
- title: '海报生成中'
|
|
|
- });
|
|
|
-
|
|
|
- let codeUrl = this.codeUrl;
|
|
|
- let bgUrl = this.bgUrl;
|
|
|
- let headUrl = this.headUrl;
|
|
|
-
|
|
|
- // this.userInfo.nickName = '阿里巴巴的的';
|
|
|
- let name = this.userInfo.nickName.length > 4 ? this.userInfo.nickName.slice(0, 4) + '...' : this.userInfo.nickName;
|
|
|
-
|
|
|
- var ctx = uni.createCanvasContext('myCanvas');
|
|
|
-
|
|
|
- // 背景图片
|
|
|
- ctx.drawImage(bgUrl, 0, 0, 340, 340)
|
|
|
-
|
|
|
- // 二维码
|
|
|
- this.circleImgOne(ctx, codeUrl, 260, 260, uni.upx2px(70));
|
|
|
- // ctx.drawImage(codeUrl, 260, 260, 70, 70)
|
|
|
-
|
|
|
- // 矩形
|
|
|
- // ctx.setFillStyle('rgba(0,0,0,0.4)')
|
|
|
- // ctx.fillRect(185, 10, 145, 30)
|
|
|
-
|
|
|
- // 圆角矩形
|
|
|
- this.fillRoundRect(ctx, 175, 10, 155, 30, 15, 'rgba(0,0,0,0.4)');
|
|
|
-
|
|
|
- // 头像
|
|
|
- // this.circleImgOne(ctx, headUrl, 200, 10, 15);
|
|
|
- ctx.drawImage(headUrl, 187, 12, 26, 26)
|
|
|
-
|
|
|
- // 文字
|
|
|
- ctx.setFontSize(12)
|
|
|
- ctx.setFillStyle('#FFFFFF')
|
|
|
- ctx.fillText(name+'向你推荐', 217, 30)
|
|
|
-
|
|
|
- ctx.draw()
|
|
|
- uni.hideLoading();
|
|
|
- this.isFinishCanvas = true;
|
|
|
- },
|
|
|
-
|
|
|
- // ctx=Canvas实例, img=图片地址, x=x轴坐标, y=y轴坐标, r=圆形半径
|
|
|
- circleImgOne(ctx, img, x, y, r) {
|
|
|
- // 如果在绘制图片之后还有需要绘制别的元素,需启动 save() 、restore() 方法,否则 clip() 方法会导致之后元素都不可见
|
|
|
- // save():保存当前 Canvas 画布状态
|
|
|
- // restore():恢复到保存时的状态
|
|
|
- ctx.save();
|
|
|
- let d = r * 2;
|
|
|
- let cx = x + r;
|
|
|
- let cy = y + r;
|
|
|
- ctx.arc(cx, cy, r, 0, 2 * Math.PI);
|
|
|
- ctx.strokeStyle = '#FFFFFF'; // 设置绘制圆形边框的颜色
|
|
|
- ctx.stroke(); // 绘制出圆形,默认为黑色,可通过 ctx.strokeStyle = '#FFFFFF', 设置想要的颜色
|
|
|
- ctx.clip();
|
|
|
- ctx.drawImage(img, x, y, d, d);
|
|
|
- ctx.restore();
|
|
|
- },
|
|
|
-
|
|
|
- /**该方法用来绘制一个有填充色的圆角矩形
|
|
|
- *@param cxt:canvas的上下文环境
|
|
|
- *@param x:左上角x轴坐标
|
|
|
- *@param y:左上角y轴坐标
|
|
|
- *@param width:矩形的宽度
|
|
|
- *@param height:矩形的高度
|
|
|
- *@param radius:圆的半径
|
|
|
- *@param fillColor:填充颜色
|
|
|
- **/
|
|
|
- fillRoundRect(cxt, x, y, width, height, radius, fillColor) {
|
|
|
- //圆的直径必然要小于矩形的宽高
|
|
|
- if (2 * radius > width || 2 * radius > height) { return false; }
|
|
|
-
|
|
|
- cxt.save();
|
|
|
- cxt.translate(x, y);
|
|
|
- //绘制圆角矩形的各个边
|
|
|
- this.drawRoundRectPath(cxt, width, height, radius);
|
|
|
- cxt.fillStyle = fillColor;
|
|
|
- cxt.fill();
|
|
|
- cxt.restore();
|
|
|
- },
|
|
|
-
|
|
|
- drawRoundRectPath(cxt, width, height, radius) {
|
|
|
- cxt.beginPath(0);
|
|
|
- //从右下角顺时针绘制,弧度从0到1/2PI
|
|
|
- cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
|
|
|
- //矩形下边线
|
|
|
- cxt.lineTo(radius, height);
|
|
|
- //左下角圆弧,弧度从1/2PI到PI
|
|
|
- cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
|
|
|
- //矩形左边线
|
|
|
- cxt.lineTo(0, radius);
|
|
|
- //左上角圆弧,弧度从PI到3/2PI
|
|
|
- cxt.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
|
|
|
- //上边线
|
|
|
- cxt.lineTo(width - radius, 0);
|
|
|
- //右上角圆弧
|
|
|
- cxt.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
|
|
|
- //右边线
|
|
|
- cxt.lineTo(width, height - radius);
|
|
|
- cxt.closePath();
|
|
|
- },
|
|
|
-
|
|
|
- // 保存图片
|
|
|
- saveImage() {
|
|
|
- let that = this;
|
|
|
- uni.canvasToTempFilePath({
|
|
|
- x: 0,
|
|
|
- y: 0,
|
|
|
- width: 340,
|
|
|
- height: 340,
|
|
|
- canvasId: 'myCanvas',
|
|
|
- success: function(res) {
|
|
|
- uni.saveImageToPhotosAlbum({
|
|
|
- filePath: res.tempFilePath,
|
|
|
- success: function () {
|
|
|
- that.$successToast('保存成功');
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
- // 关闭canvas
|
|
|
- closeCanvas() {
|
|
|
- this.isShowCanvas = false;
|
|
|
- uni.hideLoading();
|
|
|
- },
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
+import { mapState } from 'vuex'
|
|
|
+// import dragButton from '@/components/drag-button.vue';
|
|
|
+
|
|
|
+export default {
|
|
|
+ // components:{
|
|
|
+ // dragButton
|
|
|
+ // },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ configInfo: {},
|
|
|
+ dataList: [], // 优惠券列表
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 8,
|
|
|
+ noMore: false,
|
|
|
+ loading: false,
|
|
|
+ isShareDialog: false, // 是否显示分享弹窗
|
|
|
+ isShowCanvas: false, // 是否显示海报弹窗
|
|
|
+ isFinishCanvas: false, // 是否已完成海报
|
|
|
+ codeUrl: '',
|
|
|
+ bgUrl: '',
|
|
|
+ headUrl: '',
|
|
|
+ top: 300,
|
|
|
+ tabList: [], // 分类列表
|
|
|
+ tabCurrent: '', // 分类当前值
|
|
|
+ keyword: '',
|
|
|
+
|
|
|
+ scrollLeft: 50,
|
|
|
+ scrollViewWidth: 0,
|
|
|
+ tabsRect: {
|
|
|
+ left: 0
|
|
|
+ },
|
|
|
+
|
|
|
+ bannerUrl: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ watch: {
|
|
|
+ tabList() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.resize()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ computed: {
|
|
|
+ ...mapState(['userInfo', 'isLogin', 'userId'])
|
|
|
+ },
|
|
|
+
|
|
|
+ onShow() {
|
|
|
+ // this.$refs.dragButton.init();
|
|
|
+
|
|
|
+ this.top = this.$getStorage('top') < 200 ? this.$getStorage('top') : this.$getStorage('top') - 124
|
|
|
+ },
|
|
|
+
|
|
|
+ async onLoad() {
|
|
|
+ this.getTabList()
|
|
|
+ this.getBanner()
|
|
|
+ this.configInfo = await this.$getConfigInfo()
|
|
|
+ },
|
|
|
+
|
|
|
+ onShow() {
|
|
|
+ this.crossPage.$on('hanbleShare', () => {
|
|
|
+ this.clickShare()
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ onHide() {
|
|
|
+ this.crossPage.$off('hanbleShare')
|
|
|
+ },
|
|
|
+
|
|
|
+ // 下拉刷新
|
|
|
+ onPullDownRefresh() {
|
|
|
+ this.pageNum = 1
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+
|
|
|
+ // 上拉加载
|
|
|
+ onReachBottom() {
|
|
|
+ this.getList(1)
|
|
|
+ },
|
|
|
+
|
|
|
+ onShareAppMessage(options) {
|
|
|
+ if (options && options.from == 'button') {
|
|
|
+ // 来自页面内的转发按钮
|
|
|
+ } else {
|
|
|
+ // 点击微信右上角的分享按钮
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ title: `${this.userInfo.nickName}向你推荐了${this.configInfo.minAppName}的团购活动`,
|
|
|
+ // imageUrl: this.detail.imgUrl,
|
|
|
+ path: '/pages/index/index?serviceId=' + this.userId + '&otherType=groupbuyList',
|
|
|
+ query: {
|
|
|
+ // id: this.goodsId,
|
|
|
+ },
|
|
|
+ success: function (res) {
|
|
|
+ if (res.errMsg == 'shareAppMessage:ok') {
|
|
|
+ this.$successToast('分享完成')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ getList(loadMore) {
|
|
|
+ if (this.noMore && loadMore) return
|
|
|
+ this.noMore = false
|
|
|
+ if (!loadMore) {
|
|
|
+ this.pageNum = 1
|
|
|
+ } else {
|
|
|
+ this.loading = true
|
|
|
+ }
|
|
|
+ this.$api
|
|
|
+ .get('/goods/promotion/group/list', {
|
|
|
+ pageNo: this.pageNum,
|
|
|
+ pageSize: this.pageSize,
|
|
|
+ userId: this.userId,
|
|
|
+ goodsCategoryId: this.tabCurrent,
|
|
|
+ keyword: this.keyword
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ let _list = res.data.records
|
|
|
+ let pageTotal = res.data.pages
|
|
|
+ if (this.pageNum >= pageTotal) {
|
|
|
+ this.noMore = true
|
|
|
+ }
|
|
|
+ if (_list.length) {
|
|
|
+ this.pageNum += 1
|
|
|
+ }
|
|
|
+ if (loadMore) {
|
|
|
+ this.dataList = this.dataList.concat(_list)
|
|
|
+ this.loading = false
|
|
|
+ } else {
|
|
|
+ this.dataList = _list
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.stopPullDownRefresh()
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取一级菜单
|
|
|
+ getTabList() {
|
|
|
+ this.$api.get('/goods/category/list', {}).then(res => {
|
|
|
+ res.data.unshift({ name: '全部', categoryId: '' })
|
|
|
+ this.tabList = res.data
|
|
|
+ this.tabCurrent = res.data.length > 0 ? res.data[0].categoryId : 0
|
|
|
+ this.getList()
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 切换一级菜单
|
|
|
+ changeTab(current) {
|
|
|
+ this.pageNum = 1
|
|
|
+ this.tabCurrent = current
|
|
|
+ this.resize()
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+
|
|
|
+ searchSubmit() {
|
|
|
+ this.pageNum = 1
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+
|
|
|
+ setScrollLeft() {
|
|
|
+ // 当前活动tab的布局信息,有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
|
|
|
+ const index = this.findElem(this.tabList, 'categoryId', this.tabCurrent)
|
|
|
+ const tabRect = this.tabList[index]
|
|
|
+ // 累加得到当前item到左边的距离
|
|
|
+ const offsetLeft = this.tabList.slice(0, index).reduce((total, curr) => {
|
|
|
+ return total + curr.rect.width
|
|
|
+ }, 0)
|
|
|
+ // 此处为屏幕宽度
|
|
|
+ const res = uni.getSystemInfoSync()
|
|
|
+ const windowWidth = res.windowWidth
|
|
|
+ // 将活动的tabs-item移动到屏幕正中间,实际上是对scroll-view的移动
|
|
|
+ let scrollLeft =
|
|
|
+ offsetLeft -
|
|
|
+ (this.tabsRect.width - tabRect.rect.width) / 2 -
|
|
|
+ (windowWidth - this.tabsRect.right) / 2 +
|
|
|
+ this.tabsRect.left / 2
|
|
|
+
|
|
|
+ // 这里做一个限制,限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度
|
|
|
+ scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width)
|
|
|
+ this.scrollLeft = Math.max(0, scrollLeft)
|
|
|
+ },
|
|
|
+ // 获取所有标签的尺寸
|
|
|
+ resize() {
|
|
|
+ // 如果不存在list,则不处理
|
|
|
+ if (this.tabList.length === 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
|
|
|
+ this.tabsRect = tabsRect
|
|
|
+ this.scrollViewWidth = 0
|
|
|
+ itemRect.map((item, index) => {
|
|
|
+ // 计算scroll-view的宽度,这里
|
|
|
+ this.scrollViewWidth += item.width
|
|
|
+ // 另外计算每一个item的中心点X轴坐标
|
|
|
+ this.tabList[index].rect = item
|
|
|
+ })
|
|
|
+ // 获取了tabs的尺寸之后,设置滑块的位置
|
|
|
+ this.setScrollLeft()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 获取导航菜单的尺寸
|
|
|
+ getTabsRect() {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ this.queryRect('tabs-view').then(size => resolve(size))
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 获取所有标签的尺寸
|
|
|
+ getAllItemRect() {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ const promiseAllArr = this.tabList.map((item, index) => this.queryRect(`tabs-item-${index}`, true))
|
|
|
+ Promise.all(promiseAllArr).then(sizes => resolve(sizes))
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 获取各个标签的尺寸
|
|
|
+ queryRect(el, item) {
|
|
|
+ const query = uni.createSelectorQuery().in(this)
|
|
|
+ return new Promise(resolve => {
|
|
|
+ query
|
|
|
+ .select(`.${el}`)
|
|
|
+ .boundingClientRect(data => {
|
|
|
+ resolve(data)
|
|
|
+ })
|
|
|
+ .exec()
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ findElem(array, attr, val) {
|
|
|
+ for (var i = 0; i < array.length; i++) {
|
|
|
+ if (array[i][attr] == val) {
|
|
|
+ return i //返回当前索引值
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1
|
|
|
+ },
|
|
|
+
|
|
|
+ // 进入商品详情
|
|
|
+ toGoodsDetail(id) {
|
|
|
+ if (!id) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/packageGoods/pages/detail?id=' + id
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取海报图
|
|
|
+ getBanner() {
|
|
|
+ this.$api
|
|
|
+ .get('/goods/promotion/share/qrcode', {
|
|
|
+ userId: this.userId
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ this.bannerUrl = res.data.posterImgUrl
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 点击分享
|
|
|
+ clickShare() {
|
|
|
+ if (!this.isLogin) {
|
|
|
+ return uni.navigateTo({
|
|
|
+ url: '/pages/login/index'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.getCode()
|
|
|
+ this.isShareDialog = true
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取二维码
|
|
|
+ getCode() {
|
|
|
+ let that = this
|
|
|
+ this.$api
|
|
|
+ .get('/goods/promotion/share/qrcode', {
|
|
|
+ userId: this.userId
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ if (res.data) {
|
|
|
+ // this.codeUrl = res.data.qrcode;
|
|
|
+ // this.bgUrl = res.data.promotionImgUrl;
|
|
|
+ if (!this.isFinishCanvas) {
|
|
|
+ uni.downloadFile({
|
|
|
+ url: res.data.promotionImgUrl,
|
|
|
+ success: function (fileRes) {
|
|
|
+ that.bgUrl = fileRes.tempFilePath
|
|
|
+ }
|
|
|
+ })
|
|
|
+ uni.downloadFile({
|
|
|
+ url: res.data.qrcode,
|
|
|
+ success: function (fileRes) {
|
|
|
+ that.codeUrl = fileRes.tempFilePath
|
|
|
+ }
|
|
|
+ })
|
|
|
+ uni.downloadFile({
|
|
|
+ url:
|
|
|
+ that.userInfo.avatar.indexOf('http') >= 0
|
|
|
+ ? that.userInfo.avatar
|
|
|
+ : that.$imageUrl + that.userInfo.avatar,
|
|
|
+ success: function (fileRes) {
|
|
|
+ that.headUrl = fileRes.tempFilePath
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 生成图片
|
|
|
+ markImage() {
|
|
|
+ if (!this.bgUrl || !this.codeUrl || !this.headUrl) {
|
|
|
+ this.getCode()
|
|
|
+ return this.$toast('生成失败,请重新操作')
|
|
|
+ }
|
|
|
+
|
|
|
+ let that = this
|
|
|
+ this.isShareDialog = false
|
|
|
+ this.isShowCanvas = true
|
|
|
+
|
|
|
+ if (this.isFinishCanvas) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showLoading({
|
|
|
+ title: '海报生成中'
|
|
|
+ })
|
|
|
+
|
|
|
+ let codeUrl = this.codeUrl
|
|
|
+ let bgUrl = this.bgUrl
|
|
|
+ let headUrl = this.headUrl
|
|
|
+
|
|
|
+ // this.userInfo.nickName = '阿里巴巴的的';
|
|
|
+ let name = this.userInfo.nickName.length > 4 ? this.userInfo.nickName.slice(0, 4) + '...' : this.userInfo.nickName
|
|
|
+
|
|
|
+ var ctx = uni.createCanvasContext('myCanvas')
|
|
|
+
|
|
|
+ // 背景图片
|
|
|
+ ctx.drawImage(bgUrl, 0, 0, 340, 340)
|
|
|
+
|
|
|
+ // 二维码
|
|
|
+ this.circleImgOne(ctx, codeUrl, 260, 260, uni.upx2px(70))
|
|
|
+ // ctx.drawImage(codeUrl, 260, 260, 70, 70)
|
|
|
+
|
|
|
+ // 矩形
|
|
|
+ // ctx.setFillStyle('rgba(0,0,0,0.4)')
|
|
|
+ // ctx.fillRect(185, 10, 145, 30)
|
|
|
+
|
|
|
+ // 圆角矩形
|
|
|
+ this.fillRoundRect(ctx, 175, 10, 155, 30, 15, 'rgba(0,0,0,0.4)')
|
|
|
+
|
|
|
+ // 头像
|
|
|
+ // this.circleImgOne(ctx, headUrl, 200, 10, 15);
|
|
|
+ ctx.drawImage(headUrl, 187, 12, 26, 26)
|
|
|
+
|
|
|
+ // 文字
|
|
|
+ ctx.setFontSize(12)
|
|
|
+ ctx.setFillStyle('#FFFFFF')
|
|
|
+ ctx.fillText(name + '向你推荐', 217, 30)
|
|
|
+
|
|
|
+ ctx.draw()
|
|
|
+ uni.hideLoading()
|
|
|
+ this.isFinishCanvas = true
|
|
|
+ },
|
|
|
+
|
|
|
+ // ctx=Canvas实例, img=图片地址, x=x轴坐标, y=y轴坐标, r=圆形半径
|
|
|
+ circleImgOne(ctx, img, x, y, r) {
|
|
|
+ // 如果在绘制图片之后还有需要绘制别的元素,需启动 save() 、restore() 方法,否则 clip() 方法会导致之后元素都不可见
|
|
|
+ // save():保存当前 Canvas 画布状态
|
|
|
+ // restore():恢复到保存时的状态
|
|
|
+ ctx.save()
|
|
|
+ let d = r * 2
|
|
|
+ let cx = x + r
|
|
|
+ let cy = y + r
|
|
|
+ ctx.arc(cx, cy, r, 0, 2 * Math.PI)
|
|
|
+ ctx.strokeStyle = '#FFFFFF' // 设置绘制圆形边框的颜色
|
|
|
+ ctx.stroke() // 绘制出圆形,默认为黑色,可通过 ctx.strokeStyle = '#FFFFFF', 设置想要的颜色
|
|
|
+ ctx.clip()
|
|
|
+ ctx.drawImage(img, x, y, d, d)
|
|
|
+ ctx.restore()
|
|
|
+ },
|
|
|
+
|
|
|
+ /**该方法用来绘制一个有填充色的圆角矩形
|
|
|
+ *@param cxt:canvas的上下文环境
|
|
|
+ *@param x:左上角x轴坐标
|
|
|
+ *@param y:左上角y轴坐标
|
|
|
+ *@param width:矩形的宽度
|
|
|
+ *@param height:矩形的高度
|
|
|
+ *@param radius:圆的半径
|
|
|
+ *@param fillColor:填充颜色
|
|
|
+ **/
|
|
|
+ fillRoundRect(cxt, x, y, width, height, radius, fillColor) {
|
|
|
+ //圆的直径必然要小于矩形的宽高
|
|
|
+ if (2 * radius > width || 2 * radius > height) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ cxt.save()
|
|
|
+ cxt.translate(x, y)
|
|
|
+ //绘制圆角矩形的各个边
|
|
|
+ this.drawRoundRectPath(cxt, width, height, radius)
|
|
|
+ cxt.fillStyle = fillColor
|
|
|
+ cxt.fill()
|
|
|
+ cxt.restore()
|
|
|
+ },
|
|
|
+
|
|
|
+ drawRoundRectPath(cxt, width, height, radius) {
|
|
|
+ cxt.beginPath(0)
|
|
|
+ //从右下角顺时针绘制,弧度从0到1/2PI
|
|
|
+ cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2)
|
|
|
+ //矩形下边线
|
|
|
+ cxt.lineTo(radius, height)
|
|
|
+ //左下角圆弧,弧度从1/2PI到PI
|
|
|
+ cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI)
|
|
|
+ //矩形左边线
|
|
|
+ cxt.lineTo(0, radius)
|
|
|
+ //左上角圆弧,弧度从PI到3/2PI
|
|
|
+ cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2)
|
|
|
+ //上边线
|
|
|
+ cxt.lineTo(width - radius, 0)
|
|
|
+ //右上角圆弧
|
|
|
+ cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2)
|
|
|
+ //右边线
|
|
|
+ cxt.lineTo(width, height - radius)
|
|
|
+ cxt.closePath()
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存图片
|
|
|
+ saveImage() {
|
|
|
+ let that = this
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: 340,
|
|
|
+ height: 340,
|
|
|
+ canvasId: 'myCanvas',
|
|
|
+ success: function (res) {
|
|
|
+ uni.saveImageToPhotosAlbum({
|
|
|
+ filePath: res.tempFilePath,
|
|
|
+ success: function () {
|
|
|
+ that.$successToast('保存成功')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 关闭canvas
|
|
|
+ closeCanvas() {
|
|
|
+ this.isShowCanvas = false
|
|
|
+ uni.hideLoading()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
- .app-container {
|
|
|
- background: #F4F2F2;
|
|
|
- box-sizing: border-box;
|
|
|
- padding-top: 184rpx;
|
|
|
- }
|
|
|
-
|
|
|
- .fixed-container {
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
- }
|
|
|
-
|
|
|
- .share-container {
|
|
|
- position: fixed;
|
|
|
- right: 20rpx;
|
|
|
- // bottom: 30vh;
|
|
|
- button {
|
|
|
- width: 108rpx;
|
|
|
- height: 108rpx;
|
|
|
- padding: 0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- border-radius: 50%;
|
|
|
- // box-shadow: 0 1px 4px rgba(0, 21, 41, .8);
|
|
|
- background: #ffffff;
|
|
|
- border: 4rpx solid #eaeaea;
|
|
|
- image {
|
|
|
- width: 28rpx;
|
|
|
- height: 28rpx;
|
|
|
- display: block;
|
|
|
- flex-shrink: 0;
|
|
|
- margin-bottom: 6rpx;
|
|
|
- }
|
|
|
- text {
|
|
|
- font-size: 22rpx;
|
|
|
- line-height: 24rpx;
|
|
|
- color: #666666;
|
|
|
- margin-top: 8rpx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .top-container {
|
|
|
- background: #FFFFFF;
|
|
|
- .tab {
|
|
|
- display: flex;
|
|
|
- margin-left: -10rpx;
|
|
|
- .item {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- flex-shrink: 0;
|
|
|
- font-size: 28rpx;
|
|
|
- color: #666666;
|
|
|
- height: 80rpx;
|
|
|
- line-height: 80rpx;
|
|
|
- position: relative;
|
|
|
- padding: 0 30rpx;
|
|
|
- &.current {
|
|
|
- color: #FF3F42;
|
|
|
- font-weight: 600;
|
|
|
- &::after {
|
|
|
- content: '';
|
|
|
- display: block;
|
|
|
- width: 50rpx;
|
|
|
- height: 6rpx;
|
|
|
- background: #FF3F42;
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 50%;
|
|
|
- margin-left: -25rpx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .search-container {
|
|
|
- background: #FFFFFF;
|
|
|
- padding: 20rpx;
|
|
|
- .search {
|
|
|
- height: 64rpx;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- border-radius: 64rpx;
|
|
|
- padding: 0 20rpx;
|
|
|
- border: 1px solid #eaeaea;
|
|
|
- image {
|
|
|
- width: 28rpx;
|
|
|
- height: 28rpx;
|
|
|
- }
|
|
|
- input {
|
|
|
- width: 100%;
|
|
|
- padding-left: 15rpx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .banner-container {
|
|
|
- padding: 20rpx 20rpx 0;
|
|
|
- image {
|
|
|
- display: block;
|
|
|
- width: 100%;
|
|
|
- border-radius: 10rpx;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .list-container {
|
|
|
- padding: 20rpx;
|
|
|
- .item {
|
|
|
- background: #FFFFFF;
|
|
|
- border-radius: 10rpx;
|
|
|
- display: flex;
|
|
|
- padding: 20rpx;
|
|
|
- margin-bottom: 20rpx;
|
|
|
- image {
|
|
|
- display: block;
|
|
|
- width: 180rpx;
|
|
|
- height: 180rpx;
|
|
|
- flex-shrink: 0;
|
|
|
- }
|
|
|
- .right {
|
|
|
- width: 490rpx;
|
|
|
- box-sizing: border-box;
|
|
|
- padding-left: 20rpx;
|
|
|
- .title {
|
|
|
- font-size: 30rpx;
|
|
|
- color: #333333;
|
|
|
- line-height: 36rpx;
|
|
|
- font-weight: 600;
|
|
|
- }
|
|
|
- .des {
|
|
|
- font-size: 24rpx;
|
|
|
- line-height: 30rpx;
|
|
|
- color: #999999;
|
|
|
- margin-top: 6rpx;
|
|
|
- }
|
|
|
- .stock-sales {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-top: 10rpx;
|
|
|
- font-size: 24rpx;
|
|
|
- color: #666666;
|
|
|
- .stock {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- text {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #666666;
|
|
|
- }
|
|
|
- .progress-box {
|
|
|
- width: 140rpx;
|
|
|
- border-radius: 6px;
|
|
|
- overflow: hidden;
|
|
|
- margin-left: 10rpx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- .bottom {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-top: 10rpx;
|
|
|
- .price {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- }
|
|
|
- .price-1 {
|
|
|
- font-size: 32rpx;
|
|
|
- color: #FF3F42;
|
|
|
- line-height: 36rpx;
|
|
|
- }
|
|
|
- .price-2 {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #666666;
|
|
|
- line-height: 30rpx;
|
|
|
- text-decoration: line-through;
|
|
|
- }
|
|
|
- .btn {
|
|
|
- width: 110rpx;
|
|
|
- height: 44rpx;
|
|
|
- background: #FF3F42;
|
|
|
- border-radius: 5rpx;
|
|
|
- font-size: 28rpx;
|
|
|
- color: #FFFFFF;
|
|
|
- text-align: center;
|
|
|
- line-height: 44rpx;
|
|
|
- }
|
|
|
- .btn2 {
|
|
|
- width: 110rpx;
|
|
|
- height: 44rpx;
|
|
|
- background: #AAAAAA;
|
|
|
- border-radius: 5rpx;
|
|
|
- font-size: 28rpx;
|
|
|
- color: #FFFFFF;
|
|
|
- text-align: center;
|
|
|
- line-height: 44rpx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .sharelist-container {
|
|
|
- position: fixed;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- z-index: 999;
|
|
|
- width: 100%;
|
|
|
- box-sizing: border-box;
|
|
|
- background: #FFFFFF;
|
|
|
- padding: 30rpx 0;
|
|
|
- display: flex;
|
|
|
- button {
|
|
|
- background: none;
|
|
|
- border-radius:0;
|
|
|
- &::after {
|
|
|
- border: none;
|
|
|
- }
|
|
|
- }
|
|
|
- .item {
|
|
|
- display: flex;
|
|
|
- width: 50%;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- image {
|
|
|
- width: 100rpx;
|
|
|
- height: 100rpx;
|
|
|
- display: block;
|
|
|
- margin-bottom: 20rpx;
|
|
|
- }
|
|
|
- text {
|
|
|
- font-size: 28rpx;
|
|
|
- line-height: 32rpx;
|
|
|
- color: #333333;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- .canvas-container {
|
|
|
- position: fixed;
|
|
|
- left: 50%;
|
|
|
- top: 50%;
|
|
|
- z-index: 999;
|
|
|
- margin-left: -170px;
|
|
|
- margin-top: -170px;
|
|
|
- .button {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- text {
|
|
|
- display: block;
|
|
|
- width: 280rpx;
|
|
|
- height: 70rpx;
|
|
|
- border-radius: 70rpx;
|
|
|
- background: linear-gradient(-90deg,#ff3f42 0%, #fe781f 100%);
|
|
|
- font-size: 28rpx;
|
|
|
- color: #FFFFFF;
|
|
|
- text-align: center;
|
|
|
- line-height: 70rpx;
|
|
|
- margin-top: 20rpx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+.app-container {
|
|
|
+ background: #f4f2f2;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-top: 184rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.fixed-container {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.share-container {
|
|
|
+ position: fixed;
|
|
|
+ right: 20rpx;
|
|
|
+ // bottom: 30vh;
|
|
|
+ button {
|
|
|
+ width: 108rpx;
|
|
|
+ height: 108rpx;
|
|
|
+ padding: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ border-radius: 50%;
|
|
|
+ // box-shadow: 0 1px 4px rgba(0, 21, 41, .8);
|
|
|
+ background: #ffffff;
|
|
|
+ border: 4rpx solid #eaeaea;
|
|
|
+ image {
|
|
|
+ width: 28rpx;
|
|
|
+ height: 28rpx;
|
|
|
+ display: block;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-bottom: 6rpx;
|
|
|
+ }
|
|
|
+ text {
|
|
|
+ font-size: 22rpx;
|
|
|
+ line-height: 24rpx;
|
|
|
+ color: #666666;
|
|
|
+ margin-top: 8rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.top-container {
|
|
|
+ background: #ffffff;
|
|
|
+ .tab {
|
|
|
+ display: flex;
|
|
|
+ margin-left: -10rpx;
|
|
|
+ .item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #666666;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ position: relative;
|
|
|
+ padding: 0 30rpx;
|
|
|
+ &.current {
|
|
|
+ color: #ff3f42;
|
|
|
+ font-weight: 600;
|
|
|
+ &::after {
|
|
|
+ content: '';
|
|
|
+ display: block;
|
|
|
+ width: 50rpx;
|
|
|
+ height: 6rpx;
|
|
|
+ background: #ff3f42;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 50%;
|
|
|
+ margin-left: -25rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.search-container {
|
|
|
+ background: #ffffff;
|
|
|
+ padding: 20rpx;
|
|
|
+ .search {
|
|
|
+ height: 64rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ border-radius: 64rpx;
|
|
|
+ padding: 0 20rpx;
|
|
|
+ border: 1px solid #eaeaea;
|
|
|
+ image {
|
|
|
+ width: 28rpx;
|
|
|
+ height: 28rpx;
|
|
|
+ }
|
|
|
+ input {
|
|
|
+ width: 100%;
|
|
|
+ padding-left: 15rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.banner-container {
|
|
|
+ padding: 20rpx 20rpx 0;
|
|
|
+ image {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.list-container {
|
|
|
+ padding: 20rpx;
|
|
|
+ .item {
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ display: flex;
|
|
|
+ padding: 20rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ image {
|
|
|
+ display: block;
|
|
|
+ width: 180rpx;
|
|
|
+ height: 180rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ .right {
|
|
|
+ width: 490rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-left: 20rpx;
|
|
|
+ .title {
|
|
|
+ font-size: 30rpx;
|
|
|
+ color: #333333;
|
|
|
+ line-height: 36rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+ .des {
|
|
|
+ font-size: 24rpx;
|
|
|
+ line-height: 30rpx;
|
|
|
+ color: #999999;
|
|
|
+ margin-top: 6rpx;
|
|
|
+ }
|
|
|
+ .stock-sales {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 10rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666666;
|
|
|
+ .stock {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ text {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666666;
|
|
|
+ }
|
|
|
+ .progress-box {
|
|
|
+ width: 140rpx;
|
|
|
+ border-radius: 6px;
|
|
|
+ overflow: hidden;
|
|
|
+ margin-left: 10rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .bottom {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 10rpx;
|
|
|
+ .price {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ .price-1 {
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #ff3f42;
|
|
|
+ line-height: 36rpx;
|
|
|
+ }
|
|
|
+ .price-2 {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666666;
|
|
|
+ line-height: 30rpx;
|
|
|
+ text-decoration: line-through;
|
|
|
+ }
|
|
|
+ .btn {
|
|
|
+ width: 110rpx;
|
|
|
+ height: 44rpx;
|
|
|
+ background: #ff3f42;
|
|
|
+ border-radius: 5rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #ffffff;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 44rpx;
|
|
|
+ }
|
|
|
+ .btn2 {
|
|
|
+ width: 110rpx;
|
|
|
+ height: 44rpx;
|
|
|
+ background: #aaaaaa;
|
|
|
+ border-radius: 5rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #ffffff;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 44rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.sharelist-container {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ z-index: 999;
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #ffffff;
|
|
|
+ padding: 30rpx 0;
|
|
|
+ display: flex;
|
|
|
+ button {
|
|
|
+ background: none;
|
|
|
+ border-radius: 0;
|
|
|
+ &::after {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .item {
|
|
|
+ display: flex;
|
|
|
+ width: 50%;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ image {
|
|
|
+ width: 100rpx;
|
|
|
+ height: 100rpx;
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ }
|
|
|
+ text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ line-height: 32rpx;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.canvas-container {
|
|
|
+ position: fixed;
|
|
|
+ left: 50%;
|
|
|
+ top: 50%;
|
|
|
+ z-index: 999;
|
|
|
+ margin-left: -170px;
|
|
|
+ margin-top: -170px;
|
|
|
+ .button {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ text {
|
|
|
+ display: block;
|
|
|
+ width: 280rpx;
|
|
|
+ height: 70rpx;
|
|
|
+ border-radius: 70rpx;
|
|
|
+ background: linear-gradient(-90deg, #ff3f42 0%, #fe781f 100%);
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #ffffff;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 70rpx;
|
|
|
+ margin-top: 20rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|