群发控制部分

This commit is contained in:
1 2025-06-23 09:15:23 +08:00
parent 179dce665a
commit 80e88714e9
2 changed files with 507 additions and 13 deletions

View File

@ -701,7 +701,7 @@
try { try {
// mp3_list // mp3_list
const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === 'mp3_list'); const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#mp3List');
if (!mp3ListModel) { if (!mp3ListModel) {
throw new Error('未找到 mp3_list 模型'); throw new Error('未找到 mp3_list 模型');
} }
@ -799,7 +799,7 @@
} }
} }
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_list'); const playListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playList');
if (playListModel) { if (playListModel) {
try { try {
const jsonStr = playListModel.shadow.replace('JSON=', ''); const jsonStr = playListModel.shadow.replace('JSON=', '');
@ -957,7 +957,7 @@
success: async (res) => { success: async (res) => {
if (res.confirm) { if (res.confirm) {
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === const playListModel = this.deviceInfo.thingsModels.find(model => model.id ===
'play_list'); '103#playList');
if (playListModel) { if (playListModel) {
try { try {
const jsonStr = playListModel.shadow.replace('JSON=', ''); const jsonStr = playListModel.shadow.replace('JSON=', '');
@ -1079,19 +1079,19 @@
if (!this.deviceInfo.thingsModels) return; if (!this.deviceInfo.thingsModels) return;
// //
const playEnModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_en'); const playEnModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playEn');
if (playEnModel) { if (playEnModel) {
this.audioEnabled = playEnModel.shadow === '1'; this.audioEnabled = playEnModel.shadow === '1';
} }
// //
const volumeModel = this.deviceInfo.thingsModels.find(model => model.id === 'volume'); const volumeModel = this.deviceInfo.thingsModels.find(model => model.id === '103#volume');
if (volumeModel) { if (volumeModel) {
this.volume = parseInt(volumeModel.shadow) || 50; this.volume = parseInt(volumeModel.shadow) || 50;
} }
// //
const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === 'mp3_list'); const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#mp3_list');
console.log('mp3ListModel:', mp3ListModel); console.log('mp3ListModel:', mp3ListModel);
if (mp3ListModel && mp3ListModel.shadow) { if (mp3ListModel && mp3ListModel.shadow) {
@ -1104,11 +1104,11 @@
console.log('parsed data:', data); console.log('parsed data:', data);
// mp3_list // mp3_list
if (data.sound_card && data.sound_card.mp3_list) { if (data && data.mp3_list) {
console.log('mp3_list:', data.sound_card.mp3_list); console.log('mp3_list:', data.mp3_list);
// //
this.audioList = data.sound_card.mp3_list.map((item, index) => { this.audioList = data.mp3_list.map((item, index) => {
// "1_def" // "1_def"
const name = item.split('_')[1] || item; const name = item.split('_')[1] || item;
console.log('item:', item, 'name:', name); console.log('item:', item, 'name:', name);
@ -1130,14 +1130,14 @@
} }
// //
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_list'); const playListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playList');
if (playListModel && playListModel.shadow) { if (playListModel && playListModel.shadow) {
try { try {
const jsonStr = playListModel.shadow.replace('JSON=', ''); const jsonStr = playListModel.shadow.replace('JSON=', '');
const data = JSON.parse(jsonStr); const data = JSON.parse(jsonStr);
if (data.sound_card && data.sound_card.play_list) { if (data && data.play_list) {
this.defaultList = data.sound_card.play_list.map((item, index) => { this.defaultList = data.play_list.map((item, index) => {
// //
const beginTime = this.formatSecondsToTime(item.time.begin); const beginTime = this.formatSecondsToTime(item.time.begin);
const endTime = this.formatSecondsToTime(item.time.end); const endTime = this.formatSecondsToTime(item.time.end);
@ -1181,7 +1181,7 @@
return weekdays; return weekdays;
}, },
async handleStatusChange(index, value) { async handleStatusChange(index, value) {
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_list'); const playListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playList');
if (playListModel) { if (playListModel) {
try { try {
const jsonStr = playListModel.shadow.replace('JSON=', ''); const jsonStr = playListModel.shadow.replace('JSON=', '');

View File

@ -62,6 +62,9 @@
<u--text margin="0 0 0 12px" prefixIcon="list-dot" <u--text margin="0 0 0 12px" prefixIcon="list-dot"
iconStyle="margin-right: 5px; font-size: 11px; color: #0BD800" size="11px" color="#0BD800" iconStyle="margin-right: 5px; font-size: 11px; color: #0BD800" size="11px" color="#0BD800"
:text="$tt('group.detail')" @click="handleEdit(item)"></u--text> :text="$tt('group.detail')" @click="handleEdit(item)"></u--text>
<u--text margin="0 0 0 12px" prefixIcon="setting"
iconStyle="margin-right: 5px; font-size: 11px; color: #FF6B35" size="11px" color="#FF6B35"
:text="'区域控制'" @click="handleAreaControl(item)"></u--text>
</view> </view>
</view> </view>
</view> </view>
@ -70,6 +73,122 @@
<u-empty mode="list" :show="total === 0" marginTop="200"></u-empty> <u-empty mode="list" :show="total === 0" marginTop="200"></u-empty>
<u-loadmore :status="status" v-if="total > queryParams.pageSize" marginTop="20" <u-loadmore :status="status" v-if="total > queryParams.pageSize" marginTop="20"
:nomoreText="$tt('group.nomore')" /> :nomoreText="$tt('group.nomore')" />
<!-- 区域控制弹窗 -->
<u-popup :show="showAreaControlPopup" @close="showAreaControlPopup = false" mode="center"
:customStyle="{ width: '700rpx', borderRadius: '20rpx' }">
<view class="area-control-popup">
<view class="popup-header">
<text class="popup-title">区域控制</text>
<u-icon name="close" size="20" @click="showAreaControlPopup = false"></u-icon>
</view>
<view class="popup-content">
<view class="group-info">
<text class="group-name">{{currentGroup.groupName}}</text>
<text class="device-count">设备数量: {{currentGroup.deviceShortV0List ? currentGroup.deviceShortV0List.length : 0}}</text>
</view>
<!-- 基础设置 -->
<view class="basic-settings">
<view class="setting-title">基础设置</view>
<!-- 音量控制 -->
<view class="volume-slider">
<view class="volume-icon">
<u-icon name="volume" size="20" color="#2979ff"></u-icon>
</view>
<view class="slider-container">
<u-slider v-model="groupVolume" :min="0" :max="100" :step="1" @change="volumeChange"
height="4" activeColor="#2979ff" blockSize="18" :showValue="false">
</u-slider>
<view class="volume-marks">
<text>0</text>
<text>50</text>
<text>100</text>
</view>
</view>
<view class="volume-value">{{ groupVolume }}%</view>
</view>
<!-- 音频开关 -->
<view class="audio-switch">
<text>音频开关</text>
<u-switch v-model="groupAudioEnabled" @change="audioSwitchChange" size="22"></u-switch>
</view>
</view>
<!-- 音频方案设置 -->
<view class="audio-scheme">
<view class="setting-title">音频方案</view>
<view class="scheme-options">
<view class="scheme-item" :class="{ active: selectedScheme === 'welcome' }" @click="selectScheme('welcome')">
<u-icon name="volume" size="24" color="#2979ff"></u-icon>
<text>欢迎语音</text>
</view>
<view class="scheme-item" :class="{ active: selectedScheme === 'alert' }" @click="selectScheme('alert')">
<u-icon name="bell" size="24" color="#ff9900"></u-icon>
<text>警报提示</text>
</view>
<view class="scheme-item" :class="{ active: selectedScheme === 'background' }" @click="selectScheme('background')">
<u-icon name="music" size="24" color="#0BD800"></u-icon>
<text>背景音乐</text>
</view>
<view class="scheme-item" :class="{ active: selectedScheme === 'custom' }" @click="selectScheme('custom')">
<u-icon name="setting" size="24" color="#839FFF"></u-icon>
<text>自定义</text>
</view>
</view>
<!-- 自定义音频设置 -->
<view class="custom-audio" v-if="selectedScheme === 'custom'">
<view class="custom-form">
<view class="form-item">
<text class="label">主持人</text>
<view class="radio-group">
<view class="radio-item" :class="{ active: customAudio.per === '0' }" @click="customAudio.per = '0'">
<text>小美</text>
</view>
<view class="radio-item" :class="{ active: customAudio.per === '1' }" @click="customAudio.per = '1'">
<text>小宇</text>
</view>
<view class="radio-item" :class="{ active: customAudio.per === '3' }" @click="customAudio.per = '3'">
<text>逍遥</text>
</view>
<view class="radio-item" :class="{ active: customAudio.per === '4' }" @click="customAudio.per = '4'">
<text>丫丫</text>
</view>
</view>
</view>
<view class="form-item">
<text class="label">合成文本</text>
<u-input v-model="customAudio.text" type="textarea" placeholder="请输入合成文本" height="80"></u-input>
</view>
</view>
</view>
</view>
<!-- 控制操作 -->
<view class="control-actions">
<view class="setting-title">快速操作</view>
<view class="action-buttons">
<view class="action-btn primary" @click="handleControlAction('all_on')">
<u-icon name="checkmark-circle" color="#fff" size="20"></u-icon>
<text>全部开启</text>
</view>
<view class="action-btn danger" @click="handleControlAction('all_off')">
<u-icon name="close-circle" color="#fff" size="20"></u-icon>
<text>全部关闭</text>
</view>
</view>
</view>
</view>
<view class="popup-footer">
<u-button @click="showAreaControlPopup = false" plain size="small">取消</u-button>
<u-button type="primary" @click="applySettings" size="small">应用设置</u-button>
</view>
</view>
</u-popup>
</view> </view>
</template> </template>
@ -83,12 +202,21 @@
status: 'loadmore', // status: 'loadmore', //
dataList: [], // dataList: [], //
total: 0, // total: 0, //
showAreaControlPopup: false, //
currentGroup: {}, //
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
userId: 0, userId: 0,
groupName: null, groupName: null,
showDevice: true, showDevice: true,
},
groupVolume: 50,
groupAudioEnabled: true,
selectedScheme: 'welcome',
customAudio: {
per: '0',
text: ''
} }
}; };
}, },
@ -153,6 +281,107 @@
item.userId item.userId
}); });
}, },
//
handleAreaControl(item) {
this.currentGroup = item;
this.showAreaControlPopup = true;
//
this.groupVolume = 50;
this.groupAudioEnabled = true;
this.selectedScheme = 'welcome';
this.customAudio = {
per: '0',
text: ''
};
},
//
handleControlAction(action) {
const groupName = this.currentGroup.groupName;
const deviceCount = this.currentGroup.deviceShortV0List ? this.currentGroup.deviceShortV0List.length : 0;
switch(action) {
case 'all_on':
uni.showModal({
title: '确认操作',
content: `确定要开启分组"${groupName}"中的所有设备吗?`,
success: (res) => {
if (res.confirm) {
this.executeControl('all_on');
}
}
});
break;
case 'all_off':
uni.showModal({
title: '确认操作',
content: `确定要关闭分组"${groupName}"中的所有设备吗?`,
success: (res) => {
if (res.confirm) {
this.executeControl('all_off');
}
}
});
break;
}
},
//
executeControl(action) {
// API
uni.showLoading({
title: '执行中...'
});
// API
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: action === 'all_on' ? '已开启所有设备' : '已关闭所有设备',
icon: 'success'
});
}, 1500);
},
//
volumeChange(value) {
this.groupVolume = value;
console.log('音量设置为:', value);
},
//
audioSwitchChange(value) {
this.groupAudioEnabled = value;
console.log('音频开关设置为:', value);
},
//
selectScheme(scheme) {
this.selectedScheme = scheme;
console.log('选择音频方案:', scheme);
},
//
applySettings() {
uni.showLoading({
title: '应用设置中...'
});
//
const settings = {
groupId: this.currentGroup.groupId,
volume: this.groupVolume,
audioEnabled: this.groupAudioEnabled,
scheme: this.selectedScheme,
customAudio: this.selectedScheme === 'custom' ? this.customAudio : null
};
console.log('应用设置:', settings);
// API
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: '设置应用成功',
icon: 'success'
});
this.showAreaControlPopup = false;
}, 1500);
},
// //
onPullDownRefresh() { onPullDownRefresh() {
this.dataList = []; this.dataList = [];
@ -260,6 +489,271 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 26rpx 22rpx; padding: 0 26rpx 22rpx;
flex-wrap: wrap;
gap: 8rpx;
}
}
}
}
//
.area-control-popup {
background: #fff;
border-radius: 20rpx;
overflow: hidden;
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
}
.popup-content {
padding: 30rpx;
.group-info {
margin-bottom: 30rpx;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
.group-name {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 10rpx;
}
.device-count {
font-size: 24rpx;
color: #666;
}
}
.basic-settings {
margin-bottom: 30rpx;
.setting-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.volume-slider {
display: flex;
align-items: center;
margin-bottom: 20rpx;
padding: 16rpx 0;
.volume-icon {
margin-right: 20rpx;
}
.slider-container {
flex: 1;
margin-right: 20rpx;
.volume-marks {
display: flex;
justify-content: space-between;
margin-top: 10rpx;
font-size: 22rpx;
color: #999;
}
}
.volume-value {
min-width: 60rpx;
text-align: right;
font-size: 24rpx;
color: #2979ff;
font-weight: 500;
}
}
.audio-switch {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
padding: 16rpx 0;
text {
font-size: 28rpx;
color: #333;
}
}
}
.audio-scheme {
margin-bottom: 30rpx;
.setting-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.scheme-options {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16rpx;
margin-bottom: 20rpx;
.scheme-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 16rpx;
background: #f8f9fa;
border-radius: 12rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
&:active {
background: #e9ecef;
border-color: #839FFF;
}
text {
margin-top: 10rpx;
font-size: 24rpx;
color: #333;
}
&.active {
background: #e8f2ff;
border-color: #839FFF;
}
}
}
}
.custom-audio {
margin-top: 20rpx;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
.custom-form {
.form-item {
margin-bottom: 20rpx;
.label {
display: block;
font-size: 26rpx;
font-weight: 600;
color: #333;
margin-bottom: 12rpx;
}
.radio-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12rpx;
.radio-item {
display: flex;
justify-content: center;
align-items: center;
padding: 12rpx 16rpx;
background: #fff;
border-radius: 8rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
&:active {
background: #f0f0f0;
}
text {
font-size: 24rpx;
color: #333;
}
&.active {
background: #e8f2ff;
border-color: #839FFF;
}
}
}
}
}
}
.control-actions {
margin-bottom: 30rpx;
.setting-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.action-buttons {
display: flex;
gap: 16rpx;
.action-btn {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 16rpx;
border-radius: 12rpx;
transition: all 0.3s;
text {
margin-top: 8rpx;
font-size: 24rpx;
color: #fff;
}
&.primary {
background: #0BD800;
&:active {
background: #09b800;
}
}
&.danger {
background: #FF6B35;
&:active {
background: #e65a25;
}
}
}
}
}
}
.popup-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-top: 1rpx solid #f0f0f0;
.u-button {
flex: 1;
margin-right: 20rpx;
&:last-child {
margin-right: 0;
} }
} }
} }