Browse Source

feat: page-partner+;

pull/2/head
Fox-33 2 weeks ago
parent
commit
32eaa4b119
23 changed files with 1639 additions and 11 deletions
  1. +1
    -0
      components/base/navbar.vue
  2. +455
    -0
      components/partner/posterPopup.vue
  3. +9
    -0
      pages.json
  4. +1
    -1
      pages/index/center.vue
  5. +1
    -1
      pages/index/index.vue
  6. +433
    -1
      pages/index/partner.vue
  7. +3
    -3
      pages_order/auth/wxUserInfo.vue
  8. +1
    -1
      pages_order/center/styles/card.scss
  9. +1
    -1
      pages_order/comment/commentWrite.vue
  10. +2
    -0
      pages_order/growing/activity/applyEmail.vue
  11. +1
    -0
      pages_order/growing/activity/markPopup.vue
  12. +4
    -3
      pages_order/order/orderList/index.vue
  13. +252
    -0
      pages_order/partner/apply.vue
  14. +242
    -0
      pages_order/partner/team.vue
  15. +233
    -0
      pages_order/partner/withdraw.vue
  16. BIN
      static/image/icon-checkmark-circle-fill.png
  17. BIN
      static/image/partner/apply.png
  18. BIN
      static/image/partner/icon-cash.png
  19. BIN
      static/image/partner/icon-nav.png
  20. BIN
      static/image/partner/icon-qrcode.png
  21. BIN
      static/image/partner/icon-team.png
  22. BIN
      static/image/temp-50.jpg
  23. BIN
      static/image/temp-51.png

+ 1
- 0
components/base/navbar.vue View File

@ -118,6 +118,7 @@
display: flex;
justify-content: center;
font-size: 32rpx;
font-weight: 500;
align-items: center;
z-index: 999;
.left{


+ 455
- 0
components/partner/posterPopup.vue View File

@ -0,0 +1,455 @@
<template>
<uv-popup
ref="popup"
:overlayOpacity="0.6"
mode="center"
bgColor="none"
:zIndex="1000000"
@change="onPopupChange"
>
<view class="popup__view">
<view class="canvas" style="width: 566rpx; height: 1060rpx; overflow: hidden;">
<canvas id="myCanvas" canvas-id="firstCanvas1" type="2d" style="width: 100%; height: 100%;"></canvas>
</view>
<button class="btn" @click="saveImg">
<view class="content">保存到相册</view>
</button>
</view>
</uv-popup>
</template>
<script>
export default {
data() {
return {
wxCodeImage: '',
baseUrl: 'https://image.hhlm1688.com/',
canvas: {},
retry: 10,
}
},
async onLoad() {
},
methods: {
open() {
this.retry = 10
this.$refs.popup.open();
},
close() {
this.$refs.popup.close();
},
async fetchQrCode(path) {
// todo: delete
this.wxCodeImage = 'https://uploadfile.bizhizu.cn/up/e3/64/e0/e364e0f7f6af11f11abdafc22d17b15c.jpg'
return
try {
this.wxCodeImage = (await this.$fetch('getInviteCode', { path }))?.url
} catch (err) {
}
},
//
drawBg(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
ctx.lineTo(width - radius + x, y);
ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
ctx.lineTo(width + x, height + y - radius);
ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2);
ctx.lineTo(radius + x, height + y);
ctx.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI);
ctx.closePath();
ctx.fillStyle = '#fff'
ctx.fill()
},
drawCoverImg(canvas, ctx, x, y, width, height, radius, lineWidth) {
return new Promise(resolve => {
//
const paperImage = canvas.createImage()
console.log('paperImage', paperImage)
// todo: fetch
paperImage.src = 'https://i1.hdslb.com/bfs/archive/c0101b4ce06e6bdda803728408e79c8f8b8d0725.jpg'
paperImage.onload = () => {
console.log('paperImage onload')
ctx.beginPath();
ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
ctx.lineTo(width - radius + x, y);
ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
ctx.lineTo(width + x, height + y);
ctx.lineTo(x, height + y);
ctx.closePath();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = '#F8F8F8';
ctx.stroke();
ctx.clip();
ctx.drawImage(paperImage, x, y, width, height)
resolve()
}
})
},
drawContentBg(ctx, x, y, width, height, radius) {
ctx.beginPath();
// ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
ctx.moveTo(x, y);
ctx.lineTo(width + x, y);
ctx.lineTo(width + x, height + y - radius);
ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2);
ctx.lineTo(radius + x, height + y);
ctx.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI);
ctx.closePath();
let gradient = ctx.createLinearGradient(x, y, x, y + height);
gradient.addColorStop('0', '#DAF3FF');
gradient.addColorStop('0.2', '#FBFEFF');
gradient.addColorStop('1.0', '#FBFEFF');
ctx.fillStyle = gradient
ctx.fill()
},
drawAvatar(canvas, ctx, x, y, r) {
console.log('drawAvatar', 'x', x, 'y', y, 'r', r)
return new Promise(resolve => {
//
const avatarImage = canvas.createImage()
// todo: fetch
avatarImage.src = 'https://i1.hdslb.com/bfs/archive/c0101b4ce06e6bdda803728408e79c8f8b8d0725.jpg'
avatarImage.onload = () => {
console.log('avatarImage onload')
ctx.beginPath();
console.log('arc', 'x', x + r, 'y', y + r, 'r', r)
ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
ctx.clip();
const size = r*2
console.log('size', size)
ctx.drawImage(avatarImage, x, y, size, size)
resolve()
}
})
},
drawMultilineText(ctx, text, x, y, maxWidth, lineHeight) {
console.log('drawMultilineText', 'x', x, 'y', y)
let line = '';
for (let n = 0; n < text.length; n++) {
const testLine = line + text[n];
const metrics = ctx.measureText(testLine);
const testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
ctx.fillText(line, x, y);
console.log(n, 'line', line, 'x', x, 'y', y)
line = text[n];
y += lineHeight;
} else {
line = testLine;
}
}
console.log('line', line, 'x', x, 'y', y)
ctx.fillText(line, x, y);
},
drawQrCodeImg(canvas, ctx, x, y, size) {
return new Promise(resolve => {
//
const coderImage = canvas.createImage()
coderImage.src = this.wxCodeImage
coderImage.onload = () => {
console.log('coderImage onload')
ctx.drawImage(coderImage, x, y, size, size)
resolve()
}
})
},
draw() {
wx.createSelectorQuery().in(this)
.select('#myCanvas') // canvasid
.fields({
node: true,
size: true
})
.exec(async (res) => {
console.log('res', res)
if (!res?.[0]?.node) {
if (!this.retry) {
console.log('retry fail')
return
}
console.log('retry')
this.retry -= 1
setTimeout(() => {
this.draw()
}, 200)
return
}
const canvas = res[0].node
//
const ctx = canvas.getContext('2d')
// Canvas
const width = res[0].width
const height = res[0].height
//
const dpr = wx.getWindowInfo().pixelRatio
//dpr
// dpr 2 4
// 3 6
console.log("--dpr", dpr)
canvas.width = width * dpr
canvas.height = height * dpr
let Ratio = canvas.width / 566
this.canvas = canvas
ctx.scale(dpr, dpr)
ctx.clearRect(0, 0, width, height)
ctx.fillStyle = 'transparent'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.save()
let radius = 48 * Ratio / dpr
let w = 566 * Ratio / dpr
let h = 1060 * Ratio / dpr
this.drawBg(ctx, 0, 0, w, h, radius)
ctx.restore();
ctx.save()
let lineWidth = 2 * Ratio / dpr
let x = lineWidth
let y = lineWidth
w = 566 * Ratio / dpr - lineWidth * 2
h = 400 * Ratio / dpr - lineWidth * 2
await this.drawCoverImg(canvas, ctx, x, y, w, h, radius, lineWidth)
ctx.restore();
ctx.save()
x = lineWidth
y = 400 * Ratio / dpr + lineWidth
h = 660 * Ratio / dpr - lineWidth * 2
this.drawContentBg(ctx, x, y, w, h, radius, lineWidth)
ctx.restore();
ctx.save()
radius = Math.floor(27 * Ratio / dpr)
x = Math.floor(40 * Ratio / dpr)
y = Math.floor(440 * Ratio / dpr)
await this.drawAvatar(canvas, ctx, x, y, radius)
ctx.restore();
ctx.save()
let text = '战斗世界'
let maxWidth = 220 * Ratio / dpr
let lineHeight = 17 * Ratio / dpr
x = 100 * Ratio / dpr
y = 474 * Ratio / dpr
ctx.font = "normal normal normal 11px normal";
ctx.fillStyle = "#7D7D7D";
this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
ctx.restore();
ctx.save()
maxWidth = 540 * Ratio / dpr
lineHeight = 60 * Ratio / dpr
ctx.font = "normal normal 600 17px normal";
ctx.fillStyle = "#181818";
text = '邀请您'
x = 40 * Ratio / dpr
y = 564 * Ratio / dpr
this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
y += lineHeight
text = '探索新世界,开启研学之旅!'
this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
ctx.restore();
ctx.save()
text = '是否渴望一场充满知识与乐趣的冒险?现在,我们诚挚邀请你加入我们的研学小程序,开启一场别开生面的学习之旅!'
maxWidth = 486 * Ratio / dpr
lineHeight = 30 * Ratio / dpr
ctx.font = "normal normal normal 10px normal";
ctx.fillStyle = "#7D7D7D";
x = 40 * Ratio / dpr
y = 690 * Ratio / dpr
this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
ctx.restore();
ctx.save()
// 线
ctx.setLineDash([4, 4]); // 线,
ctx.lineDashOffset = 2; // 线
ctx.lineWidth = lineWidth;
ctx.strokeStyle = '#DADADA';
//
ctx.beginPath();
x = 40 * Ratio / dpr
y = 778 * Ratio / dpr
ctx.moveTo(x, y);
x += 486 * Ratio / dpr
ctx.lineTo(x, y);
ctx.stroke();
ctx.restore();
ctx.save()
maxWidth = 250 * Ratio / dpr
lineHeight = 44 * Ratio / dpr
ctx.font = "normal normal 600 13px normal";
ctx.fillStyle = "#181818";
text = '立即加入我们,'
x = 40 * Ratio / dpr
y = 879 * Ratio / dpr
this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
text = '开启你的研学之旅!'
y += lineHeight
this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
ctx.restore();
ctx.save()
x = 316 * Ratio / dpr
y = 810 * Ratio / dpr
let size = 210 * Ratio / dpr
await this.drawQrCodeImg(canvas, ctx, x, y, size)
uni.hideLoading()
return
//
const paperImage = canvas.createImage()
console.log('paperImage', paperImage)
// todo: fetch
paperImage.src = 'https://i1.hdslb.com/bfs/archive/c0101b4ce06e6bdda803728408e79c8f8b8d0725.jpg'
paperImage.onload = () => {
console.log('paperImage onload')
const w = 566 * Ratio / dpr
const h = 400 * Ratio / dpr
ctx.drawImage(paperImage, 0, 0, w, h)
//
const coderImage = canvas.createImage()
coderImage.src = this.wxCodeImage
coderImage.onload = () => {
console.log('coderImage onload')
const x = 316 * Ratio / dpr
const y = 910 * Ratio / dpr
const size = 210 * Ratio / dpr
ctx.drawImage(coderImage, x, y, size, size)
uni.hideLoading()
}
}
})
},
async init() {
uni.showLoading({
title: '加载中...'
});
await this.fetchQrCode()
uni.hideLoading();
uni.showLoading({
title: "拼命绘画中..."
})
this.draw()
},
saveImg() {
this.$authorize('scope.writePhotosAlbum').then((res) => {
this.imgApi()
})
},
imgApi() {
uni.showLoading({
title: '保存中...'
});
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: this.canvas.width,
height: this.canvas.height,
canvas: this.canvas,
success: (res) => {
let tempFilePath = res.tempFilePath;
this.saveImgToPhone(tempFilePath)
},
fail: (err) => {
console.log('--canvasToTempFilePath--fail', err)
uni.hideLoading();
}
}, this);
},
saveImgToPhone(image) {
/* 获取图片的信息 */
uni.getImageInfo({
src: image,
success: function(image) {
/* 保存图片到手机相册 */
uni.saveImageToPhotosAlbum({
filePath: image.path,
success: function() {
uni.showModal({
title: '保存成功',
content: '图片已成功保存到相册',
showCancel: false
});
},
complete(res) {
console.log(res);
uni.hideLoading();
}
});
}
});
},
onPopupChange(e) {
if (!e.show) {
return
}
this.init()
},
},
}
</script>
<style scoped lang="scss">
.canvas {
border-radius: 48rpx;
}
.btn {
margin-top: 32rpx;
width: 100%;
padding: 22rpx 0;
box-sizing: border-box;
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1;
color: #FFFFFF;
background: linear-gradient(to right, #21FEEC, #019AF9);
border: 2rpx solid #00A9FF;
border-radius: 41rpx;
}
</style>

+ 9
- 0
pages.json View File

@ -99,6 +99,15 @@
},
{
"path": "member/switch"
},
{
"path": "partner/apply"
},
{
"path": "partner/team"
},
{
"path": "partner/withdraw"
}
]
}],


+ 1
- 1
pages/index/center.vue View File

@ -278,7 +278,7 @@
.card {
margin-top: 32rpx;
width: 100%;
background: #FAFAFF;
background: #FFFFFF;
border: 2rpx solid #FFFFFF;
border-radius: 32rpx;
box-sizing: border-box;


+ 1
- 1
pages/index/index.vue View File

@ -93,7 +93,7 @@
}
},
onLoad() {
this.$utils.navigateTo(`/pages_order/growing/activity/applyEmail`)
// this.$utils.navigateTo(`/pages_order/growing/activity/applyEmail`)
// uni.navigateTo({
// url: `/pages_order/order/orderConfirm/index`
// })


+ 433
- 1
pages/index/partner.vue View File

@ -1,21 +1,453 @@
<template>
<view class="page__view">
<navbar>
<image class="icon-nav" src="@/static/image/partner/icon-nav.png" mode="widthFix"></image>
</navbar>
<view class="main">
<view class="advantage">
<view class="flex advantage-content">
<view class="flex advantage-item" v-for="(item, aIdx) in advantages" :key="aIdx">
<image class="icon" src="@/static/image/icon-checkmark-circle-fill.png" mode="widthFix"></image>
<view>{{ item }}</view>
</view>
</view>
</view>
<view class="card">
<view class="flex user">
<view class="avatar">
<image class="img" src="@/static/image/temp-30.png" mode="scaleToFill"></image>
<view :class="['tag', `tag-1`]">家长</view>
</view>
<view class="flex summary">
<view class="flex flex-column summary-item name">
<view class="summary-item-content">战斗世界</view>
<view class="summary-item-label">ID5625354</view>
</view>
<template v-if="isPartner">
<view class="flex flex-column summary-item" @click="jumpToAchievement">
<view class="summary-item-content">888</view>
<view class="summary-item-label">推广人数</view>
</view>
<view class="flex flex-column summary-item">
<view class="summary-item-content">341</view>
<view class="summary-item-label">总佣金</view>
</view>
</template>
<template v-else>
<view class="flex summary-item operate">
<button class="btn" @click="onApplyPartner">成为合伙人</button>
</view>
</template>
</view>
</view>
<view class="flex bar" v-if="isPartner">
<button class="flex col btn" @click="jumpToTeam">
<image class="icon" src="@/static/image/partner/icon-team.png" mode="widthFix"></image>
<view>我的团队</view>
</button>
<view class="flex divider">
<view class="line"></view>
</view>
<button class="flex col btn" @click="openPosterPopup">
<image class="icon" src="@/static/image/partner/icon-qrcode.png" mode="widthFix"></image>
<view>邀请二维码</view>
</button>
<view class="flex divider">
<view class="line"></view>
</view>
<button class="flex col btn" @click="jumpToWithdraw">
<image class="icon" src="@/static/image/partner/icon-cash.png" mode="widthFix"></image>
<view>提现</view>
</button>
</view>
<!-- todo: check -->
<button class="btn-apply" @click="onApplyPartner">
<image class="bg" src="@/static/image/partner/apply.png" mode="widthFix"></image>
</button>
<view class="list" v-if="isPartner && list.length">
<view class="flex list-item" v-for="item in list" :key="item.id">
<view class="flex col info">
<view class="avatar">
<image class="img" :src="item.avatar" mode="scaleToFill"></image>
</view>
<view>{{ item.name }}</view>
</view>
<view class="col price">{{ `${item.price}` }}</view>
<view class="col desc">{{ item.createTime }}</view>
</view>
</view>
</view>
</view>
<posterPopup ref="posterPopup"></posterPopup>
<tabber select="partner" />
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
import tabber from '@/components/base/tabbar.vue'
import posterPopup from '@/components/partner/posterPopup.vue'
export default {
mixins: [mixinsList],
components: {
tabber,
posterPopup,
},
data() {
return {
advantages: ['收益高', '品类全', '到账快', '城市多'],
// todo: fetch
isPartner: true,
// todo
mixinsListApi: '',
}
},
onShow() {
// todo: refresh is partner?
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
avatar: '/static/image/temp-30.png',
name: '李世海',
price: 10,
createTime: '2025-07-15',
},
{
id: '002',
avatar: '/static/image/temp-30.png',
name: '周静',
price: 10,
createTime: '2025-07-15',
},
{
id: '003',
avatar: '/static/image/temp-30.png',
name: '周海',
price: 10,
createTime: '2025-07-15',
},
{
id: '004',
avatar: '/static/image/temp-30.png',
name: '冯启彬',
price: 10,
createTime: '2025-07-15',
},
{
id: '005',
avatar: '/static/image/temp-30.png',
name: '李娉',
price: 10,
createTime: '2025-07-15',
},
{
id: '006',
avatar: '/static/image/temp-30.png',
name: '李书萍',
price: 10,
createTime: '2025-07-15',
},
{
id: '007',
avatar: '/static/image/temp-30.png',
name: '李世海',
price: 10,
createTime: '2025-07-15',
},
{
id: '008',
avatar: '/static/image/temp-30.png',
name: '周静',
price: 10,
createTime: '2025-07-15',
},
{
id: '009',
avatar: '/static/image/temp-30.png',
name: '周海',
price: 10,
createTime: '2025-07-15',
},
{
id: '010',
avatar: '/static/image/temp-30.png',
name: '冯启彬',
price: 10,
createTime: '2025-07-15',
},
{
id: '011',
avatar: '/static/image/temp-30.png',
name: '李娉',
price: 10,
createTime: '2025-07-15',
},
{
id: '012',
avatar: '/static/image/temp-30.png',
name: '李书萍',
price: 10,
createTime: '2025-07-15',
},
]
},
onApplyPartner() {
this.$utils.navigateTo(`/pages_order/partner/apply`)
},
jumpToTeam() {
this.$utils.navigateTo(`/pages_order/partner/team`)
},
openPosterPopup() {
this.$refs.posterPopup.open()
},
jumpToWithdraw() {
this.$utils.navigateTo(`/pages_order/partner/withdraw`)
},
},
}
</script>
<style scoped lang="scss">
@import '/components/member/styles/tag.scss';
@import '../../components/member/styles/tag.scss';
.page__view {
min-height: 100vh;
background: linear-gradient(to right, #21FEEC, #019AF9);
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
.icon-nav {
width: 168rpx;
height: auto;
}
/deep/ .tabbar-box {
height: auto;
padding-bottom: 0;
}
}
.main {
// min-height: 100vh;
// padding: calc(var(--status-bar-height) + 130rpx) 0 calc(120rpx + env(safe-area-inset-bottom)) 0;
padding-top: calc(var(--status-bar-height) + 130rpx);
box-sizing: border-box;
}
.advantage {
padding: 0 40rpx 32rpx 40rpx;
&-content {
justify-content: space-between;
padding: 16rpx;
background: #1FB2FD99;
border: 2rpx solid #FFFFFF4D;
border-radius: 16rpx;
}
&-item {
column-gap: 8rpx;
padding-right: 16rpx;
font-size: 26rpx;
color: #FFFFFF;
.icon {
width: 40rpx;
height: auto;
}
}
}
.card {
width: 100%;
// height: 100%;
$advantage-height: 54px;
// min-height: calc(100vh - #{$advantage-height} - (var(--status-bar-height) + 130rpx) - (120rpx + env(safe-area-inset-bottom)));
min-height: calc(100vh - #{$advantage-height} - (var(--status-bar-height) + 130rpx));
padding: 40rpx;
padding-bottom: calc(40rpx + 120rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.4;
background: linear-gradient(#DAF3FF, #FBFEFF 400rpx, #FBFEFF);
border: 2rpx solid #FFFFFF;
border-top-left-radius: 48rpx;
border-top-right-radius: 48rpx;
}
.user {
justify-content: space-between;
padding: 32rpx 40rpx;
background: linear-gradient(#DAF3FF, #FBFEFF 70%, #FBFEFF);
border: 2rpx solid #FFFFFF;
border-radius: 48rpx;
column-gap: 24rpx;
.avatar {
flex: none;
position: relative;
width: 128rpx;
height: 128rpx;
border-radius: 24rpx;
overflow: hidden;
.img {
width: 100%;
height: 100%;
}
}
.summary {
flex: 1;
column-gap: 26rpx;
&-item {
flex: 1;
row-gap: 8rpx;
&.name {
flex: none;
align-items: flex-start;
}
&.operate {
justify-content: flex-end;
}
&-content {
font-size: 32rpx;
font-weight: 600;
color: #000000;
}
&-label {
font-size: 24rpx;
color: #939393;
}
}
}
.btn {
padding: 8rpx 24rpx;
font-size: 28rpx;
font-weight: 500;
line-height: 1.4;
color: #FFFFFF;
background: linear-gradient(to right, #21FEEC, #019AF9);
border-radius: 28rpx;
}
}
.btn-apply {
margin-top: 32rpx;
width: 100%;
height: auto;
padding: 0;
background: none;
font-size: 0;
.bg {
width: 100%;
height: auto;
}
}
.bar {
margin-top: 24rpx;
flex-wrap: nowrap;
padding: 16rpx 24rpx;
.col {
flex: none;
}
.divider {
flex: 1;
.line {
width: 2rpx;
height: 44rpx;
background: #00A9FF;
}
}
.btn {
column-gap: 8rpx;
font-size: 24rpx;
color: #181818;
.icon {
width: 64rpx;
height: auto;
}
}
}
.list {
margin-top: 32rpx;
background: #FFFFFF;
border: 2rpx solid #F0F0F0;
border-radius: 24rpx;
overflow: hidden;
&-item {
margin-top: 16rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
color: #333333;
background: #FFFFFF;
border-bottom: 2rpx solid #F1F1F1;
&:last-child {
border: none;
}
.col {
flex: 1;
text-align: center;
}
.info {
justify-content: flex-start;
column-gap: 24rpx;
.avatar {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
overflow: hidden;
.img {
width: 100%;
height: 100%;
}
}
}
.desc {
font-size: 26rpx;
color: #A3A3A3;
}
}
}
</style>

+ 3
- 3
pages_order/auth/wxUserInfo.vue View File

@ -202,7 +202,7 @@
.page__view {
width: 100vw;
min-height: 100vh;
background-color: $uni-bg-color;
background: unset;
position: relative;
/deep/ .nav-bar__view {
@ -218,7 +218,7 @@
.card {
padding: 32rpx;
background: #FAFAFF;
background: #FFFFFF;
border: 2rpx solid #FFFFFF;
border-radius: 32rpx;
@ -374,7 +374,7 @@
font-size: 36rpx;
line-height: 1;
color: #FFFFFF;
background-image: linear-gradient(to right, #21FEEC #019AF9);
background: linear-gradient(to right, #21FEEC, #019AF9);
border: 2rpx solid #00A9FF;
border-radius: 41rpx;
}


+ 1
- 1
pages_order/center/styles/card.scss View File

@ -2,7 +2,7 @@
.card {
margin-top: 32rpx;
width: 100%;
background: #FAFAFF;
background: #FFFFFF;
border: 2rpx solid #FFFFFF;
border-radius: 32rpx;
box-sizing: border-box;


+ 1
- 1
pages_order/comment/commentWrite.vue View File

@ -188,7 +188,7 @@
.card {
padding: 32rpx;
background: #FAFAFF;
background: #FFFFFF;
border: 2rpx solid #FFFFFF;
border-radius: 32rpx;


+ 2
- 0
pages_order/growing/activity/applyEmail.vue View File

@ -91,6 +91,7 @@
message: '请输入邮寄地址',
},
},
formItemStyle: { padding: 0 },
}
},
onLoad(arg) {
@ -174,6 +175,7 @@
color: #191919;
}
}
.form {
&-item {
margin-top: 32rpx;


+ 1
- 0
pages_order/growing/activity/markPopup.vue View File

@ -58,6 +58,7 @@
message: '请上传图片',
},
},
formItemStyle: { padding: 0 },
}
},
methods: {


+ 4
- 3
pages_order/order/orderList/index.vue View File

@ -11,7 +11,7 @@
:list="tabs"
:current="current"
:scrollable="false"
lineColor="#7451DE"
lineColor="#00A9FF"
lineWidth="48rpx"
lineHeight="4rpx"
:activeStyle="{
@ -19,7 +19,7 @@
'font-weight': 500,
'font-size': '32rpx',
'line-height': 1.4,
'color': '#7451DE',
'color': '#00A9FF',
}"
:inactiveStyle="{
'font-family': 'PingFang SC',
@ -71,7 +71,8 @@
{ name: '待收货' },
{ name: '待评价' },
],
mixinsListApi: 'getOrderList',
// todo
mixinsListApi: '',
current: 0,
}
},


+ 252
- 0
pages_order/partner/apply.vue View File

@ -0,0 +1,252 @@
<template>
<view class="page__view">
<navbar leftClick @leftClick="$utils.navigateBack">
<image class="icon-nav" src="@/static/image/partner/icon-nav.png" mode="widthFix"></image>
</navbar>
<view class="main">
<view class="advantage">
<view class="flex advantage-content">
<view class="flex advantage-item" v-for="(item, aIdx) in advantages" :key="aIdx">
<image class="icon" src="@/static/image/icon-checkmark-circle-fill.png" mode="widthFix"></image>
<view>{{ item }}</view>
</view>
</view>
</view>
<view class="card">
<view class="card-header">申请合伙人</view>
<view class="form">
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="name" :customStyle="formItemStyle">
<view class="form-item-label">
<image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
姓名
</view>
<view class="form-item-content">
<formInput v-model="form.name"></formInput>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="phone" :customStyle="formItemStyle">
<view class="form-item-label">
<image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
电话
</view>
<view class="form-item-content">
<formInput v-model="form.phone"></formInput>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="recommend" :customStyle="formItemStyle">
<view class="form-item-label">推荐人</view>
<view class="form-item-content">
<formInput v-model="form.recommend"></formInput>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
</view>
</view>
<view class="bottom">
<view class="flex btn" @click="onSubmit">提交</view>
</view>
</view>
</template>
<script>
import formInput from '@/pages_order/components/formInput.vue'
export default {
components: {
formInput,
},
data() {
return {
advantages: ['收益高', '品类全', '到账快', '城市多'],
form: {
name: null,
phone: null,
recommend: null,
},
rules: {
'name': {
type: 'string',
required: true,
message: '请输入姓名',
},
'phone': {
type: 'string',
required: true,
message: '请输入电话',
},
},
formItemStyle: { padding: 0 },
}
},
methods: {
async onSubmit() {
try {
await this.$refs.form.validate()
const {
} = this.form
const params = {
}
// todo: fetch
// await this.$fetch('updateAddress', params)
uni.showToast({
icon: 'success',
title: '提交成功',
});
setTimeout(() => {
this.$utils.navigateBack()
}, 800)
} catch (err) {
console.log('onSave err', err)
}
},
},
}
</script>
<style scoped lang="scss">
.page__view {
min-height: 100vh;
background: linear-gradient(to right, #21FEEC, #019AF9);
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
.icon-nav {
width: 168rpx;
height: auto;
}
}
.main {
// min-height: 100vh;
// padding: calc(var(--status-bar-height) + 130rpx) 0 calc(120rpx + env(safe-area-inset-bottom)) 0;
padding-top: calc(var(--status-bar-height) + 130rpx);
box-sizing: border-box;
}
.advantage {
padding: 0 40rpx 32rpx 40rpx;
&-content {
justify-content: space-between;
padding: 16rpx;
background: #1FB2FD99;
border: 2rpx solid #FFFFFF4D;
border-radius: 16rpx;
}
&-item {
column-gap: 8rpx;
padding-right: 16rpx;
font-size: 26rpx;
color: #FFFFFF;
.icon {
width: 40rpx;
height: auto;
}
}
}
.card {
width: 100%;
// height: 100%;
$advantage-height: 54px;
// min-height: calc(100vh - #{$advantage-height} - (var(--status-bar-height) + 130rpx) - (120rpx + env(safe-area-inset-bottom)));
min-height: calc(100vh - #{$advantage-height} - (var(--status-bar-height) + 130rpx));
padding: 40rpx;
box-sizing: border-box;
font-family: PingFang SC;
font-weight: 400;
line-height: 1.4;
background: linear-gradient(#DAF3FF, #FBFEFF 400rpx, #FBFEFF);
border: 2rpx solid #FFFFFF;
border-top-left-radius: 48rpx;
border-top-right-radius: 48rpx;
&-header {
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1.4;
color: #191919;
}
}
.form {
&-item {
margin-top: 32rpx;
border-bottom: 2rpx solid #EEEEEE;
&-label {
font-family: PingFang SC;
font-weight: 400;
font-size: 26rpx;
line-height: 1.4;
color: #181818;
.icon {
margin-right: 8rpx;
width: 16rpx;
height: auto;
}
}
&-content {
}
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100vw;
background: #FFFFFF;
box-sizing: border-box;
padding: 32rpx 40rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 32rpx);
box-sizing: border-box;
.btn {
width: 100%;
padding: 14rpx 0;
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1;
color: #FFFFFF;
background: linear-gradient(to right, #21FEEC, #019AF9);
border: 2rpx solid #00A9FF;
border-radius: 41rpx;
}
}
</style>

+ 242
- 0
pages_order/partner/team.vue View File

@ -0,0 +1,242 @@
<template>
<view class="page__view">
<navbar title="我的团队" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" />
<view class="main">
<view class="tabs">
<uv-tabs
:list="tabs"
:current="current"
:scrollable="false"
lineColor="#00A9FF"
lineWidth="48rpx"
lineHeight="4rpx"
:activeStyle="{
'font-family': 'PingFang SC',
'font-weight': 500,
'font-size': '32rpx',
'line-height': 1.4,
'color': '#00A9FF',
}"
:inactiveStyle="{
'font-family': 'PingFang SC',
'font-weight': 400,
'font-size': '32rpx',
'line-height': 1.4,
'color': '#181818',
}"
@click="clickTabs"
></uv-tabs>
</view>
<view class="list">
<view class="flex list-item" v-for="item in list" :key="item.id">
<view class="avatar">
<image class="img" :src="item.avatar" mode="scaleToFill"></image>
</view>
<view>{{ item.name }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
export default {
mixins: [mixinsList],
data() {
return {
tabs: [
{ name: '直推用户列表' },
{ name: '间推用户列表' },
],
mixinsListApi: '',
current: 0,
}
},
onShow() {
console.log('onShow')
},
onLoad(arg) {
this.clickTabs({ index: arg.index || 0 })
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
avatar: '/static/image/temp-30.png',
name: '李世海',
price: 10,
createTime: '2025-07-15',
},
{
id: '002',
avatar: '/static/image/temp-30.png',
name: '周静',
price: 10,
createTime: '2025-07-15',
},
{
id: '003',
avatar: '/static/image/temp-30.png',
name: '周海',
price: 10,
createTime: '2025-07-15',
},
{
id: '004',
avatar: '/static/image/temp-30.png',
name: '冯启彬',
price: 10,
createTime: '2025-07-15',
},
{
id: '005',
avatar: '/static/image/temp-30.png',
name: '李娉',
price: 10,
createTime: '2025-07-15',
},
{
id: '006',
avatar: '/static/image/temp-30.png',
name: '李书萍',
price: 10,
createTime: '2025-07-15',
},
{
id: '007',
avatar: '/static/image/temp-30.png',
name: '李世海',
price: 10,
createTime: '2025-07-15',
},
{
id: '008',
avatar: '/static/image/temp-30.png',
name: '周静',
price: 10,
createTime: '2025-07-15',
},
{
id: '009',
avatar: '/static/image/temp-30.png',
name: '周海',
price: 10,
createTime: '2025-07-15',
},
{
id: '010',
avatar: '/static/image/temp-30.png',
name: '冯启彬',
price: 10,
createTime: '2025-07-15',
},
{
id: '011',
avatar: '/static/image/temp-30.png',
name: '李娉',
price: 10,
createTime: '2025-07-15',
},
{
id: '012',
avatar: '/static/image/temp-30.png',
name: '李书萍',
price: 10,
createTime: '2025-07-15',
},
]
},
//tab
clickTabs({ index }) {
console.log('clickTabs')
this.current = index
if (index == 0) {
delete this.queryParams.status
} else {
this.queryParams.status = index - 1
}
this.getData()
},
},
}
</script>
<style scoped lang="scss">
.page__view {
width: 100vw;
min-height: 100vh;
background-color: $uni-bg-color;
position: relative;
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
}
.main {
padding: calc(var(--status-bar-height) + 244rpx) 32rpx 40rpx 32rpx;
.tabs {
position: fixed;
top: calc(var(--status-bar-height) + 120rpx);
left: 0;
width: 100%;
height: 84rpx;
background: #FFFFFF;
z-index: 1;
/deep/ .uv-tabs__wrapper__nav__line {
border-radius: 2rpx;
}
}
}
.list {
background: #FFFFFF;
border-radius: 32rpx;
overflow: hidden;
&-item {
margin-top: 16rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
color: #333333;
background: #FFFFFF;
border-bottom: 2rpx solid #F1F1F1;
justify-content: flex-start;
column-gap: 24rpx;
&:last-child {
border: none;
}
.avatar {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
overflow: hidden;
.img {
width: 100%;
height: 100%;
}
}
}
}
</style>

+ 233
- 0
pages_order/partner/withdraw.vue View File

@ -0,0 +1,233 @@
<template>
<view class="page__view">
<navbar title="提现" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" />
<view class="main">
<view class="card">
<view class="card-header">微信提现</view>
<view class="form">
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="name" :customStyle="formItemStyle">
<view class="form-item-label">真实姓名</view>
<view class="form-item-content">
<formInput v-model="form.name"></formInput>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="amount" :customStyle="formItemStyle">
<view class="form-item-label">提现金额</view>
<view class="form-item-content">
<formInput v-model="form.amount"></formInput>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
</view>
<view class="notice">
请仔细检查并确认相关信息因用户个人疏忽导致的充值错误需由用户自行承担
<!-- todo: 替换配置项key -->
<text class="highlight" @click="$refs.modal.open('user_ys', '提现须知')">提现须知</text>
</view>
<agreementModal ref="modal"></agreementModal>
</view>
<view class="bottom">
<button class="btn" @click="onSubmit">提现</button>
</view>
</view>
</template>
<script>
import formInput from '@/pages_order/components/formInput.vue'
import agreementModal from '@/pages_order/components/agreementModal.vue'
export default {
components: {
formInput,
agreementModal,
},
data() {
return {
form: {
name: null,
amount: null,
},
rules: {
'name': {
type: 'string',
required: true,
message: '请输入真实姓名',
},
'amount': {
type: 'string',
required: true,
message: '请输入提现金额',
},
},
formItemStyle: { padding: 0 },
}
},
methods: {
async onSubmit() {
try {
await this.$refs.form.validate()
const {
} = this.form
const params = {
}
// todo: fetch
// await this.$fetch('updateAddress', params)
uni.showToast({
icon: 'success',
title: '提交成功',
});
setTimeout(() => {
this.$utils.navigateBack()
}, 800)
} catch (err) {
console.log('onSave err', err)
}
},
},
}
</script>
<style lang="scss" scoped>
.page__view {
width: 100vw;
min-height: 100vh;
background: unset;
position: relative;
/deep/ .nav-bar__view {
position: fixed;
top: 0;
left: 0;
}
}
.main {
padding: calc(var(--status-bar-height) + 144rpx) 32rpx 224rpx 32rpx;
}
.card {
padding: 32rpx;
background: #FFFFFF;
border: 2rpx solid #FFFFFF;
border-radius: 32rpx;
& + & {
margin-top: 40rpx;
}
&-header {
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1.4;
color: #252545;
margin-bottom: 32rpx;
}
}
.form {
padding: 8rpx 0 0 0;
&-item {
border-bottom: 2rpx solid #EEEEEE;
&:last-child {
border: none;
}
& + & {
margin-top: 40rpx;
}
&-label {
font-family: PingFang SC;
font-weight: 400;
font-size: 26rpx;
line-height: 1.4;
color: #181818;
}
&-content {
margin-top: 14rpx;
padding: 6rpx 0;
.text {
padding: 2rpx 0;
font-family: PingFang SC;
font-weight: 400;
font-size: 32rpx;
line-height: 1.4;
&.placeholder {
color: #C6C6C6;
}
}
}
}
}
.notice {
margin-top: 40rpx;
font-size: 24rpx;
line-height: 1.4;
color: #BABABA;
.highlight {
color: #F79400;
}
}
.bottom {
position: fixed;
left: 0;
bottom: 0;
width: 100vw;
// height: 200rpx;
padding: 24rpx 40rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 24rpx);
background: #FFFFFF;
box-sizing: border-box;
.btn {
width: 100%;
padding: 14rpx 0;
box-sizing: border-box;
font-family: PingFang SC;
font-weight: 500;
font-size: 36rpx;
line-height: 1;
color: #FFFFFF;
background: linear-gradient(to right, #21FEEC, #019AF9);
border: 2rpx solid #00A9FF;
border-radius: 41rpx;
}
}
</style>

BIN
static/image/icon-checkmark-circle-fill.png View File

Before After
Width: 60  |  Height: 60  |  Size: 1.1 KiB

BIN
static/image/partner/apply.png View File

Before After
Width: 1005  |  Height: 288  |  Size: 256 KiB

BIN
static/image/partner/icon-cash.png View File

Before After
Width: 128  |  Height: 128  |  Size: 1.1 KiB

BIN
static/image/partner/icon-nav.png View File

Before After
Width: 241  |  Height: 80  |  Size: 7.0 KiB

BIN
static/image/partner/icon-qrcode.png View File

Before After
Width: 129  |  Height: 128  |  Size: 1.0 KiB

BIN
static/image/partner/icon-team.png View File

Before After
Width: 128  |  Height: 128  |  Size: 1.9 KiB

BIN
static/image/temp-50.jpg View File

Before After
Width: 4428  |  Height: 3200  |  Size: 2.1 MiB

BIN
static/image/temp-51.png View File

Before After
Width: 105  |  Height: 106  |  Size: 11 KiB

Loading…
Cancel
Save