【私域操盘手】 操盘手端UI - 添加设备

This commit is contained in:
柳清爽
2025-03-25 15:00:52 +08:00
parent 663542a455
commit f7f48a03fe
10 changed files with 393 additions and 43 deletions

View File

@@ -5,7 +5,7 @@
:class="{ active: active === 'home' }"
@click="switchTab('/pages/index/index', 'home')"
>
<u-icon :name="active === 'home' ? 'home-fill' : 'home'" :size="48" :color="active === 'home' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'home' ? 'home-fill' : 'home'" :size="48" :color="active === 'home' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'home' }">首页</text>
</view>
@@ -14,7 +14,7 @@
:class="{ active: active === 'market' }"
@click="switchTab('/pages/scenarios/index', 'market')"
>
<u-icon :name="active === 'market' ? 'tags-fill' : 'tags'" :size="48" :color="active === 'market' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'market' ? 'tags-fill' : 'tags'" :size="48" :color="active === 'market' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'market' }">场景获客</text>
</view>
@@ -23,7 +23,7 @@
:class="{ active: active === 'work' }"
@click="switchTab('/pages/work/index', 'work')"
>
<u-icon :name="active === 'work' ? 'grid-fill' : 'grid'" :size="48" :color="active === 'work' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'work' ? 'grid-fill' : 'grid'" :size="48" :color="active === 'work' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'work' }">工作台</text>
</view>
@@ -32,7 +32,7 @@
:class="{ active: active === 'profile' }"
@click="switchTab('/pages/profile/index', 'profile')"
>
<u-icon :name="active === 'profile' ? 'account-fill' : 'account'" :size="48" :color="active === 'profile' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'profile' ? 'account-fill' : 'account'" :size="48" :color="active === 'profile' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'profile' }">我的</text>
</view>
</view>
@@ -83,7 +83,7 @@ export default {
.tab-text {
font-size: 26rpx;
color: #999;
color: #777;
&.active-text {
color: #4080ff;

View File

@@ -135,7 +135,7 @@ export default {
.axis-label {
font-size: 22rpx;
color: #999;
color: #777;
text-align: right;
padding-right: 10rpx;
}
@@ -244,7 +244,7 @@ export default {
position: absolute;
transform: translateX(-50%);
font-size: 22rpx;
color: #999;
color: #777;
text-align: center;
top: 10rpx;
}

View File

@@ -5,7 +5,7 @@
:class="{ active: active === 'home' }"
@click="switchTab('/pages/index/index', 'home')"
>
<u-icon :name="active === 'home' ? 'home-fill' : 'home'" :size="48" :color="active === 'home' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'home' ? 'home-fill' : 'home'" :size="48" :color="active === 'home' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'home' }">首页</text>
</view>
@@ -14,7 +14,7 @@
:class="{ active: active === 'market' }"
@click="switchTab('/pages/scenarios/index', 'market')"
>
<u-icon :name="active === 'market' ? 'tags-fill' : 'tags'" :size="48" :color="active === 'market' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'market' ? 'tags-fill' : 'tags'" :size="48" :color="active === 'market' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'market' }">场景获客</text>
</view>
@@ -23,7 +23,7 @@
:class="{ active: active === 'work' }"
@click="switchTab('/pages/index/index', 'work')"
>
<u-icon :name="active === 'work' ? 'grid-fill' : 'grid'" :size="48" :color="active === 'work' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'work' ? 'grid-fill' : 'grid'" :size="48" :color="active === 'work' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'work' }">工作台</text>
</view>
@@ -32,7 +32,7 @@
:class="{ active: active === 'profile' }"
@click="switchTab('/pages/profile/index', 'profile')"
>
<u-icon :name="active === 'profile' ? 'account-fill' : 'account'" :size="48" :color="active === 'profile' ? '#4080ff' : '#e9e9e9'"></u-icon>
<u-icon :name="active === 'profile' ? 'account-fill' : 'account'" :size="48" :color="active === 'profile' ? '#4080ff' : '#999999'"></u-icon>
<text class="tab-text" :class="{ 'active-text': active === 'profile' }">我的</text>
</view>
</view>
@@ -84,7 +84,7 @@ export default {
.tab-text {
font-size: 26rpx;
color: #999;
color: #777;
margin-top: 10rpx;
&.active-text {

View File

@@ -157,6 +157,39 @@
title="选择状态"
></u-picker>
<!-- 添加设备弹窗 -->
<view class="add-device-modal" v-if="showAddDeviceModal">
<view class="modal-mask" @click="cancelAddDevice"></view>
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">添加设备</text>
<view class="modal-close" @click="cancelAddDevice">
<text class="close-icon">×</text>
</view>
</view>
<view class="modal-body">
<view class="qr-container">
<image class="qr-image" src="/static/images/qr-placeholder.png" mode="aspectFit"></image>
</view>
<view class="qr-hint">请使用设备扫描二维码进行添加</view>
<view class="qr-hint">或手动输入设备ID</view>
<view class="device-id-input">
<u-input
v-model="deviceId"
placeholder="请输入设备ID"
shape="circle"
border="surround"
clearable
></u-input>
</view>
</view>
<view class="modal-actions">
<view class="cancel-btn" @click="cancelAddDevice">取消</view>
<view class="confirm-btn" @click="confirmAddDevice">确认添加</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<CustomTabBar active="profile"></CustomTabBar>
</view>
@@ -183,7 +216,10 @@ export default {
{ text: '在线', value: 'online' },
{ text: '离线', value: 'offline' }
],
currentStatus: 'all'
currentStatus: 'all',
// 添加设备相关数据
showAddDeviceModal: false,
deviceId: ''
}
},
computed: {
@@ -203,10 +239,37 @@ export default {
// 添加设备
addDevice() {
uni.showToast({
title: '添加设备功能待实现',
icon: 'none'
this.showAddDeviceModal = true;
},
// 取消添加设备
cancelAddDevice() {
this.showAddDeviceModal = false;
this.deviceId = '';
},
// 确认添加设备
confirmAddDevice() {
if (!this.deviceId.trim()) {
uni.showToast({
title: '请输入设备ID',
icon: 'none'
});
return;
}
uni.showLoading({
title: '添加中'
});
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: '添加成功',
icon: 'success'
});
this.cancelAddDevice();
}, 1500);
},
// 刷新列表
@@ -375,7 +438,7 @@ export default {
border-radius: 35rpx;
padding: 30rpx;
margin: 15rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
.stat-label {
font-size: 28rpx;
@@ -404,6 +467,7 @@ export default {
border-radius: 35rpx;
overflow: hidden;
border: 2rpx solid #e9e9e9;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
.search-bar {
@@ -498,6 +562,7 @@ export default {
margin: 25rpx;
border-radius: 20rpx;
border: 2rpx solid #e9e9e9;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
&:last-child {
border-bottom: none;
@@ -555,4 +620,117 @@ export default {
}
}
}
/* 添加设备弹窗样式 */
.add-device-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
position: relative;
width: 650rpx;
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 40rpx;
.modal-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.modal-close {
padding: 10rpx;
.close-icon {
font-size: 44rpx;
color: #777;
line-height: 1;
}
}
}
.modal-body {
padding: 0rpx 40rpx;
padding-bottom: 30rpx;
.qr-container {
width: 450rpx;
height: 450rpx;
margin: 0 auto 30rpx;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10rpx;
.qr-image {
width: 400rpx;
height: 400rpx;
}
}
.qr-hint {
text-align: center;
color: #666;
font-size: 28rpx;
}
.device-id-input {
margin-top: 40rpx;
}
}
.modal-actions {
display: flex;
justify-content: center;
padding: 20rpx 40rpx 40rpx;
.cancel-btn, .confirm-btn {
width: 180rpx;
height: 80rpx;
border-radius: 25rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
margin: 0 15rpx;
}
.cancel-btn {
background-color: #ffffff;
color: #333;
border: 1px solid #e5e5e5;
}
.confirm-btn {
background-color: #4080ff;
color: #fff;
}
}
}
}
</style>

View File

@@ -323,7 +323,7 @@ export default {
.stat-label {
font-size: 24rpx;
color: #999;
color: #777;
}
}
}
@@ -339,4 +339,14 @@ export default {
height: 100%;
}
}
.tab-text {
font-size: 26rpx;
color: #777;
margin-top: 10rpx;
&.active-text {
color: #4080ff;
}
}
</style>

View File

@@ -3,7 +3,7 @@
<!-- 登录方式切换 -->
<u-tabs
:list="tabsList"
:current="current"
:current="Number(current)"
@change="handleTabChange"
activeStyle="color: #4080ff; font-size: 36rpx"
inactiveStyle="color: #e9e9e9; font-size: 36rpx"
@@ -37,7 +37,7 @@
</view>
<!-- 验证码输入 -->
<view v-if="current === 0" class="input-box code-box">
<view v-if="current == 0" class="input-box code-box">
<u--input
v-model="form.code"
placeholder="验证码"
@@ -61,7 +61,7 @@
</view>
<!-- 密码输入 -->
<view v-if="current === 1" class="input-box">
<view v-if="current == 1" class="input-box">
<u--input
v-model="form.password"
placeholder="密码"
@@ -71,17 +71,25 @@
fontSize="30rpx"
suffixIcon="eye"
@clickSuffixIcon="showPassword = !showPassword"
suffixIconStyle="font-size: 45rpx;"
></u--input>
</view>
<!-- 用户协议 -->
<view class="agreement">
<u-checkbox
<u-checkbox-group
v-model="isAgree"
shape="circle"
activeColor="#4080ff"
iconSize="48"
></u-checkbox>
placement="column"
@change="checkboxChange"
>
<u-checkbox
key="1"
shape="circle"
activeColor="#4080ff"
size="35"
iconSize="30"
></u-checkbox>
</u-checkbox-group>
<text class="agreement-text">
已阅读并同意
<text class="link" @click="goToUserAgreement">用户协议</text>
@@ -95,7 +103,7 @@
text="登录"
type="primary"
@click="handleLogin"
customStyle="width: 100%; margin-top: 40rpx; height: 96rpx; border-radius: 24rpx; font-size: 70rpx;"
customStyle="width: 100%; margin-top: 40rpx; height: 96rpx; border-radius: 24rpx; font-size: 32rpx; font-weight: 500;"
></u-button>
<!-- 分割线 -->
@@ -131,8 +139,8 @@ export default {
data() {
return {
tabsList: [
{ name: '验证码登录' },
{ name: '密码登录' }
{ text: '验证码登录', name: '验证码登录', id: 0 },
{ text: '密码登录', name: '密码登录', id: 1 }
],
current: 0,
form: {
@@ -146,18 +154,34 @@ export default {
codeTips: '发送验证码'
}
},
onLoad() {
// 确保初始状态下表单字段正确
this.current = 0;
this.form.password = '';
},
computed: {
isValidMobile() {
return /^1\d{10}$/.test(this.form.mobile)
},
canLogin() {
if (!this.isAgree || !this.isValidMobile) return false
return this.current === 0 ? !!this.form.code : !!this.form.password
return this.current == 0 ? !!this.form.code : !!this.form.password
}
},
methods: {
checkboxChange(value) {
console.log('checkboxChange', value)
},
handleTabChange(index) {
this.current = index
this.current = Number(index.index);
// 清除不相关的表单字段
if (this.current == 0) {
this.form.password = '';
} else {
this.form.code = '';
}
// 确保密码输入框的可见状态正确重置
this.showPassword = false;
},
getCode() {
if (this.sending || !this.isValidMobile) return
@@ -175,17 +199,96 @@ export default {
}, 1000)
},
handleLogin() {
if (!this.canLogin) return
uni.showToast({
title: '登录成功',
icon: 'success'
if (!this.canLogin) {
if (!this.isAgree) {
uni.showToast({
title: '请先同意用户协议和隐私政策',
icon: 'none'
})
return
}
if (!this.isValidMobile) {
uni.showToast({
title: '请输入有效的手机号',
icon: 'none'
})
return
}
if (this.current == 0 && !this.form.code) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
})
return
}
if (this.current == 1 && !this.form.password) {
uni.showToast({
title: '请输入密码',
icon: 'none'
})
return
}
return
}
// 显示加载中
uni.showLoading({
title: '登录中...',
mask: true
})
// 模拟登录成功
setTimeout(() => {
// 隐藏加载提示
uni.hideLoading()
// 保存登录状态和用户信息
uni.setStorageSync('token', 'mock_token_' + Date.now())
uni.setStorageSync('userInfo', {
mobile: this.form.mobile,
loginTime: Date.now()
})
// 显示登录成功提示
uni.showToast({
title: '登录成功',
icon: 'success',
duration: 1500
})
// 延迟跳转到首页
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index',
success: () => {
console.log('跳转到首页成功')
},
fail: (err) => {
console.error('跳转失败:', err)
uni.showToast({
title: '跳转失败,请重试',
icon: 'none'
})
}
})
}, 1500)
}, 1000)
},
handleWechatLogin() {
console.log('微信登录')
// 仅模拟
uni.showToast({
title: '微信登录',
icon: 'none'
})
},
handleAppleLogin() {
console.log('Apple登录')
// 仅模拟
uni.showToast({
title: 'Apple登录',
icon: 'none'
})
},
goToUserAgreement() {
uni.navigateTo({
@@ -266,7 +369,7 @@ export default {
.agreement-text {
font-size: 28rpx;
color: #999999;
color: #777777;
margin-left: 12rpx;
}
@@ -288,7 +391,7 @@ export default {
}
.text {
color: #999999;
color: #777777;
padding: 0 30rpx;
font-size: 28rpx;
}
@@ -331,8 +434,8 @@ export default {
.contact-us {
text-align: center;
font-size: 28rpx;
color: #999999;
font-size: 26rpx;
color: #777777;
margin-top: 60rpx;
padding-bottom: 40rpx;
}

View File

@@ -329,7 +329,7 @@ export default {
.channel-desc {
font-size: 28rpx;
color: #999;
color: #777;
}
}
}
@@ -351,7 +351,7 @@ export default {
.data-label {
font-size: 28rpx;
color: #999;
color: #777;
}
}
}
@@ -467,7 +467,7 @@ export default {
.customer-time {
font-size: 24rpx;
color: #999;
color: #777;
}
}
}
@@ -475,8 +475,30 @@ export default {
.empty-tip {
text-align: center;
padding: 40rpx 0;
color: #999;
color: #777;
font-size: 28rpx;
}
}
.progress-label {
font-size: 24rpx;
color: #777;
margin-bottom: 10rpx;
}
.stat-label {
font-size: 24rpx;
color: #777;
}
.timeline-time {
font-size: 24rpx;
color: #777;
margin-bottom: 8rpx;
}
.timeline-meta {
font-size: 22rpx;
color: #777;
}
</style>

View File

@@ -499,4 +499,14 @@ export default {
margin-left: 20rpx;
}
}
.tab-text {
font-size: 26rpx;
color: #777;
margin-top: 10rpx;
&.active-text {
color: #4080ff;
}
}
</style>

View File

@@ -0,0 +1 @@
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAABX5JREFUeJzt3U2IXGUUxvH/TCYkThLTqMVCoV0oBBcuChVcuHIjCFZw6c6NQlwLQkHowoUiQhcKRRDBlRsRioguBUEEQRAERRQEKX5UxdTYJE0nXw7cQrFkct+Ze+55vw/MMwi995znndOmEySYSAiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiItKcfusF7GQQbAGHgTuBW4BDwE3AQeAGYA1YBxaBzcnX34EfgfPAD8AZ4DRwGthMXbzsyRRxMBxVewOeBA4D9wMP1X7wGXwDfAF8DnwInPNdTnscTEcTHG5p2qzaG/AccBQ40mQJue0A7wEfAO8C59zWUZuD8WiCwy1NO1Z7A14AngWmm/rQAv4F3gWOAx97LybC3XnN8TiyuOVpZ2rvxEvARjMf1MZOACeJf3Gr9ZOcgyMh/+SWp52qvRNHgdm6H9CQ7YELwDHgdde1Tbg0Vo7Qd0vuNdTejbeBtxr4jFacAr4HxsDXzBOArdaGzwDTwNXAdcDVwF3A/cC9+T+iGR8DLwLfuq4s4mTIx6WxcoS+W3KvoXbxbwMn6Z6vgVeAj1zXdal2oXYf8SQbE5/k61x4B3gd+Ml1ZREeJ8dEd0vuNdQu/qPAdt0PcbYDvA8cxvX1yiWahdpV3A28OvnfMfBZrkdP2CY+uX/uuqqIZyO+xnx3S+4n1I72AJ9W/QBHm8TXxhdxHiZ28I5ys3eUd5SH0T7sJu4aDyP8UD7i64h3QRjKwT5UvPccvED8TnqtgY9pw3vAPcDXriuL+CniaxzeUZ5GeLCPFe8/B2Pgywb2cAw837b5aAdZYN5Rvj4+Pv6U3WvIcTzYx4r334MxcKbCDubOGHgJVa0J1wE7Od5RbkcY7EXxfnzwN3Bzyd3LcCfxSk3jDdw1pou8ozyPMNiL4v34YQv4rcDeZbk/cB9Vq5jLCvyOcofBIB/Dfa24Lx9s0O0fz/1O4D6qVpGFAr9j36E8kDDci+L+/PAn8H3JPSyhDbfEqVql5QYf6MYID/ay4v58sQWcLrx/1vYauHeqVnG5wQd7UdyXL3aAjwr3z5KqVU5u8MFeFvfljz3go8L9s6JqZdfM8YzwRngjvHG5wd+3q7g/n5wDfor3z4KqldXIZCx33t/c4O/bVdyjTzaZoyPGrKhadg0dzyC3Ed4Ib8zH/Vn1V+HemVO17Fxfk+cG/4DZi3v0ywzwR+H+mVK1xjRzPOeVG/wDZi/u0TeHgF8L98+MqjWmoeM579zgHzB7cY++me3ACadqjWnueO7LDf6BdRf36p9t2v/3r6rWmGsaOp7Lyg3+AfYg7tU/swP+r6NWqFqOxzMzN/gH2sdCNfCxRfs/L65qOWm4FDtyg3+g/SS0WDfXF+6fkarloKFS7MoN/oH201C97ttr+UfCWqFqFdZAKfbkBv9A+02wZhnWS35GoFaqVkFFSnEgN/gH2u9CNcuzQvvvZqladRUoxYHc4B9o/zW5zTquCd2n21QtpdgXa1kj7tFAe67swXuZqiUXsbZFvLs0/wfvkKqlFwtZo9A90p0HRuV2MJ2qpRcLGcN1XuDO06l2VCwVSy8WMEexe6Q7T6jYV7FULGOm0LvHR+V2MC1VSy8WMEexe6Q7T6jYV7FULIO43jvNHQZVS7TvgnJFcb13mjsMqpZo3wVli+I67zR3GFQt0b4LyhXFdd5p7jCoWqJ9F5QriOu709xhULVE+y4oWxDXd6e5w7D8bxhULdG+C8oVxPXdae4waJTvwKtaejFDriCu705zh0HV0osZcgVxfXeaOwyqll7MkCuI67vT3GFQtfRihlxBXN+d5g6DqqUXM+QK4vruNHcYVC29mKG/AO0MF6TIrRxLAAAAAElFTkSuQmCC

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="200" height="200" rx="10" fill="#F5F5F5"/>
<!-- 二维码方块 -->
<rect x="50" y="50" width="20" height="20" fill="#CCCCCC"/>
<rect x="70" y="50" width="20" height="20" fill="#CCCCCC"/>
<rect x="90" y="50" width="20" height="20" fill="#CCCCCC"/>
<rect x="130" y="50" width="20" height="20" fill="#CCCCCC"/>
<rect x="50" y="70" width="20" height="20" fill="#CCCCCC"/>
<rect x="110" y="70" width="20" height="20" fill="#CCCCCC"/>
<rect x="130" y="70" width="20" height="20" fill="#CCCCCC"/>
<rect x="50" y="90" width="20" height="20" fill="#CCCCCC"/>
<rect x="90" y="90" width="20" height="20" fill="#CCCCCC"/>
<rect x="110" y="90" width="20" height="20" fill="#CCCCCC"/>
<rect x="70" y="110" width="20" height="20" fill="#CCCCCC"/>
<rect x="110" y="110" width="20" height="20" fill="#CCCCCC"/>
<rect x="130" y="110" width="20" height="20" fill="#CCCCCC"/>
<rect x="50" y="130" width="20" height="20" fill="#CCCCCC"/>
<rect x="70" y="130" width="20" height="20" fill="#CCCCCC"/>
<rect x="90" y="130" width="20" height="20" fill="#CCCCCC"/>
<rect x="130" y="130" width="20" height="20" fill="#CCCCCC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB