如图微信小程序生成海报自定义调整位置
//微信小程序组件 poster.wxml
<view style='position: relative;{{customStyle}};{{painterStyle}}'>
<block wx:if="{{!use2D}}">
<canvas canvas-id="photo" style="{{photoStyle}};position: absolute; left: -9999px; top: -9999rpx;" />
<block wx:if="{{dancePalette}}">
<canvas canvas-id="bottom" style="{{painterStyle}};position: absolute;" />
<canvas canvas-id="k-canvas" style="{{painterStyle}};position: absolute;" />
<canvas canvas-id="top" style="{{painterStyle}};position: absolute;" />
<canvas
canvas-id="front"
style="{{painterStyle}};position: absolute;"
bindtouchstart="onTouchStart"
bindtouchmove="onTouchMove"
bindtouchend="onTouchEnd"
bindtouchcancel="onTouchCancel"
disable-scroll="{{true}}" />
</block>
</block>
<block wx:if="{{use2D}}">
<canvas type="2d" id="photo" style="{{photoStyle}};" />
</block>
</view>
//组件poster.js
import Pen, { penCache, clearPenCache } from './lib/pen';
import Downloader from './lib/downloader';
import WxCanvas from './lib/wx-canvas';
const util = require('./lib/util');
const calc = require('./lib/calc');
const downloader = new Downloader();
// 最大尝试的绘制次数
const MAX_PAINT_COUNT = 5;
const ACTION_DEFAULT_SIZE = 24;
const ACTION_OFFSET = '2rpx';
Component({
canvasWidthInPx: 0,
canvasHeightInPx: 0,
canvasNode: null,
paintCount: 0,
currentPalette: {},
outterDisabled: false,
isDisabled: false,
needClear: false,
/**
* 组件的属性列表
*/
properties: {
use2D: {
type: Boolean,
},
customStyle: {
type: String,
},
// 运行自定义选择框和删除缩放按钮
customActionStyle: {
type: Object,
},
palette: {
type: Object,
observer: function (newVal, oldVal) {
if (this.isNeedRefresh(newVal, oldVal)) {
this.paintCount = 0;
clearPenCache();
this.startPaint();
}
},
},
dancePalette: {
type: Object,
observer: function (newVal, oldVal) {
if (!this.isEmpty(newVal) && !this.properties.use2D) {
clearPenCache();
this.initDancePalette(newVal);
}
},
},
// 缩放比,会在传入的 palette 中统一乘以该缩放比
scaleRatio: {
type: Number,
value: 1,
},
widthPixels: {
type: Number,
value: 0,
},
// 启用脏检查,默认 false
dirty: {
type: Boolean,
value: false,
},
LRU: {
type: Boolean,
value: false,
},
action: {
type: Object,
observer: function (newVal, oldVal) {
if (newVal && !this.isEmpty(newVal) && !this.properties.use2D) {
this.doAction(newVal, null, false, true);
}
},
},
disableAction: {
type: Boolean,
observer: function (isDisabled) {
this.outterDisabled = isDisabled;
this.isDisabled = isDisabled;
},
},
clearActionBox: {
type: Boolean,
observer: function (needClear) {
if (needClear && !this.needClear) {
if (this.frontContext) {
setTimeout(() => {
this.frontContext.draw();
}, 100);
this.touchedView = {};
this.prevFindedIndex = this.findedIndex;
this.findedIndex = -1;
}
}
this.needClear = needClear;
},
},
},
data: {
picURL: '',
showCanvas: true,
painterStyle: '',
},
methods: {
/**
* 判断一个 object 是否为 空
* @param {object} object
*/
isEmpty(object) {
for (const i in object) {
return false;
}
return true;
},
isNeedRefresh(newVal, oldVal) {
if (!newVal || this.isEmpty(newVal) || (this.data.dirty && util.equal(newVal, oldVal))) {
return false;
}
return true;
},
getBox(rect, type) {
const boxArea = {
type: 'rect',
css: {
height: `${rect.bottom - rect.top}px`,
width: `${rect.right - rect.left}px`,
left: `${rect.left}px`,
top: `${rect.top}px`,
borderWidth: '4rpx',
borderColor: '#1A7AF8',
color: 'transparent',
},
};
if (type === 'text') {
boxArea.css = Object.assign({}, boxArea.css, {
borderStyle: 'dashed',
});
}
if (this.properties.customActionStyle && this.properties.customActionStyle.border) {
boxArea.css = Object.assign({}, boxArea.css, this.properties.customActionStyle.border);
}
Object.assign(boxArea, {
id: 'box',
});
return boxArea;
},
getScaleIcon(rect, type) {
let scaleArea = {};
const { customActionStyle } = this.properties;
if (customActionStyle && customActionStyle.scale) {
scaleArea = {
type: 'image',
url: type === 'text' ? customActionStyle.scale.textIcon : customActionStyle.scale.imageIcon,
css: {
height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
},
};
} else {
scaleArea = {
type: 'rect',
css: {
height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
color: '#0000ff',
},
};
}
scaleArea.css = Object.assign({}, scaleArea.css, {
align: 'center',
left: `${rect.right + ACTION_OFFSET.toPx()}px`,
top:
type === 'text'
? `${rect.top - ACTION_OFFSET.toPx() - scaleArea.css.height.toPx() / 2}px`
: `${rect.bottom - ACTION_OFFSET.toPx() - scaleArea.css.height.toPx() / 2}px`,
});
Object.assign(scaleArea, {
id: 'scale',
});
return scaleArea;
},
getDeleteIcon(rect) {
let deleteArea = {};
const { customActionStyle } = this.properties;
if (customActionStyle && customActionStyle.scale) {
deleteArea = {
type: 'image',
url: customActionStyle.delete.icon,
css: {
height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
},
};
} else {
deleteArea = {
type: 'rect',
css: {
height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
color: '#0000ff',
},
};
}
deleteArea.css = Object.assign({}, deleteArea.css, {
align: 'center',
left: `${rect.left - ACTION_OFFSET.toPx()}px`,
top: `${rect.top - ACTION_OFFSET.toPx() - deleteArea.css.height.toPx() / 2}px`,
});
Object.assign(deleteArea, {
id: 'delete',
});
return deleteArea;
},
doAction(action, callback, isMoving, overwrite) {
if (this.properties.use2D) {
return;
}
let newVal = null;
if (action) {
newVal = action.view;
}
if (newVal && newVal.id && this.touchedView.id !== newVal.id) {
// 带 id 的动作给撤回时使用,不带 id,表示对当前选中对象进行操作
const { views } = this.currentPalette;
for (let i = 0; i < views.length; i++) {
if (views[i].id === newVal.id) {
// 跨层回撤,需要重新构建三层关系
this.touchedView = views[i];
this.findedIndex = i;
this.sliceLayers();
break;
}
}
}
const doView = this.touchedView;
if (!doView || this.isEmpty(doView)) {
return;
}
if (newVal && newVal.css) {
if (overwrite) {
doView.css = newVal.css;
} else if (Array.isArray(doView.css) && Array.isArray(newVal.css)) {
doView.css = Object.assign({}, ...doView.css, ...newVal.css);
} else if (Array.isArray(doView.css)) {
doView.css = Object.assign({}, ...doView.css, newVal.css);
} else if (Array.isArray(newVal.css)) {
doView.css = Object.assign({}, doView.css, ...newVal.css);
} else {
doView.css = Object.assign({}, doView.css, newVal.css);
}
}
if (newVal && newVal.rect) {
doView.rect = newVal.rect;
}
if (newVal && newVal.url && doView.url && newVal.url !== doView.url) {
downloader
.download(newVal.url, this.properties.LRU)
.then(path => {
if (newVal.url.startsWith('https')) {
doView.originUrl = newVal.url;
}
doView.url = path;
wx.getImageInfo({
src: path,
success: res => {
doView.sHeight = res.height;
doView.sWidth = res.width;
this.reDraw(doView, callback, isMoving);
},
fail: () => {
this.reDraw(doView, callback, isMoving);
},
});
})
.catch(error => {
// 未下载成功,直接绘制
console.error(error);
this.reDraw(doView, callback, isMoving);
});
} else {
newVal && newVal.text && doView.text && newVal.text !== doView.text && (doView.text = newVal.text);
newVal &&
newVal.content &&
doView.content &&
newVal.content !== doView.content &&
(doView.content = newVal.content);
this.reDraw(doView, callback, isMoving);
}
},
reDraw(doView, callback, isMoving) {
const draw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: this.isEmpty(doView) ? [] : [doView],
};
const pen = new Pen(this.globalContext, draw);
pen.paint(callbackInfo => {
callback && callback(callbackInfo);
this.triggerEvent('viewUpdate', {
view: this.touchedView,
});
});
const { rect, css, type } = doView;
this.block = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: this.isEmpty(doView) ? [] : [this.getBox(rect, doView.type)],
};
if (css && css.scalable) {
this.block.views.push(this.getScaleIcon(rect, type));
}
if (css && css.deletable) {
this.block.views.push(this.getDeleteIcon(rect));
}
const topBlock = new Pen(this.frontContext, this.block);
topBlock.paint();
},
isInView(x, y, rect) {
return x > rect.left && y > rect.top && x < rect.right && y < rect.bottom;
},
isInDelete(x, y) {
for (const view of this.block.views) {
if (view.id === 'delete') {
return x > view.rect.left && y > view.rect.top && x < view.rect.right && y < view.rect.bottom;
}
}
return false;
},
isInScale(x, y) {
for (const view of this.block.views) {
if (view.id === 'scale') {
return x > view.rect.left && y > view.rect.top && x < view.rect.right && y < view.rect.bottom;
}
}
return false;
},
touchedView: {},
findedIndex: -1,
onClick() {
const x = this.startX;
const y = this.startY;
const totalLayerCount = this.currentPalette.views.length;
let canBeTouched = [];
let isDelete = false;
let deleteIndex = -1;
for (let i = totalLayerCount - 1; i >= 0; i--) {
const view = this.currentPalette.views[i];
const { rect } = view;
if (this.touchedView && this.touchedView.id && this.touchedView.id === view.id && this.isInDelete(x, y, rect)) {
canBeTouched.length = 0;
deleteIndex = i;
isDelete = true;
break;
}
if (this.isInView(x, y, rect)) {
canBeTouched.push({
view,
index: i,
});
}
}
this.touchedView = {};
if (canBeTouched.length === 0) {
this.findedIndex = -1;
} else {
let i = 0;
const touchAble = canBeTouched.filter(item => Boolean(item.view.id));
if (touchAble.length === 0) {
this.findedIndex = canBeTouched[0].index;
} else {
for (i = 0; i < touchAble.length; i++) {
if (this.findedIndex === touchAble[i].index) {
i++;
break;
}
}
if (i === touchAble.length) {
i = 0;
}
this.touchedView = touchAble[i].view;
this.findedIndex = touchAble[i].index;
this.triggerEvent('viewClicked', {
view: this.touchedView,
});
}
}
if (this.findedIndex < 0 || (this.touchedView && !this.touchedView.id)) {
// 证明点击了背景 或无法移动的view
this.frontContext.draw();
if (isDelete) {
this.triggerEvent('touchEnd', {
view: this.currentPalette.views[deleteIndex],
index: deleteIndex,
type: 'delete',
});
this.doAction();
} else if (this.findedIndex < 0) {
this.triggerEvent('viewClicked', {});
}
this.findedIndex = -1;
this.prevFindedIndex = -1;
} else if (this.touchedView && this.touchedView.id) {
this.sliceLayers();
}
},
sliceLayers() {
const bottomLayers = this.currentPalette.views.slice(0, this.findedIndex);
const topLayers = this.currentPalette.views.slice(this.findedIndex + 1);
const bottomDraw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
background: this.currentPalette.background,
views: bottomLayers,
};
const topDraw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: topLayers,
};
if (this.prevFindedIndex < this.findedIndex) {
new Pen(this.bottomContext, bottomDraw).paint();
this.doAction();
new Pen(this.topContext, topDraw).paint();
} else {
new Pen(this.topContext, topDraw).paint();
this.doAction();
new Pen(this.bottomContext, bottomDraw).paint();
}
this.prevFindedIndex = this.findedIndex;
},
startX: 0,
startY: 0,
startH: 0,
startW: 0,
isScale: false,
startTimeStamp: 0,
onTouchStart(event) {
if (this.isDisabled) {
return;
}
const { x, y } = event.touches[0];
this.startX = x;
this.startY = y;
this.startTimeStamp = new Date().getTime();
if (this.touchedView && !this.isEmpty(this.touchedView)) {
const { rect } = this.touchedView;
if (this.isInScale(x, y, rect)) {
this.isScale = true;
this.startH = rect.bottom - rect.top;
this.startW = rect.right - rect.left;
} else {
this.isScale = false;
}
} else {
this.isScale = false;
}
},
onTouchEnd(e) {
if (this.isDisabled) {
return;
}
const current = new Date().getTime();
if (current - this.startTimeStamp <= 500 && !this.hasMove) {
!this.isScale && this.onClick(e);
} else if (this.touchedView && !this.isEmpty(this.touchedView)) {
this.triggerEvent('touchEnd', {
view: this.touchedView,
});
}
this.hasMove = false;
},
onTouchCancel(e) {
if (this.isDisabled) {
return;
}
this.onTouchEnd(e);
},
hasMove: false,
onTouchMove(event) {
if (this.isDisabled) {
return;
}
this.hasMove = true;
if (!this.touchedView || (this.touchedView && !this.touchedView.id)) {
return;
}
const { x, y } = event.touches[0];
const offsetX = x - this.startX;
const offsetY = y - this.startY;
const { rect, type } = this.touchedView;
let css = {};
if (this.isScale) {
clearPenCache(this.touchedView.id);
const newW = this.startW + offsetX > 1 ? this.startW + offsetX : 1;
if (this.touchedView.css && this.touchedView.css.minWidth) {
if (newW < this.touchedView.css.minWidth.toPx()) {
return;
}
}
if (this.touchedView.rect && this.touchedView.rect.minWidth) {
if (newW < this.touchedView.rect.minWidth) {
return;
}
}
const newH = this.startH + offsetY > 1 ? this.startH + offsetY : 1;
css = {
width: `${newW}px`,
};
if (type !== 'text') {
if (type === 'image') {
css.height = `${(newW * this.startH) / this.startW}px`;
} else {
css.height = `${newH}px`;
}
}
} else {
this.startX = x;
this.startY = y;
css = {
left: `${rect.x + offsetX}px`,
top: `${rect.y + offsetY}px`,
right: undefined,
bottom: undefined,
};
}
this.doAction(
{
view: {
css,
},
},
null,
!this.isScale,
);
},
initScreenK() {
if (!(getApp() && getApp().systemInfo && getApp().systemInfo.screenWidth)) {
try {
getApp().systemInfo = wx.getSystemInfoSync();
} catch (e) {
console.error(`Painter get system info failed, ${JSON.stringify(e)}`);
return;
}
}
this.screenK = 0.5;
if (getApp() && getApp().systemInfo && getApp().systemInfo.screenWidth) {
this.screenK = getApp().systemInfo.screenWidth / 750;
}
setStringPrototype(this.screenK, this.properties.scaleRatio);
},
initDancePalette() {
if (this.properties.use2D) {
return;
}
this.isDisabled = true;
this.initScreenK();
this.downloadImages(this.properties.dancePalette).then(async palette => {
this.currentPalette = palette;
const { width, height } = palette;
if (!width || !height) {
console.error(`You should set width and height correctly for painter, width: ${width}, height: ${height}`);
return;
}
this.setData({
painterStyle: `width:${width.toPx()}px;height:${height.toPx()}px;`,
});
this.frontContext || (this.frontContext = await this.getCanvasContext(this.properties.use2D, 'front'));
this.bottomContext || (this.bottomContext = await this.getCanvasContext(this.properties.use2D, 'bottom'));
this.topContext || (this.topContext = await this.getCanvasContext(this.properties.use2D, 'top'));
this.globalContext || (this.globalContext = await this.getCanvasContext(this.properties.use2D, 'k-canvas'));
new Pen(this.bottomContext, palette, this.properties.use2D).paint(() => {
this.isDisabled = false;
this.isDisabled = this.outterDisabled;
this.triggerEvent('didShow');
});
this.globalContext.draw();
this.frontContext.draw();
this.topContext.draw();
});
this.touchedView = {};
},
startPaint() {
this.initScreenK();
const { width, height } = this.properties.palette;
if (!width || !height) {
console.error(`You should set width and height correctly for painter, width: ${width}, height: ${height}`);
return;
}
let needScale = false;
// 生成图片时,根据设置的像素值重新绘制
if (width.toPx() !== this.canvasWidthInPx) {
this.canvasWidthInPx = width.toPx();
needScale = this.properties.use2D;
}
if (this.properties.widthPixels) {
setStringPrototype(this.screenK, this.properties.widthPixels / this.canvasWidthInPx);
this.canvasWidthInPx = this.properties.widthPixels;
}
if (this.canvasHeightInPx !== height.toPx()) {
this.canvasHeightInPx = height.toPx();
needScale = needScale || this.properties.use2D;
}
this.setData(
{
photoStyle: `width:${this.canvasWidthInPx}px;height:${this.canvasHeightInPx}px;`,
},
function () {
this.downloadImages(this.properties.palette).then(async palette => {
if (!this.photoContext) {
this.photoContext = await this.getCanvasContext(this.properties.use2D, 'photo');
}
if (needScale) {
const scale = getApp().systemInfo.pixelRatio;
this.photoContext.width = this.canvasWidthInPx * scale;
this.photoContext.height = this.canvasHeightInPx * scale;
this.photoContext.scale(scale, scale);
}
new Pen(this.photoContext, palette).paint(() => {
this.saveImgToLocal();
});
setStringPrototype(this.screenK, this.properties.scaleRatio);
});
},
);
},
downloadImages(palette) {
return new Promise((resolve, reject) => {
let preCount = 0;
let completeCount = 0;
const paletteCopy = JSON.parse(JSON.stringify(palette));
if (paletteCopy.background) {
preCount++;
downloader.download(paletteCopy.background, this.properties.LRU).then(
path => {
paletteCopy.background = path;
completeCount++;
if (preCount === completeCount) {
resolve(paletteCopy);
}
},
() => {
completeCount++;
if (preCount === completeCount) {
resolve(paletteCopy);
}
},
);
}
if (paletteCopy.views) {
for (const view of paletteCopy.views) {
if (view && view.type === 'image' && view.url) {
preCount++;
/* eslint-disable no-loop-func */
downloader.download(view.url, this.properties.LRU).then(
path => {
view.originUrl = view.url;
view.url = path;
wx.getImageInfo({
src: path,
success: res => {
// 获得一下图片信息,供后续裁减使用
view.sWidth = res.width;
view.sHeight = res.height;
},
fail: error => {
// 如果图片坏了,则直接置空,防止坑爹的 canvas 画崩溃了
console.warn(`getImageInfo ${view.originUrl} failed, ${JSON.stringify(error)}`);
view.url = '';
},
complete: () => {
completeCount++;
if (preCount === completeCount) {
resolve(paletteCopy);
}
},
});
},
() => {
completeCount++;
if (preCount === completeCount) {
resolve(paletteCopy);
}
},
);
}
}
}
if (preCount === 0) {
resolve(paletteCopy);
}
});
},
saveImgToLocal() {
const that = this;
const optionsOf2d = {
canvas: that.canvasNode,
}
const optionsOfOld = {
canvasId: 'photo',
destWidth: that.canvasWidthInPx,
destHeight: that.canvasHeightInPx,
}
setTimeout(() => {
wx.canvasToTempFilePath(
{
...(that.properties.use2D ? optionsOf2d : optionsOfOld),
success: function (res) {
that.getImageInfo(res.tempFilePath);
},
fail: function (error) {
console.error(`canvasToTempFilePath failed, ${JSON.stringify(error)}`);
that.triggerEvent('imgErr', {
error: error,
});
},
},
this,
);
}, 300);
},
getCanvasContext(use2D, id) {
const that = this;
return new Promise(resolve => {
if (use2D) {
const query = wx.createSelectorQuery().in(that);
const selectId = `#${id}`;
query
.select(selectId)
.fields({ node: true, size: true })
.exec(res => {
that.canvasNode = res[0].node;
const ctx = that.canvasNode.getContext('2d');
const wxCanvas = new WxCanvas('2d', ctx, id, true, that.canvasNode);
resolve(wxCanvas);
});
} else {
const temp = wx.createCanvasContext(id, that);
resolve(new WxCanvas('mina', temp, id, true));
}
});
},
getImageInfo(filePath) {
const that = this;
wx.getImageInfo({
src: filePath,
success: infoRes => {
if (that.paintCount > MAX_PAINT_COUNT) {
const error = `The result is always fault, even we tried ${MAX_PAINT_COUNT} times`;
console.error(error);
that.triggerEvent('imgErr', {
error: error,
});
return;
}
// 比例相符时才证明绘制成功,否则进行强制重绘制
if (
Math.abs(
(infoRes.width * that.canvasHeightInPx - that.canvasWidthInPx * infoRes.height) /
(infoRes.height * that.canvasHeightInPx),
) < 0.01
) {
that.triggerEvent('imgOK', {
path: filePath,
});
} else {
that.startPaint();
}
that.paintCount++;
},
fail: error => {
console.error(`getImageInfo failed, ${JSON.stringify(error)}`);
that.triggerEvent('imgErr', {
error: error,
});
},
});
},
},
});
function setStringPrototype(screenK, scale) {
/* eslint-disable no-extend-native */
/**
* string 到对应的 px
* @param {Number} baseSize 当设置了 % 号时,设置的基准值
*/
String.prototype.toPx = function toPx(_, baseSize) {
if (this === '0') {
return 0;
}
const REG = /-?[0-9]+(\.[0-9]+)?(rpx|px|%)/;
const parsePx = origin => {
const results = new RegExp(REG).exec(origin);
if (!origin || !results) {
console.error(`The size: ${origin} is illegal`);
return 0;
}
const unit = results[2];
const value = parseFloat(origin);
let res = 0;
if (unit === 'rpx') {
res = Math.round(value * (screenK || 0.5) * (scale || 1));
} else if (unit === 'px') {
res = Math.round(value * (scale || 1));
} else if (unit === '%') {
res = Math.round((value * baseSize) / 100);
}
return res;
};
const formula = /^calc\((.+)\)$/.exec(this);
if (formula && formula[1]) {
// 进行 calc 计算
const afterOne = formula[1].replace(/([^\s\(\+\-\*\/]+)\.(left|right|bottom|top|width|height)/g, word => {
const [id, attr] = word.split('.');
return penCache.viewRect[id][attr];
});
const afterTwo = afterOne.replace(new RegExp(REG, 'g'), parsePx);
return calc(afterTwo);
} else {
return parsePx(this);
}
};
}
项目中引用:
<view class="shopView">
<!-- 轮播 -->
<view class="swp">
<zswiper style="position: relative;" SwiperList="{{shopBase.slider_image_arr}}" current="{{current}}" bind:monitorCurrent="monitorCurrent"></zswiper>
<view class="shopHead">
<view><text>让利价:</text>¥{{shopBase.price}}</view>
<view>市场价: ¥{{shopBase.ot_price}}</view>
</view>
</view>
<!-- 介绍 -->
<view class="shopRemark">
<view class="shopTitle hiddenD">{{shopBase.title}}</view>
<view class="shopbag">{{shopBase.keyword}}</view>
<view class="shopyy">
<view class="shopRadioView">剩余{{shopBase.stock}}{{shopBase.unit_name}} | 月销量{{shopBase.ficti }}{{shopBase.unit_name}}</view>
</view>
<view class="shopyys">
<view class="colView">
<image src="../../images/all/hd.png" mode="" /> <text>品质保障</text>
</view>
<view class="colView">
<image src="../../images/all/twy.png" mode="" /> <text>退换无忧</text>
</view>
<view class="colView">
<image src="../../images/all/che.png" mode="" /> <text>直采直销</text>
</view>
</view>
</view>
<!-- 优惠券 -->
<!-- 优惠券-->
<view wx:if="{{couponList.money}}">
<view class="yhq animated heartBeats delay-5s" bindtap="getSelected" data-id="{{couponList.id}}">
<image src="../../images/all/yhq.png" wx:if="{{couponList.status==0}}" mode=""/>
<image src="../../images/all/yyq.png" wx:else mode=""/>
<view class="copunBox">
<view>{{couponList.money}}元{{couponList.name}}</view>
<view>部分商品通用</view>
</view>
</view></view>
<!-- end -->
<!-- <view class="chListBox" wx:if="{{couponList.length>0}}" style="margin-bottom: 20rpx;" bindtap="onClose">
<view class="cliflex">
<label>优惠</label>
<view class="cpubox">
<view>满100减10</view>
<view class="bgap"></view>
<view>领券</view>
</view>
</view>
<view class="flexicon">
去使用
<image src="../../images/all/right.png" mode=""/>
</view>
</view> -->
<!-- 尺寸 -->
<!-- <view class="chList" style="margin-bottom: 20rpx;">
<label>包装尺寸</label>
<text>100cm × 120cm × 60cm</text>
</view> -->
<view class="chList" style=" border-bottom-left-radius: 0;border-bottom-right-radius: 0;">
<label>规格</label>
<text>默认规格</text>
</view>
<view class="border"></view>
<view class="chLists">
<label>数量</label>
<text>(当前剩余{{shopBase.stock }}件)</text>
<view class="stepper">
<van-stepper value="{{shopNum}}" bind:change="getShopNum" disable-input integer />
</view>
</view>
<view class="chList" style="border-bottom-left-radius: 0;border-bottom-right-radius: 0;">
<label>配送</label>
<text>商家配送</text>
</view>
<view class="border"></view>
<view class="chList" style="margin-bottom: 20rpx;">
<label>服务</label>
<text> 支持7天无理由退货</text>
</view>
<!-- 详情 -->
<view class="shopBaseView">
<view class="headT">
<view class="text" style="font-weight: 600;">商品详情</view>
<view class="druk"></view>
</view>
<richtext rich_content="{{shopBase.newHtml}}" />
</view>
<!-- 评价 -->
<!-- <view class="shopBaseView">
<view class="headT">
<view class="text" style="font-weight: 600;">商品</view>
<view class="druk"></view>
</view>
</view> -->
<!-- 操作 -->
<view class="submitView">
<view class="iconviewtexts" bindtap="goHome">
<button plain="true" class="iconviewtexts">
<image src="../../images/all/sy.png" class="icons"></image>
<text lines="1" class="texty">首页</text>
</button>
</view>
<view>
<view class="iconviewtexts" bindtap="initCollect" style="margin-left: 0rpx;" data-item="{{shopBase}}" wx:if="{{collectStatus==0}}" data-type="{{1}}">
<image src="../../images/all/ai.png" class="icons"></image>
<text lines="1" class="texty">收藏</text>
</view>
<view class="iconviewtexts" bindtap="initCollect" style="margin-left: 0rpx;" data-type="{{0}}" data-item="{{shopBase}}" wx:else>
<image src="../../images/all/xss.png" class="icons animated rubberBand"></image>
<text lines="1" class="texty">已收藏</text>
</view>
</view>
<view>
<view class="iconviewtexts" style="margin-left: 0;">
<button plain="true" open-type="contact" class="iconviewtexts">
<image src="../../images/all/tes.png" class="icons"></image>
<text lines="1" class="texty">客服</text>
</button>
</view>
</view>
<view class="aleview">
<view bindtap="getshare" class="rViewBtn">分享得{{shopBase.rebate_money}}元
<view class="bubble animated animate__rubberBand">本商品每分享成功一次可得{{shopBase.rebate_money}}元</view>
</view>
<!-- <button plain="true" class="rViewBtn" open-type="share">分享得9元</button> -->
<view class="rSelBtn" bindtap="getPayOrder" data-shopBase="{{shopBase}}">立即购买</view>
</view>
</view>
<!-- end -->
</view>
<!-- 海报 -->
<van-overlay show="{{ show }}" z-index="999" bind:click="onClickHide">
<view class="wrapper">
<view style="height: 72rpx;"></view>
<!-- poster -->
<view class="block" catch:tap="noop">
<view class="closeView" bindtap="getClose">
<image src="../../images/all/cha.png" mode="" />
</view>
<view style="height: 30rpx;"></view>
<view style='position: relative;'>
<view class="top">
<!-- <button bind:tap='onRevert'>撤销</button>
<button bind:tap='onRecover'>恢复</button> -->
<!-- <button bind:tap='saveImage'>保存</button> -->
</view>
<painter customActionStyle="{{customActionStyle}}" palette="{{paintPallette}}" bind:imgOK="onImgOK" wx:if="{{show}}" action="{{action}}" widthPixels="580" />
<image wx:if="{{show}}" src="{{image}}" style="width: 640rpx; height:928rpx;" />
</view>
<image class="logo" src="../../images/all/logo.png" mode="" />
</view>
<!-- end -->
<!-- 底部弹窗 -->
<view class="bottomView">
<view class="headBoxs">
<text>
分享给好友,好友注册并下单后您可得{{shopBase.rebate_money}}元
</text>
</view>
<view class="fwidth">
<van-row gutter="20">
<van-col class="colConter iconshars" span="12">
<button open-type='share' plain="true">
<image class="shareicons" src="../../images/all/s1.png" mode="" />
</button>
</van-col>
<!-- <van-col class="colConter iconshars" span="8">
<button open-type='share' plain="true">
<image class="shareicons" src="../../images/all/s2.png" mode="" />
</button>
</van-col> -->
<van-col class="colConter" span="12" bind:tap='saveImage'>
<image class="shareicons" src="../../images/all/s3.png" mode="" />
</van-col>
</van-row>
</view>
<view class="fwidth">
<van-row gutter="20">
<van-col class="colConter" span="12">
<button open-type='share' plain="true">微信好友</button>
</van-col>
<!-- <van-col class="colConter" span="8" bindtap="shopShare"> <button open-type='share' plain="true">朋友圈</button></van-col> -->
<van-col class="colConter" span="12" bind:tap='saveImage'>保存图片</van-col>
</van-row>
</view>
</view>
<!-- end -->
</view>
</van-overlay>
<!-- 优惠券 -->
<!-- 自定义图标 -->
<van-popup show="{{ modelSHow }}" closeable round z-index="999" position="bottom" custom-style="height: 50%; background-color:#f5f5f5 ;" bind:close="onClose">
<view class="headBox" bindtap="onClose">
选择优惠券
</view>
<scroll-view class="couBox" scroll-y="true" bindscrolltoupper="upper" bindscrolltolower="lower" bindscroll="scroll" scroll-into-view="{{toView}}" scroll-top="{{scrollTop}}">
<sCouList List="{{couponList}}" bind:getSelected="getSelected"></sCouList>
</scroll-view>
<view class="btnBox">
<view class="btnview" bindtap="onClose">
确定
</view>
</view>
</van-popup>
import {
request
} from '../../utils/request'
Page({
imagePath: '',
history: [],
future: [],
isSave: false,
/**
* 页面的初始数据
*/
data: {
drawing: [],
show: false,
modelSHow: false,
savebtnText: '点击按钮,保存图片',
//轮播图的数组
shopBase: {},
shopNum: 1,
shopid: 0,
coupon_id:0,
couponList: {},
collectStatus: 0,
// 海报生成
paintPallette: {
width: '640rpx',
height: '928rpx',
background: '#f5f5f5',
left: 0,
views: [{
type: 'rect',
css: {
width: '580rpx',
left: '30rpx',
top: '30rpx',
height: '766rpx',
color: "#fff",
},
},
{
type: 'image',
url: 'https://shop.rlmeijia.com/statics/uploads/recommendimg/recommendimg20221111141855.jpg',
css: {
top: '30rpx',
left: '30rpx',
width: '580rpx',
height: '580rpx',
},
},
{
type: 'text',
text: '【现货】民福康 天然维生素E软胶囊 100粒装',
css: {
top: '638rpx',
left: '58rpx',
width: "376rpx",
lineHeight: "44rpx",
color: '#333333',
fontSize: "28rpx",
},
},
{
type: 'text',
text: '¥194.00',
css: {
top: '730rpx',
left: '58rpx',
color: '#E1A765',
fontSize: "32rpx",
},
},
{
type: 'qrcode',
content: 'https://github.com/Kujiale-Mobile/Painter',
css: {
top: '638rpx',
right: '62rpx',
width: '96rpx',
height: '96rpx',
},
},
{
type: 'text',
text: '扫码购买',
css: {
top: '750rpx',
right: '66rpx',
color: '#333',
fontSize: "22rpx",
},
},
{
type: 'image',
url: '../../images/all/logo.png',
css: {
top: '818rpx',
left: '212rpx',
width: '222rpx',
height: '72rpx',
},
},
],
},
customActionStyle: {
border: {
borderColor: '#1A7AF8',
},
scale: {
textIcon: '/palette/switch.png',
imageIcon: '/palette/scale.png',
},
delete: {
icon: '/palette/close.png',
},
},
},
goHome() {
wx.redirectTo({
url: '/pages/index/index',
})
},
getShopNum(e){
console.error(e);
this.setData({
shopNum:e.detail
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline'],
success(res){
},fail(error){}
})
if (options) {
this.initData(options.id)
this.setData({
shopid: options.id
})
this.initCouponList(options.id)
this.getcollect(options.id)
if (options.chnnel) {
console.error("分享进入==>", options);
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
request("/login/getoauthtoken", 'post', {
"authcode": res.code
}).then(res => {
if (res.code == 200) {
console.error("粉丝添加获取传参==>", "商品id" + options.id, "老用户" + options.openid, "新用户" + res.openid);
request("/login/addfriend", 'post', {
pid: options.id,
openid: options.openid,
form_openid: res.openid,
sitepage: 2
}).then(res => {
if (res.code == 0) {
} else {
}
}).catch(err => {
console.log(err);
})
} else {
// wx.setStorageSync('openid', 1352168512)
}
}).catch(err => {
console.log(err);
})
}
})
}
}
},
/**
* 获取优惠券列表
* @param {*} options
*/
initCouponList(id) {
var openid = wx.getStorageSync('openid')
request("/coupon/proccoupon", 'post', {
openid: openid,
pid: id
}).then(res => {
if (res.code == 0) {
this.setData({
couponList: res.data
})
} else {
}
}).catch(err => {
console.log(err);
})
},
/**
* 初始化数据
*/
initData(id) {
var that = this;
request("/product/details/", 'post', {
pid: id,
}).then(res => {
if (res.code == 0) {
res.detailsRow.newHtml = res.detailsRow.detailed.replace(/(<img\s+.*?style=")(.*?)(".*?>)/g, function (match, p1, p2, p3) {
var newStyle = 'width:100%;height:100%;';
return p1 + newStyle + p3;
});
if (res.detailsRow.recommend_image != '') {
console.error("判断是否有商品图片生成==>",res.detailsRow);
var openid=wx.getStorageSync('openid')
request("/login/createwxaqrcode", 'post', {
path: "pages/shopBase/index?chnnel=1&id=" + this.data.shopid + "&openid=" + openid,
}).then(data => {
console.error("生成二维码==>",data);
if (data.code == 0) {
console.error("成功生成==>",data);
that.setData({
shopBase: res.detailsRow,
paintPallette: {
width: '640rpx',
height: '928rpx',
background: '#f5f5f5',
left: 0,
views: [{
type: 'rect',
css: {
width: '580rpx',
left: '30rpx',
top: '30rpx',
height: '766rpx',
color: "#fff",
},
},
{
type: 'image',
url: res.detailsRow.recommend_image,
css: {
top: '30rpx',
left: '30rpx',
width: '580rpx',
height: '580rpx',
},
},
{
type: 'text',
text: res.detailsRow.title,
css: {
top: '648rpx',
left: '58rpx',
width: "376rpx",
maxLines: 2,
lineHeight: "40rpx",
color: '#333333',
fontSize: "27rpx",
},
},
{
type: 'text',
text: '¥' + res.detailsRow.price,
css: {
top: '730rpx',
left: '58rpx',
color: '#E1A765',
fontSize: "32rpx",
},
},
{
type: 'image',
url: data.wxaqrcodepath,
css: {
top: '638rpx',
right: '62rpx',
width: '100rpx',
height: '100rpx',
},
},
// {
// type: 'qrcode',
// content: data.wxaqrcodepath,
// css: {
// top: '638rpx',
// right: '62rpx',
// width: '96rpx',
// height: '96rpx',
// },
// },
{
type: 'text',
text: '扫码购买',
css: {
top: '750rpx',
right: '66rpx',
color: '#333',
fontSize: "22rpx",
},
},
{
type: 'image',
url: '../../images/all/logo.png',
css: {
top: '818rpx',
left: '212rpx',
width: '222rpx',
height: '72rpx',
},
},
],
}
})
} else {
}
}).catch(err => {
console.log(err);
})
}
} else {
}
}).catch(err => {
console.log(err);
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 商品是否收藏
*/
getcollect(id) {
var openid = wx.getStorageSync('openid')
request("/collect/getcollect", 'post', {
openid: openid,
cid: id
}).then(res => {
this.setData({
collectStatus: res.code
})
}).catch(err => {
console.log(err);
})
},
getSelected(e) {
var openid=wx.getStorageSync('openid')
request("/coupon/receivecoupon", 'post', {
openid:openid,
coupon_id:parseInt(e.currentTarget.dataset.id),
}).then(res => {
if (res.code == 0) {
wx.showToast({
title: '领取成功',
icon:"none"
})
} else {
wx.showToast({
title:res.msg,
icon:"none"
})
}
}).catch(err => {
console.log(err);
})
// for (var i in this.data.couponList) {
// if (e.detail.item.coupon_id == this.data.couponList[i].coupon_id) {
// this.data.couponList[i].stats = 1;
// var openid=wx.getStorageSync('openid')
// request("/coupon/receivecoupon", 'post', {
// openid:openid,
// coupon_id:this.data.couponList[i].coupon_id,
// }).then(res => {
// if (res.code == 0) {
// wx.showToast({
// title: '领取成功',
// icon:"none"
// })
// } else {
// }
// }).catch(err => {
// console.log(err);
// })
// this.setData({
// coupon_id: this.data.couponList[i].coupon_id
// })
// } else {
// this.data.couponList[i].stats = 0;
// }
// }
// this.setData({
// couponList: this.data.couponList
// })
},
/**
* 收藏
*/
initCollect(data, type) {
var type = data.currentTarget.dataset.type;
var item = data.currentTarget.dataset.item;
var openid = wx.getStorageSync('openid')
console.error("type", type);
if (type == 1) {
request("/collect/collect", 'post', {
openid: openid,
cid: item.id,
type: 2,
stats: type,
}).then(res => {
if (res.code == 0) {
wx.showToast({
title: '收藏成功',
icon: "none",
})
this.setData({
collectStatus: 1
})
}
}).catch(err => {
console.log(err);
})
} else {
request("/collect/getcollect", 'post', {
openid: openid,
cid: item.id
}).then(res => {
console.error("“删除", res);
if (res.code == 1) {
wx.showToast({
title: '取消收藏',
icon: "none",
})
this.setData({
collectStatus: 0
})
}
}).catch(err => {
console.log(err);
})
}
return;
},
getClose() {
this.setData({
show: false
})
},
onClose() {
this.data.modelSHow = !this.data.modelSHow
this.setData({
modelSHow: this.data.modelSHow
})
},
shopShare() {
wx.shopShareMenu()
},
getshare() {
var that = this;
setTimeout(() => {
if (this.data.shopBase.recommend_image != '') {
that.setData({
show: true,
})
} else {
wx.showToast({
title: '生成失败,请重新尝试',
})
}
}, 800);
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
getPayOrder(data) {
var item = data.currentTarget.dataset.shopbase;
var shopNum = this.data.shopNum;
var arrbase = {};
arrbase.id = item.id;
arrbase.coupon_id=this.data.coupon_id;
arrbase.shopNum = shopNum;
arrbase.recommend_image = item.recommend_image;
arrbase.title = item.title;
arrbase.price = item.price;
wx.setStorageSync('shopBase', arrbase)
console.error(arrbase);
wx.navigateTo({
url: '/pages/nextOrder/index',
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
this.setData({
show: false
})
var openid = wx.getStorageSync('openid')
return {
title: this.data.shopBase.title,
path: '/pages/shopBase/index?chnnel=1&id=' + this.data.shopid + "&openid=" + openid,
}
},
onShareTimeline(){
this.setData({
show:false
})
var openid = wx.getStorageSync('openid')
return {
title: this.data.shopBase.title,
path: '/pages/shopBase/index?chnnel=1&id=' + this.data.shopid + "&openid=" + openid,
imageUrl: "/images/share_3.png"
}
},
// 海报生成
onImgOK(e) {
this.imagePath = e.detail.path;
this.setData({
image: this.imagePath,
});
if (this.isSave) {
this.saveImage(this.imagePath);
}
},
saveImage() {
var that=this;
wx.showToast({
title: '正在生成中,请稍后',
icon:"none",
duration:1500
})
var openid=wx.getStorageSync('openid')
if (this.imagePath && typeof this.imagePath === 'string') {
this.isSave = false;
wx.getFileSystemManager().readFile({ // 读取本地文件内容
filePath:this.imagePath,
encoding: 'base64', //编码格式
success(res) {
request("/login/dowfile", 'post', {
"fileUrl": res.data,
openid:openid
}, 3).then(gbase => {
console.error("https",gbase);
var timestamp = Date.parse(new Date());
timestamp = timestamp / 1000;
console.error("传参",gbase.picUrl+"?timestamp="+timestamp);
wx.downloadFile({
url:gbase.picUrl+"?timestamp="+timestamp,
success: res => {
console.error("down-success保存到相册权限", res);
//保存到相册
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: res => {
console.info("saveImageToPhotosAlbum-success===>", res);
that.setData({
show: false,
// successShow: true
})
wx.showToast({
title: '已保存到系统相册',
icon:'none'
})
},
fail: function (err) {
console.info("saveImageToPhotosAlbum-fail===>", err);
wx.showModal({
title: '提示',
content: '需要您授权保存相册',
modalType: false,
success: modalSuccess => {
wx.openSetting({
success(settingdata) {
console.log("settingdata", settingdata)
if (settingdata.authSetting['scope.writePhotosAlbum']) {
wx.showModal({
title: '提示',
content: '获取权限成功,再次点击图片即可保存',
modalType: false,
})
} else {
wx.showModal({
title: '提示',
content: '获取权限失败,将无法保存到相册哦~',
modalType: false,
})
}
},
fail(failData) {
console.log("failData", failData)
},
complete(finishData) {
console.log("finishData", finishData)
}
})
}
})
},complete(res) {
that.setData({
show:false
})
}
})
},
fail: error => {
console.error("downloadFile-fail失败2", error);
wx.showToast({
title: '保存失败,请稍后再试~',
icon:'none'
})
that.setData({
show: false,
})
},
});
}).catch(err => {
console.log(err);
})
}
})
return;
this.isSave = false;
wx.saveImageToPhotosAlbum({
filePath: this.imagePath,
});
console.error("保存",this.imagePath);
this.setData({
show: false
})
}
},
})
page {
background: #F5F5F5;
padding-bottom: 150rpx;
}
.shopRemark {
width: 100%;
margin: 0 auto;
padding-bottom: 35rpx;
background: #fff;
border-bottom-left-radius: 20rpx;
border-bottom-right-radius: 20rpx;
/* margin-bottom: 20rpx; */
}
.abs{
position: relative;
left: 30rpx;
}
richtext img{
width: 100!important;
}
.iconviewtexts button[plain]{
border: 0;
border-radius: 0;
position: relative;
right: 15rpx;
}
.aleview button[plain]{
border: 0;
border-radius: 0;
width: 208rpx;
height: 98rpx;
text-align: center;
line-height: 98rpx;
font-size: 28rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #FFDB9E;
background: linear-gradient(90deg, #505050 0%, #515151 100%);
}
.border {
width: 666rpx;
border-bottom: 1rpx solid #E4E4E4;
margin: 0 auto;
}
.shopTitle {
width: 686rpx;
margin: 0 auto;
font-size: 32rpx;
padding-top: 20rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #333333;
}
.shopbag {
width: 686rpx;
margin: 0 auto;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
}
.shopyy {
width: 686rpx;
margin: 0 auto;
margin-top: 16rpx;
}
.shopRadioView {
width: 344rpx;
display: flex;
align-items: center;
justify-content: center;
height: 52rpx;
padding: 0rpx 20rpx;
background: #FFF3F3;
font-size: 26rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #E1A765;
border-radius: 28rpx;
}
.colView image {
width: 24rpx;
height: 24rpx;
margin-right: 10rpx;
}
.shopyys {
width: 686rpx;
margin: 0 auto;
margin-top: 16rpx;
display: flex;
align-items: center;
}
.colView {
font-size: 24rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
display: flex;
align-items: center;
color: #B38953;
}
.colView:nth-child(2) {
margin-left: 80rpx;
}
.colView:nth-child(3) {
margin-left: 80rpx;
}
.chList {
width: 100%;
height: 108rpx;
margin: 0 auto;
line-height: 108rpx;
background: #FFFFFF;
border-radius: 20rpx;
}
.chListBox{
width: 100%;
height: 108rpx;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
line-height: 108rpx;
background: #FFFFFF;
border-radius: 20rpx;
}
.chListBox image{
width: 16rpx;
height: 32rpx;
margin-right: 32rpx;
}
.chListBox label {
margin-left: 20rpx;
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
}
.flexicon{
display: flex;
align-items: center;font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
}
.cpubox view:nth-child(1){
margin-left: 12rpx;
}
.cpubox view:nth-child(2){
width: 2rpx;
height: 34rpx;
border-right: 1rpx dotted #E1A765;
}
.cpubox view:nth-child(3){
margin-right: 12rpx;
}
.cpubox{
width: 228rpx;
height: 52rpx;
line-height: 52rpx;
position: relative;
margin-left: 86rpx;
text-align: center;
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 10rpx;
font-size: 26rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #E1A765;
background: #FFF3F3;
}
.cliflex{
display: flex;
align-items: center;
}
.flexicon image{
margin-left: 12rpx;
}
.chList label {
margin-left: 32rpx;
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
}
.bu{
width: 31rpx;
height: 30rpx;
background: #E1A765;
}
.chList text {
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #999999;
margin-left: 30rpx;
}.chListBox text {
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #999999;
margin-left: 30rpx;
}
.chLists {
width: 100%;
margin: 0 auto;
height: 136rpx;
border-bottom-right-radius: 20rpx;
display: flex;
border-bottom-left-radius: 20rpx;
background-color: #fff;
align-items: center;
line-height: 136rpx;
position: relative;
margin-bottom: 20rpx;
}
.chLists label {
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
margin-left: 32rpx;
margin-right: 4rpx;
}
.chLists text {
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
}
.stepper {
position: absolute;
right: 38rpx;
}
.shopBaseView {
width: 100%;
margin: 0 auto;
background-color: #fff;
border-radius: 20rpx;
padding-bottom: 30rpx;
}
.headT .text {
padding-top: 30rpx;
margin-left: 32rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
height: 44rpx;
color: #333333;
}
.druk {
width: 32rpx;
height: 8rpx;
position: relative;
top: 5rpx;
left: 65rpx;
border: 5rpx solid #E1A765;
border-radius: 0 0 50% 50%/0 0 100% 100%;
border-top: none;
margin-bottom: 36rpx;
}
.shopBaseView image {
margin: 0 auto;
display: flex;
justify-content: center;
}
.submitView {
width: 100%;
height: 98rpx;
display: flex;
align-items: center;
background: #FFFFFF;
position: fixed;
justify-content: space-between;
bottom: 0;
z-index: 999;
}
.iconviewtexts {
display: flex;
width: 80rpx;
text-align: center;
align-items: center;
/* background-color: red; */
flex-direction: column;
align-items: center;
margin-left: 10rpx;
}
.shopHead view:nth-child(1){
font-size: 48rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #E1A765;
display: flex;
align-items: center;
margin-left: 32rpx;
margin-bottom: 10rpx;
}
.shopHead view:nth-child(1) text{
font-size: 30rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #E1A765;
}
.shopHead view:nth-child(2){
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;margin-left: 32rpx;
color: #999999;
text-decoration: line-through;
}
.swp{
position: relative;
}
.shopHead{
padding-top: 20rpx;
width: 100%;
margin: 0 auto;
background: #fff;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
position: absolute;
z-index: 8;
bottom: 0rpx;
text-align: left;
transform: translate(-50%);
left: 50%;
}
.texty {
overflow-wrap: break-word;
color: rgba(51,51,51,1);
font-size: 22rpx;
font-family: PingFangSC-Regular;
font-weight: normal;
text-align: right;
white-space: nowrap;
line-height: 20rpx;
margin-top: 16rpx;
}
.icons {
width: 36rpx;
height: 32rpx;
align-self: center;
}
.aleview {
display: flex;
}
.rViewBtn {
width: 208rpx;
height: 98rpx;
position: relative;
text-align: center;
line-height: 98rpx;
font-size: 28rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #FFDB9E;
background: linear-gradient(90deg, #505050 0%, #515151 100%);
}
.rSelBtn {
width: 250rpx;
font-size: 28rpx;
text-align: center;
line-height: 98rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #8A511A;
height: 98rpx;
background: linear-gradient(90deg, #E6C58E 0%, #E1A664 100%);
}
/* 海报 */
/* 点击分享弹窗 */
.wrapper {
width: 100%;
height: 2024rpx!important;
overflow: auto;
}
.closeView{
width: 48rpx;
position: absolute;
height: 48rpx;
top: -25rpx;
right: -25rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
z-index: 9;
background: rgba(0,0,0,0.5);
}
.overlays{
width: 750rpx;
height: 1624rpx!important;
background: rgba(0,0,0,0.6);
overflow: auto!important;
}
.closeView image{
width: 30rpx;
height: 30rpx;
}
.block {
width: 640rpx;
position: relative;
height: 928rpx;
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
background: #EEEEEE;
}
.canvas-style{
width: 580rpx !important;
height: 766rpx !important;
margin: 0 auto;
}
.savebtn-style{
position: relative;
top:220rpx!important;
width: 130rpx!important;
height: 162rpx!important;
right: -265rpx!important;
z-index: 999;
/* opacity: 0; */
/* display: none; */
}
.logo{
display: flex;
align-items: center;
margin: 0 auto;
width: 222rpx;
height: 72rpx;
margin-top: 22rpx;
}
.bottomView{
width: 100%;
/* height: 376rpx; */
background: #FFFFFF;
position: fixed;
bottom: 0;
margin-top: 30rpx;
padding-bottom: 50rpx;
border: 2rpx solid #FFFFFF;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
}
.headBoxs{
width: 100%;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
height: 110rpx;
/* position: fixed;
top: 0;
z-index: 2; */
text-align: center;
background: linear-gradient(180deg, rgba(230,142,142,0.83) 0%, rgba(225,166,100,0) 100%);
}
.headBoxs text{
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #8A511A;
}
.colConter{
text-align: center;
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
margin-top: 14rpx;
}
.shareicons{
width: 100rpx;
height: 100rpx;
}
.colConter button[plain]{
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
height: 40rpx;
line-height: 40rpx;
}
.iconshars button[plain]{
width: 100rpx;
height: 100rpx;
padding: 0;
margin: 0 auto;
}
/* 气泡 */
.bubble:before{
position: absolute;
top: 73rpx;
left: 35%;
content: '';
border: 15rpx solid transparent;
border-top-color: #302417;
opacity: 0.9;
}
.bubble{
position: absolute;
width: 392rpx;
height: 73rpx;
top: -95rpx;
left: -50rpx;
text-align: center;
line-height: 73rpx;
font-size: 24rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #FFDB9E;
background: rgba(0,0,0,0.72);
border-radius: 30rpx;
box-shadow: 0rpx 4rpx 8rpx 0rpx rgba(0,0,0,0.9);
/* background-color: rgba(#302417,#302417,#302417, 0.8); */
/* background-color: rgb(#302417, #302417, #302417,0.5); */
/* border: 2rpx solid #302417; */
}
/* 优惠券 */
.headBox{
width: 100%;
text-align: center;
display: flex;font-size: 36rpx;
font-family: PingFang-SC-Bold, PingFang-SC;
font-weight: bold;
color: #333333;
position: relative;
align-items: center;
height: 110rpx;
justify-content: center;
line-height: 110rpx;
background: linear-gradient(180deg, rgba(230,142,142,0.83) 0%, rgba(225,166,100,0) 100%);
}
.headBox image{
width: 40rpx;
height: 40rpx;
}
.couBox{
width: 100%;
height: 320rpx;
overflow: hidden;
}
.btnBox{
width: 100%;
position: fixed;
bottom: 0;
height: 148rpx;
justify-content: center;
display: flex;
align-items: center;
background: #FFFFFF;
}
.btnview{
width: 686rpx;
height: 84rpx;font-size: 32rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #8A511A;
line-height: 84rpx;
text-align: center;
background: linear-gradient(90deg, #E6C58E 0%, #E1A664 100%);
box-shadow: 0rpx 4rpx 8rpx 0rpx rgba(255,59,60,0.25);
border-radius: 42rpx;
}
/* */
.yhq{
width: 702rpx;
height: 218rpx;
display: flex;
align-items: center;
margin: 0 auto; position: relative;
}
.yhq image{
position: relative;
width: 702rpx;
height: 218rpx;
display: flex;
align-items: center;
margin: 0 auto;
}
.copunBox{
position: absolute;
z-index: 2;
top: 60rpx;
margin-left: 58rpx;
}
.copunBox view:nth-child(1){
font-size: 40rpx;
font-family: PingFang-SC-Heavy, PingFang-SC;
font-weight: 800;
color: #EE5514;
}
.copunBox view:nth-child(2){
font-size: 22rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #EE5514;
}
.fwidth{
width: 80%;
margin: 0 auto;
}