暂时提交

feasure-livedata
lld 2026-04-04 02:26:12 +08:00
parent 6d26d1f3d7
commit 0d14266fa7
11 changed files with 1985 additions and 1 deletions

View File

@ -80,6 +80,50 @@
"style": { "style": {
"navigationBarTitleText": "控制中心" "navigationBarTitleText": "控制中心"
} }
},
{
"path": "invite/shareDevice/index",
"style": {
"navigationBarTitleText": "设备分享"
}
},
{
"path": "invite/shareTarget/index",
"style": {
"navigationBarTitleText": "分享对象"
}
},
{
"path": "invite/selectDevice/index",
"style": {
"navigationBarTitleText": "选择设备"
}
},
{
"path": "invite/setPermission/index",
"style": {
"navigationBarTitleText": "设置权限"
}
},
{
"path": "invite/myShareDetail/index",
"style": {
"navigationBarTitleText": "我的分享"
}
},
{
"path": "invite/shareConfirm/index",
"style": {
"navigationBarTitleText": "确认分享",
"navigationStyle": "custom"
}
},
{
"path": "invite/sharedToMe/index",
"style": {
"navigationBarTitleText": "分享给我的",
"navigationStyle": "custom"
}
} }
// { // {

View File

View File

@ -0,0 +1,260 @@
<template>
<view class="page">
<!-- 设备卡片 -->
<view class="device-card">
<image :src="deviceInfo.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ deviceInfo.name }}</text>
<text class="device-serial">序列号{{ deviceInfo.serial }}</text>
</view>
<button class="add-share-btn" @click="addShare"></button>
</view>
<!-- 分享对象列表标题 -->
<view class="targets-header">
<text class="targets-title">分享对象 ({{ shareTargets.length }}/10)</text>
<text class="cancel-all" @click="cancelAll"></text>
</view>
<!-- 分享对象列表 -->
<view class="targets-list">
<view v-for="target in shareTargets" :key="target.id" class="target-item">
<view class="target-top">
<view class="target-name-row">
<text class="target-name">{{ target.name }}</text>
<image src="/static/images/share/icon_edit.png" class="edit-icon" mode="aspectFit" />
</view>
<view class="shared-badge">已分享</view>
</view>
<text class="target-permissions">{{ target.permissions.join(' / ') }}</text>
<text class="target-last-use">最新使用{{ target.lastUse }}</text>
<view class="target-actions">
<button class="action-btn" @click="cancelShare(target)"></button>
<button class="action-btn" @click="editPermission(target)"></button>
</view>
</view>
<view v-if="!shareTargets.length" class="empty-tip"></view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
deviceInfo: {
id: 3,
name: 'DS-2DE4423DW-D/GL...',
serial: 'FW1167162',
img: '/static/images/share/camera1.png'
},
shareTargets: [
{
id: 1,
name: '132*****131/94198854的互联',
permissions: ['看视频', '看录像', '报警消息', '控制设备'],
lastUse: '2026-04-03'
}
]
}
},
onLoad(options) {
if (options.id) {
// id
}
},
methods: {
addShare() {
uni.navigateTo({ url: '/pages/home/invite/shareTarget/index' })
},
cancelAll() {
uni.showModal({
title: '提示',
content: '确定取消所有分享?',
success: (res) => {
if (res.confirm) {
this.shareTargets = []
uni.showToast({ title: '已取消所有分享', icon: 'none' })
}
}
})
},
cancelShare(target) {
uni.showModal({
title: '提示',
content: `确定取消对【${target.name}】的分享?`,
success: (res) => {
if (res.confirm) {
this.shareTargets = this.shareTargets.filter(t => t.id !== target.id)
uni.showToast({ title: '已取消分享', icon: 'none' })
}
}
})
},
editPermission(target) {
uni.navigateTo({
url: `/pages/home/invite/setPermission/index?targetId=${target.id}`
})
}
}
}
</script>
<style lang="scss" scoped>
page { background: #edf1f7; }
.page {
min-height: 100vh;
background: #edf1f7;
padding: 20rpx 25rpx;
}
/* 设备卡片 */
.device-card {
display: flex;
align-items: center;
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
.device-img {
width: 90rpx;
height: 90rpx;
margin-right: 20rpx;
flex-shrink: 0;
}
.device-info {
flex: 1;
overflow: hidden;
.device-name {
display: block;
font-size: 28rpx;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.device-serial {
display: block;
font-size: 24rpx;
color: #999;
margin-top: 6rpx;
}
}
.add-share-btn {
background: #3d7ff5;
color: #fff;
font-size: 24rpx;
border-radius: 30rpx;
padding: 12rpx 24rpx;
border: none;
line-height: 1.4;
flex-shrink: 0;
}
}
/* 分享对象标题 */
.targets-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 26rpx 10rpx;
.targets-title {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.cancel-all {
font-size: 26rpx;
color: #999;
}
}
/* 分享对象列表 */
.targets-list {
background: #fff;
border-radius: 16rpx;
overflow: hidden;
.target-item {
padding: 40rpx 34rpx;
border-bottom: 1rpx solid #f2f2f2;
&:last-child { border-bottom: none; }
.target-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
.target-name-row {
display: flex;
align-items: center;
.target-name {
font-size: 28rpx;
color: #3d7ff5;
margin-right: 8rpx;
}
.edit-icon {
width: 28rpx;
height: 28rpx;
}
}
.shared-badge {
font-size: 22rpx;
color: #999;
background: #f5f5f5;
padding: 4rpx 16rpx;
border-radius: 20rpx;
}
}
.target-permissions {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 8rpx;
}
.target-last-use {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
}
.target-actions {
display: flex;
gap: 20rpx;
.action-btn {
font-size: 24rpx;
color: #555;
background: #fff;
border: 2rpx solid #ddd;
border-radius: 30rpx;
padding: 10rpx 30rpx;
line-height: 1.4;
}
}
}
}
.empty-tip {
text-align: center;
color: #bbb;
font-size: 26rpx;
padding: 60rpx 0;
}
</style>

View File

@ -0,0 +1,235 @@
<template>
<view class="page">
<!-- 提示条 -->
<view class="notice-bar">
<text class="notice-icon"></text>
<text class="notice-text">已分享分享已达上限的设备请前往 [我的-分享管理] 进行权限编辑或取消分享</text>
</view>
<!-- 设备列表 -->
<view class="device-list">
<view
v-for="device in deviceList"
:key="device.id"
class="device-item"
@click="toggleSelect(device)"
>
<!-- 单选框 -->
<view class="radio" :class="{ 'radio-checked': selectedIds.includes(device.id), 'radio-disabled': device.shared }">
<view v-if="selectedIds.includes(device.id)" class="radio-inner" />
</view>
<image :src="device.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ device.name }}</text>
<text class="device-serial">{{ device.serial }}</text>
</view>
<text v-if="device.shared" class="shared-tag"></text>
</view>
</view>
<!-- 底部已选 + 下一步 -->
<view class="bottom-bar">
<text class="selected-tip">已选中{{ selectedIds.length }}/{{ maxShare }}</text>
<button
class="next-btn"
:class="{ 'next-btn-active': selectedIds.length > 0 }"
:disabled="selectedIds.length === 0"
@click="goNext"
>下一步</button>
</view>
</view>
</template>
<script>
const MAX_SHARE = 10
export default {
data() {
return {
maxShare: MAX_SHARE,
selectedIds: [],
phone: '',
deviceList: [
{ id: 1, name: '八方', serial: 'GL5074046', img: '/static/images/share/camera1.png', shared: true },
{ id: 2, name: '十方', serial: 'GK5192621', img: '/static/images/share/camera2.png', shared: true },
{ id: 3, name: 'DS-2DE4423DW-D/GL...', serial: 'FW1167162', img: '/static/images/share/camera1.png', shared: true },
{ id: 4, name: 'DS-7804N-Z1/X(D)(FR...', serial: 'FR5725238', img: '/static/images/share/nvr.png', shared: true }
]
}
},
onLoad(options) {
this.phone = options.phone || ''
},
methods: {
toggleSelect(device) {
if (device.shared) return //
const idx = this.selectedIds.indexOf(device.id)
if (idx > -1) {
this.selectedIds.splice(idx, 1)
} else {
if (this.selectedIds.length >= this.maxShare) {
uni.showToast({ title: `最多分享${this.maxShare}`, icon: 'none' })
return
}
this.selectedIds.push(device.id)
}
},
goNext() {
const selected = this.deviceList.filter(d => this.selectedIds.includes(d.id))
uni.navigateTo({
url: `/pages/home/invite/setPermission/index?phone=${this.phone}&devices=${encodeURIComponent(JSON.stringify(selected))}`
})
}
}
}
</script>
<style lang="scss" scoped>
page { background: #edf1f7; }
.page {
min-height: 100vh;
background: #edf1f7;
padding-bottom: 120rpx;
}
/* 提示条 */
.notice-bar {
display: flex;
align-items: flex-start;
background: #fff8ee;
border-left: 6rpx solid #f5a623;
padding: 20rpx 24rpx;
margin: 20rpx 20rpx 0;
border-radius: 8rpx;
.notice-icon {
color: #f5a623;
font-size: 28rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.notice-text {
font-size: 24rpx;
color: #f5a623;
line-height: 1.6;
}
}
/* 设备列表 */
.device-list {
background: #fff;
border-radius: 16rpx;
margin: 20rpx;
overflow: hidden;
.device-item {
display: flex;
align-items: center;
padding: 24rpx 24rpx;
border-bottom: 1rpx solid #f2f2f2;
&:last-child { border-bottom: none; }
.radio {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid #ccc;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
flex-shrink: 0;
&-checked {
border-color: #3d7ff5;
background: #3d7ff5;
}
&-inner {
width: 18rpx;
height: 18rpx;
background: #fff;
border-radius: 50%;
}
&-disabled {
background: #f5f5f5;
border-color: #e0e0e0;
}
}
.device-img {
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
flex-shrink: 0;
}
.device-info {
flex: 1;
overflow: hidden;
.device-name {
font-size: 28rpx;
color: #333;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.device-serial {
font-size: 24rpx;
color: #999;
display: block;
margin-top: 6rpx;
}
}
.shared-tag {
font-size: 24rpx;
color: #999;
flex-shrink: 0;
margin-left: 10rpx;
}
}
}
/* 底部 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 30rpx;
background: #edf1f7;
.selected-tip {
font-size: 26rpx;
color: #666;
}
.next-btn {
width: 200rpx;
height: 80rpx;
line-height: 80rpx;
background: #ccc;
color: #fff;
border-radius: 40rpx;
font-size: 28rpx;
border: none;
padding: 0;
margin: 0;
&-active {
background: #3d7ff5;
}
}
}
</style>

View File

@ -0,0 +1,186 @@
<template>
<view class="page">
<text class="page-hint">请设置分享对象的视频权限</text>
<!-- 权限选项列表 -->
<view class="permission-list">
<view
v-for="item in permissionOptions"
:key="item.value"
class="permission-item"
@click="togglePermission(item)"
>
<view class="radio" :class="{ 'radio-checked': selectedPermissions.includes(item.value) }">
<view v-if="selectedPermissions.includes(item.value)" class="check-icon"></view>
</view>
<view class="permission-info">
<text class="permission-name">{{ item.label }}</text>
<text class="permission-desc">{{ item.desc }}</text>
</view>
</view>
</view>
<!-- 底部提示 + 按钮 -->
<view class="footer">
<view class="footer-notice">
<text class="notice-icon"></text>
<text class="notice-text">分享成功后设备仅限被分享账号本人使用</text>
</view>
<button class="next-btn" @click="goNext"></button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
phone: '',
devices: [],
selectedPermissions: ['watch_video'], // ""
permissionOptions: [
{ value: 'watch_video', label: '看视频', desc: '可查看实时画面' },
{ value: 'watch_record', label: '看录像', desc: '可查看录像回放' },
{ value: 'alarm_msg', label: '报警消息', desc: '可接收、查看设备消息' },
{ value: 'control_device', label: '控制设备', desc: '可调整云台、画面、声音灯光等设置' }
]
}
},
onLoad(options) {
this.phone = options.phone || ''
if (options.devices) {
try {
this.devices = JSON.parse(decodeURIComponent(options.devices))
} catch (e) {}
}
},
methods: {
togglePermission(item) {
const idx = this.selectedPermissions.indexOf(item.value)
if (idx > -1) {
this.selectedPermissions.splice(idx, 1)
} else {
this.selectedPermissions.push(item.value)
}
},
goNext() {
if (!this.selectedPermissions.length) {
uni.showToast({ title: '请至少选择一项权限', icon: 'none' })
return
}
uni.navigateTo({
url: `/pages/home/invite/shareConfirm/index?phone=${this.phone}&permissions=${encodeURIComponent(JSON.stringify(this.selectedPermissions))}&devices=${encodeURIComponent(JSON.stringify(this.devices))}`
})
}
}
}
</script>
<style lang="scss" scoped>
page { background: #edf1f7; }
.page {
min-height: 100vh;
background: #edf1f7;
display: flex;
flex-direction: column;
padding: 30rpx 20rpx;
}
.page-hint {
font-size: 26rpx;
color: #999;
margin-bottom: 20rpx;
padding-left: 4rpx;
}
/* 权限列表 */
.permission-list {
background: #fff;
border-radius: 16rpx;
overflow: hidden;
flex: 1;
.permission-item {
display: flex;
align-items: center;
padding: 30rpx 28rpx;
border-bottom: 1rpx solid #f2f2f2;
&:last-child { border-bottom: none; }
.radio {
width: 44rpx;
height: 44rpx;
border-radius: 50%;
border: 2rpx solid #ccc;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
flex-shrink: 0;
&-checked {
background: #555;
border-color: #555;
}
.check-icon {
color: #fff;
font-size: 26rpx;
line-height: 1;
}
}
.permission-info {
.permission-name {
display: block;
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 6rpx;
}
.permission-desc {
display: block;
font-size: 24rpx;
color: #aaa;
}
}
}
}
/* 底部 */
.footer {
margin-top: 40rpx;
.footer-notice {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24rpx;
.notice-icon {
color: #f5a623;
font-size: 26rpx;
margin-right: 8rpx;
}
.notice-text {
font-size: 24rpx;
color: #f5a623;
}
}
.next-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #3d7ff5;
color: #fff;
border-radius: 50rpx;
font-size: 32rpx;
border: none;
}
}
</style>

View File

@ -0,0 +1,343 @@
<template>
<view class="page">
<!-- 顶部蓝色区分享对象信息 -->
<view class="header-section">
<view class="back-btn" @click="goBack"></view>
<view class="header-info">
<text class="header-title">分享对象</text>
<text class="header-phone">{{ phone }}</text>
<text class="header-permissions">{{ permissionLabels }}</text>
</view>
</view>
<!-- 白色区分享设备卡片 -->
<view class="content-section">
<view class="share-devices-card">
<text class="card-title">分享设备</text>
<view
v-for="device in devices"
:key="device.id"
class="device-row"
>
<image :src="device.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ device.name }}</text>
<text class="device-serial">{{ device.serial }}</text>
</view>
</view>
</view>
</view>
<!-- 底部提示 -->
<view class="footer">
<view class="footer-notice">
<text class="notice-icon"></text>
<text class="notice-text">
请仔细核对并确认分享对象在注册账号并接受邀请后将能在权限内使用您分享的设备分享成功后设备仅限被分享账号本人使用
</text>
</view>
<button class="confirm-btn" @click="confirmShare"></button>
</view>
<!-- 微信通知弹窗 -->
<view v-if="showNotifyModal" class="modal-mask" @click.self="closeModal">
<view class="modal-content">
<view class="modal-close" @click="closeModal">×</view>
<text class="modal-title">是否微信发送分享邀请</text>
<text class="modal-desc">推荐通过微信通知对方便于对方即时接受分享</text>
<image src="/static/images/share/share_card.png" class="modal-img" mode="aspectFit" />
<button class="wx-notify-btn" @click="sendWxNotify"></button>
<button class="skip-btn" @click="skipNotify"></button>
<view class="privacy-row">
<text class="privacy-icon"></text>
<text class="privacy-text">微信隐私协议</text>
</view>
</view>
</view>
</view>
</template>
<script>
// value -> label
const PERMISSION_MAP = {
watch_video: '看视频',
watch_record: '看录像',
alarm_msg: '报警消息',
control_device: '控制设备'
}
export default {
data() {
return {
phone: '',
permissions: [],
devices: [],
showNotifyModal: false
}
},
computed: {
permissionLabels() {
return this.permissions.map(p => PERMISSION_MAP[p] || p).join(' / ')
}
},
onLoad(options) {
this.phone = options.phone || ''
try {
this.permissions = JSON.parse(decodeURIComponent(options.permissions || '[]'))
this.devices = JSON.parse(decodeURIComponent(options.devices || '[]'))
} catch (e) {}
},
methods: {
goBack() {
uni.navigateBack()
},
confirmShare() {
this.showNotifyModal = true
},
closeModal() {
this.showNotifyModal = false
},
sendWxNotify() {
this.showNotifyModal = false
// wx.shareAppMessageopenCustomerServiceChat
uni.showToast({ title: '微信通知已发送', icon: 'success' })
setTimeout(() => uni.navigateBack({ delta: 4 }), 1500)
},
skipNotify() {
this.showNotifyModal = false
uni.showToast({ title: '分享成功', icon: 'success' })
setTimeout(() => uni.navigateBack({ delta: 4 }), 1500)
}
}
}
</script>
<style lang="scss" scoped>
page { background: #edf1f7; }
.page {
min-height: 100vh;
background: #edf1f7;
display: flex;
flex-direction: column;
}
/* 顶部蓝色区 */
.header-section {
background: #3d7ff5;
padding: 60rpx 30rpx 120rpx;
position: relative;
.back-btn {
color: #fff;
font-size: 50rpx;
position: absolute;
top: 50rpx;
left: 24rpx;
line-height: 1;
}
.header-info {
padding-left: 20rpx;
.header-title {
display: block;
color: rgba(255,255,255,0.8);
font-size: 26rpx;
margin-bottom: 8rpx;
}
.header-phone {
display: block;
color: #fff;
font-size: 40rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.header-permissions {
display: block;
color: rgba(255,255,255,0.85);
font-size: 26rpx;
}
}
}
/* 内容区(白色卡片)*/
.content-section {
margin: -60rpx 20rpx 0;
position: relative;
flex: 1;
.share-devices-card {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
.card-title {
display: block;
font-size: 30rpx;
color: #333;
font-weight: bold;
margin-bottom: 20rpx;
}
.device-row {
display: flex;
align-items: center;
padding: 10rpx 0;
.device-img {
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
}
.device-info {
.device-name {
display: block;
font-size: 28rpx;
color: #333;
}
.device-serial {
display: block;
font-size: 24rpx;
color: #aaa;
margin-top: 4rpx;
}
}
}
}
}
/* 底部 */
.footer {
padding: 30rpx 20rpx;
margin-top: auto;
.footer-notice {
display: flex;
align-items: flex-start;
background: #fff8ee;
border-radius: 8rpx;
padding: 18rpx 20rpx;
margin-bottom: 24rpx;
.notice-icon {
color: #f5a623;
font-size: 26rpx;
margin-right: 10rpx;
flex-shrink: 0;
}
.notice-text {
font-size: 24rpx;
color: #f5a623;
line-height: 1.6;
}
}
.confirm-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #3d7ff5;
color: #fff;
border-radius: 50rpx;
font-size: 30rpx;
border: none;
}
}
/* 弹窗遮罩 */
.modal-mask {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: flex-end;
justify-content: center;
z-index: 999;
.modal-content {
background: #fff;
border-radius: 30rpx 30rpx 0 0;
padding: 40rpx 40rpx 60rpx;
width: 100%;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
.modal-close {
position: absolute;
top: 28rpx;
right: 36rpx;
font-size: 40rpx;
color: #999;
line-height: 1;
}
.modal-title {
font-size: 34rpx;
font-weight: bold;
color: #222;
margin-bottom: 16rpx;
}
.modal-desc {
font-size: 26rpx;
color: #888;
text-align: center;
margin-bottom: 30rpx;
}
.modal-img {
width: 260rpx;
height: 200rpx;
margin-bottom: 40rpx;
}
.wx-notify-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #3d7ff5;
color: #fff;
border-radius: 50rpx;
font-size: 32rpx;
border: none;
margin-bottom: 20rpx;
}
.skip-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #f0f0f0;
color: #333;
border-radius: 50rpx;
font-size: 32rpx;
border: none;
margin-bottom: 20rpx;
}
.privacy-row {
display: flex;
align-items: center;
.privacy-icon {
color: #aaa;
font-size: 22rpx;
margin-right: 6rpx;
}
.privacy-text {
font-size: 22rpx;
color: #aaa;
}
}
}
}
</style>

View File

@ -0,0 +1,372 @@
<template>
<view class="page-bg">
<!-- 顶部标签切换 -->
<view class="tab-bar">
<view
v-for="tab in tabs"
:key="tab.value"
class="tab-item"
:class="{ active: activeTab === tab.value }"
@click="activeTab = tab.value"
>{{ tab.label }}</view>
</view>
<!-- 步骤引导条 -->
<view class="steps-bar">
<view v-for="(step, idx) in steps" :key="idx" class="step-item">
<view class="step-icon-wrap">
<image :src="step.icon" class="step-icon" mode="aspectFit" />
</view>
<text class="step-label">{{ step.label }}</text>
<view v-if="idx < steps.length - 1" class="step-line">···</view>
</view>
</view>
<!-- 功能说明标签 -->
<view class="feature-tags">
<view v-for="tag in featureTags" :key="tag" class="feature-tag">{{ tag }}</view>
</view>
<!-- 我的分享 / 分享给我的 切换 -->
<view class="sub-tabs">
<view
v-for="sub in subTabs"
:key="sub.value"
class="sub-tab"
:class="{ 'sub-tab-active': activeSubTab === sub.value }"
@click="activeSubTab = sub.value"
>{{ sub.label }}</view>
</view>
<!-- 设备列表 -->
<view class="device-list">
<!-- 我的分享列表 -->
<view v-if="activeSubTab === 'mine'">
<view
v-for="device in mySharedDevices"
:key="device.id"
class="device-item"
@click="goToDetail(device)"
>
<image :src="device.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ device.name }}</text>
<text class="device-sub">已分享{{ device.sharedCount }}</text>
</view>
<view class="arrow"></view>
</view>
</view>
<!-- 分享给我的列表 -->
<view v-if="activeSubTab === 'tome'">
<view
v-for="device in toMeDevices"
:key="device.id"
class="device-item"
>
<image :src="device.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ device.name }}</text>
<text class="device-sub">{{ device.channels }}个通道 | {{ device.serial }}</text>
</view>
<button class="quit-btn" @click="quitShare(device)">退</button>
</view>
<view v-if="!toMeDevices.length" class="empty-tip"></view>
</view>
</view>
<!-- 底部发起分享按钮 -->
<view class="bottom-bar">
<button class="share-btn" @click="goToShareTarget"></button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
activeTab: 'device',
tabs: [
{ label: '分享设备', value: 'device' },
{ label: '分享团队', value: 'team' }
],
steps: [
{ icon: '/static/images/share/step_send.png', label: '发起分享' },
{ icon: '/static/images/share/step_add.png', label: '添加分享对象' },
{ icon: '/static/images/share/step_key.png', label: '选择视频和权限' },
{ icon: '/static/images/share/step_mail.png', label: '接受分享' }
],
featureTags: ['功能按需分享', '最多分享10人', '仅视频设备'],
activeSubTab: 'mine',
subTabs: [
{ label: '我的分享', value: 'mine' },
{ label: '分享给我的', value: 'tome' }
],
// API
mySharedDevices: [
{ id: 1, name: '八方', img: '/static/images/share/camera1.png', sharedCount: 1 },
{ id: 2, name: '十方', img: '/static/images/share/camera2.png', sharedCount: 1 },
{ id: 3, name: 'DS-2DE4423DW-D/GLT/XM(...', img: '/static/images/share/camera1.png', sharedCount: 1 },
{ id: 4, name: 'DS-7804N-Z1/X(D)(FR5725238)', img: '/static/images/share/nvr.png', sharedCount: 5 }
],
//
toMeDevices: [
{ id: 5, name: 'DS-7804N-Z1/X(D)(F...', img: '/static/images/share/nvr.png', channels: 3, serial: 'FX3773731' }
]
}
},
methods: {
goToDetail(device) {
uni.navigateTo({
url: `/pages/home/invite/myShareDetail/index?id=${device.id}`
})
},
goToShareTarget() {
uni.navigateTo({ url: '/pages/home/invite/shareTarget/index' })
},
quitShare(device) {
uni.showModal({
title: '提示',
content: `确定退出【${device.name}】的分享?`,
success: (res) => {
if (res.confirm) {
this.$modal.msgSuccess('已退出分享')
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
page {
background: linear-gradient(180deg, #e8f0ff 0%, #f5f7fa 60%, #ffffff 100%);
}
.page-bg {
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 顶部Tab */
.tab-bar {
display: flex;
justify-content: center;
align-items: center;
margin: 24rpx 30rpx 0;
background: #e0e5ef;
border-radius: 40rpx;
padding: 6rpx;
.tab-item {
flex: 1;
text-align: center;
padding: 14rpx 0;
border-radius: 34rpx;
font-size: 28rpx;
color: #666;
transition: all 0.2s;
&.active {
background: #1a1a1a;
color: #fff;
font-weight: bold;
}
}
}
/* 步骤条 */
.steps-bar {
display: flex;
align-items: center;
justify-content: space-between;
margin: 30rpx 30rpx 0;
.step-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
position: relative;
}
.step-icon-wrap {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.08);
}
.step-icon {
width: 40rpx;
height: 40rpx;
}
.step-label {
font-size: 22rpx;
color: #666;
margin-top: 8rpx;
text-align: center;
}
.step-line {
position: absolute;
top: 30rpx;
right: -20rpx;
font-size: 24rpx;
color: #4a90e2;
letter-spacing: 2rpx;
}
}
/* 功能标签 */
.feature-tags {
display: flex;
margin: 20rpx 30rpx;
gap: 16rpx;
.feature-tag {
padding: 8rpx 20rpx;
border-radius: 8rpx;
font-size: 22rpx;
&:first-child {
background: rgba(8, 115, 255, 0.14);
color: rgb(45, 86, 216);
}
&:nth-child(2) {
background: #fff3e0;
color: #f5a623;
}
&:nth-child(3) {
background: #fff3e0;
color: #f5a623;
}
}
}
/* 二级Tab */
.sub-tabs {
display: flex;
margin: 30rpx 30rpx;
.sub-tab {
padding: 16rpx 30rpx;
font-size: 28rpx;
color: #999;
position: relative;
&-active {
color: #1a1a1a;
font-weight: bold;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 4rpx;
background: #1a1a1a;
border-radius: 2rpx;
}
}
}
}
/* 设备列表 */
.device-list {
margin: 16rpx 25rpx;
background: #fff;
border-radius: 16rpx;
overflow: hidden;
.device-item {
display: flex;
align-items: center;
padding: 34rpx 28rpx;
border-bottom: 1rpx solid #f2f2f2;
&:last-child { border-bottom: none; }
.device-img {
width: 90rpx;
height: 90rpx;
margin-right: 20rpx;
flex-shrink: 0;
}
.device-info {
flex: 1;
overflow: hidden;
.device-name {
font-size: 28rpx;
color: #333;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.device-sub {
font-size: 24rpx;
color: #999;
display: block;
margin-top: 6rpx;
}
}
.arrow {
color: #ccc;
font-size: 36rpx;
margin-left: 10rpx;
}
.quit-btn {
font-size: 24rpx;
color: #555;
background: #fff;
border: 2rpx solid #ddd;
border-radius: 30rpx;
padding: 10rpx 28rpx;
line-height: 1.4;
}
}
}
.empty-tip {
text-align: center;
color: #bbb;
font-size: 26rpx;
padding: 60rpx 0;
}
/* 底部按钮 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 30rpx;
background: #edf1f7;
.share-btn {
background: #3d7ff5;
color: #fff;
border-radius: 50rpx;
font-size: 32rpx;
height: 90rpx;
line-height: 90rpx;
text-align: center;
border: none;
}
}
</style>

View File

@ -0,0 +1,171 @@
<template>
<view class="page">
<!-- 手机号输入区 -->
<view class="input-row">
<input
v-model="phone"
class="phone-input"
type="number"
placeholder="请输入正确的手机号"
maxlength="11"
@input="onPhoneInput"
/>
<button class="next-btn" :disabled="!phoneValid" @click="goNext"></button>
</view>
<view class="hint-row">
<text class="hint-icon"></text>
<text class="hint-text">您正在尝试将视频分享至其他人</text>
</view>
<!-- 最近分享 -->
<view class="section-title">最近分享</view>
<view class="recent-list">
<view
v-for="item in recentList"
:key="item.id"
class="recent-item"
@click="selectRecent(item)"
>
<text class="recent-phone">{{ item.phone }}</text>
<view class="arrow"></view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
phone: '',
// API
recentList: [
{ id: 1, phone: '132*****131' },
{ id: 2, phone: '156*****228' },
{ id: 3, phone: '183*****326' },
{ id: 4, phone: '155*****330' },
{ id: 5, phone: '150*****639' }
]
}
},
computed: {
phoneValid() {
return /^1\d{10}$/.test(this.phone)
}
},
methods: {
onPhoneInput(e) {
this.phone = e.detail.value
},
selectRecent(item) {
this.phone = item.phone
this.goNext()
},
goNext() {
if (!this.phoneValid) {
uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
return
}
uni.navigateTo({
url: `/pages/home/invite/selectDevice/index?phone=${this.phone}`
})
}
}
}
</script>
<style lang="scss" scoped>
page { background: #edf1f7; }
.page {
padding: 30rpx;
background: #edf1f7;
min-height: 100vh;
}
/* 输入行 */
.input-row {
display: flex;
align-items: center;
background: #fff;
border-radius: 16rpx;
overflow: hidden;
border: 2rpx solid #3d7ff5;
.phone-input {
flex: 1;
height: 90rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #333;
background: transparent;
}
.next-btn {
width: 180rpx;
height: 90rpx;
line-height: 90rpx;
background: #3d7ff5;
color: #fff;
font-size: 28rpx;
border-radius: 0;
border: none;
margin: 0;
padding: 0;
text-align: center;
}
}
/* 提示 */
.hint-row {
display: flex;
align-items: center;
margin-top: 16rpx;
padding-left: 4rpx;
.hint-icon {
color: #aaa;
font-size: 26rpx;
margin-right: 8rpx;
}
.hint-text {
font-size: 24rpx;
color: #aaa;
}
}
/* 最近分享 */
.section-title {
font-size: 28rpx;
color: #333;
font-weight: bold;
margin: 36rpx 0 16rpx;
}
.recent-list {
background: #fff;
border-radius: 16rpx;
overflow: hidden;
.recent-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 28rpx;
border-bottom: 1rpx solid #f2f2f2;
&:last-child { border-bottom: none; }
.recent-phone {
font-size: 28rpx;
color: #333;
}
.arrow {
color: #ccc;
font-size: 36rpx;
}
}
}
</style>

View File

@ -0,0 +1,370 @@
<template>
<view class="page-bg">
<!-- 顶部标签切换 -->
<view class="tab-bar">
<view
v-for="tab in tabs"
:key="tab.value"
class="tab-item"
:class="{ active: activeTab === tab.value }"
@click="activeTab = tab.value"
>{{ tab.label }}</view>
</view>
<!-- 步骤引导条 -->
<view class="steps-bar">
<view v-for="(step, idx) in steps" :key="idx" class="step-item">
<view class="step-icon-wrap">
<image :src="step.icon" class="step-icon" mode="aspectFit" />
</view>
<text class="step-label">{{ step.label }}</text>
<view v-if="idx < steps.length - 1" class="step-line">···</view>
</view>
</view>
<!-- 功能说明标签 -->
<view class="feature-tags">
<view v-for="tag in featureTags" :key="tag" class="feature-tag">{{ tag }}</view>
</view>
<!-- 我的分享 / 分享给我的 切换 -->
<view class="sub-tabs">
<view
v-for="sub in subTabs"
:key="sub.value"
class="sub-tab"
:class="{ 'sub-tab-active': activeSubTab === sub.value }"
@click="activeSubTab = sub.value"
>{{ sub.label }}</view>
</view>
<!-- 已接受分组 -->
<view v-if="activeSubTab === 'tome'" class="device-section">
<text class="section-label">已接受</text>
<view class="device-list">
<view
v-for="device in toMeDevices"
:key="device.id"
class="device-item"
>
<image :src="device.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ device.name }}</text>
<text class="device-sub">{{ device.channels }}个通道 | {{ device.serial }}</text>
</view>
<button class="quit-btn" @click="quitShare(device)">退</button>
</view>
<view v-if="!toMeDevices.length" class="empty-tip"></view>
</view>
</view>
<!-- 我的分享列表 -->
<view v-if="activeSubTab === 'mine'" class="device-list">
<view
v-for="device in mySharedDevices"
:key="device.id"
class="device-item"
@click="goToDetail(device)"
>
<image :src="device.img" class="device-img" mode="aspectFit" />
<view class="device-info">
<text class="device-name">{{ device.name }}</text>
<text class="device-sub">已分享{{ device.sharedCount }}</text>
</view>
<view class="arrow"></view>
</view>
</view>
<!-- 底部发起分享按钮 -->
<view class="bottom-bar">
<button class="share-btn" @click="goToShareTarget"></button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
activeTab: 'device',
tabs: [
{ label: '分享设备', value: 'device' },
{ label: '分享团队', value: 'team' }
],
steps: [
{ icon: '/static/images/share/step_send.png', label: '发起分享' },
{ icon: '/static/images/share/step_add.png', label: '添加分享对象' },
{ icon: '/static/images/share/step_key.png', label: '选择视频和权限' },
{ icon: '/static/images/share/step_mail.png', label: '接受分享' }
],
featureTags: ['功能按需分享', '最多分享10人', '仅视频设备'],
activeSubTab: 'tome', // ""
subTabs: [
{ label: '我的分享', value: 'mine' },
{ label: '分享给我的', value: 'tome' }
],
toMeDevices: [
{
id: 5,
name: 'DS-7804N-Z1/X(D)(F...',
img: '/static/images/share/nvr.png',
channels: 3,
serial: 'FX3773731'
}
],
mySharedDevices: [
{ id: 1, name: '八方', img: '/static/images/share/camera1.png', sharedCount: 1 },
{ id: 2, name: '十方', img: '/static/images/share/camera2.png', sharedCount: 1 },
{ id: 3, name: 'DS-2DE4423DW-D/GLT/XM(...', img: '/static/images/share/camera1.png', sharedCount: 1 },
{ id: 4, name: 'DS-7804N-Z1/X(D)(FR5725238)', img: '/static/images/share/nvr.png', sharedCount: 5 }
]
}
},
methods: {
goToDetail(device) {
uni.navigateTo({ url: `/pages/home/invite/myShareDetail/index?id=${device.id}` })
},
goToShareTarget() {
uni.navigateTo({ url: '/pages/home/invite/shareTarget/index' })
},
quitShare(device) {
uni.showModal({
title: '提示',
content: `确定退出【${device.name}】的分享?`,
success: (res) => {
if (res.confirm) {
this.toMeDevices = this.toMeDevices.filter(d => d.id !== device.id)
uni.showToast({ title: '已退出分享', icon: 'none' })
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
page { background: #edf1f7; }
.page-bg {
min-height: 100vh;
background: #edf1f7;
padding-bottom: 120rpx;
}
.tab-bar {
display: flex;
justify-content: center;
align-items: center;
margin: 24rpx 30rpx 0;
background: #e0e5ef;
border-radius: 40rpx;
padding: 6rpx;
.tab-item {
flex: 1;
text-align: center;
padding: 14rpx 0;
border-radius: 34rpx;
font-size: 28rpx;
color: #666;
&.active {
background: #1a1a1a;
color: #fff;
font-weight: bold;
}
}
}
.steps-bar {
display: flex;
align-items: center;
justify-content: space-between;
margin: 30rpx 30rpx 0;
.step-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
position: relative;
}
.step-icon-wrap {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.08);
}
.step-icon {
width: 40rpx;
height: 40rpx;
}
.step-label {
font-size: 22rpx;
color: #666;
margin-top: 8rpx;
text-align: center;
}
.step-line {
position: absolute;
top: 30rpx;
right: -20rpx;
font-size: 24rpx;
color: #4a90e2;
letter-spacing: 2rpx;
}
}
.feature-tags {
display: flex;
margin: 20rpx 30rpx;
gap: 16rpx;
.feature-tag {
padding: 8rpx 20rpx;
border-radius: 8rpx;
font-size: 22rpx;
&:first-child { background: #e8f0fe; color: #3d7ff5; }
&:nth-child(2) { background: #fff3e0; color: #f5a623; }
&:nth-child(3) { background: #fff3e0; color: #f5a623; }
}
}
.sub-tabs {
display: flex;
margin: 0 30rpx 0;
border-bottom: 2rpx solid #e5e5e5;
.sub-tab {
padding: 16rpx 30rpx;
font-size: 28rpx;
color: #999;
position: relative;
&-active {
color: #1a1a1a;
font-weight: bold;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 4rpx;
background: #1a1a1a;
border-radius: 2rpx;
}
}
}
}
.section-label {
display: block;
font-size: 26rpx;
color: #999;
padding: 20rpx 20rpx 8rpx;
}
.device-list {
margin: 0 20rpx;
background: #fff;
border-radius: 16rpx;
overflow: hidden;
.device-item {
display: flex;
align-items: center;
padding: 24rpx 28rpx;
border-bottom: 1rpx solid #f2f2f2;
&:last-child { border-bottom: none; }
.device-img {
width: 90rpx;
height: 90rpx;
margin-right: 20rpx;
flex-shrink: 0;
}
.device-info {
flex: 1;
overflow: hidden;
.device-name {
font-size: 28rpx;
color: #333;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.device-sub {
font-size: 24rpx;
color: #999;
display: block;
margin-top: 6rpx;
}
}
.arrow {
color: #ccc;
font-size: 36rpx;
margin-left: 10rpx;
}
.quit-btn {
font-size: 24rpx;
color: #555;
background: #fff;
border: 2rpx solid #ddd;
border-radius: 30rpx;
padding: 10rpx 28rpx;
line-height: 1.4;
}
}
}
.device-section {
margin-top: 10rpx;
}
.empty-tip {
text-align: center;
color: #bbb;
font-size: 26rpx;
padding: 60rpx 0;
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 30rpx;
background: #edf1f7;
.share-btn {
background: #3d7ff5;
color: #fff;
border-radius: 50rpx;
font-size: 32rpx;
height: 90rpx;
line-height: 90rpx;
text-align: center;
border: none;
}
}
</style>

View File

@ -378,7 +378,9 @@ export default {
} }
}); });
} else if (e.content.text === '邀请用户') { } else if (e.content.text === '邀请用户') {
this.$refs.fab.close() uni.navigateTo({
url: `/pages/home/invite/shareDevice/index`
})
} }
}, },
// //

1
utils/echarts.min.js vendored Normal file

File diff suppressed because one or more lines are too long