Commit d83864e6 by wangcx1997

提交台粮道

parent 1f58acec
unpackage
<script>
import Vue from 'vue'
import {
getInvitaCode
} from '@/config/api.js'
export default {
onLaunch: function() {
console.log('App Launch')
const IMG_BASE_URL = "https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/"
getInvitaCode('', {
suc: (res) => {
Vue.prototype.invateCode = res.data.code
}
})
uni.getSystemInfo({
success: function(e) {
//屏幕高度
Vue.prototype.ScreenHeight = uni.getSystemInfoSync().screenHeight;
// #ifndef MP
Vue.prototype.StatusBar = e.statusBarHeight;
if (e.platform == 'android') {
Vue.prototype.CustomBar = e.statusBarHeight + 50;
} else {
Vue.prototype.CustomBar = e.statusBarHeight + 45;
};
// #endif
// #ifdef MP-WEIXIN
Vue.prototype.StatusBar = e.statusBarHeight;
let custom = wx.getMenuButtonBoundingClientRect();
Vue.prototype.Custom = custom;
Vue.prototype.CustomBar = custom.bottom + custom.top - e.statusBarHeight;
// #endif
// #ifdef MP-ALIPAY
Vue.prototype.StatusBar = e.statusBarHeight;
Vue.prototype.CustomBar = e.statusBarHeight + e.titleBarHeight;
// #endif
}
})
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
body {
background-color: #f1f1f1;
}
view {
box-sizing: border-box;
}
.status_bar {
height: var(--status-bar-height);
width: 100%;
}
/*单行*/
.singline {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;/*要显示的行数*/
overflow: hidden;
}
/*选项卡 插件v-tab 主要设置它的位置top*/
.tabs {
position: fixed;
/* #ifdef H5 */
top: 44px;
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
left: 0;
display: flex;
align-items: center;
width: 100%;
height: 100rpx;
box-sizing: border-box;
background-color: #fff;
box-shadow: 0px 0px 10rpx rgba(0, 0, 0, 0.1);
border-radius: 0px 0px 10rpx 10rpx;
z-index: 3;
}
.container-tabs__list {
height: 100%;
}
.container-tabs__swiper {
height: 100%;
}
/*分页*/
.loading-more {
align-items: center;
justify-content: center;
padding-top: 10px;
padding-bottom: 10px;
text-align: center;
}
.loading-more-text {
font-size: 28rpx;
color: #999;
}
</style>
<style lang="less">
/*每个页面公共css */
@import url("./static/style/cx-style.less");
/*自定义状态栏高度*/
.status-bar {
height: var(--status-bar-height);
width: 100%;
background-color: white;
}
/* https://www.jianshu.com/p/93d7104be420 、
去除自带的边框
*/
button {
background-color: white;
}
button::after {
border: none;
border-radius: 0;
}
button.theme {
width: calc(100% - 70rpx);
margin: 50rpx 35rpx 0 35rpx;
height: 88rpx;
line-height: 88rpx;
color: white;
font-size: 30rpx;
background-color: #21D183;
border-radius: 88rpx;
}
button.theme[disabled] {
color: white;
background-color: #DCDCDC;
}
uni-button.theme::after {
border: none;
}
</style>
\ No newline at end of file
export function adaptor(ctx) {
return Object.assign(ctx, {
setStrokeStyle(val) {
ctx.strokeStyle = val;
},
setLineWidth(val) {
ctx.lineWidth = val;
},
setLineCap(val) {
ctx.lineCap = val;
},
setFillStyle(val) {
ctx.fillStyle = val;
},
setFontSize(val) {
ctx.font = String(val);
},
setGlobalAlpha(val) {
ctx.globalAlpha = val;
},
setLineJoin(val) {
ctx.lineJoin = val;
},
setTextAlign(val) {
ctx.textAlign = val;
},
setMiterLimit(val) {
ctx.miterLimit = val;
},
setShadow(offsetX, offsetY, blur, color) {
ctx.shadowOffsetX = offsetX;
ctx.shadowOffsetY = offsetY;
ctx.shadowBlur = blur;
ctx.shadowColor = color;
},
setTextBaseline(val) {
ctx.textBaseline = val;
},
createCircularGradient() {},
draw() {},
});
}
import { toPx, CHAR_WIDTH_SCALE_MAP, isNumber, getImageInfo } from './utils'
import { GD } from './gradient'
import QR from './qrcode'
let id = 0
export class Draw {
constructor(context, canvas, use2dCanvas = false, isH5PathToBase64 = false, boundary) {
this.ctx = context
this.canvas = canvas || null
this.root = boundary
this.use2dCanvas = use2dCanvas
this.isH5PathToBase64 = isH5PathToBase64
}
roundRect(x, y, w, h, r, fill = false, stroke = false, ) {
if (r < 0) return
const {ctx} = this
ctx.beginPath()
if(!r) {
ctx.rect(x, y, w, h)
} else if(typeof r === 'number' && [0,1,-1].includes(w - r * 2) && [0, 1, -1].includes(h - r * 2)) {
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 2)
} else {
let {
borderTopLeftRadius: tl = r || 0,
borderTopRightRadius: tr = r || 0,
borderBottomRightRadius: br = r || 0,
borderBottomLeftRadius: bl = r || 0
} = r || {r,r,r,r}
ctx.beginPath()
// 右下角
ctx.arc(x + w - br, y + h - br, br, 0, Math.PI * 0.5)
ctx.lineTo(x + bl, y + h)
// 左下角
ctx.arc(x + bl, y + h - bl, bl, Math.PI * 0.5, Math.PI)
ctx.lineTo(x, y + tl)
// 左上角
ctx.arc(x + tl, y + tl, tl, Math.PI, Math.PI * 1.5)
ctx.lineTo(x + w - tr, y)
// 右上角
ctx.arc(x + w - tr, y + tr, tr, Math.PI * 1.5, Math.PI * 2)
ctx.lineTo(x + w, y + h - br)
}
ctx.closePath()
if (stroke) ctx.stroke()
if (fill) ctx.fill()
}
measureText(text, fontSize) {
const { ctx } = this
// #ifndef APP-PLUS
return ctx.measureText(text).width
// #endif
// #ifdef APP-PLUS
// app measureText为0需要累加计算0
return text.split("").reduce((widthScaleSum, char) => {
let code = char.charCodeAt(0);
let widthScale = CHAR_WIDTH_SCALE_MAP[code - 0x20] || 1;
return widthScaleSum + widthScale;
}, 0) * fontSize;
// #endif
}
setFont({fontFamily: ff = 'sans-serif', fontSize: fs = 14, fontWeight: fw = 'normal' , textStyle: ts = 'normal'}) {
let ctx = this.ctx
// 设置属性
// #ifndef MP-TOUTIAO
// fw = fw == 'bold' ? 'bold' : 'normal'
// ts = ts == 'italic' ? 'italic' : 'normal'
// #endif
// #ifdef MP-TOUTIAO
fw = fw == 'bold' ? 'bold' : ''
ts = ts == 'italic' ? 'italic' : ''
// #endif
// fs = toPx(fs)
ctx.font = `${ts} ${fw} ${fs}px ${ff}`;
}
setTransform(box, {transform}) {
const {ctx} = this
const {
scaleX = 1,
scaleY = 1,
translateX = 0,
translateY = 0,
rotate = 0,
skewX = 0,
skewY = 0
} = transform || {}
let {
left: x,
top: y,
width: w,
height: h
} = box
ctx.scale(scaleX, scaleY)
ctx.translate(
w * (scaleX > 0 ? 1 : -1) / 2 + (x + translateX) / scaleX,
h * (scaleY > 0 ? 1 : -1) / 2 + (y + translateY) / scaleY)
if(rotate) {
ctx.rotate(rotate * Math.PI / 180)
}
if(skewX || skewY) {
ctx.transform(1, Math.tan(skewY * Math.PI/180), Math.tan(skewX * Math.PI/180), 1 , 0, 0)
}
}
setBackground(bd, w, h) {
const {ctx} = this
if (!bd) {
// #ifndef MP-TOUTIAO || MP-BAIDU
ctx.setFillStyle('transparent')
// #endif
// #ifdef MP-TOUTIAO || MP-BAIDU
ctx.setFillStyle('rgba(0,0,0,0)')
// #endif
} else if(GD.isGradient(bd)) {
GD.doGradient(bd, w, h, ctx);
} else {
ctx.setFillStyle(bd)
}
}
setShadow({boxShadow: bs = []}) {
// #ifndef APP-NVUE
const {ctx} = this
if (bs.length) {
const [x, y, b, c] = bs
ctx.setShadow(x, y, b, c)
}
// #endif
}
setBorder(box, style) {
const {ctx} = this
let {
left: x,
top: y,
width: w,
height: h
} = box
const {border, borderBottom, borderTop, borderRight, borderLeft, borderRadius: r, opacity = 1} = style;
const {
borderWidth : bw = 0,
borderStyle : bs,
borderColor : bc,
} = border || {}
const {
borderBottomWidth : bbw = bw,
borderBottomStyle : bbs = bs,
borderBottomColor : bbc= bc,
} = borderBottom || {}
const {
borderTopWidth: btw = bw,
borderTopStyle: bts = bs,
borderTopColor: btc = bc,
} = borderTop || {}
const {
borderRightWidth: brw = bw,
borderRightStyle: brs = bs,
borderRightColor: brc = bc,
} = borderRight || {}
const {
borderLeftWidth: blw = bw,
borderLeftStyle: bls = bs,
borderLeftColor: blc = bc,
} = borderLeft || {}
let {
borderTopLeftRadius: tl = r || 0,
borderTopRightRadius: tr = r || 0,
borderBottomRightRadius: br = r || 0,
borderBottomLeftRadius: bl = r || 0
} = r || {r,r,r,r}
if(!borderBottom && !borderLeft && !borderTop && !borderRight && !border) return;
const _borderType = (w, s, c) => {
// #ifndef APP-NVUE
if (s == 'dashed') {
// #ifdef MP
ctx.setLineDash([Math.ceil(w * 4 / 3), Math.ceil(w * 4 / 3)])
// #endif
// #ifndef MP
ctx.setLineDash([Math.ceil(w * 6), Math.ceil(w * 6)])
// #endif
} else if (s == 'dotted') {
ctx.setLineDash([w, w])
}
// #endif
ctx.setStrokeStyle(c)
}
const _setBorder = (x1, y1, x2, y2, x3, y3, r1, r2, p1, p2, p3, bw, bs, bc) => {
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
ctx.setLineWidth(bw)
_borderType(bw, bs, bc)
ctx.beginPath()
ctx.arc(x1, y1, r1, Math.PI * p1, Math.PI * p2)
ctx.lineTo(x2, y2)
ctx.arc(x3, y3, r2, Math.PI * p2, Math.PI * p3)
ctx.stroke()
ctx.restore()
}
if(border) {
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
ctx.setLineWidth(bw)
_borderType(bw, bs, bc)
this.roundRect(-w/2, -h/2, w, h, r, false, bc ? true : false)
ctx.restore()
}
x = -w/2
y = -h/2
if(borderBottom) {
_setBorder(x + w - br, y + h - br, x + bl, y + h, x + bl, y + h - bl, br, bl, 0.25, 0.5, 0.75, bbw, bbs, bbc)
}
if(borderLeft) {
// 左下角
_setBorder(x + bl, y + h - bl, x, y + tl, x + tl, y + tl, bl, tl, 0.75, 1, 1.25, blw, bls, blc)
}
if(borderTop) {
// 左上角
_setBorder(x + tl, y + tl, x + w - tr, y, x + w - tr, y + tr, tl, tr, 1.25, 1.5, 1.75, btw, bts, btc)
}
if(borderRight) {
// 右上角
_setBorder(x + w - tr, y + tr, x + w, y + h - br, x + w - br, y + h - br, tr, br, 1.75, 2, 0.25, btw, bts, btc)
}
}
setOpacity({opacity = 1}) {
this.ctx.setGlobalAlpha(opacity)
}
drawView(box, style) {
const {ctx} = this
const {
left: x,
top: y,
width: w,
height: h
} = box
let {
borderRadius = 0,
border,
borderTop,
borderBottom,
borderLeft,
borderRight,
color = '#000000',
backgroundColor: bg,
rotate,
shadow
} = style || {}
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
this.setShadow(style)
this.setBackground(bg, w, h)
this.roundRect(-w/2, -h/2, w, h, borderRadius, true, false)
ctx.restore()
this.setBorder(box, style)
}
async drawImage(img, box = {}, style = {}, custom = true) {
await new Promise(async (resolve, reject) => {
const {ctx} = this
const canvas = this.canvas
const {
borderRadius = 0,
mode,
backgroundColor: bg,
} = style
let {
left: x,
top: y,
width: w,
height: h
} = box
ctx.save()
if(!custom) {
this.setOpacity(style)
this.setTransform(box, style)
this.setBackground(bg, w, h)
this.setShadow(style)
x = -w/2
y = -h/2
this.roundRect(x, y, w, h, borderRadius, true, false)
}
ctx.clip()
const _modeImage = (img) => {
// 获得图片原始大小
let rWidth = img.width
let rHeight = img.height
let startX = 0
let startY = 0
// 绘画区域比例
const cp = w / h
// 原图比例
const op = rWidth / rHeight
if (cp >= op) {
rHeight = rWidth / cp;
// startY = Math.round((h - rHeight) / 2)
} else {
rWidth = rHeight * cp;
startX = Math.round(((img.width || w) - rWidth) / 2)
}
if (mode === 'scaleToFill' || !img.width) {
ctx.drawImage(img.src, x, y, w, h);
} else {
// 百度小程序 开发工具 顺序有问题 暂不知晓真机
// #ifdef MP-BAIDU
ctx.drawImage(img.src, x, y, w, h, startX, startY, rWidth, rHeight)
// #endif
// #ifndef MP-BAIDU
ctx.drawImage(img.src, startX, startY, rWidth, rHeight, x, y, w, h)
// #endif
}
}
const _drawImage = (img) => {
if (this.use2dCanvas) {
const Image = canvas.createImage()
Image.onload = () => {
img.src = Image
_modeImage(img)
_restore()
}
Image.onerror = () => {
console.error(`createImage fail: ${img}`)
reject(new Error(`createImage fail: ${img}`))
}
Image.src = img.src
} else {
_modeImage(img)
_restore()
}
}
const _restore = () => {
ctx.restore()
this.setBorder(box, style)
setTimeout(() => {
resolve(true)
}, this.root.sleep)
}
if(typeof img === 'string') {
const {path: src, width, height} = await getImageInfo(img, this.isH5PathToBase64)
_drawImage({src, width, height})
} else {
_drawImage(img)
}
})
}
drawText(text, box, style, rules) {
const {ctx} = this
let {
left: x,
top: y,
width: w,
height: h,
offsetLeft: ol = 0
} = box
let {
color = '#000000',
lineHeight = '1.4em',
fontSize = 14,
fontWeight,
fontFamily,
textStyle,
textAlign = 'left',
verticalAlign: va = 'top',
backgroundColor: bg,
maxLines,
textDecoration: td
} = style
lineHeight = toPx(lineHeight, fontSize)
if (!text) return
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
x = -w/2
y = -h/2
ctx.setTextBaseline(va)
this.setFont({fontFamily, fontSize, fontWeight, textStyle})
ctx.setTextAlign(textAlign)
if(bg) {
this.setBackground(bg, w, h)
this.roundRect(x, y, w, h, 1, bg)
}
this.setShadow(style)
ctx.setFillStyle(color)
let rulesObj = {};
if(rules) {
if (rules.word.length > 0) {
for (let i = 0; i < rules.word.length; i++) {
let startIndex = 0,
index;
while ((index = text.indexOf(rules.word[i], startIndex)) > -1) {
rulesObj[index] = {
reset: true
};
for (let j = 0; j < rules.word[i].length; j++) {
rulesObj[index + j] = {
reset: true
};
}
startIndex = index + 1;
}
}
}
}
// 水平布局
switch (textAlign) {
case 'left':
break
case 'center':
x += 0.5 * w
break
case 'right':
x += w
break
default:
break
}
const textWidth = this.measureText(text, fontSize)
const actualHeight = Math.ceil(textWidth / w) * lineHeight
let paddingTop = Math.ceil((h - actualHeight) / 2)
if (paddingTop < 0) paddingTop = 0
// 垂直布局
switch (va) {
case 'top':
break
case 'middle':
y += fontSize / 2
break
case 'bottom':
y += fontSize
break
default:
break
}
// 绘线
const _drawLine = (x, y, textWidth) => {
const { system } = uni.getSystemInfoSync()
if(/win|mac/.test(system)){
y += (fontSize / 3)
}
// 垂直布局
switch (va) {
case 'top':
break
case 'middle':
y -= fontSize / 2
break
case 'bottom':
y -= fontSize
break
default:
break
}
let to = x
switch (textAlign) {
case 'left':
x = x
to+= textWidth
break
case 'center':
x = x - textWidth / 2
to = x + textWidth
break
case 'right':
to = x
x = x - textWidth
break
default:
break
}
if(td) {
ctx.setLineWidth(fontSize / 13);
ctx.beginPath();
if (/\bunderline\b/.test(td)) {
y -= inlinePaddingTop * 0.8
ctx.moveTo(x, y);
ctx.lineTo(to, y);
}
if (/\boverline\b/.test(td)) {
y += inlinePaddingTop
ctx.moveTo(x, y - lineHeight);
ctx.lineTo(to, y - lineHeight);
}
if (/\bline-through\b/.test(td)) {
ctx.moveTo(x , y - lineHeight / 2 );
ctx.lineTo(to, y - lineHeight /2 );
}
ctx.closePath();
ctx.setStrokeStyle(color);
ctx.stroke();
}
}
const _reset = (text, x, y) => {
const rs = Object.keys(rulesObj)
for (let i = 0; i < rs.length; i++) {
const item = rulesObj[rs[i]]
// ctx.globalCompositeOperation = "destination-out";
ctx.save();
ctx.setFillStyle(rules.color);
if(item.char) {
ctx.fillText(item.char, item.x , item.y)
}
ctx.restore();
}
}
const _setText = (isReset, char) => {
if(isReset) {
const t1 = Math.round(this.measureText('\u0020', fontSize))
const t2 = Math.round(this.measureText('\u3000', fontSize))
const t3 = Math.round(this.measureText(char, fontSize))
let _char = ''
let _num = 1
if(t3 == t2){
_char ='\u3000'
_num = 1
} else {
_char = '\u0020'
_num = Math.ceil(t3 / t1)
}
return new Array(_num).fill(_char).join('')
} else {
return char
}
}
const _setRulesObj = (text, index, x, y) => {
rulesObj[index].x = x
rulesObj[index].y = y
rulesObj[index].char = text
}
const inlinePaddingTop = Math.ceil((lineHeight - fontSize) / 2)
// 不超过一行
if (textWidth + ol <= w && !text.includes('\n')) {
x = x + ol
const rs = Object.keys(rulesObj)
let _text = text.split('')
if(rs) {
for (let i = 0; i < rs.length; i++) {
const index = rs[i]
const t = _text[index]
let char = _setText(rulesObj[index], t)
_text[index] = char
_setRulesObj(t, index, x + this.measureText(text.substring(0, index), fontSize), y + inlinePaddingTop)
}
_reset()
}
ctx.fillText(_text.join(''), x, y + inlinePaddingTop)
y += lineHeight
_drawLine(x, y, textWidth)
ctx.restore()
this.setBorder(box, style)
return
}
// 多行文本
const chars = text.split('')
const _y = y
let _x = x
// 逐行绘制
let line = ''
let lineIndex = 0
for(let index = 0 ; index <= chars.length; index++){
let ch = chars[index] || ''
const isLine = ch === '\n'
const isRight = ch == ''// index == chars.length
ch = isLine ? '' : ch;
let textline = line + _setText(rulesObj[index], ch)
let textWidth = this.measureText(textline, fontSize)
// 绘制行数大于最大行数,则直接跳出循环
if (lineIndex >= maxLines) {
break;
}
if(lineIndex == 0) {
textWidth = textWidth + ol
_x += ol
}
if(rulesObj[index]) {
_setRulesObj(ch, index, _x + this.measureText(line, fontSize), y + inlinePaddingTop)
}
if (textWidth > w || isLine || isRight) {
lineIndex++
line = isRight && textWidth <= w ? textline : line
if(lineIndex === maxLines && textWidth > w) {
while( this.measureText(`${line}...`, fontSize) > w) {
if (line.length <= 1) {
// 如果只有一个字符时,直接跳出循环
break;
}
line = line.substring(0, line.length - 1);
if(rulesObj[index - 1]) {
rulesObj[index - 1].char = ''
}
}
line += '...'
}
ctx.fillText(line, _x, y + inlinePaddingTop)
y += lineHeight
_drawLine(_x, y, textWidth)
line = ch
if ((y + lineHeight) > (_y + h)) break
} else {
line = textline
}
}
const rs = Object.keys(rulesObj)
if(rs) {
_reset()
}
ctx.restore()
this.setBorder(box, style)
}
async findNode(element, parent = {}, index = 0, siblings = [], source) {
let computedStyle = Object.assign({}, this.getComputedStyle(element, parent, index));
let attributes = await this.getAttributes(element)
let node = {
id: id++,
parent,
computedStyle,
rules: element.rules,
attributes: Object.assign({}, attributes),
name: element?.type || 'view',
}
if(JSON.stringify(parent) === '{}' && !element.type) {
const {left = 0, top = 0, width = 0, height = 0 } = computedStyle
node.layoutBox = {left, top, width, height }
} else {
node.layoutBox = Object.assign({left: 0, top: 0}, this.getLayoutBox(node, parent, index, siblings, source))
}
if (element?.views) {
let childrens = []
node.children = []
for (let i = 0; i < element.views.length; i++) {
let v = element.views[i]
childrens.push(await this.findNode(v, node, i, childrens, element))
}
node.children = childrens
}
return node
}
getComputedStyle(element, parent = {}, index = 0) {
const style = {}
const node = JSON.stringify(parent) == '{}' && !element.type ? element : element.css;
if(parent.computedStyle) {
for (let value of Object.keys(parent.computedStyle)){
const item = parent.computedStyle[value]
if(['color', 'fontSize', 'lineHeight', 'verticalAlign', 'fontWeight', 'textAlign'].includes(value)) {
style[value] = /em|px$/.test(item) ? toPx(item, node?.fontSize) : item
}
}
}
if(!node) return style
for (let value of Object.keys(node)) {
const item = node[value]
if(value == 'views') {
continue
}
if (['boxShadow', 'shadow'].includes(value)) {
let shadows = item.split(' ').map(v => /^\d/.test(v) ? toPx(v) : v)
style.boxShadow = shadows
continue
}
if (value.includes('border') && !value.includes('adius')) {
const prefix = value.match(/^border([BTRLa-z]+)?/)[0]
const type = value.match(/[W|S|C][a-z]+/)
let v = item.split(' ').map(v => /^\d/.test(v) ? toPx(v) : v)
if(v.length > 1) {
style[prefix] = {
[prefix + 'Width'] : v[0] || 1,
[prefix + 'Style'] : v[1] || 'solid',
[prefix + 'Color'] : v[2] || 'black'
}
} else {
style[prefix] = {
[prefix + 'Width'] : 1,
[prefix + 'Style'] : 'solid',
[prefix + 'Color'] : 'black'
}
style[prefix][prefix + type[0]] = v[0]
}
continue
}
if (['background', 'backgroundColor'].includes(value)) {
style['backgroundColor'] = item
continue
}
if(value.includes('padding') || value.includes('margin') || value.includes('adius')) {
let isRadius = value.includes('adius')
let prefix = isRadius ? 'borderRadius' : value.match(/[a-z]+/)[0]
let pre = [0,0,0,0].map((item, i) => isRadius ? ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'][i] : [prefix + 'Top', prefix + 'Right', prefix + 'Bottom', prefix + 'Left'][i] )
if(value === 'padding' || value === 'margin' || value === 'radius' || value === 'borderRadius') {
let v = item?.split(' ').map((item) => /^\d/.test(item) && toPx(item, node['width']), []) ||[0];
let type = isRadius ? 'borderRadius' : value;
if(v.length == 1) {
style[type] = v[0]
} else {
let [t, r, b, l] = v
style[type] = {
[pre[0]]: t,
[pre[1]]: isNumber(r) ? r : t,
[pre[2]]: isNumber(b) ? b : t,
[pre[3]]: isNumber(l) ? l : r
}
}
} else {
if(typeof style[prefix] === 'object') {
style[prefix][value] = toPx(item, node['width'])
} else {
style[prefix] = {
[pre[0]]: style[prefix] || 0,
[pre[1]]: style[prefix] || 0,
[pre[2]]: style[prefix] || 0,
[pre[3]]: style[prefix] || 0
}
style[prefix][value] = toPx(item, node['width'])
}
}
continue
}
if(value.includes('width') || value.includes('height')) {
if(/%$/.test(item)) {
style[value] = toPx(item, parent.layoutBox[value])
} else {
style[value] = /px|rpx$/.test(item) ? toPx(item) : item
}
continue
}
if(value.includes('transform')) {
style[value]= {}
item.replace(/([a-zA-Z]+)\(([0-9,-\.%rpxdeg\s]+)\)/g, (g1, g2, g3) => {
const v = g3.split(',').map(k => k.replace(/(^\s*)|(\s*$)/g,''))
const transform = (v, r) => {
return v.includes('deg') ? v * 1 : toPx(v, r)
}
if(g2.includes('matrix')) {
style[value][g2] = v.map(v => v * 1)
} else if(g2.includes('rotate')) {
style[value][g2] = g3.match(/\d+/)[0] * 1
}else if(/[X, Y]/.test(g2)) {
style[value][g2] = /[X]/.test(g2) ? transform(v[0], node['width']) : transform(v[0], node['height'])
} else {
style[value][g2+'X'] = transform(v[0], node['width'])
style[value][g2+'Y'] = transform(v[1] || v[0], node['height'])
}
})
continue
}
if(/em$/.test(item) && !value.includes('lineHeight')) {
style[value] = Math.ceil(parseFloat(item.replace('em')) * toPx(node['fontSize'] || 14))
} else {
style[value] = /%|px|rpx$/.test(item) ? toPx(item, node['width']) : item
}
}
if((element.name == 'image' || element.type == 'image') && !style.mode) {
style.mode = 'aspectFill'
if((!node.width || node.width == 'auto') && (!node.height || node.width == 'auto') ) {
style.mode = ''
}
}
return style
}
getLayoutBox(element, parent = {}, index = 0, siblings = [], source = {}) {
let box = {}
let {name, computedStyle: cstyle, layoutBox, attributes} = element || {}
if(!name) return box
const {ctx} = this
const pbox = parent.layoutBox || this.root
const pstyle = parent.computedStyle
let {
verticalAlign: v,
left: x,
top: y,
width: w,
height: h,
fontSize = 14,
lineHeight = '1.4em',
maxLines,
fontWeight,
fontFamily,
textStyle,
position,
display
} = cstyle;
const { paddingTop: pt = 0, paddingRight: pr = 0, paddingBottom: pb = 0, paddingLeft: pl = 0, } = cstyle.padding || {}
const { marginTop: mt = 0, marginRight: mr = 0, marginBottom: mb = 0, marginLeft: ml = 0, } = cstyle.margin || {}
if(position == 'relative') {
x += pbox.left
y += pbox.top
}
if(name === 'text') {
const text = attributes.text ||''
lineHeight = toPx(lineHeight, fontSize)
ctx.save()
this.setFont({fontFamily, fontSize, fontWeight, textStyle})
const {layoutBox: lbox, computedStyle: ls} = siblings[index - 1] || {}
const {layoutBox: rbox, computedStyle: rs} = siblings[index + 1] || {}
const isLeft = index == 0
const isblock = display === 'block' || ls?.display === 'block'
const isOnly = isLeft && !rbox || !parent?.id
const lboxR = isLeft || isblock ? 0 : lbox.offsetRight || 0
let texts = text.split('\n')
let lineIndex = 1
let line = ''
const textIndent = cstyle.textIndent || 0
if(!isOnly) {
texts.map((t, i) => {
lineIndex += i
const chars = t.split('')
for (let j = 0; j < chars.length; j++) {
let ch = chars[j]
let textline = line + ch
let textWidth = this.measureText(textline, fontSize)
if(lineIndex == 1) {
textWidth = textWidth + (isblock ? 0 : lboxR) + textIndent
}
if(textWidth > pbox.width) {
lineIndex++
line = ch
} else {
line = textline
}
}
})
} else {
line = text
lineIndex = Math.max(texts.length, Math.ceil(this.measureText(text, fontSize) / ((w || pbox.width) - this.measureText('0', fontSize))))
}
box.offsetLeft = (isNumber(x) || isblock || isOnly ? textIndent : lboxR) + pl + ml;
// 剩下的字宽度
const remain = (this.measureText(line, fontSize))
let width = lineIndex > 1 ? pbox.width : remain + box.offsetLeft;
box.offsetRight = box.offsetLeft + (w ? w : (isblock ? pbox.width : remain)) + pr + mr;
const _getLeft = () => {
return (x || pbox.left)
}
const _getWidth = () => {
return w || (isOnly ? pbox.width : (width > pbox.width - box.left || lineIndex > 1 ? pbox.width - box.left : width))
}
const _getHeight = () => {
if(h) {
return h
} else if(lineIndex > 1 ) {
return (maxLines || lineIndex) * lineHeight + pt + pb + mt + mb
} else {
return lineHeight + pt + pb + mt + mb
}
}
const _getTop = () => {
let _y = y
if(_y) {
return _y + pt + mt
}
if(isLeft) {
_y = pbox.top
} else if(lbox.width < pbox.width) {
_y = lbox.top
} else {
_y = lbox.top + lbox.height - (ls?.lineHeight || 0)
}
return _y + pt + mt + (isblock && ls?.lineHeight || 0 )
}
box.left = _getLeft()
box.width = _getWidth()
box.height = _getHeight()
box.top = _getTop()
ctx.restore()
} else if(['view', 'qrcode'].includes(name)) {
box.left = x || pbox.left
box.width = (w || pbox?.width) - pl - pr
box.height = h || 0
box.top = y || pbox.top
} else if(name === 'image') {
box.left = x || pbox.left
box.width = (w || pbox?.width) - pl - pr
const {
width: rWidth,
height: rHeight
} = attributes
box.height = h || box.width * rHeight / rWidth
box.top = y || pbox.top
}
return box
}
async getAttributes(element) {
let arr = { }
if(element?.url || element?.src) {
arr.src = element.url || element?.src;
const {width = 0, height = 0, path: src} = await getImageInfo(arr.src, this.isH5PathToBase64) || {}
arr = Object.assign({}, arr, {width, height, src})
}
if(element?.text) {
arr.text = element.text
}
return arr
}
async drawBoard(element) {
const node = await this.findNode(element)
return this.drawNode(node)
}
async drawNode(element) {
const {
layoutBox,
computedStyle,
name,
rules
} = element
const {
src,
text
} = element.attributes
if (name === 'view') {
this.drawView(layoutBox, computedStyle)
} else if (name === 'image' && src) {
await this.drawImage(element.attributes, layoutBox, computedStyle, false)
} else if (name === 'text') {
this.drawText(text, layoutBox, computedStyle, rules)
} else if (name === 'qrcode') {
QR.api.draw(text, this, layoutBox, computedStyle)
}
if (!element.children) return
const childs = Object.values ? Object.values(element.children) : Object.keys(element.children).map((key) => element.children[key]);
for (const child of childs) {
await this.drawNode(child)
}
}
}
\ No newline at end of file
/* eslint-disable */
export const GD = {
isGradient(bg) {
if (bg && (bg.startsWith('linear') || bg.startsWith('radial'))) {
return true;
}
return false;
},
doGradient(bg, width, height, ctx) {
if (bg.startsWith('linear')) {
linearEffect(width, height, bg, ctx);
} else if (bg.startsWith('radial')) {
radialEffect(width, height, bg, ctx);
}
},
}
function analizeGrad(string) {
const colorPercents = string.substring(0, string.length - 1).split("%,");
const colors = [];
const percents = [];
for (let colorPercent of colorPercents) {
colors.push(colorPercent.substring(0, colorPercent.lastIndexOf(" ")).trim());
percents.push(colorPercent.substring(colorPercent.lastIndexOf(" "), colorPercent.length) / 100);
}
return {
colors: colors,
percents: percents
};
}
function radialEffect(width, height, bg, ctx) {
const colorPer = analizeGrad(bg.match(/radial-gradient\((.+)\)/)[1]);
const grd = ctx.createCircularGradient(0, 0, width < height ? height / 2 : width / 2);
for (let i = 0; i < colorPer.colors.length; i++) {
grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
}
ctx.setFillStyle(grd);
}
function analizeLinear(bg, width, height) {
const direction = bg.match(/([-]?\d{1,3})deg/);
const dir = direction && direction[1] ? parseFloat(direction[1]) : 0;
let coordinate;
switch (dir) {
case 0:
coordinate = [0, -height / 2, 0, height / 2];
break;
case 90:
coordinate = [width / 2, 0, -width / 2, 0];
break;
case -90:
coordinate = [-width / 2, 0, width / 2, 0];
break;
case 180:
coordinate = [0, height / 2, 0, -height / 2];
break;
case -180:
coordinate = [0, -height / 2, 0, height / 2];
break;
default:
let x1 = 0;
let y1 = 0;
let x2 = 0;
let y2 = 0;
if (direction[1] > 0 && direction[1] < 90) {
x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
} else if (direction[1] > -180 && direction[1] < -90) {
x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
} else if (direction[1] > 90 && direction[1] < 180) {
x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
} else {
x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 *
(90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
}
coordinate = [x1, y1, x2, y2];
break;
}
return coordinate;
}
function linearEffect(width, height, bg, ctx) {
const param = analizeLinear(bg, width, height);
const grd = ctx.createLinearGradient(param[0], param[1], param[2], param[3]);
const content = bg.match(/linear-gradient\((.+)\)/)[1];
const colorPer = analizeGrad(content.substring(content.indexOf(',') + 1));
for (let i = 0; i < colorPer.colors.length; i++) {
grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
}
ctx.setFillStyle(grd);
}
<template>
<canvas v-if="use2dCanvas" :id="canvasId" type="2d" :style="style"></canvas>
<canvas v-else :canvas-id="canvasId" :style="style" :id="canvasId" :width="boardWidth * dpr" :height="boardHeight * dpr"></canvas>
</template>
<script>
import { toPx, base64ToPath, compareVersion} from './utils';
import { Draw } from './draw';
import { adaptor } from './canvas';
export default {
// version: '1.5.9.2',
name: 'l-painter',
props: {
board: Object,
fileType: {
type: String,
default: 'png'
},
width: [Number, String],
height: [Number, String],
pixelRatio: Number,
customStyle: String,
isRenderImage: Boolean,
isBase64ToPath: Boolean,
isH5PathToBase64: Boolean,
sleep: {
type: Number,
default: 1000/30
},
type: {
type: String,
default: '2d',
}
},
data() {
return {
// #ifndef MP-WEIXIN || MP-QQ
canvasId: `l-painter_${this._uid}`,
// #endif
// #ifdef MP-WEIXIN || MP-QQ
canvasId: `l-painter`,
// #endif
// #ifdef MP-WEIXIN
use2dCanvas: true,
// #endif
// #ifndef MP-WEIXIN
use2dCanvas: false,
// #endif
draw: null,
ctx: null
};
},
computed: {
newboard() {
return this.board && JSON.parse(JSON.stringify(this.board))
},
style() {
return `width:${this.boardWidth}px; height: ${this.boardHeight}px; ${this.customStyle}`;
},
dpr() {
return this.pixelRatio || uni.getSystemInfoSync().pixelRatio;
},
boardWidth() {
const { width = 200 } = this.board || {};
return toPx(this.width || width);
},
boardHeight() {
const { height = 200 } = this.board || {};
return toPx(this.height || height);
}
},
mounted() {
// #ifdef MP-WEIXIN
const {SDKVersion} = wx.getSystemInfoSync()
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0;
// #endif
this.$watch('newboard', async (val, old) => {
if (JSON.stringify(val) === '{}' || !val) return;
const {width: w, height: h} = val || {};
const {width: ow, height: oh} = old || {};
if(w !== ow || h !== oh) {
this.inited = false;
}
this.render();
}, {
deep: true,
immediate: true,
})
},
methods: {
async render(args = {}, single = false) {
const ctx = await this.getContext()
const { use2dCanvas, boardWidth, boardHeight, board, canvas, isBase64ToPath, isH5PathToBase64, sleep } = this;
if (use2dCanvas && !canvas) {
return Promise.reject(new Error('render: fail canvas has not been created'));
}
if(!this.boundary) {
this.boundary = {
top: 0,
left: 0,
width: boardWidth,
height: boardHeight,
sleep
}
}
if(!single) {
ctx.clearRect(0, 0, boardWidth, boardHeight);
}
if(!this.draw) {
this.draw = new Draw(ctx, canvas, use2dCanvas, isH5PathToBase64, this.boundary);
}
if(JSON.stringify(args) != '{}' || board && JSON.stringify(board) != '{}') {
await this.draw.drawBoard(JSON.stringify(args) != '{}' ? args : board);
}
await new Promise(resolve => this.$nextTick(resolve))
if (!use2dCanvas && !single) {
await this.canvasDraw(ctx);
}
this.$emit('done')
if(this.isRenderImage && !single) {
this.canvasToTempFilePath()
.then(async res => {
if(/^data:image\/(\w+);base64/.test(res.tempFilePath) && isBase64ToPath) {
const img = await base64ToPath(res.tempFilePath)
this.$emit('success', img)
} else {
this.$emit('success', res.tempFilePath)
}
})
.catch(err => {
this.$emit('fail', err)
new Error(JSON.stringify(err))
console.error(111, JSON.stringify(err))
})
}
return Promise.resolve({ctx, draw: this.draw});
},
async custom(cb) {
const {ctx, draw} = await this.render({}, true)
ctx.save()
await cb(ctx, draw)
ctx.restore()
return Promise.resolve(true);
},
async single(args = {}) {
await this.render(args, true)
return Promise.resolve(true);
},
canvasDraw(flag = false) {
const {ctx} = this
return new Promise(resolve => {
ctx.draw(flag, () => {
resolve(true);
});
});
},
async getContext() {
if(this.ctx && this.inited) {
return Promise.resolve(this.ctx)
};
const { type, use2dCanvas, dpr, boardWidth, boardHeight } = this;
const _getContext = () => {
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select('#' + this.canvasId)
.boundingClientRect()
.exec(res => {
if(res) {
const ctx = uni.createCanvasContext(this.canvasId, this);
if (!this.inited) {
this.inited = true;
this.use2dCanvas = false;
this.canvas = res
}
// #ifdef MP-ALIPAY
ctx.scale(dpr, dpr);
// #endif
this.ctx = ctx
resolve(ctx);
}
})
})
}
// #ifndef MP-WEIXIN
return _getContext()
// #endif
if(!use2dCanvas) {
return _getContext()
}
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select('#l-painter')
.node()
.exec(res => {
const canvas = res[0].node;
if(!canvas) {
this.use2dCanvas = false;
return this.getContext()
}
const ctx = canvas.getContext(type);
if (!this.inited) {
this.inited = true;
canvas.width = boardWidth * dpr;
canvas.height = boardHeight * dpr;
this.use2dCanvas = true;
this.canvas = canvas
ctx.scale(dpr, dpr);
}
this.ctx = adaptor(ctx)
resolve(adaptor(ctx));
});
});
},
canvasToTempFilePath(args = {}) {
const {use2dCanvas, canvasId} = this
return new Promise((resolve, reject) => {
let { top = 0, left = 0, width, height } = this.boundary || this
let destWidth = width * this.dpr
let destHeight = height * this.dpr
// #ifdef MP-ALIPAY
width = width * this.dpr
height = height * this.dpr
// #endif
const copyArgs = {
x: left,
y: top,
width,
height,
destWidth,
destHeight,
canvasId,
fileType: args.fileType || this.fileType,
quality: args.quality || 1,
success: resolve,
fail: reject
}
if (use2dCanvas) {
delete copyArgs.canvasId
copyArgs.canvas = this.canvas
}
uni.canvasToTempFilePath(copyArgs, this)
})
}
}
};
</script>
<style></style>
// 请去下载覆盖:https://gitee.com/liangei/lime-painter/blob/master/qrcode.js
\ No newline at end of file
const screen = uni.getSystemInfoSync().windowWidth / 750;
// 缓存图片
let cache = {}
export function isNumber(value) {
return /^-?\d+(\.\d+)?$/.test(value);
}
export function toPx(value, baseSize) {
// 如果是数字
if (typeof value === 'number') {
return value
}
// 如果是字符串数字
if (isNumber(value)) {
return value * 1
}
// 如果有单位
if (typeof value === 'string') {
const reg = /^-?[0-9]+([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g
const results = reg.exec(value);
if (!value || !results) {
return 0;
}
const unit = results[2];
value = parseFloat(value);
let res = 0;
if (unit === 'rpx') {
res = Math.floor(value * (screen || 0.5) * 1);
} else if (unit === 'px') {
res = Math.floor(value * 1);
} else if (unit === '%') {
res = Math.floor(value * toPx(baseSize) / 100);
} else if (unit === 'em') {
res = Math.ceil(value * toPx(baseSize || 14));
}
return res;
}
}
// 计算版本
export function compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i], 10)
const num2 = parseInt(v2[i], 10)
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
/** 从 0x20 开始到 0x80 的字符宽度数据 */
export const CHAR_WIDTH_SCALE_MAP = [0.296, 0.313, 0.436, 0.638, 0.586, 0.89, 0.87, 0.256, 0.334, 0.334, 0.455, 0.742,
0.241, 0.433, 0.241, 0.427, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.241, 0.241, 0.742,
0.742, 0.742, 0.483, 1.031, 0.704, 0.627, 0.669, 0.762, 0.55, 0.531, 0.744, 0.773, 0.294, 0.396, 0.635, 0.513, 0.977,
0.813, 0.815, 0.612, 0.815, 0.653, 0.577, 0.573, 0.747, 0.676, 1.018, 0.645, 0.604, 0.62, 0.334, 0.416, 0.334, 0.742,
0.448, 0.295, 0.553, 0.639, 0.501, 0.64, 0.567, 0.347, 0.64, 0.616, 0.266, 0.267, 0.544, 0.266, 0.937, 0.616, 0.636,
0.639, 0.64, 0.382, 0.463, 0.373, 0.616, 0.525, 0.79, 0.507, 0.529, 0.492, 0.334, 0.269, 0.334, 0.742, 0.296
];
// #ifdef MP
const prefix = () => {
// #ifdef MP-TOUTIAO
return tt
// #endif
// #ifdef MP-WEIXIN
return wx
// #endif
// #ifdef MP-BAIDU
return swan
// #endif
// #ifdef MP-ALIPAY
return my
// #endif
// #ifdef MP-QQ
return qq
// #endif
// #ifdef MP-360
return qh
// #endif
}
const base64ToArrayBuffer = (data) => {
/**
* base64ToArrayBuffer
* Base64Binary.decode(base64_string);
* Base64Binary.decodeArrayBuffer(base64_string);
*/
const Base64Binary = {
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
/* will return a Uint8Array type */
decodeArrayBuffer(input) {
const bytes = (input.length/4) * 3;
const ab = new ArrayBuffer(bytes);
this.decode(input, ab);
return ab;
},
removePaddingChars(input) {
const lkey = this._keyStr.indexOf(input.charAt(input.length - 1));
if(lkey == 64){
return input.substring(0,input.length - 1);
}
return input;
},
decode(input, arrayBuffer) {
//get last chars to see if are valid
input = this.removePaddingChars(input);
input = this.removePaddingChars(input);
const bytes = parseInt((input.length / 4) * 3, 10);
let uarray;
let chr1, chr2, chr3;
let enc1, enc2, enc3, enc4;
let i = 0;
let j = 0;
if (arrayBuffer)
uarray = new Uint8Array(arrayBuffer);
else
uarray = new Uint8Array(bytes);
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
for (i=0; i<bytes; i+=3) {
//get the 3 octects in 4 ascii chars
enc1 = this._keyStr.indexOf(input.charAt(j++));
enc2 = this._keyStr.indexOf(input.charAt(j++));
enc3 = this._keyStr.indexOf(input.charAt(j++));
enc4 = this._keyStr.indexOf(input.charAt(j++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
uarray[i] = chr1;
if (enc3 != 64) uarray[i+1] = chr2;
if (enc4 != 64) uarray[i+2] = chr3;
}
return uarray;
}
}
return (uni.base64ToArrayBuffer && uni.base64ToArrayBuffer(data)) || Base64Binary.decodeArrayBuffer(data)
}
// #endif
/**
* base64转路径
* @param {Object} base64
*/
export function base64ToPath(base64) {
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
return new Promise((resolve, reject) => {
// #ifdef MP
const fs = uni.getFileSystemManager()
//自定义文件名
if (!format) {
console.error('ERROR_BASE64SRC_PARSE')
reject(new Error('ERROR_BASE64SRC_PARSE'))
}
const time = new Date().getTime();
let pre = prefix()
const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}`
let buffer = base64ToArrayBuffer(bodyData)
fs.writeFile({
filePath,
data: buffer,
encoding: 'binary',
success() {
resolve(filePath)
},
fail(err) {
console.error('获取base64图片失败', JSON.stringify(err))
reject(err)
}
})
// #endif
// #ifdef H5
// mime类型
let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
//base64 解码
let byteString = atob(base64.split(',')[1]);
//创建缓冲数组
let arrayBuffer = new ArrayBuffer(byteString.length);
//创建视图
let intArray = new Uint8Array(arrayBuffer);
for (let i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
resolve(URL.createObjectURL(new Blob([intArray], { type: mimeString })))
// #endif
// #ifdef APP-PLUS
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
bitmap.loadBase64Data(base64, () => {
if (!format) {
console.error('ERROR_BASE64SRC_PARSE')
reject(new Error('ERROR_BASE64SRC_PARSE'))
}
const time = new Date().getTime();
const filePath = `_doc/uniapp_temp/${time}.${format}`
bitmap.save(filePath, {},
() => {
bitmap.clear()
resolve(filePath)
},
(error) => {
bitmap.clear()
console.error(`${JSON.stringify(error)}`)
reject(error)
})
}, (error) => {
bitmap.clear()
console.error(`${JSON.stringify(error)}`)
reject(error)
})
// #endif
})
}
/**
* 路径转base64
* @param {Object} string
*/
export function pathToBase64(path) {
return new Promise((resolve, reject) => {
// #ifdef H5
const _canvas = ()=> {
let image = new Image();
image.onload = function() {
let canvas = document.createElement('canvas');
// 获取图片原始宽高
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
// 将图片插入画布并开始绘制
canvas.getContext('2d').drawImage(image, 0, 0);
let result = canvas.toDataURL('image/png')
resolve(result);
canvas.height = canvas.width = 0
}
image.src = path
image.setAttribute("crossOrigin",'Anonymous');
image.src = path;
image.onerror = (error) => {
console.error(`urlToBase64 error: ${path}`, JSON.stringify(error))
reject(new Error('urlToBase64 error'));
};
}
const _fileReader = (blob) => {
const fileReader = new FileReader();
fileReader.onload = (e) => {
resolve(e.target.result);
};
fileReader.readAsDataURL(blob);
fileReader.onerror = (error) => {
console.error('blobToBase64 error:', JSON.stringify(error))
reject(new Error('blobToBase64 error'));
};
}
const isFileReader = typeof FileReader === 'function'
if(/^(http|\/\/)/.test(path) && isFileReader ) {
window.URL = window.URL || window.webkitURL;
const xhr = new XMLHttpRequest();
xhr.open("get", path, true);
xhr.timeout = 2000;
xhr.responseType = "blob";
xhr.onload = function() {
if(this.status == 200) {
_fileReader(this.response)
} else {
_canvas()
}
}
xhr.onreadystatechange = function() {
if(this.status === 0) {
_canvas()
}
}
xhr.send();
} else if(/^blob/.test(path) && isFileReader){
_fileReader(path)
} else {
_canvas()
}
// #endif
// #ifdef MP
if(uni.canIUse('getFileSystemManager')) {
uni.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: (res) => {
resolve('data:image/png;base64,' + res.data)
},
fail: (error) => {
console.error('urlToBase64 error:', JSON.stringify(error))
reject(error)
}
})
}
// #endif
// #ifdef APP-PLUS
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.onload = (data) => {
resolve(data.target.result)
}
fileReader.onerror = (error) => {
console.error('pathToBase64 error:', JSON.stringify(error))
reject(error)
}
fileReader.readAsDataURL(file)
}, (error) => {
console.error('pathToBase64 error:', JSON.stringify(error))
reject(error)
})
}, (error) => {
console.error('pathToBase64 error:', JSON.stringify(error))
reject(error)
})
// #endif
})
}
// #ifdef APP-PLUS
const getLocalFilePath = (path)=> {
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
return path
}
if (path.indexOf('file://') === 0) {
return path
}
if (path.indexOf('/storage/emulated/0/') === 0) {
return path
}
if (path.indexOf('/') === 0) {
const localFilePath = plus.io.convertAbsoluteFileSystem(path)
if (localFilePath !== path) {
return localFilePath
} else {
path = path.substr(1)
}
}
return '_www/' + path
}
// #endif
export function getImageInfo(img, isH5PathToBase64) {
return new Promise(async (resolve, reject) => {
const base64Reg = /^data:image\/(\w+);base64/
const localReg = /^\.|^\/(?=[^\/])/;
const networkReg = /^(http|\/\/)/
// #ifdef H5
if(networkReg.test(img) && isH5PathToBase64) {
img = await pathToBase64(img)
}
// #endif
// #ifndef MP-ALIPAY
if(base64Reg.test(img)) {
if(!cache[img]) {
const imgName = img
img = await base64ToPath(img)
cache[imgName] = img
} else {
img = cache[img]
}
}
// #endif
if(cache[img] && cache[img].errMsg) {
resolve(cache[img])
} else {
uni.getImageInfo({
src: img,
success: (image) => {
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
image.path = localReg.test(img) ? `/${image.path}` : image.path;
// #endif
// image.path = /^(http|\/\/|\/|wxfile|data:image\/(\w+);base64|file|bdfile|ttfile|blob)/.test(image.path) ? image.path : `/${image.path}`;
cache[img] = image
resolve(cache[img])
},
fail(err) {
resolve({path: img})
console.error(`getImageInfo:fail ${img} failed ${JSON.stringify(err)}`);
}
})
}
})
}
\ No newline at end of file
# Painter 画板
> uniapp 海报画板,可根据自身需求配置生成海报
> [查看更多](http://liangei.gitee.io/limeui-docs/components/painter/) <br>
> Q群:458377637 <br>
> 群里有最新Demo
<br>
### 平台兼容
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
| √ | √ | √ | 未测 | √ | √ | √ |
<br>
<br>
### 代码演示
#### 基本用法
定一个画板对象,包含`width`、`height`、`background`,`views`为画板里的元素集,它是一个数组对象。<br>
元素类型目前有`view`、`text`、`image`<br>
css 对象里的位置都是相对于画板的绝对定位,支持`rpx`、`px`
```html
<l-painter :board="base"/>
```
```js
export default {
data() {
return {
base: {
width: '686rpx',
height: '130rpx',
views: [
{
type: 'view',
css: {
left: '0rpx',
top: '0rpx',
background: '#07c160',
width: '120rpx',
height: '120rpx'
}
},
{
type: 'view',
css: {
left: '180rpx',
top: '18rpx',
background: '#1989fa',
width: '80rpx',
height: '80rpx',
transform: 'transform: rotate(50deg)'
}
}
]
}
}
}
}
```
<br><br>
#### 圆角
为可元素定一个圆角`radius`,支持`rpx`、`px`、`%`
```html
<l-painter :board="base"/>
```
```js
export default {
data() {
return {
base: {
width: '686rpx',
height: '130rpx',
views: [
{
type: 'view',
css: {
left: '0rpx',
top: '0rpx',
background: '#07c160',
width: '120rpx',
height: '120rpx',
radius: '16rpx 30rpx 10rpx 80rpx'
}
},
{
type: 'view',
css: {
left: '150rpx',
top: '0rpx',
background: '#1989fa',
width: '120rpx',
height: '120rpx',
radius: '16rpx 60rpx'
}
},
{
type: 'view',
css: {
left: '300rpx',
top: '0rpx',
background: '#ff976a',
width: '120rpx',
height: '120rpx',
radius: '50%'
}
}
]
}
}
}
}
```
<br><br>
#### 描边投影
为可元素定一个描边`border`和投影`shadow`,支持`rpx`、`px`
```html
<l-painter :board="base"/>
```
```js
export default {
data() {
return {
base: {
width: '686rpx',
height: '130rpx',
views: [
{
type: 'view',
css: {
left: '10rpx',
top: '10rpx',
background: 'rgba(7,193,96,.1)',
width: '120rpx',
height: '120rpx',
radius: '50%',
border: '2rpx dashed rgb(7,193,96)'
}
},
{
type: 'view',
css: {
left: '150rpx',
top: '10rpx',
background: 'rgba(25,137,250,.4)',
width: '120rpx',
height: '120rpx',
radius: '50%',
shadow: '0 5rpx 10rpx rgba(25,137,250,.8)'
}
},
{
type: 'view',
css: {
left: '300rpx',
top: '10rpx',
background: 'rgba(255, 151, 106, .1)',
width: '120rpx',
height: '120rpx',
radius: '50%',
border: '2rpx solid #ff976a'
}
}
]
}
}
}
}
```
<br><br>
#### 图片
元素类型为`image`时,需要一个图片地址`src`,图片地址支持`相对路径`和`网络地址`<br>
::: warning 温馨提示
当为网络地址时,<br>
H5:需要解决跨域问题或使用`isH5PathToBase64`可解决部分问题。 <br>
小程序:需要配置 downloadFile 域名 <br>
本插件全端支持 base64 图片
:::
```html
<l-painter :board="base"/>
```
```js
export default {
data() {
return {
base: {
width: '686rpx',
height: '130rpx',
views: [
{
type: 'image',
<!-- src: '../../static/avatar-1.jpeg', -->
src: '',
css: {
left: '0rpx',
top: '0rpx',
width: '120rpx',
height: '120rpx'
}
},
{
type: 'image',
<!-- src: '../../static/avatar-2.jpg', -->
src: '',
css: {
left: '150rpx',
top: '0rpx',
width: '120rpx',
height: '120rpx',
radius: '16rpx'
}
},
{
type: 'image',
<!-- src:'../../static/avatar-3.jpeg', -->
src:'',
css: {
left: '300rpx',
top: '0rpx',
background: '#ff976a',
width: '120rpx',
height: '120rpx',
radius: '50%'
}
}
]
}
}
}
}
```
<br><br>
#### 文字
元素类型`text`时,内容写在`text`里,支持`\n`换行符,css 的属性有字体大小`fontSize`、行高`lineHeight`、对齐`textAlign`、修饰`textDecoration`、粗细`fontWeight`、 宽度`width`、最大行数`maxLines`。
设置了最大行数和宽度时,当文字内容超过会显示省略号。
```html
<l-painter :board="base"/>
```
```js
export default {
data() {
return {
base: {
width: '686rpx',
height: '500rpx',
views: [
{
type: 'text',
text: '左对齐,下划线\n无风才到地,有风还满空\n缘渠偏似雪,莫近鬓毛生',
// 可以指定关键字颜色
rules: {
word: ['到地'],
color: 'red'
},
css: {
left: '0rpx',
top: '10rpx',
fontSize: '28rpx',
lineHeight: '36rpx',
textDecoration: 'underline'
}
},
{
type: 'text',
text: '居中,上划线\n无风才到地,有风还满空\n缘渠偏似雪,莫近鬓毛生',
css: {
left: '0rpx',
top: '150rpx',
fontSize: '28rpx',
lineHeight: '36rpx',
textAlign: 'center',
textDecoration: 'overline'
}
},
{
type: 'text',
text: '右对齐,中划线\n无风才到地,有风还满空\n缘渠偏似雪,莫近鬓毛生',
css: {
left: '0rpx',
top: '290rpx',
fontSize: '28rpx',
lineHeight: '36rpx',
textAlign: 'right',
textDecoration: 'line-through',
}
},
{
type: 'text',
text: '省略号\n明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间。',
rules: {
word: ['几时有'],
color: 'red'
},
css: {
left: '0rpx',
top: '420rpx',
fontSize: '28rpx',
maxLines: 2,
width: '686rpx',
lineHeight: '36rpx'
}
}
]
}
}
}
}
```
<br>
#### 调用内部方法
插件也允许通过`ref`获取内部方法来实现绘制和生成图片。
需要设置画板的`width`和`height`
```html
<l-painter ref="painter" width="686rpx" height="500rpx" />
<image :src="path" />
```
```js
export default {
data() {
return {
base: {
width: '686rpx',
height: '500rpx',
views: [
{
type: 'view',
css: {
fontSize: '28rpx',
lineHeight: '1.4em',
},
views: [
{
type: 'text',
text: '水调歌头',
css: {
display: 'block',
fontSize: '42rpx',
textAlign: 'center'
}
},
{
type: 'text',
text: '丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。',
css: {
display: 'block',
textIndent: '2em'
}
},
{
type: 'text',
text: '明月几时有?把酒问青天。不知天上宫阙,今夕是何年?我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间',
css: {
display: 'block',
color: 'red',
textIndent: '2em'
}
},
{
type: 'text',
text: '转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟',
css: {
textIndent: '2em'
}
}
]
}
]
},
path: '',
}
},
methods: {
onRender() {
// 支持通过调用render传入参数
const painter = this.$refs.painter
painter.render(this.base)
},
canvasToTempFilePath() {
const painter = this.$refs.painter
// 支持通过调用canvasToTempFilePath方法传入参数 调取生成图片
painter.canvasToTempFilePath().then(res => this.path = res.tempFilePath)
}
}
}
```
<br>
#### 自定义
有时画板提供的方法无法满足复杂个性的需要,可通过插件`ref`获取`ctx`来使用原生方法绘制。
```html
<l-painter ref="painter" width="686rpx" height="500rpx" />
<image :src="path" />
```
```js
export default {
data() {
return {
path: '',
}
},
methods: {
async onCustom() {
const p = this.$refs.custom
// 自定义,使用原生和内部方法生成更个性的图形
await p.custom(async (ctx, draw) => {
// 原生方法的单位为px,如果想用rpx,请使用uni.rpx2px(150)
// 绘制背景颜色
ctx.setFillStyle('#ff976a')
ctx.setShadow(5, 5, 50, '#ff976a')
ctx.beginPath()
ctx.arc(150, 150, 20, Math.PI, Math.PI * 1.5)
ctx.lineTo(150, 20)
ctx.arc(150, 0, 20, Math.PI * 0.5, Math.PI * 1)
ctx.lineTo(5, 0)
ctx.arc(0, 0, 20, Math.PI * 0, Math.PI * 0.5)
ctx.lineTo(0, 130)
ctx.arc(0, 150, 20, Math.PI * 1.5, Math.PI * 2)
ctx.lineTo(130, 150)
ctx.closePath()
ctx.fill()
// 绘制好形状后,调用draw的drawImage方法填充图片,图片会下载完成后绘制。无需自己下载。
await draw.drawImage('../../static/avatar-1.jpeg', {left: 0, top: 0, width:150, height:150})
})
await p.custom((ctx) => {
// 绘制背景颜色
ctx.setFillStyle('#07c160')
ctx.beginPath()
ctx.arc(280, 50, 50, 0, Math.PI * 2)
ctx.closePath()
ctx.fill()
})
// 单独绘制单个或多个元素的内部方法,
// 多个是是数组,单个是为对象
// 绘制二维码,由于二维码JS文件较大,也不是所有人需要。所以需自行下载覆盖。
await p.single({
type: 'qrcode',
text: 'https://www.baidu.com',
css: {
left: '380rpx',
top: '230rpx',
width: '200rpx',
height: '200rpx',
color: '#1989fa',
backgroundColor: 'rgba(25,137,250,.1)',
border: '20rpx solid rgba(25,137,250,.1)',
transform: 'rotate(45deg)'
}
})
await p.single({
type: 'text',
text: '床前明月光,疑是地上霜。\n举头望明月,低头思故乡。',
css: {
left: '0rpx',
top: '330rpx'
}
})
// 使用自定义时,要配合方法绘制,否则无法绘制。
await p.canvasDraw(true)
},
// 支持通过调用canvasToTempFilePath方法传入参数 调取生成图片
onCanvasToTempFilePath() {
const painter = this.$refs.custom
painter.canvasToTempFilePath({dpr:2}).then(res => this.path = res.tempFilePath)
}
}
}
```
<br><br>
#### 提供一份海报样式案例
是否生成图片:`isRenderImage` <br>
生成图片成功:`success`返回一个图片临时地址。
```html
<l-painter
v-if="isShowPainter"
isRenderImage
custom-style="position: fixed; left: 200%;"
:board="base"
@success="path = $event"
/>
```
```js
export default {
data() {
return {
base: {
width: '750rpx',
height: '1114rpx',
background: '#F6F7FB',
views: [
{
type: 'view',
css: {
left: '40rpx',
top: '144rpx',
background: '#fff',
radius: '16rpx',
width: '670rpx',
height: '930rpx',
shadow: '0 20rpx 48rpx rgba(0,0,0,.05)'
}
},
{
type: 'image',
src: '../../static/avatar-2.jpg',
mode: 'widthFix',
css: {
left: '40rpx',
top: '40rpx',
width: '84rpx',
height: '84rpx',
radius: '50%',
color: '#999'
}
},
{
type: 'text',
text: '隔壁老王',
css: {
color: '#333',
left: '144rpx',
top: '40rpx',
fontSize: '32rpx',
fontWeight: 'bold'
}
},
{
type: 'text',
text: '为您挑选了一个好物',
css: {
color: '#666',
left: '144rpx',
top: '90rpx',
fontSize: '24rpx'
}
},
{
type: 'image',
src: '../../static/goods.jpg',
mode: 'widthFix',
css: {
left: '72rpx',
top: '176rpx',
width: '606rpx',
height: '606rpx',
radius: '12rpx'
}
},
{
type: 'text',
text: '¥39.90',
css: {
color: '#FF0000',
left: '66rpx',
top: '812rpx',
fontSize: '56rpx',
fontWeight: 'bold'
}
},
{
type: 'text',
text: '360儿童电话手表9X 智能语音问答定位支付手表 4G全网通20米游泳级防水视频通话拍照手表男女孩星空蓝',
css: {
maxLines: 2,
width: '396rpx',
color: '#333',
left: '72rpx',
top: '948rpx',
fontSize: '36rpx',
lineHeight: '50rpx'
}
},
{
type: 'image',
src: '../../static/qr.png',
mode: 'widthFix',
css: {
left: '500rpx',
top: '864rpx',
width: '178rpx',
height: '178rpx'
}
}
]
}
}
},
methods: {
saveImage() {
this.isShowPopup = false
uni.saveImageToPhotosAlbum({
filePath: this.path,
success(res) {
uni.showToast({
title: '已保存到相册',
icon: 'success',
duration: 2000
})
}
})
},
}
}
```
### API
#### Props
| 参数 | 说明 | 类型 | 默认值 |
| ------------- | ------------ | ---------------- | ------------ |
| board | 画板对象 | <em>object</em> | 参数请向下看 |
| customStyle | 自定义样式 | <em>string</em> | |
| isRenderImage | 是否生成图片 | <em>boolean</em> | `false` |
| isH5PathToBase64 | H5端把网络图片转成base64,解决部分跨域问题 | <em>boolean</em> | `false` |
| isBase64ToPath | H5端把base64转成网络图片,应用场景不多考虑删除慎用 | <em>boolean</em> | `false` |
| sleep | 此参数是为解决图片渲染时不按JSON层次前后渲染。若有此情况请增大数值 | <em>number</em> | `33` |
| type | 只对微信小程序可有效 | <em>string</em> | `2d` |
| fileType | 生成图片的后缀类型 | <em>string</em> | `png` |
| pixelRatio | 生成图片的像素密度,默认为对应手机的像素密度 | <em>number</em> | `` |
| width | 画板的宽度,一般只用于通过内部方法时加上 | <em>number</em> | `` |
| height | 画板的高度 ,同上 | <em>number</em> | `` |
<br>
#### Board
| 参数 | 说明 | 类型 |
| ---------- | ---------------------------------- | --------------- |
| width | 画板的宽度 | <em>string</em> |
| height | 画板的高度 | <em>string</em> |
| background | 画板的背景色,支持颜色渐变,但要写百分比及方向如:`background: 'linear-gradient(to right, #ff971b 0%, #ff5000 100%)'` | <em>string</em> |
| views | 画板的元素集,请向下看各元素的参数 | <em>object</em> |
<br>
#### 块 View
| 参数 | 说明 |
| ---- | --------------------------------------------------------------------------------------------------- |
| type | 元素类型`view` |
| css | 元素的样式,`top`、`left`、`width`、`height`、`background`、`radius`、`border`、`shadow` 、`transform`包含缩放: `scaleX(-1)`、旋转`rotate(50deg)`、倾斜`skewX(50deg)` |
<br>
#### 文本 text
| 参数 | 说明 |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type | 元素类型`text` |
| text | 文本内容 |
| css | 元素的样式,`top`、`left`、`fontSize`、`fontWeight`、`fontFamily`、`width`、`lineHeight`、`color`、`textDecoration`、`textAlign`:center, left, right、最大行数:`maxLines`、`transform` |
| rules | 是一个对象 `Object`指定文字颜色, `word`关键词数组、`color`关键词颜色,目前只能定一种颜色。|
<br>
#### 图片 image
| 参数 | 说明 |
| ---- | -------------------------------------------------------------------------- |
| type | 元素类型`image` |
| src | 图片地址 |
| css | 元素的样式,`top`、`left`、`width`、`height`、`radius`、`border`、`shadow`、`transform` |
<br>
#### 二维码 qrcode
| 参数 | 说明 |
| ---- | -------------------------------------------------------------------------- |
| type | 元素类型`qrcode`, 二维码。[需要自行下载覆盖](https://gitee.com/liangei/lime-painter/blob/master/qrcode.js)。 |
| text | 二维码文本内容 |
| css | 元素的样式,`top`、`left`、`width`、`height`、`border`、`transform`、`backgroundColor`背景色、`color` 前景色|
<br>
#### 事件 Events
| 事件名 | 说明 | 回调 |
| ------- | ------------ | -------------- |
| success | 生成图片成功 | $event |
| fail | 生成图片失败 | {error: error} |
| done | 绘制成功 | |
### 常见问题
> 1、H5端使用网络图片需要解决跨域问题、或者添加`isH5PathToBase64`可解决部分问题。<br>
> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!<br>
> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签`<IMG/>`<br>
> 4、发生保存图片倾斜变形或提示native buffer exceed size limit时,使用pixel-ratio="2"参数,降分辨率。<br>
> 5、h5保存图片不需要调接口,提示用户长按图片保存。<br>
> 6、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。<br>
> 7、不生成图片或不绘制时,请查看是否把组件隐藏了!<br>
> 8、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。<br>
> 9、微信小程序2D不支持真机调试,请使用真机预览方式。<br>
### 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。<br>
![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")
\ No newline at end of file
export function adaptor(ctx) {
return Object.assign(ctx, {
setStrokeStyle(val) {
ctx.strokeStyle = val;
},
setLineWidth(val) {
ctx.lineWidth = val;
},
setLineCap(val) {
ctx.lineCap = val;
},
setFillStyle(val) {
ctx.fillStyle = val;
},
setFontSize(val) {
ctx.font = String(val);
},
setGlobalAlpha(val) {
ctx.globalAlpha = val;
},
setLineJoin(val) {
ctx.lineJoin = val;
},
setTextAlign(val) {
ctx.textAlign = val;
},
setMiterLimit(val) {
ctx.miterLimit = val;
},
setShadow(offsetX, offsetY, blur, color) {
ctx.shadowOffsetX = offsetX;
ctx.shadowOffsetY = offsetY;
ctx.shadowBlur = blur;
ctx.shadowColor = color;
},
setTextBaseline(val) {
ctx.textBaseline = val;
},
createCircularGradient() {},
draw() {},
});
}
import { toPx, CHAR_WIDTH_SCALE_MAP, isNumber, getImageInfo } from './utils'
import { GD } from './gradient'
import QR from './qrcode'
let id = 0
export class Draw {
constructor(context, canvas, use2dCanvas = false, isH5PathToBase64 = false, boundary) {
this.ctx = context
this.canvas = canvas || null
this.root = boundary
this.use2dCanvas = use2dCanvas
this.isH5PathToBase64 = isH5PathToBase64
}
roundRect(x, y, w, h, r, fill = false, stroke = false, ) {
if (r < 0) return
const {ctx} = this
ctx.beginPath()
if(!r) {
ctx.rect(x, y, w, h)
} else if(typeof r === 'number' && [0,1,-1].includes(w - r * 2) && [0, 1, -1].includes(h - r * 2)) {
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 2)
} else {
let {
borderTopLeftRadius: tl = r || 0,
borderTopRightRadius: tr = r || 0,
borderBottomRightRadius: br = r || 0,
borderBottomLeftRadius: bl = r || 0
} = r || {r,r,r,r}
// ctx.beginPath()
// 右下角
ctx.arc(x + w - br, y + h - br, br, 0, Math.PI * 0.5)
ctx.lineTo(x + bl, y + h)
// 左下角
ctx.arc(x + bl, y + h - bl, bl, Math.PI * 0.5, Math.PI)
ctx.lineTo(x, y + tl)
// 左上角
ctx.arc(x + tl, y + tl, tl, Math.PI, Math.PI * 1.5)
ctx.lineTo(x + w - tr, y)
// 右上角
ctx.arc(x + w - tr, y + tr, tr, Math.PI * 1.5, Math.PI * 2)
ctx.lineTo(x + w, y + h - br)
}
ctx.closePath()
if (stroke) ctx.stroke()
if (fill) ctx.fill()
}
measureText(text, fontSize) {
const { ctx } = this
// #ifndef APP-PLUS
return ctx.measureText(text).width
// #endif
// #ifdef APP-PLUS
// app measureText为0需要累加计算0
return text.split("").reduce((widthScaleSum, char) => {
let code = char.charCodeAt(0);
let widthScale = CHAR_WIDTH_SCALE_MAP[code - 0x20] || 1;
return widthScaleSum + widthScale;
}, 0) * fontSize;
// #endif
}
setFont({fontFamily: ff = 'sans-serif', fontSize: fs = 14, fontWeight: fw = 'normal' , textStyle: ts = 'normal'}) {
let ctx = this.ctx
// 设置属性
// #ifndef MP-TOUTIAO
// fw = fw == 'bold' ? 'bold' : 'normal'
// ts = ts == 'italic' ? 'italic' : 'normal'
// #endif
// #ifdef MP-TOUTIAO
fw = fw == 'bold' ? 'bold' : ''
ts = ts == 'italic' ? 'italic' : ''
// #endif
// fs = toPx(fs)
ctx.font = `${ts} ${fw} ${fs}px ${ff}`;
}
setTransform(box, {transform}) {
const {ctx} = this
const {
scaleX = 1,
scaleY = 1,
translateX = 0,
translateY = 0,
rotate = 0,
skewX = 0,
skewY = 0
} = transform || {}
let {
left: x,
top: y,
width: w,
height: h
} = box
ctx.scale(scaleX, scaleY)
ctx.translate(
w * (scaleX > 0 ? 1 : -1) / 2 + (x + translateX) / scaleX,
h * (scaleY > 0 ? 1 : -1) / 2 + (y + translateY) / scaleY)
if(rotate) {
ctx.rotate(rotate * Math.PI / 180)
}
if(skewX || skewY) {
ctx.transform(1, Math.tan(skewY * Math.PI/180), Math.tan(skewX * Math.PI/180), 1 , 0, 0)
}
}
setBackground(bd, w, h) {
const {ctx} = this
if (!bd) {
// #ifndef MP-TOUTIAO || MP-BAIDU
ctx.setFillStyle('transparent')
// #endif
// #ifdef MP-TOUTIAO || MP-BAIDU
ctx.setFillStyle('rgba(0,0,0,0)')
// #endif
} else if(GD.isGradient(bd)) {
GD.doGradient(bd, w, h, ctx);
} else {
ctx.setFillStyle(bd)
}
}
setShadow({boxShadow: bs = []}) {
// #ifndef APP-NVUE
const {ctx} = this
if (bs.length) {
const [x, y, b, c] = bs
ctx.setShadow(x, y, b, c)
}
// #endif
}
setBorder(box, style) {
const {ctx} = this
let {
left: x,
top: y,
width: w,
height: h
} = box
const {border, borderBottom, borderTop, borderRight, borderLeft, borderRadius: r, opacity = 1} = style;
const {
borderWidth : bw = 0,
borderStyle : bs,
borderColor : bc,
} = border || {}
const {
borderBottomWidth : bbw = bw,
borderBottomStyle : bbs = bs,
borderBottomColor : bbc= bc,
} = borderBottom || {}
const {
borderTopWidth: btw = bw,
borderTopStyle: bts = bs,
borderTopColor: btc = bc,
} = borderTop || {}
const {
borderRightWidth: brw = bw,
borderRightStyle: brs = bs,
borderRightColor: brc = bc,
} = borderRight || {}
const {
borderLeftWidth: blw = bw,
borderLeftStyle: bls = bs,
borderLeftColor: blc = bc,
} = borderLeft || {}
let {
borderTopLeftRadius: tl = r || 0,
borderTopRightRadius: tr = r || 0,
borderBottomRightRadius: br = r || 0,
borderBottomLeftRadius: bl = r || 0
} = r || {r,r,r,r}
if(!borderBottom && !borderLeft && !borderTop && !borderRight && !border) return;
const _borderType = (w, s, c) => {
// #ifndef APP-NVUE
if (s == 'dashed') {
// #ifdef MP
ctx.setLineDash([Math.ceil(w * 4 / 3), Math.ceil(w * 4 / 3)])
// #endif
// #ifndef MP
ctx.setLineDash([Math.ceil(w * 6), Math.ceil(w * 6)])
// #endif
} else if (s == 'dotted') {
ctx.setLineDash([w, w])
}
// #endif
ctx.setStrokeStyle(c)
}
const _setBorder = (x1, y1, x2, y2, x3, y3, r1, r2, p1, p2, p3, bw, bs, bc) => {
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
ctx.setLineWidth(bw)
_borderType(bw, bs, bc)
ctx.beginPath()
ctx.arc(x1, y1, r1, Math.PI * p1, Math.PI * p2)
ctx.lineTo(x2, y2)
ctx.arc(x3, y3, r2, Math.PI * p2, Math.PI * p3)
ctx.stroke()
ctx.restore()
}
if(border) {
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
ctx.setLineWidth(bw)
_borderType(bw, bs, bc)
this.roundRect(-w/2, -h/2, w, h, r, false, bc ? true : false)
ctx.restore()
}
x = -w/2
y = -h/2
if(borderBottom) {
_setBorder(x + w - br, y + h - br, x + bl, y + h, x + bl, y + h - bl, br, bl, 0.25, 0.5, 0.75, bbw, bbs, bbc)
}
if(borderLeft) {
// 左下角
_setBorder(x + bl, y + h - bl, x, y + tl, x + tl, y + tl, bl, tl, 0.75, 1, 1.25, blw, bls, blc)
}
if(borderTop) {
// 左上角
_setBorder(x + tl, y + tl, x + w - tr, y, x + w - tr, y + tr, tl, tr, 1.25, 1.5, 1.75, btw, bts, btc)
}
if(borderRight) {
// 右上角
_setBorder(x + w - tr, y + tr, x + w, y + h - br, x + w - br, y + h - br, tr, br, 1.75, 2, 0.25, btw, bts, btc)
}
}
setOpacity({opacity = 1}) {
this.ctx.setGlobalAlpha(opacity)
}
drawView(box, style) {
const {ctx} = this
const {
left: x,
top: y,
width: w,
height: h
} = box
let {
borderRadius = 0,
border,
borderTop,
borderBottom,
borderLeft,
borderRight,
color = '#000000',
backgroundColor: bg,
rotate,
shadow
} = style || {}
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
this.setShadow(style)
this.setBackground(bg, w, h)
this.roundRect(-w/2, -h/2, w, h, borderRadius, true, false)
ctx.restore()
this.setBorder(box, style)
}
async drawImage(img, box = {}, style = {}, custom = true) {
await new Promise(async (resolve, reject) => {
const {ctx} = this
const canvas = this.canvas
const {
borderRadius = 0,
mode,
backgroundColor: bg,
} = style
let {
left: x,
top: y,
width: w,
height: h
} = box
ctx.save()
if(!custom) {
this.setOpacity(style)
this.setTransform(box, style)
this.setBackground(bg, w, h)
this.setShadow(style)
x = -w/2
y = -h/2
this.roundRect(x, y, w, h, borderRadius, false, false)
}
ctx.clip()
const _modeImage = (img) => {
// 获得图片原始大小
let rWidth = img.width
let rHeight = img.height
let startX = 0
let startY = 0
// 绘画区域比例
const cp = w / h
// 原图比例
const op = rWidth / rHeight
if (cp >= op) {
rHeight = rWidth / cp;
// startY = Math.round((h - rHeight) / 2)
} else {
rWidth = rHeight * cp;
startX = Math.round(((img.width || w) - rWidth) / 2)
}
if (mode === 'scaleToFill' || !img.width) {
ctx.drawImage(img.src, x, y, w, h);
} else {
// 百度小程序 开发工具 顺序有问题 暂不知晓真机
// #ifdef MP-BAIDU
ctx.drawImage(img.src, x, y, w, h, startX, startY, rWidth, rHeight)
// #endif
// #ifndef MP-BAIDU
ctx.drawImage(img.src, startX, startY, rWidth, rHeight, x, y, w, h)
ctx.restore()
// #ifdef APP-NVUE
ctx.draw(true)
// #endif
// #endif
}
}
const _drawImage = (img) => {
if (this.use2dCanvas) {
const Image = canvas.createImage()
Image.onload = () => {
img.src = Image
_modeImage(img)
_restore()
}
Image.onerror = () => {
console.error(`createImage fail: ${img}`)
reject(new Error(`createImage fail: ${img}`))
}
Image.src = img.src
} else {
_modeImage(img)
_restore()
}
}
const _restore = () => {
// ctx.restore()
this.setBorder(box, style)
resolve(true)
setTimeout(() => {
resolve(true)
}, this.root.sleep)
}
if(typeof img === 'string') {
const {path: src, width, height} = await getImageInfo(img, this.isH5PathToBase64)
_drawImage({src, width, height})
} else {
_drawImage(img)
}
})
}
drawText(text, box, style, rules) {
const {ctx} = this
let {
left: x,
top: y,
width: w,
height: h,
offsetLeft: ol = 0
} = box
let {
color = '#000000',
lineHeight = '1.4em',
fontSize = 14,
fontWeight,
fontFamily,
textStyle,
textAlign = 'left',
verticalAlign: va = 'top',
backgroundColor: bg,
maxLines,
textDecoration: td
} = style
lineHeight = toPx(lineHeight, fontSize)
if (!text) return
ctx.save()
this.setOpacity(style)
this.setTransform(box, style)
x = -w/2
y = -h/2
ctx.setTextBaseline(va)
this.setFont({fontFamily, fontSize, fontWeight, textStyle})
ctx.setTextAlign(textAlign)
if(bg) {
this.setBackground(bg, w, h)
this.roundRect(x, y, w, h, 1, bg)
}
this.setShadow(style)
ctx.setFillStyle(color)
let rulesObj = {};
if(rules) {
if (rules.word.length > 0) {
for (let i = 0; i < rules.word.length; i++) {
let startIndex = 0,
index;
while ((index = text.indexOf(rules.word[i], startIndex)) > -1) {
rulesObj[index] = {
reset: true
};
for (let j = 0; j < rules.word[i].length; j++) {
rulesObj[index + j] = {
reset: true
};
}
startIndex = index + 1;
}
}
}
}
// 水平布局
switch (textAlign) {
case 'left':
break
case 'center':
x += 0.5 * w
break
case 'right':
x += w
break
default:
break
}
const textWidth = this.measureText(text, fontSize)
const actualHeight = Math.ceil(textWidth / w) * lineHeight
let paddingTop = Math.ceil((h - actualHeight) / 2)
if (paddingTop < 0) paddingTop = 0
// 垂直布局
switch (va) {
case 'top':
break
case 'middle':
y += fontSize / 2
break
case 'bottom':
y += fontSize
break
default:
break
}
// 绘线
const _drawLine = (x, y, textWidth) => {
const { system } = uni.getSystemInfoSync()
if(/win|mac/.test(system)){
y += (fontSize / 3)
}
// 垂直布局
switch (va) {
case 'top':
break
case 'middle':
y -= fontSize / 2
break
case 'bottom':
y -= fontSize
break
default:
break
}
let to = x
switch (textAlign) {
case 'left':
x = x
to+= textWidth
break
case 'center':
x = x - textWidth / 2
to = x + textWidth
break
case 'right':
to = x
x = x - textWidth
break
default:
break
}
if(td) {
ctx.setLineWidth(fontSize / 13);
ctx.beginPath();
if (/\bunderline\b/.test(td)) {
y -= inlinePaddingTop * 0.8
ctx.moveTo(x, y);
ctx.lineTo(to, y);
}
if (/\boverline\b/.test(td)) {
y += inlinePaddingTop
ctx.moveTo(x, y - lineHeight);
ctx.lineTo(to, y - lineHeight);
}
if (/\bline-through\b/.test(td)) {
ctx.moveTo(x , y - lineHeight / 2 );
ctx.lineTo(to, y - lineHeight /2 );
}
ctx.closePath();
ctx.setStrokeStyle(color);
ctx.stroke();
}
}
const _reset = (text, x, y) => {
const rs = Object.keys(rulesObj)
for (let i = 0; i < rs.length; i++) {
const item = rulesObj[rs[i]]
// ctx.globalCompositeOperation = "destination-out";
ctx.save();
ctx.setFillStyle(rules.color);
if(item.char) {
ctx.fillText(item.char, item.x , item.y)
}
ctx.restore();
}
}
const _setText = (isReset, char) => {
if(isReset) {
const t1 = Math.round(this.measureText('\u0020', fontSize))
const t2 = Math.round(this.measureText('\u3000', fontSize))
const t3 = Math.round(this.measureText(char, fontSize))
let _char = ''
let _num = 1
if(t3 == t2){
_char ='\u3000'
_num = 1
} else {
_char = '\u0020'
_num = Math.ceil(t3 / t1)
}
return new Array(_num).fill(_char).join('')
} else {
return char
}
}
const _setRulesObj = (text, index, x, y) => {
rulesObj[index].x = x
rulesObj[index].y = y
rulesObj[index].char = text
}
const inlinePaddingTop = Math.ceil((lineHeight - fontSize) / 2)
// 不超过一行
if (textWidth + ol <= w && !text.includes('\n')) {
x = x + ol
const rs = Object.keys(rulesObj)
let _text = text.split('')
if(rs) {
for (let i = 0; i < rs.length; i++) {
const index = rs[i]
const t = _text[index]
let char = _setText(rulesObj[index], t)
_text[index] = char
_setRulesObj(t, index, x + this.measureText(text.substring(0, index), fontSize), y + inlinePaddingTop)
}
_reset()
}
ctx.fillText(_text.join(''), x, y + inlinePaddingTop)
y += lineHeight
_drawLine(x, y, textWidth)
ctx.restore()
this.setBorder(box, style)
return
}
// 多行文本
const chars = text.split('')
const _y = y
let _x = x
// 逐行绘制
let line = ''
let lineIndex = 0
for(let index = 0 ; index <= chars.length; index++){
let ch = chars[index] || ''
const isLine = ch === '\n'
const isRight = ch == ''// index == chars.length
ch = isLine ? '' : ch;
let textline = line + _setText(rulesObj[index], ch)
let textWidth = this.measureText(textline, fontSize)
// 绘制行数大于最大行数,则直接跳出循环
if (lineIndex >= maxLines) {
break;
}
if(lineIndex == 0) {
textWidth = textWidth + ol
_x += ol
}
if(rulesObj[index]) {
_setRulesObj(ch, index, _x + this.measureText(line, fontSize), y + inlinePaddingTop)
}
if (textWidth > w || isLine || isRight) {
lineIndex++
line = isRight && textWidth <= w ? textline : line
if(lineIndex === maxLines && textWidth > w) {
while( this.measureText(`${line}...`, fontSize) > w) {
if (line.length <= 1) {
// 如果只有一个字符时,直接跳出循环
break;
}
line = line.substring(0, line.length - 1);
if(rulesObj[index - 1]) {
rulesObj[index - 1].char = ''
}
}
line += '...'
}
ctx.fillText(line, _x, y + inlinePaddingTop)
y += lineHeight
_drawLine(_x, y, textWidth)
line = ch
if ((y + lineHeight) > (_y + h)) break
} else {
line = textline
}
}
const rs = Object.keys(rulesObj)
if(rs) {
_reset()
}
ctx.restore()
this.setBorder(box, style)
}
async findNode(element, parent = {}, index = 0, siblings = [], source) {
let computedStyle = Object.assign({}, this.getComputedStyle(element, parent, index));
let attributes = await this.getAttributes(element)
let node = {
id: id++,
parent,
computedStyle,
rules: element.rules,
attributes: Object.assign({}, attributes),
name: element?.type || 'view',
}
if(JSON.stringify(parent) === '{}' && !element.type) {
const {left = 0, top = 0, width = 0, height = 0 } = computedStyle
node.layoutBox = {left, top, width, height }
} else {
node.layoutBox = Object.assign({left: 0, top: 0}, this.getLayoutBox(node, parent, index, siblings, source))
}
if (element?.views) {
let childrens = []
node.children = []
for (let i = 0; i < element.views.length; i++) {
let v = element.views[i]
childrens.push(await this.findNode(v, node, i, childrens, element))
}
node.children = childrens
}
return node
}
getComputedStyle(element, parent = {}, index = 0) {
const style = {}
const node = JSON.stringify(parent) == '{}' && !element.type ? element : element.css;
if(parent.computedStyle) {
for (let value of Object.keys(parent.computedStyle)){
const item = parent.computedStyle[value]
if(['color', 'fontSize', 'lineHeight', 'verticalAlign', 'fontWeight', 'textAlign'].includes(value)) {
style[value] = /em|px$/.test(item) ? toPx(item, node?.fontSize) : item
}
}
}
if(!node) return style
for (let value of Object.keys(node)) {
const item = node[value]
if(value == 'views') {
continue
}
if (['boxShadow', 'shadow'].includes(value)) {
let shadows = item.split(' ').map(v => /^\d/.test(v) ? toPx(v) : v)
style.boxShadow = shadows
continue
}
if (value.includes('border') && !value.includes('adius')) {
const prefix = value.match(/^border([BTRLa-z]+)?/)[0]
const type = value.match(/[W|S|C][a-z]+/)
let v = item.split(' ').map(v => /^\d/.test(v) ? toPx(v) : v)
if(v.length > 1) {
style[prefix] = {
[prefix + 'Width'] : v[0] || 1,
[prefix + 'Style'] : v[1] || 'solid',
[prefix + 'Color'] : v[2] || 'black'
}
} else {
style[prefix] = {
[prefix + 'Width'] : 1,
[prefix + 'Style'] : 'solid',
[prefix + 'Color'] : 'black'
}
style[prefix][prefix + type[0]] = v[0]
}
continue
}
if (['background', 'backgroundColor'].includes(value)) {
style['backgroundColor'] = item
continue
}
if(value.includes('padding') || value.includes('margin') || value.includes('adius')) {
let isRadius = value.includes('adius')
let prefix = isRadius ? 'borderRadius' : value.match(/[a-z]+/)[0]
let pre = [0,0,0,0].map((item, i) => isRadius ? ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'][i] : [prefix + 'Top', prefix + 'Right', prefix + 'Bottom', prefix + 'Left'][i] )
if(value === 'padding' || value === 'margin' || value === 'radius' || value === 'borderRadius') {
let v = item?.split(' ').map((item) => /^\d/.test(item) && toPx(item, node['width']), []) ||[0];
let type = isRadius ? 'borderRadius' : value;
if(v.length == 1) {
style[type] = v[0]
} else {
let [t, r, b, l] = v
style[type] = {
[pre[0]]: t,
[pre[1]]: isNumber(r) ? r : t,
[pre[2]]: isNumber(b) ? b : t,
[pre[3]]: isNumber(l) ? l : r
}
}
} else {
if(typeof style[prefix] === 'object') {
style[prefix][value] = toPx(item, node['width'])
} else {
style[prefix] = {
[pre[0]]: style[prefix] || 0,
[pre[1]]: style[prefix] || 0,
[pre[2]]: style[prefix] || 0,
[pre[3]]: style[prefix] || 0
}
style[prefix][value] = toPx(item, node['width'])
}
}
continue
}
if(value.includes('width') || value.includes('height')) {
if(/%$/.test(item)) {
style[value] = toPx(item, parent.layoutBox[value])
} else {
style[value] = /px|rpx$/.test(item) ? toPx(item) : item
}
continue
}
if(value.includes('transform')) {
style[value]= {}
item.replace(/([a-zA-Z]+)\(([0-9,-\.%rpxdeg\s]+)\)/g, (g1, g2, g3) => {
const v = g3.split(',').map(k => k.replace(/(^\s*)|(\s*$)/g,''))
const transform = (v, r) => {
return v.includes('deg') ? v * 1 : toPx(v, r)
}
if(g2.includes('matrix')) {
style[value][g2] = v.map(v => v * 1)
} else if(g2.includes('rotate')) {
style[value][g2] = g3.match(/\d+/)[0] * 1
}else if(/[X, Y]/.test(g2)) {
style[value][g2] = /[X]/.test(g2) ? transform(v[0], node['width']) : transform(v[0], node['height'])
} else {
style[value][g2+'X'] = transform(v[0], node['width'])
style[value][g2+'Y'] = transform(v[1] || v[0], node['height'])
}
})
continue
}
if(/em$/.test(item) && !value.includes('lineHeight')) {
style[value] = Math.ceil(parseFloat(item.replace('em')) * toPx(node['fontSize'] || 14))
} else {
style[value] = /%|px|rpx$/.test(item) ? toPx(item, node['width']) : item
}
}
if((element.name == 'image' || element.type == 'image') && !style.mode) {
style.mode = 'aspectFill'
if((!node.width || node.width == 'auto') && (!node.height || node.width == 'auto') ) {
style.mode = ''
}
}
return style
}
getLayoutBox(element, parent = {}, index = 0, siblings = [], source = {}) {
let box = {}
let {name, computedStyle: cstyle, layoutBox, attributes} = element || {}
if(!name) return box
const {ctx} = this
const pbox = parent.layoutBox || this.root
const pstyle = parent.computedStyle
let {
verticalAlign: v,
left: x,
top: y,
width: w,
height: h,
fontSize = 14,
lineHeight = '1.4em',
maxLines,
fontWeight,
fontFamily,
textStyle,
position,
display
} = cstyle;
const { paddingTop: pt = 0, paddingRight: pr = 0, paddingBottom: pb = 0, paddingLeft: pl = 0, } = cstyle.padding || {}
const { marginTop: mt = 0, marginRight: mr = 0, marginBottom: mb = 0, marginLeft: ml = 0, } = cstyle.margin || {}
if(position == 'relative') {
x += pbox.left
y += pbox.top
}
if(name === 'text') {
const text = attributes.text ||''
lineHeight = toPx(lineHeight, fontSize)
ctx.save()
this.setFont({fontFamily, fontSize, fontWeight, textStyle})
const {layoutBox: lbox, computedStyle: ls} = siblings[index - 1] || {}
const {layoutBox: rbox, computedStyle: rs} = siblings[index + 1] || {}
const isLeft = index == 0
const isblock = display === 'block' || ls?.display === 'block'
const isOnly = isLeft && !rbox || !parent?.id
const lboxR = isLeft || isblock ? 0 : lbox.offsetRight || 0
let texts = text.split('\n')
let lineIndex = 1
let line = ''
const textIndent = cstyle.textIndent || 0
if(!isOnly) {
texts.map((t, i) => {
lineIndex += i
const chars = t.split('')
for (let j = 0; j < chars.length; j++) {
let ch = chars[j]
let textline = line + ch
let textWidth = this.measureText(textline, fontSize)
if(lineIndex == 1) {
textWidth = textWidth + (isblock ? 0 : lboxR) + textIndent
}
if(textWidth > pbox.width) {
lineIndex++
line = ch
} else {
line = textline
}
}
})
} else {
line = text
lineIndex = Math.max(texts.length, Math.ceil(this.measureText(text, fontSize) / ((w || pbox.width) - this.measureText('0', fontSize))))
}
box.offsetLeft = (isNumber(x) || isblock || isOnly ? textIndent : lboxR) + pl + ml;
// 剩下的字宽度
const remain = (this.measureText(line, fontSize))
let width = lineIndex > 1 ? pbox.width : remain + box.offsetLeft;
box.offsetRight = box.offsetLeft + (w ? w : (isblock ? pbox.width : remain)) + pr + mr;
const _getLeft = () => {
return (x || pbox.left)
}
const _getWidth = () => {
return w || (isOnly ? pbox.width : (width > pbox.width - box.left || lineIndex > 1 ? pbox.width - box.left : width))
}
const _getHeight = () => {
if(h) {
return h
} else if(lineIndex > 1 ) {
return (maxLines || lineIndex) * lineHeight + pt + pb + mt + mb
} else {
return lineHeight + pt + pb + mt + mb
}
}
const _getTop = () => {
let _y = y
if(_y) {
return _y + pt + mt
}
if(isLeft) {
_y = pbox.top
} else if(lbox.width < pbox.width) {
_y = lbox.top
} else {
_y = lbox.top + lbox.height - (ls?.lineHeight || 0)
}
return _y + pt + mt + (isblock && ls?.lineHeight || 0 )
}
box.left = _getLeft()
box.width = _getWidth()
box.height = _getHeight()
box.top = _getTop()
ctx.restore()
} else if(['view', 'qrcode'].includes(name)) {
box.left = x || pbox.left
box.width = (w || pbox?.width) - pl - pr
box.height = h || 0
box.top = y || pbox.top
} else if(name === 'image') {
box.left = x || pbox.left
box.width = (w || pbox?.width) - pl - pr
const {
width: rWidth,
height: rHeight
} = attributes
box.height = h || box.width * rHeight / rWidth
box.top = y || pbox.top
}
return box
}
async getAttributes(element) {
let arr = { }
if(element?.url || element?.src) {
arr.src = element.url || element?.src;
const {width = 0, height = 0, path: src} = await getImageInfo(arr.src, this.isH5PathToBase64) || {}
arr = Object.assign({}, arr, {width, height, src})
}
if(element?.text) {
arr.text = element.text
}
return arr
}
async drawBoard(element) {
const node = await this.findNode(element)
return this.drawNode(node)
}
async drawNode(element) {
const {
layoutBox,
computedStyle,
name,
rules
} = element
const {
src,
text
} = element.attributes
if (name === 'view') {
this.drawView(layoutBox, computedStyle)
} else if (name === 'image' && src) {
await this.drawImage(element.attributes, layoutBox, computedStyle, false)
} else if (name === 'text') {
this.drawText(text, layoutBox, computedStyle, rules)
} else if (name === 'qrcode') {
QR.api.draw(text, this, layoutBox, computedStyle)
}
if (!element.children) return
const childs = Object.values ? Object.values(element.children) : Object.keys(element.children).map((key) => element.children[key]);
for (const child of childs) {
await this.drawNode(child)
}
}
}
\ No newline at end of file
/* eslint-disable */
export const GD = {
isGradient(bg) {
if (bg && (bg.startsWith('linear') || bg.startsWith('radial'))) {
return true;
}
return false;
},
doGradient(bg, width, height, ctx) {
if (bg.startsWith('linear')) {
linearEffect(width, height, bg, ctx);
} else if (bg.startsWith('radial')) {
radialEffect(width, height, bg, ctx);
}
},
}
function analizeGrad(string) {
const colorPercents = string.substring(0, string.length - 1).split("%,");
const colors = [];
const percents = [];
for (let colorPercent of colorPercents) {
colors.push(colorPercent.substring(0, colorPercent.lastIndexOf(" ")).trim());
percents.push(colorPercent.substring(colorPercent.lastIndexOf(" "), colorPercent.length) / 100);
}
return {
colors: colors,
percents: percents
};
}
function radialEffect(width, height, bg, ctx) {
const colorPer = analizeGrad(bg.match(/radial-gradient\((.+)\)/)[1]);
const grd = ctx.createCircularGradient(0, 0, width < height ? height / 2 : width / 2);
for (let i = 0; i < colorPer.colors.length; i++) {
grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
}
ctx.setFillStyle(grd);
}
function analizeLinear(bg, width, height) {
const direction = bg.match(/([-]?\d{1,3})deg/);
const dir = direction && direction[1] ? parseFloat(direction[1]) : 0;
let coordinate;
switch (dir) {
case 0:
coordinate = [0, -height / 2, 0, height / 2];
break;
case 90:
coordinate = [width / 2, 0, -width / 2, 0];
break;
case -90:
coordinate = [-width / 2, 0, width / 2, 0];
break;
case 180:
coordinate = [0, height / 2, 0, -height / 2];
break;
case -180:
coordinate = [0, -height / 2, 0, height / 2];
break;
default:
let x1 = 0;
let y1 = 0;
let x2 = 0;
let y2 = 0;
if (direction[1] > 0 && direction[1] < 90) {
x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
} else if (direction[1] > -180 && direction[1] < -90) {
x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
} else if (direction[1] > 90 && direction[1] < 180) {
x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
} else {
x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 *
(90 - direction[1]) * Math.PI * 2 / 360) / 2;
y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
x2 = -x1;
y1 = -y2;
}
coordinate = [x1, y1, x2, y2];
break;
}
return coordinate;
}
function linearEffect(width, height, bg, ctx) {
const param = analizeLinear(bg, width, height);
const grd = ctx.createLinearGradient(param[0], param[1], param[2], param[3]);
const content = bg.match(/linear-gradient\((.+)\)/)[1];
const colorPer = analizeGrad(content.substring(content.indexOf(',') + 1));
for (let i = 0; i < colorPer.colors.length; i++) {
grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
}
ctx.setFillStyle(grd);
}
<template>
<canvas v-if="use2dCanvas" :id="canvasId" type="2d" :style="style"></canvas>
<canvas v-else :canvas-id="canvasId" :style="style" :id="canvasId" :width="boardWidth * dpr" :height="boardHeight * dpr"></canvas>
</template>
<script>
import { toPx, base64ToPath, compareVersion} from './utils';
import { Draw } from './draw';
import { adaptor } from './canvas';
export default {
// version: '1.5.9.2',
name: 'l-painter',
props: {
board: Object,
fileType: {
type: String,
default: 'png'
},
width: [Number, String],
height: [Number, String],
pixelRatio: Number,
customStyle: String,
isRenderImage: Boolean,
isBase64ToPath: Boolean,
isH5PathToBase64: Boolean,
sleep: {
type: Number,
default: 1000/30
},
type: {
type: String,
default: '2d',
}
},
data() {
return {
// #ifndef MP-WEIXIN || MP-QQ
canvasId: `l-painter_${this._uid}`,
// #endif
// #ifdef MP-WEIXIN || MP-QQ
canvasId: `l-painter`,
// #endif
// #ifdef MP-WEIXIN
use2dCanvas: true,
// #endif
// #ifndef MP-WEIXIN
use2dCanvas: false,
// #endif
draw: null,
ctx: null
};
},
computed: {
newboard() {
return this.board && JSON.parse(JSON.stringify(this.board))
},
style() {
return `width:${this.boardWidth}px; height: ${this.boardHeight}px; ${this.customStyle}`;
},
dpr() {
return this.pixelRatio || uni.getSystemInfoSync().pixelRatio;
},
boardWidth() {
const { width = 200 } = this.board || {};
return toPx(this.width || width);
},
boardHeight() {
const { height = 200 } = this.board || {};
return toPx(this.height || height);
}
},
mounted() {
// #ifdef MP-WEIXIN
const {SDKVersion} = wx.getSystemInfoSync()
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0;
// #endif
this.$watch('newboard', async (val, old) => {
if (JSON.stringify(val) === '{}' || !val) return;
const {width: w, height: h} = val || {};
const {width: ow, height: oh} = old || {};
if(w !== ow || h !== oh) {
this.inited = false;
}
this.render();
}, {
deep: true,
immediate: true,
})
},
methods: {
async render(args = {}, single = false) {
const ctx = await this.getContext()
const { use2dCanvas, boardWidth, boardHeight, board, canvas, isBase64ToPath, isH5PathToBase64, sleep } = this;
if (use2dCanvas && !canvas) {
return Promise.reject(new Error('render: fail canvas has not been created'));
}
if(!this.boundary) {
this.boundary = {
top: 0,
left: 0,
width: boardWidth,
height: boardHeight,
sleep
}
}
if(!single) {
ctx.clearRect(0, 0, boardWidth, boardHeight);
}
if(!this.draw) {
this.draw = new Draw(ctx, canvas, use2dCanvas, isH5PathToBase64, this.boundary);
}
if(JSON.stringify(args) != '{}' || board && JSON.stringify(board) != '{}') {
await this.draw.drawBoard(JSON.stringify(args) != '{}' ? args : board);
}
await new Promise(resolve => this.$nextTick(resolve))
if (!use2dCanvas && !single) {
await this.canvasDraw(ctx);
}
this.$emit('done')
if(this.isRenderImage && !single) {
this.canvasToTempFilePath()
.then(async res => {
if(/^data:image\/(\w+);base64/.test(res.tempFilePath) && isBase64ToPath) {
const img = await base64ToPath(res.tempFilePath)
this.$emit('success', img)
} else {
this.$emit('success', res.tempFilePath)
}
})
.catch(err => {
this.$emit('fail', err)
new Error(JSON.stringify(err))
console.error(JSON.stringify(err))
})
}
return Promise.resolve({ctx, draw: this.draw});
},
async custom(cb) {
const {ctx, draw} = await this.render({}, true)
ctx.save()
await cb(ctx, draw)
ctx.restore()
return Promise.resolve(true);
},
async single(args = {}) {
await this.render(args, true)
return Promise.resolve(true);
},
canvasDraw(flag = false) {
const {ctx} = this
return new Promise(resolve => {
ctx.draw(flag, () => {
resolve(true);
});
});
},
async getContext() {
if(this.ctx && this.inited) {
return Promise.resolve(this.ctx)
};
const { type, use2dCanvas, dpr, boardWidth, boardHeight } = this;
const _getContext = () => {
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select('#' + this.canvasId)
.boundingClientRect()
.exec(res => {
if(res) {
const ctx = uni.createCanvasContext(this.canvasId, this);
if (!this.inited) {
this.inited = true;
this.use2dCanvas = false;
this.canvas = res
}
// #ifdef MP-ALIPAY
ctx.scale(dpr, dpr);
// #endif
this.ctx = ctx
resolve(ctx);
}
})
})
}
// #ifndef MP-WEIXIN
return _getContext()
// #endif
if(!use2dCanvas) {
return _getContext()
}
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select('#l-painter')
.node()
.exec(res => {
const canvas = res[0].node;
if(!canvas) {
this.use2dCanvas = false;
return this.getContext()
}
const ctx = canvas.getContext(type);
if (!this.inited) {
this.inited = true;
canvas.width = boardWidth * dpr;
canvas.height = boardHeight * dpr;
this.use2dCanvas = true;
this.canvas = canvas
ctx.scale(dpr, dpr);
}
this.ctx = adaptor(ctx)
resolve(adaptor(ctx));
});
});
},
canvasToTempFilePath(args = {}) {
const {use2dCanvas, canvasId} = this
return new Promise((resolve, reject) => {
let { top = 0, left = 0, width, height } = this.boundary || this
let destWidth = width * this.dpr
let destHeight = height * this.dpr
// #ifdef MP-ALIPAY
width = width * this.dpr
height = height * this.dpr
// #endif
const copyArgs = {
x: left,
y: top,
width,
height,
destWidth,
destHeight,
canvasId,
fileType: args.fileType || this.fileType,
quality: args.quality || 1,
success: resolve,
fail: reject
}
if (use2dCanvas) {
delete copyArgs.canvasId
copyArgs.canvas = this.canvas
}
uni.canvasToTempFilePath(copyArgs, this)
})
}
}
};
</script>
<style></style>
/* eslint-disable */
!(function () {
// alignment pattern
let adelta = [
0, 11, 15, 19, 23, 27, 31,
16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
];
// version block
let vpat = [
0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d,
0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9,
0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75,
0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64,
0x541, 0xc69
];
// final format bits with mask: level << 3 | mask
let fmtword = [
0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L
0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M
0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q
0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b //H
];
// 4 per version: number of blocks 1,2; data width; ecc width
let eccblocks = [
1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,
1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,
1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,
1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,
1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,
2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,
2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,
2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,
2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,
2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,
4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,
2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,
4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,
3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,
5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,
5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30,
1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28,
5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28,
3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26,
3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28,
4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,
2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24,
4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30,
6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30,
8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30,
10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,
8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30,
3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30,
7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30,
5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30,
13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30,
17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30,
17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30,
13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,
12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30,
6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30,
17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30,
4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30,
20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30,
19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30
];
// Galois field log table
let glog = [
0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
];
// Galios field exponent table
let gexp = [
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
];
// Working buffers:
// data input and ecc append, image working buffer, fixed part of image, run lengths for badness
let strinbuf = [], eccbuf = [], qrframe = [], framask = [], rlens = [];
// Control values - width is based on version, last 4 are from table.
let version, width, neccblk1, neccblk2, datablkw, eccblkwid;
let ecclevel = 2;
// set bit to indicate cell in qrframe is immutable. symmetric around diagonal
function setmask(x, y) {
let bt;
if (x > y) {
bt = x;
x = y;
y = bt;
}
// y*y = 1+3+5...
bt = y;
bt *= y;
bt += y;
bt >>= 1;
bt += x;
framask[bt] = 1;
}
// enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
function putalign(x, y) {
let j;
qrframe[x + width * y] = 1;
for (j = -2; j < 2; j++) {
qrframe[(x + j) + width * (y - 2)] = 1;
qrframe[(x - 2) + width * (y + j + 1)] = 1;
qrframe[(x + 2) + width * (y + j)] = 1;
qrframe[(x + j + 1) + width * (y + 2)] = 1;
}
for (j = 0; j < 2; j++) {
setmask(x - 1, y + j);
setmask(x + 1, y - j);
setmask(x - j, y - 1);
setmask(x + j, y + 1);
}
}
//========================================================================
// Reed Solomon error correction
// exponentiation mod N
function modnn(x) {
while (x >= 255) {
x -= 255;
x = (x >> 8) + (x & 255);
}
return x;
}
let genpoly = [];
// Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
function appendrs(data, dlen, ecbuf, eclen) {
let i, j, fb;
for (i = 0; i < eclen; i++)
strinbuf[ecbuf + i] = 0;
for (i = 0; i < dlen; i++) {
fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]];
if (fb != 255) /* fb term is non-zero */
for (j = 1; j < eclen; j++)
strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])];
else
for (j = ecbuf; j < ecbuf + eclen; j++)
strinbuf[j] = strinbuf[j + 1];
strinbuf[ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])];
}
}
//========================================================================
// Frame data insert following the path rules
// check mask - since symmetrical use half.
function ismasked(x, y) {
let bt;
if (x > y) {
bt = x;
x = y;
y = bt;
}
bt = y;
bt += y * y;
bt >>= 1;
bt += x;
return framask[bt];
}
//========================================================================
// Apply the selected mask out of the 8.
function applymask(m) {
let x, y, r3x, r3y;
switch (m) {
case 0:
for (y = 0; y < width; y++)
for (x = 0; x < width; x++)
if (!((x + y) & 1) && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
break;
case 1:
for (y = 0; y < width; y++)
for (x = 0; x < width; x++)
if (!(y & 1) && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
break;
case 2:
for (y = 0; y < width; y++)
for (r3x = 0, x = 0; x < width; x++ , r3x++) {
if (r3x == 3)
r3x = 0;
if (!r3x && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
}
break;
case 3:
for (r3y = 0, y = 0; y < width; y++ , r3y++) {
if (r3y == 3)
r3y = 0;
for (r3x = r3y, x = 0; x < width; x++ , r3x++) {
if (r3x == 3)
r3x = 0;
if (!r3x && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
}
}
break;
case 4:
for (y = 0; y < width; y++)
for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < width; x++ , r3x++) {
if (r3x == 3) {
r3x = 0;
r3y = !r3y;
}
if (!r3y && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
}
break;
case 5:
for (r3y = 0, y = 0; y < width; y++ , r3y++) {
if (r3y == 3)
r3y = 0;
for (r3x = 0, x = 0; x < width; x++ , r3x++) {
if (r3x == 3)
r3x = 0;
if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
}
}
break;
case 6:
for (r3y = 0, y = 0; y < width; y++ , r3y++) {
if (r3y == 3)
r3y = 0;
for (r3x = 0, x = 0; x < width; x++ , r3x++) {
if (r3x == 3)
r3x = 0;
if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
}
}
break;
case 7:
for (r3y = 0, y = 0; y < width; y++ , r3y++) {
if (r3y == 3)
r3y = 0;
for (r3x = 0, x = 0; x < width; x++ , r3x++) {
if (r3x == 3)
r3x = 0;
if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) && !ismasked(x, y))
qrframe[x + y * width] ^= 1;
}
}
break;
}
return;
}
// Badness coefficients.
let N1 = 3, N2 = 3, N3 = 40, N4 = 10;
// Using the table of the length of each run, calculate the amount of bad image
// - long runs or those that look like finders; called twice, once each for X and Y
function badruns(length) {
let i;
let runsbad = 0;
for (i = 0; i <= length; i++)
if (rlens[i] >= 5)
runsbad += N1 + rlens[i] - 5;
// BwBBBwB as in finder
for (i = 3; i < length - 1; i += 2)
if (rlens[i - 2] == rlens[i + 2]
&& rlens[i + 2] == rlens[i - 1]
&& rlens[i - 1] == rlens[i + 1]
&& rlens[i - 1] * 3 == rlens[i]
// white around the black pattern? Not part of spec
&& (rlens[i - 3] == 0 // beginning
|| i + 3 > length // end
|| rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4)
)
runsbad += N3;
return runsbad;
}
// Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
function badcheck() {
let x, y, h, b, b1;
let thisbad = 0;
let bw = 0;
// blocks of same color.
for (y = 0; y < width - 1; y++)
for (x = 0; x < width - 1; x++)
if ((qrframe[x + width * y] && qrframe[(x + 1) + width * y]
&& qrframe[x + width * (y + 1)] && qrframe[(x + 1) + width * (y + 1)]) // all black
|| !(qrframe[x + width * y] || qrframe[(x + 1) + width * y]
|| qrframe[x + width * (y + 1)] || qrframe[(x + 1) + width * (y + 1)])) // all white
thisbad += N2;
// X runs
for (y = 0; y < width; y++) {
rlens[0] = 0;
for (h = b = x = 0; x < width; x++) {
if ((b1 = qrframe[x + width * y]) == b)
rlens[h]++;
else
rlens[++h] = 1;
b = b1;
bw += b ? 1 : -1;
}
thisbad += badruns(h);
}
// black/white imbalance
if (bw < 0)
bw = -bw;
let big = bw;
let count = 0;
big += big << 2;
big <<= 1;
while (big > width * width)
big -= width * width, count++;
thisbad += count * N4;
// Y runs
for (x = 0; x < width; x++) {
rlens[0] = 0;
for (h = b = y = 0; y < width; y++) {
if ((b1 = qrframe[x + width * y]) == b)
rlens[h]++;
else
rlens[++h] = 1;
b = b1;
}
thisbad += badruns(h);
}
return thisbad;
}
function genframe(instring) {
let x, y, k, t, v, i, j, m;
// find the smallest version that fits the string
t = instring.length;
version = 0;
do {
version++;
k = (ecclevel - 1) * 4 + (version - 1) * 16;
neccblk1 = eccblocks[k++];
neccblk2 = eccblocks[k++];
datablkw = eccblocks[k++];
eccblkwid = eccblocks[k];
k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9);
if (t <= k)
break;
} while (version < 40);
// FIXME - insure that it fits insted of being truncated
width = 17 + 4 * version;
// allocate, clear and setup data structures
v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
for (t = 0; t < v; t++)
eccbuf[t] = 0;
strinbuf = instring.slice(0);
for (t = 0; t < width * width; t++)
qrframe[t] = 0;
for (t = 0; t < (width * (width + 1) + 1) / 2; t++)
framask[t] = 0;
// insert finders - black to frame, white to mask
for (t = 0; t < 3; t++) {
k = 0;
y = 0;
if (t == 1)
k = (width - 7);
if (t == 2)
y = (width - 7);
qrframe[(y + 3) + width * (k + 3)] = 1;
for (x = 0; x < 6; x++) {
qrframe[(y + x) + width * k] = 1;
qrframe[y + width * (k + x + 1)] = 1;
qrframe[(y + 6) + width * (k + x)] = 1;
qrframe[(y + x + 1) + width * (k + 6)] = 1;
}
for (x = 1; x < 5; x++) {
setmask(y + x, k + 1);
setmask(y + 1, k + x + 1);
setmask(y + 5, k + x);
setmask(y + x + 1, k + 5);
}
for (x = 2; x < 4; x++) {
qrframe[(y + x) + width * (k + 2)] = 1;
qrframe[(y + 2) + width * (k + x + 1)] = 1;
qrframe[(y + 4) + width * (k + x)] = 1;
qrframe[(y + x + 1) + width * (k + 4)] = 1;
}
}
// alignment blocks
if (version > 1) {
t = adelta[version];
y = width - 7;
for (; ;) {
x = width - 7;
while (x > t - 3) {
putalign(x, y);
if (x < t)
break;
x -= t;
}
if (y <= t + 9)
break;
y -= t;
putalign(6, y);
putalign(y, 6);
}
}
// single black
qrframe[8 + width * (width - 8)] = 1;
// timing gap - mask only
for (y = 0; y < 7; y++) {
setmask(7, y);
setmask(width - 8, y);
setmask(7, y + width - 7);
}
for (x = 0; x < 8; x++) {
setmask(x, 7);
setmask(x + width - 8, 7);
setmask(x, width - 8);
}
// reserve mask-format area
for (x = 0; x < 9; x++)
setmask(x, 8);
for (x = 0; x < 8; x++) {
setmask(x + width - 8, 8);
setmask(8, x);
}
for (y = 0; y < 7; y++)
setmask(8, y + width - 7);
// timing row/col
for (x = 0; x < width - 14; x++)
if (x & 1) {
setmask(8 + x, 6);
setmask(6, 8 + x);
}
else {
qrframe[(8 + x) + width * 6] = 1;
qrframe[6 + width * (8 + x)] = 1;
}
// version block
if (version > 6) {
t = vpat[version - 7];
k = 17;
for (x = 0; x < 6; x++)
for (y = 0; y < 3; y++ , k--)
if (1 & (k > 11 ? version >> (k - 12) : t >> k)) {
qrframe[(5 - x) + width * (2 - y + width - 11)] = 1;
qrframe[(2 - y + width - 11) + width * (5 - x)] = 1;
}
else {
setmask(5 - x, 2 - y + width - 11);
setmask(2 - y + width - 11, 5 - x);
}
}
// sync mask bits - only set above for white spaces, so add in black bits
for (y = 0; y < width; y++)
for (x = 0; x <= y; x++)
if (qrframe[x + width * y])
setmask(x, y);
// convert string to bitstream
// 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
v = strinbuf.length;
// string to array
for (i = 0; i < v; i++)
eccbuf[i] = strinbuf.charCodeAt(i);
strinbuf = eccbuf.slice(0);
// calculate max string length
x = datablkw * (neccblk1 + neccblk2) + neccblk2;
if (v >= x - 2) {
v = x - 2;
if (version > 9)
v--;
}
// shift and repack to insert length prefix
i = v;
if (version > 9) {
strinbuf[i + 2] = 0;
strinbuf[i + 3] = 0;
while (i--) {
t = strinbuf[i];
strinbuf[i + 3] |= 255 & (t << 4);
strinbuf[i + 2] = t >> 4;
}
strinbuf[2] |= 255 & (v << 4);
strinbuf[1] = v >> 4;
strinbuf[0] = 0x40 | (v >> 12);
}
else {
strinbuf[i + 1] = 0;
strinbuf[i + 2] = 0;
while (i--) {
t = strinbuf[i];
strinbuf[i + 2] |= 255 & (t << 4);
strinbuf[i + 1] = t >> 4;
}
strinbuf[1] |= 255 & (v << 4);
strinbuf[0] = 0x40 | (v >> 4);
}
// fill to end with pad pattern
i = v + 3 - (version < 10);
while (i < x) {
strinbuf[i++] = 0xec;
// buffer has room if (i == x) break;
strinbuf[i++] = 0x11;
}
// calculate and append ECC
// calculate generator polynomial
genpoly[0] = 1;
for (i = 0; i < eccblkwid; i++) {
genpoly[i + 1] = 1;
for (j = i; j > 0; j--)
genpoly[j] = genpoly[j]
? genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1];
genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)];
}
for (i = 0; i <= eccblkwid; i++)
genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
// append ecc to data buffer
k = x;
y = 0;
for (i = 0; i < neccblk1; i++) {
appendrs(y, datablkw, k, eccblkwid);
y += datablkw;
k += eccblkwid;
}
for (i = 0; i < neccblk2; i++) {
appendrs(y, datablkw + 1, k, eccblkwid);
y += datablkw + 1;
k += eccblkwid;
}
// interleave blocks
y = 0;
for (i = 0; i < datablkw; i++) {
for (j = 0; j < neccblk1; j++)
eccbuf[y++] = strinbuf[i + j * datablkw];
for (j = 0; j < neccblk2; j++)
eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
}
for (j = 0; j < neccblk2; j++)
eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
for (i = 0; i < eccblkwid; i++)
for (j = 0; j < neccblk1 + neccblk2; j++)
eccbuf[y++] = strinbuf[x + i + j * eccblkwid];
strinbuf = eccbuf;
// pack bits into frame avoiding masked area.
x = y = width - 1;
k = v = 1; // up, minus
/* inteleaved data and ecc codes */
m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
for (i = 0; i < m; i++) {
t = strinbuf[i];
for (j = 0; j < 8; j++ , t <<= 1) {
if (0x80 & t)
qrframe[x + width * y] = 1;
do { // find next fill position
if (v)
x--;
else {
x++;
if (k) {
if (y != 0)
y--;
else {
x -= 2;
k = !k;
if (x == 6) {
x--;
y = 9;
}
}
}
else {
if (y != width - 1)
y++;
else {
x -= 2;
k = !k;
if (x == 6) {
x--;
y -= 8;
}
}
}
}
v = !v;
} while (ismasked(x, y));
}
}
// save pre-mask copy of frame
strinbuf = qrframe.slice(0);
t = 0; // best
y = 30000; // demerit
// for instead of while since in original arduino code
// if an early mask was "good enough" it wouldn't try for a better one
// since they get more complex and take longer.
for (k = 0; k < 8; k++) {
applymask(k); // returns black-white imbalance
x = badcheck();
if (x < y) { // current mask better than previous best?
y = x;
t = k;
}
if (t == 7)
break; // don't increment i to a void redoing mask
qrframe = strinbuf.slice(0); // reset for next pass
}
if (t != k) // redo best mask - none good enough, last wasn't t
applymask(t);
// add in final mask/ecclevel bytes
y = fmtword[t + ((ecclevel - 1) << 3)];
// low byte
for (k = 0; k < 8; k++ , y >>= 1)
if (y & 1) {
qrframe[(width - 1 - k) + width * 8] = 1;
if (k < 6)
qrframe[8 + width * k] = 1;
else
qrframe[8 + width * (k + 1)] = 1;
}
// high byte
for (k = 0; k < 7; k++ , y >>= 1)
if (y & 1) {
qrframe[8 + width * (width - 7 + k)] = 1;
if (k)
qrframe[(6 - k) + width * 8] = 1;
else
qrframe[7 + width * 8] = 1;
}
return qrframe;
}
let _canvas = null;
let api = {
get ecclevel() {
return ecclevel;
},
set ecclevel(val) {
ecclevel = val;
},
get size() {
return _size;
},
set size(val) {
_size = val
},
get canvas() {
return _canvas;
},
set canvas(el) {
_canvas = el;
},
getFrame(string) {
return genframe(string);
},
//这里的utf16to8(str)是对Text中的字符串进行转码,让其支持中文
utf16to8(str) {
let out, i, len, c;
out = "";
len = str.length;
for (i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
} else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
},
draw(str, $this, box, style, ecc) {
const {ctx} = $this
let {
left: startX,
top: startY,
width: cavW,
height: cavH
} = box
const {
borderRadius = 0,
backgroundColor: bg,
color = '#000000',
border
} = style
const { borderWidth: bw } = border || {}
let that = this;
ecclevel = ecc || ecclevel;
if (!ctx) {
console.warn('No canvas provided to draw QR code in!')
return;
}
ctx.save()
if(bw) {
cavW = cavW - bw
cavH = cavH - bw
}
let size = Math.min(cavW, cavH);
//增加中文显示
str = that.utf16to8(str);
let frame = that.getFrame(str);
let px = size / width;
$this.setOpacity(style)
$this.setTransform(box, style)
startX = -cavW/2,
startY = -cavH/2
if (bg) {
$this.setBackground(bg, cavW, cavH)
$this.roundRect(startX, startY, cavW, cavH, borderRadius, true, false)
}
ctx.setFillStyle(color)
for (let i = 0; i < width; i++) {
for (let j = 0; j < width; j++) {
if (frame[j * width + i]) {
ctx.fillRect(startX + px * i, startY + px * j, px, px);
}
}
}
ctx.restore()
$this.setBorder(box, style)
}
}
module.exports = { api }
})();
\ No newline at end of file
const screen = uni.getSystemInfoSync().windowWidth / 750;
// 缓存图片
let cache = {}
export function isNumber(value) {
return /^-?\d+(\.\d+)?$/.test(value);
}
export function toPx(value, baseSize) {
// 如果是数字
if (typeof value === 'number') {
return value
}
// 如果是字符串数字
if (isNumber(value)) {
return value * 1
}
// 如果有单位
if (typeof value === 'string') {
const reg = /^-?[0-9]+([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g
const results = reg.exec(value);
if (!value || !results) {
return 0;
}
const unit = results[2];
value = parseFloat(value);
let res = 0;
if (unit === 'rpx') {
res = Math.floor(value * (screen || 0.5) * 1);
} else if (unit === 'px') {
res = Math.floor(value * 1);
} else if (unit === '%') {
res = Math.floor(value * toPx(baseSize) / 100);
} else if (unit === 'em') {
res = Math.ceil(value * toPx(baseSize || 14));
}
return res;
}
}
// 计算版本
export function compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i], 10)
const num2 = parseInt(v2[i], 10)
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
/** 从 0x20 开始到 0x80 的字符宽度数据 */
export const CHAR_WIDTH_SCALE_MAP = [0.296, 0.313, 0.436, 0.638, 0.586, 0.89, 0.87, 0.256, 0.334, 0.334, 0.455, 0.742,
0.241, 0.433, 0.241, 0.427, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.241, 0.241, 0.742,
0.742, 0.742, 0.483, 1.031, 0.704, 0.627, 0.669, 0.762, 0.55, 0.531, 0.744, 0.773, 0.294, 0.396, 0.635, 0.513, 0.977,
0.813, 0.815, 0.612, 0.815, 0.653, 0.577, 0.573, 0.747, 0.676, 1.018, 0.645, 0.604, 0.62, 0.334, 0.416, 0.334, 0.742,
0.448, 0.295, 0.553, 0.639, 0.501, 0.64, 0.567, 0.347, 0.64, 0.616, 0.266, 0.267, 0.544, 0.266, 0.937, 0.616, 0.636,
0.639, 0.64, 0.382, 0.463, 0.373, 0.616, 0.525, 0.79, 0.507, 0.529, 0.492, 0.334, 0.269, 0.334, 0.742, 0.296
];
// #ifdef MP
const prefix = () => {
// #ifdef MP-TOUTIAO
return tt
// #endif
// #ifdef MP-WEIXIN
return wx
// #endif
// #ifdef MP-BAIDU
return swan
// #endif
// #ifdef MP-ALIPAY
return my
// #endif
// #ifdef MP-QQ
return qq
// #endif
// #ifdef MP-360
return qh
// #endif
}
const base64ToArrayBuffer = (data) => {
/**
* base64ToArrayBuffer
* Base64Binary.decode(base64_string);
* Base64Binary.decodeArrayBuffer(base64_string);
*/
const Base64Binary = {
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
/* will return a Uint8Array type */
decodeArrayBuffer(input) {
const bytes = (input.length/4) * 3;
const ab = new ArrayBuffer(bytes);
this.decode(input, ab);
return ab;
},
removePaddingChars(input) {
const lkey = this._keyStr.indexOf(input.charAt(input.length - 1));
if(lkey == 64){
return input.substring(0,input.length - 1);
}
return input;
},
decode(input, arrayBuffer) {
//get last chars to see if are valid
input = this.removePaddingChars(input);
input = this.removePaddingChars(input);
const bytes = parseInt((input.length / 4) * 3, 10);
let uarray;
let chr1, chr2, chr3;
let enc1, enc2, enc3, enc4;
let i = 0;
let j = 0;
if (arrayBuffer)
uarray = new Uint8Array(arrayBuffer);
else
uarray = new Uint8Array(bytes);
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
for (i=0; i<bytes; i+=3) {
//get the 3 octects in 4 ascii chars
enc1 = this._keyStr.indexOf(input.charAt(j++));
enc2 = this._keyStr.indexOf(input.charAt(j++));
enc3 = this._keyStr.indexOf(input.charAt(j++));
enc4 = this._keyStr.indexOf(input.charAt(j++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
uarray[i] = chr1;
if (enc3 != 64) uarray[i+1] = chr2;
if (enc4 != 64) uarray[i+2] = chr3;
}
return uarray;
}
}
return (uni.base64ToArrayBuffer && uni.base64ToArrayBuffer(data)) || Base64Binary.decodeArrayBuffer(data)
}
// #endif
/**
* base64转路径
* @param {Object} base64
*/
export function base64ToPath(base64) {
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
return new Promise((resolve, reject) => {
// #ifdef MP
const fs = uni.getFileSystemManager()
//自定义文件名
if (!format) {
console.error('ERROR_BASE64SRC_PARSE')
reject(new Error('ERROR_BASE64SRC_PARSE'))
}
const time = new Date().getTime();
let pre = prefix()
const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}`
let buffer = base64ToArrayBuffer(bodyData)
fs.writeFile({
filePath,
data: buffer,
encoding: 'binary',
success() {
resolve(filePath)
},
fail(err) {
console.error('获取base64图片失败', JSON.stringify(err))
reject(err)
}
})
// #endif
// #ifdef H5
// mime类型
let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
//base64 解码
let byteString = atob(base64.split(',')[1]);
//创建缓冲数组
let arrayBuffer = new ArrayBuffer(byteString.length);
//创建视图
let intArray = new Uint8Array(arrayBuffer);
for (let i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
resolve(URL.createObjectURL(new Blob([intArray], { type: mimeString })))
// #endif
// #ifdef APP-PLUS
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
bitmap.loadBase64Data(base64, () => {
if (!format) {
console.error('ERROR_BASE64SRC_PARSE')
reject(new Error('ERROR_BASE64SRC_PARSE'))
}
const time = new Date().getTime();
const filePath = `_doc/uniapp_temp/${time}.${format}`
bitmap.save(filePath, {},
() => {
bitmap.clear()
resolve(filePath)
},
(error) => {
bitmap.clear()
console.error(`${JSON.stringify(error)}`)
reject(error)
})
}, (error) => {
bitmap.clear()
console.error(`${JSON.stringify(error)}`)
reject(error)
})
// #endif
})
}
/**
* 路径转base64
* @param {Object} string
*/
export function pathToBase64(path) {
return new Promise((resolve, reject) => {
// #ifdef H5
const _canvas = ()=> {
let image = new Image();
image.onload = function() {
let canvas = document.createElement('canvas');
// 获取图片原始宽高
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
// 将图片插入画布并开始绘制
canvas.getContext('2d').drawImage(image, 0, 0);
let result = canvas.toDataURL('image/png')
resolve(result);
canvas.height = canvas.width = 0
}
image.src = path
image.setAttribute("crossOrigin",'Anonymous');
image.src = path;
image.onerror = (error) => {
console.error(`urlToBase64 error: ${path}`, JSON.stringify(error))
reject(new Error('urlToBase64 error'));
};
}
const _fileReader = (blob) => {
const fileReader = new FileReader();
fileReader.onload = (e) => {
resolve(e.target.result);
};
fileReader.readAsDataURL(blob);
fileReader.onerror = (error) => {
console.error('blobToBase64 error:', JSON.stringify(error))
reject(new Error('blobToBase64 error'));
};
}
const isFileReader = typeof FileReader === 'function'
if(/^(http|\/\/)/.test(path) && isFileReader ) {
window.URL = window.URL || window.webkitURL;
const xhr = new XMLHttpRequest();
xhr.open("get", path, true);
xhr.timeout = 2000;
xhr.responseType = "blob";
xhr.onload = function() {
if(this.status == 200) {
_fileReader(this.response)
} else {
_canvas()
}
}
xhr.onreadystatechange = function() {
if(this.status === 0) {
_canvas()
}
}
xhr.send();
} else if(/^blob/.test(path) && isFileReader){
_fileReader(path)
} else {
_canvas()
}
// #endif
// #ifdef MP
if(uni.canIUse('getFileSystemManager')) {
uni.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: (res) => {
resolve('data:image/png;base64,' + res.data)
},
fail: (error) => {
console.error('urlToBase64 error:', JSON.stringify(error))
reject(error)
}
})
}
// #endif
// #ifdef APP-PLUS
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.onload = (data) => {
resolve(data.target.result)
}
fileReader.onerror = (error) => {
console.error('pathToBase64 error:', JSON.stringify(error))
reject(error)
}
fileReader.readAsDataURL(file)
}, (error) => {
console.error('pathToBase64 error:', JSON.stringify(error))
reject(error)
})
}, (error) => {
console.error('pathToBase64 error:', JSON.stringify(error))
reject(error)
})
// #endif
})
}
// #ifdef APP-PLUS
const getLocalFilePath = (path)=> {
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
return path
}
if (path.indexOf('file://') === 0) {
return path
}
if (path.indexOf('/storage/emulated/0/') === 0) {
return path
}
if (path.indexOf('/') === 0) {
const localFilePath = plus.io.convertAbsoluteFileSystem(path)
if (localFilePath !== path) {
return localFilePath
} else {
path = path.substr(1)
}
}
return '_www/' + path
}
// #endif
export function getImageInfo(img, isH5PathToBase64) {
return new Promise(async (resolve, reject) => {
const base64Reg = /^data:image\/(\w+);base64/
const localReg = /^\.|^\/(?=[^\/])/;
const networkReg = /^(http|\/\/)/
// #ifdef H5
if(networkReg.test(img) && isH5PathToBase64) {
img = await pathToBase64(img)
}
// #endif
// #ifndef MP-ALIPAY
if(base64Reg.test(img)) {
if(!cache[img]) {
const imgName = img
img = await base64ToPath(img)
cache[imgName] = img
} else {
img = cache[img]
}
}
// #endif
if(cache[img] && cache[img].errMsg) {
resolve(cache[img])
} else {
uni.getImageInfo({
src: img,
success: (image) => {
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
image.path = localReg.test(img) ? `/${image.path}` : image.path;
// #endif
// image.path = /^(http|\/\/|\/|wxfile|data:image\/(\w+);base64|file|bdfile|ttfile|blob)/.test(image.path) ? image.path : `/${image.path}`;
cache[img] = image
resolve(cache[img])
},
fail(err) {
resolve({path: img})
console.error(`getImageInfo:fail ${img} failed ${JSON.stringify(err)}`);
}
})
}
})
}
\ No newline at end of file
<template>
<view class="simple-address" v-if="showPopup" @touchmove.stop.prevent="clear">
<!-- 遮罩层 -->
<view class="simple-address-mask" @touchmove.stop.prevent="clear" v-if="maskClick" :class="[ani + '-mask', animation ? 'mask-ani' : '']"
:style="{
'background-color': maskBgColor
}" @tap="hideMask(true)"></view>
<view class="simple-address-content simple-address--fixed" :class="[type, ani + '-content', animation ? 'content-ani' : '']">
<view class="simple-address__header">
<view class="simple-address__header-btn-box" @click="pickerCancel">
<text class="simple-address__header-text" :style="{ color: cancelColor, fontSize: btnFontSize }">取消</text>
</view>
<view class="simple-address__header-btn-box" @click="pickerConfirm">
<text class="simple-address__header-text" :style="{ color: confirmColor || themeColor, fontSize: btnFontSize }">确定</text>
</view>
</view>
<view class="simple-address__box">
<picker-view indicator-style="height: 70rpx;" class="simple-address-view" :value="pickerValue" @change="pickerChange">
<picker-view-column>
<!-- #ifndef APP-NVUE -->
<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.areaName }}</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.areaName }}</text>
<!-- #endif -->
</picker-view-column>
<picker-view-column>
<!-- #ifndef APP-NVUE -->
<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.areaName }}</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.areaName }}</text>
<!-- #endif -->
</picker-view-column>
<picker-view-column>
<!-- #ifndef APP-NVUE -->
<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.areaName }}</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.areaName }}</text>
<!-- #endif -->
</picker-view-column>
</picker-view>
</view>
</view>
</view>
</template>
<script>
/**
* Simple-addres 地址联动组件
* @description 三级地址联动,支持(app)nvue、小程序、H5
* @tutorial https://ext.dcloud.net.cn/plugin?id=1084
* @property {String} animation 是否开启动画
* @property {String} type = [bottom] 弹出层类型,暂时只支持底部弹出
* @property {Boolean} maskClick = [true | false] 是否允许点击遮罩层关闭
* @property {Boolean} show = [true | false] 显示或隐藏地址组件
* @property {String} maskBgColor 遮罩层背景颜色
* @property {String} cancelColor 取消按钮颜色,默认为:#1aad19
* @property {String} confirmColor 确认按钮颜色,默认为:themeColor
* @property {String} themeColor 主题颜色,后续会废弃该配置,建议使用`cancelColor`或`confirmColor`
* @property {String} btnFontSize 取消、确认按钮字体大小,默认为`uni.scss里的 $uni-font-size-base `
* @property {String} fontSize picker-item字体大小,默认为:28rpx
* @property {Array} pickerValueDefault 默认值,可以通过function queryIndex 获取
* @property {Function} queryIndex 根据自定义信息返回对应的index
* @property {Function} open 打开
* @example <simple-address ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onConfirm" themeColor='#007AFF'></simple-address>
*/
import util from '@/config/util.js'
import {
areaList
} from '@/config/api.js'
export default {
name: 'simpleAddress',
props: {
mode: {
// 地址类型
// default 则代表老版本根据index索引获取数据
//
type: String,
default: 'default'
},
// 开启动画
animation: {
type: Boolean,
default: true
},
/* 弹出层类型,可选值;
bottom:底部弹出层
*/
type: {
type: String,
default: 'bottom'
},
// maskClick
maskClick: {
type: Boolean,
default: true
},
show: {
type: Boolean,
default: true
},
maskBgColor: {
type: String,
default: 'rgba(0, 0, 0, 0.4)' //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss
},
themeColor: {
type: String,
default: '' // 确认按钮颜色(向下兼容)
},
cancelColor: {
type: String,
default: '' // 取消按钮颜色
},
confirmColor: {
type: String,
default: '' // 确认按钮颜色
},
fontSize: {
type: String,
default: '28rpx' // picker-item字体大小
},
btnFontSize: {
type: String,
default: '' // 按钮的字体大小
},
/* 默认值 */
pickerValueDefault: {
type: Array,
default () {
return [0, 0, 0];
}
}
},
data() {
return {
ani: '',
showPopup: false,
pickerValue: [0, 0, 0],
provinceDataList: [],
cityDataList: [],
areaDataList: []
};
},
watch: {
show(newValue) {
if (newValue) {
this.open()
} else {
this.close()
}
},
pickerValueDefault() {
this.init()
}
},
methods: {
init() {
// 设置默认值
this.pickerValue = this.pickerValueDefault
// 获取省级数据
areaList({
parentId: 0
}, {
hideLoading: true,
suc: res => {
this.provinceDataList = res.data
this.initCityData()
}
})
},
initCityData() {
// 获取市级数据
areaList({
parentId: this.provinceDataList[this.pickerValue[0]].id
}, {
hideLoading: true,
suc: res => {
this.cityDataList = res.data;
this.initAreaData();
}
})
},
initAreaData() {
// 获取区级数据
areaList({
parentId: this.cityDataList[this.pickerValue[1]].id
}, {
hideLoading: true,
suc: res => {
this.areaDataList = res.data;
}
})
},
pickerChange(e) {
let changePickerValue = e.detail.value;
if (this.pickerValue[0] !== changePickerValue[0]) {
// 第一级滚动
changePickerValue[1] = 0;
changePickerValue[2] = 0;
this.pickerValue = changePickerValue;
this.initCityData();
} else if (this.pickerValue[1] !== changePickerValue[1]) {
// 第二级滚动
changePickerValue[2] = 0;
this.pickerValue = changePickerValue;
this.initAreaData();
} else {
// 第三级滚动
this.pickerValue = changePickerValue;
}
this._$emit('onChange');
},
_$emit(emitName) {
let pickObj = {
label: this._getLabel(),
value: this.pickerValue,
cityCode: this._getCityCode(),
cityId: this._getCityId(),
areaCode: this._getAreaCode(),
areaId: this._getAreaId(),
provinceCode: this._getProvinceCode(),
provinceId: this._getProvinceId(),
labelArr: this._getLabel().split('-')
};
this.$emit(emitName, pickObj);
},
_getLabel() {
let pcikerLabel =
this.provinceDataList[this.pickerValue[0]].areaName + '-' + this.cityDataList[this.pickerValue[1]].areaName + '-' + this
.areaDataList[this.pickerValue[2]].areaName;
return pcikerLabel;
},
_getProvinceId() {
return this.provinceDataList[this.pickerValue[0]].id;
},
_getProvinceCode() {
return this.provinceDataList[this.pickerValue[0]].areaType;
},
_getCityId() {
return this.cityDataList[this.pickerValue[1]].id;
},
_getCityCode() {
return this.cityDataList[this.pickerValue[1]].areaType;
},
_getAreaId() {
return this.areaDataList[this.pickerValue[2]].id;
},
_getAreaCode() {
return this.areaDataList[this.pickerValue[2]].areaType;
},
queryIndex(params = [], type = 'value') {
// params = [ 11 ,1101,110101 ];
// 1.获取省份的index
let provinceIndex = this.provinceDataList.findIndex(res => res[type] == params[0]);
let cityIndex = cityData[provinceIndex].findIndex(res => res[type] == params[1]);
let areaIndex = areaData[provinceIndex][cityIndex].findIndex(res => res[type] == params[2]);
return {
index: [provinceIndex, cityIndex, areaIndex],
data: {
province: this.provinceDataList[provinceIndex],
city: cityData[provinceIndex][cityIndex],
area: areaData[provinceIndex][cityIndex][areaIndex]
}
};
},
clear() {},
hideMask() {
this._$emit('onCancel')
this.close()
},
pickerCancel() {
this._$emit('onCancel')
this.close()
},
pickerConfirm() {
this._$emit('onConfirm')
this.close()
},
open() {
if (this.provinceDataList.length == 0) {
this.init();
}
this.showPopup = true;
this.$nextTick(() => {
setTimeout(() => {
this.ani = 'simple-' + this.type;
}, 100);
});
},
close(type) {
if (!this.maskClick && type) return;
this.ani = '';
this.$nextTick(() => {
setTimeout(() => {
this.showPopup = false;
}, 300);
});
}
}
};
</script>
<style scoped>
.simple-address {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.simple-address-mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.simple-bottom-mask {
opacity: 1;
}
.simple-center-mask {
opacity: 1;
}
.simple-address--fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460rpx);
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.simple-address-content {
background-color: #ffffff;
}
.simple-content-bottom {
bottom: 0;
left: 0;
right: 0;
transform: translateY(500rpx);
}
.content-ani {
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.simple-bottom-content {
transform: translateY(0);
}
.simple-center-content {
transform: scale(1);
opacity: 1;
}
.simple-address__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
border-bottom-color: #f2f2f2;
border-bottom-style: solid;
border-bottom-width: 1rpx;
}
.simple-address--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 1rpx;
}
.simple-address__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 70rpx;
}
.simple-address__header-text {
text-align: center;
font-size: $uni-font-size-base;
color: #1aad19;
line-height: 70rpx;
padding-left: 40rpx;
padding-right: 40rpx;
}
.simple-address__box {
position: relative;
}
.simple-address-view {
position: relative;
bottom: 0;
left: 0;
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
/* #ifdef APP-NVUE */
width: 750rpx;
/* #endif */
height: 408rpx;
background-color: rgba(255, 255, 255, 1);
}
.picker-item {
text-align: center;
line-height: 70rpx;
text-overflow: ellipsis;
font-size: 28rpx;
}
</style>
export default {
'contact': '\ue100',
'person': '\ue101',
'personadd': '\ue102',
'contact-filled': '\ue130',
'person-filled': '\ue131',
'personadd-filled': '\ue132',
'phone': '\ue200',
'email': '\ue201',
'chatbubble': '\ue202',
'chatboxes': '\ue203',
'phone-filled': '\ue230',
'email-filled': '\ue231',
'chatbubble-filled': '\ue232',
'chatboxes-filled': '\ue233',
'weibo': '\ue260',
'weixin': '\ue261',
'pengyouquan': '\ue262',
'chat': '\ue263',
'qq': '\ue264',
'videocam': '\ue300',
'camera': '\ue301',
'mic': '\ue302',
'location': '\ue303',
'mic-filled': '\ue332',
'speech': '\ue332',
'location-filled': '\ue333',
'micoff': '\ue360',
'image': '\ue363',
'map': '\ue364',
'compose': '\ue400',
'trash': '\ue401',
'upload': '\ue402',
'download': '\ue403',
'close': '\ue404',
'redo': '\ue405',
'undo': '\ue406',
'refresh': '\ue407',
'star': '\ue408',
'plus': '\ue409',
'minus': '\ue410',
'circle': '\ue411',
'checkbox': '\ue411',
'close-filled': '\ue434',
'clear': '\ue434',
'refresh-filled': '\ue437',
'star-filled': '\ue438',
'plus-filled': '\ue439',
'minus-filled': '\ue440',
'circle-filled': '\ue441',
'checkbox-filled': '\ue442',
'closeempty': '\ue460',
'refreshempty': '\ue461',
'reload': '\ue462',
'starhalf': '\ue463',
'spinner': '\ue464',
'spinner-cycle': '\ue465',
'search': '\ue466',
'plusempty': '\ue468',
'forward': '\ue470',
'back': '\ue471',
'left-nav': '\ue471',
'checkmarkempty': '\ue472',
'home': '\ue500',
'navigate': '\ue501',
'gear': '\ue502',
'paperplane': '\ue503',
'info': '\ue504',
'help': '\ue505',
'locked': '\ue506',
'more': '\ue507',
'flag': '\ue508',
'home-filled': '\ue530',
'gear-filled': '\ue532',
'info-filled': '\ue534',
'help-filled': '\ue535',
'more-filled': '\ue537',
'settings': '\ue560',
'list': '\ue562',
'bars': '\ue563',
'loop': '\ue565',
'paperclip': '\ue567',
'eye': '\ue568',
'arrowup': '\ue580',
'arrowdown': '\ue581',
'arrowleft': '\ue582',
'arrowright': '\ue583',
'arrowthinup': '\ue584',
'arrowthindown': '\ue585',
'arrowthinleft': '\ue586',
'arrowthinright': '\ue587',
'pulldown': '\ue588',
'closefill': '\ue589',
'sound': '\ue590',
'scan': '\ue612'
}
<template>
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" @click="_onClick">{{icons[type]}}</text>
</template>
<script>
import icons from './icons.js';
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
domModule.addRule('fontFace', {
'fontFamily': "uniicons",
'src': "url('data:font/truetype;charset=utf-8;base64,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PDgtsDEssAAWILAJI0IgICBGI0ewACsjYTgtsDIssAAWsAMlsAIlRyNHI2GwAFRYLiA8IyEbsAIlsAIlRyNHI2EgsAUlsAQlRyNHI2GwBiWwBSVJsAIlYbABRWMjIFhiGyFZY7ABRWJgIy4jICA8ijgjIVktsDMssAAWILAJQyAuRyNHI2EgYLAgYGawgGIjICA8ijgtsDQsIyAuRrACJUZSWCA8WS6xJAEUKy2wNSwjIC5GsAIlRlBYIDxZLrEkARQrLbA2LCMgLkawAiVGUlggPFkjIC5GsAIlRlBYIDxZLrEkARQrLbA3LLAuKyMgLkawAiVGUlggPFkusSQBFCstsDgssC8riiAgPLAEI0KKOCMgLkawAiVGUlggPFkusSQBFCuwBEMusCQrLbA5LLAAFrAEJbAEJiAuRyNHI2GwBkUrIyA8IC4jOLEkARQrLbA6LLEJBCVCsAAWsAQlsAQlIC5HI0cjYSCwBCNCsAZFKyCwYFBYILBAUVizAiADIBuzAiYDGllCQiMgR7AEQ7CAYmAgsAArIIqKYSCwAkNgZCOwA0NhZFBYsAJDYRuwA0NgWbADJbCAYmGwAiVGYTgjIDwjOBshICBGI0ewACsjYTghWbEkARQrLbA7LLAuKy6xJAEUKy2wPCywLyshIyAgPLAEI0IjOLEkARQrsARDLrAkKy2wPSywABUgR7AAI0KyAAEBFRQTLrAqKi2wPiywABUgR7AAI0KyAAEBFRQTLrAqKi2wPyyxAAEUE7ArKi2wQCywLSotsEEssAAWRSMgLiBGiiNhOLEkARQrLbBCLLAJI0KwQSstsEMssgAAOistsEQssgABOistsEUssgEAOistsEYssgEBOistsEcssgAAOystsEgssgABOystsEkssgEAOystsEossgEBOystsEsssgAANystsEwssgABNystsE0ssgEANystsE4ssgEBNystsE8ssgAAOSstsFAssgABOSstsFEssgEAOSstsFIssgEBOSstsFMssgAAPCstsFQssgABPCstsFUssgEAPCstsFYssgEBPCstsFcssgAAOCstsFgssgABOCstsFkssgEAOCstsFossgEBOCstsFsssDArLrEkARQrLbBcLLAwK7A0Ky2wXSywMCuwNSstsF4ssAAWsDArsDYrLbBfLLAxKy6xJAEUKy2wYCywMSuw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bmlFMjAwB3VuaUUyMDEHdW5pRTIwMgd1bmlFMjAzB3VuaUUyMzAHdW5pRTIzMQd1bmlFMjMyB3VuaUUyMzMHdW5pRTI2MAd1bmlFMjYxB3VuaUUyNjIHdW5pRTI2Mwd1bmlFMjY0B3VuaUUzMDAHdW5pRTMwMQd1bmlFMzAyB3VuaUUzMDMHdW5pRTMzMgd1bmlFMzMzB3VuaUUzNjAHdW5pRTM2Mwd1bmlFMzY0B3VuaUU0MDAHdW5pRTQwMQd1bmlFNDAyB3VuaUU0MDMHdW5pRTQwNAd1bmlFNDA1B3VuaUU0MDYHdW5pRTQwNwd1bmlFNDA4B3VuaUU0MDkHdW5pRTQxMAd1bmlFNDExB3VuaUU0MTMHdW5pRTQzNAd1bmlFNDM3B3VuaUU0MzgHdW5pRTQzOQd1bmlFNDQwB3VuaUU0NDEHdW5pRTQ0Mgd1bmlFNDQzB3VuaUU0NjAHdW5pRTQ2MQd1bmlFNDYyB3VuaUU0NjMHdW5pRTQ2NAd1bmlFNDY1B3VuaUU0NjYHdW5pRTQ2OAd1bmlFNDcwB3VuaUU0NzEHdW5pRTQ3Mgd1bmlFNTAwB3VuaUU1MDEHdW5pRTUwMgd1bmlFNTAzB3VuaUU1MDQHdW5pRTUwNQd1bmlFNTA2B3VuaUU1MDcHdW5pRTUwOAd1bmlFNTMwB3VuaUU1MzIHdW5pRTUzNAd1bmlFNTM1B3VuaUU1MzcHdW5pRTU2MAd1bmlFNTYyB3VuaUU1NjMHdW5pRTU2NQd1bmlFNTY3B3VuaUU1NjgHdW5pRTU4MAd1bmlFNTgxB3VuaUU1ODIHdW5pRTU4Mwd1bmlFNTg0B3VuaUU1ODUHdW5pRTU4Ngd1bmlFNTg3B3VuaUU1ODgHdW5pRTU4OQRFdXJvB3VuaUU2MTIAAAEAAf//AA8AAQAAAAwAAAAWAAAAAgABAAEAXwABAAQAAAACAAAAAAAAAAEAAAAA1aQnCAAAAADZqlu5AAAAANmqXAk=')"
});
// #endif
export default {
name: 'UniIcons',
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
}
},
data() {
return {
icons: icons
}
},
methods: {
_onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
@font-face {
font-family: uniicons;
src: url('data:font/truetype;charset=utf-8;base64,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PDgtsDEssAAWILAJI0IgICBGI0ewACsjYTgtsDIssAAWsAMlsAIlRyNHI2GwAFRYLiA8IyEbsAIlsAIlRyNHI2EgsAUlsAQlRyNHI2GwBiWwBSVJsAIlYbABRWMjIFhiGyFZY7ABRWJgIy4jICA8ijgjIVktsDMssAAWILAJQyAuRyNHI2EgYLAgYGawgGIjICA8ijgtsDQsIyAuRrACJUZSWCA8WS6xJAEUKy2wNSwjIC5GsAIlRlBYIDxZLrEkARQrLbA2LCMgLkawAiVGUlggPFkjIC5GsAIlRlBYIDxZLrEkARQrLbA3LLAuKyMgLkawAiVGUlggPFkusSQBFCstsDgssC8riiAgPLAEI0KKOCMgLkawAiVGUlggPFkusSQBFCuwBEMusCQrLbA5LLAAFrAEJbAEJiAuRyNHI2GwBkUrIyA8IC4jOLEkARQrLbA6LLEJBCVCsAAWsAQlsAQlIC5HI0cjYSCwBCNCsAZFKyCwYFBYILBAUVizAiADIBuzAiYDGllCQiMgR7AEQ7CAYmAgsAArIIqKYSCwAkNgZCOwA0NhZFBYsAJDYRuwA0NgWbADJbCAYmGwAiVGYTgjIDwjOBshICBGI0ewACsjYTghWbEkARQrLbA7LLAuKy6xJAEUKy2wPCywLyshIyAgPLAEI0IjOLEkARQrsARDLrAkKy2wPSywABUgR7AAI0KyAAEBFRQTLrAqKi2wPiywABUgR7AAI0KyAAEBFRQTLrAqKi2wPyyxAAEUE7ArKi2wQCywLSotsEEssAAWRSMgLiBGiiNhOLEkARQrLbBCLLAJI0KwQSstsEMssgAAOistsEQssgABOistsEUssgEAOistsEYssgEBOistsEcssgAAOystsEgssgABOystsEkssgEAOystsEossgEBOystsEsssgAANystsEwssgABNystsE0ssgEANystsE4ssgEBNystsE8ssgAAOSstsFAssgABOSstsFEssgEAOSstsFIssgEBOSstsFMssgAAPCstsFQssgABPCstsFUssgEAPCstsFYssgEBPCstsFcssgAAOCstsFgssgABOCstsFkssgEAOCstsFossgEBOCstsFsssDArLrEkARQrLbBcLLAwK7A0Ky2wXSywMCuwNSstsF4ssAAWsDArsDYrLbBfLLAxKy6xJAEUKy2wYCywMSuw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bmlFMjAwB3VuaUUyMDEHdW5pRTIwMgd1bmlFMjAzB3VuaUUyMzAHdW5pRTIzMQd1bmlFMjMyB3VuaUUyMzMHdW5pRTI2MAd1bmlFMjYxB3VuaUUyNjIHdW5pRTI2Mwd1bmlFMjY0B3VuaUUzMDAHdW5pRTMwMQd1bmlFMzAyB3VuaUUzMDMHdW5pRTMzMgd1bmlFMzMzB3VuaUUzNjAHdW5pRTM2Mwd1bmlFMzY0B3VuaUU0MDAHdW5pRTQwMQd1bmlFNDAyB3VuaUU0MDMHdW5pRTQwNAd1bmlFNDA1B3VuaUU0MDYHdW5pRTQwNwd1bmlFNDA4B3VuaUU0MDkHdW5pRTQxMAd1bmlFNDExB3VuaUU0MTMHdW5pRTQzNAd1bmlFNDM3B3VuaUU0MzgHdW5pRTQzOQd1bmlFNDQwB3VuaUU0NDEHdW5pRTQ0Mgd1bmlFNDQzB3VuaUU0NjAHdW5pRTQ2MQd1bmlFNDYyB3VuaUU0NjMHdW5pRTQ2NAd1bmlFNDY1B3VuaUU0NjYHdW5pRTQ2OAd1bmlFNDcwB3VuaUU0NzEHdW5pRTQ3Mgd1bmlFNTAwB3VuaUU1MDEHdW5pRTUwMgd1bmlFNTAzB3VuaUU1MDQHdW5pRTUwNQd1bmlFNTA2B3VuaUU1MDcHdW5pRTUwOAd1bmlFNTMwB3VuaUU1MzIHdW5pRTUzNAd1bmlFNTM1B3VuaUU1MzcHdW5pRTU2MAd1bmlFNTYyB3VuaUU1NjMHdW5pRTU2NQd1bmlFNTY3B3VuaUU1NjgHdW5pRTU4MAd1bmlFNTgxB3VuaUU1ODIHdW5pRTU4Mwd1bmlFNTg0B3VuaUU1ODUHdW5pRTU4Ngd1bmlFNTg3B3VuaUU1ODgHdW5pRTU4OQRFdXJvB3VuaUU2MTIAAAEAAf//AA8AAQAAAAwAAAAWAAAAAgABAAEAXwABAAQAAAACAAAAAAAAAAEAAAAA1aQnCAAAAADZqlu5AAAAANmqXAk=') format('truetype');
}
/* #endif */
.uni-icons {
font-family: uniicons;
text-decoration: none;
text-align: center;
}
</style>
<template>
<view class="uni-navbar">
<view :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }" :style="{ 'background-color': backgroundColor }"
class="uni-navbar__content">
<uni-status-bar v-if="statusBar" />
<view :style="{ color: color,backgroundColor: backgroundColor }" class="uni-navbar__header uni-navbar__content_view">
<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left uni-navbar__content_view">
<view class="uni-navbar__content_view" v-if="leftIcon.length">
<uni-icons :color="color" :type="leftIcon" size="24" />
</view>
<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length }" class="uni-navbar-btn-text uni-navbar__content_view"
v-if="leftText.length">
<text :style="{ color: color, fontSize: '14px' }">{{ leftText }}</text>
</view>
<slot name="left" />
</view>
<view class="uni-navbar__header-container uni-navbar__content_view">
<view class="uni-navbar__header-container-inner uni-navbar__content_view" v-if="title.length">
<text class="uni-nav-bar-text" :style="{color: color }">{{ title }}</text>
</view>
<!-- 标题插槽 -->
<slot />
</view>
<view :class="title.length ? 'uni-navbar__header-btns-right' : ''" @tap="onClickRight" class="uni-navbar__header-btns uni-navbar__content_view">
<view class="uni-navbar__content_view" v-if="rightIcon.length">
<uni-icons :color="color" :type="rightIcon" size="24" />
</view>
<!-- 优先显示图标 -->
<view class="uni-navbar-btn-text uni-navbar__content_view" v-if="rightText.length && !rightIcon.length">
<text class="uni-nav-bar-right-text">{{ rightText }}</text>
</view>
<slot name="right" />
</view>
</view>
</view>
<view class="uni-navbar__placeholder" v-if="fixed">
<uni-status-bar v-if="statusBar" />
<view class="uni-navbar__placeholder-view" />
</view>
</view>
</template>
<script>
import uniStatusBar from "../uni-status-bar/uni-status-bar.vue";
import uniIcons from "../uni-icons/uni-icons.vue";
export default {
name: "UniNavBar",
components: {
uniStatusBar,
uniIcons
},
props: {
title: {
type: String,
default: ""
},
leftText: {
type: String,
default: ""
},
rightText: {
type: String,
default: ""
},
leftIcon: {
type: String,
default: ""
},
rightIcon: {
type: String,
default: ""
},
fixed: {
type: [Boolean, String],
default: false
},
color: {
type: String,
default: "#000000"
},
backgroundColor: {
type: String,
default: "#FFFFFF"
},
statusBar: {
type: [Boolean, String],
default: false
},
shadow: {
type: [String, Boolean],
default: false
},
border: {
type: [String, Boolean],
default: true
}
},
mounted() {
if(uni.report && this.title !== '') {
uni.report('title', this.title)
}
},
methods: {
onClickLeft() {
this.$emit("clickLeft");
},
onClickRight() {
this.$emit("clickRight");
}
}
};
</script>
<style lang="scss" scoped>
$nav-height: 44px;
.uni-nav-bar-text {
/* #ifdef APP-PLUS */
font-size: 34rpx;
/* #endif */
/* #ifndef APP-PLUS */
font-size: $uni-font-size-lg;
/* #endif */
}
.uni-nav-bar-right-text {
font-size: $uni-font-size-base;
}
.uni-navbar {
width: 750rpx;
}
.uni-navbar__content {
position: relative;
width: 750rpx;
background-color: $uni-bg-color;
overflow: hidden;
}
.uni-navbar__content_view {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
flex-direction: row;
// background-color: #FFFFFF;
}
.uni-navbar__header {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
width: 750rpx;
height: $nav-height;
line-height: $nav-height;
font-size: 16px;
// background-color: #ffffff;
}
.uni-navbar__header-btns {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-wrap: nowrap;
width: 120rpx;
padding: 0 6px;
justify-content: center;
align-items: center;
}
.uni-navbar__header-btns-left {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
width: 150rpx;
justify-content: flex-start;
}
.uni-navbar__header-btns-right {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
width: 150rpx;
padding-right: 30rpx;
justify-content: flex-end;
}
.uni-navbar__header-container {
flex: 1;
}
.uni-navbar__header-container-inner {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
align-items: center;
justify-content: center;
font-size: $uni-font-size-base;
}
.uni-navbar__placeholder-view {
height: $nav-height;
}
.uni-navbar--fixed {
position: fixed;
z-index: 998;
}
.uni-navbar--shadow {
/* #ifndef APP-NVUE */
box-shadow: 0 1px 6px #ccc;
/* #endif */
}
.uni-navbar--border {
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: $uni-border-color;
}
</style>
export default {
created() {
if (this.type === 'message') {
// 不显示遮罩
this.maskShow = false
// 获取子组件对象
this.childrenMsg = null
}
},
methods: {
customOpen() {
if (this.childrenMsg) {
this.childrenMsg.open()
}
},
customClose() {
if (this.childrenMsg) {
this.childrenMsg.close()
}
}
}
}
import message from './message.js';
// 定义 type 类型:弹出类型:top/bottom/center
const config = {
// 顶部弹出
top:'top',
// 底部弹出
bottom:'bottom',
// 居中弹出
center:'center',
// 消息提示
message:'top',
// 对话框
dialog:'center',
// 分享
share:'bottom',
}
export default {
data(){
return {
config:config
}
},
mixins: [message],
}
<template>
<view class="uni-popup-select">
<view class="uni-select-title">
<text class="uni-select-title-text">选择支付方式</text>
<view class="close" @click="close">
<image src="/static/ic_black_close.png"></image>
</view>
</view>
<view class="uni-select-content">
<view class="row" @click="changePay(1)">
<view class="pay-type">
<image mode="aspectFill" src="/static/plays@3x.png"></image>
<label>支付宝支付</label>
</view>
<image class="choose" :src="payType == 1 ? '/static/Selecti.png' : '/static/ic_now.png'"></image>
</view>
<view class="row" @click="changePay(2)">
<view class="pay-type">
<image mode="aspectFill" src="/static/WChat@3x.png"></image>
<label>微信支付</label>
</view>
<image class="choose" :src="payType == 2 ? '/static/Selecti.png' : '/static/ic_now.png'"></image>
</view>
<view class="row" @click="changePay(3)" v-if="fromType == 1">
<view class="pay-type">
<image mode="aspectFill" src="/static/banlance.png"></image>
<label>余额支付</label>
</view>
<image class="choose" :src="payType == 3 ? '/static/Selecti.png' : '/static/ic_now.png'"></image>
</view>
<view class="row">
<button @click="sure">确认支付</button>
</view>
</view>
</view>
</template>
<script>
import util from '@/utils/util.js'
import {
balancePay,
createAliPayOrder,
wxPayCreateOrder
} from '@/utils/api.js'
export default {
props: {
payAmount: {
type: Number
},
combineOrderNo: {
type: String
},
fromType: { //1购买物品 2申请代理 3购买tz
type: Number
},
},
name: 'UniPopupPay',
inject: ['popup'],
data() {
return {
payType: 1
}
},
methods: {
// 修改支付方式
changePay(type) {
this.payType = type
},
// 关闭窗口
close() {
this.popup.close()
},
// 确认支付
sure() {
var params = {}
if (this.payType == 1) { //支付宝支付 需要传
params['amount'] = this.payAmount
params["tradeNo"] = this.combineOrderNo
params["type"] = this.fromType
}
if (this.payType == 2) { //微信支付 需要传
params['totalFee'] = this.payAmount
params["outTradeNo"] = this.combineOrderNo
params["type"] = this.fromType
}
if (this.payType == 3) { //余额支付 需要传
params['combineOrderNo'] = this.combineOrderNo
params['payAmount'] = this.payAmount
params["payType"] = this.payType
}
if (this.payType == 1) {
console.log('支付包参赛')
console.log(params)
// 支付宝支付
createAliPayOrder(params, {
suc: res => {
uni.requestPayment({
provider: 'alipay',
orderInfo: res.data,
success: res => {
this.$emit('ok')
this.close()
},
fail: err => {
util.printLog(err)
}
})
}
})
} else if (this.payType == 2) {
console.log('微信参赛')
console.log(params)
// 微信支付
wxPayCreateOrder(params, {
suc: res => {
uni.requestPayment({
provider: 'wxpay',
orderInfo: res.result,
success: res => {
this.$emit('ok')
this.close()
},
fail: err => {
util.printLog(err)
}
})
}
})
}else if (this.payType == 3) {
console.log('余额参赛')
console.log(params)
// 余额支付
balancePay(params, {
suc: res => {
this.$emit('ok')
this.close()
}
})
}
}
}
}
</script>
<style scoped>
.uni-popup-select {
background-color: #fff;
}
.uni-select-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 50px;
position: relative;
border-bottom: 1rpx solid #E8E8E8;
}
.uni-select-title-text {
font-size: 34rpx;
font-weight: bold;
color: #020202;
text-align: center;
}
.uni-select-title .close {
position: absolute;
right: 30rpx;
top: 32rpx;
}
.close image {
width: 30rpx;
height: 30rpx;
}
.uni-select-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #F2F2F2;
}
.row .left {
flex: 1;
font-size: 26rpx;
color: #020202;
}
.left view:last-child {
font-size: 22rpx;
color: #AAAAAA;
}
.row .pay-type {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
font-size: 26rpx;
color: #020202;
}
.pay-type image {
width: 33rpx;
height: 33rpx;
margin-right: 10rpx;
}
.row .choose {
width: 30rpx;
height: 30rpx;
}
.row button {
width: 100vw;
height: 80rpx;
line-height: 88rpx;
color: white;
font-size: 30rpx;
background-color: #ff4229;
border-radius: 88rpx;
}
</style>
<template>
<view class="uni-popup-share">
<view class="uni-share-title"><text class="uni-share-title-text">{{title}}</text></view>
<view class="uni-share-content">
<view class="uni-share-content-box">
<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
<text class="uni-share-text">{{item.text}}</text>
</view>
</view>
</view>
<view class="uni-share-button-box">
<button class="uni-share-button" @click="close">取消</button>
</view>
</view>
</template>
<script>
export default {
name: 'UniPopupShare',
props: {
title: {
type: String,
default: '分享到'
}
},
inject: ['popup'],
data() {
return {
imgBaseUrl: null,
bottomData: [{
text: '微信',
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/WeChatdl.png',
name: 'wx'
},
{
text: '朋友圈',
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/friend.png',
name: 'wx'
}
]
}
},
created() {
this.imgBaseUrl = this.$api.IMG_BASE_URL
},
methods: {
/**
* 选择内容
*/
select(item, index) {
this.$emit('select', {
item,
index
}, () => {
this.popup.close()
})
},
/**
* 关闭窗口
*/
close() {
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-share {
background-color: #fff;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 40px;
}
.uni-share-title-text {
font-size: 14px;
color: #666;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 10px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
width: 360px;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3B4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 10px 15px;
}
.uni-share-button {
flex: 1;
border-radius: 50px;
color: #666;
font-size: 16px;
}
.uni-share-button::after {
border-radius: 50px;
}
</style>
<template>
<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans"
@click="onTap" />
<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
<view class="uni-popup__wrapper-box" @click.stop="clear">
<slot />
</view>
</uni-transition>
</view>
</template>
<script>
import uniTransition from '../uni-transition/uni-transition.vue'
import popup from './popup.js'
/**
* PopUp 弹出层
* @description 弹出层组件,为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @value message 消息提示
* @value dialog 对话框
* @value share 底部分享示例
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
* @event {Function} change 打开关闭弹窗触发,e={show: false}
*/
export default {
name: 'UniPopup',
components: {
uniTransition
},
props: {
// 开启动画
animation: {
type: Boolean,
default: true
},
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
// message: 消息提示 ; dialog : 对话框
type: {
type: String,
default: 'center'
},
// maskClick
maskClick: {
type: Boolean,
default: true
}
},
provide() {
return {
popup: this
}
},
mixins: [popup],
watch: {
/**
* 监听type类型
*/
type: {
handler: function(newVal) {
this[this.config[newVal]]()
},
immediate: true
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick(val) {
this.mkclick = val
}
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
maskClass: {
'position': 'fixed',
'bottom': 0,
'top': 0,
'left': 0,
'right': 0,
'backgroundColor': 'rgba(0, 0, 0, 0.4)'
},
transClass: {
'position': 'fixed',
'left': 0,
'right': 0,
},
maskShow: true,
mkclick: true,
popupstyle: 'top'
}
},
created() {
this.mkclick = this.maskClick
if (this.animation) {
this.duration = 300
} else {
this.duration = 0
}
},
methods: {
clear(e) {
// TODO nvue 取消冒泡
e.stopPropagation()
},
open() {
this.showPopup = true
this.$nextTick(() => {
new Promise(resolve => {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.showTrans = true
// fixed by mehaotian 兼容 app 端
this.$nextTick(() => {
resolve();
})
}, 50);
}).then(res => {
// 自定义打开事件
clearTimeout(this.msgtimer)
this.msgtimer = setTimeout(() => {
this.customOpen && this.customOpen()
}, 100)
this.$emit('change', {
show: true,
type: this.type
})
})
})
},
close(type) {
this.showTrans = false
this.$nextTick(() => {
this.$emit('change', {
show: false,
type: this.type
})
clearTimeout(this.timer)
// 自定义关闭事件
this.customOpen && this.customClose()
this.timer = setTimeout(() => {
this.showPopup = false
}, 300)
})
},
onTap() {
if (!this.mkclick) return
this.close()
},
/**
* 顶部弹出样式处理
*/
top() {
this.popupstyle = 'top'
this.ani = ['slide-top']
this.transClass = {
'position': 'fixed',
'left': 0,
'right': 0,
}
},
/**
* 底部弹出样式处理
*/
bottom() {
this.popupstyle = 'bottom'
this.ani = ['slide-bottom']
this.transClass = {
'position': 'fixed',
'left': 0,
'right': 0,
'bottom': 0
}
},
/**
* 中间弹出样式处理
*/
center() {
this.popupstyle = 'center'
this.ani = ['zoom-out', 'fade']
this.transClass = {
'position': 'fixed',
/* #ifndef APP-NVUE */
'display': 'flex',
'flexDirection': 'column',
/* #endif */
'bottom': 0,
'left': 0,
'right': 0,
'top': 0,
'justifyContent': 'center',
'alignItems': 'center'
}
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-popup__mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
opacity: 0;
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.uni-top-mask {
opacity: 1;
}
.uni-bottom-mask {
opacity: 1;
}
.uni-center-mask {
opacity: 1;
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
}
.top {
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
}
.bottom {
bottom: 0;
}
.uni-popup__wrapper-box {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
/* #endif */
}
.content-ani {
// transition: transform 0.3s;
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.uni-top-content {
transform: translateY(0);
}
.uni-bottom-content {
transform: translateY(0);
}
.uni-center-content {
transform: scale(1);
opacity: 1;
}
</style>
<template>
<view :style="{ height: statusBarHeight }" class="uni-status-bar">
<slot />
</view>
</template>
<script>
var statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px'
export default {
name: 'UniStatusBar',
data() {
return {
statusBarHeight: statusBarHeight
}
}
}
</script>
<style lang="scss" scoped>
.uni-status-bar {
width: 750rpx;
height: 20px;
background-color: white;
// height: var(--status-bar-height);
}
</style>
<template>
<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
@click="change">
<slot></slot>
</view>
</template>
<script>
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation');
// #endif
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
*/
export default {
name: 'uniTransition',
props: {
show: {
type: Boolean,
default: false
},
modeClass: {
type: Array,
default () {
return []
}
},
duration: {
type: Number,
default: 300
},
styles: {
type: Object,
default () {
return {}
}
}
},
data() {
return {
isShow: false,
transform: '',
ani: { in: '',
active: ''
}
};
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.open()
} else {
this.close()
}
},
immediate: true
}
},
computed: {
stylesObject() {
let styles = {
...this.styles,
'transition-duration': this.duration / 1000 + 's'
}
let transfrom = ''
for (let i in styles) {
let line = this.toLine(i)
transfrom += line + ':' + styles[i] + ';'
}
return transfrom
}
},
created() {
// this.timer = null
// this.nextTick = (time = 50) => new Promise(resolve => {
// clearTimeout(this.timer)
// this.timer = setTimeout(resolve, time)
// return this.timer
// });
},
methods: {
change() {
this.$emit('click', {
detail: this.isShow
})
},
open() {
clearTimeout(this.timer)
this.isShow = true
this.transform = ''
this.ani.in = ''
for (let i in this.getTranfrom(false)) {
if (i === 'opacity') {
this.ani.in = 'fade-in'
} else {
this.transform += `${this.getTranfrom(false)[i]} `
}
}
this.$nextTick(() => {
setTimeout(() => {
this._animation(true)
}, 50)
})
},
close(type) {
clearTimeout(this.timer)
this._animation(false)
},
_animation(type) {
let styles = this.getTranfrom(type)
// #ifdef APP-NVUE
if(!this.$refs['ani']) return
animation.transition(this.$refs['ani'].ref, {
styles,
duration: this.duration, //ms
timingFunction: 'ease',
needLayout: false,
delay: 0 //ms
}, () => {
if (!type) {
this.isShow = false
}
this.$emit('change', {
detail: this.isShow
})
})
// #endif
// #ifndef APP-NVUE
this.transform = ''
for (let i in styles) {
if (i === 'opacity') {
this.ani.in = `fade-${type?'out':'in'}`
} else {
this.transform += `${styles[i]} `
}
}
this.timer = setTimeout(() => {
if (!type) {
this.isShow = false
}
this.$emit('change', {
detail: this.isShow
})
}, this.duration)
// #endif
},
getTranfrom(type) {
let styles = {
transform: ''
}
this.modeClass.forEach((mode) => {
switch (mode) {
case 'fade':
styles.opacity = type ? 1 : 0
break;
case 'slide-top':
styles.transform += `translateY(${type?'0':'-100%'}) `
break;
case 'slide-right':
styles.transform += `translateX(${type?'0':'100%'}) `
break;
case 'slide-bottom':
styles.transform += `translateY(${type?'0':'100%'}) `
break;
case 'slide-left':
styles.transform += `translateX(${type?'0':'-100%'}) `
break;
case 'zoom-in':
styles.transform += `scale(${type?1:0.8}) `
break;
case 'zoom-out':
styles.transform += `scale(${type?1:1.2}) `
break;
}
})
return styles
},
_modeClassArr(type) {
let mode = this.modeClass
if (typeof(mode) !== "string") {
let modestr = ''
mode.forEach((item) => {
modestr += (item + '-' + type + ',')
})
return modestr.substr(0, modestr.length - 1)
} else {
return mode + '-' + type
}
},
// getEl(el) {
// console.log(el || el.ref || null);
// return el || el.ref || null
// },
toLine(name) {
return name.replace(/([A-Z])/g, "-$1").toLowerCase();
}
}
}
</script>
<style>
.uni-transition {
transition-timing-function: ease;
transition-duration: 0.3s;
transition-property: transform, opacity;
}
.fade-in {
opacity: 0;
}
.fade-active {
opacity: 1;
}
.slide-top-in {
/* transition-property: transform, opacity; */
transform: translateY(-100%);
}
.slide-top-active {
transform: translateY(0);
/* opacity: 1; */
}
.slide-right-in {
transform: translateX(100%);
}
.slide-right-active {
transform: translateX(0);
}
.slide-bottom-in {
transform: translateY(100%);
}
.slide-bottom-active {
transform: translateY(0);
}
.slide-left-in {
transform: translateX(-100%);
}
.slide-left-active {
transform: translateX(0);
opacity: 1;
}
.zoom-in-in {
transform: scale(0.8);
}
.zoom-out-active {
transform: scale(1);
}
.zoom-out-in {
transform: scale(1.2);
}
</style>
## 插件说明
> 这是 `v-tabs` 插件的升级版本,参数上有很大变动,支持 `H5` `小程序` `手机端`,如果是在之前的插件上升级的话,请注意参数的变更,触发的事件没有变更。
## 使用说明
### 1、最基本用法
- 视图文件
```html
<v-tabs v-model="current" :tabs="tabs" @change="changeTab"></v-tabs>
```
- 脚本文件
```js
export default {
data() {
return {
current: 0,
tabs: ['军事', '国内', '新闻新闻', '军事', '国内', '新闻', '军事', '国内', '新闻']
}
},
methods: {
changeTab(index) {
console.log('当前选中的项:' + index)
}
}
}
```
### 2、平铺整个屏幕
- 视图文件
```html
<v-tabs v-model="activeTab" :scroll="false" :tabs="['全部', '进行中', '已完成']"></v-tabs>
```
- 脚本文件
```js
export default {
data() {
return {
activeTab: 0
}
}
}
```
### 3、胶囊用法
- 视图文件
```html
<v-tabs v-model="current" :tabs="tabs" :pills="true" line-height="0" activeColor="#fff" @change="changeTab"></v-tabs>
```
- 脚本文件
```js
data() {
return {
current: 2,
tabs: [
'军事',
'国内',
'新闻新闻',
'军事',
'国内',
'新闻',
'军事',
'国内',
'新闻',
],
},
methods: {
changeTab(index) {
console.log('当前选中索引:' + index)
}
}
}
```
## 文档说明
### 1、属性说明
| 参数 | 类型 | 默认值 | 说明 |
| :---------------: | :-----: | :-------: | :----------------------------------------: |
| value | Number | 0 | 必传(双向绑定的值) |
| color | String | '#333' | 默认文字颜色 |
| activeColor | String | '#2979ff' | 选中文字的颜色 |
| fontSize | String | '28rpx' | 默认文字大小(rpx 或 px) |
| bold | Boolean | true | 是否加粗选中项 |
| scroll | Boolean | true | 是否显示滚动条,平铺设置 false |
| height | String | '70rpx' | tab 高度(rpx 或 px) |
| lineHeight | String | '10rpx' | 滑块高度(rpx 或 px) |
| lineColor | String | '#2979ff' | 滑块的颜色 |
| lineScale | Number | 0.5 | 滑块宽度缩放值 |
| lineRadius | String | '10rpx' | 滑块圆角宽度(rpx 或 px) |
| pills | Boolean | false | 是否开启胶囊 |
| pillsColor | String | '#2979ff' | 胶囊背景颜色(rpx 或 px) |
| pillsBorderRadius | String | '10rpx' | 胶囊圆角宽度(rpx 或 px) |
| field | String | '' | 如果 tabs 子项是对象,输入需要展示的键名 |
| bgColor | String | '#fff' | 背景色,支持 linear-gradient 渐变 |
| padding | String | '0' | 整个 tab padding 属性 |
| fixed | Boolean | false | 是否固定在顶部 |
| paddingItem | String | '0 22rpx' | 选项的边距(设置上下不生效,需要设置高度) |
### 2、事件说明
| 名称 | 参数 | 说明 |
| :----: | :---: | :--------------------------------: |
| change | index | 改变选中项触发, index 选中项的下标 |
## 更新日志
### 2020-09-24
1. 修复 `v-tabs` 第一次可能出现第一个标签显示不完整的情况
2. 修改了 `pages/tabs/order` 示例文件
### 2020-09-21
1. 修复添加 `fixed` 属性后,滚动条无效
2. 修复选项很少的情况下,下划线计算计算错误
3. 新增 `paddingItem` 属性,设置选项左右边距(上下边距需要设置 `height` 属性,或者设置 `padding` 属性)
**写在最后:**
欢迎各位老铁反馈 bug ,本人后端 PHP 一枚,只是应为感兴趣前端,自己琢磨,自己搞。如果你在使用的过程中有什么不合理,需要优化的,都可以在下面评论(或加我 QQ: 1207791534),本人看见后回复、修正,感谢。
### 2020-09-17
1. 紧急修复 bug,横向滑动不了的情况
### 2020-09-16
1. 新增 `fixed` 属性,是否固定在顶部,示例地址:`pages/tabs/tabs-static`
2. 优化之前的页面结构
**注意:**
1. 使用 `padding` 属性的时候,尽量不要左右边距,会导致下划线位置不对
2. 如果不绑定 `v-model` 会导致 `change` 事件改变的时候,下划线不跟随问题
### 2020-09-09
1. 修复 `width` 错误,dom 加载的时候没有及时获取到 `data` 属性导致的。
### 2020-08-29
1. 优化异步改变 `tabs` 后,下划线不初始化问题
2. `github` 地址上有图 2 的源码,需要的自行下载,页面路径:`pages/tabs/order`
### 2020-08-20
1. 优化 `节点查询` 和 `选中渲染`
2. 优化支付宝中 `createSelectorQuery()` 的影响
### 2020-08-19
1. 优化 `change` 事件触发机制
### 2020-08-16
1. 修改默认高度为 `70rpx`
2. 新增属性 `bgColor`,可设置背景颜色,默认 `#fff`
3. 新增整个 `tab` 的 `padding` 属性,默认 `0`
### 2020-08-13
1. 全新的 `v-tabs 2.0`
2. 支持 `H5` `小程序` `APP`
3. 属性高度可配置
## 预览
![v-tabs 2.0.1.gif](https://tva1.sinaimg.cn/large/007S8ZIlgy1ghsv40mj76g30ai0i2tsd.gif)
![v-tabs 2.0.2.gif](https://img-cdn-aliyun.dcloud.net.cn/stream/plugin_screens/42f3a920-a674-11ea-8a24-ffee00625e2e_1.png?v=1597912963)
<template>
<view :id="elId" class="v-tabs">
<scroll-view
id="scrollContainer"
:scroll-x="scroll"
:scroll-left="scroll ? scrollLeft : 0"
:scroll-with-animation="scroll"
:style="{ position: fixed ? 'fixed' : 'relative', zIndex: 1993 }"
>
<view
class="v-tabs__container"
:style="{
display: scroll ? 'inline-flex' : 'flex',
whiteSpace: scroll ? 'nowrap' : 'normal',
background: bgColor,
height,
padding
}"
>
<view
class="v-tabs__container-item"
v-for="(v, i) in tabs"
:key="i"
:style="{
color: current == i ? activeColor : color,
fontSize: current == i ? fontSize : fontSize,
fontWeight: bold && current == i ? 'bold' : '',
justifyContent: !scroll ? 'center' : '',
flex: scroll ? '' : 1,
padding: paddingItem
}"
@click="change(i)"
>
{{ field ? v[field] : v }}
</view>
<view
v-if="!pills"
class="v-tabs__container-line"
:style="{
background: lineColor,
width: lineWidth + 'px',
height: lineHeight,
borderRadius: lineRadius,
left: lineLeft + 'px',
transform: `translateX(-${lineWidth / 2}px)`
}"
></view>
<view
v-else
class="v-tabs__container-pills"
:style="{
background: pillsColor,
borderRadius: pillsBorderRadius,
left: pillsLeft + 'px',
width: currentWidth + 'px',
height
}"
></view>
</view>
</scroll-view>
<view
class="v-tabs__placeholder"
:style="{
height: fixed ? height : '0',
padding
}"
></view>
</view>
</template>
<script>
/**
* v-tabs
* @property {Number} value 选中的下标
* @property {Array} tabs tabs 列表
* @property {String} bgColor = '#fff' 背景颜色
* @property {String} color = '#333' 默认颜色
* @property {String} activeColor = '#2979ff' 选中文字颜色
* @property {String} fontSize = '28rpx' 默认文字大小
* @property {String} activeFontSize = '28rpx' 选中文字大小
* @property {Boolean} bold = [true | false] 选中文字是否加粗
* @property {Boolean} scroll = [true | false] 是否滚动
* @property {String} height = '60rpx' tab 的高度
* @property {String} lineHeight = '10rpx' 下划线的高度
* @property {String} lineColor = '#2979ff' 下划线的颜色
* @property {Number} lineScale = 0.5 下划线的宽度缩放比例
* @property {String} lineRadius = '10rpx' 下划线圆角
* @property {Boolean} pills = [true | false] 是否胶囊样式
* @property {String} pillsColor = '#2979ff' 胶囊背景色
* @property {String} pillsBorderRadius = '10rpx' 胶囊圆角大小
* @property {String} field 如果是对象,显示的键名
* @property {Boolean} fixed = [true | false] 是否固定
* @property {String} paddingItem = '0 22rpx' 选项的边距
*
* @event {Function(current)} change 改变标签触发
*/
export default {
props: {
value: {
type: Number,
default: 0
},
tabs: {
type: Array,
default() {
return []
}
},
bgColor: {
type: String,
default: '#fff'
},
padding: {
type: String,
default: '0'
},
color: {
type: String,
default: '#333'
},
activeColor: {
type: String,
default: '#2979ff'
},
fontSize: {
type: String,
default: '28rpx'
},
activeFontSize: {
type: String,
default: '32rpx'
},
bold: {
type: Boolean,
default: true
},
scroll: {
type: Boolean,
default: true
},
height: {
type: String,
default: '70rpx'
},
lineColor: {
type: String,
default: '#2979ff'
},
lineHeight: {
type: String,
default: '10rpx'
},
lineScale: {
type: Number,
default: 0.5
},
lineRadius: {
type: String,
default: '10rpx'
},
pills: {
type: Boolean,
deafult: false
},
pillsColor: {
type: String,
default: '#2979ff'
},
pillsBorderRadius: {
type: String,
default: '10rpx'
},
field: {
type: String,
default: ''
},
fixed: {
type: Boolean,
default: false
},
paddingItem: {
type: String,
default: '0 22rpx'
}
},
data() {
return {
elId: '',
lineWidth: 30,
currentWidth: 0, // 当前选项的宽度
lineLeft: 0, // 滑块距离左侧的位置
pillsLeft: 0, // 胶囊距离左侧的位置
scrollLeft: 0, // 距离左边的位置
containerWidth: 0, // 容器的宽度
current: 0 // 当前选中项
}
},
watch: {
value(newVal) {
this.current = newVal
this.$nextTick(() => {
this.getTabItemWidth()
})
},
current(newVal) {
this.$emit('input', newVal)
},
tabs(newVal) {
this.$nextTick(() => {
this.getTabItemWidth()
})
}
},
methods: {
// 产生随机字符串
randomString(len) {
len = len || 32
let $chars =
'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
let maxPos = $chars.length
let pwd = ''
for (let i = 0; i < len; i++) {
pwd += $chars.charAt(Math.floor(Math.random() * maxPos))
}
return pwd
},
// 切换事件
change(index) {
if (this.current !== index) {
this.current = index
this.$emit('change', index)
}
},
// 获取左移动位置
getTabItemWidth() {
let query = uni
.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this)
// #endif
// 获取容器的宽度
query
.select(`#scrollContainer`)
.boundingClientRect((data) => {
if (!this.containerWidth && data) {
this.containerWidth = data.width
}
})
.exec()
// 获取所有的 tab-item 的宽度
query
.selectAll('.v-tabs__container-item')
.boundingClientRect((data) => {
if (!data) {
return
}
let lineLeft = 0
let currentWidth = 0
if (data) {
for (let i = 0; i < data.length; i++) {
if (i < this.current) {
lineLeft += data[i].width
} else if (i == this.current) {
currentWidth = data[i].width
} else {
break
}
}
}
// 当前滑块的宽度
this.currentWidth = currentWidth
// 缩放后的滑块宽度
this.lineWidth = currentWidth * this.lineScale * 1
// 滑块作移动的位置
this.lineLeft = lineLeft + currentWidth / 2
// 胶囊距离左侧的位置
this.pillsLeft = lineLeft
// 计算滚动的距离左侧的位置
if (this.scroll) {
this.scrollLeft = this.lineLeft - this.containerWidth / 2
}
})
.exec()
}
},
mounted() {
this.elId = 'xfjpeter_' + this.randomString()
this.current = this.value
this.$nextTick(() => {
this.getTabItemWidth()
})
}
}
</script>
<style lang="scss" scoped>
.v-tabs {
width: 100%;
box-sizing: border-box;
overflow: hidden;
::-webkit-scrollbar {
display: none;
}
&__container {
min-width: 100%;
position: relative;
display: inline-flex;
align-items: center;
white-space: nowrap;
overflow: hidden;
&-item {
display: flex;
align-items: center;
height: 100%;
position: relative;
z-index: 10;
// padding: 0 11px;
transition: all 0.3s;
white-space: nowrap;
}
&-line {
position: absolute;
bottom: 0;
transition: all 0.3s linear;
}
&-pills {
position: absolute;
transition: all 0.3s linear;
z-index: 9;
}
}
}
</style>
var util = require('./util.js')
// 118.31.122.114 接口域名地址192.168.31.129
// var domain = "http://47.114.191.86:8201/mall-portal/"
// var domain = "http://192.168.31.42:8201/mall-portal/"
var domain = "https://api.tl.jsonpro.cn/mall-portal/"
// var domain = "http://192.168.1.35:8201/mall-portal/"
var imgUrl = "https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/"
// 请求方法处理
var request = function(method, url, params, cfg) {
// 获取本地token
var token = uni.getStorageSync('token')
// 设置头部
var header = {
'X-Access-Token': ''
}
// 判断有token设置进头部
if (token) {
header = {
// 'X-Access-Token': token
'Content-Type': 'application/json',
'Authorization': token
}
}
// 根据配置显示加载等待
if (!cfg.hideLoading) {
util.showLoading()
}
// 配置网络路径
if (url.indexOf('https://api.zhugonet.com') == -1) { //拿筑购网的数据
url = domain + url
}
// 打印日志
util.printLog('request url => ' + url)
util.printLog('request header => ' + JSON.stringify(header))
util.printLog('request params => ' + JSON.stringify(params))
// 请求处理
uni.request({
url: url,
method: method,
data: params,
header: header,
success: res => {
util.printLog('request url => ' + url)
util.printLog(res)
if (!cfg.hideLoading) {
util.closeLoading()
}
// util.closeLoading()
if (res.data.code == 200) {
//request success callback
if (cfg.suc) {
cfg.suc(res.data)
}
} else if (res.data.code == 401 || res.statusCode == 401) {
//request not authorization
util.goLogin()
} else {
//request error callback
if (cfg.erc) {
cfg.erc(res)
} else if (res.data.message) {
console.log('error: ', res)
util.showToast(res.data.message)
} else {
util.showToast('请求失败,请重试!')
}
}
},
fail: err => {
// util.closeLoading()
if (!cfg.hideLoading) {
util.closeLoading()
}
util.printLog('request url => ' + url)
util.printLog(err)
util.showToast('请求失败,请重试!')
if (cfg.erc) {
cfg.erc(err)
}
}
})
}
// 上传文件
var uploadImgByOss = function(filePath, cfg) {
// 设置请求头部
var header = {
'X-Access-Token': ''
}
// 请求路径
var url = domain + '/jeecg-boot-api/api/z/file/upload'
// 根据配置显示加载等待
if (!cfg.hideLoading) {
util.showLoading()
}
// 请求上传
uni.uploadFile({
url: url,
filePath: filePath,
name: 'file',
header: header,
formData: {},
success: res => {
util.printLog('request url => ' + url)
util.printLog(res)
util.closeLoading()
let data = res.data
if (data.constructor == String) {
data = JSON.parse(res.data)
}
if (data.code == 200) {
//request success callback
if (cfg.suc) {
cfg.suc(data)
}
} else if (data.code == 401 || res.statusCode == 401) {
//request not authorization
util.goLogin()
} else {
//request error callback
if (cfg.erc) {
cfg.erc(res)
} else if (data.message) {
util.showToast(data.message)
} else {
util.showToast('请求失败,请重试!')
}
}
},
fail: err => {
util.closeLoading()
util.printLog('request url => ' + url)
util.printLog(err)
util.showToast('请求失败,请重试!')
if (cfg.erc) {
cfg.erc(err)
}
}
})
}
// 对外方法导出
module.exports = {
// 接口域名
domain: domain,
// 图片资源网络路径前缀
IMG_BASE_URL: imgUrl,
// 统一请求处理
request: request,
// 上传图片
uploadImgByOss: uploadImgByOss,
// 获取验证码
checkCode(params, config) {
return request('GET', 'api/z/sms/checkCode', params, config)
},
// 注册
register(params, config) {
return request('POST', 'api/z/member/register', params, config)
},
// 微信登录
wxLogin(params, config) {
return request('POST', 'api/z/wx/login', params, config)
},
// 获取unionid、openid
getId(params, config) {
return request('GET', 'api/z/member/miniAppGetOpenIdAndUnionId', params, config)
},
// 绑定微信
bindWx(params, config) {
return request('POST', 'api/z/wx/bind', params, config)
},
// 密码登录
passLogin(params, config) {
return request('GET', 'api/z/member/login', params, config)
},
// 获取验证码
getCode(params, config) {
return request('GET', 'api/z/member/phoneCodeLogin', params, config)
},
// 重置密码
resetPassword(params, config) {
return request('POST', 'api/z/member/updatePassword', params, config)
},
// 首页数据
homeData(params, config) {
return request('GET', 'home/homeDate', params, config)
},
// 申请代理
applyAgent(params, config) {
return request('POST', 'agencyin/agencyinApply', params, config)
},
// 协议、说明详情
agreementDetail(params, config) {
return request('GET', 'api/z/content/getContentDetail', params, config)
},
// 台粮环境
tlImages(params, config) {
return request('GET', 'conditionList', params, config)
},
// 台粮报道
tlNews(params, config) {
return request('GET', 'proclamation/proclamationList', params, config)
},
// 商品列表
goodsList(params, config) {
return request('GET', 'api/z/product/list', params, config)
},
//商城首页轮播图
goodsSwiper(params, config) {
return request('GET', 'api/z/navigation/navigationList', params, config)
},
// 商品分类列表
goodsTypeList(params, config) {
return request('GET', 'api/z/product/sort/getProductSortList', params, config)
},
// 商品详情
goodsDetail(params, config) {
return request('GET', 'api/z/product/detail', params, config)
},
// 消息列表
msgList(params, config) {
return request('GET', 'message/list', params, config)
},
// 立即生成确认订单
makeConfirmOrder(params, config) {
return request('POST', 'order/immediatelyConfirmOrder', params, config)
},
// 立即生成订单
makeOrder(params, config) {
return request('POST', 'order/immediatelySubmitOrder', params, config)
},
// 购物车立即生成确认订单
cartMakeConfirmOrder(params, config) {
return request('POST', 'order/cartConfirmOrder', params, config)
},
// 购物车立即生成订单
cartMakeOrder(params, config) {
return request('POST', 'order/cartSubmitOrder', params, config)
},
// 立即支付(积分)
pay(params, config) {
return request('POST', 'order/integralPay', params, config)
},
// 支付(微信)
wxPay(params, config) {
return request('POST', 'pay/wxMaCreateOrder', params, config)
},
// 个人中心
personal(params, config) {
return request('GET', 'member/detail', params, config)
},
// 带对碰列表
vipChildList(params, config) {
return request('GET', 'member/listOfPendingMembers', params, config)
},
// 填写微信号
writeWechat(params, config) {
return request('GET', 'member/fillInWeChatAccount', params, config)
},
// 修改个人信息
setUserInfo(params, config) {
return request('POST', 'member/updateMessage', params, config)
},
// 订单列表
orderInfo(params, config) {
return request('GET', 'order/sonList', params, config)
},
// 删除订单
delOrder(params, config) {
return request('GET', 'order/deleteOrder', params, config)
},
// 订单详情
orderDetail(params, config) {
return request('GET', 'order/detail', params, config)
},
// 我的钱包
myWallet(params, config) {
return request('GET', 'member/account', params, config)
},
// 管理奖
mangerPrize(params, config) {
return request('GET', 'account/managementAward', params, config)
},
// 管理奖转出
mangerPrizeOut(params, config) {
return request('GET', 'account/managementAwardTransferOut', params, config)
},
// 提现
cashOut(params, config) {
return request('POST', 'withdraw/withdrawApply', params, config)
},
// 余额/提现明细
balanceRecord(params, config) {
return request('GET', 'member/accountDetail', params, config)
},
// 提现金额判断
judgAmount(params, config) {
return request('GET', 'withdraw/amountJudgment', params, config)
},
// 我的银行卡
myBankCard(params, config) {
return request('GET', 'bank/detail', params, config)
},
// 更新银行卡信息
updateMyBankCard(params, config) {
return request('POST', 'bank/updateMyBank', params, config)
},
// 优惠券
myCoupon(params, config) {
return request('GET', 'coupon/myCoupon', params, config)
},
// 收货地址
myAdress(params, config) {
return request('GET', 'address/list', params, config)
},
// 新增/编辑收货地址
addEditAdress(params, config) {
return request('POST', 'address/add', params, config)
},
// 收货地址 编辑查询
adressDetail(params, config) {
return request('GET', 'address/detail', params, config)
},
// 删除收货地址
delAdress(params, config) {
return request('GET', 'address/delete', params, config)
},
// 订单列表
myOrder(params, config) {
return request('GET', 'order/sonList', params, config)
},
// 订单列表付款时获取的单号
orderGetInfo(params, config) {
return request('POST', 'order/getOrderSn', params, config)
},
// 确认收货
confirmReceiv(params, config) {
return request('GET', 'order/confirmOrder', params, config)
},
// 提醒发货
remindShip(params, config) {
return request('GET', 'order/tipShip', params, config)
},
// 商品收藏列表
goodsCollection(params, config) {
return request('GET', 'collect/productList', params, config)
},
// 添加/取消收藏
setCollection(params, config) {
return request('GET', 'collect/addOrCancel', params, config)
},
// 添加购物车
addShopCar(params, config) {
return request('POST', 'cart/addProduct', params, config)
},
// 购物车列表
shopCarList(params, config) {
return request('GET', 'cart/list', params, config)
},
// 修改购物车中的商品数量
setShopCarCount(params, config) {
return request('GET', 'cart/updateCartProductCount', params, config)
},
// 从购物车中删除
shopCarDelGoods(params, config) {
return request('POST', 'cart/removeProduct', params, config)
},
// 获取所有城市
getCitys(params, config) {
return request('GET', 'api/z/area/getcity', params, config)
},
// 物流信息
logisticDetail(params, config) {
return request('GET', 'order/getLogisticDate', params, config)
},
// OSS上传
ossPolicy(params, config) {
return request('GET', 'aliyun/oss/policy', params, config)
},
// 获取邀请码
getInvitaCode(params, config) {
return request('GET', 'api/z/member/memberInvitationCode', params, config)
},
// 我的团队
myTeam(params, config) {
return request('GET', 'member/myTeam', params, config)
},
// 团队成员业绩
teamDetail(params, config) {
return request('GET', 'member/memberPerformanceDetail', params, config)
},
// 坐标转换
location(params, config) {
return request('GET', 'https://restapi.amap.com/v3/assistant/coordinate/convert?parameters', params, config)
},
// 意见反馈
feedback(params, config) {
return request('POST', 'member/saveMemberFeedback', params, config)
},
// 选择位置
areaList(params, config) {
return request('GET', 'api/z/area/list', params, config)
},
//所有城市
allCityList(params, config) {
return request('GET', 'https://api.zhugonet.com/jeecg-boot-api/api/z/area/all', params, config)
}
}
// uni框架的方法封装
const main = {
// 显示消息提示窗
showToast: (title = '', duration = 1500, icon = 'none') => {
uni.showToast({
icon: icon,
title: title,
duration: duration
})
},
// 隐藏消息提示窗
hideToast: () => {
uni.hideToast()
},
// 显示loadding提示窗 需主动调用 hideLoading 才能关闭提示框
showLoading: (title = '') => {
uni.showLoading({
title: title
})
},
// 隐藏loadding提示窗
hideLoading: (duration = 0) => {
setTimeout(function () {
uni.hideLoading()
}, duration)
},
// 显示模态提示框
showModal: (content = '', title = '提示', showCancel = true, confirmText = '确定', cancelText = '取消', confirmColor = '#50A8FC', cancelColor = '#9b9b9b') => {
if (content && content instanceof Object) {
let data = content
title = data.title || title
showCancel = data.showCancel || showCancel
confirmText = data.confirmText || confirmText
cancelText = data.cancelText || cancelText
confirmColor = data.confirmColor || confirmColor
cancelColor = data.cancelColor || cancelColor
content = data.content || ''
}
var promise = new Promise(function (resolve, reject) {
uni.showModal({
title: title, // 标题
content: content, // 内容
showCancel: showCancel, // 是否显示取消按钮
confirmText: confirmText, // 确认按钮文字
cancelText: cancelText, // 取消按钮文字
confirmColor: confirmColor, // 确认按钮颜色
cancelColor: cancelColor, // 取消按钮颜色
success: function (res) {
if (res.confirm) {
resolve(true)
} else if (res.cancel) {
resolve(false)
}
}
})
})
return promise
},
// 显示从底部弹出的操作菜单
showActionSheet: (itemList = [], itemColor = '#333333') => {
var promise = new Promise(function (resolve, reject) {
uni.showActionSheet({
itemList: itemList, // 菜单列表
itemColor: itemColor, // 选项文字
success (res) {
resolve(res.tapIndex)
},
fail (res) {
resolve(false)
}
})
})
return promise
},
// 动态设置当前页面的标题
setNavigationBarTitle: (title = '') => {
uni.setNavigationBarTitle({
title: title
})
},
//将页面滚动到目标位置
pageScrollTo: (scrollTop, selector, duration = 300) => {
uni.pageScrollTo({
scrollTop: scrollTop,
selector: selector, // 选择器(id、class)
duration: duration
})
},
//获取当前位置(经度、纬度)
getLocation: (type = 'wgs84') => {
var promise = new Promise((resolve, reject) => {
uni.getLocation({
type: type,
success: res => {
resolve(res)
},
fail: err => {
reject(err)
}
})
})
return promise
},
// 复制文本内容
setClipboardData: (data, msg = '') => {
uni.setClipboardData({
data: data, // 复制的文本
success: function () {
if (msg) {
main.showToast(msg, 1000)
}
}
})
},
// 支付
requestPayment: (type, orderInfo) => {
var promise = new Promise (function (resolve, reject) {
uni.requestPayment({
provider: type,
orderInfo: orderInfo,
success: (res) => {
resolve (res)
},
fail: (err) => {
// console.log('err', err)
}
})
})
return promise
},
// 登录
uniLogin: (type) => {
var promise = new Promise (function (resolve, reject) {
uni.login({
provider: type,
success: (res) => {
resolve(res)
},
fail: (err) => {
reject(err)
}
})
})
return promise
}
}
export default main
\ No newline at end of file
// 配置路由
const path = {
// 跳转到非tabBar的子页面
navigateTo (url) {
uni.navigateTo({
url: url
})
},
// 跳转到tabBar页面
switchTab (url) {
uni.switchTab({
url: url
})
},
// 重定向跳转
redirectTo (url) {
uni.redirectTo({
url: url
})
},
// 关闭所有页面,跳转一个新页面
reLaunch (url) {
uni.reLaunch({
url: url
})
},
// 返回上一个页面
navigateBack (count) {
uni.navigateBack({
delta: count
})
},
// 预加载页面,打开时速度更快
preloadPage (url) {
uni.preloadPage({
url: url
})
}
}
export default path
// 缓存封装
const store = {
// 存缓存
setStorage: (key, data) => {
uni.setStorage({
key: key,
data: data
})
},
// 存缓存(同步)
setStorageSync: (key, data) => {
try {
uni.setStorageSync(key, data)
} catch (e) {
// error
}
},
// 取缓存 (异步)
getStorage(key) {
var promise = new Promise((resolve, reject) => {
uni.getStorage({
key: key,
success (res) {
resolve(res.data)
},
fail (err) {
},
complete (res) {
}
})
})
return promise
},
// 取缓存(同步)
getStorageSync(key) {
return uni.getStorageSync(key)
},
// 移除缓存(异步)
removeStorage(key) {
uni.removeStorage({
key: key
})
},
// 移除缓存(同步)
removeStorageSync(key) {
uni.removeStorageSync(key)
},
// 清空缓存(异步)
clearStorage: () => {
uni.clearStorage()
},
//清空缓存(同步)
clearStorageSync: () => {
uni.clearStorageSync()
}
}
export default store
\ No newline at end of file
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [hour, minute].map(formatNumber).join(':')
}
const formatDate = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('-')
}
const showIntervalTime = (currentTime, nowTime) => {
var time = Math.floor((nowTime - currentTime) / 1000)
var str = ''
if (time < 60) {
str = '1分钟'
} else if (time > 60 && time < 3600) {
str = Math.ceil(time / 60) + '分钟'
} else if (time > 3600 && time < 3600 * 24) {
str = Math.ceil(time / 3600) + '小时'
} else {
str = Math.ceil(time / (3600 * 24)) + '天'
}
return str
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
const getDistance = (la1, lo1, la2, lo2) => {
var La1 = la1 * Math.PI / 180.0
var La2 = la2 * Math.PI / 180.0
var La3 = La1 - La2
var Lb3 = lo1 * Math.PI / 180.0 - lo2 * Math.PI / 180.0
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(La3 / 2), 2) + Math.cos(La1) * Math.cos(La2) * Math.pow(Math.sin(
Lb3 / 2), 2)))
s = s * 6378.137
s = Math.round(s * 10000) / 10000
s = s > 1 ? s.toFixed(2) + 'km' : (s * 1000).toFixed(0) + 'm'
return s
}
const hidePhone = (phone) => {
if (phone) {
return phone.substring(0, 3) + '****' + phone.substring(7)
} else {
return ''
}
}
//从存储去获取用户信息
const getUsersInfoByStore = () => {
var obj = {}
if (uni.getStorageSync('user')) {
let userInfoStr = uni.getStorageSync('user')
obj = JSON.parse(userInfoStr)
}
return obj
}
// 搜索历史
const getSearchHistory = () => {
let history = []
let historyStr = uni.getStorageSync('search')
if (historyStr) {
history = historyStr.split(',')
}
return history
}
// 设置搜索历史
const addSearchHistory = (word) => {
let history = getSearchHistory()
if (history.indexOf(word) != -1) {
history.splice(history.indexOf(word), 1)
}
history.unshift(word)
uni.setStorageSync('search', history.join(','))
}
// 清空搜索历史
const clearSearchHistory = () => {
uni.setStorageSync('search', '')
}
// 微信分享 朋友圈/好友
const wetchatShare = (scene, href, title, summary, imageUrl) => {
//如果没图片就用logo图
var imgUrl = (imageUrl.length > 0) ? imageUrl : 'https://yun-kuang.oss-cn-hangzhou.aliyuncs.com/upload/test/ic_logo_1603180073960.png';
uni.share({
provider: "weixin",
scene: scene,
type: 0,
href: href,
title: title,
summary: summary,
imageUrl: imgUrl,//decodeURIComponent(imageUrl),//还是显示不了
success: function(res) {
uni.showToast({
title: '分享成功',
icon: 'none'
})
},
fail: function(err) {
console.log("fail:" + JSON.stringify(err));
uni.showToast({
title: '分享失败',
icon: 'none'
})
}
});
}
//转rgb
//https://blog.csdn.net/mossbaoo/article/details/93484635
const colorRgb = (oldColor,rgb) => {
// 16进制颜色值的正则
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
// 把颜色值变成小写
var color = oldColor.toLowerCase();
if (reg.test(color)) {
// 如果只有三位的值,需变成六位,如:#fff => #ffffff
if (color.length === 4) {
var colorNew = "#";
for (var i = 1; i < 4; i += 1) {
colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1));
}
color = colorNew;
}
// 处理六位的颜色值,转为RGB
var colorChange = [];
for (var i = 1; i < 7; i += 2) {
colorChange.push(parseInt("0x" + color.slice(i, i + 2)));
}
return "RGB(" + colorChange.join(",") + "," + rgb +")";
} else {
return color;
}
}
module.exports = {
formatTime: formatTime,
formatDate: formatDate,
showIntervalTime: showIntervalTime,
getDistance: getDistance,
hidePhone: hidePhone,
getSearchHistory: getSearchHistory,
addSearchHistory: addSearchHistory,
clearSearchHistory: clearSearchHistory,
getUsersInfoByStore: getUsersInfoByStore,
wetchatShare: wetchatShare,
colorRgb:colorRgb,
printLog: function(msg) {
console.log(msg)
},
showLoading: function() {
uni.showLoading({
title: '加载中'
})
},
closeLoading: function() {
uni.hideLoading()
},
showToast: function(msg) {
uni.showToast({
title: msg,
icon: 'none'
})
},
isLogin: function() {
return uni.getStorageSync('token')
},
goLogin: function() {
uni.removeStorageSync('token')
uni.removeStorageSync('user')
uni.reLaunch({
url: '/pages/index/login'
})
},
//是否安装微信
isInstallWetchat: function() {
var isInstall = false;
// 判断第三方程序(微信) 是否安装
if(plus.runtime.isApplicationExist({pname:'com.hexagon.sandstone',action:'weixin://'})){
console.log("微信应用已安装");
isInstall = true;
}else{
console.log("微信应用未安装");
isInstall = false;
}
return isInstall;
}
}
function AMapWX(a){this.key=a.key,this.requestConfig={key:a.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"}}AMapWX.prototype.getWxLocation=function(a,b){wx.getLocation({type:"gcj02",success:function(a){var c=a.longitude+","+a.latitude;wx.setStorage({key:"userLocation",data:c}),b(c)},fail:function(c){wx.getStorage({key:"userLocation",success:function(a){a.data&&b(a.data)}}),a.fail({errCode:"0",errMsg:c.errMsg||""})}})},AMapWX.prototype.getRegeo=function(a){function c(c){var d=b.requestConfig;wx.request({url:"https://restapi.amap.com/v3/geocode/regeo",data:{key:b.key,location:c,extensions:"all",s:d.s,platform:d.platform,appname:b.key,sdkversion:d.sdkversion,logversion:d.logversion},method:"GET",header:{"content-type":"application/json"},success:function(b){var d,e,f,g,h,i,j,k,l;b.data.status&&"1"==b.data.status?(d=b.data.regeocode,e=d.addressComponent,f=[],g="",d&&d.roads[0]&&d.roads[0].name&&(g=d.roads[0].name+"附近"),h=c.split(",")[0],i=c.split(",")[1],d.pois&&d.pois[0]&&(g=d.pois[0].name+"附近",j=d.pois[0].location,j&&(h=parseFloat(j.split(",")[0]),i=parseFloat(j.split(",")[1]))),e.provice&&f.push(e.provice),e.city&&f.push(e.city),e.district&&f.push(e.district),e.streetNumber&&e.streetNumber.street&&e.streetNumber.number?(f.push(e.streetNumber.street),f.push(e.streetNumber.number)):(k="",d&&d.roads[0]&&d.roads[0].name&&(k=d.roads[0].name),f.push(k)),f=f.join(""),l=[{iconPath:a.iconPath,width:a.iconWidth,height:a.iconHeight,name:f,desc:g,longitude:h,latitude:i,id:0,regeocodeData:d}],a.success(l)):a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}var b=this;a.location?c(a.location):b.getWxLocation(a,function(a){c(a)})},AMapWX.prototype.getWeather=function(a){function d(d){var e="base";a.type&&"forecast"==a.type&&(e="all"),wx.request({url:"https://restapi.amap.com/v3/weather/weatherInfo",data:{key:b.key,city:d,extensions:e,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion},method:"GET",header:{"content-type":"application/json"},success:function(b){function c(a){var b={city:{text:"城市",data:a.city},weather:{text:"天气",data:a.weather},temperature:{text:"温度",data:a.temperature},winddirection:{text:"风向",data:a.winddirection+"风"},windpower:{text:"风力",data:a.windpower+"级"},humidity:{text:"湿度",data:a.humidity+"%"}};return b}var d,e;b.data.status&&"1"==b.data.status?b.data.lives?(d=b.data.lives,d&&d.length>0&&(d=d[0],e=c(d),e["liveData"]=d,a.success(e))):b.data.forecasts&&b.data.forecasts[0]&&a.success({forecast:b.data.forecasts[0]}):a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}function e(e){wx.request({url:"https://restapi.amap.com/v3/geocode/regeo",data:{key:b.key,location:e,extensions:"all",s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion},method:"GET",header:{"content-type":"application/json"},success:function(b){var c,e;b.data.status&&"1"==b.data.status?(e=b.data.regeocode,e.addressComponent?c=e.addressComponent.adcode:e.aois&&e.aois.length>0&&(c=e.aois[0].adcode),d(c)):a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}var b=this,c=b.requestConfig;a.city?d(a.city):b.getWxLocation(a,function(a){e(a)})},AMapWX.prototype.getPoiAround=function(a){function d(d){var e={key:b.key,location:d,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.querytypes&&(e["types"]=a.querytypes),a.querykeywords&&(e["keywords"]=a.querykeywords),wx.request({url:"https://restapi.amap.com/v3/place/around",data:e,method:"GET",header:{"content-type":"application/json"},success:function(b){var c,d,e,f;if(b.data.status&&"1"==b.data.status){if(b=b.data,b&&b.pois){for(c=[],d=0;d<b.pois.length;d++)e=0==d?a.iconPathSelected:a.iconPath,c.push({latitude:parseFloat(b.pois[d].location.split(",")[1]),longitude:parseFloat(b.pois[d].location.split(",")[0]),iconPath:e,width:22,height:32,id:d,name:b.pois[d].name,address:b.pois[d].address});f={markers:c,poisData:b.pois},a.success(f)}}else a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}var b=this,c=b.requestConfig;a.location?d(a.location):b.getWxLocation(a,function(a){d(a)})},AMapWX.prototype.getStaticmap=function(a){function f(b){c.push("location="+b),a.zoom&&c.push("zoom="+a.zoom),a.size&&c.push("size="+a.size),a.scale&&c.push("scale="+a.scale),a.markers&&c.push("markers="+a.markers),a.labels&&c.push("labels="+a.labels),a.paths&&c.push("paths="+a.paths),a.traffic&&c.push("traffic="+a.traffic);var e=d+c.join("&");a.success({url:e})}var e,b=this,c=[],d="https://restapi.amap.com/v3/staticmap?";c.push("key="+b.key),e=b.requestConfig,c.push("s="+e.s),c.push("platform="+e.platform),c.push("appname="+e.appname),c.push("sdkversion="+e.sdkversion),c.push("logversion="+e.logversion),a.location?f(a.location):b.getWxLocation(a,function(a){f(a)})},AMapWX.prototype.getInputtips=function(a){var b=this,c=b.requestConfig,d={key:b.key,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.location&&(d["location"]=a.location),a.keywords&&(d["keywords"]=a.keywords),a.type&&(d["type"]=a.type),a.city&&(d["city"]=a.city),a.citylimit&&(d["citylimit"]=a.citylimit),wx.request({url:"https://restapi.amap.com/v3/assistant/inputtips",data:d,method:"GET",header:{"content-type":"application/json"},success:function(b){b&&b.data&&b.data.tips&&a.success({tips:b.data.tips})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})},AMapWX.prototype.getDrivingRoute=function(a){var b=this,c=b.requestConfig,d={key:b.key,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.origin&&(d["origin"]=a.origin),a.destination&&(d["destination"]=a.destination),a.strategy&&(d["strategy"]=a.strategy),a.waypoints&&(d["waypoints"]=a.waypoints),a.avoidpolygons&&(d["avoidpolygons"]=a.avoidpolygons),a.avoidroad&&(d["avoidroad"]=a.avoidroad),wx.request({url:"https://restapi.amap.com/v3/direction/driving",data:d,method:"GET",header:{"content-type":"application/json"},success:function(b){b&&b.data&&b.data.route&&a.success({paths:b.data.route.paths,taxi_cost:b.data.route.taxi_cost||""})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})},AMapWX.prototype.getWalkingRoute=function(a){var b=this,c=b.requestConfig,d={key:b.key,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.origin&&(d["origin"]=a.origin),a.destination&&(d["destination"]=a.destination),wx.request({url:"https://restapi.amap.com/v3/direction/walking",data:d,method:"GET",header:{"content-type":"application/json"},success:function(b){b&&b.data&&b.data.route&&a.success({paths:b.data.route.paths})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})},AMapWX.prototype.getTransitRoute=function(a){var b=this,c=b.requestConfig,d={key:b.key,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.origin&&(d["origin"]=a.origin),a.destination&&(d["destination"]=a.destination),a.strategy&&(d["strategy"]=a.strategy),a.city&&(d["city"]=a.city),a.cityd&&(d["cityd"]=a.cityd),wx.request({url:"https://restapi.amap.com/v3/direction/transit/integrated",data:d,method:"GET",header:{"content-type":"application/json"},success:function(b){if(b&&b.data&&b.data.route){var c=b.data.route;a.success({distance:c.distance||"",taxi_cost:c.taxi_cost||"",transits:c.transits})}},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})},AMapWX.prototype.getRidingRoute=function(a){var b=this,c=b.requestConfig,d={key:b.key,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.origin&&(d["origin"]=a.origin),a.destination&&(d["destination"]=a.destination),wx.request({url:"https://restapi.amap.com/v4/direction/bicycling",data:d,method:"GET",header:{"content-type":"application/json"},success:function(b){b&&b.data&&b.data.data&&a.success({paths:b.data.data.paths})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})},module.exports.AMapWX=AMapWX;
\ No newline at end of file
import Vue from 'vue'
import App from './App'
import path from './config/router.js'
import store from './config/store.js'
import main from './config/main.js'
import api from './config/api.js'
Vue.config.productionTip = false
Vue.prototype.$path = path
Vue.prototype.$store = store
Vue.prototype.$main = main
Vue.prototype.$api = api
App.mpType = 'app'
// Vue.util.productionTip = false
const app = new Vue({
...App,
path,
store,
main,
api
})
app.$mount()
{
"name" : "华仁优选",
"appid" : "__UNI__E592995",
"description" : "华仁优选",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* 模块配置 */
"modules" : {
"Payment" : {},
"OAuth" : {},
"Share" : {},
"Maps" : {}
},
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
"android" : {
"permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios打包配置 */
"ios" : {
"privacyDescription" : {
"NSLocationWhenInUseUsageDescription" : "华仁访问您的位置,仅仅显示你当前的位置,从而更快得到你附近咨讯和供应商品数据,该信息数据不会上传到服务器",
"NSLocationAlwaysUsageDescription" : "华仁访问您的位置,仅仅显示你当前的位置,从而更快得到你附近咨讯和供应商品数据,该信息数据不会上传到服务器",
"NSLocationAlwaysAndWhenInUseUsageDescription" : "华仁访问您的位置,仅仅显示你当前的位置,从而更快得到你附近咨讯和供应商品数据,该信息数据不会上传到服务器"
}
},
/* SDK配置 */
"sdkConfigs" : {
"ad" : {},
"payment" : {
"alipay" : {
"__platform__" : [ "android" ]
},
"weixin" : {
"__platform__" : [ "android" ],
"appid" : "wx5ffb0a232bf3fc9b",
"UniversalLinks" : "https://tr5z78.xinstall.top/tolink/"
}
},
"oauth" : {
"weixin" : {
"appid" : "wx5ffb0a232bf3fc9b",
"appsecret" : "ffb9665edfbbdeeebba04c01e5272a9d",
"UniversalLinks" : "https://tr5z78.xinstall.top/tolink/"
}
},
"share" : {
"weixin" : {
"appid" : "wx5ffb0a232bf3fc9b",
"UniversalLinks" : "https://tr5z78.xinstall.top/tolink/"
}
},
"maps" : {
"amap" : {
"appkey_ios" : "67250069dd9762ec0b12b6b49a2150f9",
"appkey_android" : "892e741ef93a9552647aec2826f038c0"
}
},
"geolocation" : {}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
},
"splashscreen" : {
"androidStyle" : "common"
}
}
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "wx5990f741872f4974",
"setting" : {
"urlCheck" : false,
"es6" : true,
"minified" : false
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true,
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于小程序位置接口的效果展示"
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"mp-qq" : {
"uniStatistics" : {
"enable" : false
}
},
"h5" : {
"title" : "华仁优选",
"domain" : "http://hr.jsonpro.cn"
}
}
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"address": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/address/download/address-1.1.2.tgz",
"integrity": "sha1-vxEWycdYxRt6kz0pa3LCIe2UKLY="
},
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npm.taobao.org/agent-base/download/agent-base-4.3.0.tgz",
"integrity": "sha1-gWXwHENgCbzK0LHRIvBe13Dvxu4=",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"agentkeepalive": {
"version": "3.5.2",
"resolved": "https://registry.npm.taobao.org/agentkeepalive/download/agentkeepalive-3.5.2.tgz?cache=0&sync_timestamp=1592196581655&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fagentkeepalive%2Fdownload%2Fagentkeepalive-3.5.2.tgz",
"integrity": "sha1-oROSTdP6JKC8O3gQjEUMKr7gD2c=",
"requires": {
"humanize-ms": "^1.2.1"
}
},
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz",
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
},
"ast-types": {
"version": "0.14.2",
"resolved": "https://registry.npm.taobao.org/ast-types/download/ast-types-0.14.2.tgz",
"integrity": "sha1-YAuILfhYPjzU8t9fog+oN1nUvf0=",
"requires": {
"tslib": "^2.0.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"bowser": {
"version": "1.9.4",
"resolved": "https://registry.npm.taobao.org/bowser/download/bowser-1.9.4.tgz",
"integrity": "sha1-iQxYooE6nTJDcEM0+oG5alwVDJo="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz?cache=0&sync_timestamp=1601898189928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrace-expansion%2Fdownload%2Fbrace-expansion-1.1.11.tgz",
"integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"builtin-status-codes": {
"version": "3.0.0",
"resolved": "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz",
"integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz",
"integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"co-defer": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/co-defer/download/co-defer-1.0.0.tgz",
"integrity": "sha1-Pkp4eo7tawoh7ih8CU9+jeDTyBg="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz",
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js="
},
"copy-to": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/copy-to/download/copy-to-2.0.1.tgz",
"integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"data-uri-to-buffer": {
"version": "1.2.0",
"resolved": "https://registry.npm.taobao.org/data-uri-to-buffer/download/data-uri-to-buffer-1.2.0.tgz",
"integrity": "sha1-dxY+qcINhkG0cH6PGKvfmnjzSDU="
},
"dateformat": {
"version": "2.2.0",
"resolved": "https://registry.npm.taobao.org/dateformat/download/dateformat-2.2.0.tgz?cache=0&sync_timestamp=1608672393856&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdateformat%2Fdownload%2Fdateformat-2.2.0.tgz",
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
"integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
},
"default-user-agent": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/default-user-agent/download/default-user-agent-1.0.0.tgz",
"integrity": "sha1-FsRu/cq6PtxF8k8r1IaLAbfCrcY=",
"requires": {
"os-name": "~1.0.3"
}
},
"degenerator": {
"version": "1.0.4",
"resolved": "https://registry.npm.taobao.org/degenerator/download/degenerator-1.0.4.tgz",
"integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=",
"requires": {
"ast-types": "0.x.x",
"escodegen": "1.x.x",
"esprima": "3.x.x"
}
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"digest-header": {
"version": "0.0.1",
"resolved": "https://registry.npm.taobao.org/digest-header/download/digest-header-0.0.1.tgz",
"integrity": "sha1-Ecz23uxXZqw3l0TZAcEsuklRS+Y=",
"requires": {
"utility": "0.1.11"
},
"dependencies": {
"utility": {
"version": "0.1.11",
"resolved": "https://registry.npm.taobao.org/utility/download/utility-0.1.11.tgz?cache=0&sync_timestamp=1608037972811&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futility%2Fdownload%2Futility-0.1.11.tgz",
"integrity": "sha1-/eYM+bTkdRlHoM9dEEzik2ciZxU=",
"requires": {
"address": ">=0.0.1"
}
}
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.4.tgz?cache=0&sync_timestamp=1569416367473&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fend-of-stream%2Fdownload%2Fend-of-stream-1.4.4.tgz",
"integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=",
"requires": {
"once": "^1.4.0"
}
},
"end-or-error": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/end-or-error/download/end-or-error-1.0.1.tgz",
"integrity": "sha1-3HpiEP5403L+4kqLSJnb0VVBTcs="
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npm.taobao.org/es6-promise/download/es6-promise-4.2.8.tgz",
"integrity": "sha1-TrIVlMlyvEBVPSduUQU5FD21Pgo="
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npm.taobao.org/es6-promisify/download/es6-promisify-5.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes6-promisify%2Fdownload%2Fes6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"requires": {
"es6-promise": "^4.0.3"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"escodegen": {
"version": "1.14.3",
"resolved": "https://registry.npm.taobao.org/escodegen/download/escodegen-1.14.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescodegen%2Fdownload%2Fescodegen-1.14.3.tgz",
"integrity": "sha1-TnuB+6YVgdyXWC7XjKt/Do1j9QM=",
"requires": {
"esprima": "^4.0.1",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
},
"dependencies": {
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz",
"integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE="
}
}
},
"esprima": {
"version": "3.1.3",
"resolved": "https://registry.npm.taobao.org/esprima/download/esprima-3.1.3.tgz",
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1596641261520&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz",
"integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0="
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz",
"integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz",
"integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo="
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz?cache=0&sync_timestamp=1595428000133&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-levenshtein%2Fdownload%2Ffast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz?cache=0&sync_timestamp=1570825475173&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffile-uri-to-path%2Fdownload%2Ffile-uri-to-path-1.0.0.tgz",
"integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90="
},
"formstream": {
"version": "1.1.0",
"resolved": "https://registry.npm.taobao.org/formstream/download/formstream-1.1.0.tgz",
"integrity": "sha1-UfOXDyYTbrCtRDBN5M67UCB7RHk=",
"requires": {
"destroy": "^1.0.4",
"mime": "^1.3.4",
"pause-stream": "~0.0.11"
},
"dependencies": {
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz?cache=0&sync_timestamp=1608084083331&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-1.6.0.tgz",
"integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE="
}
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"ftp": {
"version": "0.3.10",
"resolved": "https://registry.npm.taobao.org/ftp/download/ftp-0.3.10.tgz",
"integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
"requires": {
"readable-stream": "1.1.x",
"xregexp": "2.0.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz?cache=0&sync_timestamp=1562592096220&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fisarray%2Fdownload%2Fisarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-1.1.14.tgz?cache=0&sync_timestamp=1581624324274&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-0.10.31.tgz?cache=0&sync_timestamp=1565170823020&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring_decoder%2Fdownload%2Fstring_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
}
}
},
"get-ready": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/get-ready/download/get-ready-1.0.0.tgz",
"integrity": "sha1-+RgX8emt7P6hOlYq38jeiDqzR4I="
},
"get-uri": {
"version": "2.0.4",
"resolved": "https://registry.npm.taobao.org/get-uri/download/get-uri-2.0.4.tgz",
"integrity": "sha1-1JN6uBniGNTLWuGOT1livvFpzGo=",
"requires": {
"data-uri-to-buffer": "1",
"debug": "2",
"extend": "~3.0.2",
"file-uri-to-path": "1",
"ftp": "~0.3.10",
"readable-stream": "2"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1573078121947&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz",
"integrity": "sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz?cache=0&sync_timestamp=1593407679215&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.3.tgz",
"integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npm.taobao.org/http-proxy-agent/download/http-proxy-agent-2.1.0.tgz",
"integrity": "sha1-5IIb7vWyFCogJr1zkm/lN2McVAU=",
"requires": {
"agent-base": "4",
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"https-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npm.taobao.org/https-proxy-agent/download/https-proxy-agent-3.0.1.tgz",
"integrity": "sha1-uMKGQz6HYCMRsByOo0QT2Fakr4E=",
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.7.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.7.tgz",
"integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npm.taobao.org/humanize-ms/download/humanize-ms-1.2.1.tgz",
"integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
"requires": {
"ms": "^2.0.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184297399&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz",
"integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz?cache=0&sync_timestamp=1560975547815&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finherits%2Fdownload%2Finherits-2.0.4.tgz",
"integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w="
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
},
"is-class-hotfix": {
"version": "0.0.6",
"resolved": "https://registry.npm.taobao.org/is-class-hotfix/download/is-class-hotfix-0.0.6.tgz",
"integrity": "sha1-pSfTH7IyeSgd3l84XHe13nCnJDU="
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
},
"is-type-of": {
"version": "1.2.1",
"resolved": "https://registry.npm.taobao.org/is-type-of/download/is-type-of-1.2.1.tgz",
"integrity": "sha1-4mPsOFes608oxHEw7HjbCakg+MU=",
"requires": {
"core-util-is": "^1.0.2",
"is-class-hotfix": "~0.0.6",
"isstream": "~0.1.2"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz?cache=0&sync_timestamp=1562592096220&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fisarray%2Fdownload%2Fisarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"js-base64": {
"version": "2.6.4",
"resolved": "https://registry.npm.taobao.org/js-base64/download/js-base64-2.6.4.tgz?cache=0&sync_timestamp=1604448575022&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-base64%2Fdownload%2Fjs-base64-2.6.4.tgz",
"integrity": "sha1-9OaGxd4eofhn28rT1G2WlCjfmMQ="
},
"jstoxml": {
"version": "0.2.4",
"resolved": "https://registry.npm.taobao.org/jstoxml/download/jstoxml-0.2.4.tgz",
"integrity": "sha1-/z+2eFaIOgMpU8fOjOdIYhD0hEc="
},
"ko-sleep": {
"version": "1.0.3",
"resolved": "https://registry.npm.taobao.org/ko-sleep/download/ko-sleep-1.0.3.tgz",
"integrity": "sha1-KKKgoUhei39BX/SI3uF9JHiKsII=",
"requires": {
"ms": "^2.0.0"
}
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz?cache=0&sync_timestamp=1594427700888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-5.1.1.tgz",
"integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=",
"requires": {
"yallist": "^3.0.2"
}
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"mime": {
"version": "2.4.7",
"resolved": "https://registry.npm.taobao.org/mime/download/mime-2.4.7.tgz?cache=0&sync_timestamp=1608084083331&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-2.4.7.tgz",
"integrity": "sha1-lirtm+DtGckf19wuzl1/TompDXQ="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz",
"integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz",
"integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI="
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz",
"integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=",
"requires": {
"minimist": "^1.2.5"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.3.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.3.tgz",
"integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI="
},
"mz": {
"version": "2.7.0",
"resolved": "https://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz",
"integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=",
"requires": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
"thenify-all": "^1.0.0"
}
},
"mz-modules": {
"version": "2.1.0",
"resolved": "https://registry.npm.taobao.org/mz-modules/download/mz-modules-2.1.0.tgz",
"integrity": "sha1-f1KYd6/Q1C9AmnRjuWmG1hz7z5Y=",
"requires": {
"glob": "^7.1.2",
"ko-sleep": "^1.0.3",
"mkdirp": "^0.5.1",
"pump": "^3.0.0",
"rimraf": "^2.6.1"
}
},
"netmask": {
"version": "1.0.6",
"resolved": "https://registry.npm.taobao.org/netmask/download/netmask-1.0.6.tgz",
"integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz?cache=0&sync_timestamp=1571657171505&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-assign%2Fdownload%2Fobject-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"optionator": {
"version": "0.8.3",
"resolved": "https://registry.npm.taobao.org/optionator/download/optionator-0.8.3.tgz?cache=0&sync_timestamp=1585966141328&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Foptionator%2Fdownload%2Foptionator-0.8.3.tgz",
"integrity": "sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU=",
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
}
},
"os-name": {
"version": "1.0.3",
"resolved": "https://registry.npm.taobao.org/os-name/download/os-name-1.0.3.tgz",
"integrity": "sha1-GzefZINa98Wn9JizV8uVIVwVnt8=",
"requires": {
"osx-release": "^1.0.0",
"win-release": "^1.0.0"
}
},
"osx-release": {
"version": "1.1.0",
"resolved": "https://registry.npm.taobao.org/osx-release/download/osx-release-1.1.0.tgz",
"integrity": "sha1-8heRGigTaUmvG/kwiyQeJzfTzWw=",
"requires": {
"minimist": "^1.1.0"
}
},
"pac-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npm.taobao.org/pac-proxy-agent/download/pac-proxy-agent-3.0.1.tgz",
"integrity": "sha1-EVseWPkldsrC66cYWTynsON94q0=",
"requires": {
"agent-base": "^4.2.0",
"debug": "^4.1.1",
"get-uri": "^2.0.0",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^3.0.0",
"pac-resolver": "^3.0.0",
"raw-body": "^2.2.0",
"socks-proxy-agent": "^4.0.1"
},
"dependencies": {
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz",
"integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz",
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
}
}
},
"pac-resolver": {
"version": "3.0.0",
"resolved": "https://registry.npm.taobao.org/pac-resolver/download/pac-resolver-3.0.0.tgz?cache=0&sync_timestamp=1581134844855&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpac-resolver%2Fdownload%2Fpac-resolver-3.0.0.tgz",
"integrity": "sha1-auoweH2wqJFwTet4AKcip2FabyY=",
"requires": {
"co": "^4.6.0",
"degenerator": "^1.0.4",
"ip": "^1.1.5",
"netmask": "^1.0.6",
"thunkify": "^2.1.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pause-stream": {
"version": "0.0.11",
"resolved": "https://registry.npm.taobao.org/pause-stream/download/pause-stream-0.0.11.tgz",
"integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
"requires": {
"through": "~2.3"
}
},
"platform": {
"version": "1.3.6",
"resolved": "https://registry.npm.taobao.org/platform/download/platform-1.3.6.tgz",
"integrity": "sha1-SLTOmDFksgnC1FoQetsx9HOm56c="
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fprelude-ls%2Fdownload%2Fprelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz",
"integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I="
},
"proxy-agent": {
"version": "3.1.1",
"resolved": "https://registry.npm.taobao.org/proxy-agent/download/proxy-agent-3.1.1.tgz?cache=0&sync_timestamp=1602110112844&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fproxy-agent%2Fdownload%2Fproxy-agent-3.1.1.tgz",
"integrity": "sha1-fgTga/Nq+mJKFUC+JHtHyXC9MBQ=",
"requires": {
"agent-base": "^4.2.0",
"debug": "4",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^3.0.0",
"lru-cache": "^5.1.1",
"pac-proxy-agent": "^3.0.1",
"proxy-from-env": "^1.0.0",
"socks-proxy-agent": "^4.0.1"
},
"dependencies": {
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz",
"integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz",
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
}
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npm.taobao.org/proxy-from-env/download/proxy-from-env-1.1.0.tgz",
"integrity": "sha1-4QLxbKNVQkhldV0sno6k8k1Yw+I="
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz",
"integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npm.taobao.org/qs/download/qs-6.9.4.tgz?cache=0&sync_timestamp=1588543068614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqs%2Fdownload%2Fqs-6.9.4.tgz",
"integrity": "sha1-kJCykNH5FyjTwi5UhDykSupatoc="
},
"raw-body": {
"version": "2.4.1",
"resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.1.tgz",
"integrity": "sha1-MKyC+Yu1rowVLmcUnayNVRU7Fow=",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.3",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz?cache=0&sync_timestamp=1581624324274&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-2.3.7.tgz",
"integrity": "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.7.1.tgz",
"integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=",
"requires": {
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589129611964&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz",
"integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz",
"integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz",
"integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk="
},
"sdk-base": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/sdk-base/download/sdk-base-2.0.1.tgz",
"integrity": "sha1-ukAonovfJy7RHdnql+r5jgNtJMY=",
"requires": {
"get-ready": "~1.0.0"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1606852064928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz",
"integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc="
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz",
"integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM="
},
"smart-buffer": {
"version": "4.1.0",
"resolved": "https://registry.npm.taobao.org/smart-buffer/download/smart-buffer-4.1.0.tgz",
"integrity": "sha1-kWBcJdkWUvRmHqacz0XxszHKIbo="
},
"socks": {
"version": "2.3.3",
"resolved": "https://registry.npm.taobao.org/socks/download/socks-2.3.3.tgz?cache=0&sync_timestamp=1607055763392&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsocks%2Fdownload%2Fsocks-2.3.3.tgz",
"integrity": "sha1-ARKfCl1TTSuJdxLtis6rfuZdeOM=",
"requires": {
"ip": "1.1.5",
"smart-buffer": "^4.1.0"
}
},
"socks-proxy-agent": {
"version": "4.0.2",
"resolved": "https://registry.npm.taobao.org/socks-proxy-agent/download/socks-proxy-agent-4.0.2.tgz",
"integrity": "sha1-PImR8xRbJ5nnDhG9X7yLGWMRY4Y=",
"requires": {
"agent-base": "~4.2.1",
"socks": "~2.3.2"
},
"dependencies": {
"agent-base": {
"version": "4.2.1",
"resolved": "https://registry.npm.taobao.org/agent-base/download/agent-base-4.2.1.tgz",
"integrity": "sha1-2J5ZmfeXh1Z0wH2H8mD8Qeg+jKk=",
"requires": {
"es6-promisify": "^5.0.0"
}
}
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM="
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"stream-http": {
"version": "2.8.2",
"resolved": "https://registry.npm.taobao.org/stream-http/download/stream-http-2.8.2.tgz?cache=0&sync_timestamp=1588701397289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstream-http%2Fdownload%2Fstream-http-2.8.2.tgz",
"integrity": "sha1-QSboxrEHAERlkYqi/DVUnndALIc=",
"requires": {
"builtin-status-codes": "^3.0.0",
"inherits": "^2.0.1",
"readable-stream": "^2.3.6",
"to-arraybuffer": "^1.0.0",
"xtend": "^4.0.0"
}
},
"stream-wormhole": {
"version": "1.1.0",
"resolved": "https://registry.npm.taobao.org/stream-wormhole/download/stream-wormhole-1.1.0.tgz",
"integrity": "sha1-MAr/Rs7VU8/sZCoFJRiFQXaTwz0="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz?cache=0&sync_timestamp=1565170823020&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring_decoder%2Fdownload%2Fstring_decoder-1.1.1.tgz",
"integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"thenify": {
"version": "3.3.1",
"resolved": "https://registry.npm.taobao.org/thenify/download/thenify-3.3.1.tgz",
"integrity": "sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8=",
"requires": {
"any-promise": "^1.0.0"
}
},
"thenify-all": {
"version": "1.6.0",
"resolved": "https://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz",
"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
"requires": {
"thenify": ">= 3.1.0 < 4"
}
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"thunkify": {
"version": "2.1.2",
"resolved": "https://registry.npm.taobao.org/thunkify/download/thunkify-2.1.2.tgz",
"integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0="
},
"to-arraybuffer": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz",
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz",
"integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM="
},
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.0.3.tgz",
"integrity": "sha1-jgdBrEX8DCJuWKF7/D5kubxsphw="
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz?cache=0&sync_timestamp=1585883120824&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype-check%2Fdownload%2Ftype-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"requires": {
"prelude-ls": "~1.1.2"
}
},
"unescape": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/unescape/download/unescape-1.0.1.tgz",
"integrity": "sha1-lW5DD2HK2KTVfYLFGPXmzF0N2pY=",
"requires": {
"extend-shallow": "^2.0.1"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"urllib": {
"version": "2.36.1",
"resolved": "https://registry.npm.taobao.org/urllib/download/urllib-2.36.1.tgz?cache=0&sync_timestamp=1591669891325&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Furllib%2Fdownload%2Furllib-2.36.1.tgz",
"integrity": "sha1-+9n7E7vBQOH8FbzbqHA9YUKn6zo=",
"requires": {
"any-promise": "^1.3.0",
"content-type": "^1.0.2",
"debug": "^2.6.9",
"default-user-agent": "^1.0.0",
"digest-header": "^0.0.1",
"ee-first": "~1.1.1",
"formstream": "^1.1.0",
"humanize-ms": "^1.2.0",
"iconv-lite": "^0.4.15",
"ip": "^1.1.5",
"proxy-agent": "^3.1.0",
"pump": "^3.0.0",
"qs": "^6.4.0",
"statuses": "^1.3.1",
"utility": "^1.16.1"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"utility": {
"version": "1.17.0",
"resolved": "https://registry.npm.taobao.org/utility/download/utility-1.17.0.tgz?cache=0&sync_timestamp=1608037972811&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futility%2Fdownload%2Futility-1.17.0.tgz",
"integrity": "sha1-YIGfcSpuDOd09S+x1pGZKl9Z02I=",
"requires": {
"copy-to": "^2.0.1",
"escape-html": "^1.0.3",
"mkdirp": "^0.5.1",
"mz": "^2.7.0",
"unescape": "^1.0.1"
}
},
"win-release": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/win-release/download/win-release-1.1.1.tgz",
"integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=",
"requires": {
"semver": "^5.0.1"
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz",
"integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npm.taobao.org/xml2js/download/xml2js-0.4.23.tgz?cache=0&sync_timestamp=1576776888003&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxml2js%2Fdownload%2Fxml2js-0.4.23.tgz",
"integrity": "sha1-oMaVFnUkIesqx1juTUzPWIQ+rGY=",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-11.0.1.tgz",
"integrity": "sha1-vpuuHIoEbnazESdyY0fQrXACvrM="
},
"xregexp": {
"version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/xregexp/download/xregexp-2.0.0.tgz?cache=0&sync_timestamp=1607403606167&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxregexp%2Fdownload%2Fxregexp-2.0.0.tgz",
"integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz",
"integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q="
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz",
"integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0="
}
}
}
{
"pages": [
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path" : "pages/index/home",
"style" :
{
"navigationBarTitleText": "台粮道",
"enablePullDownRefresh": false
}
},
{
"path": "pages/index/goodsDetail",
"style": {
"navigationBarTitleText": "商品详情",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/my/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#FFFFFF",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/myWallet",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/cashOut",
"style": {
"navigationBarTitleText": "提现",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/cashOutRecord",
"style": {
"navigationBarTitleText": "提现记录",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/coupon",
"style": {
"navigationBarTitleText": "优惠券",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/manageAdress",
"style": {
"navigationBarTitleText": "管理收货地址",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/creatAdress",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/balanceRecord",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/signForDetail",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/setting",
"style": {
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/aboutUs",
"style": {
"navigationBarTitleText": "关于我们",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/myCollection",
"style": {
"navigationBarTitleText": "我的收藏",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/inviteFriend",
"style": {
"navigationBarTitleText": "邀请好友",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/myOrder",
"style": {
"navigationBarTitleText": "我的订单",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/orderDetail",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/index/login",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/index/bind",
"style": {
"navigationBarTitleText": "绑定手机"
}
},
{
"path": "pages/my/feedback",
"style": {
"navigationBarTitleText": "意见反馈",
"enablePullDownRefresh": false
}
},
{
"path": "pages/index/detail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/index/webView",
"style" :
{
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/my/myTeam",
"style" :
{
"navigationBarTitleText": "我的团队",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/my/setUserInfo",
"style" :
{
"navigationBarTitleText": "个人资料",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/shopping/index",
"style" :
{
"navigationStyle": "custom",
"navigationBarTitleText": "",
// "onReachBottomDistance": 80,
"enablePullDownRefresh": true
}
},
{
"path" : "pages/shopping/shopCar",
"style" :
{
"navigationBarTitleText": "购物车",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/shopping/confirmOrder",
"style" :
{
"navigationBarTitleText": "确认订单",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/shopping/orderSettle",
"style" :
{
"navigationBarTitleText": "确认订单",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/shopping/payResult",
"style" :
{
"navigationBarTitleText": "支付结果",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/index/more",
"style" :
{
"navigationBarTitleText": "更多",
"enablePullDownRefresh": false
}
}
,{
"path" : "pages/my/manger",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
}
,{
"path" : "pages/my/rollOut",
"style" :
{
"navigationBarTitleText": "转出到余额",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#FFF",
"backgroundColor": "#F8F8F8"
},
"condition": {
//模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项)
"list": [{
"name": "", //模式名称
"path": "", //启动页面,必选
"query": "" //启动参数,在页面的onLoad函数里面得到
}]
},
"easycom": {
"autoscan": true,
"custom": {
"l-(.*)": "@/components/$1/index.vue"
}
}
}
<template>
<view class="white-content">
<view class="content">
<view class="input-row">
<label>手机号</label>
<input v-model="phone" type="digit" maxlength="11" placeholder="请输入手机号码" @blur="handleBlur" />
</view>
<view class="input-row">
<label>验证码</label>
<input v-model="smsCode" type="digit" maxlength="6" placeholder="请输入验证码" />
<button @click="getSmsCode" :disabled="!phone || phone.length < 11 || time < 60">{{codeTip}}</button>
</view>
</view>
<button class="theme" :disabled="!phone || phone.length < 11 || !smsCode || smsCode.length < 6 " @click="gobind">绑定</button>
</view>
</template>
<script>
import util from '@/config/util.js'
import {
checkCode,
bindWx
} from '@/config/api.js'
export default {
data() {
return {
phone: null,
smsCode: null,
codeTip: '获取验证码',
time: 60,
userInfo: null
};
},
onLoad(options) {
Object.assign(this, this.$options.data())
if (options.data) {
this.userInfo = JSON.parse(options.data)
} else {
util.showToast('数据缺失,请重试!')
uni.navigateBack({
delta: 1
})
}
},
methods: {
getSmsCode() {
var that = this
if (that.time != 60) {
return
}
var params = {
phone: that.phone
}
checkCode(params, {
suc: (res) => {
util.showToast('验证码发送成功');
that.startCountDown()
}
})
},
startCountDown() {
var that = this
var id = setInterval(function() {
var time = that.time
var str = ''
if (time > 0) {
time--
str = time + 's'
} else {
time = 60
str = '获取验证码'
}
that.time = time
that.codeTip = str
if (time == 60) {
clearInterval(id)
}
}, 1000)
},
//提交
gobind() {
if (!this.phoneStatus) this.$main.showToast('手机号格式有误,请重新输入')
var that = this
var params = {
phone: that.phone,
code: that.smsCode,
bindType: 2,
openId: that.userInfo.openId,
nickName: that.userInfo.nickName,
avatar: that.userInfo.avatar
}
bindWx(params, {
suc: res => {
util.showToast('登录成功')
var data = res.data;
uni.setStorageSync('token', data.token)
uni.setStorageSync('user', that.userInfo)
setTimeout(() => {
that.$path.reLaunch('/pages/index/home')
}, 1000)
}
})
},
//登录成功操作
loginSuccess(res) {
},
// 正则验证
getRegExp(value) {
let regExp =
/^1[3-9]\d{9}$/
if (regExp.test(value)) {
this.phoneStatus = true
} else {
this.phoneStatus = false
}
},
// 手机号输入框失焦事件
handleBlur (e) {
this.getRegExp(this.phone)
}
}
}
</script>
<style>
.white-content {
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
background: white;
}
.logo {
width: 380rpx;
height: 120rpx;
margin-top: 170rpx;
}
.content {
width: calc(100% - 140rpx);
margin: 24rpx 70rpx 0 70rpx;
}
.input-row {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
margin-top: 27rpx;
border-bottom: 2rpx solid #f2f2f2;
}
.input-row image {
width: 40rpx;
height: 40rpx;
}
.input-row label {
width: 120rpx;
font-size: 26rpx;
font-weight: bold;
color: #020202;
}
.input-row image:last-child {
height: 30rpx;
}
.input-row input {
flex: 1;
padding: 40rpx 26rpx;
height: auto;
font-size: 26rpx;
}
.input-row button {
padding: 0 24rpx;
min-width: 142rpx;
height: 50rpx;
line-height: 50rpx;
font-size: 20rpx;
color: #ff3c39;;
border-radius: 40rpx;
border: 1rpx solid #ff3c39;;
}
.input-row button[disabled] {
border: 1rpx solid #F2F2F2;
}
.agreement {
width: 100vw;
position: absolute;
left: 0;
display: flex;
flex-direction: column;
align-items: center;
color: #AAAAAA;
font-size: 24rpx;
}
.agreement text {
color: #007AFF;
}
.input-tip {
display: flex;
color: #999999;
font-size: 24rpx;
margin-top: 10rpx;
}
</style>
<template>
<view class="cx-detail">
<!-- <view class="title" v-if="name">
{{name}}
</view> -->
<view class="detail" ref="detail" id="detail" v-html="detail"></view>
</view>
</template>
<script>
import {
contractDetail,
medicalWikiSecondDetail,
agreementDetail
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
type: null,
id: null,
name: null,
status: null,
detail: null,
imgSrc: ''
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (options.id) this.id = options.id
if (options.detail) this.detail = options.detail
if (options.status) this.status = options.status
if (options.title) {
this.$main.setNavigationBarTitle(options.title)
} else {
this.$main.setNavigationBarTitle('详情')
}
if (options.type) {
this.type = options.type
this.getApiagreementTips()
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 协议、说明详情
getApiagreementTips () {
let that = this
let params = {
type: that.type
}
agreementDetail(params, {
suc: (res) => {
that.detail = res.data.detailHtml
}
})
}
}
}
</script>
<style scoped lang="less">
.title {
padding: 20rpx;
box-sizing: border-box;
color: #020202;
font-size: 32rpx;
text-align: center;
font-weight:bold;
background-color: #FFF;
}
.detail {
white-space: pre-wrap;
}
</style>
<template>
<view class="content cx-goods-detail cx-ipone-x" v-if="Ok">
<view class="section">
<!--轮播图-->
<view class="banner">
<!-- <view class="top-back-box">
<image class="icon" @click="btnBack(1)" :src="imgBaseUrl + 'returns.png'" webp="true" lazy-load="true"></image>
</view> -->
<swiper class="screen-swiper" :indicator-dots="true" indicator-active-color="#21d183" indicator-color="#ffffff"
:circular="true" :autoplay="true" interval="3000" duration="1000">
<swiper-item v-for="(item, index) in swiperList" :key="index">
<image :src="item" mode="aspectFill" webp="true" lazy-load="true" @click="btnPreviewImage(index, swiperList)"></image>
</swiper-item>
</swiper>
</view>
<!--名称-->
<view class="goods-name">
{{goodsData.name}}
</view>
<!--价格 销量-->
<view class="goods-info" style="padding: 0 30rpx;">
<view class="goods-price">
<view class="price">
<text>¥</text>
<label>{{goodsData.price}}</label>
</view>
<view v-if="shoppingGift" class="marketprice">
{{shoppingGift}}
</view>
</view>
<view class="goods-sales">
销售量:{{sale || 0}}
</view>
</view>
<view class="desc">
{{goodsData.description || ''}}
</view>
</view>
<view class="section">
<!--发货地-->
<view class="goods-address" style="border-bottom: 1rpx solid #F1F1F1;">
<label class="title">商品类目</label>
<view class="address-info">
{{goodsData.productCategoryName}}
</view>
</view>
<!--规格-->
<view class="goods-sku">
<label class="title">商品规格</label>
<view class="sku-info" @click="btnShowStandard()">
{{standardValue ? standardValue : '点击选择规格'}}
</view>
</view>
</view>
<view class="section">
<view class="goods-detail">
<view class="detail-title">商品详情</view>
<view id="detail" class="details" v-html="detailHtml"></view>
<!-- <view class="details">
<image class="wscnph" src="https://taozhou2020.oss-cn-beijing.aliyuncs.com/mall/images/20210205/1612502182194详情页.jpg"></image>
</view> -->
</view>
</view>
<view class="footer">
<view class="footer-left">
<view class="footer-item" style="margin-right: 35rpx;">
<image :src="imgBaseUrl + 'service.png'" webp="true" lazy-load="true"></image>
<text>客服</text>
<button class="button" open-type="contact" @contact="handleContact"></button>
</view>
<view class="footer-item" v-if="!isPartner" style="margin-right: 35rpx;" @click="btnCollect()">
<image v-if="isCollection" :src="imgBaseUrl + 'collected.png'" webp="true" lazy-load="true"></image>
<image v-else :src="imgBaseUrl + 'Collectionq.png'" webp="true" lazy-load="true"></image>
<text>收藏</text>
</view>
<view class="footer-item">
<image :src="imgBaseUrl + 'sharefx.png'" webp="true" lazy-load="true"></image>
<p>分享</p>
<button class="button" open-type="share"></button>
</view>
</view>
<view class="footer-right">
<view class="btn" v-if="!isPartner" @click="btnAddShopCar()">加入购物车</view>
<view class="btn" style="margin-left: 20rpx;" @click="btnBuy()">立即购买</view>
</view>
</view>
<view class="standard-bg" v-if="standardPopup" @click="standardPopup = false">
<view class="standard-box" :catchtouchmove="true" @click.stop>
<view class="top-box">
<p class="empty"></p>
<p class="title">选择规格</p>
<image class="icon-close" :src="imgBaseUrl + 'close.png'" @click.stop="standardPopup = false" webp="true"
lazy-load="true"></image>
</view>
<view class="goods-info">
<view class="img-box">
<image class="img" :src="goodsData.productPic" webp="true" lazy-load="true"></image>
</view>
<view class="right-box">
<p class="price">{{goodsPrice}}</p>
<p class="text">已选:{{standardValue}}</p>
</view>
</view>
<view class="option-box">
<view class="options" v-for="(item, index) in standardList" :key="index">
<p class="name">{{item[0].ckey}}</p>
<view class="value-box">
<view class="value" v-for="(x, y) in item" :key="y" :class="x.isCheck ? 'selected' : 'no-select'" @click.stop="btnScreen(index, y)">{{x.value}}</view>
</view>
</view>
</view>
<view class="count-box">
<view class="left">
<p class="text1">商品库存</p>
<p class="text2">{{goodsStock}}件</p>
</view>
<view class="right">
<image class="icon" :src="imgBaseUrl + 'reduce.png'" webp="true" lazy-load="true" @click="btnCount(0)"></image>
<view class="count">{{count}}</view>
<image class="icon" :src="imgBaseUrl + 'plus.png'" webp="true" lazy-load="true" @click="btnCount(1)"></image>
</view>
</view>
<view class="btn" @click.stop="btnStandardSure()">{{skuType === 0 ? '确定' : skuType === 1 ? '加入购物车' : '立即购买'}}</view>
</view>
</view>
</view>
</template>
<script>
import {
addShopCar,
goodsDetail,
setCollection,
commentList
} from '@/config/api.js'
export default {
data() {
return {
Ok: false,
imgBaseUrl: null,
invateCode: this.invateCode,
skuType: 0,
isCollection: 0,
standardPopup: false,
count: 1,
skuId: null,
swiperList: [], //轮播图
goodsData: {
name: '商品名称',
price: 66,
sale: 99,
productPic: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1793586382,811319846&fm=26&gp=0.jpg',
productCategoryName: '类目1 类目2'
},
commentList: [],
goodsPrice: 0,
goodsStock: 0,
skuStocks: '',
goodsId: null, //商品ID
detailHtml: null, // 商品详情图 - 富文本
standardIds: '',
standardValue: '',
shoppingGift: '',
standardFlag: true,
sale: null,
isPartner: 0, // 是否是合伙人
standardList: null
}
},
onLoad(options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
this.Ok = true
if (options.id) {
this.goodsId = options.id
if (options.isPartner) this.isPartner = options.isPartner
this.getApiIndexData()
} else {
// this.$main.showToast('数据缺失,请重试!')
// this.$path.navigateBack(1)
}
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/goodsDetail?id=' + this.goodsId + '&invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/goodsDetail?id=' + this.goodsId + '&invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData() {
let that = this
let params = {
productId: that.goodsId
}
goodsDetail(params, {
suc: (res) => {
that.goodsData = res.data.product
that.shoppingGift = res.data.shoppingGift
that.isCollection = res.data.collectStatus
that.skuStocks = res.data.skuStocks
that.sale = that.skuStocks[0].sale
// let imgExp = new RegExp('<img.*?')
// that.goodsData.detailHtml.replace(imgExp, "<img style='max-width:750rpx; height:auto'")
// that.detailHtml = that.goodsData.detailHtml
that.detailHtml = that.formatRichText(that.goodsData.detailHtml)
for (let val in res.data.skuValues) {
for (let i = 0; i < res.data.skuValues[val].length; i++) {
res.data.skuValues[val][i].isCheck = false
}
}
that.standardList = res.data.skuValues
if (that.goodsData.albumPics.indexOf(',') != -1) {
that.swiperList = that.goodsData.albumPics.split(',')
} else {
that.swiperList.push(that.goodsData.albumPics)
}
}
})
},
/*
* 处理富文本里的图片宽度自适应
* 1.去掉img标签里的style、width、height属性
* 2.img标签添加style属性:max-width:100%;height:auto
* 3.修改所有style里的width属性为max-width:100%
* 4.去掉<br/>标签
* @param html
* @returns {void|string|*}
*/
formatRichText (html) {
let newContent = html.replace(/<img[^>]*>/gi, function(match, capture) {
match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
return match;
});
newContent = newContent.replace(/style="[^"]+"/gi, function(match, capture) {
match = match.replace(/width:[^;]+;/gi, 'width:100%;').replace(/width:[^;]+;/gi, 'width:100%;');
return match;
});
//newContent = newContent.replace(/<br[^>]*\/>/gi, '');
newContent = newContent.replace(/\<img/gi,
'< img style="width:100%;height:auto;display:inline-block;margin:10rpx auto;"');
//'src="//', 'src="https//'
newContent = newContent.replace(/src="\/\//g, 'src="https://'); //<src="
return newContent;
},
// 添加/取消收藏操作
getApiCollection(text) {
let that = this
let params = {
articleId: that.goodsId,
type: 2
}
setCollection(params, {
suc: (res) => {
that.$main.showToast(text)
}
})
},
// 点击客服
handleContact (e) {
console.log('客服', e)
},
// 添加/取消收藏按钮
btnCollect() {
if (this.isCollection) {
this.isCollection = 0
this.getApiCollection('取消收藏成功!')
} else {
this.isCollection = 1
this.getApiCollection('添加收藏成功!')
}
},
// 添加购物车
async btnAddShopCar() {
this.skuType = 1
this.standardPopup = true
let that = this
for (let val in this.standardList) {
for (let i = 0; i < this.standardList[val].length; i++) {
this.standardList[val][0].isCheck = true
}
}
// this.btnStandard(true)
},
// 立即购买按钮
async btnBuy() {
this.skuType = 2
this.standardPopup = true
let path = ''
// await this.judgeStandard()
// if (!this.standardFlag) {
// this.standardPopup = true
// this.$main.showToast('请先选择规格!')
// return
// }
for (let val in this.standardList) {
for (let i = 0; i < this.standardList[val].length; i++) {
this.standardList[val][0].isCheck = true
}
}
this.btnStandard(true)
},
// 判断是否选了规格参数
judgeStandard() {
for (let val in this.standardList) {
for (let i = 0; i < this.standardList[val].length; i++) {
if (this.standardList[val][i].isCheck) {
this.standardFlag = true
break
} else {
this.standardFlag = false
}
}
}
},
// 展示规格选择弹窗
btnShowStandard() {
this.standardPopup = true
for (let val in this.standardList) {
for (let i = 0; i < this.standardList[val].length; i++) {
this.standardList[val][0].isCheck = true
}
}
this.btnStandard()
},
// 选择规格
btnScreen(index, y) {
for (let val in this.standardList) {
// if (!this.standardList[val][y].isCheck) this.count = 1
for (let i = 0; i < this.standardList[val].length; i++) {
if (index == this.standardList[val][i].ckey) {
this.standardList[val][i].isCheck = false
this.standardList[val][y].isCheck = true
}
}
}
this.btnStandard(y)
},
// 展示已选规格
async btnStandard (isSure) {
let arr = []
let itemIds = ''
this.standardValue = ''
this.goodsPrice = 0
this.goodsStock = 0
await this.judgeStandard()
for (let val in this.standardList) {
for (let i = 0; i < this.standardList[val].length; i++) {
if (this.standardList[val][i].isCheck) {
arr.push(this.standardList[val][i])
if (this.standardFlag) {
itemIds = itemIds ? itemIds + ',' + this.standardList[val][i].skuValueId : this.standardList[val][i].skuValueId
}
}
}
}
// 判断选中的规格,匹配库存、价格
if (itemIds) {
let itemArr = null
let stocksArr = null
for (let i = 0; i < this.skuStocks.length; i++) {
if (String(itemIds).indexOf(',') != -1) {
itemArr = String(itemIds).split(',')
itemArr.sort(function(a, b) {
return a - b
})
itemIds = itemArr.join(',')
}
if (this.skuStocks[i].itemIds.indexOf(',') != -1) {
stocksArr = this.skuStocks[i].itemIds.split(',')
stocksArr.sort(function(a, b) {
return a - b
})
this.skuStocks[i].itemIds = stocksArr.join(',')
}
if (itemIds == this.skuStocks[i].itemIds) {
this.goodsPrice = this.skuStocks[i].price
this.goodsStock = this.skuStocks[i].stock
break
}
}
}
if (arr.length) {
let sortArr = null
if (arr.length > 1) {
for (let i = 0; i < arr.length; i++) {
this.standardValue += arr[i].value + ' '
if (isSure) {
this.standardIds = !this.standardIds ? arr[i].skuValueId : this.standardIds + ',' + arr[i].skuValueId
if (String(this.standardIds).indexOf(',') != -1) {
sortArr = this.standardIds.split(',')
sortArr.sort(function(a, b) {
return a - b
})
this.standardIds = sortArr.join(',')
}
}
}
} else {
this.standardIds = arr[0].skuValueId
}
}
},
// 规格确定按钮
async btnStandardSure() {
let that = this
if (this.skuType === 0) {
this.standardIds = ''
this.standardPopup = false
} else if (this.skuType === 1) {
await this.btnAddShopCar()
await this.btnStandard(true)
for (let i = 0; i < this.skuStocks.length; i++) {
if (this.skuStocks[i].itemIds == this.standardIds) {
this.skuId = this.skuStocks[i].id
}
}
let params = {
mchtId: that.goodsData.mchtId,
productId: that.goodsData.id,
productSkuId: that.skuId,
quantity: that.count
}
addShopCar(params, {
suc: (res) => {
that.$main.showToast('加入购物车成功!')
}
})
} else {
await this.btnBuy()
await this.btnStandard(true)
console.log('standardIds: ', this.standardIds)
for (let i = 0; i < this.skuStocks.length; i++) {
if (this.skuStocks[i].itemIds == this.standardIds) {
this.skuId = this.skuStocks[i].id
let data = {
mchtId: this.goodsData.mchtId,
productId: this.goodsData.id,
quantity: this.count,
skuId: this.skuStocks[i].id
}
this.btnPath('/pages/shopping/confirmOrder?data=' + JSON.stringify(data))
}
}
}
},
// 商品加加减减
async btnCount(type) {
await this.judgeStandard()
if (!this.standardFlag) return this.$main.showToast('请先选择规格!')
if (type) {
this.count++
if (!this.goodsStock) return
this.goodsStock--
} else {
if (this.count === 1) return
this.count--
this.goodsStock++
}
},
// 查看大图
btnPreviewImage (index, imgs) {
uni.previewImage({
current: index,
urls: imgs
})
},
// 详情页图片点击事件
btnImgClick (e) {
let that = this
let imgs = that.imgSrc + ','
uni.previewImage({
current: that.imgSrc,
urls: imgs.split(','),
success: res => {
},
fail: err => {
}
})
},
// 路由 - 跳转子页面
btnPath(url) {
this.$path.navigateTo(url)
},
// 路由 - 回退
btnBack(count) {
this.$path.navigateBack(1)
},
// 点击分享按钮
btnShare () {
this.$refs.popupShare.open()
},
// 选择分享方式
select (e) {
this.share(e.index)
this.$refs.popupShare.close()
},
// 分享操作
share (type) {
let that = this
let scene = (type === 0) ? 'WXSceneSession' : 'WXSceneTimeline'
uni.share({
provider: "weixin",
scene: scene,
type: 1,
summary: '', // 分享链接(h5)
success: function(res) {
// console.log("success:" + JSON.stringify(res))
that.$main.showToast('分享成功')
},
fail: function(err) {
// console.log("fail:" + JSON.stringify(err))
that.$main.showToast('分享失败,请重试')
}
})
},
/*
* 处理富文本里的图片宽度自适应
* 1.去掉img标签里的style、width、height属性
* 2.img标签添加style属性:max-width:100%;height:auto
* 3.修改所有style里的width属性为max-width:100%
* 4.去掉<br/>标签
* @param html
* @returns {void|string|*}
*/
formatRichText(html) {
let newContent = html.replace(/<img[^>]*>/gi, function(match, capture) {
match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
return match;
});
newContent = newContent.replace(/style="[^"]+"/gi, function(match, capture) {
match = match.replace(/width:[^;]+;/gi, 'width:100%;').replace(/width:[^;]+;/gi, 'width:100%;');
return match;
});
//newContent = newContent.replace(/<br[^>]*\/>/gi, '');
newContent = newContent.replace(/\<img/gi,
'<img style="width:100%;height:auto;display:inline-block;margin:10rpx auto;"');
return newContent;
}
}
}
</script>
<style scoped lang="less">
.content {
margin-bottom: 140rpx;
}
.section {
margin-bottom: 20rpx;
background: white;
}
.banner {}
.screen-swiper {
height: 600rpx;
min-height: 300rpx;
}
.screen-swiper swiper-item image {
width: 100%;
height: 100%;
}
.goods-name {
color: #020202;
font-size: 40rpx;
font-weight: bold;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
/*要显示的行数*/
overflow: hidden;
margin: 30rpx 30rpx;
}
.goods-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx 30rpx 30rpx;
}
.desc {
padding: 0 30rpx 30rpx;
color: #aaaaaa;
font-size: 24rpx;
}
.goods-price {
display: flex;
align-items: center;
}
.price {
display: flex;
align-items: baseline;
color: #dc331d;
font-size: 60rpx;
font-weight: bold;
}
.price text {
font-size: 30rpx;
}
.marketprice {
margin-left: 15rpx;
padding: 5rpx 15rpx;
box-sizing: border-box;
color: #FFF;
font-size: 24rpx;
border-radius: 30rpx;
letter-spacing: 3rpx;
background-color: #ff3c39;
}
.goods-sales {
color: #AAAAAA;
font-size: 30rpx;
}
.goods-address,
.goods-sku {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 30rpx;
}
.title {
color: #AAAAAA;
font-size: 32rpx;
width: 180rpx;
text-align: left;
}
.address-info,
.sku-info {
flex: 1;
display: flex;
align-items: center;
color: #020202;
font-size: 28rpx;
}
.address-info image {
width: 28rpx;
height: 32rpx;
margin-right: 20rpx;
}
.vline {
height: 22rpx;
width: 2rpx;
background: #020202;
margin: 0 34rpx;
}
.goods-detail {
display: flex;
flex-direction: column;
width: 100vw;
overflow: hidden;
}
.detail-title {
padding: 30rpx 30rpx;
color: #2a2a2a;
font-size: 32rpx;
font-weight: bold;
}
.details {
overflow: auto;
image {
width: 100%;
// height: auto;
}
.wscnph {
width: 100%;
// height: auto;
}
}
.detail-html {
background-color: #FFFFFF;
}
.footer {
position: fixed;
left: 0;
bottom: 0;
padding: 0 30rpx 20rpx;
/* width: calc(100vw - 60rpx); */
width: 100%;
height: 120rpx;
background: white;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
.footer-left {
display: flex;
align-items: center;
justify-content: space-around;
}
.footer-item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
width: 60rpx;
color: #333333;
font-size: 22rpx;
image {
width: 36rpx;
height: 36rpx;
margin-bottom: 10rpx;
}
.button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
outline: none;
}
}
.footer-right {
display: flex;
align-items: center;
}
.footer-right .btn {
/* padding: 10rpx 15rpx;
box-sizing: border-box; */
width: 160rpx;
height: 56rpx;
text-align: center;
line-height: 56rpx;
color: #FFF;
font-size: 26rpx;
border-radius: 33rpx;
background-color: #ff3c39;
}
</style>
<template>
<view class="cx-home">
<view class="swiper-box">
<swiper class="swiper" style="height: 400rpx;" :indicator-dots="true" indicator-active-color="#ff3c39;" :autoplay="true" interval="5000" duration="800" :circular="true">
<swiper-item class="swiper-item" v-for="(item, index) in swiperList" :key="index" @click="btnSwiper(index)">
<image class="img" :src="item.image" mode="aspectFill" webp="true" lazy-load="true"></image>
</swiper-item>
</swiper>
</view>
<view class="title-box">
<p class="title">关于台粮道</p>
<p class="English">ABOUT TAI LIANG DAO</p>
<view class="border"></view>
</view>
<view class="desc">
<!-- 台粮道集团股份有限公司成立于1999年8月18日,系符合国食品行业准入的综合性食品企业,
拥有国内外先进装备,形成了以食品、销售为主,向高端精品食品、现代物流服务业、
钢铁文化生态旅游等产业链延伸的综合性钢铁集团企业。2019年,集团年产值290亿元,
纳税10亿元,系泉州市首家纳税突破十亿大关的粮食企业,被福建省发改委、
福建省工信厅联合列入福建省千亿产业集群的重点培育企业之一。先后荣获"国家高新技术企业"、
"全国民营企业500强"、"全国民营制造业500强"、"全国绿色工厂"、"全国守合同、重信用企业"、
"福建省百强企业"、"福建省百强民营企业"、 "经济建设突出贡献奖"等众多殊荣。 -->
{{companyData.aboutTailiangRoad || ''}}
</view>
<view class="title-box">
<p class="title">台粮人环境</p>
<p class="English">ENVIRONMENTAL SCINICE</p>
<view class="border"></view>
</view>
<view class="imgs-box">
<image class="img" v-for="(item, index) in imgsList" :key="index" :src="item.pic" mode="aspectFill" @click="btnPreviewImage(index, imgsList)"></image>
</view>
<view class="more-box" v-if="imgsList.length >= 6" @click="btnPath('./more?type=1')">
<!-- <image class="icon" :src="imgBaseUrl + 'more@2x.png'"></image> -->
<p class="text">更多 &gt;&gt;</p>
</view>
<view class="video-box">
<swiper class="swiper" style="height: 400rpx;" :indicator-dots="true" indicator-active-color="#2EA9EA" :autoplay="false"
interval="4000" duration="1000" :circular="true" @change="handleSwiperChange">
<swiper-item class="swiper-item" v-for="(item, index) in videoList" :key="index" @click="btnPlayVideo(index)">
<image v-if="!videoPath" class="img" :src="item.videoPic" mode="aspectFill" webp="true" lazy-load="true"></image>
<video v-else :src="videoPath" class="img" controls autoplay @fullscreenchange="handleFullScreenChange"></video>
<view class="bg" v-if="!videoPath">
<image class="icon" :src="imgBaseUrl + 'time-out@2x.png'"></image>
</view>
</swiper-item>
</swiper>
</view>
<view class="title-box">
<p class="title">台粮报道</p>
<p class="English">TAILIANG FOOD REPORT</p>
<view class="border"></view>
</view>
<view class="new-box">
<view class="list" v-for="(item, index) in newsList" :key="index" @click="btnPath('./detail?detail=' + item.detailHtml)">
<p class="left">{{item.title}} | {{item.subTitle}}</p>
<p class="date">{{item.createDate.split(' ')[0]}}</p>
</view>
</view>
<view class="more-box" v-if="newsList.length >= 5" @click="btnPath('./more?type=2')">
<!-- <image class="icon" :src="imgBaseUrl + 'more@2x.png'"></image> -->
<p class="text">更多 &gt;&gt;</p>
</view>
<view class="title-box">
<p class="title">关于我们</p>
<p class="English">ABOUT US</p>
<view class="border"></view>
</view>
<view class="address-box">
<p>电话:{{companyData.phone || ''}}</p>
<p>电邮:{{companyData.email || ''}}</p>
<p>公司地址:{{companyData.companyDetailAddress || ''}}</p>
<!-- <p>工厂地址:{{companyData.factoryDetailAddress || ''}}</p> -->
</view>
<view class="map-box">
<map class="map" @click="btnOpenLocation(companyData.companyLatitude, companyData.companyLongitude)" name="map" :markers="markers" :longitude="companyData.companyLongitude" :latitude="companyData.companyLatitude"></map>
<!-- <map class="map" @click="btnOpenLocation(companyData.factoryLatitude, companyData.factoryLongitude)" name="map2" :markers="markers2" :longitude="companyData.factoryLongitude" :latitude="companyData.factoryLatitude" style="width: 335rpx; height: 335rpx;"></map> -->
</view>
<view class="title-box">
<p class="title">招聘信息</p>
<p class="English">RECRUITMENT INFORMATION</p>
<view class="border"></view>
</view>
<view class="other-box">
<image class="img" :src="companyData.jobOffersUrl" mode="" @click="btnPath('./detail?type=2')"></image>
</view>
<view class="title-box">
<p class="title">招商代理</p>
<p class="English">INVESTMENT AGENCY</p>
<view class="border"></view>
</view>
<view class="form-box">
<view class="options">
<p class="title"><span v-if="!name" class="symbol">*</span>成员申请</p>
<input class="input" type="text" v-model="name" placeholder="请输入您的姓名" :style="{'color': name ? '#202020' : '#AAA'}" />
</view>
<view class="options">
<p class="title"><span v-if="!position" class="symbol">*</span>所在地</p>
<view class="position-box" @click="btnShowAddress()">
<p class="text" :style="{'color': position ? '#202020' : '#AAA'}">{{position || '请选择'}}</p>
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/page.png"></image>
</view>
</view>
<view class="options">
<p class="title"><span v-if="!phone" class="symbol">*</span>手机号</p>
<input class="input" type="number" maxlength="11" placeholder="输入您的手机号" v-model="phone" :style="{'color': phone ? '#202020' : '#AAA'}" />
</view>
<view class="options">
<p class="title"><span v-if="!wechat" class="symbol">*</span>微信号</p>
<input class="input" type="number" maxlength="11" placeholder="输入您的微信号" v-model="wechat" :style="{'color': wechat ? '#202020' : '#AAA'}" />
</view>
<view class="options">
<p class="title"><span v-if="!achievement" class="symbol">*</span>计划业绩</p>
<input class="input" type="text" v-model="achievement" placeholder="请输入您的计划业绩" :style="{'color': achievement ? '#202020' : '#AAA'}" />
</view>
<!-- <view class="options" style="align-items: flex-start;">
<p class="title"><span v-if="!reason" class="symbol">*</span>申请理由</p>
<textarea class="textarea" placeholder="请输入您的申请理由" v-model="reason" :style="{'color': reason ? '#202020' : '#AAA'}" />
</view> -->
</view>
<simpleAddress ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onConfirm" confirmColor="#2EA9EA" cancelColor="#020202"></simpleAddress>
<view class="btn-box">
<view class="btn" @click="btnApply()">确定申请</view>
</view>
<cover-view v-if="showBtn" class="btn-shopping" @click="btnPath('/pages/shopping/index')">
进入商城
</cover-view>
<!-- <view class="public-float-button" @click="btnPath('/pages/shopping/index')">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/shopping.png"></image>
</view> -->
</view>
</template>
<script>
import simpleAddress from '@/components/simple-address/simple-address.vue'
import {
homeData,
applyAgent
} from '@/config/api.js'
export default {
components: {
simpleAddress
},
data() {
return {
invateCode: this.invateCode,
companyData: null,
imgBaseUrl: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/',
videoPath: '',
swiperList: [],
imgsList: [],
videoList: [],
newsList: [],
markers: [],
name: '',
phone: '',
wechat: '',
showBtn: true,
achievement: '',
reason: '',
position: '',
provinceCity: '',
provinceId: null,
areaValue: '',
cityId: null,
district: '',
areaId: null,
openRequest: true
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (options.invateCode) {
this.$store.setStorageSync('invateCode', options.invateCode)
}
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
homeData('', {
suc: (res) => {
that.companyData = res.data.companyInformation
that.swiperList = res.data.navigationLists
that.imgsList = res.data.companyConditions
that.videoList = res.data.FrontVideos
that.newsList = res.data.proclamations
that.markers = [
{
latitude: that.companyData.companyLatitude,
longitude: that.companyData.companyLongitude,
callout: {
content: '厦门运营点',
color: "#FFF",
fontSize: 15,
bgColor: "#2EA9EA",
anchorX: 0,
anchorY: 0,
display: 'ALWAYS'
}
}
]
}
})
},
// 确定申请
btnApply () {
if (!this.openRequest) return
this.openRequest = false
if (!this.name) {
this.$main.showToast('请输入姓名')
this.openRequest = true
return
}
if (!this.position) {
this.$main.showToast('请选所在地')
this.openRequest = true
return
}
if (!this.phone) {
this.$main.showToast('请输入手机号')
this.openRequest = true
return
}
if (!this.wechat) {
this.$main.showToast('请输入微信号')
this.openRequest = true
return
}
if (!this.achievement) {
this.$main.showToast('请输入计划业绩')
this.openRequest = true
return
}
if (!this.reason) {
this.$main.showToast('请输入申请理由')
this.openRequest = true
return
}
let that = this
let params = {
provinceId: that.provinceId,
cityId: that.cityId,
areaId: that.areaId,
receiverProvinceName: that.provinceCity,
receiverCityName: that.areaValue,
receiverAreaName: that.district,
memberName: that.name,
phone: that.phone,
wxAccount: that.wechat,
performance: that.achievement,
reason: that.reason
}
applyAgent(params, {
suc: res => {
that.$main.showToast('申请成功', 1000)
setTimeout(() => {
that.$path.navigateBack(1)
}, 1000)
}
})
},
// 三级联动组件
btnShowAddress() {
this.$refs.simpleAddress.open()
},
// 获取省市区三级联动选择器值
onConfirm (e) {
this.provinceCity = e.labelArr[0]
this.areaValue = e.labelArr[1]
this.district = e.labelArr[2]
this.provinceId = e.provinceId
this.cityId = e.cityId
this.areaId = e.areaId
this.position = e.label
},
// 打开地图查看位置
btnOpenLocation (latitude, longitude) {
let that = this
// this.$main.getLocation().then(res => {
uni.openLocation({
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
success: ress => {
// console.log('res: ', ress)
},
fail: err => {
// console.log('err: ', err)
}
})
// })
},
// 轮播图点击跳转判断
btnSwiper (index) {
if (this.swiperList[index].type == 1) {
this.btnPath('./webView?src=' + this.swiperList[index].url)
} else if (this.swiperList[index].type == 2) {
this.btnPath('./goodsDetail?id=' + this.swiperList[index].productId)
} else if (this.swiperList[index].type == 3) {
this.btnPath('./detail?type=7 ')
}
},
// 监听视频进入/退出全屏
handleFullScreenChange (e) {
if (e.detail.fullScreen) {
this.showBtn = false
} else {
this.showBtn = true
}
},
// 切换视频轮播图
handleSwiperChange (e) {
this.videoPath = ''
},
// 查看大图
btnPreviewImage (index, imgs) {
let arr = []
for (let i = 0; i < imgs.length; i++) {
arr.push(imgs[i].pic)
}
uni.previewImage({
current: index,
urls: arr
})
},
// 播放视频
btnPlayVideo (index) {
this.videoPath = this.videoList[index].video
},
// 路由跳转
btnPath (url) {
this.$path.navigateTo(url)
}
}
}
</script>
<style scoped lang="less">
</style>
<template>
<view class="cx-login">
<view class="top-box">
<view class="view-bg">
</view>
<view class="wx-login-box">
<image class="icon" :src="imgBaseUrl + 'WeChatdl.png'" webp="true" lazy-load="true" :style="{'margin-bottom': authType ? '60rpx;' : '0'}"></image>
<button v-if="authType" class="button" style="background-color: #2EA9EA;" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">授权手机号</button>
<button v-else class="button" open-type="getUserInfo" @click="getWxLogin()">微信授权登录</button>
</view>
<view class="bottom-box">
<!-- <view class="text-box">
<p class="text">登录即表明同意</p>
<p class="agreement" @click="btnPath('./detail?type=4&status=2')">《台粮道用户协议》</p>
<p class="text">和</p>
<p class="agreement" @click="btnPath('./detail?type=4&status=3')">《隐私政策》</p>
</view> -->
<p class="support">POWERED BY&copy;六方网络</p>
</view>
</view>
</view>
</template>
<script>
import util from '@/config/util.js'
import {
getId,
wxLogin,
bindWx,
personal,
checkCode
} from '@/config/api.js'
export default {
data() {
return {
imgBaseUrl: null,
userInfo: null,
openId: null,
codeText: '获取验证码',
passText: 'password',
invateCode: '',
phone: '',
jsonData: {},
authType: 0
}
},
onLoad() {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
if (this.$store.getStorageSync('invateCode')) {
this.invateCode = this.$store.getStorageSync('invateCode')
}
},
methods: {
// 获取验证码
getApiCode() {
setTimeout(() => {
if (!this.phoneValue) return this.$main.showToast('手机号不能为空!')
if (!this.phoneStatus) return this.$main.showToast('您输入的手机号有误,请重新输入')
let that = this
let num = 60
let params = {
phone: that.phoneValue
}
checkCode(params, {
suc: (res) => {
that.$main.showToast('验证码已发送')
let timeSmap = setInterval(function() {
num--
that.codeText = num + 's后重新获取'
if (!num) {
clearInterval(timeSmap)
that.codeText = '获取验证码'
}
}, 1000)
},
err: (err) => {
}
})
}, 50)
},
// 获取手机号
getPhoneNumber (e) {
this.getWxLogin(e.detail.encryptedData, e.detail.iv)
},
// 绑定微信
apiBind (data) {
console.log(1111, this.invateCode)
let that = this
let params = {
phone: data.phone,
bindType: 2,
openId: data.openId,
nickName: data.nickName,
avatar: data.avatar
}
if (that.invateCode) params.invitationCode = that.invateCode
bindWx(params, {
suc: (res) => {
that.$main.showToast('登录成功', 1000)
let token = res.data.tokenHead + ' ' + res.data.token
if (this.$store.getStorageSync('invateCode')) {
this.$store.removeStorageSync('invateCode')
}
uni.setStorageSync('token', token)
let userInfo = {
avatar: data.avatar,
phone: data.phone,
nickName: data.nickName
}
uni.setStorageSync('user', userInfo)
setTimeout(() => {
that.$path.reLaunch('/pages/index/home')
}, 1000)
}
})
},
// 微信登录
getWxLogin (data, iv) {
let that = this
wx.login({
success (res) {
if (that.authType) {
let params = {
jsCode: res.code,
encryptedData: data,
iv: iv
}
if (that.invateCode) params.invitationCode = that.invateCode
getId(params, {
suc: (ress) => {
let token = ress.data.tokenHead + ' ' + ress.data.token
that.$store.setStorageSync('token', token)
that.$main.showToast('登录成功', 1000)
setTimeout(() => {
that.$path.reLaunch('/pages/index/home')
}, 1000)
},
erc: (err) => {
if (err.data.code === 15000) {
that.phone = err.data.data.phone
that.jsonData.phone = that.phone
// let jsonData = {
// phone: that.phone,
// openId: err.data.data.openId,
// nickName: ress.userInfo.nickName,
// avatar: ress.userInfo.avatarUrl
// }
that.apiBind(that.jsonData)
}
}
})
} else {
wx.getUserInfo({
success: function(ress) {
that.$main.showLoading('登陆中')
let params = {
jsCode: res.code,
encryptedData: ress.encryptedData,
iv: ress.iv
}
if (that.invateCode) params.invitationCode = that.invateCode
getId(params, {
suc: (reslove) => {
that.$main.hideLoading()
let token = reslove.data.tokenHead + ' ' + reslove.data.token
that.$store.setStorageSync('token', token)
if (that.$store.getStorageSync('invateCode')) {
that.$store.removeStorageSync('invateCode')
}
that.$main.showToast('登录成功', 1000)
setTimeout(() => {
that.$path.reLaunch('/pages/index/home')
}, 1000)
},
erc: err => {
if (err.data.code === 15000) {
that.jsonData = {
openId: err.data.data.openid,
nickName: ress.userInfo.nickName,
avatar: ress.userInfo.avatarUrl
}
that.authType = 1
that.$forceUpdate()
// let jsonData = {
// phone: that.phone,
// openId: err.data.data.openId,
// nickName: ress.userInfo.nickName,
// avatar: ress.userInfo.avatarUrl
// }
// that.apiBind(jsonData)
}
}
})
},
fail: function(err) {
that.$main.hideLoading()
}
})
}
},
fail: (err) => {
}
})
},
// 获取个人信息
getApiUserInfo (status) {
let that = this
let params = ''
personal(params, {
suc: (res) => {
let data = res.data
if (status) {
uni.getUserInfo({
provider: 'weixin',
success: function (info) {
that.userInfo = {
nickName: info.userInfo.nickName,
avatar: info.userInfo.avatarUrl
}
data.nickName = info.userInfo.nickName
data.avatar = info.userInfo.avatarUrl
that.$store.setStorageSync('user', data)
}
})
} else {
that.$store.setStorageSync('user', data)
}
}
})
},
// 路由 - 跳转子页面
btnPath(url) {
this.$path.navigateTo(url)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-more">
<view class="imgs-box" v-if="type == 1">
<image class="img" v-for="(item, index) in imgList" :key="index" :src="item.pic" @click="btnPreviewImage(index, imgList)" mode="aspectFill"></image>
</view>
<view class="new-box" v-if="type == 2">
<view class="list" v-for="(item, index) in newsList" :key="index">
<p class="left">{{item.title}} | {{item.subTitle}}</p>
<p class="date">{{item.createDate.split(' ')[0]}}</p>
</view>
</view>
</view>
</template>
<script>
import {
tlImages,
tlNews
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
type: 0,
imgList: [],
newsList: [],
page: 1,
total: 0
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.type = options.type
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
this.page++
if (this.type == 1) {
if (this.total === this.imgList.length) return
this.imgList = []
} else if (this.type == 2){
if (this.total === this.newsList.length) return
this.newsList = []
}
this.getApiIndexData()
},
methods: {
// 请求主数据
getApiIndexData () {
if (this.type == 1) {
let that = this
let params = {
pageNum: that.page,
pageSize: 30
}
tlImages(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum === 1) that.imgList = []
that.imgList = that.imgList.concat(res.data.list)
}
})
} else {
let that = this
let params = {
pageNum: that.page,
pageSize: 30
}
tlNews(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum === 1) that.newsList = []
that.newsList = that.newsList.concat(res.data.list)
}
})
}
},
// 查看大图
btnPreviewImage (index, imgs) {
let arr = []
for (let i = 0; i < imgs.length; i++) {
arr.push(imgs[i].pic)
}
uni.previewImage({
current: index,
urls: arr
})
},
}
}
</script>
<style>
</style>
<template>
<view class="cx-web-view">
<web-view :src="src"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
src: ''
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.src = options.src
},
methods: {
}
}
</script>
<style>
</style>
<template>
<view class="cx-about-us">
<view class="logo-box">
<image class="logo" :src="imgBaseUrl + 'logowe.png'" webp="true" lazy-load="true"></image>
</view>
<view class="edition-info">{{mobileInfo}}</view>
<view class="option-box">
<view class="options">
<p class="title">邮箱</p>
<view class="right">
<p class="text">632598226@qq.com</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="options">
<p class="title">官方微信公众号</p>
<view class="right">
<p class="text">jsksjd</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="options">
<p class="title">官方微博</p>
<view class="right">
<p class="text">jsksjd</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="options">
<p class="title">官网技术支持</p>
<view class="right">
<p class="text">泉州六方网络有限公司</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
Ok: false,
imgBaseUrl: null,
invateCode: this.invateCode,
mobileInfo: ''
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getSystemInfo()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取系统信息
getSystemInfo () {
uni.getSystemInfo({
success: res => {
let system = res.platform == 'ios' ? 'ios版本' : '安卓版本'
let edition = res.system.substr(res.system.indexOf(' '))
this.mobileInfo = system + edition
}
})
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-balance-record">
<uni-nav-bar left-icon="back" title="余额明细" right-text=" " :fixed="true" :statusBar="true" :border="false" @clickLeft="btnBack(1)">
</uni-nav-bar>
<view class="tips-box">
<p>总支出:¥{{outcome}} &nbsp;&nbsp; 总收入:¥{{income}}</p>
<p @click="btnPath('/pages/index/detail?type=6')">说明</p>
</view>
<view class="record-box">
<view class="options" v-for="(item, index) in list" :key="index">
<view class="left-box">
<p class="title" v-if="item.type === 1">购买商品</p>
<p class="title" v-else-if="item.type === 2">下级升级获得</p>
<p class="title" v-else-if="item.type === 3">提现</p>
<p class="title" v-else-if="item.type === 5">佣金管理奖</p>
<p class="title" v-else-if="item.type === 6">直推佣金</p>
<p class="title" v-else-if="item.type === 7">间推佣金</p>
<p class="title" v-else-if="item.type === 8">管理奖转入</p>
<p class="title" v-else-if="item.type === 9">管理奖转出</p>
<view class="count red" v-if="item.changeType === 2">-{{item.changeAmount}}</view>
<view class="count black" v-else>+{{item.changeAmount}}</view>
</view>
<p class="time">{{item.createDate}}</p>
</view>
</view>
</view>
</template>
<script>
import {
balanceRecord
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
list: [],
income: 0,
outcome: 0,
page: 1,
total: 0
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 15
}
balanceRecord(params, {
suc: (res) => {
that.total = res.data.detailList.total
if (res.data.detailList.pageNum === 1) that.list = []
that.list = that.list.concat(res.data.detailList.list)
that.outcome = res.data.allExpenditure
that.income = res.data.allIncome
}
})
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(1)
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.list.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style scoped lang="less">
.record-box {
height: calc(100vh - 88rpx - 82rpx - var(--status-bar-height));
}
</style>
<template>
<view class="cx-cash-out">
<view class="top-tips">提现需要扣除手续费3%,到账时间以实际到账时间为准</view>
<view class="option-box">
<view class="options">
<p class="title">当前余额</p>
<p class="text">{{balance.balance}}</p>
</view>
<view class="options">
<p class="title">收款人</p>
<input class="input" type="text" v-model="nameValue" placeholder="请输入收款人姓名" />
</view>
<view class="options">
<view class="title">收款方式</view>
<view class="right">
<view class="list" @click="type = 0">
<view class="border">
<view class="point" v-if="type === 0"></view>
</view>
<p class="text">支付宝</p>
</view>
<view class="list" @click="type = 1">
<view class="border">
<view class="point" v-if="type === 1"></view>
</view>
<p class="text">微信</p>
</view>
</view>
</view>
<view class="options">
<p class="title">提现金额</p>
<input class="input" type="digit" v-model="moneyValue" placeholder="请输入提现金额" @input="handleInput" />
</view>
<view class="options">
<p class="title">实际到账金额</p>
<p class="text">{{actualAmount}}</p>
</view>
</view>
<view class="btn" @click="chooseImage()">上传收款码</view>
<view class="btn" style="margin-top: 30rpx;" @click="btnSure()">确认提现,48小时内到账</view>
</view>
</template>
<script>
import {
cashOut,
ossPolicy,
myWallet,
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
type: 0,
balance: '',
nameValue: '',
moneyValue: '',
actualAmount: '',
imgURL: '',
openRequest: true // 按钮保护
}
},
onLoad () {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiMoney()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取余额
getApiMoney () {
let that = this
myWallet('', {
suc: (res) => {
that.balance = res.data
}
})
},
// 提现按钮
btnSure () {
if (!this.openRequest) return
this.openRequest = false
if (!this.nameValue) {
this.openRequest = true
return this.$main.showToast('请输入收款人姓名!')
}
if (!this.moneyValue || this.moneyValue <= 0) {
this.openRequest = true
return this.$main.showToast('请输入提现金额!')
}
if (!this.imgURL) {
this.openRequest = true
return this.$main.showToast('请先上传收款码')
}
this.getApiCashOut()
},
// 选择图片操作
async chooseImage () {
let that = this
await uni.chooseImage({
count: 1,
success: res => {
for (let i = 0; i < res.tempFiles.length; i++) {
if (res.tempFiles[i].size > 2097152) return that.$main.showToast('您上传的图片过大,请重新上传')
that.getUpload(res.tempFiles[i].path)
}
},
fail: err => {
that.openRequest = true
}
})
},
// 上传
getUpload (data) {
let that = this
ossPolicy('', {
suc: (res) => {
let tiemr = new Date()
let address = res.data.dir + '/'
let str = data.substr(data.lastIndexOf('.'))
let nameStr = address + tiemr.getTime() + str
uni.uploadFile({
url: res.data.host,
filePath: data,
fileType: 'image',
name: 'file',
formData: {
name: nameStr,
key: nameStr,
policy: res.data.policy,
OSSAccessKeyId: res.data.accessKeyId,
success_action_status: '200',
signature: res.data.signature
},
success: ress => {
if (ress.statusCode == '200'){
// console.log(111, res.data.host + '/' + nameStr)
that.$main.showToast('上传成功')
let path = res.data.host + '/' + nameStr
that.imgURL = path
} else {
that.$main.showToast('上传失败,请重试')
}
}
})
}
})
},
// 提现接口
getApiCashOut () {
let that = this
let params = {
name: that.nameValue,
method: that.type,
amount: that.moneyValue,
withdrawalQrCode: that.imgURL
}
cashOut(params, {
suc: (res) => {
that.openRequest = true
that.$main.showToast('提现成功')
that.moneyValue = ''
that.nameValue = ''
that.imgURL = ''
that.actualAmount = ''
},
erc: (err) => {
that.openRequest = true
}
})
},
// 提现金额输入框事件
handleInput (e) {
if (!this.balance.balance || this.balance.balance === 0) {
this.$main.showToast('余额不足')
return this.actualAmount = ''
}
if (!e.detail.value) return this.actualAmount = ''
let value = e.detail.value
let count = value * 0.03
this.actualAmount = value - count
},
// 判断提现金额
getApiJudgAmount (value, id, type) {
let that = this
let params = {
withdrawalAmount: value,
userId: id,
userType: type
}
judgAmount(params, {
suc: (res) => {
that.openCashout = false
}
})
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
},
// 提现金额输入框失焦
handleBlur (e) {
setTimeout(() => {
// if (e.mp.detail.value > this.balance) return this.$main.showToast('提现金额超过可用金额!')
if (e.mp.detail.value) this.getApiJudgAmount(e.mp.detail.value, this.$store.getStorageSync('user').memberId, 1)
}, 50)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-cash-out-record">
<view class="option-box">
<view class="options" v-for="(item, index) in recordList" :key="index" v-if="item.type === 3">
<view class="title-box">
<p class="time">{{item.createDate}}</p>
</view>
<view class="count"> - {{item.changeAmount}}</view>
</view>
</view>
<view class="empty-text" v-if="isEmpty">
暂时还没有数据哦~
</view>
</view>
</template>
<script>
import { balanceRecord } from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
recordList: [],
isEmpty: false,
page: 1,
total: 0
}
},
onLoad () {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 5,
type: 3
}
balanceRecord(params, {
suc: (res) => {
that.total = res.data.detailList.total
if (res.data.detailList.pageNum === 1) that.recordList = []
that.recordList = that.recordList.concat(res.data.detailList.list)
if (!that.recordList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
}
})
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.recordList.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style>
</style>
<template>
<view class="cx-coupon" style="padding-top: 100rpx;">
<view class="tabs" style="z-index: 99;">
<v-tabs style="width: 100vw !important;" :tabs="menuList" v-model="active" :scroll="false" line-color="#ff3c39;" active-color="#ff3c39;" fontSize="30rpx"
:lineScale="0.15" padding="0rpx" line-height="10rpx" @change="changeTab"></v-tabs>
</view>
<view class="coupon-list-box">
<view class="list-box" v-if="active === 0">
<view class="coupon-list" v-for="(item, index) in couponList" :key="index" @click="btnChooseCoupon(item.couponHistoryId)">
<view class="top-box">
<view class="left-box">
<p class="title used">{{item.name}}</p>
<p class="time used">有效期:{{item.endTime}}</p>
</view>
<view class="right-box">
<p v-if="item.preferentialWay == 1"><span class="symbol used">¥</span><span class="count used">{{item.reduceAmount}}</span></p>
<p v-if="item.preferentialWay == 2"><span class="count used">{{item.discount}}折</span></p>
<p class="text used" v-if="item.preferentialWay == 1">满{{item.amount}}可用</p>
</view>
</view>
</view>
</view>
<view class="list-box" v-if="active === 1">
<view class="coupon-list" v-for="(item, index) in couponList" :key="index" @click="btnChooseCoupon(item.couponHistoryId)">
<view class="top-box">
<view class="left-box">
<p class="title used">{{item.name}}</p>
<p class="time used">有效期:{{item.endTime}}</p>
</view>
<view class="right-box">
<p v-if="item.preferentialWay == 1"><span class="symbol used">¥</span><span class="count used">{{item.reduceAmount}}</span></p>
<p v-if="item.preferentialWay == 2"><span class="count used">{{item.discount}}折</span></p>
<p class="text used" v-if="item.preferentialWay == 1">满{{item.amount}}可用</p>
</view>
</view>
</view>
</view>
<view class="list-box" v-if="active === 2">
<view class="coupon-list" v-for="(item, index) in couponList" :key="index" @click="btnChooseCoupon(item.couponHistoryId)">
<view class="top-box">
<view class="left-box">
<p class="title used">{{item.name}}</p>
<p class="time used">有效期{{item.endTime}}</p>
</view>
<view class="right-box">
<image class="icon-bg" :src="imgBaseUrl + 'use.png'" webp="true" lazy-load="true"></image>
<p v-if="item.preferentialWay == 1"><span class="symbol used">¥</span><span class="count used">{{item.reduceAmount}}</span></p>
<p v-if="item.preferentialWay == 2"><span class="count used">{{item.discount}}折</span></p>
<p class="text used" v-if="item.preferentialWay == 1">满{{item.amount}}可用</p>
</view>
</view>
</view>
</view>
</view>
<view class="empty-text" v-if="isEmpty">
暂时还没有数据哦~
</view>
</view>
</template>
<script>
import { myCoupon } from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
active: 0,
imgBaseUrl: null,
menuList: ['优惠券', '已使用', '已过期'],
couponList: [],
isEmpty: false,
page: 1,
total: 0
}
},
onLoad () {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.imgBaseUrl = this.$api.IMG_BASE_URL
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 5,
status: that.active
}
myCoupon(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum === 1) that.couponList = []
that.couponList = that.couponList.concat(res.data.list)
if (!that.couponList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
}
})
},
// 选项卡切换
changeTab (e) {
if (this.active === e) return
this.active = e
this.page = 1
this.getApiIndexData()
},
// 确认订单页跳转至此,选择优惠券
btnChooseCoupon () {
if (!this.$root.$mp.query.isOrder) return
this.$store.setStorageSync('couponsId', id)
setTimeout(() => {
this.btnBack(1)
}, 50)
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.couponList.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style>
</style>
<template>
<view class="cx-creat-adress">
<view class="adress-info-box">
<view class="name-box border-bottom">
<p class="name">收货人</p>
<input class="input" type="text" placeholder="请填写收货人姓名" :placeholder-style="placeholderStyle" v-model="nameValue" />
</view>
<view class="phone-box border-bottom">
<p class="phone">手机号码</p>
<input class="input" type="digit" maxlength="11" placeholder="请填写收货人手机号码" :placeholder-style="placeholderStyle" v-model="phoneValue" />
</view>
<view class="position-box border-bottom">
<p class="title">所在地区</p>
<view class="right" @click="btnShowAddress()">
<p class="text" :class="position ? 'isValue' : 'isEmpty'">{{position || '请选择'}}</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="adress-box">
<textarea class="textarea" v-model="detailAddress" placeholder="详细地址:如道路、门牌号、小区、楼栋号、单元室等" :placeholder-style="placeholderStyle" />
</view>
<view class="auto">
<textarea class="textarea" v-model="autoAddress" placeholder="地址复制到这里自动识别 如:福建省厦门市思明区望海路63号之一701-1;张三; 13659852653" :placeholder-style="placeholderStyle" @blur="handleBlur" />
</view>
<view class="switch-box">
<p class="title">设为默认地址</p>
<image v-if="!checked" class="icon" :src="imgBaseUrl + 'defaultmdk.png'" webp="true" lazy-load="true" @click="checked = 1"></image>
<image v-else class="icon" :src="imgBaseUrl + 'defaultdk.png'" webp="true" lazy-load="true" @click="checked = 0"></image>
</view>
</view>
<view class="btn-botom-position" @click="btnAddAdress()">保存收货地址</view>
<simpleAddress ref="simpleAddress" :pickerValueDefault="cityPickerValueDefault" @onConfirm="onConfirm" confirmColor="#ff3c39;" cancelColor="#ff3c39;"></simpleAddress>
</view>
</template>
<script>
import simpleAddress from '@/components/simple-address/simple-address.vue'
import {
addEditAdress,
adressDetail
} from '@/config/api.js'
export default {
components: {
simpleAddress
},
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
placeholderStyle: 'color: #D8D8D8;',
id: null,
checked: 0,
position: '',
nameValue: '',
phoneValue: '',
provinceCity: '',
areaValue: '',
district: '',
autoAddress: '',
detailAddress: '',
openRequest: true, // 按钮保护
cityPickerValueDefault: [0, 0, 1],
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (options.id) {
this.id = options.id
this.$main.setNavigationBarTitle('编辑收货地址')
this.getApiData()
} else {
this.$main.setNavigationBarTitle('新建收货地址')
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 收货地址查询回显
getApiData () {
let that = this
let params = {
addressId: that.id
}
adressDetail(params, {
suc: (res) => {
// that.nameValue = res.data.name
// that.phoneValue = res.data.phoneNumber
// that.provinceCity = res.data.province
// that.areaValue = res.data.city
// that.district = res.data.region
// that.detailAddress = res.data.detailAddress
// that.checked = res.data.defaultStatus
}
})
},
// 新建/编辑收货地址
btnAddAdress () {
if (!this.openRequest) return
this.openRequest = false
if (!this.nameValue) {
this.openRequest = true
return this.$main.showToast('收货人不能为空!')
}
if (!this.phoneValue) {
this.openRequest = true
return this.$main.showToast('手机号不能为空!')
}
if (!this.provinceCity || !this.areaValue || !this.district) {
this.openRequest = true
return this.$main.showToast('区域不能为空!')
}
if (!this.detailAddress) {
this.openRequest = true
return this.$main.showToast('详细地址不能为空!')
}
let that = this
let params = {
name: that.nameValue,
phoneNumber: that.phoneValue,
defaultStatus: that.checked,
province: that.provinceCity,
city: that.areaValue,
region: that.district,
detailAddress: that.detailAddress
}
if (that.id) params.id = that.id
addEditAdress(params, {
suc: (res) => {
that.$store.setStorageSync('isUpdate', true)
that.$store.setStorageSync('addressData', params)
that.$main.showToast(res.message, 800)
setTimeout(() => {
that.btnBack(1)
}, 800)
}
})
},
// 智能识别收货信息
getAddressRequest () {
uni.request({
url: 'https://wangzc.wang/smAddress',
data: {
// address: '福建省厦门市思明区望海路63号之一701-1;张三; 13659852653'
address: this.autoAddress
},
method: 'POST',
success: (res) => {
if (res.data.province) this.provinceCity = res.data.province
if (res.data.city) this.areaValue = res.data.city
if (res.data.county) this.district = res.data.county
this.position = this.provinceCity + '-' + this.areaValue + '-' + this.district
if (res.data.address) this.detailAddress = res.data.address
if (res.data.name) this.nameValue = res.data.name
if (parseInt(res.data.phone)) this.phoneValue = res.data.phone
}
})
},
// 三级联动组件
btnShowAddress() {
this.$refs.simpleAddress.open()
},
// 获取省市区三级联动选择器值
onConfirm (e) {
this.provinceCity = e.labelArr[0]
this.areaValue = e.labelArr[1]
this.district = e.labelArr[2]
this.position = e.label
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
},
// 自动识别文本框失焦
handleBlur (e) {
setTimeout(() => {
if (this.autoAddress) this.getAddressRequest()
}, 50)
}
}
}
</script>
<style>
</style>
<template>
<view class="page">
<textarea v-model="content" placeholder="请输入反馈内容" maxlength="200"></textarea>
<button class="btn" @click="submit()">意见提交</button>
</view>
</template>
<script>
import util from '@/config/util.js'
import {
feedback
} from '@/config/api.js'
export default {
data() {
return {
content: null
};
},
methods: {
submit() {
if (!this.content) {
util.showToast('请输入反馈内容');
return;
}
feedback({
content: this.content,
memberId: this.$store.getStorageSync('user').memberId
}, {
suc: (res) => {
util.showToast('反馈成功');
setTimeout(function() {
uni.navigateBack();
}, 1500)
}
})
}
}
}
</script>
<style lang="less">
.page {
min-height: 100vh;
textarea {
width: 100%;
padding: 30rpx;
font-size: 30rpx;
background-color: white;
}
.btn {
position: fixed;
left: 30rpx;
bottom: 30rpx;
width: calc(100% - 60rpx);
height: 88rpx;
line-height: 88rpx;
font-size: 30rpx;
color: white;
border-radius: 44rpx;
background: #2EA9EA;
}
}
</style>
<template>
<view class="cx-my" v-if="Ok">
<view class="top-status-bar-bg" :style="{'height': StatusBar + 'px'}"></view>
<view class="top-user-info-box">
<view class="circular-bg"></view>
<view class="public-top-boxs" style="width: 100vw; padding-top: 0;" :style="{'top': StatusBar + 'px'}">
<view class="back-box" style="display: flex; align-items: center; align-content: center;" @click="btnShop('/pages/shopping/index')">
<image class="icon-back" style="width: 20rpx; height: 30rpx;" :src="imgBaseUrl + 'returnfh.png'" webp="true" lazy-load="true"></image>
<p class="text" style="margin-left: 8rpx; color: #FFF; font-size: 28rpx;">商城</p>
</view>
<view class="title" style="color: #202020;"></view>
<view class="empty" style="width: 70rpx;"></view>
</view>
</view>
<view class="top-user-info">
<view class="top">
<view class="left">
<view class="user-box" v-if="userInfo.nickname" @click="btnPath('./setUserInfo')">
<view class="avatar-box" @click="btnPath('./setUserInfo')">
<image class="avatar" :src="userInfo.icon || imgBaseUrl + 'xsupplier.png'" webp="true" lazy-load="true"></image>
</view>
<view class="level-box">
<p class="name">{{userInfo.nickname}}</p>
<view class="vip-service" @click.stop="btnPath('./myTeam')">
<image class="icon-vip" v-if="userInfo.level === 0" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level1.png" webp="true" lazy-load="true"></image>
<image class="icon-vip" v-else-if="userInfo.level === 2" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level2.png" webp="true" lazy-load="true"></image>
<image class="icon-vip" v-else-if="userInfo.level === 3" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level3.png" webp="true" lazy-load="true"></image>
<image class="icon-vip" v-else-if="userInfo.level === 4" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level4.png" webp="true" lazy-load="true"></image>
<image class="icon-vip" v-else-if="userInfo.level === 5" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level5.png" webp="true" lazy-load="true"></image>
<image class="icon-vip" v-else-if="userInfo.level === 6" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level6.png" webp="true" lazy-load="true"></image>
</view>
</view>
</view>
<view class="no-login-box" v-else>
<image class="avatar" :src="imgBaseUrl + 'xsupplier.png'" webp="true" lazy-load="true"></image>
<view class="text" @click="gologin" style="color: #202020;font-size: 40rpx;margin-left: 30rpx;">立即登录</view>
</view>
</view>
<view class="right" v-if="!userInfo.wxaccount && userInfo.nickname" @click="showInput = true; type = 1">
<image src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/weichat1.png"></image>
<p class="">填写微信号</p>
</view>
</view>
<view class="bottom" v-if="userInfo.nickname">
<view class="options" @click="btnPath('./myWallet')">
<p class="count">{{userInfo.price}}</p>
<p class="text">余额(元)</p>
</view>
<view class="options">
<p class="count">{{userInfo.amountToBeActivated}}</p>
<p class="text">待激活金额(元)</p>
</view>
<view class="options" @click="btnPath('./coupon')">
<p class="count">{{userInfo.couponCount}}</p>
<p class="text">优惠券(张)</p>
</view>
</view>
</view>
<!--待对碰会员列表-->
<view class="table-box">
<view class="table-head">
<view class="title-box">
<p class="title">待激活佣金列表</p>
<p class="text">{{levelFirstGet == 1 ? '已完成激活' : '未完成首次激活'}}</p>
<image class="icon" @click="showInput = true; type = 2;" :src="imgBaseUrl + 'tips.png'"></image>
</view>
<view class="box">
<view class="options">会员名</view>
<view class="options">已激活级别</view>
<view class="options">待激活金额</view>
<view class="options">进度</view>
</view>
</view>
<view class="table-body">
<view class="list" v-for="(item, index) in vipList" :key="index">
<view class="options">{{item.username}}</view>
<view class="options" v-if="item.level === 0">会员</view>
<view class="options" v-else-if="item.level === 2">举人</view>
<view class="options" v-else-if="item.level === 3">进士</view>
<view class="options" v-else-if="item.level === 4">探花</view>
<view class="options" v-else-if="item.level === 5">榜眼</view>
<view class="options" v-else>状元</view>
<view class="options">{{item.amountToBeCollided}}</view>
<view class="options">50%</view>
</view>
<view class="tips-text" v-if="isEmpty">暂时没有数据哦~</view>
</view>
</view>
<view class="order-info-box">
<view class="title-box">
<p class="title">我的订单</p>
<p class="text" @click="btnPath('./myOrder')">全部订单 ></p>
</view>
<view class="option-box">
<view class="options" @click="btnPath('./myOrder?active=1')">
<view class="icon-box">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/pay.png" webp="true" lazy-load="true"></image>
<view class="point" v-if="userInfo.noPayOrder">{{userInfo.noPayOrder}}</view>
</view>
<p class="text">待付款</p>
</view>
<view class="options" @click="btnPath('./myOrder?active=2')">
<view class="icon-box">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/send.png" webp="true" lazy-load="true"></image>
<view class="point" v-if="userInfo.noSendorder">{{userInfo.noSendorder}}</view>
</view>
<p class="text">待发货</p>
</view>
<view class="options" @click="btnPath('./myOrder?active=3')">
<view class="icon-box">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/receive.png" webp="true" lazy-load="true"></image>
<view class="point" v-if="userInfo.sendOrder">{{userInfo.sendOrder}}</view>
</view>
<p class="text">待收货</p>
</view>
<view class="options" @click="btnPath('./myOrder?active=4')">
<view class="icon-box">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/compelete.png" webp="true" lazy-load="true"></image>
<view class="point" v-if="userInfo.completed">{{userInfo.completed}}</view>
</view>
<p class="text">已完成</p>
</view>
</view>
</view>
<view class="my-server-box">
<view class="title-box">
<p class="title">我的服务</p>
</view>
<view class="server-box">
<view class="options" v-for="(item, index) in serverList" :key="index" @click="btnNavigateTo(item.url)">
<image class="icon" mode="aspectFit" :src="item.icon" webp="true" lazy-load="true"></image>
<p class="text">{{item.text}}</p>
<button class="button" v-if="item.url == 'server'" open-type="contact" @contact="handleContact"></button>
</view>
</view>
</view>
<view class="black-bg" v-if="showInput">
<view class="box" v-if="type === 1">
<input class="input" type="text" v-model="wechatValue" placeholder="请输入微信号" />
<view class="btn-box">
<view class="btn sure" @click="btnConfirm()">确认</view>
</view>
</view>
<view class="rule" v-if="type === 2">
<p class="title">激活规则</p>
<p class="text">1、在下单区完成级别升级,即可激活玩法;</p>
<p class="text">2、分享2个会员完成同级别升级,即可首次激活;</p>
<p class="text">3、首次激活后,在激活列表内任意分享会员完成对应级别升级,即可二次激活;</p>
<p class="text">4、激活列表内无会员,则需分享2个会员完成同级别升级,即可二次激活</p>
</view>
<view class="icon-close-box" @click="showInput = false">
<image class="icon-close" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/close.png"></image>
</view>
</view>
</view>
</template>
<script>
import util from '@/config/util.js'
import {
personal,
orderInfo,
writeWechat,
vipChildList
} from '@/config/api.js'
export default {
data() {
return {
Ok: false,
isEmpty: false,
type: null,
imgBaseUrl: null,
invateCode: this.invateCode,
StatusBar: this.StatusBar,
CustomBar: this.CustomBar,
userInfo: {},
vipList: [],
wechatValue: '',
showInput: false,
serverList: [
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/team.png',
text: '我的团队',
url: '/pages/my/myTeam'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/invite.png',
text: '邀请好友',
url: './inviteFriend'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/address.png',
text: '地址管理',
url: './manageAdress'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/collection.png',
text: '我的收藏',
url: './myCollection'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/money.png',
text: '我的钱包',
url: './myWallet'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/manger.png',
text: '管理奖',
url: './manger'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/coupon.png',
text: '优惠券',
url: './coupon'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/cart.png',
text: '购物车',
url: '/pages/shopping/shopCar'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/college.png',
text: '商学院',
url: ''
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/cash.png',
text: '天天提现',
url: ''
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/drink.png',
text: '喝酒赚钱',
url: ''
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/game.png',
text: '幸运转盘',
url: ''
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/money.png',
text: '打卡赚钱',
url: ''
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/service.png',
text: '在线客服',
url: 'server'
},
{
icon: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/setting.png',
text: '设置',
url: './setting'
}
]
}
},
onLoad() {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (util.isLogin() || !this.$store.getStorageSync('user')) {
this.getApiUserInfo();
} else {
this.userInfo = {}
uni.stopPullDownRefresh();
}
this.getApiVipList()
this.Ok = true
},
onShow () {
if (this.$store.getStorageSync('isInfoUpdate')) {
this.getApiUserInfo()
this.$store.removeStorageSync('isInfoUpdate')
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
//登录
gologin() {
this.$store.removeStorageSync('token');
this.$store.removeStorageSync('user');
uni.navigateTo({
url: '/pages/index/login'
});
},
// 获取个人信息
getApiUserInfo () {
let that = this
let params = ''
personal(params, {
suc: (res) => {
that.$store.setStorageSync('user', res.data)
that.userInfo = res.data
}
})
},
// 获取订单信息
getApiOrderInfo() {
let that = this
let params = {
pageNum: 1,
pageSize: 5
}
orderInfo(params, {
suc: (res) => {
for (let i = 0; i < res.data.list.length; i++) {
if (res.data.list[i].status === 1) {
that.noPay++
} else if (res.data.list[i].status === 3) {
that.waitReceiv++
}
}
}
})
},
// 填写微信号
btnConfirm () {
let that = this
let params = {
wxAccount: that.wechatValue
}
writeWechat(params, {
suc: (res) => {
that.$main.showToast('成功!', 1000)
that.showInput = false
that.wechatValue = ''
that.type = null
}
})
},
// 带对碰会员列表
getApiVipList () {
let that = this
vipChildList('', {
suc: (res) => {
that.vipList = res.data
if (!that.vipList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
}
})
},
// 点击我的服务
btnNavigateTo (url) {
if (!url) return this.$main.showToast('即将开放~')
this.btnPath(url)
},
// 点击左上角
btnShop (url) {
this.$path.reLaunch(url)
},
// 路由 - 跳转
btnPath(url) {
this.$path.navigateTo(url)
}
}
}
</script>
<style scoped lang="less">
</style>
<template>
<view class="page">
<view class="point-box">
<view class="point" v-for="(item, index) of imgsList.length" :class="{'is-now': active === index}"></view>
</view>
<swiper class="swiper" duration="800" :loop="true" @change="handleChange">
<block v-for="(item, index) in imgsList" :key="index">
<swiper-item class="swiper-item">
<image class="image" :src="item.img"></image>
<view class="code-box">
<image class="qrcode" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/qrcode.jpg"></image>
</view>
</swiper-item>
</block>
</swiper>
<!-- <view class="" v-if="isIos">
<view class="share-bg-one" style="display: none;">
<view class="img-item">
<l-painter isBase64ToPath isRenderImage :board="board" @success="success" @fail="fail"></l-painter>
</view>
</view>
</view> -->
<!-- <view class="" v-else> -->
<!-- <view class="" style="padding: 0 30rpx; height: 580px; overflow: hidden;">
<image :src="poster" style="width: 100%; height: 600px;"></image>
</view> -->
<view class="share-bg-one" style="display: none;">
<view class="img-item">
<l-painter isBase64ToPath isRenderImage :board="board" @success="success" @fail="fail"></l-painter>
</view>
</view>
<!-- </view> -->
<!--底部按钮-->
<view class="bottom-btn">
<view class="share-btn" style="margin-right: 100rpx;">
<image src="https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/copy.png"></image>
<text>分享</text>
<button class="button" type="default" open-type="share"></button>
</view>
<view class="save-btn" @click="saveImage">
<image src="https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/pictures.png"></image>
<text>保存图片</text>
</view>
</view>
</view>
</template>
<script>
import util from '@/config/util.js'
import {
getInvitaCode
} from '@/config/api.js'
export default {
data() {
return {
active: 0,
isIos: false,
imgsList: [],
invateCode: '', //邀请码
poster: '', //海报图生成链接 ---这个是生成绘制图的图片链接。可以使用在image上
board: {}, //海报图
shareH: 1200,//分享图片高度
shareqrtop: (1200 * 524) / 810,//二维码里图片的top
sharecodetop: (1200 * 445) / 810,//邀请码的top
}
},
created() {
var StatusBar = this.StatusBar;
var CustomBar = this.CustomBar;
var ScreenHeight = this.ScreenHeight;
this.shareH = 1200;//ScreenHeight - CustomBar; //这里高度是 屏幕高度-导航栏-状态了
// 810(设计稿高度 750rpx为基准) - (设计稿 464qrtop)
// shareH (屏幕图片展示高度) * shareqrtop(屏幕 qrtop
this.shareqrtop = (this.shareH * 524) / 810;
this.sharecodetop = (this.shareH * 445) / 810;
let that = this
wx.getSystemInfo({
success: function (res) {
if (res.brand == 'iPone' || res.platform == 'ios') {
that.isIos = true
} else {
that.isIos = false
}
}
})
},
async onLoad(e) {
Object.assign(this, this.$options.data())
await this.getApiData()
var that = this;
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
wx.getSystemInfo({
success: function (res) {
if (res.brand == 'iPone' || res.platform == 'ios') {
that.isIos = true
} else {
that.isIos = false
}
}
})
// await setTimeout(async () => {
// that.board = await that.boardView()
// }, 1000)
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取邀请码
getApiData () {
let that = this
getInvitaCode('', {
suc: (res) => {
that.invateCode = res.data.code
that.imgsList = res.data.shareImgs
}
})
},
// 切换轮播图
handleChange (e) {
this.active = e.detail.current
},
//根据网络请求 --加载画板内容
boardView (imgPath) {
var board = {
width: '690rpx',
height: this.shareH + 70 + 'rpx',
views: []
}
board.views = [
{
type: 'image',
src: imgPath,
mode: 'widthFix',
css: {
left: '0rpx',
top: '30rpx',
width: '690rpx',
height: this.shareH + 5 + 'rpx'
}
},
{
type: 'image',
src: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/qrcode.jpg',
// src: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=383622954,1725930414&fm=26&gp=0.jpg',
css: {
left: '450rpx',
top: '1100rpx',
width: '120rpx',
height: '120rpx'
}
}
]
return board
},
//加载画板失败
fail (v) {
},
//加载画板成功
success (s) {
this.poster = s;
// this.saveImageToPhotosAlbum(this.poster)
console.log('url: ', s)
this.previewImage(s)
},
// 查看大图
previewImage (path) {
wx.hideLoading()
uni.previewImage({
urls: [path]
})
},
//保存图片
async saveImage() {
wx.showLoading({title: '正在保存'})
await setTimeout(async () => {
this.board = await this.boardView(this.imgsList[this.active].img)
}, 1000)
},
// 保存操作
saveImageToPhotosAlbum (url) {
uni.saveImageToPhotosAlbum({
filePath: url,
success(res) {
wx.hideLoading()
uni.showToast({
title: '已保存到相册',
icon: 'success',
duration: 2000
})
}
})
}
}
}
</script>
<style scoped lang="less">
.page {
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 100vh;
}
.point-box {
margin-top: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.point {
width: 20rpx;
height: 20rpx;
border-radius: 50%;
border: 1px solid #FF3C39;
&:not(:last-child) {
margin-right: 30rpx;
}
}
.is-now {
background-color: #FF3C39;
}
}
.swiper {
margin: 30rpx auto 0;
width: calc(100vw - 100rpx);
height: 1100rpx;
box-sizing: border-box;
.swiper-item {
position: relative;
width: 100%;
height: 100%;
&:not(:last-child) {
margin-right: 20rpx;
}
.image {
width: 100%;
height: 100%;
}
.code-box {
position: absolute;
bottom: 10rpx;
right: 60rpx;
.qrcode {
width: 130rpx;
height: 130rpx;
}
}
}
}
.share-bg-one {
/* margin-top: 60rpx;*/
margin-left: 30rpx;
height: 100vh;
width: calc(100% - 60rpx);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: #000000;
}
.s-list {
width: 100%;
height: 100%;
/*横行滚动关键1*/
flex-direction: row;
white-space: nowrap;
}
.img-item {
display: inline-block;
/*横行滚动关键2*/
width: 100%;
height: 100%;
position: relative;
}
.share-code {
position: absolute;
left: 0;
bottom: 388rpx;
width: 460rpx;
height: 60rpx;
display: flex;
justify-content: center;
align-items: center;
color: red;
font-size: 26rpx;
}
.share-qrcode {
position: absolute;
left: 0;
bottom: 80rpx;
width: 460rpx;
height: 200rpx;
display: flex;
justify-content: center;
align-items: center;
}
.share-img {
width: 100%;
height: 100%;
}
.bottom-btn {
position: fixed;
left: 0rpx;
bottom: 40rpx;
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
bottom: calc(constant(safe-area-inset-bottom) + 40rpx);
/* 兼容 iOS < 11.2 */
bottom: calc(env(safe-area-inset-bottom) + 40rpx);
/* 兼容 iOS >= 11.2 */
.share-btn,
.save-btn {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #202020;
font-size: 24rpx;
}
.button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
outline: none;
}
}
.bottom-btn image {
width: 88rpx;
height: 88rpx;
margin-bottom: 20rpx;
}
</style>
<template>
<view class="cx-manage-adress">
<view class="list-box">
<view class="adress-list" v-for="(item, index) in adressList" :key="index" @click="btnChooseAddress(item.id)">
<view class="top">
<p class="name">{{item.name}}</p>
<p class="phone">{{item.phoneNumber}}</p>
<p class="tips" v-if="item.defaultStatus">默认</p>
</view>
<view class="adress">中国{{item.province}}{{item.city}}{{item.remark}}{{item.street}}{{item.detailAddress}}</view>
<view class="bottom border-top">
<view class="left">
<image v-if="item.defaultStatus" class="icon" :src="imgBaseUrl + 'Selection.png'" webp="true" lazy-load="true"></image>
<image v-else class="icon" :src="imgBaseUrl + 'Notselected.png'" webp="true" lazy-load="true"></image>
<p class="tips">默认地址</p>
</view>
<view class="right" v-if="!isOrder">
<view class="edit" @click="btnPath('./creatAdress?id=' + item.id)">
<image class="icon" :src="imgBaseUrl + 'edit.png'" webp="true" lazy-load="true"></image>
<p class="text">编辑</p>
</view>
<view class="del" @click="btnDelAdress(item.id, index)">
<image class="icon" :src="imgBaseUrl + 'deletes.png'" webp="true" lazy-load="true"></image>
<p class="text">删除</p>
</view>
</view>
</view>
</view>
</view>
<view class="empty-text" v-if="isEmpty">
暂时还没有数据哦~
</view>
<view class="btn-botom-position" @click="btnPath('./creatAdress')">新建收货地址</view>
</view>
</template>
<script>
import {
myAdress,
delAdress
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
adressList: [],
isOrder: 0,
isEmpty: false,
page: 1,
total: 0
}
},
onShow () {
if (this.$store.getStorageSync('isUpdate')) {
this.$store.removeStorageSync('isUpdate')
this.adressList = []
setTimeout(() => {
this.getApiIndexData()
}, 50)
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (options.isOrder) this.isOrder = options.isOrder
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 5
}
myAdress(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum === 1) that.adressList = []
that.adressList = that.adressList.concat(res.data.list)
if (!that.adressList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
}
})
},
// 删除收货地址
btnDelAdress (id, index) {
this.$main.showModal('确定删除?', '警告', true, '删除', '取消', '#ff3c39;').then(resolve => {
if (resolve) {
let that = this
let params = {
addressId: id
}
delAdress(params, {
suc: (res) => {
that.$main.showToast(res.message)
that.page = 1
that.getApiIndexData()
}
})
}
})
},
// 订单页面跳转至此,选择收货地址
btnChooseAddress (id) {
if (!this.$root.$mp.query.isOrder) return
this.$store.setStorageSync('addressId', id)
setTimeout(() => {
this.btnBack(1)
}, 50)
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.adressList.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style>
</style>
<template>
<view class="cx-manger cx-my-wallet">
<view class="top-title-box-bg">
<image class="icon-bg" :src="imgBaseUrl + 'walletbg.png'" webp="true" lazy-load="true"></image>
<view class="top-title-box">
<image class="icon-back" :src="imgBaseUrl + 'returnfh.png'" webp="true" lazy-load="true" @click="btnBack(1)"></image>
<p class="title">管理奖</p>
<view class="empty"></view>
</view>
<view class="count-box">
<view class="left-box">
<view class="all-count">
<p class="title">管理奖金额(元)</p>
<p class="count">{{mangerData.commissionManagementAward || 0}}</p>
</view>
<view class="use-count">
<p class="title">已转出金额(元)</p>
<p class="count">{{mangerData.transferredOutManagementAward || 0}}</p>
</view>
</view>
<view class="right-btn" @click="btnPath('./rollOut')">转出到余额</view>
</view>
</view>
<view class="list-box">
<block v-for="(item, index) in list" :key="index">
<view class="list">
<view class="top">
<p class="title" v-if="item.type === 1">购买物品</p>
<p class="title" v-else-if="item.type === 2">下级升级获得</p>
<p class="title" v-else-if="item.type === 3">提现</p>
<p class="title" v-else-if="item.type === 4">退货</p>
<p class="title" v-else-if="item.type === 5">佣金管理奖</p>
<p class="title" v-else-if="item.type === 6">直推佣金</p>
<p class="title" v-else-if="item.type === 7">间推佣金</p>
<p class="title" v-else-if="item.type === 8">管理奖转入</p>
<p class="title" v-else-if="item.type === 9">管理奖转出</p>
<p class="text" :style="{'color': item.changeType === 1 ? '#202020;' : '#ff3c39;'}">
{{item.changeType === 1 ? '+' : '-'}}
{{item.changeAmount}}
</p>
</view>
<view class="time">
{{item.createDate}}
</view>
</view>
</block>
</view>
<view class="empty-text" v-if="isEmpty">
暂时还没有数据哦~
</view>
</view>
</template>
<script>
import {
mangerPrize
} from '@/config/api.js'
export default {
data() {
return {
Ok: false,
imgBaseUrl: null,
mangerData: '',
list: [],
isEmpty: false,
page: 1,
total: ''
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
this.getApiIndexData()
},
onShow () {
if (this.$store.getStorageSync('isUpdate')) {
this.getApiIndexData()
this.$store.removeStorageSync('isUpdate')
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 15
}
mangerPrize(params, {
suc: (res) => {
that.mangerData = res.data
that.total = res.data.memberAccountDetailVos.total
if (res.data.memberAccountDetailVos.pageNum) that.list = []
that.list = that.list.concat(res.data.memberAccountDetailVos.list)
if (that.list.length) {
that.isEmpty = false
} else {
that.isEmpty = true
}
}
})
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 路由 - 返回
btnBack (count) {
this.$path.navigateBack(count)
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.list.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style>
</style>
<template>
<view class="cx-my-collection">
<view class="goods-box">
<view class="list" v-for="(item, index) in goodsList" :key="index">
<image class="cover" :src="item.productPic" webp="true" lazy-load="true"></image>
<p class="title">{{item.name}}</p>
<view class="price-del-box">
<view class="price-box">
<p class="symbol">¥</p>
<p class="price">{{item.price}}</p>
</view>
<view class="icon-box" @click="btnDel(item.id, index)">
<image class='icon-del' :src="imgBaseUrl + 'close.png'" webp="true" lazy-load="true"></image>
</view>
</view>
</view>
</view>
<view class="empty-text" v-if="isEmpty">
暂无数据哦~
</view>
</view>
</template>
<script>
import {
goodsCollection,
setCollection
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
menuList: ['医美项目', '商品'],
projectList: [],
goodsList: [],
longitude: '',
latitude: '',
isEmpty: false,
page: 1,
total: 0,
//左滑默认宽度
delBtnWidth: 69
}
},
async mounted() {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData() {
let that = this
let params = {
pageNum: that.page,
pageSize: 8
}
goodsCollection(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum == 1) that.goodsList = []
that.goodsList = that.goodsList.concat(res.data.list)
if (!that.goodsList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
}
})
},
// 取消收藏接口
getApiCollect (id, index) {
let that = this
let params = {
articleId: id,
type: 2
}
setCollection(params, {
suc: (res) => {
that.$main.showToast('取消成功', 1000)
setTimeout(() => {
that.goodsList.splice(index, 1)
}, 1000)
}
})
},
// 取消收藏按钮
btnDel (id, index) {
this.$main.showModal('确定移出收藏?', '警告').then(res => {
if (res) {
this.getApiCollect(id, index)
}
})
},
// 路由 - 跳转
btnPath(url) {
this.$path.navigateTo(url)
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
this.page++
if (this.total === this.goodsList.length) return
this.goodsList = []
this.getApiIndexData()
}
}
</script>
<style>
</style>
<template>
<view class="cx-my-order" style="padding-top: 100rpx;" v-if="Ok">
<!-- <view class="public-option-box">
<view class="options" v-for="(item, index) in menuList" :key="index" @click="btnSwitchMenu(item.id)">
<p class="title">{{item.title}}</p>
<view class="border" :class="active === item.id ? 'isSelected' : 'noSelect'"></view>
</view>
</view> -->
<view class="tabs">
<v-tabs style="width: 100vw !important;" :tabs="menuList" v-model="active" :scroll="false" line-color="#ff3c39;" active-color="#ff3c39;" fontSize="30rpx"
:lineScale="0.15" padding="0rpx" line-height="10rpx" @change="changeTab"></v-tabs>
</view>
<view class="option-box">
<!--全部-->
<view class="options" v-for="(item, index) in orderList" :key="index" v-if="active === 0">
<view class="shop-info" @click="btnPath('/pages/index/hospitalDetail?id=' + item.mchtId)">
<image class="icon-shop" :src="item.mchtIcon" mode="aspectFill" webp="true" lazy-load="true"></image>
<p class="shop-name">{{item.mchtName}}</p>
</view>
<view class="goods-info" @click="btnPage(item.status, item.id)">
<view class="top">
<view class="left-box">
<p class="status-text">
{{item.status === 1 ? '待付款' : item.status === 2 ? '待发货' : item.status === 3 ? '待收货' : item.status === 4 ? '已完成' : item.status === 5 ? '已取消' : item.status === 6 ? '已关闭' : '确认收货'}}
</p>
<p class="time">{{item.updateDate}}</p>
</view>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle" v-for="(x, y) in item.orderItems" :key="y">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="right-box">
<view class="title-box">
<p class="title">{{x.productName}}</p>
<p class="price">¥{{x.productPrice}}</p>
</view>
<view class="count-box">
<p class="color">{{x.productAttr}}</p>
<p class="count">x{{x.productQuantity}}</p>
</view>
</view>
</view>
</view>
<view class="bottom border-top">
<view class="price-box">
<p class="count">共{{item.orderItems.length}}件,应付总额:</p>
<p class="symbol">¥</p>
<p class="all-price">{{item.payAmount}}</p>
</view>
<view class="btn-box">
<view class="btn btn-left" v-if="item.status === 1" @click.stop="btnDel(item.id, 0)">取消订单</view>
<view class="btn btn-right2" v-if="item.status === 2" @click.stop="btnRemindShip(item.id)">提醒发货</view>
<view class="btn btn-left" v-if="item.status === 3" @click="btnPath('./signForDetail?id=' + item.id + '&ststus=' + item.status)">查看物流</view>
<view class="btn btn-left" v-if="item.status === 7 || item.status === 5" @click.stop="btnDel(item.id, 1)" style="margin-left: 10rpx;">删除订单</view>
<view class="btn btn-right1" v-if="item.status === 1" @click="btnPay(index)">付款{{item.timeMsg}}</view>
<view class="btn btn-right2" v-if="item.status === 3" @click.stop="btnConfirmReceiv(item.id)">确认收货</view>
<view class="btn btn-right2" v-if="item.status >3" @click="btnReLaunch('/pages/shopping/index')">再次购买</view>
</view>
</view>
</view>
<!--待付款-->
<view class="options" v-for="(item, index) in orderList" :key="index" v-if="active === 1 && item.status === 1">
<view class="shop-info" @click="btnPath('/pages/index/hospitalDetail?id=' + item.mchtId)">
<image class="icon-shop" :src="item.mchtIcon" mode="aspectFill" webp="true" lazy-load="true"></image>
<p class="shop-name">{{item.mchtName}}</p>
</view>
<view class="goods-info" @click="btnPath('./orderDetail?id=' + item.id)">
<view class="top">
<view class="left-box">
<p class="status-text">
待付款
</p>
<p class="time">{{item.updateDate}}</p>
</view>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle" v-for="(x, y) in item.orderItems" :key="y">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="right-box">
<view class="title-box">
<p class="title">{{x.productName}}</p>
<p class="price">¥{{x.productPrice}}</p>
</view>
<view class="count-box">
<p class="color">{{x.productAttr}}</p>
<p class="count">x{{x.productQuantity}}</p>
</view>
</view>
</view>
</view>
<view class="bottom border-top">
<view class="price-box">
<p class="count">共{{item.orderItems.length}}件,应付总额:</p>
<p class="symbol">¥</p>
<p class="all-price">{{item.payAmount}}</p>
</view>
<view class="btn-box">
<view class="btn btn-left" @click.stop="btnDel(item.id, 0)">取消订单</view>
<view class="btn btn-right1" @click="btnPay(index)">付款{{item.timeMsg}}</view>
</view>
</view>
</view>
<!--待发货-->
<view class="options" v-for="(item, index) in orderList" :key="index" v-if="active === 2 && item.status === 2">
<view class="shop-info" @click="btnPath('/pages/index/hospitalDetail?id=' + item.mchtId)">
<image class="icon-shop" :src="item.mchtIcon" mode="aspectFill" webp="true" lazy-load="true"></image>
<p class="shop-name">{{item.mchtName}}</p>
</view>
<view class="goods-info" @click="btnPath('./orderDetail?id=' + item.id)">
<view class="top">
<view class="left-box">
<p class="status-text">
待发货
</p>
<p class="time">{{item.updateDate}}</p>
</view>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle" v-for="(x, y) in item.orderItems" :key="y">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="right-box">
<view class="title-box">
<p class="title">{{x.productName}}</p>
<p class="price">¥{{x.productPrice}}</p>
</view>
<view class="count-box">
<p class="color">{{x.productAttr}}</p>
<p class="count">x{{x.productQuantity}}</p>
</view>
</view>
</view>
</view>
<view class="bottom border-top">
<view class="price-box">
<p class="count">共{{item.orderItems.length}}件,应付总额:</p>
<p class="symbol">¥</p>
<p class="all-price">{{item.payAmount}}</p>
</view>
<view class="btn-box">
<view class="btn btn-right2" @click.stop="btnRemindShip(item.id)">提醒发货</view>
</view>
</view>
</view>
<!--待收货-->
<view class="options" v-for="(item, index) in orderList" :key="index" v-if="active === 3 && item.status === 3">
<view class="shop-info" @click="btnPath('/pages/index/hospitalDetail?id=' + item.mchtId)">
<image class="icon-shop" :src="item.mchtIcon" mode="aspectFill" webp="true" lazy-load="true"></image>
<p class="shop-name">{{item.mchtName}}</p>
</view>
<view class="goods-info" @click="btnPath('./orderDetail?id=' + item.id)">
<view class="top">
<view class="left-box">
<p class="status-text">
待收货
</p>
<p class="time">{{item.updateDate}}</p>
</view>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle" v-for="(x, y) in item.orderItems" :key="y">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="right-box">
<view class="title-box">
<p class="title">{{x.productName}}</p>
<p class="price">¥{{x.productPrice}}</p>
</view>
<view class="count-box">
<p class="color">{{x.productAttr}}</p>
<p class="count">x{{x.productQuantity}}</p>
</view>
</view>
</view>
</view>
<view class="bottom border-top">
<view class="price-box">
<p class="count">共{{item.orderItems.length}}件,应付总额:</p>
<p class="symbol">¥</p>
<p class="all-price">{{item.payAmount}}</p>
</view>
<view class="btn-box">
<view class="btn btn-left" @click="btnPath('./signForDetail?id=' + item.id + '&ststus=' + item.status)">查看物流</view>
<view class="btn btn-right2" @click.stop="btnConfirmReceiv(item.id)">确认收货</view>
</view>
</view>
</view>
<!--已完成-->
<view class="options" v-for="(item, index) in orderList" :key="index" v-if="active === 4 && item.status === 4">
<view class="shop-info" @click="btnPath('/pages/index/hospitalDetail?id=' + item.mchtId)">
<image class="icon-shop" :src="item.mchtIcon" mode="aspectFill" webp="true" lazy-load="true"></image>
<p class="shop-name">{{item.mchtName}}</p>
</view>
<view class="goods-info" @click="btnPath('./signForDetail?id=' + item.id)">
<view class="top">
<view class="left-box">
<p class="status-text">
交易成功
</p>
<p class="time">{{item.updateDate}}</p>
</view>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle" v-for="(x, y) in item.orderItems" :key="y">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="right-box">
<view class="title-box">
<p class="title">{{x.productName}}</p>
<p class="price">¥{{x.productPrice}}</p>
</view>
<view class="count-box">
<p class="color">{{x.productAttr}}</p>
<p class="count">x{{x.productQuantity}}</p>
</view>
</view>
</view>
</view>
<view class="bottom border-top">
<view class="price-box">
<p class="count">共{{item.orderItems.length}}件,应付总额:</p>
<p class="symbol">¥</p>
<p class="all-price">{{item.payAmount}}</p>
</view>
<view class="btn-box">
<view class="btn btn-left" @click.stop="btnDel(item.id)">删除订单</view>
<view class="btn btn-right2" @click="btnReLaunch('/pages/shopping/index')">再次购买</view>
</view>
</view>
</view>
</view>
<view class="empty-text" v-if="isEmpty">
暂时还没有数据哦~
</view>
</view>
</template>
<script>
import {
myOrder,
delOrder,
confirmReceiv,
remindShip,
orderGetInfo
} from '@/config/api.js'
export default {
data() {
return {
Ok: false,
imgBaseUrl: null,
invateCode: this.invateCode,
active: 0,
menuList: ['全部', '待付款', '待发货', '待收货', '已完成'],
orderList: [],
isEmpty: false,
page: 1,
total: 0
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
this.Ok = true
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (Number(options.active)) this.active = Number(options.active)
this.getApiIndexData()
},
onShow () {
if (this.$store.getStorageSync('isOrderUpdate')) {
this.getApiIndexData()
this.$store.removeStorageSync('isOrderUpdate')
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 5
}
switch (that.active) {
case 0:
break;
case 1:
params.status = 1
break;
case 2:
params.status = 2
break;
case 3:
params.status = 3
break;
case 4:
params.status = 4
break;
}
myOrder(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum === 1) that.orderList = []
that.orderList = that.orderList.concat(res.data.list)
if (!that.orderList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
for (let i = 0; i < that.orderList.length; i++) {
that.orderList[i].timeMsg = ''
if (that.orderList[i].status === 1) {
// 订单状态为待付款,计算剩余付款时间
let timer = setInterval(() => {
let nowTime = new Date().getTime()
let surPlustime= that.orderList[i].paySurplusTimeStamp
let time = surPlustime - nowTime
if (time <= 0) {
that.orderList[i].timeMsg = ''
clearInterval(timer)
that.getApiIndexData()
that.$forceUpdate()
} else {
let minutes = new Date(time).getMinutes()
let seconds = new Date(time).getSeconds()
let msg = minutes + ":" + (seconds < 10 ? '0' + seconds : seconds)
that.orderList[i].timeMsg = msg
that.$forceUpdate()
}
}, 1000)
}
}
}
})
},
// 删除订单接口
getAPiDElOrder (id) {
let that = this
let params = {
orderId: id
}
delOrder(params, {
suc: (res) => {
that.$main.showToast('删除成功!', 800)
setTimeout(() => {
that.getApiIndexData()
}, 800)
}
})
},
// 删除订单按钮
btnDel (id, type) {
let text = type ? '确定删除?' : '确定取消?'
this.$main.showModal(text, '').then(res => {
if (res) {
this.getAPiDElOrder(id)
}
})
},
// 确认收货
btnConfirmReceiv (id) {
this.$main.showModal('确认收货后将无法修改,确认继续?', '').then(res => {
if (res) {
let that = this
let params = {
orderId: id
}
confirmReceiv(params, {
suc: (res) => {
that.$main.showToast('确认收货成功', 1000)
// that.page = 1
setTimeout(() => {
that.getApiIndexData()
}, 1000)
}
})
}
})
},
// 提醒发货
btnRemindShip (id) {
let that = this
let params = {
orderId: id
}
remindShip(params, {
suc: (res) => {
that.$main.showToast('提醒发货成功', 800)
// that.page = 1
setTimeout(() => {
that.getApiIndexData()
}, 800)
}
})
},
// 点击付款
btnPay (index) {
orderGetInfo([this.orderList[index].id], {
suc: (res) => {
let data = res.data.order
this.btnPath('/pages/shopping/orderSettle?id=' + data.id + '&orderSn=' + data.orderSn + '&price=' + data.payAmount + '&paySource=1')
}
})
},
// 判断跳转哪个页面
btnPage (status, id) {
if (status === 4) {
this.btnPath('signForDetail?id=' + id)
} else {
this.btnPath('./orderDetail?id=' + id)
}
},
// 路由 - 重定向跳转
btnReLaunch (url) {
this.$path.reLaunch(url)
},
// 路由 - 跳转
btnPath (url) {
this.$path.navigateTo(url)
},
// 切换选项卡
changeTab (e) {
if (e === this.active) return
this.active = e
this.page = 1
this.getApiIndexData()
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.orderList.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style>
</style>
<template>
<view class="cx-my-team">
<view class="top-box">
<view class="title-text">我的团队</view>
<view class="count">{{teamData.totalNumberOfTeam || 0}}</view>
<view class="icon-box" @click="btnShowInfo(1)">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/myInvite.png"></image>
</view>
<view class="date-box">
<image class="icon left" :src="imgBaseUrl + 'page.png'" @click="btnSwitchDate(false)" webp="true" lazy-load="true"></image>
<p class="date">{{year}}年{{month}}月</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" @click="btnSwitchDate(true)" webp="true" lazy-load="true"></image>
</view>
<p class="title" style="margin-top: 30rpx;">团队当月总业绩:<span style="color: #ff3c39;">{{teamData.datamonthAllPerformance || 0}}</span></p>
</view>
<view class="tab-box">
<view class="options" @click="btnSwitch(0)">
<p class="title" :class="{'is-select': type === 0}">直推({{teamData.totalNumberOfDirectPush || 0}})</p>
<view class="border" :class="type === 0 ? 'is-ckeck' : 'no-check'"></view>
</view>
<view class="options" @click="btnSwitch(1)">
<p class="title" :class="{'is-select': type === 1}">间推({{teamData.totalNumberOfIndirectPush || 0}})</p>
<view class="border" :class="type === 1 ? 'is-ckeck' : 'no-check'"></view>
</view>
</view>
<view class="navbar" style="margin-top: 15rpx; padding: 0 30rpx;">
<view class="tabs" style="position: unset !important;">
<v-tabs style="width: 100vw;" :tabs="tabs" v-model="active" :fixed="false" :scroll="false" line-color="#ff3c39" active-color="#ff3c39" fontSize="30rpx"
:lineScale="0.3" height="80rpx" line-height="10rpx" @change="changeTab"></v-tabs>
</view>
</view>
<view class="list-box">
<view v-if="!isEmpty" class="list">
<block v-for="(item, index) in list" :key="index">
<view class="options" @click="btnShowInfo(0, index)">
<view class="left">
<view class="avatar-box">
<image class="avatar" :src="item.icon"></image>
</view>
<view class="level-box">
<p class="name">{{item.username}}</p>
<image class="icon-level" v-if="item.level === 0" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level1.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="item.level === 2" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level2.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="item.level === 3" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level3.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="item.level === 4" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level4.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="item.level === 5" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level5.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="item.level === 6" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level6.png" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="right">
{{item.createDate.split(' ')[0]}} >
</view>
</view>
</block>
</view>
<view v-else class="empty-text">
暂无数据哦~
</view>
</view>
<view class="black-bg" v-if="showUserInfo">
<view class="block">
<view class="my-inviter-info" v-if="status">
<view class="avatar-box">
<image class="avatar" :src="userInfo.avatar"></image>
</view>
<view class="right">
<view class="top">
<p class="name">{{userInfo.name}}</p>
<image class="icon-level" v-if="userInfo.level === 0" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level1.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="userInfo.level === 2" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level2.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="userInfo.level === 3" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level3.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="userInfo.level === 4" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level4.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="userInfo.level === 5" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level5.png" webp="true" lazy-load="true"></image>
<image class="icon-level" v-else-if="userInfo.level === 6" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/level6.png" webp="true" lazy-load="true"></image>
</view>
<view class="bottom">
<p class="wechat">微信号 &nbsp;<span style="color: #ff3c39;">{{userInfo.wechat || '未填写'}}</span></p>
<image class="icon-copy" @click="btnCopy(userInfo.wechat)" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/copy.png"></image>
</view>
</view>
</view>
<view class="user-info" v-else>
<view class="avatar-box">
<image class="avatar" :src="userInfo.avatar"></image>
</view>
<view class="name">{{userInfo.name}}</view>
<p class="text">当月业绩(元)</p>
<p class="count">{{userInfo.count}}</p>
<view class="options-box">
<view class="options">
<view class="top">
<p class="title">手机号</p>
<image class="icon-copy" @click="btnCopy(userInfo.phone)" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/copy.png"></image>
</view>
<view class="bottom">{{userInfo.phone || '未填写'}}</view>
</view>
<view class="options">
<view class="top">
<p class="title">微信号</p>
<image class="icon-copy" @click="btnCopy(userInfo.wechat)" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/copy.png"></image>
</view>
<view class="bottom">{{userInfo.wechat || '未填写'}}</view>
</view>
</view>
<view class="date">
注册时间:{{userInfo.date}}
</view>
</view>
<view class="icon-close-box" @click="showUserInfo = false; userInfo = {}">
<image class="icon-close" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/close.png"></image>
</view>
</view>
</view>
</view>
</template>
<script>
import {
myTeam
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
active: 0,
type: 0,
teamData: {},
status: 1,
tabs: ['状元', '榜眼', '探花', '进士', '举人', '会员'],
allAchievement: 0,
isEmpty: false,
year: '',
month: '',
date: '',
userInfo: {},
showUserInfo: false,
list: [],
page: 1,
total: 0
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getNowDate()
setTimeout(() => {
this.getApiIndexData()
}, 50)
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 计算当前日期
getNowDate () {
let date = new Date()
this.year = date.getFullYear()
this.month = date.getMonth() + 1
this.date = this.year + '年' + this.month + '月'
},
// 获取主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 15,
type: that.type + 1,
date: that.year + '-' + (that.month >= 10 ? that.month : '0' + that.month)
}
if (that.active === 0) {
params.level = 6
} else if (that.active === 1) {
params.level = 5
} else if (that.active === 2) {
params.level = 4
} else if (that.active === 3) {
params.level = 3
} else if (that.active === 4) {
params.level = 2
} else {
params.level = 0
}
myTeam(params, {
suc: (res) => {
that.total = res.data.memberTeamVos.total
that.teamData = res.data
that.allAchievement = res.data.monthAllPerformance
if (res.data.memberTeamVos.pageNum === 1) that.list = []
that.list = that.list.concat(res.data.memberTeamVos.list)
if (that.list.length) {
that.isEmpty = false
} else {
that.isEmpty = true
}
}
})
},
// 切换直推间推
btnSwitch (type) {
this.type = type
this.page = 1
this.getApiIndexData()
},
// 切换月份
btnSwitchDate (type) {
if (type) {
this.month++
if (this.month >= 12) {
this.year++
this.month = 1
this.date = this.year + '年' + this.month + '月'
}
} else {
this.month--
if (this.month <= 1) {
this.year--
this.month = 12
this.date = this.year + '年' + this.month + '月'
}
}
this.page = 1
this.getApiIndexData()
},
// 复制文本
btnCopy (data) {
if (!data) return this.$main.showToast('文本为空')
this.$main.setClipboardData(data)
this.$main.showToast('复制成功')
},
// 查看会员信息
btnShowInfo (type, index) {
if (type) { // 查看我的邀请人信息
this.userInfo = {
name: this.teamData.invitationName,
avatar: this.teamData.invitationIcon,
level: this.teamData.invitationLevel,
wechat: this.teamData.wxaccount
}
console.log(111111, this.userInfo)
this.status = type
this.showUserInfo = true
} else {
this.userInfo = {
name: this.list[index].username,
avatar: this.list[index].icon,
level: this.list[index].level,
wechat: this.list[index].wxAccount,
phone: this.list[index].phone,
date: this.list[index].createDate,
count: this.list[index].monthPerformance
}
this.status = type
this.showUserInfo = true
}
},
// 路由 - 跳转
btnPath (url) {
this.$path.navigateTo(url)
},
// 切换tab
changeTab (e) {
if (e === this.active) return
this.active = e
this.page = 1
this.getApiIndexData()
}
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.list.length) return
this.page++
this.getApiIndexData()
}
}
</script>
<style scoped>
</style>
<template>
<view class="cx-my-wallet" v-if="Ok">
<view class="top-title-box-bg">
<image class="icon-bg" :src="imgBaseUrl + 'walletbg.png'" webp="true" lazy-load="true"></image>
<view class="top-title-box">
<image class="icon-back" :src="imgBaseUrl + 'returnfh.png'" webp="true" lazy-load="true" @click="btnBack(1)"></image>
<p class="title">我的钱包</p>
<view class="empty"></view>
</view>
<!-- <uni-nav-bar left-icon="back" title="我的钱包" right-text="说明" :fixed="true" :statusBar="true"
:border="false" @clickLeft="btnBack(1)" @click="btnPath('/pages/index/detail?type=4&status=4')"></uni-nav-bar> -->
<view class="count-box">
<view class="left-box">
<view class="all-count">
<p class="title">可用余额</p>
<p class="count"><span class="symbol">¥</span>{{data.balance}}</p>
</view>
<view class="use-count">
<p class="title">已提现金额</p>
<p class="count">¥{{data.availableBalance || 0}}</p>
</view>
</view>
<view class="right-btn" @click="btnPath('./cashOut')">去提现</view>
</view>
<view class="option-box">
<view class="options border-bottom" v-for="(item, index) in optionlist" :key="index" @click="btnPath(item.url)">
<p class="title">{{item.title}}</p>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
</view>
</view>
</template>
<script>
import {
myWallet
} from '@/config/api.js'
export default {
data() {
return {
Ok: false,
imgBaseUrl: null,
invateCode: this.invateCode,
optionlist: [
{title: '余额明细', url: './balanceRecord'},
{title: '提现记录', url: './cashOutRecord'}
],
data: ''
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
this.Ok = true
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = ''
myWallet(params, {
suc: (res) => {
that.data = res.data
}
})
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-order-detail">
<view class="public-top-info-box" style="padding-top: 70rpx;">
<image class="icon-bg" :src="imgBaseUrl + 'statebg.png'" webp="true" lazy-load="true"></image>
<image class="icon-back" :src="imgBaseUrl + 'returnfh.png'" webp="true" lazy-load="true" @click="btnBack(1)"></image>
<view class="info-box">
<view class="left">
<p class="title">{{statustext}}</p>
<p class="tips">{{tipsText}}</p>
</view>
<image class="icon-right" v-if="type == 1" :src="imgBaseUrl + 'ipayment.png'" webp="true" lazy-load="true"></image>
<image class="icon-right" v-if="type == 2" :src="imgBaseUrl + 'ideliver.png'" webp="true" lazy-load="true"></image>
<image class="icon-right" v-if="type == 3" :src="imgBaseUrl + 'idelivers.png'" webp="true" lazy-load="true"></image>
<image class="icon-right" v-if="type == 4" :src="imgBaseUrl + 'iSignfors.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="adress-info-box">
<view class="express-box" v-if="type > 2" @click="btnPath('./signForDetail?id=' + orderId + '&ststus=' + type)">
<view class="icon-box">
<image class="icon" :src="imgBaseUrl + 'collect.png'" webp="true" lazy-load="true"></image>
<view class="text-box">
<p class="text">{{logisticsData.acceptStation}}</p>
<p class="time">{{logisticsData.acceptTime}}</p>
</view>
</view>
<image class="icon-back" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
<view class="info-box">
<view class="icon-box">
<image class="icon" :src="imgBaseUrl + 'locationqr.png'" webp="true" lazy-load="true"></image>
</view>
<view class="right">
<view class="text-box">
<p class="text">{{orderAddressData.receiverName}}</p>
<p class="text" style="margin-left: 30rpx;">{{orderAddressData.receiverPhone}}</p>
</view>
<view class="adress">中国{{orderAddressData.receiverProvince}}{{orderAddressData.receiverCity}}{{orderAddressData.receiverRegion}}{{orderAddressData.receiverDetailAddress}}</view>
</view>
</view>
</view>
<view class="option-box">
<view class="options" v-for="(item, index) in goodsList" :key="index">
<view class="cover-box">
<image class="cover" :src="item.productPic" webp="true" lazy-load="true"></image>
</view>
<view class="right">
<view class="title-box">
<p class="title">{{item.productName}}</p>
<p class="price">¥{{item.productPrice}}</p>
</view>
<view class="count-box">
<p class="text">{{item.productAttr}}</p>
<p class="text">x{{item.productQuantity}}</p>
</view>
</view>
</view>
</view>
<view class="order-info">
<p class='title'>订单信息</p>
<view class="order-num">
<p class="text">订单编号</p>
<view class="right">
<p class="num">{{orderAddressData.orderSn}}</p>
<view class="btn-copy" @click="btnCopy(orderAddressData.orderSn)">复制</view>
</view>
</view>
<view class="time-num">
<p class="text">创建时间</p>
<view class="time">{{orderAddressData.createDate}}</view>
</view>
<view class="time-num" v-if="type !== 1">
<p class="text">付款时间</p>
<view class="time">{{orderAddressData.paymentTime}}</view>
</view>
<view class="time-num" v-if="type === 3">
<p class="text">发货时间</p>
<view class="time">{{orderAddressData.deliveryTime}}</view>
</view>
</view>
<view class="btn-box">
<view class="btn btn-left" v-if="type === 1" @click="btnCancelOrder(0)">取消订单</view>
<view class="btn btn-right" v-if="type === 1" @click="btnPay()">付款{{timeMsg}}</view>
<view class="btn btn-left" v-if="type === 3" @click="btnPath('./signForDetail?id=' + orderId + '&ststus=' + type)">查看物流</view>
<view class="btn btn-left" v-if="(type === 5 || type === 6) && orderAddressData.commentStatus" @click="btnCancelOrder(1)">删除订单</view>
<view class="btn btn-right" v-if="type === 2" @click="btnRemindShip()">提醒发货</view>
<view class="btn btn-right" v-if="type === 3" @click="btnConfirmReceiv()">确认收货</view>
<view class="btn btn-right" v-if="type > 3" @click="btnSwitchTab('/pages/shopping/index')">再次购买</view>
</view>
</view>
</template>
<script>
import {
orderDetail,
delOrder,
confirmReceiv,
remindShip,
orderGetInfo,
logisticDetail
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
type: 0,
statustext: '',
tipsText: '',
timeMsg: '',
orderId: null,
goodsList: [],
addressData: {},
orderData: {},
logisticsData: {},
orderAddressData: {}
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.orderId = options.id
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
orderId: that.orderId
}
orderDetail(params, {
suc: (res) => {
that.orderAddressData = res.data.orderSon
that.goodsList = res.data.orderItems
that.type = that.orderAddressData.status
if (that.type === 1) {
that.statustext = '待付款'
that.tipsText = '您的订单还未付款,请尽快付款'
} else if (that.type === 2) {
that.statustext = '待发货'
that.tipsText = '您的订单已进入仓库,请耐心等待'
} else if (that.type === 3) {
that.getApiInfo(that.orderId)
that.statustext = '已发货'
that.tipsText = '您的订单在配送中,请耐心等待'
} else if (that.type === 4) {
that.getApiInfo(that.orderId)
that.statustext = '已签收'
that.tipsText = '您的订单已签收'
} else if (that.type === 5) {
that.statustext = '已取消'
that.tipsText = '您的订单已取消'
} else if (that.type === 6) {
that.getApiInfo(that.orderId)
that.statustext = '已关闭'
that.tipsText = '订单已关闭'
} else {
that.getApiInfo(that.orderId)
that.statustext = '确认收货'
that.tipsText = '订单已签收'
}
// 订单状态为待付款,计算剩余付款时间
if (that.type === 1) {
let timer = setInterval(() => {
let nowTime = new Date().getTime()
let surPlustime= new Date(res.data.paySurplusTimestamp).getTime()
let time = surPlustime - nowTime
if (time <= 0) {
that.timeMsg = ''
clearInterval(timer)
that.getApiIndexData()
that.$forceUpdate()
} else {
let minutes = new Date(time).getMinutes()
let seconds = new Date(time).getSeconds()
let msg = minutes + ":" + (seconds < 10 ? '0' + seconds : seconds)
that.timeMsg = msg
that.$forceUpdate()
}
}, 1000)
}
// 订单信息
// that.addressData = res.data.order
// that.addressData.receiverName = res.data.order.receiverName
// that.addressData.receiverPhone = res.data.order.receiverPhone
// that.addressData.receiverProvince = res.data.order.receiverProvince
// that.addressData.receiverCity = res.data.order.receiverCity
// that.addressData.receiverRegion = res.data.order.receiverRegion
// that.addressData.receiverDetailAddress = res.data.order.receiverDetailAddress
// 收货信息
// that.orderData.createDate = res.data.order.createDate
// that.orderData.deliverySn = res.data.order.deliverySn
// that.orderData.deliveryTime = res.data.order.deliveryTime
// that.orderData.orderSn = res.data.order.orderSn
// that.orderData.paymentTime = res.data.order.paymentTime
}
})
},
// 请求物流信息
getApiInfo (id) {
let that = this
let params = {
orderId: id
}
logisticDetail(params, {
suc: (res) => {
that.logisticsData = res.data.traces[0]
}
})
},
// 点击付款
btnPay () {
orderGetInfo([this.orderId], {
suc: (res) => {
let data = res.data.order
this.btnPath('/pages/shopping/orderSettle?id=' + data.id + '&orderSn=' + data.orderSn + '&price=' + data.payAmount + '&paySource=1')
}
})
},
// 取消订单接口
apiCancelOrder () {
let that = this
let params = {
orderId: that.orderId
}
delOrder(params, {
suc: (res) => {
that.$store.setStorageSync('isOrderUpdate', true)
that.$main.showToast('取消成功', 1000)
setTimeout(() => {
that.btnBack(1)
}, 1000)
}
})
},
// 取消订单按钮
btnCancelOrder (type) {
let text = type ? '确定删除?' : '确定取消?'
this.$main.showModal(text, '').then(res => {
if (res) {
this.apiCancelOrder()
}
})
},
// 确认收货
btnConfirmReceiv (id) {
this.$main.showModal('确认收货后将无法修改,确认继续?', '').then(res => {
if (res) {
let that = this
let params = {
orderId: that.orderId
}
confirmReceiv(params, {
suc: (res) => {
that.$store.setStorageSync('isOrderUpdate', true)
that.$main.showToast('确认收货成功', 1000)
setTimeout(() => {
that.btnBack(1)
}, 1000)
}
})
}
})
},
// 提醒发货
btnRemindShip () {
let that = this
let params = {
orderId: that.orderId
}
remindShip(params, {
suc: (res) => {
that.$main.showToast('提醒发货成功', 800)
// that.page = 1
setTimeout(() => {
that.getApiIndexData()
}, 800)
}
})
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
},
// 路由 - 跳转tab页
btnSwitchTab (url) {
this.$path.switchTab(url)
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 复制
btnCopy (text) {
this.$main.setClipboardData(text, '复制成功!')
}
}
}
</script>
<style scoped lang="less">
</style>
<template>
<view class="cx-roll-out">
<view class="options">
<p class="title">当前管理奖金额</p>
<p class="text">{{balanceData.commissionManagementAward}}</p>
</view>
<view class="options">
<p class="title">转出金额</p>
<input class="input" type="digit" v-model="moneyValue" placeholder="请输入转出金额" />
</view>
<view class="btn" @click="btnOut()">确认转出</view>
</view>
</template>
<script>
import {
mangerPrize,
mangerPrizeOut
} from '@/config/api.js'
export default {
data() {
return {
balanceData: '',
moneyValue: '',
openRequest: true
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.getApiIndexData()
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: 1,
pageSize: 50
}
mangerPrize(params, {
suc: (res) => {
that.balanceData = res.data
}
})
},
// 转出
btnOut () {
if (!this.balanceData.commissionManagementAward) return this.$main.showToast('额度不足')
if (!this.openRequest) return
this.openRequest = false
if (!this.moneyValue) {
this.openRequest = true
return this.$main.showToast('请填写转出金额')
}
let that = this
let params = {
amount: parseInt(that.moneyValue)
}
mangerPrizeOut(params, {
suc: (res) => {
that.$main.showToast('转出成功')
that.$store.setStorageSync('isUpdate', true)
}
})
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-set-unerInfo" vif="Ok">
<view class="info-box">
<view class="options" @click="chooseImage()">
<view class="title">
个人头像
</view>
<view class="right">
<image class="avatar" :src="userInfo.icon || imgBaseUrl + 'xsupplier.png'" webp="true" lazy-load="true" mode="aspectFill"></image>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="options" @click="showBox = true">
<view class="title">
昵称
</view>
<view class="right">
<p class="text">{{userInfo.nickname}}</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
</view>
<view class="mark" v-if="showBox" @click="showBox = false">
<view class="Box" @click.stop>
<p class="title">修改昵称</p>
<input class="input" type="text" :placeholder="userInfo.nickname" v-model="inputValue" />
<view class="btn-box">
<view class="btn" @click="showBox = false">取消</view>
<view class="btn" @click="btnSave(0)">确定</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
personal,
ossPolicy,
setUserInfo
} from '@/config/api.js'
export default {
data() {
return {
Ok: false,
imgBaseUrl: null,
invateCode: this.invateCode,
avatar: '',
userInfo: {},
showBox: false,
openRequest: true,
inputValue: ''
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取主数据
getApiIndexData () {
let that = this
personal('', {
suc: (res) => {
that.userInfo = res.data
that.Ok = true
},
erc: err => {
that.Ok = true
}
})
},
// 选择图片操作
chooseImage () {
uni.chooseImage({
count: 1,
success: res => {
for (let i = 0; i < res.tempFiles.length; i++) {
if (res.tempFiles[i].size > 2097152) return this.$main.showToast('您上传的图片过大,请重新上传')
this.getUpload(res.tempFiles[i].path)
}
}
})
},
// 上传
getUpload (data) {
let that = this
ossPolicy('', {
suc: (res) => {
let tiemr = new Date()
let address = res.data.dir + '/'
let str = name.substr(name.lastIndexOf('.'))
let nameStr = address + tiemr.getTime() + str
uni.uploadFile({
url: res.data.host,
filePath: data,
fileType: 'image',
name: 'file',
formData: {
name: nameStr,
key: nameStr,
policy: res.data.policy,
OSSAccessKeyId: res.data.accessKeyId,
success_action_status: '200',
signature: res.data.signature
},
success: ress => {
if (ress.statusCode == '200'){
// console.log(111, res.data.host + '/' + nameStr)
let path = res.data.host + '/' + nameStr
that.avatar = path
// that.userInfo.icon = path
// that.$forceUpdate()
that.btnSave(1)
} else {
that.$main.showToast('上传失败,请重试')
}
}
})
}
})
},
// 保存
btnSave (type) {
if (!this.openRequest) return
this.openRequest = false
if (!type) {
if (!this.inputValue) {
this.openRequest = true
this.$main.showToast('昵称不能为空!')
return
}
}
let that = this
let params = {
id: that.$store.getStorageSync('user').memberId
}
if (that.avatar) params.icon = that.avatar
if (that.inputValue) params.nickname = that.inputValue
setUserInfo(params, {
suc: (res) => {
that.avatar = ''
that.inputValue = ''
that.getApiIndexData()
that.$main.showToast('修改成功!')
that.showBox = false
that.$store.setStorageSync('isInfoUpdate', true)
that.openRequest = true
},
erc: err => {
that.openRequest = true
}
})
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-setting">
<view class="option-box">
<view class="options" v-for="(item, index) in setList" :key="index" @click="btnSet(item.url)">
<p class="title">{{item.title}}</p>
<image class="icon" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<!-- <view class="btn-botom-position" @click="logout">
退出登录
</view> -->
</view>
</template>
<script>
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
setList: [
{
title: '意见反馈',
url: './feedback'
},
{
title: '地址管理',
url: './manageAdress'
},
{
title: '清除缓存',
url: ''
}
]
}
},
onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
//退出功能
logout() {
var that = this;
that.$main.showModal('您确定要退出登录吗?', '退出登录').then(res => {
//res true/false
if (res) {
that.$store.removeStorageSync('token');
that.$store.removeStorageSync('user');
uni.navigateTo({
url: '/pages/index/login'
});
}
})
},
// 操作
async btnSet(url) {
if (!url) {
let token = this.$store.getStorageSync('token')
let user = this.$store.getStorageSync('user')
await this.$store.clearStorageSync()
setTimeout(() => {
this.$main.showToast('清除成功!')
this.$store.setStorageSync('token', token)
this.$store.setStorageSync('user', user)
}, 200)
return
}
this.btnPath(url)
},
// 路由 - 跳转子页面
btnPath(url) {
this.$path.navigateTo(url)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-sign-for-detail">
<view class="public-top-info-box" style="padding-top: 70rpx;">
<image class="icon-bg" :src="imgBaseUrl + 'statebg.png'" webp="true" lazy-load="true"></image>
<image class="icon-back" :src="imgBaseUrl + 'returnfh.png'" webp="true" lazy-load="true" @click="btnBack(1)"></image>
<view class="info-box">
<view class="left">
<p class="title">已签收</p>
<p class="tips">您的订单已签收</p>
</view>
<image class="icon-right" :src="imgBaseUrl + 'iSignfors.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="order-info-box">
<view class="title-box">
<p class="title">订单编号</p>
<view class="num-box">
<p class="num">{{orderData.orderNo}}</p>
<view class="btn" @click="btnCopy(orderData.orderNo)">复制</view>
</view>
</view>
<!-- <view class="title-box">
<p class="title">运单编号</p>
<view class="num-box">
<p class="num">{{orderData.orderSn}}</p>
<view class="btn">复制</view>
</view>
</view> -->
<view class="text-box">
<p class="title">承运人</p>
<p class="text">{{orderData.expressCompanyName}}</p>
</view>
<view class="text-box">
<!-- <p>运单编号</p> -->
<p class="title">创建时间</p>
<p class="text">{{orderData.createDate}}</p>
</view>
<v<!-- iew class="text-box">
<p class="title">支付方式</p>
<p class="text">{{payType === 1 ? '支付宝' : payType === 2 ? '微信' : '余额'}}</p>
</view> -->
</view>
<view class="list-box" v-if="expressInfoList.length">
<view class="list" v-for="(item, index) in expressInfoList" :key="index">
<view class="left">
<p class="date">{{item.acceptTime}}</p>
<!-- <p class="time">{{item.time}}</p> -->
</view>
<view class="middle">
<view class="circular" :class="index === 0 ? 'is-now' : 'no-now'">
<view class="border border-top" v-if="index < expressInfoList.length-1"></view>
</view>
<!-- <view class="circular" v-if="item.status === 5">
<view v-if="index < expressInfoList.length-1" class="border border-top"></view>
</view>
<view class="icon-box" v-if="item.status === 1">
<view v-if="index < expressInfoList.length-1" class="border no-border-top"></view>
<image class="icon" v-if="item.isNow" :src="imgBaseUrl + 'orderbright.png'" webp="true" lazy-load="true"></image>
<image class="icon" v-else :src="imgBaseUrl + 'order1.png'" webp="true" lazy-load="true"></image>
</view>
<view class="icon-box" v-if="item.status === 2">
<view v-if="index < expressInfoList.length-1" class="border no-border-top"></view>
<image class="icon" v-if="item.isNow" :src="imgBaseUrl + 'delivergoods.png'" webp="true" lazy-load="true"></image>
<image class="icon" v-else :src="imgBaseUrl + 'deliver.png'" webp="true" lazy-load="true"></image>
</view>
<view class="icon-box" v-if="item.status === 3">
<view v-if="index < expressInfoList.length-1" class="border no-border-top"></view>
<image class="icon" v-if="item.isNow" :src="imgBaseUrl + 'Warehousebright.png'" webp="true" lazy-load="true"></image>
<image class="icon" v-else :src="imgBaseUrl + 'Warehouse.png'" webp="true" lazy-load="true"></image>
</view>
<view class="icon-box" v-if="item.status === 4">
<view v-if="index < expressInfoList.length-1" class="border no-border-top"></view>
<image class="icon" v-if="item.isNow" :src="imgBaseUrl + 'piecebright.png'" webp="true" lazy-load="true"></image>
<image class="icon" v-else :src="imgBaseUrl + 'piece.png'" webp="true" lazy-load="true"></image>
</view>
<view class="icon-box" v-if="item.status === 6">
<view v-if="index < expressInfoList.length-1" class="border no-border-top"></view>
<image class="icon" v-if="item.isNow" :src="imgBaseUrl + 'transportbright.png'" webp="true" lazy-load="true"></image>
<image class="icon" v-else :src="imgBaseUrl + 'transport1.png'" webp="true" lazy-load="true"></image>
</view>
<view class="icon-box" v-if="item.status === 7">
<view v-if="index < expressInfoList.length-1" class="border no-border-top"></view>
<image class="icon" v-if="item.isNow" :src="imgBaseUrl + 'collectbright.png'" webp="true" lazy-load="true"></image>
<image class="icon" v-else :src="imgBaseUrl + 'collect.png'" webp="true" lazy-load="true"></image>
</view> -->
</view>
<view class="right">
<p class="text">{{item.acceptStation}}</p>
<!-- <p class="tips">{{item.tips}}</p> -->
</view>
</view>
</view>
</view>
</template>
<script>
import {
logisticDetail
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
expressInfoList: [],
orderData: {
// createDate: '2019-12-25 10:31:23', // 创建时间
// deliveryTime: '2019-12-25 10:31:23', // 发货时间
// orderSn: '320129302132', // 订单编号
// deliveryCompany: '顺丰快递', // 物流公司
// receiveTime: '2019-12-25 10:31:23' // 签收时间
},
orderId: null,
orderStatus: null
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
// if (this.expressInfoList.length === 1) this.isShowBorder = false
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.orderId = options.id
this.ststus = options.ststus
this.getApiIndexData()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取主数据
getApiIndexData () {
let that = this
let params = {
orderId: that.orderId
}
logisticDetail(params, {
suc: (res) => {
// 订单信息
that.orderData = res.data
for (let i = 0; i < that.orderData.traces.length; i++) {
let text = that.orderData.traces[i].acceptTime
that.orderData.traces[i].acceptTime = text.substr(text.indexOf('-') + 1)
}
that.expressInfoList = that.orderData.traces
}
})
},
// 复制
btnCopy (text) {
this.$main.setClipboardData(text, '复制成功!')
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
},
}
}
</script>
<style>
</style>
<template>
<view class="cx-confirm-order">
<!-- <view class="adress-border-box" v-if="addressData || addressList.length">
<view class="adress-box" @click="btnPath('/pages/my/manageAdress?isOrder=true')">
<view class="icon-box">
<image class="icon-adress" :src="imgBaseUrl + 'locationqr.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle-box">
<p class="name-phone">{{addressData.name}} &nbsp;&nbsp; {{addressData.phoneNumber}}</p>
<p class="adress">中国{{addressData.province}}{{addressData.city}}{{addressData.region}}{{addressData.detailAddress}}</p>
</view>
<image class="icon-back" :src="imgBaseUrl + 'NextLa.png'" webp="true" lazy-load="true"></image>
</view>
<view class="border-box">
<image class="icon-border" :src="imgBaseUrl + 'decorate.png'" webp="true" lazy-load="true"></image>
</view>
</view> -->
<view class="adress-border-box" v-if="addressList.length">
<view class="adress-box" @click="btnPath('/pages/my/manageAdress?isOrder=true')">
<view class="left">
<view class="icon-box">
<image class="icon-adress" :src="imgBaseUrl + 'locationqr.png'" webp="true" lazy-load="true"></image>
</view>
<view class="middle-box">
<p class="name-phone">{{addressList[0].name}} &nbsp;&nbsp; {{addressList[0].phoneNumber}}</p>
<p class="adress">中国{{addressList[0].province}}{{addressList[0].city}}{{addressList[0].region}}{{addressList[0].detailAddress}}</p>
</view>
</view>
<image class="icon-back" :src="imgBaseUrl + 'NextLa.png'" webp="true" lazy-load="true"></image>
</view>
<view class="border-box">
<image class="icon-border" :src="imgBaseUrl + 'decorate.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<!-- <view class="no-address" v-if="!addressData">
<span style="color: #2EA9EA; text-decoration: underline;" @click="btnPath('/pages/my/manageAdress')">点击选择</span>收货地址
</view> -->
<view class="no-address" v-if="!addressList.length">
您还没有收获地址,<span style="color: #ff3c39; text-decoration: underline;" @click="btnPath('/pages/my/creatAdress?isOrder=' + true)">点击创建</span>
</view>
<view class="order-box" v-for="(item, index) in orderList" :key="index">
<view class="goods-box" v-for="(x, y) in item.cartItemDetails.cartItemDetails" :key="y">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="right-box">
<view class="title-box">
<p class="title">{{x.productName}} <span style="color: #FF3C39; font-size: 26rpx;">({{item.productAreaType === 1 ? '会员区' : '勉单区'}})</span></p>
<p class="price">{{x.price}}</p>
</view>
<view class="color-count-box">
<p class="color">{{x.productAttr}}</p>
<p class="count">x{{x.quantity}}</p>
</view>
</view>
</view>
<view class="coupon-box border-bottom" v-if="item.coupons.length">
<p class="title">优惠券</p>
<view class="right-box" @click="btnPageCoupon('/pages/my/coupon?isOrder=true', index)">
<span class="text">{{item.coupons.length}}张可用</span>
<image class="icon-back-gray" :src="imgBaseUrl + 'page.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="message-box border-bottom">
<p class="title">买家留言</p>
<input class="input" type="text" placeholder="选填, 请输入" :v-model="item.message" />
</view>
<view class="discount-info-box">
<view class="options">
<p class="title">订单金额</p>
<p class="num">¥{{item.allPrice}}</p>
</view>
<view class="options">
<p class="title">商品金额</p>
<p class="num">¥{{item.payAmount}}</p>
</view>
<view class="options" v-if="item.couponAmount">
<p class="title">优惠金额</p>
<p class="num">¥{{item.couponAmount}}</p>
</view>
<view class="options">
<p class="title">运费</p>
<p class="num">¥0</p>
</view>
</view>
</view>
<view class="btn-box">
<view class="text-box">
<p class="text">合计:</p>
<p class="symbol">¥</p>
<p class="price">{{allPrice}}</p>
</view>
<view class="btn" @click="btnCommitOrder()">提交订单</view>
</view>
</view>
</template>
<script>
import {
makeConfirmOrder,
makeOrder,
cartMakeConfirmOrder,
cartMakeOrder
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
// checked: false,
orderList: [],
requestData: '',
addressData: null,
couponsData: {
amount: 20, // 优惠券条件金额
couponHistoryId: 1, // 优惠券ID
couponName: '大额满减券', // 优惠券名字
reduceAmount: 10, // 可减金额
useType: 0 // 使用类型
},
addressList: [],
couponsList: [],
addressId: null,
couponsId: null,
couponsIndex: null,
isShopCar: 0,
allPrice: 0
}
},
onLoad(options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (options.data) {
this.requestData = JSON.parse(options.data)
if (options.isShopCar) {
this.isShopCar = options.isShopCar
setTimeout(() => {
this.getApiIndexData()
}, 80)
} else {
setTimeout(() => {
this.getApiIndexData()
}, 80)
}
}
},
onShow() {
if (this.$store.getStorageSync('addressId')) {
this.addressId = Number(this.$store.getStorageSync('addressId'))
this.getUpdateAdress(this.addressId)
this.$store.removeStorageSync('addressId')
}
if (this.$store.getStorageSync('couponsId')) {
this.couponsId = Number(this.$store.getStorageSync('couponsId'))
// this.getUpdateCoupons(this.couponsId)
this.getApiIndexData()
this.$store.removeStorageSync('couponsId')
}
if (this.$store.getStorageSync('isUpdate')) {
// this.addressData = this.$store.getStorageSync('addressData')
// this.addressList.push(this.$store.getStorageSync('addressData'))
// this.$forceUpdate()
this.getApiIndexData()
this.$store.removeStorageSync('isUpdate')
this.$store.removeStorageSync('addressData')
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 获取主数据
getApiIndexData() {
let that = this
let params = null
if (that.isShopCar) {
params = that.requestData
if (that.couponsIndex || that.couponsIndex === 0) {
that.couponsList[that.couponsIndex].couponHistoryId = that.couponsId
params.couponId = that.couponsList[that.couponsIndex].couponHistoryId
}
cartMakeConfirmOrder(params, {
suc: (res) => {
that.addressData = res.data.address
that.addressList = res.data.addresses
that.allPrice = res.data.allPrice
for (let i = 0; i < res.data.shopItemVos.length; i++) {
res.data.shopItemVos[i].message = ''
}
that.orderList = res.data.shopItemVos
}
})
} else {
params = {
mchtId: that.requestData.mchtId,
productId: that.requestData.productId,
quantity: that.requestData.quantity,
skuId: that.requestData.skuId
}
makeConfirmOrder(params, {
suc: (res) => {
that.addressData = res.data.address
that.addressList = res.data.addresses
that.allPrice = res.data.allPrice
for (let i = 0; i < res.data.shopItemVos.length; i++) {
res.data.shopItemVos[i].message = ''
}
that.orderList = res.data.shopItemVos
that.couponsList = res.data.shopItemVos[0].coupons
},
erc: err => {
if (err.code === 14000) {
setTimeout(() => {
that.btnBack(2)
}, 1000)
}
}
})
}
},
// 提交订单
btnCommitOrder() {
// !this.addressData ||
if (!this.addressList.length) return this.$main.showToast('您还没有选择收货地址')
let that = this
let params = {
// addressId: that.addressData.id
addressId: that.addressList[0].id
}
if (that.isShopCar) {
let shopCartList = []
for (let i = 0; i < this.orderList.length; i++) {
let obj = {
ids: []
// mchtCouponId: '',
// note: ''
}
if (this.orderList[i].cartItemDetails.couponId) {
this.orderList[i].cartItemDetails.couponId
}
for (let q = 0; q < this.orderList[i].cartItemDetails.cartItemDetails.length; q++) {
obj.ids.push(this.orderList[i].cartItemDetails.cartItemDetails[q].id)
if (this.orderList[i].cartItemDetails.cartItemDetails[q].message) {
obj.note = this.orderList[i].cartItemDetails.cartItemDetails[q].message
}
}
shopCartList.push(obj)
}
params.shopCartList = shopCartList
cartMakeOrder(params, {
suc: (res) => {
let data = res.data.order
that.btnPath('./orderSettle?id=' + data.id + '&orderSn=' + data.orderSn + '&price=' + data.totalAmount + '&paySource=1')
}
})
} else {
params.note = ''
if (that.couponsId) params.couponId = that.couponsId
params.productSkuDto = {
skuId: that.requestData.skuId,
mchtId: that.requestData.mchtId,
quantity: that.requestData.quantity,
productId: that.requestData.productId
}
makeOrder(params, {
suc: (res) => {
let data = res.data.order
that.btnPath('./orderSettle?id=' + data.id + '&orderSn=' + data.orderSn + '&price=' + data.totalAmount + '&paySource=1')
}
})
}
},
// 选择完地址后回来,更新地址信息
getUpdateAdress(id) {
for (let i = 0; i < this.addressList.length; i++) {
if (this.addressList[i].id === id) this.addressData = this.addressList[i]
}
this.$forceUpdate()
},
// 选择完优惠券后回来,更新优惠券信息
getUpdateCoupons(id) {
for (let i = 0; i < this.couponsList.length; i++) {
if (this.couponsList[i].couponHistoryId === this.couponsId) this.couponsData = this.couponsList[i]
}
this.$forceUpdate()
},
// 判断是否有优惠券
btnPageCoupon(url, index) {
if (this.isShopCar) {
if (!this.couponsList.length) return this.$main.showToast('暂无可用的优惠券哦!')
} else {
if (!this.orderList[index].coupons.length) return this.$main.showToast('暂无可用的优惠券哦!')
}
this.couponsIndex = index
this.btnPath(url)
},
// 路由- 子页面跳转
btnPath(url) {
this.$path.navigateTo(url)
}
}
}
</script>
<style scoped lang="less">
</style>
<template>
<view class="cx-shopping">
<view class="empty-bar" style="position: fixed; top: 0; left: 0; width: 100vw; z-index: 9999; background-color: #FFF;" :style="{'height': StatusBar + 'px'}">
</view>
<uni-nav-bar style="z-index: 9998;" left-icon="back" left-text="首页" title="商城" right-text=" " :fixed="true" :statusBar="true" :border="false" @clickLeft="btnHome('/pages/index/home')">
</uni-nav-bar>
<view class="" style="overflow: auto;" :style="{'height': 'calc(100vh - 44rpx - ' + StatusBar + 'px)'}">
<view class="top-search-box">
<view class="search-box">
<image class="icon-search" :src="imgBaseUrl + 'search.png'" webp="true" lazy-load="true"></image>
<input class="input" type="text" placeholder="搜索您感兴趣的商品" v-model="goodsNameValue" @input="handleInput" />
</view>
<view class="icon-box">
<image class="icon-car" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/service.png" webp="true" lazy-load="true"></image>
<button class="button" open-type="contact"></button>
</view>
</view>
<view class="swiper-box">
<swiper class="swiper" :indicator-dots="true" indicator-active-color="#ff3c39;" :autoplay="true" interval="5000" duration="800" :circular="true">
<swiper-item class="swiper-item" v-for="(item, index) in swiperList" :key="index" @click="btnSwiper(index)">
<image class="img" :src="item.image" mode="aspectFill" webp="true" lazy-load="true"></image>
</swiper-item>
</swiper>
</view>
<view class="navbar" style="margin-top: 20rpx;">
<view class="tabs" style="position: unset !important; z-index: 0 !important;">
<v-tabs style="width: 100vw !important;" :tabs="tabs" v-model="active" :fixed="false" field="sortName" :scroll="tabs.length <= 5 ? false : true" line-color="#ff3c39"
active-color="#ff3c39" fontSize="30rpx" :lineScale="0.15" height="80rpx" line-height="10rpx" @change="changeTab"></v-tabs>
</view>
</view>
<view class="container-box" v-if="goodsList.length">
<view class="goods-list">
<view class="options" v-for="(item, index) in goodsList" :key="index" @click="btnPath('/pages/index/goodsDetail?id=' + item.id)">
<image class="cover" :src="item.productPic" mode="aspectFill" webp="true" lazy-load="true"></image>
<p class="title">{{item.name}}</p>
<view class="content">
<view class="price-box">
<span class="symbol">¥</span>
<span class="price">{{item.price}}</span>
</view>
<view class="btn" @click.stop="btnPath('/pages/index/goodsDetail?id=' + item.id)">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/cart@2x.png"></image>
<span class="text">立即抢购</span>
</view>
</view>
</view>
</view>
</view>
<!-- <view class="public-float-button" @click="btnPath('/pages/shopping/shopCar')" style="bottom: 250rpx;">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/shopping.png"></image>
</view>
<view class="public-float-button" @click="btnPath('/pages/my/index')" style="bottom: 120rpx;">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/mine.png"></image>
</view> -->
<view class="bottom-menu-box">
<view class="box">
<view class="options" @click="btnPath('/pages/shopping/shopCar')">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/cart-white.png"></image>
<p class="text">购物车</p>
</view>
<view class="options" @click="btnPath('/pages/my/index')">
<image class="icon" src="https://huarenv1.oss-cn-beijing.aliyuncs.com/TLD_icon/mine-white.png"></image>
<p class="text">个人中心</p>
</view>
</view>
</view>
<view class="empty-text" v-if="isEmpty">
暂时还没有数据哦~
</view>
</view>
</view>
</template>
<script>
import {
goodsSwiper,
goodsList,
goodsTypeList
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
StatusBar: this.StatusBar,
active: 0,
imgBaseUrl: null,
tabs: [
{id: 0, sortName: '勉单区'}
],
swiperList: [],
goodsList: [],
goodsNameValue: '',
isEmpty: false,
sortId: null,
page: 1,
total: 0
}
},
onPullDownRefresh () {
this.page = 1
this.getApiIndexData()
setTimeout(() => {
wx.stopPullDownRefresh()
}, 1000)
},
// 触底刷新
onReachBottom () {
if (!this.total) return
if (this.total === this.goodsList.length) return
this.page++
this.getApiIndexData()
},
async onLoad () {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.startPullDownRefresh()
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
await this.getApiGoodsType()
this.getApiIndexData()
this.getApiBannerList()
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求商品分类列表
getApiGoodsType () {
let that = this
goodsTypeList('', {
suc: (res) => {
that.tabs = that.tabs.concat(res.data)
}
})
},
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 6,
}
if (that.sortId) params.sortId = that.sortId
if (that.goodsNameValue) params.productName = that.goodsNameValue
if (that.active === 0) params.goodTypeOfBrothers = 1
goodsList(params, {
suc: (res) => {
that.total = res.data.total
if (res.data.pageNum === 1) that.goodsList = []
that.goodsList = that.goodsList.concat(res.data.list)
if (!that.goodsList.length) {
that.isEmpty = true
} else {
that.isEmpty = false
}
}
})
},
// 获取轮播图列表
getApiBannerList () {
let that = this
let params = {
type: 2
}
goodsSwiper(params, {
suc: (res) => {
that.swiperList = res.data
}
})
},
// 点击轮播图
btnSwiper (index) {
if (this.swiperList[index].type == 1) {
if (this.swiperList[index].url) this.btnPath('/pages/index/webView?src=' + this.swiperList[index].url)
} else if (this.swiperList[index].type == 2) {
this.btnPath('/pages/index/goodsDetail?id=' + this.swiperList[index].productId)
} else {
this.btnPath('/pages/index/detail?type=7')
}
},
// 切换tab
changeTab (e) {
wx.startPullDownRefresh()
if (this.active === e) return
this.active = e
this.sortId = this.tabs[this.active].id
this.page = 1
this.getApiIndexData()
},
// 点击左上角返回首页
btnHome (url) {
this.$path.reLaunch(url)
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 输入框事件
handleInput (e) {
this.page = 1
this.getApiIndexData()
}
}
}
</script>
<style scoped lang="less">
.navbar {
scroll-view {
z-index: 0 !important;
}
}
</style>
<template>
<view class="cx-order-settle">
<view class="order-info-box">
<p class="order-num">订单号:{{orderSn}}</p>
<view class="price-box">
<p class="text">需要支付:</p>
<p class="price">¥{{price}}</p>
</view>
</view>
<view class="tips-box">
<p class="symbol">*</p>
<p class="text">为避免订单失效,建议您30分钟内完成支付!</p>
</view>
<view class="pay-box">
<view class="options" @click="btnSelectPay(2)">
<view class="text-box">
<image class="icon-pay" :src="imgBaseUrl + 'WeChatpayment.png'" webp="true" lazy-load="true"></image>
<p class="text">微信支付</p>
</view>
<view class="icon-box">
<image v-if="active === 2" class="icon-select" :src="imgBaseUrl + 'Selection.png'" webp="true" lazy-load="true"></image>
<image v-else class="icon-select" :src="imgBaseUrl + 'Notselected.png'" webp="true" lazy-load="true"></image>
</view>
</view>
<view class="options" v-if="!isProject" @click="btnSelectPay(3)">
<view class="text-box">
<image class="icon-pay" :src="imgBaseUrl + 'Goldcoin.png'" webp="true" lazy-load="true"></image>
<p class="text">余额支付</p>
</view>
<view class="icon-box">
<image v-if="active === 3" class="icon-select" :src="imgBaseUrl + 'Selection.png'" webp="true" lazy-load="true"></image>
<image v-else class="icon-select" :src="imgBaseUrl + 'Notselected.png'" webp="true" lazy-load="true"></image>
</view>
</view>
</view>
<view class="tips">温馨提示:为避免订单失效,建议您在30分钟内完成支付</view>
<view class="btn-pay-box" @click="btnPay()">去支付</view>
</view>
</template>
<script>
import {
pay,
aliPay,
wxPay
} from '@/config/api.js'
export default {
data() {
return {
invateCode: this.invateCode,
imgBaseUrl: null,
active: 2,
id: null,
type: null,
price: '',
orderSn: '',
isProject: null,
paySource: null,
openRequest: true
}
},
onLoad (options) {
Object.assign(this, this.$options.data())
this.imgBaseUrl = this.$api.IMG_BASE_URL
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
if (options.id) {
if (options.id) this.id = options.id
if (options.type) this.type = options.type
if (options.price) this.price = options.price
if (options.orderSn) this.orderSn = options.orderSn
if (options.isProject) this.isProject = options.isProject
if (options.paySource) this.paySource = options.paySource
} else {
// this.$main.showToast('数据缺失,请重试!')
// this.$path.navigateBack(1)
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 去支付
btnPay () {
if (!this.openRequest) return
this.openRequest = false
if (this.active == 2) {
this.apiWxPay()
} else {
this.apiPointsPay()
}
},
// 微信支付
apiWxPay () {
let that = this
let params = {
outTradeNo: that.orderSn,
totalFee: that.price,
type: 2,
paySource: that.paySource
}
wxPay(params, {
suc: (res) => {
uni.requestPayment({
provider: 'wxpay',
timeStamp: res.data.timestamp + '',
nonceStr: res.data.noncestr + '',
package: res.data.package,
signType: res.data.signType,
paySign: res.data.paySign,
success: (ress) => {
that.$store.setStorageSync('isOrderUpdate', true)
that.openRequest = true
that.btnPath('./payResult?payStatus=1')
},
fail: (err) => {
// console.log('err: ', err)
that.openRequest = true
that.btnPath('./payResult?payStatus=0')
}
})
},
erc: err => {
// console.log('erc: ', err)
}
})
},
// 余额/积分支付
apiPointsPay () {
let that = this
let params = {
orderId: that.id,
payType: 3
}
pay(params, {
suc: (res) => {
that.$store.setStorageSync('isOrderUpdate', true)
that.$main.showToast(res.data, 800)
setTimeout(() => {
if (res.code === 200) {
that.openRequest = true
that.btnPath('./payResult?payStatus=1')
} else {
that.openRequest = true
that.btnPath('./payResult?payStatus=0')
}
}, 1000)
},
erc: err => {
that.btnPath('./payResult?payStatus=0')
}
})
},
// 选择支付方式
btnSelectPay (type) {
this.active = type
},
// 路由- 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-pay-sesult">
<view class="icon-box">
<image v-if="status" class="icon" :src="imgBaseUrl + 'successsd.png'" webp="true" lazy-load="true"></image>
<image v-else class="icon" :src="imgBaseUrl + 'fail.png'" webp="true" lazy-load="true"></image>
</view>
<view class="tips-text">{{status ? '支付成功~' : '支付失败~'}}</view>
<view class="btn-box">
<view class="buy" @click="btnBack(3)">继续购买</view>
<view class="back" @click="btnReLaunch('/pages/shopping/index')">返回首页</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
imgBaseUrl: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/',
status: 0
}
},
onNavigationBarButtonTap () {
this.btnBack(3)
},
onLoad (options) {
Object.assign(this, this.$options.data())
if (options.payStatus) {
this.status = Number(options.payStatus)
}
},
methods: {
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
},
// 路由- 重定向跳转
btnReLaunch (url) {
this.$path.reLaunch(url)
}
}
}
</script>
<style>
</style>
<template>
<view class="cx-shop-car">
<view class="btn-box">
<p @click="btnEdit()">{{isEdit ? '完成' : '编辑'}}</p>
</view>
<view class="goods-box" style="padding-top: 20rpx;">
<view class="opitons" v-if="goodsList[0].list.length">
<view class="goods" v-for="(x, y) in goodsList[0].list" :key="y">
<image v-if="!x.isSelect" class="icon-select" :src="imgBaseUrl + 'Notselected.png'" webp="true" lazy-load="true" @click="btnSelectGoods(x)"></image>
<image v-else class="icon-select" :src="imgBaseUrl + 'Selection.png'" webp="true" lazy-load="true" @click="btnSelectGoods(x)"></image>
<view class="right-box" @click="btnSelectGoods(x)">
<image class="cover" :src="x.productPic" webp="true" lazy-load="true"></image>
<view class="content">
<p class="name">{{x.productName}}</p>
<view class="color">
<p class="attr">{{x.productAttr || (x.sp1 || '' + ' ' + x.sp2 || '')}}</p>
<p class="type">{{x.productAreaType == 1 ? '会员区' : '勉单区'}}</p>
</view>
<view class="price-count-box">
<view class="price-box">
<span class="symbol">¥</span>
<span class="price">{{x.price}}</span>
</view>
<view class="count-box">
<image class="icon-count" :src="imgBaseUrl + 'reduce.png'" webp="true" lazy-load="true" @click.stop="btnCount(false, x)"></image>
<p class="count">{{x.quantity}}</p>
<image class="icon-count" :src="imgBaseUrl + 'plus.png'" webp="true" lazy-load="true" @click.stop="btnCount(true, x)"></image>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="btn-bottom-box">
<view class="left-box" @click="btnSelectAll()">
<image v-if="!isSelectAll" class="icon-select" :src="imgBaseUrl + 'Notselected.png'" webp="true" lazy-load="true"></image>
<image v-else class="icon-select" :src="imgBaseUrl + 'Selection.png'" webp="true" lazy-load="true"></image>
<p class="text">全选</p>
</view>
<view class="right-box1" v-if="!isEdit">
<view class="text-box">
<span class="text">合计:</span>
<span class="symbol">¥</span>
<span class="price">{{priceCount}}</span>
</view>
<view class="btn" @click="btnSettle()">结算</view>
</view>
<view class="right-box2" v-else @click="btnDel()">删除</view>
</view>
<view class="empty-text" style="margin-top: 30rpx;" v-if="isEmpty">
您的购物车空空如也~
</view>
</view>
</template>
<script>
import uniNavBar from '@/components/uni-nav-bar/uni-nav-bar.vue'
import {
shopCarList,
shopCarDelGoods,
setShopCarCount,
cartMakeSureOrder
} from '@/config/api.js'
export default {
components: {
uniNavBar
},
data() {
return {
invateCode: this.invateCode,
CustomBar: this.CustomBar,
imgBaseUrl: 'https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/',
isSelectAll: true,
priceCount: 0,
mchtCount: 0,
isEdit: false,
goodsList: [],
goodsIds: [],
mchtIds: [],
isEmpty: false,
page: 1,
total: 0
}
},
onLoad () {
Object.assign(this, this.$options.data())
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
this.getApiIndexData()
},
onShow () {
if (this.$store.getStorageSync('isOrderUpdate')) {
this.getApiIndexData()
this.$store.removeStorageSync('isOrderUpdate')
}
},
// 分享给朋友
onShareAppMessage (res) {
return {
title: '快来注册吧',
path: '/pages/index/home?invateCode=' + this.invateCode
}
},
// 分享朋友圈
onShareTimeline () {
return {
title: '快来注册吧',
query: '/pages/index/home?invateCode=' + this.invateCode
}
},
methods: {
// 请求主数据
getApiIndexData () {
let that = this
let params = {
pageNum: that.page,
pageSize: 6
}
shopCarList('', {
suc: (res) => {
for (let i = 0; i < res.data.list.length; i++) {
// res.data.list[i].merchantName = '这是测试用的名字'
// res.data.list[i].merchantIcon = that.imgBaseUrl + 'zcbg.png'
res.data.list[i].isCheck = true
that.mchtCount++
for (let q = 0; q < res.data.list[i].list.length; q++) {
res.data.list[i].list[q].isSelect = true
}
}
that.total = res.data.total
if (res.data.pageNum === 1) that.goodsList = []
that.goodsList = that.goodsList.concat(res.data.list)
if (!that.goodsList.length) {
that.isEmpty = true
that.isSelectAll = false
} else {
that.isEmpty = false
that.isSelectAll = true
}
that.getPriceCount()
}
})
},
// 删除购物车中的商品
getApiDelShopCar () {
let that = this
let params = {}
if (this.goodsIds.length) param.itemIds = this.goodsIds
if (this.mchtIds.length) params.mchtIds = this.mchtIds
shopCarDelGoods(params, {
suc: (res) => {
that.$main.showToast('删除成功', 1000)
setTimeout(() => {
that.getApiIndexData()
that.isEdit = true
}, 1000)
}
})
},
// 结算按钮
btnSettle () {
let that = this
let params = []
for (let i = 0; i < this.goodsList.length; i++) {
let obj = {
ids: []
}
for (let q = 0; q < this.goodsList[i].list.length; q++) {
if (this.goodsList[i].list[q].isSelect) {
obj.ids.push(this.goodsList[i].list[q].id)
params.push(obj)
}
}
}
setTimeout(() => {
if (params.length) {
let data = JSON.stringify(params)
this.btnPath('./confirmOrder?data=' + data + '&isShopCar=1')
} else {
this.$main.showToast('请先选择商品')
}
}, 50)
},
// 删除按钮
btnDel () {
for (let i = 0; i < this.goodsList.length; i++) {
if (this.goodsList[i].isCheck) {
this.mchtIds.push(this.goodsList[i].merchantId)
} else {
for (let q = 0; q < this.goodsList[i].list.length; q++) {
if (this.goodsList[i].list[q].isSelect) this.goodsIds.push(this.goodsList[i].list[q].id)
}
}
}
if (!this.mchtIds.length && !this.goodsIds.length) return this.$main.showToast('请先选择要删除的商品')
this.$main.showModal('确定删除?').then(res => {
if (res) this.getApiDelShopCar()
})
},
// 购物车加加减减
btnCount (type, item) {
if (type) {
this.priceCount += item.price
this.apiGoodsCount(item, 1)
} else {
if (item.quantity <= 1) return
this.priceCount -= item.price
this.apiGoodsCount(item, 0)
}
},
// 修改数量
apiGoodsCount (item, type) {
let that = this
let params = {
cartId: item.id,
type: type ? 1 : 0
}
setShopCarCount(params, {
suc: (res) => {
if (type) {
item.quantity++
} else {
item.quantity--
}
}
})
},
// 计算总金额
getPriceCount () {
this.priceCount = 0
for (let i = 0; i < this.goodsList.length; i++) {
for (let q = 0; q < this.goodsList[i].list.length; q++) {
if (this.goodsList[i].list[q].isSelect) {
this.priceCount += (this.goodsList[i].list[q].price * this.goodsList[i].list[q].quantity)
}
}
}
},
// 选择商家
btnSelectMcht (index) {
this.goodsList[index].isCheck = !this.goodsList[index].isCheck
if (this.goodsList[index].isCheck) {
this.mchtCount++
} else {
this.mchtCount--
}
if (this.mchtCount === this.goodsList.length) {
this.isSelectAll = true
} else {
this.isSelectAll = false
}
for (let i = 0; i < this.goodsList[index].list.length; i++) {
if (this.goodsList[index].isCheck) {
this.goodsList[index].list[i].isSelect = true
} else {
this.goodsList[index].list[i].isSelect = false
}
}
this.getPriceCount()
},
// 选择商品
btnSelectGoods (item) {
item.isSelect = !item.isSelect
this.getPriceCount()
let count = 0
let goodsCount = 0
for (let q = 0; q < this.goodsList.length; q++) {
goodsCount += this.goodsList[q].list.length
for (let i = 0; i < this.goodsList[q].list.length; i++) {
if (this.goodsList[q].list[i].isSelect) {
count++
}
}
if (count < goodsCount) {
this.goodsList[q].isCheck = false
} else {
this.goodsList[q].isCheck = true
}
}
if (count) {
if (count === goodsCount) {
this.isSelectAll = true
} else {
this.isSelectAll = false
}
} else {
this.isSelectAll = false
}
},
// 全选/全不选
btnSelectAll () {
this.isSelectAll = !this.isSelectAll
if (this.isSelectAll) {
for (let i = 0; i < this.goodsList.length; i++) {
this.goodsList[i].isCheck = true
for (let q = 0; q < this.goodsList[i].list.length; q++) {
this.goodsList[i].list[q].isSelect = true
}
}
this.getPriceCount()
} else {
for (let i = 0; i < this.goodsList.length; i++) {
this.goodsList[i].isCheck = false
for (let q = 0; q < this.goodsList[i].list.length; q++) {
this.goodsList[i].list[q].isSelect = false
}
}
this.getPriceCount()
}
},
// 点击编辑/完成
btnEdit () {
this.isEdit = !this.isEdit
this.mchtCount = 0
if (this.isEdit) {
for (let i = 0; i < this.goodsList.length; i++) {
this.goodsList[i].isCheck = false
for (let q = 0; q < this.goodsList[i].list.length; q++) {
this.goodsList[i].list[q].isSelect = false
}
}
this.isSelectAll = false
} else {
for (let i = 0; i < this.goodsList.length; i++) {
for (let q = 0; q < this.goodsList[i].list.length; q++) {
this.goodsList[i].list[q].isSelect = true
}
}
this.isSelectAll = true
}
},
// 路由 - 跳转子页面
btnPath (url) {
this.$path.navigateTo(url)
},
// 路由 - 回退
btnBack (count) {
this.$path.navigateBack(count)
}
}
}
</script>
<style scoped lang="less">
.btn-box {
padding: 20rpx 30rpx;
box-sizing: border-box;
display: flex;
justify-content: flex-end;
background-color: #FFF;
p {
color: #202020;
font-size: 28rpx;
}
}
.navbar {
margin: 0;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: calc(100vw - 60rpx);
background-color: #FFF;
/* padding: 28rpx 30rpx;
box-sizing: border-box;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF; */
}
.icon {
width: 25rpx;
height: 43rpx;
}
.title {
color: #020202;
font-size: 34rpx;
font-weight: 500;
text-align: center;
}
.text {
color: #020202;
font-size: 30rpx;
}
</style>
/*官网首页*/
.cx-home {
padding-bottom: 140rpx;
background-color: #FFF;
.swiper-box {
.swiper {
overflow: hidden;
.swiper-item {
.img {
width: 100vw;
height: 400rpx;
}
}
}
}
.title-box {
margin-top: 60rpx;
padding: 0 30rpx;
.title {
color: #2EA9EA;
font-size: 30rpx;
font-weight: bold;
}
.English {
margin-top: 20rpx;
color: #AAAAAA;
font-size: 26rpx;
}
.border {
margin-top: 25rpx;
width: 80rpx;
height: 2rpx;
background-color: #C9C7C7;
}
}
.desc {
margin-top: 30rpx;
padding: 0 30rpx;
color: #999999;
font-size: 28rpx;
line-height: 34rpx;
letter-spacing: 0.5rpx;
}
.imgs-box {
margin-top: 10rpx;
padding: 0 30rpx;
display: flex;
flex-wrap: wrap;
.img {
margin-top: 20rpx;
margin-right: 20rpx;
width: 216rpx;
height: 150rpx;
border-radius: 4rpx;
&:nth-child(3n) {
margin-right: 0;
}
}
}
.more-box {
padding: 30rpx;
box-sizing: border-box;
// .icon {
// width: 227rpx;
// height: 77rpx;
// }
.text {
text-align: right;
color: #AAAAAA;
font-size: 26rpx;
}
}
.video-box {
margin-top: 60rpx;
padding: 0 30rpx;
.swiper {
border-radius: 10rpx;
overflow: hidden;
.swiper-item {
position: relative;
.img {
width: calc(100vw - 60rpx);
height: 400rpx;
}
.bg {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .2);
.icon {
width: 100rpx;
height: 100rpx;
}
}
}
}
}
.new-box {
padding: 0 30rpx;
.list {
margin-top: 30rpx;
padding-bottom: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
border-bottom: 1px solid #C9C7C7;
.left {
width: 500rpx;
color: #333333;
font-size: 26rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.date {
margin-left: 50rpx;
color: #AAAAAA;
font-size: 24rpx;
}
}
}
.address-box {
margin-top: 30rpx;
padding: 0 30rpx;
p {
color: #333333;
font-size: 28rpx;
&:not(:first-child) {
margin-top: 20rpx;
}
}
}
.map-box {
margin-top: 30rpx;
padding: 0 30rpx;
.map {
width: 100%;
height: 430rpx;
}
}
.other-box {
margin-top: 30rpx;
padding: 0 30rpx;
.title {
text-align: center;
}
.img {
margin-top: 20rpx;
width: 690rpx;
height: 400rpx;
}
}
.form-box {
margin-top: 30rpx;
.options {
padding: 20rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
&:not(:last-child) {
border-bottom: 1px solid #E8E8E8;
}
.title {
display: flex;
align-items: center;
align-content: center;
width: 140rpx;
color: #202020;
font-size: 30rpx;
.symbol {
display: block;
color: #F00;
font-size: 30rpx;
}
}
.input {
margin-left: 50rpx;
flex-grow: 1;
font-size: 30rpx;
}
.textarea {
margin-left: 50rpx;
width: 500rpx;
height: 150rpx;
font-size: 30rpx;
}
.position-box {
margin-left: 50rpx;
flex-grow: 1;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.text {
font-size: 30rpx;
}
.icon {
width: 15rpx;
height: 25rpx;
}
}
}
}
.btn-box {
margin-top: 30rpx;
width: 100vw;
.btn {
margin: 0 auto;
padding: 20rpx 0;
width: 690rpx;
color: #FFF;
font-size: 30rpx;
text-align: center;
border-radius: 40rpx;
background-color: #ff3c39;
}
}
.btn-shopping {
position: fixed;
bottom: 40rpx;
left: 30rpx;
z-index: 99999;
padding: 20rpx 0;
width: 690rpx;
color: #FFF;
font-size: 30rpx;
font-weight: bold;
text-align: center;
border-radius: 40rpx;
background-color: #ff3c39;
}
}
/*台粮首页 - 更多*/
.cx-more {
.imgs-box {
padding: 0 30rpx;
background-color: #FFF;
.img {
margin-top: 20rpx;
margin-right: 15rpx;
width: 220rpx;
height: 220rpx;
&:nth-child(3n) {
margin-right: 0;
}
}
}
.new-box {
padding: 0 30rpx;
background-color: #FFF;
.list {
margin-top: 30rpx;
padding-bottom: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
border-bottom: 1px solid #C9C7C7;
.left {
width: 500rpx;
color: #333333;
font-size: 26rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.date {
margin-left: 50rpx;
color: #AAAAAA;
font-size: 24rpx;
}
}
}
}
/*富文本页面*/
.cx-detail {
.detail {
image {
max-width: 100vw !important;
}
img {
max-width: 100vw !important;
}
.wscnph {
max-width: 100vw !important;
}
}
}
/*商品详情页规格选择*/
.cx-goods-detail {
.banner {
position: relative;
.top-back-box {
position: absolute;
top: 30rpx;
left: 0;
z-index: 9;
padding: 0 30rpx;
width: 750rpx;
background-color: #FFF;
.icon {
width: 21rpx;
height: 37rpx;
}
}
}
.comment-box {
margin-top: 30rpx;
padding: 30rpx 30rpx 40rpx;
background-color: #FFF;
.title-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left-box {
display: flex;
align-items: center;
align-content: center;
.border {
width: 6rpx;
height: 24rpx;
border-radius: 6rpx;
background-color: #ff3c39;
}
.text {
margin-left: 10rpx;
color: #020202;
font-size: 30rpx;
}
}
.right-box {
display: flex;
align-items: center;
align-content: center;
.text {
color: #999999;
font-size: 24rpx;
}
.icon {
margin-left: 8rpx;
width: 12rpx;
height: 20rpx;
}
}
}
.content-box {
margin-top: 30rpx;
display: flex;
align-items: flex-start;
.logo {
width: 66rpx;
height: 66rpx;
border-radius: 50%;
}
.right-box {
margin-left: 15rpx;
.name {
color: #010101;
font-size: 26rpx;
}
.stars-box {
margin-top: 10rpx;
display: flex;
align-items: center;
align-content: center;
.icon-star {
margin-right: 6rpx;
width: 25rpx;
height: 25rpx;
}
.text {
margin-left: 5rpx;
color: #999999;
font-size: 22rpx;
}
}
.comment-content {
margin-top: 15rpx;
color: #666666;
font-size: 26rpx;
}
.imgs-box {
margin-top: 15rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.img {
width: 194rpx;
height: 194rpx;
border-radius: 6rpx;
}
}
}
}
}
.standard-bg {
position: fixed;
top: 0;
left: 0;
z-index: 10;
width: 750rpx;
height: 100vh;
background-color: rgba(0, 0, 0, 0.3);
.standard-box {
position: absolute;
bottom: 0;
left: 0;
width: 750rpx;
background-color: #FFF;
.top-box {
padding: 30rpx;
display: flex;
align-items: center;
align-content: centre;
justify-content: space-between;
.title {
color: #020202;
font-size: 26rpx;
}
.icon-close {
width: 30rpx;
height: 30rpx;
}
}
.goods-info {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
.img-box {
.img {
width: 80rpx;
height: 80rpx;
border-radius: 15rpx;
}
}
.right-box {
margin-left: 35rpx;
flex-grow: 1;
.price {
color: #ff3c39;
font-size: 24rpx;
}
.text {
color: #020202;
font-size: 24rpx;
}
}
}
.option-box {
.options {
padding: 15rpx 30rpx;
border-bottom: 1px solid #E5E5E5;
&:first-child {
border-top: 1px solid #E5E5E5;
}
.name {
color: #020202;
font-size: 24rpx;
}
.value-box {
display: flex;
.value {
margin-top: 10rpx;
padding: 10rpx 15rpx;
min-width: 130rpx;
text-align: center;
font-size: 24rpx;
border-radius: 20rpx;
&:not(:last-child) {
margin-right: 20rpx;
}
}
.selected {
color: #E96C63;
background-color: #FADBD9;
}
.no-select {
color: #020202;
border: 1px solid #E8E8E8;
}
}
}
}
.count-box {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left {
display: flex;
.text1 {
color: #020202;
font-size: 28rpx;
}
.text2 {
margin-left: 10rpx;
color: #B4B4B4;
font-size: 24rpx;
}
}
.right {
display: flex;
align-items: center;
align-content: center;
.icon {
width: 40rpx;
height: 40rpx;
}
.count {
margin: 0 25rpx;
color: #020202;
font-size: 26rpx;
}
}
}
.btn {
height: 88rpx;
line-height: 88rpx;
margin-top: 120rpx;
color: #FFF;
font-size: 30rpx;
text-align: center;
background-color: #ff3c39;
}
}
}
}
/*会员商城首页*/
.cx-shopping {
padding-bottom: 170rpx;
.top-search-box {
padding: 14rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: 750rpx;
background-color: #FFF;
.search-box {
flex-grow: 1;
padding: 18rpx 26rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
border-radius: 30rpx;
background-color: #F7F7F7;
.icon-search {
width: 28rpx;
height: 29rpx;
}
.input {
flex-grow: 1;
margin-left: 10rpx;
color: #020202;
font-size: 22rpx;
}
}
.icon-box {
position: relative;
width: 60rpx;
height: 60rpx;
overflow: hidden;
.icon-car {
margin-left: 10rpx;
width: 45rpx;
height: 45rpx;
}
.button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
outline: none;
}
}
}
.swiper-box {
padding: 30rpx;
background-color: #FFF;
.swiper {
border-radius: 10rpx;
overflow: hidden;
.swiper-item {
.img {
width: 690rpx;
height: 350rpx;
}
}
}
}
.container-box {
padding: 0 30rpx;
.switch-tab-box {
padding: 0 20rpx;
display: flex;
align-items: center;
align-content: center;
.switch-tab {
flex: 1;
display: flex;
align-items: center;
align-content: center;
.child-box {
display: flex;
flex-wrap: wrap;
text-align: center;
justify-content: center;
height: 60rpx;
.title {
width: 100%;
color: #020202;
font-size: 30rpx;
}
.border {
margin-top: 15rpx;
width: 28rpx;
height: 6rpx;
background-color: #ff3c39;
}
}
}
}
.goods-list {
padding-bottom: 20rpx;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
justify-content: space-between;
.options {
margin-top: 30rpx;
padding-bottom: 20rpx;
box-sizing: border;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
width: 338rpx;
border-radius: 10rpx;
overflow: hidden;
background-color: #FFF;
.cover {
width: 338rpx;
height: 340rpx;
border-radius: 10rpx 10rpx 0 0;
}
.title {
margin: 15rpx 13rpx 0 13rpx;
width: 100%;
height: 80rpx;
color: #2A2A2A;
font-size: 28rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.content {
margin: 15rpx 13rpx 0 13rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: 100%;
.price-box {
display: flex;
align-items: flex-end;
.symbol {
color: #ff3c39;
font-size: 24rpx;
}
.price {
color: #ff3c39;
font-size: 32rpx;
}
}
.btn {
padding: 15rpx 20rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
border-radius: 25rpx;
background-color: #ff3c39;
.icon {
margin-right: 5rpx;
width: 21rpx;
height: 21rpx;
}
.text {
color: #FFF;
font-size: 22rpx;
}
}
}
}
}
}
.bottom-menu-box {
position: fixed;
bottom: 40rpx;
left: 0;
width: 100vw;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.box {
padding: 20rpx 30rpx;
box-sizing: border-box;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
border-radius: 60rpx;
background-color: rgba(0, 0, 0, .8);
.options {
flex: 1;
display: flex;
align-items: center;
align-content: center;
flex-direction: column;
justify-content: center;
width: 200rpx;
text-align: center;
&:not(:last-child) {
border-right: 1px solid #FFF;
}
.icon {
width: 40rpx;
height: 40rpx;
}
.text {
margin-top: 10rpx;
color: #FFF;
font-size: 24rpx;
}
}
}
}
}
/*购物车*/
.cx-shop-car {
padding-bottom: 120rpx;
min-height: calc(100vh - 88rpx - var(--status-bar-height));
background-color: #F8F8F8;
.top-set-box {
padding: 28rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.icon {
width: 25rpx;
height: 43rpx;
}
.title {
color: #020202;
font-size: 34rpx;
font-weight: 500;
}
.text {
color: #020202;
font-size: 30rpx;
}
}
.goods-box {
padding-top: 108rpx;
.opitons {
margin-bottom: 20rpx;
padding: 30rpx 30rpx 40rpx;
background-color: #FFF;
.goods {
display: flex;
align-items: center;
align-content: center;
&:not(:last-child) {
margin-bottom: 40rpx;
}
.icon-select {
width: 34rpx;
height: 34rpx;
}
.right-box {
margin-left: 20rpx;
flex-grow: 1;
display: flex;
.cover {
width: 150rpx;
height: 150rpx;
border-radius: 9rpx;
}
.content {
flex-grow: 1;
margin-left: 20rpx;
.name {
color: #020202;
font-size: 30rpx;
font-weight: 400;
}
.color {
margin-top: 15rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.attr {
color: #666666;
font-size: 24rpx;
}
.type {
color: #ff3c39;
font-size: 24rpx;
}
}
.price-count-box {
margin-top: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.price-box {
display: flex;
align-items: flex-end;
.symbol {
color: #ff3c39;
font-size: 24rpx;
}
.price {
color: #ff3c39;
font-size: 32rpx;
}
}
.count-box {
display: flex;
align-items: center;
align-content: center;
.icon-count {
width: 40rpx;
height: 40rpx;
}
.count {
width: 70rpx;
height: 40rpx;
line-height: 40rpx;
text-align: center;
}
}
}
}
}
}
}
}
.btn-bottom-box {
position: fixed;
bottom: 0;
left: 0;
padding: 15rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: 750rpx;
height: 100rpx;
background-color: #FFF;
.left-box {
display: flex;
align-items: center;
align-content: center;
.icon-select {
width: 33rpx;
height: 33rpx;
}
.text {
margin-left: 15rpx;
color: #020202;
font-size: 26rpx;
}
}
.right-box1 {
display: flex;
align-items: center;
align-content: center;
.text-box {
display: flex;
align-items: center;
align-content: center;
.text {
color: #020202;
font-size: 28rpx;
}
.symbol {
color: #ff3c39;
font-size: 24rpx;
}
.price {
color: #ff3c39;
font-size: 32rpx;
}
}
.btn {
margin-left: 10rpx;
height: 66rpx;
line-height: 66rpx;
padding: 0 60rpx;
border-radius: 45rpx;
font-size: 30rpx;
color: #FFF;
background-color: #ff3c39;
}
}
.right-box2 {
height: 66rpx;
line-height: 66rpx;
padding: 0 60rpx;
border-radius: 45rpx;
font-size: 30rpx;
color: #FFF;
background-color: #ff3c39;
}
}
}
/*确认订单*/
.cx-confirm-order {
padding-bottom: 120rpx;
min-height: 100vh;
background-color: #F8F8F8;
.top-title-box {
padding: 27rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.icon-back {
width: 21rpx;
height: 37rpx;
}
.title {
color: #020202;
font-size: 34rpx;
font-weight: 500;
}
}
.adress-border-box {
display: flex;
flex-wrap: wrap;
.adress-box {
padding: 27rpx 30rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: 750rpx;
background-color: #FFF;
.left {
display: flex;
align-items: center;
align-content: center;
.icon-box {
.icon-adress {
width: 60rpx;
height: 60rpx;
}
}
.middle-box {
margin-left: 30rpx;
.name-phone {
color: #010101;
font-size: 30rpx;
}
.adress {
margin-top: 10rpx;
color: #666666;
font-size: 26rpx;
}
}
}
.icon-back {
margin-left: 30rpx;
width: 25rpx;
height: 15rpx;
transform: rotate(-90deg);
}
}
.border-box {
margin-top: -35rpx;
.icon-border {
width: 750rpx;
height: 6rpx;
}
}
}
.no-address {
padding: 30rpx;
text-align: center;
background-color: #FFF;
color: #202020;
font-size: 28rpx;
}
.order-box {
padding: 30rpx 0 40rpx;
background-color: #FFF;
&:not(:first-child) {
margin-top: 40rpx;
}
.goods-box {
padding: 0 30rpx;
box-sizing: border;
display: flex;
align-items: center;
align-content: center;
&:not(:last-child) {
margin-bottom: 40rpx;
}
.cover {
width: 150rpx;
height: 150rpx;
border-radius: 9rpx;
}
.right-box {
margin-left: 20rpx;
flex-grow: 1;
.title-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #020202;
font-size: 30rpx;
font-weight: 400;
}
.price {
color: #020202;
font-size: 26rpx;
}
}
.color-count-box {
margin-top: 15rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.color {
color: #666666;
font-size: 24rpx;
}
.count {
color: #666666;
font-size: 24rpx;
}
}
}
}
.coupon-box {
margin-top: 20rpx;
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.title {
color: #010101;
font-size: 26rpx;
}
.right-box {
display: flex;
align-items: center;
align-content: center;
.text {
color: #B4B4B4;
font-size: 26rpx;
}
.icon-back-gray{
margin-left: 15rpx;
width: 15rpx;
height: 25rpx;
}
}
}
.integral-box {
padding: 25rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.title-box {
display: flex;
align-items: center;
align-content: center;
.title {
color: #010101;
font-size: 26rpx;
}
.tips {
margin-left: 20rpx;
color: #B4B4B4;
font-size: 26rpx;
}
}
.switch-bx {
.icon-switch {
width: 75rpx;
height: 44rpx;
}
}
}
.message-box {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
background-color: #FFF;
.title {
color: #010101;
font-size: 26rpx;
}
.input {
flex: 1;
margin-left: 20rpx;
color: #020202;
font-size: 26rpx;
}
}
.discount-info-box {
margin-top: 20rpx;
padding: 30rpx 30rpx 40rpx;
background-color: #FFF;
.options {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
&:not(:last-child) {
margin-bottom: 25rpx;
}
.title {
color: #020202;
font-size: 26rpx;
}
.num {
color: #333333;
font-size: 26rpx;
}
}
}
}
.btn-box {
position: fixed;
bottom: 0;
left: 0;
padding: 16rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: 100%;
background-color: #FFF;
.text-box {
display: flex;
align-items: flex-end;
align-content: flex-end;
.text {
color: #020202;
font-size: 28rpx;
}
.symbol {
color: #ff3c39;
font-size: 24rpx;
}
.price {
color: #ff3c39;
font-size: 32rpx;
font-weight: 400;
}
}
.btn {
padding: 18rpx 31rpx;
border-radius: 45rpx;
color: #FFF;
font-size: 30rpx;
background-color: #ff3c39;
}
}
}
/*结算页面*/
.cx-order-settle {
padding-bottom: 120rpx;
.top-title-box {
padding: 27rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.icon-back {
width: 21rpx;
height: 37rpx;
}
.title {
color: #020202;
font-size: 34rpx;
font-weight: 500;
}
}
.order-info-box {
padding: 30rpx 27rpx;
background-color: #FFF;
.order-num {
color: #666666;
font-size: 28rpx;
}
.price-box {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
.text {
color: #666666;
font-size: 28rpx;
}
.price {
color: #ff3c39;
font-size: 28rpx;
}
}
}
.tips-box {
padding: 20rpx 27rpx;
display: flex;
align-items: center;
align-content: center;
.symbol {
color: #FF0000;
font-size: 22rpx;
}
.text{
color: #999999;
font-size: 22rpx;
}
}
.pay-box {
.options {
padding: 25rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
&:not(:last-child) {
border-bottom: 1px solid #E8E8E8;
}
.text-box {
display: flex;
align-items: center;
align-content: center;
.icon-pay {
width: 40rpx;
height: 40rpx;
}
.text {
margin-left: 30rpx;
color: #020202;
font-size: 30rpx;
}
}
.icon-box {
display: flex;
align-items: center;
align-content: center;
.icon-select {
width: 34rpx;
height: 34rpx;
}
}
}
}
.tips {
padding: 20rpx 30rpx;
color: #ff3c39;
font-size: 24rpx;
}
.btn-pay-box {
position: fixed;
bottom: 30rpx;
left: 30rpx;
width: 690rpx;
height: 88rpx;
color: #FFF;
font-size: 30rpx;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
background-color: #ff3c39;
}
}
/*支付结果页*/
.cx-pay-sesult {
padding-top: 40rpx;
height: 100vh;
background-color: #FFF;
.icon-box {
text-align: center;
.icon {
width: 175rpx;
height: 175rpx;
}
}
.tips-text {
margin-left: 15rpx;
text-align: center;
color: #020202;
font-size: 30rpx;
}
.btn-box {
margin-top: 80rpx;
padding: 0 60rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.buy {
width: 280rpx;
height: 60rpx;
color: #ff3c39;
font-size: 26rpx;
text-align: center;
line-height: 60rpx;
border-radius: 30rpx;
border: 1px solid #ff3c39;
}
.back {
width: 280rpx;
height: 60rpx;
color: #999999;
font-size: 26rpx;
text-align: center;
line-height: 60rpx;
border-radius: 30rpx;
border: 1px solid #DCDCDC;
}
}
}
/*我的(个人中心)*/
.cx-my {
// min-height: 100vh;
background-color: #F8F8F8;
overflow-x: hidden;
overflow-y: scroll;
.top-status-bar-bg {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100vw;
// opacity: 0;
background-color: #ff3c39;
}
.top-user-info-box {
position: relative;
margin-left: -15%;
display: flex;
flex-wrap: wrap;
justify-content: center;
overflow: hidden;
width: 130%;
height: 450rpx;
// background: linear-gradient(#64AAF0, #ff3c39);
background-color: #ff3c39;
border-radius: 0 0 80% 80%;
.circular-bg {
position: absolute;
bottom: -50rpx;
right: -50rpx;
width: 300rpx;
height: 300rpx;
border-radius: 50%;
background-color: rgba(255, 255, 255, .1);
}
}
.top-user-info {
position: relative;
z-index: 9998;
margin: -220rpx auto 0;
// padding: calc(80rpx + var(--status-bar-height) / 2) 40rpx 0 40rpx;
padding: 30rpx 40rpx;
display: flex;
flex-direction: column;
width: calc(100vw - 60rpx);
background-color: #FFF;
border-radius: 35rpx;
.top {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left {
display: flex;
align-items: center;
align-content: center;
.user-box {
display: flex;
align-items: center;
align-content: center;
.avatar-box {
.avatar {
width: 108rpx;
height: 108rpx;
border-radius: 50%;
border: 1px solid #FFF;
}
}
.level-box {
margin-left: 30rpx;
display: flex;
flex-direction: column;
.name {
width: 240rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #202020;
font-size: 35rpx;
font-weight: 600;
}
.vip-service {
margin-top: 10rpx;
.icon-vip {
width: 130rpx;
height: 40rpx;
}
}
}
}
.no-login-box {
display: flex;
align-items: center;
align-content: center;
.avatar {
width: 108rpx;
height: 108rpx;
}
.text {
color: #202020;
font-size: 32rpx;
}
}
}
.right {
margin-right: -40rpx;
width: 330rpx;
height: 60rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
border-radius: 30rpx 0 0 30rpx;
background-color: #EEEEEE;
image {
width: 45rpx;
height: 40rpx;
}
p {
margin-left: 10rpx;
color: #202020;
font-size: 30rpx;
}
}
}
.bottom {
margin-top: 60rpx;
display: flex;
align-items: center;
align-content: center;
.options {
flex: 1;
.count {
color: #ff3c39;
font-size: 36rpx;
font-weight: bold;
text-align: center;
}
.text {
margin-top: 5rpx;
color: #AAA;
font-size: 26rpx;
text-align: center;
}
}
}
}
.table-box {
position: relative;
margin: 30rpx auto 0;
padding: 0 0 20rpx 0;
width: calc(100vw - 60rpx);
border-radius: 30rpx;
background-color: #FFF;
.table-head {
.title-box {
padding: 30rpx 0 0 40rpx;
display: flex;
align-items: center;
align-content: center;
.title {
color: #202020;
font-size: 34rpx;
font-weight: bold;
}
.text {
margin-left: 15rpx;
padding: 2rpx 8rpx;
color: #FFF;
font-size: 24rpx;
background-color: #FF3C3A;
border-radius: 10rpx;
}
.icon {
margin-left: 15rpx;
width: 40rpx;
height: 40rpx;
}
}
.box {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
.options {
flex: 1;
color: #202020;
font-size: 26rpx;
font-weight: bold;
text-align: center;
}
}
}
.table-body {
margin-top: 20rpx;
.list {
display: flex;
align-items: center;
align-content: center;
.options {
flex: 1;
padding: 20rpx 0;
color: #202020;
font-size: 24rpx;
text-align: center;
}
}
.tips-text {
margin-left: 15rpx;
text-align: center;
color: #AAA;
font-size: 30rpx;
}
}
}
.order-info-box {
margin: 30rpx auto 0;
padding: 30rpx 0 30rpx;
width: 690rpx;
background-color: #FFF;
border-radius: 30rpx;
.title-box {
padding: 0 40rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #202020;
font-size: 34rpx;
font-weight: bold;
}
.text {
color: #AAA;
font-size: 24rpx;
}
}
.option-box {
margin-top: 40rpx;
display: flex;
align-items: center;
align-content: center;
.options {
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
text-align: center;
justify-content: center;
.icon-box {
position: relative;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.icon {
width: 60rpx;
height: 50rpx;
}
.point {
position: absolute;
top: -8rpx;
right: -8rpx;
min-width: 30rpx;
min-height: 30rpx;
text-align: center;
line-height: 30rpx;
border-radius: 50%;
color: #F7F7F7;
font-size: 20rpx;
background-color: #F00;
}
}
.text {
margin-top: 10rpx;
width: 100%;
text-align: center;
color: #333333;
font-size: 22rpx;
}
}
}
}
.my-server-box {
margin: 20rpx auto 0;
padding-bottom: 40rpx;
width: calc(100vw - 60rpx);
background-color: #FFF;
border-radius: 30rpx;
.title-box {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
.title {
color: #202020;
font-size: 34rpx;
font-weight: bold;
}
.icon {
width: 15rpx;
height: 25rpx;
}
}
.server-box {
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
.options {
position: relative;
padding-top: 45rpx;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
justify-content: center;
width: 172rpx;
.icon {
width: 50rpx;
height: 50rpx;
}
.text {
margin-top: 15rpx;
width: 100%;
text-align: center;
color: #6F6F71;
font-size: 22rpx;
}
.button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
outline: none;
}
}
}
}
.black-bg {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100vw;
height: 100vh;
padding: 0 30rpx;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
background-color: rgba(0, 0, 0, .5);
.box {
padding: 30rpx;
width: calc(100vw - 60rpx);
border-radius: 35rpx;
background-color: #FFF;
max-height: 400rpx;
overflow-x: hidden;
overflow-y: scroll;
.input {
padding: 3rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
border: 1px solid #202020;
border-radius: 30rpx;
font-size: 30rpx;
}
.btn-box {
margin-top: 60rpx;
.btn {
padding: 20rpx 0;
color: #FFF;
font-size: 30rpx;
text-align: center;
border-radius: 30rpxssssssssssss;
background-color: #ff3c39;
}
}
.text {
color: #202020;
font-size: 30rpx;
}
}
.rule {
padding: 30rpx;
width: calc(100vw - 60rpx);
border-radius: 35rpx;
background-color: #FFF;
max-height: 500rpx;
overflow-x: hidden;
overflow-y: scroll;
.title {
margin-bottom: 40rpx;
text-align: center;
font-size: 36rpx;
color: #ff3c39;
font-weight: bold;
}
.text {
margin-top: 15rpx;
color: #202020;
font-size: 30rpx;
letter-spacing: 0.5;
}
}
.icon-close-box {
margin: 40rpx auto 0;
text-align: center;
.icon-close {
width: 80rpx;
height: 80rpx;
}
}
}
}
/*管理奖*/
.cx-manger {
.list-box {
width: 100vw;
.list {
padding: 30rpx;
.top {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #202020;
font-size: 30rpx;
}
.text {
font-size: 30rpx;
}
}
.time {
margin-top: 15rpx;
color: #999999;
font-size: 22rpx;
}
}
}
}
/*我的钱包*/
.cx-my-wallet {
.top-title-box-bg {
padding-top: var(--status-bar-height);
position: relative;
width: 100%;
.icon-bg {
position: absolute;
top: 0;
height: 0;
z-index: -1;
width: 100%;
height: 100%;
}
.top-title-box {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.icon-back {
width: 21rpx;
height: 37rpx;
}
.title {
color: #FFFFFF;
font-size: 34rpx;
font-weight: 500;
}
.tips {
color: #FFFFFF;
font-size: 30rpx;
}
}
.count-box {
padding: 50rpx 40rpx 70rpx 50rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left-box {
.all-count {
}
.use-count {
margin-top: 45rpx;
}
.title {
color: #FFFFFF;
font-size: 26rpx;
}
.count {
margin-top: 10rpx;
color: #FFFFFF;
font-size: 40rpx;
font-weight: bold;
.symbol {
color: #FFFFFF;
font-size: 30rpx;
}
}
}
.right-btn {
width: 175rpx;
height: 60rpx;
color: #FFFFFF;
font-size: 28rpx;
text-align: center;
line-height: 60rpx;
border-radius: 30rpx;
border: 1px solid #FFF;
}
}
.option-box {
background-color: #FFF;
.options {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #020202;
font-size: 30rpx;
}
.icon-back {
width: 15rpx;
height: 25rpx;
}
}
}
}
}
/*转出到余额*/
.cx-roll-out {
height: 100vh;
background-color: #F8F8F8;
.options {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.title {
width: 220rpx;
color: #202020;
font-size: 30rpx;
}
.text {
flex-grow: 1;
margin-left: 40rpx;
color: #ff3c39;
font-size: 30rpx;
}
.input {
flex-grow: 1;
margin-left: 40rpx;
}
}
.btn {
margin: 50rpx auto 0;
padding: 20rpx 0;
width: calc(100vw - 60rpx);
text-align: center;
color: #FFF;
border-radius: 15rpx;
background-color: #ff3c39;
}
}
/*提现*/
.cx-cash-out {
min-height: 100vh;
background-color: #F8F8F8;
.top-tips {
padding: 17rpx 22rpx;
color: #F59453;
font-size: 24rpx;
background-color: #FFEDE3;
}
.option-box {
margin-top: 30rpx;
.options {
padding: 20rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
&:not(:last-child) {
border-bottom: 1px solid #E8E8E8;
}
.title-text {
color: #202020;
font-size: 30rpx;
}
.right {
flex-grow: 1;
margin-left: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.list {
flex: 1;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.border {
display: flex;
align-items: center;
align-content: center;
justify-content: center;
width: 30rpx;
height: 30rpx;
border-radius: 50%;
border: 1px solid #ff3c39;
.point {
width: 18rpx;
height: 18rpx;
border-radius: 50%;
background-color: #FF3C39;
}
}
.text {
color: #202020;
font-size: 30rpx;
}
}
}
.title {
width: 230rpx;
color: #202020;
font-size: 30rpx;
}
.text {
margin-left: 30rpx;
text-align: left;
flex-grow: 1;
color: #ff3c39;
font-size: 30rpx;
}
.input {
margin-left: 30rpx;
flex-grow: 1;
color: #202020;
font-size: 30rpx;
}
}
}
.btn {
margin: 40rpx auto 0;
padding: 20rpx 0;
width: calc(100vw - 60rpx);
text-align: center;
color: #FFF;
font-size: 30rpx;
border-radius: 15rpx;
background-color: #ff3c39;
}
}
/*提现记录*/
.cx-cash-out-record {
min-height: 100vh;
background-color: #F8F8F8;
.option-box {
.options {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
&:not(:last-child) {
border-bottom: 1px solid #E8E8E8;
}
.title-box {
.title {
color: #020202;
font-size: 28rpx;
}
.time {
margin-top: 15rpx;
color: #999999;
font-size: 22rpx;
}
}
.count {
color: #020202;
font-size: 32rpx;
}
}
}
}
/*余额明细*/
.cx-balance-record {
min-height: 100vh;
background-color: #F8F8F8;
.top-title-box {
height: calc(88rpx + var(--status-bar-height));
padding: 0 30rpx;
padding-top: var(--status-bar-height);
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.icon-back {
width: 21rpx;
height: 37rpx;
}
.title {
color: #020202;
font-size: 34rpx;
font-weight: 500;
}
.tips {
color: #020202;
font-size: 30rpx;
}
}
.tips-box {
padding: 30rpx 30rpx 20rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
color: #999999;
font-size: 24rpx;
}
.record-box {
.options {
padding: 30rpx;
background-color: #FFF;
&:not(:last-child) {
border-bottom: 1rpx solid #F8F8F8;
}
.left-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #020202;
font-size: 28rpx;
}
.count {
font-size: 32rpx;
}
.red {
color: #FF0000;
}
.black {
color: #020202;
}
}
.time {
margin-top: 15rpx;
color: #999999;
font-size: 22rpx;
}
}
}
}
/*优惠券*/
.cx-coupon {
min-height: 100vh;
background-color: #F8F8F8;
.coupon-list-box {
padding: 0 30rpx 20rpx;
.list-box {
.coupon-list {
margin-top: 20rpx;
padding: 20rpx 30rpx 25rpx;
border-radius: 10rpx;
background-color: #FFF;
box-shadow: 3rpx 5rpx 10rpx 17rpx rgba(236,230,230,0.66);
.top-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left-box {
.title {
font-size: 32rpx;
font-weight: 500;
}
.time {
margin-top: 20rpx;
font-size: 22rpx;
}
.black {
color: #020202;
}
.gray {
color: #666666;
}
}
.right-box {
position: relative;
.icon-bg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 126rpx;
height: 94rpx;
}
.symbol {
position: relative;
z-index: 9;
font-size: 30rpx;
}
.count {
position: relative;
z-index: 9;
font-size: 60rpx;
}
.text {
margin-top: -8rpx;
font-size: 20rpx;
}
.red {
color: #ff3c39;
}
.gray {
color: #999999;
}
}
}
.use-text {
margin-top: 30rpx;
padding-top: 30rpx;
color: #AAAAAA;
font-size: 20rpx;
border-top: 3rpx dashed #E8E8E8;
}
.used {
color: #AAAAAA;
}
}
}
}
}
/*管理收货地址*/
.cx-manage-adress {
padding-bottom: 120rpx;
min-height: 100vh;
background-color: #F8F8F8;
.list-box {
.adress-list {
padding: 40rpx 0 30rpx;
background-color: #FFF;
&:not(:last-child) {
margin-bottom: 20rpx;
}
.top {
margin: 0 30rpx;
display: flex;
align-items: center;
align-content: center;
.name {
color: #020202;
font-size: 30rpx;
}
.phone {
margin-left: 20rpx;
color: #020202;
font-size: 30rpx;
}
.tips {
margin-left: 30rpx;
width: 60rpx;
height: 34rpx;
color: #ff3c39;
font-size: 20rpx;
text-align: center;
line-height: 34rpx;
border-radius: 16rpx;
border: 1px solid #ff3c39;
}
}
.adress {
margin: 20rpx 30rpx 30rpx;
width: 550rpx;
color: #666666;
font-size: 26rpx;
line-height: 34rpx;
}
.bottom {
padding: 30rpx 30rpx 0;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left {
display: flex;
align-items: center;
align-content: center;
.icon {
width: 34rpx;
height: 34rpx;
}
.tips {
margin-left: 10rpx;
color: #999999;
font-size: 24rpx;
}
}
.right {
display: flex;
align-items: center;
align-content: center;
.edit {
display: flex;
align-items: center;
align-content: center;
.icon {
width: 27rpx;
height: 27rpx;
}
.text {
margin-left: 10rpx;
color: #020202;
font-size: 24rpx;
}
}
.del {
margin-left: 30rpx;
display: flex;
align-items: center;
align-content: center;
.icon {
width: 27rpx;
height: 31rpx;
}
.text {
margin-left: 10rpx;
color: #020202;
font-size: 24rpx;
}
}
}
}
}
}
}
/*新建/编辑收货地址*/
.cx-creat-adress {
padding-bottom: 120rpx;
min-height: 100vh;
background-color: #F8F8F8;
.adress-info-box {
.name-box {
padding: 40rpx 30rpx 20rpx;
display: flex;
align-items: center;
align-content: center;
background-color: #FFF;
.name {
width: 120rpx;
color: #020202;
font-size: 30rpx;
}
.input {
margin-left: 50rpx;
flex-grow: 1;
color: #020202;
font-size: 28rpx;
}
}
.phone-box {
padding: 40rpx 30rpx 20rpx;
display: flex;
align-items: center;
align-content: center;
background-color: #FFF;
.phone {
width: 120rpx;
color: #020202;
font-size: 30rpx;
}
.input {
margin-left: 50rpx;
flex-grow: 1;
color: #020202;
font-size: 28rpx;
}
}
.position-box {
padding: 40rpx 30rpx 20rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.title {
width: 120rpx;
color: #020202;
font-size: 30rpx;
}
.right {
margin-left: 50rpx;
flex-grow: 1;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.text {
font-size: 28rpx;
}
.isValue {
color: #020202;
}
.isEmpty {
color: #D8D8D8;
}
.icon {
width: 15rpx;
height: 25rpx;
}
}
}
.adress-box {
padding: 35rpx 40rpx;
background-color: #FFF;
.textarea {
height: 75rpx;
color: #020202;
font-size: 28rpx;
}
}
.auto {
margin-top: 20rpx;
padding: 50rpx 45rpx 60rpx 30rpx;
background-color: #FFF;
.textarea {
height: 110rpx;
color: #020202;
font-size: 28rpx;
}
}
.switch-box {
margin-top: 20rpx;
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.title {
color: #020202;
font-size: 30rpx;
}
.icon {
width: 75rpx;
height: 44rpx;
}
}
}
}
/*我的收藏*/
.cx-my-collection {
min-height: 100vh;
background-color: #F8F8F8;
.goods-box {
padding-left: 29rpx;
display: flex;
flex-wrap: wrap;
.list {
margin: 20rpx 16rpx 0 0;
padding-bottom: 30rpx;
width: 338rpx;
background-color: #FFF;
.cover {
width: 338rpx;
height: 340rpx;
border-radius: 10rpx 10rpx 0 0;
}
.title {
padding: 20rpx 15rpx 0;
box-sizing: border-box;
width: 100%;
font-size: 26rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.price-del-box {
margin: 25rpx 15rpx 0;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.price-box {
display: flex;
align-items: flex-end;
.symbol {
margin-bottom: 2rpx;
color: #ff3c39;
font-size: 24rpx;
}
.price {
color: #ff3c39;
font-size: 32rpx;
}
}
.icon-box {
padding: 8rpx;
display: flex;
align-items: center;
align-content: center;
.icon-del {
width: 20rpx;
height: 20rpx;
}
}
}
}
}
}
/*关于我们*/
.cx-about-us {
padding-top: 50rpx;
height: calc(100vh - 50rpx);
background-color: #FFF;
.logo-box {
width: 750rpx;
text-align: center;
.logo {
width: 350rpx;
height: 188rpx;
}
}
.edition-info {
margin-top: 20rpx;
color: #AAAAAA;
font-size: 22rpx;
text-align: center;
}
.option-box {
margin-top: 70rpx;
.options {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
border-bottom: 1px solid #F8F8F8;
.title {
color: #666666;
font-size: 28rpx;
}
.right {
display: flex;
align-items: center;
align-content: center;
.text {
color: #020202;
font-size: 28rpx;
}
.icon {
margin-left: 15rpx;
width: 15rpx;
height: 25rpx;
}
}
}
}
}
/*设置*/
.cx-setting {
min-height: 100vh;
background-color: #F8F8F8;
.option-box {
.options {
display: flex;
flex-direction: row;
align-items: center;
padding: 30rpx 40rpx;
background-color: #FFF;
border-bottom: 1px solid #F8F8F8;
.title {
flex: 1;
color: #020202;
font-size: 28rpx;
}
.icon {
width: 15rpx;
height: 25rpx;
}
}
}
}
/*我的订单*/
.cx-my-order {
padding-bottom: 30rpx;
min-height: 100vh;
background-color: #F8F8F8;
.option-box {
.options {
margin-top: 20rpx;
padding: 30rpx;
background-color: #FFF;
.shop-info {
display: flex;
align-items: center;
align-content: center;
.icon-shop {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
}
.shop-name {
margin-left: 20rpx;
color: #202020;
font-size: 26rpx;
}
}
.goods-info {
margin-top: 20rpx;
.top {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left-box {
display: flex;
align-items: center;
align-content: center;
.status-text {
color: #020202;
font-size: 30rpx;
font-weight: 500;
}
.time {
margin-left: 20rpx;
color: #999999;
font-size: 22rpx;
}
}
.icon-back {
width: 11rpx;
height: 18rpx;
}
}
.middle {
margin: 30rpx 0 50rpx 0;
display: flex;
.cover {
width: 150rpx;
height: 150rpx;
border-radius: 9rpx;
}
.right-box {
margin-left: 20rpx;
flex-grow: 1;
.title-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #020202;
font-size: 30rpx;
}
.price {
color: #020202;
font-size: 26rpx;
}
}
.count-box {
margin-top: 15rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.color {
color: #666666;
font-size: 24rpx;
}
.count {
color: #AAAAAA;
font-size: 24rpx;
}
}
}
}
}
.bottom {
padding-top: 25rpx;
.price-box {
display: flex;
align-items: center;
align-content: center;
justify-content: flex-end;
.count {
color: #999999;
font-size: 22rpx;
}
.symbol {
color: #ff3c39;
font-size: 24rpx;
}
.all-price {
color: #ff3c39;
font-size: 32rpx;
}
}
.btn-box {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: flex-end;
.btn {
width: 180rpx;
height: 66rpx;
text-align: center;
line-height: 66rpx;
font-size: 26rpx;
font-weight: bold;
border-radius: 33rpx;
}
.btn-left {
color: #999999;
border: 1px solid #E8E8E8;
}
.btn-right1 {
margin-left: 10rpx;
color: #FFF;
background-color: #ff3c39;
}
.btn-right2 {
margin-left: 10rpx;
color: #ff3c39;
border: 1px solid #ff3c39;
}
}
}
}
}
}
/*订单详情*/
.cx-order-detail {
padding-bottom: 120rpx;
min-height: 100vh;
background-color: #F8F8F8;
.adress-info-box {
position: relative;
z-index: 1;
margin-top: -40rpx;
padding: 35rpx 35rpx 40rpx 30rpx;
border-radius: 30rpx 30rpx 0 0;
background-color: #FFF;
.express-box {
margin-bottom: 50rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.icon-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.icon {
width: 60rpx;
height: 60rpx;
}
.text-box {
margin-left: 25rpx;
.text {
margin-left: -17rpx;
color: #010101;
font-size: 30rpx;
}
.time {
margin-top: 20rpx;
color: #666666;
font-size: 22rpx;
}
}
}
.icon-back {
width: 15rpx;
height: 25rpx;
}
}
.info-box {
display: flex;
align-items: center;
align-content: center;
.icon-box {
.icon {
width: 60rpx;
height: 60rpx;
}
}
.right {
margin-left: 30rpx;
.text-box {
display: flex;
.text {
color: #010101;
font-size: 30rpx;
}
}
.adress {
margin-top: 20rpx;
width: 555rpx;
color: #666666;
font-size: 26rpx;
}
}
}
}
.option-box {
margin-top: 20rpx;
padding-bottom: 40rpx;
background-color: #FFF;
.options {
padding: 30rpx 30rpx 0;
display: flex;
&:not(:last-child) {
margin-bottom: 40rpx;
}
.cover-box {
position: relative;
overflow: hidden;
.cover {
width: 150rpx;
height: 150rpx;
border-radius: 9rpx;
}
.tips-text {
position: absolute;
top: calc((150rpx - 40rpx) / 2);
right: calc((150rpx - 90rpx) / 2);
// transform: rotate(45deg);
color: #ff3c39;
font-size: 30rpx;
font-weight: bold;
}
}
.right {
margin-left: 20rpx;
flex-grow: 1;
.title-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #020202;
font-size: 30rpx;
}
.price {
color: #020202;
font-size: 26rpx;
}
}
.count-box {
margin-top: 15rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.text {
color: #666666;
font-size: 24rpx;
}
}
}
.return {
margin-left: 20rpx;
width: 80rpx;
height: 180rpx;
color: #FFF;
text-align: center;
line-height: 180rpx;
font-size: 26rpx;
border-radius: 10rpx;
background-color: #ff3c39;
}
}
}
.order-info {
margin-top: 20rpx;
padding: 30rpx 30rpx 40rpx;
background-color: #FFF;
.title {
color: #020202;
font-size: 30rpx;
font-weight: 500;
}
.order-num {
margin-top: 35rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.text {
color: #020202;
font-size: 26rpx;
}
.right {
display: flex;
align-items: center;
align-content: center;
.num {
color: #020202;
font-size: 26rpx;
}
.btn-copy {
margin-left: 15rpx;
width: 60rpx;
height: 34rpx;
color: #ff3c39;
font-size: 20rpx;
font-weight: 500;
text-align: center;
line-height: 34rpx;
border-radius: 16rpx;
border: 1px solid #ff3c39;
}
}
}
.time-num {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.text {
color: #020202;
font-size: 26rpx;
}
.time {
color: #666666;
font-size: 26rpx;
}
}
}
.btn-box {
position: fixed;
bottom: 0;
left: 0;
padding: 16rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: flex-end;
width: 750rpx;
background-color: #FFF;
.btn {
width: 150rpx;
height: 66rpx;
text-align: center;
line-height: 66rpx;
font-size: 26rpx;
font-weight: bold;
border-radius: 33rpx;
}
.btn-left {
margin-right: 15rpx;
color: #999999;
border: 1px solid #E8E8E8;
}
.btn-right {
color: #ff3c39;
border: 1px solid #ff3c39;
}
}
}
/*订单签收信息*/
.cx-sign-for-detail {
padding-bottom: 30rpx;
min-height: 100vh;
background-color: #F8F8F8;
.order-info-box {
position: relative;
z-index: 1;
margin-top: -40rpx;
padding: 30rpx 30rpx 40rpx;
background-color: #FFF;
border-radius: 30rpx 30rpx 0 0;
.text-box {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
&:not(:last-child) {
margin-bottom: 25rpx;
}
.title {
color: #666666;
font-size: 26rpx;
}
.text {
color: #020202;
font-size: 26rpx;
}
}
.title-box {
margin-bottom: 25rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #666666;
font-size: 26rpx;
}
.num-box {
display: flex;
align-items: center;
align-content: center;
.num {
color: #020202;
font-size: 26rpx;
}
.btn {
margin-left: 10rpx;
width: 60rpx;
height: 34rpx;
color: #ff3c39;
font-size: 20rpx;
font-weight: 500;
text-align: center;
line-height: 34rpx;
border-radius: 16rpx;
border: 1px solid #ff3c39;
}
}
}
}
.list-box {
margin-top: 20rpx;
padding: 40rpx 35rpx 0 35rpx;
background-color: #FFF;
.list {
display: flex;
.left {
display: flex;
flex-wrap: wrap;
width: 84rpx;
&:not(:last-child) {
margin-bottom: 60rpx;
}
.date {
width: 100%;
color: #333333;
font-size: 24rpx;
}
.time {
margin-top: 10rpx;
width: 100%;
color: #999999;
font-size: 18rpx;
}
}
.middle {
.circular {
position: relative;
margin: 7rpx 31rpx 7rpx 19rpx;
width: 17rpx;
height: 17rpx;
border-radius: 50%;
background-color: #DDDDDD;
.border {
position: absolute;
width: 1rpx;
height: 105rpx;
background-color: #F0F0F0;
}
}
.is-now {
background-color: #0786E8;
}
.no-now {
background-color: #F0F0F0;
}
.icon-box {
position: relative;
margin: 0 12rpx 0 2rpx;
.border {
position: absolute;
width: 1rpx;
height: 85rpx;
background-color: #F0F0F0;
}
.icon {
width: 55rpx;
height: 55rpx;
}
}
.border-top {
bottom: -112rpx;
left: 9rpx;
}
.no-border-top {
bottom: -85rpx;
left: 26rpx;
}
}
.right {
.text {
color: #666666;
font-size: 22rpx;
}
.tips {
width: 538rpx;
color: #666666;
font-size: 20rpx;
}
}
}
}
}
/*邀请好友页面*/
.cx-invite-friend {
padding-top: 45rpx;
height: 100vh;
background-color: #1A1A1B;
.title {
color: #FFFFFF;
text-align: center;
font-size: 30rpx;
font-weight: 500;
}
.bottom-option {
position: fixed;
bottom: 35rpx;
left: 0;
padding: 0 215rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
width: 750rpx;
.options {
text-align: center;
.icon {
width: 88rpx;
height: 88rpx;
}
.text {
margin-top: 15rpx;
color: #FFFFFF;
font-size: 26rpx;
}
}
}
}
/*登录*/
.cx-login {
height: 100vh;
background-color: #FFF;
.top-box {
.view-bg {
position: relative;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
width: 100vw;
height: 470rpx;
background: url(https://huarenv1.oss-cn-beijing.aliyuncs.com/huaren_icon/zcbg.png) no-repeat;
background-size: 100% 100%;
.icon-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.logo-box {
.icon-logo {
width: 290rpx;
height: 150rpx;
}
}
}
.wx-login-box {
margin: 100rpx auto 0;
width: 100vw;
text-align: center;
.icon {
width: 150rpx;
height: 150rpx;
}
.button {
margin: 30rpx auto 0;
width: 420rpx;
height: 80rpx;
line-height: 80rpx;
color: #FFF;
font-size: 36rpx;
text-align: center;
border-radius: 15rpx;
// background-color: #ff3c39;
background-color: #E2007E;
outline: none;
}
}
}
.bottom-box {
position: fixed;
bottom: 20rpx;
padding: 20rpx 30rpx;
width: 100vw;
.wx-icon-box {
position: relative;
margin: 0 auto;
width: 60rpx;
text-align: center;
.icon {
width: 50rpx;
height: 50rpx;
}
.text {
margin-top: 15rpx;
color: #999999;
text-align: center;
font-size: 22rpx;
}
.button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
outline: none;
}
}
.text-box {
margin-top: 35rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.text {
color: #999999;
font-size: 20rpx;
}
.agreement {
color: #4072F1;
font-size: 20rpx;
}
}
.support {
margin-top: 10rpx;
text-align: center;
color: #999999;
font-size: 20rpx;
}
}
}
/*我的团队*/
.cx-my-team {
.top-box {
margin: 30rpx auto 0;
width: calc(100vw - 60rpx);
padding: 40rpx 0;
background-color: #FFF;
border-radius: 30rpx;
.title-text {
color: #202020;
font-size: 36rpx;
text-align: center;
}
.count {
margin-top: 20rpx;
color: #FD3C39;
font-size: 50rpx;
font-size: bold;
text-align: center;
}
.icon-box {
margin-top: 50rpx;
text-align: center;
.icon {
width: 240rpx;
height: 64rpx;
}
}
.date-box {
margin-top: 40rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
.icon {
width: 25rpx;
height: 35rpx;
}
.left {
transform: rotateY(180deg);
}
.date {
margin: 0 15rpx;
font-size: 40rpx;
}
}
.title {
margin-top: 10rpx;
color: #202020;
font-size: 32rpx;
text-align: center;
}
}
.tab-box {
margin: 30rpx auto 0;
padding: 20rpx 0 40rpx;
display: flex;
align-items: center;
align-content: center;
width: calc(100vw - 60rpx);
background-color: #ff3c39;
border-radius: 35rpx 35rpx 0 0;
.options {
flex: 1;
display: flex;
justify-content: center;
flex-direction: column;
.title {
color: #FFF;
font-size: 36rpx;
text-align: center;
}
.border {
margin: 10rpx auto 0;
width: 100rpx;
height: 10rpx;
border-radius: 10rpx;
}
.is-select {
font-weight: bold;
}
.is-ckeck {
background-color: #FFF;
}
.no-check {
background-color: #ff3c39;
}
}
}
.list-box {
margin: -8rpx auto 0;
padding: 40rpx 30rpx 30rpx;
width: calc(100vw - 60rpx);
background-color: #FFF;
.list {
.options {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
&:not(:last-child) {
margin-bottom: 50rpx;
}
.left {
display: flex;
align-items: center;
align-content: center;
.avatar-box {
margin-left: 20rpx;
display: flex;
flex-direction: column;
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
}
}
.level-box {
margin-left: 30rpx;
display: flex;
flex-direction: column;
.name {
color: #202020;
font-size: 30rpx;
font-weight: bold;
width: 300rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.icon-level {
margin-top: 20rpx;
width: 100rpx;
height: 30rpx;
}
}
}
.right {
color: #AAA;
font-size: 28rpx;
}
}
}
}
.black-bg {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
padding: 0 40rpx;
display: flex;
align-items: center;
align-content: center;
flex-direction: column;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, .5);
.block {
position: relative;
top: calc((100vh - 550rpx) / 2);
z-index: 9999;
.my-inviter-info {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
border-radius: 30rpx;
background-color: #FFF;
.avatar-box {
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
}
}
.right {
margin-left: 20rpx;
display: flex;
flex-direction: column;
.top {
display: flex;
align-items: center;
align-content: center;
.name {
color: #202020;
width: 230rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.icon-level {
width: 130rpx;
height: 40rpx;
}
}
.bottom {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.wechat {
color: #202020;
font-size: 30rpx;
}
.icon-copy {
width: 46rpx;
height: 46rpx;
}
}
}
}
.user-info {
padding: 0 20rpx 40rpx;
display: flex;
align-items: center;
align-content: center;
flex-direction: column;
width: calc(100vw - 80rpx);
border-radius: 35rpx;
background-color: #FFF;
.avatar-box {
margin: -80rpx auto 0;
text-align: center;
.avatar {
width: 160rpx;
height: 160rpx;
border: 1px solid #FFF;
border-radius: 50%;
}
}
.name {
margin-top: 20rpx;
color: #202020;
font-size: 30rpx;
font-weight: bold;
text-align: center;
}
.text {
margin-top: 60rpx;
text-align: center;
color: #AAA;
font-size: 28rpx;
}
.count {
margin-top: 20rpx;
color: #ff3c39;
font-size: 32rpx;
font-weight: bold;
}
.options-box {
margin-top: 50rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.options {
padding: 30rpx 20rpx;
display: flex;
flex-direction: column;
width: 305rpx;
background-color: #F1F1F1;
border-radius: 30rpx;
&:not(:last-child) {
margin-right: 20rpx;
}
.top {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.title {
color: #202020;
font-size: 30rpx;
}
.icon-copy {
width: 30rpx;
height: 30rpx;
}
}
.bottom {
margin-top: 20rpx;
color: #ff3c39;
font-size: 28rpx;
}
}
}
.date {
margin-top: 40rpx;
color: #202020;
font-size: 28rpx;
text-align: center;
}
}
.icon-close-box {
margin-top: 40rpx;
text-align: center;
.icon-close {
width: 80rpx;
height: 80rpx;
}
}
}
}
}
/*个人资料*/
.cx-set-unerInfo {
.info-box {
.options {
padding: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
&:not(:last-child) {
border-bottom: 1rpx solid #F8F8F8;
}
.title {
color: #202020;
font-size: 28rpx;
}
.right {
display: flex;
align-items: center;
align-content: center;
.avatar {
width: 70rpx;
height: 70rpx;
border-radius: 50%;
}
.text {
color: #AAAAAA;
font-size: 28rpx;
}
.icon {
margin-left: 20rpx;
width: 15rpx;
height: 25rpx;
}
}
}
}
.mark {
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
justify-content: flex-end;
width: 100%;
height: 100%;
.Box {
background: #ffffff;
// text-align: center;
.title {
margin: 20rpx;
text-align: center;
}
.input {
margin: auto;
padding: 0 10rpx;
border: 1rpx solid;
width: 95%;
height: 66rpx;
margin-bottom: 25rpx;
}
.btn-box {
width: 100%;
display: flex;
align-items: center;
border-top: 1rpx solid #f1efef;
.btn {
width: 50%;
height: 80rpx;
font-size: 28rpx;
text-align: center;
line-height: 80rpx;
}
.btn:nth-child(1) {
color: #999999;
border-right: 1rpx solid #f1efef;
}
.btn:nth-child(2) {
color: #ff3c39;
}
}
}
}
}
/*公共*/
image {
vertical-align: bottom;
}
.border-top {
border-top: 1px solid #E8E8E8;
}
.border-bottom {
border-bottom: 1px solid #E8E8E8;
}
.border-left {
border-left: 1px solid #E8E8E8;
}
.border-right {
border-right: 1px solid #E8E8E8;
}
/*iponeX适配*/
.cx-ipone-x {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
/*公共无数据提示*/
.empty-text {
padding: 30rpx;
color: #AAAAAA;
font-size: 26rpx;
text-align: center;
}
/*公共悬浮按钮*/
.public-float-button {
position: fixed;
bottom: 180rpx;
right: 40rpx;
border-radius: 50%;
box-shadow: 4rpx 7rpx 15rpx 5rpx rgba(0, 0, 0, 0.3);
.icon-box {
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #FFF;
}
.icon {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
}
}
/*公共全部数据提示*/
.total-text {
padding: 30rpx;
color: #AAAAAA;
font-size: 26rpx;
text-align: center;
}
/*公共透明遮罩*/
.public-opacity-0-bg {
position: fixed;
top: 0;
left: 0;
z-index: 999;
width: 100vw;
height: 100vh;
opacity: 0;
background-color: #FFF;
}
/*公共表格*/
.public-table-head {
margin-top: 10rpx;
padding: 20rpx 0;
background-color: #FFF;
.title {
font-size: 30rpx;
text-align: center;
}
.box {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
.options {
flex: 1;
color: #696969;
font-size: 24rpx;
text-align: center;
}
}
}
.public-table-body {
margin-top: 10rpx;
height: 400rpx;
overflow: auto;
.list {
padding: 20rpx 0;
display: flex;
align-items: center;
align-content: center;
&:nth-child(odd) {
background-color: #FFF;
}
&:nth-child(even) {
background-color: #F8F8F8;
}
.options {
flex: 1;
color: #696969;
font-size: 24rpx;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.tips-text {
padding: 20rpx 30rpx;
color: #B8B8B8;
font-size: 26rpx;
text-align: center;
background-color: #FFF;
}
}
/*公共底部悬浮按钮*/
.btn-botom-position {
position: fixed;
bottom: 40rpx;
left: 30rpx;
width: 690rpx;
height: 88rpx;
color: #FFF;
font-size: 30rpx;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
background-color: #ff3c39;
/*适配机型*/
bottom: calc(constant(safe-area-inset-bottom) + 40rpx);
/* 兼容 iOS < 11.2 */
bottom: calc(env(safe-area-inset-bottom) + 40rpx);
/* 兼容 iOS >= 11.2 */
}
/*公共上传样式*/
.public-upload-box {
margin-top: 20rpx;
padding: 30rpx 15rpx 30rpx 30rpx;
background-color: #FFF;
.title {
color: #020202;
font-size: 30rpx;
}
.add-box {
margin-top: 20rpx;
display: flex;
align-items: center;
align-content: center;
flex-wrap: wrap;
.img {
margin: 10rpx 15rpx 0 0;
width: 220rpx;
height: 220rpx;
border-radius: 10rpx;
}
.icon-add {
margin: 10rpx 15rpx 0 0;
width: 220rpx;
height: 220rpx;
}
}
.tips {
margin-top: 20rpx;
color: #AAAAAA;
font-size: 24rpx;
}
}
/*公共自定义导航栏头部*/
.public-top-boxs {
position: fixed;
left: 0;
z-index: 9999;
// padding-top: var(--status-bar-height);
padding-left: 30rpx;
padding-right: 30rpx;
width: calc(100vw - 60rpx);
height: 88rpx;
display: flex;
align-items: center;
align-content: center;
background-color: #ff3c39;
}
.public-top-box {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
padding-top: var(--status-bar-height);
padding-left: 30rpx;
padding-right: 30rpx;
width: calc(100vw - 60rpx);
height: 88rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.localtion-box {
display: flex;
align-items: center;
align-content: center;
.icon {
width: 40rpx;
height: 40rpx;
}
.text {
color: #333333;
font-size: 30rpx;
}
}
.search-box {
flex-grow: 1;
margin-left: 20rpx;
padding: 18rpx 26rpx;
display: flex;
align-items: center;
align-content: center;
border-radius: 30rpx;
background-color: rgba(233,231,231,0.75);
.icon {
width: 22rpx;
height: 23rpx;
}
// .input {
// flex-grow: 1;
// margin-left: 10rpx;
// font-size: 22rpx;
// }
.text {
margin-left: 10rpx;
color: #B4B4B4;
font-size: 22rpx;
}
}
.title {
color: #202020;
font-size: 34rpx;
}
.tips-box {
margin-left: 12rpx;
position: relative;
display: flex;
align-items: center;
align-content: center;
.icon {
width: 40rpx;
height: 40rpx;
}
.point {
position: absolute;
top: -5rpx;
right: 0;
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #f00;
}
}
.right-text {
color: #202020;
font-size: 26rpx;
}
}
/*公共顶部导航菜单*/
.public-option-box {
padding: 40rpx 40rpx 10rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
background-color: #FFF;
.options {
display: flex;
flex-wrap: wrap;
justify-content: center;
.title {
width: 100%;
text-align: center;
color: #020202;
font-size: 30rpx;
}
.border {
margin-top: 15rpx;
width: 28rpx;
height: 6rpx;
border-radius: 6rpx;
background-color: #ff3c39;
transition: all .3s;
}
.isSelected {
opacity: 1;
}
.noSelect {
opacity: 0;
}
}
}
/*公共头部订单信息*/
.public-top-info-box {
position: relative;
z-index: 0;
width: 750rpx;
height: 320rpx;
.icon-bg {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 750rpx;
height: 320rpx;
}
.icon-back {
margin-left: 28rpx;
width: 21rpx;
height: 37rpx;
}
.info-box {
margin-top: 40rpx;
padding: 0 75rpx 0 50rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.left {
.title {
color: #FFFFFF;
font-size: 34rpx;
font-weight: 500;
}
.tips {
margin-top: 15rpx;
color: #FFFFFF;
font-size: 24rpx;
}
}
.icon-right {
width: 95rpx;
height: 97rpx;
}
}
}
/*公共头部搜索盒子*/
.public-top-search-box {
padding: 15rpx 30rpx;
display: flex;
align-items: center;
align-content: center;
background-color: #FFF;
.icon-back {
width: 21rpx;
height: 37rpx;
}
.search-box {
flex-grow: 1;
margin-left: 30rpx;
padding: 19rpx 26rpx;
display: flex;
align-items: center;
align-content: center;
border-radius: 30rpx;
background-color: rgba(233,231,231,0.75);
.search-icon {
width: 25rpx;
height: 26rpx;
}
.input {
margin-left: 9rpx;
font-size: 22rpx;
}
}
}
/*公共商品列表*/
.public-goods-list {
background-color: #FFF;
.options {
padding: 0 30rpx 35rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
border-bottom: 1px solid #E8E8E8;
&:first-child {
padding-top: 30rpx;
}
&:not(:first-child) {
margin-top: 30rpx;
}
.img {
width: 150rpx;
height: 150rpx;
border-radius: 6rpx;
}
.right-box {
flex-grow: 1;
margin-left: 30rpx;
.title {
width: 100%;
color: #020202;
font-size: 30rpx;
font-weight: 500;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.price-time-box {
margin-top: 30rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.price-box {
.symbol {
color: #ff3c39;
font-size: 20rpx;
}
.price {
color: #ff3c39;
font-size: 28rpx;
font-weight: 500;
}
.original-price {
color: #B4B4B4;
font-size: 20rpx;
text-decoration: line-through;
}
}
.time-box {
padding: 5rpx 10rpx;
display: flex;
align-items: center;
align-content: center;
border-radius: 6rpx;
border: 1px solid #32D499;
.icon {
width: 25rpx;
height: 25rpx;
}
.time {
margin-left: 8rpx;
color: #32D499;
font-size: 20rpx;
}
}
}
.adress-box {
margin-top: 5rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.text {
color: #AAAAAA;
font-size: 24rpx;
}
.text {
}
}
}
}
}
/*公共商品大图列表*/
.public-goods-imgs-box {
padding-left: 30rpx;
display: flex;
flex-wrap: wrap;
.options {
margin: 20rpx 15rpx 20rpx 0;
padding-bottom: 25rpx;
border-radius: 10rpx;
overflow: hidden;
background-color: #FFF;
.img {
width: 338rpx;
height: 340rpx;
}
.title {
padding: 15rpx 0 0 15rpx;
width: 338rpx;
color: #2A2A2A;
font-size: 28rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.price-buy-box {
margin: 15rpx 15rpx 0 15rpx;
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
.price-box {
.symbol {
color: #ff3c39;
font-size: 24rpx;
}
.price {
color: #ff3c39;
font-size: 32rpx;
font-weight: 400;
}
}
.btn-buy {
padding: 10rpx 18rpx;
color: #FFF;
font-size: 20rpx;
border-radius: 25rpx;
background-color: #ff3c39;
}
}
}
}
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:24rpx;
$uni-font-size-base:28rpx;
$uni-font-size-lg:32rpx;
/* 图片尺寸 */
$uni-img-size-sm:40rpx;
$uni-img-size-base:52rpx;
$uni-img-size-lg:80rpx;
/* Border Radius */
$uni-border-radius-sm: 4rpx;
$uni-border-radius-base: 6rpx;
$uni-border-radius-lg: 12rpx;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 10px;
$uni-spacing-row-base: 20rpx;
$uni-spacing-row-lg: 30rpx;
/* 垂直间距 */
$uni-spacing-col-sm: 8rpx;
$uni-spacing-col-base: 16rpx;
$uni-spacing-col-lg: 24rpx;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:40rpx;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:36rpx;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:30rpx;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment