Browse Source

feat(workbenchManage): 新增分享海报功能并优化绑定用户页面

- 在`bindUser`页面中新增分享海报功能,用户可保存海报到相册
- 优化绑定用户页面样式,添加背景图片和点击事件
- 新增`configPopup`组件用于展示配置信息
- 调整`myLevel`页面组件,添加`dataInfo`属性传递数据
master
前端-胡立永 3 months ago
parent
commit
30594d99a8
11 changed files with 669 additions and 109 deletions
  1. +55
    -0
      components/configPopup.vue
  2. +5
    -1
      otherPages/workbenchManage/bindUser/index.scss
  3. +64
    -16
      otherPages/workbenchManage/bindUser/index.vue
  4. +193
    -0
      otherPages/workbenchManage/bindUser/sharing - 副本.vue
  5. +209
    -0
      otherPages/workbenchManage/bindUser/sharing.vue
  6. +11
    -0
      otherPages/workbenchManage/myLevel/commponents/levelInfo.vue
  7. +42
    -27
      otherPages/workbenchManage/myLevel/commponents/myData.vue
  8. +2
    -2
      otherPages/workbenchManage/myLevel/index.vue
  9. +9
    -4
      otherPages/workbenchManage/myUser/index.vue
  10. +8
    -1
      pages.json
  11. +71
    -58
      store/modules/system.js

+ 55
- 0
components/configPopup.vue View File

@ -0,0 +1,55 @@
<template>
<view class="configPopup">
<up-popup :show="showConfirmOrder" mode="bottom" @close="close" :round="10" :closeable="true"
:safeAreaInsetBottom="false">
<view class="content">
<up-parse :content="content"></up-parse>
</view>
</up-popup>
</view>
</template>
<script>
import { mapState, mapGetters } from 'vuex'
export default {
name: 'configPoup',
data() {
return {
content : '',
showConfirmOrder : false,
}
},
onShow(){
},
methods: {
//
open(key){
this.content = this.configList[key].paramValueArea
this.showConfirmOrder = true
},
openText(content){
this.content = content
this.showConfirmOrder = true
},
close(){
this.showConfirmOrder = false
},
},
computed : {
...mapGetters(['configList'])
}
}
</script>
<style lang="scss" scoped>
.configPopup {
.content{
min-height: 50vh;
max-height: 70vh;
padding: 30rpx 20rpx;
overflow: scroll;
height: 100%;
box-sizing: border-box;
}
}
</style>

+ 5
- 1
otherPages/workbenchManage/bindUser/index.scss View File

@ -38,14 +38,17 @@
}
.bind-main-one{
text-align: center;
background: #FAE7E3;
// background: #FAE7E3;
border-radius: 20rpx;
padding: 40rpx 60rpx;
background-size: 100% 100%;
// background-image: url('https://image.hhlm1688.com/2025/03/29d85e1fc00ba64d3496fdc5c79be35ff6组件 88 – 1.png');
}
.bind-main-two{
text-align: center;
background: #D0E5F9;
border-radius: 20rpx;
background-size: 100% 100%;
padding: 40rpx 50rpx;
}
.bind-main-three{
@ -53,6 +56,7 @@
background: #FDE7C5;
border-radius: 20rpx;
padding: 40rpx 50rpx;
background-size: 100% 100%;
}
.label1 {
width: 120rpx;


+ 64
- 16
otherPages/workbenchManage/bindUser/index.vue View File

@ -6,7 +6,7 @@
<view class="header-name">
<view class="font32 mb20" :style="{color:'#000'}">{{ userInfo?.userName}}</view>
<view class="label1">
初级合伙人
{{ baseInfo.partner_level }}
</view>
<view class="flex font24">
<view :style="{color:'#A55822'}">当前分成比例
@ -19,7 +19,8 @@
</view>
</view>
<view class="flex flex-evenly mt60">
<view class="header-card card-left box-size">
<view class="header-card card-left box-size"
@click="configPopupRef.open('pet_attention_details')">
<view class="flex-between flex">
<view class="mr20">
<view class="mb20 ml20" :style="{color:'#A55822',fontWeight:'bold',fontSize:'30rpx'}">推广攻略
@ -30,7 +31,8 @@
width="71rpx" height="85rpx"></up-image>
</view>
</view>
<view class="header-card card-right box-size">
<view class="header-card card-right box-size"
@click="configPopupRef.open('pet_attention_details')">
<view class="flex flex-between">
<view class="mr20">
<view class="mb20 ml20" :style="{color:'#A55822',fontWeight:'bold',fontSize:'30rpx'}">推广教程
@ -43,51 +45,77 @@
</view>
</view>
</view>
<!--
:style="{'background-image' : `url(${configList.background_popularize_one.paramValueImage})`}" -->
<view class="bind-main">
<view class="bind-main-one mb10">
<view class="bind-main-one mb10"
:style="{'background-image' : `url('${configList.background_popularize_one.paramValueImage}')`}">
<view class="mb20 font32">邀请码邀请</view>
<view class="mb20">用户输入邀请码直接完成绑定</view>
<up-input disabled v-model="userInfo.invitationCode">
<up-input disabled v-model="dataF.code">
<template #suffix>
<up-button @click="copyMessage(code)" text="复制" type="success" size="small" shape="circle"></up-button>
<up-button @click="copyMessage(dataF.code)" text="复制" type="success" size="small" shape="circle"></up-button>
</template>
</up-input>
</view>
<view class="bind-main-two mb10">
<view class="bind-main-two mb10"
:style="{'background-image' : `url('${configList.background_popularize_two.paramValueImage}')`}">
<view class="mb20 font32">分享海报邀请</view>
<view class="mb20">扫码进入猫妈狗爸完成绑定</view>
<up-button text="保存海报" type="primary" shape="circle" plain style="background: transparent;"></up-button>
<up-button @click="toSharing" text="保存海报" type="primary" shape="circle" plain style="background: transparent;"></up-button>
</view>
<view class="bind-main-three">
<view class="bind-main-three"
:style="{'background-image' : `url('${configList.background_popularize_three.paramValueImage}')`}">
<view class="mb20 font32">分享链接邀请</view>
<view class="mb20">复制链接给好友进入直接绑定</view>
<up-input disabled v-model="url">
<up-input disabled v-model="dataF.code">
<template #suffix>
<up-button @click="copyMessage(url)" text="复制" type="success" size="small" shape="circle"></up-button>
<up-button @click="copyMessage(dataF.code)" text="复制" type="success" size="small" shape="circle"></up-button>
</template>
</up-input>
</view>
</view>
<configPopup ref="configPopupRef" />
</view>
</template>
<script setup>
import {
computed,
ref
ref,
onMounted,
} from "vue";
import {
useStore
} from "vuex"
import {
binBaseInfo,
bindCode,
} from "@/api/home.js"
import configPopup from '@/components/configPopup.vue'
const store = useStore();
const dataF = ref({})
const baseInfo = ref({})
const store = useStore();
const configPopupRef = ref(null)
const configList = computed(() => {
return store.getters.configList
})
const userInfo = computed(() => {
return store.getters.userInfo
})
const code = ref('asdasaadsdsa')
const url = ref('https://uview-plus.jiangruyi.com/components/button.html');
//
const copyMessage = (value) => {
uni.setClipboardData({
@ -104,6 +132,26 @@
},
});
}
const getBaseInfo = () => {
binBaseInfo(baseInfo.value.userId).then(res => {
baseInfo.value = res.data
})
bindCode(baseInfo.value.userId).then(res => {
dataF.value = res.data
})
}
function toSharing(){
uni.navigateTo({
url: `/otherPages/workbenchManage/bindUser/sharing`
})
}
onMounted(() => {
baseInfo.value = JSON.parse(uni.getStorageSync("baseInfo"))
getBaseInfo()
})
</script>


+ 193
- 0
otherPages/workbenchManage/bindUser/sharing - 副本.vue View File

@ -0,0 +1,193 @@
<template>
<view class="page">
<navbar title="分享好友" leftClick @leftClick="$utils.navigateBack" />
<view class="flex content">
<view style="width: 598rpx; height: 1063rpx;">
<canvas id="myCanvas" canvas-id="firstCanvas1" type="2d" style="width: 100%; height: 100%;"></canvas>
</view>
<view class="flex btns">
<button class="flex btn btn-back" @click="$utils.navigateBack">返回</button>
<button plain class="flex btn btn-save" @click="saveImg" >保存到相册</button>
</view>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
wxCodeImage: null,
canvas: {},
}
},
computed : {
...mapState(['configList'])
},
onLoad() {
},
onReady() {
this.fetchQrCode()
},
methods: {
async fetchQrCode() {
try {
const url = (await this.$fetch('getQrCode'))?.url
this.wxCodeImage = this.$config.aliOss.url + url
console.log('--wxCodeImage', this.wxCodeImage)
this.draw()
} catch (err) {
}
},
draw() {
uni.showLoading({
title: "拼命绘画中..."
})
wx.createSelectorQuery()
.select('#myCanvas') // canvasid
.fields({
node: true,
size: true
})
.exec(async (res) => {
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 / 598
this.canvas = canvas
ctx.scale(dpr, dpr)
ctx.clearRect(0, 0, width, height)
//
const bgImage = canvas.createImage()
bgImage.src = this.configList.index_lvxing || 'https://image.hhlm1688.com//upload/组3833x_1742803627396.png'
bgImage.onload = () => {
ctx.drawImage(bgImage, 0, 0, width, height)
//
const coderImage = canvas.createImage()
coderImage.src = this.wxCodeImage
coderImage.onload = () => {
const x = 197 * Ratio / dpr
const y = 562 * Ratio / dpr
const size = 206 * Ratio / dpr
ctx.drawImage(coderImage, x, y, size, size)
uni.hideLoading()
}
}
})
},
saveImg(){
this.$authorize('scope.writePhotosAlbum').then((res) => {
this.imgApi()
})
},
imgApi() {
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)
}
}, 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);
}
});
}
});
}
},
}
</script>
<style scoped lang="scss">
.page {
background-color: #111317;
height: 100vh;
}
.content {
margin-top: 79rpx;
flex-direction: column;
}
.btns {
justify-content: space-between;
margin-top: 53rpx;
width: 598rpx;
}
.btn {
display: inline-flex;
width: 280rpx;
height: 90rpx;
font-size: 36rpx;
line-height: 1;
color: #FFFFFF;
border-radius: 45rpx;
margin: 0;
&-back {
background-color: #4E5053;
}
&-save {
background-image: linear-gradient(to right, #02DED6, #05D9A2);
}
}
</style>

+ 209
- 0
otherPages/workbenchManage/bindUser/sharing.vue View File

@ -0,0 +1,209 @@
<template>
<view class="page">
<view class="flex content">
<view style="width: 598rpx; height: 1063rpx;">
<canvas id="myCanvas" canvas-id="firstCanvas1" type="2d" style="width: 100%; height: 100%;"></canvas>
</view>
<view class="flex btns">
<button plain class="flex btn btn-save" @click="saveImg">保存到相册</button>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from 'vuex'
import {
binBaseInfo,
bindCode,
} from "@/api/home.js"
export default {
data() {
return {
wxCodeImage: null,
canvas: {},
data : {},
baseInfo : {},
}
},
computed: {
...mapState(['configList'])
},
onLoad() {
this.baseInfo = JSON.parse(uni.getStorageSync("baseInfo"))
this.getBaseInfo()
},
onReady() {
// this.fetchQrCode()
},
methods: {
async fetchQrCode() {
try {
const url = (await this.$fetch('getQrCode'))?.url
this.wxCodeImage = this.$config.aliOss.url + url
console.log('--wxCodeImage', this.wxCodeImage)
this.draw()
} catch (err) {
}
},
getBaseInfo(){
binBaseInfo(this.baseInfo.userId).then(res => {
this.baseInfo = res.data
})
bindCode(this.baseInfo.userId).then(res => {
this.data = res.data
this.draw()
})
},
draw() {
uni.showLoading({
title: "拼命绘画中..."
})
wx.createSelectorQuery()
.select('#myCanvas') // canvasid
.fields({
node: true,
size: true
})
.exec(async (res) => {
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 / 598
this.canvas = canvas
ctx.scale(dpr, dpr)
ctx.clearRect(0, 0, width, height)
//
const bgImage = canvas.createImage()
bgImage.src = this.data.bj_url ||
'https://image.hhlm1688.com//upload/组3833x_1742803627396.png'
bgImage.onload = () => {
ctx.drawImage(bgImage, 0, 0, width, height)
//
const coderImage = canvas.createImage()
coderImage.src = this.data.url
coderImage.onload = () => {
const x = 197 * Ratio / dpr
const y = 562 * Ratio / dpr
const size = 206 * Ratio / dpr
ctx.drawImage(coderImage, x, y, size, size)
uni.hideLoading()
}
}
})
},
saveImg() {
this.$authorize('scope.writePhotosAlbum').then((res) => {
this.imgApi()
})
},
imgApi() {
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)
}
}, 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);
}
});
}
});
}
},
}
</script>
<style scoped lang="scss">
.page {
height: 100vh;
}
.content {
margin-top: 79rpx;
flex-direction: column;
}
.btns {
justify-content: center;
margin-top: 53rpx;
display: flex;
}
.btn {
display: flex;
width: 520rpx;
height: 90rpx;
font-size: 36rpx;
line-height: 1;
color: #FFFFFF;
border-radius: 45rpx;
margin: 0;
justify-content: center;
align-items: center;
border: none;
&-save {
background: #FFBF60;
}
}
</style>

+ 11
- 0
otherPages/workbenchManage/myLevel/commponents/levelInfo.vue View File

@ -22,6 +22,17 @@
ref,
reactive
} from "vue"
const props = defineProps({
dataInfo : {
default : () => {
return {}
}
}
})
const cardName = ref("距离下一等级要求")
const baseList = ref([
{


+ 42
- 27
otherPages/workbenchManage/myLevel/commponents/myData.vue View File

@ -37,40 +37,55 @@
import { useStore } from 'vuex'
const store = useStore()
const props = defineProps({
dataInfo : {
default : () => {
return {}
}
}
})
const configList = computed(() => {
return store.getters.configList
})
const nounthData = computed(() => {
return [{
title: '当月注册用户',
num: props.dataInfo.register_users + "个",
},
{
title: '当月下单用户',
num: props.dataInfo.register_users + "个",
},
{
title: '当月有效用户',
num: props.dataInfo.register_users + "个",
},
]
})
const totalData = computed(() => {
return [{
title: '累计注册用户',
num: props.dataInfo.register_users + "个",
},
{
title: '累计下单用户',
num: props.dataInfo.register_users + "个",
},
{
title: '累计有效用户',
num: props.dataInfo.register_users + "个",
color:'red'
},
]
})
const nounthName = ref('当月数据')
const totalName = ref('累计数据')
const nounthData = reactive([{
title: '当月注册用户',
num: "0个"
},
{
title: '当月下单用户',
num: "0个"
},
{
title: '当月有效用户',
num: "0个"
},
])
const totalData = reactive([{
title: '累计注册用户',
num: "0个"
},
{
title: '累计下单用户',
num: "0个"
},
{
title: '累计有效用户',
num: "0个",
color:'red'
},
])
</script>
<style scoped lang="scss">


+ 2
- 2
otherPages/workbenchManage/myLevel/index.vue View File

@ -30,8 +30,8 @@
</view>
<view class="bind-main">
<myData v-show="showFlag === 'data'"></myData>
<levelInfo v-show="showFlag === 'level'"></levelInfo>
<myData v-show="showFlag === 'data'" :dataInfo="state.baseInfo"></myData>
<levelInfo v-show="showFlag === 'level'" :dataInfo="state.baseInfo"></levelInfo>
</view>
<view class="bind-user-foot flex-around">


+ 9
- 4
otherPages/workbenchManage/myUser/index.vue View File

@ -64,7 +64,8 @@
import {
ref,
reactive,
onMounted
onMounted,
computed,
} from "vue"
import { useStore } from 'vuex'
import haveOrder from "./components/haveOrder.vue"
@ -76,16 +77,20 @@ import {
import {
binBaseInfo,
bindCode,
computed,
} from "@/api/home.js"
const store = useStore()
const Store = useStore()
const configList = computed(() => {
return store.getters.configList
return Store.getters.configList
})
const userInfo = computed(() => {
return Store.getters.userInfo
})
const code = ref('asdasaadsdsa')
const url = ref('https://uview-plus.jiangruyi.com/components/button.html')
const current = ref(0)


+ 8
- 1
pages.json View File

@ -283,12 +283,19 @@
{
"root": "otherPages/workbenchManage",
//
"pages": [{
"pages": [
{
"path": "bindUser/index",
"style": {
"navigationBarTitleText": "绑定用户"
}
},
{
"path": "bindUser/sharing",
"style": {
"navigationBarTitleText": "分享海报"
}
},
{
"path": "myUser/index",
"style": {


+ 71
- 58
store/modules/system.js View File

@ -1,63 +1,76 @@
import { getConfigList, getPetTypeList, getIncreaseServiceList } from '@/api/config/config.js'
import {
getConfigList,
getPetTypeList,
getIncreaseServiceList
} from '@/api/config/config.js'
const system = {
state: {
configList: {},
petTypeOptions: [],
increaseServiceOptions: [],
},
mutations: {
setConfigList(state, list) {
const obj = {}
list.forEach(n => {
obj[n.paramCode] = n;
})
state.configList = obj;
},
setPetTypeOptions(state, list) {
state.petTypeOptions = list
},
setIncreaseServiceOptions(state, list) {
state.increaseServiceOptions = list
},
},
actions: {
async fetchConfigList({commit, state}) {
try {
const data = await getConfigList()
commit('setConfigList', data)
} catch (err) {
}
},
async fetchPetTypeOptions({commit, state}) {
if (state.petTypeOptions.length) {
return
}
try {
const data = await getPetTypeList()
commit('setPetTypeOptions', data)
} catch (err) {
}
},
async fetchIncreaseServiceOptions({commit, state}) {
if (state.increaseServiceOptions.length) {
return
}
try {
const data = await getIncreaseServiceList()
commit('setIncreaseServiceOptions', data)
} catch (err) {
}
},
}
state: {
configList: {},
petTypeOptions: [],
increaseServiceOptions: [],
},
mutations: {
setConfigList(state, list) {
const obj = {}
list.forEach(n => {
obj[n.paramCode] = n;
})
state.configList = obj;
},
setPetTypeOptions(state, list) {
state.petTypeOptions = list
},
setIncreaseServiceOptions(state, list) {
state.increaseServiceOptions = list
},
},
actions: {
async fetchConfigList({
commit,
state
}) {
try {
const data = await getConfigList()
commit('setConfigList', data)
} catch (err) {
}
},
async fetchPetTypeOptions({
commit,
state
}) {
if (state.petTypeOptions.length) {
return
}
try {
const data = await getPetTypeList()
commit('setPetTypeOptions', data)
} catch (err) {
}
},
async fetchIncreaseServiceOptions({
commit,
state
}) {
if (state.increaseServiceOptions.length) {
return
}
try {
const data = await getIncreaseServiceList()
commit('setIncreaseServiceOptions', data)
} catch (err) {
}
},
}
}
export default system

Loading…
Cancel
Save