mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
@@ -0,0 +1,54 @@
|
||||
import RequestService from '../httpRequest'
|
||||
import {getServiceUrl} from '../api'
|
||||
|
||||
export default {
|
||||
// 已绑设备
|
||||
getAgentBindDevices(agentId, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/device/bind/${agentId}`)
|
||||
.method('GET')
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.fail((err) => {
|
||||
console.error('获取设备列表失败:', err);
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.getAgentBindDevices(agentId, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
// 解绑设备
|
||||
unbindDevice(device_id, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/device/unbind`)
|
||||
.method('POST')
|
||||
.data({ deviceId: device_id })
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.fail((err) => {
|
||||
console.error('解绑设备失败:', err);
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.unbindDevice(device_id, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
// 绑定设备
|
||||
bindDevice(agentId, deviceCode, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/device/bind/${agentId}/${deviceCode}`)
|
||||
.method('POST')
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.fail((err) => {
|
||||
console.error('绑定设备失败:', err);
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.bindDevice(agentId, deviceCode, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
}
|
||||
@@ -21,7 +21,6 @@ export default {
|
||||
},
|
||||
// 获取验证码
|
||||
getCaptcha(uuid, callback) {
|
||||
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/user/captcha?uuid=${uuid}`)
|
||||
.method('GET')
|
||||
@@ -52,7 +51,6 @@ export default {
|
||||
.fail(() => {
|
||||
}).send()
|
||||
},
|
||||
|
||||
// 保存设备配置
|
||||
saveDeviceConfig(device_id, configData, callback) {
|
||||
RequestService.sendRequest()
|
||||
@@ -106,54 +104,4 @@ export default {
|
||||
})
|
||||
.send();
|
||||
},
|
||||
|
||||
// 已绑设备
|
||||
getAgentBindDevices(agentId, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/user/agent/device/bind/${agentId}`)
|
||||
.method('GET')
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.fail((err) => {
|
||||
console.error('获取设备列表失败:', err);
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.getAgentBindDevices(agentId, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
// 解绑设备
|
||||
unbindDevice(device_id, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/user/device/unbind/${device_id}`)
|
||||
.method('PUT')
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.fail((err) => {
|
||||
console.error('解绑设备失败:', err);
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.unbindDevice(device_id, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
// 绑定设备
|
||||
bindDevice(agentId, code, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/api/v1/user/agent/device/bind/${agentId}`)
|
||||
.method('POST')
|
||||
.data({ code })
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.fail((err) => {
|
||||
console.error('绑定设备失败:', err);
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.bindDevice(agentId, code, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
import('@/apis/module/user').then(({ default: userApi }) => {
|
||||
userApi.bindDevice(
|
||||
import('@/apis/module/device').then(({ default: deviceApi }) => {
|
||||
deviceApi.bindDevice(
|
||||
this.agentId,
|
||||
this.deviceCode, ({data}) => {
|
||||
this.loading = false;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<form>
|
||||
<el-dialog :visible.sync="value" width="400px" center>
|
||||
<div
|
||||
style="width: 40px;height: 40px;border-radius: 50%;background: #5778ff;display: flex;align-items: center;justify-content: center;">
|
||||
<img loading="lazy" src="@/assets/login/shield.png" alt="" style="width: 19px;height: 23px; filter: brightness(0) invert(1);" />
|
||||
<div style="margin: 0 10px 10px;display: flex;align-items: center;gap: 10px;font-weight: 700;font-size: 20px;text-align: left;color: #3d4566;">
|
||||
<div style="width: 40px;height: 40px;border-radius: 50%;background: #5778ff;display: flex;align-items: center;justify-content: center;">
|
||||
<img loading="lazy" src="@/assets/login/shield.png" alt="" style="width: 19px;height: 23px; filter: brightness(0) invert(1);" />
|
||||
</div>
|
||||
修改密码
|
||||
</div>
|
||||
<div style="height: 1px;background: #e8f0ff;"/>
|
||||
<div style="margin: 22px 15px;">
|
||||
@@ -109,7 +111,6 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
.input-46 {
|
||||
border: 1px solid #e4e6ef;
|
||||
background: #f6f8fb;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
<!-- 中间导航菜单 -->
|
||||
<div class="header-center">
|
||||
<div class="equipment-management" :class="{ 'active-tab': $route.path === '/home' }" @click="goHome">
|
||||
|
||||
<img loading="lazy" alt="" src="@/assets/header/robot.png" :style="{ filter: $route.path === '/home' ? 'brightness(0) invert(1)' : 'None' }"/>
|
||||
|
||||
智能体管理
|
||||
</div>
|
||||
<div class="equipment-management" :class="{ 'active-tab': $route.path === '/user-management' }" @click="goUserManagement">
|
||||
@@ -43,7 +41,6 @@
|
||||
{{ userInfo.username || '加载中...' }}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item icon="el-icon-plus" @click.native="">个人中心</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-circle-plus" @click.native="showChangePasswordDialog">修改密码</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-circle-plus-outline" @click.native="handleLogout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -128,9 +125,7 @@ export default {
|
||||
try {
|
||||
// 调用 Vuex 的 logout action
|
||||
await this.logout();
|
||||
|
||||
this.$message.success('退出登录成功');
|
||||
|
||||
this.$router.push('/login');
|
||||
} catch (error) {
|
||||
console.error('退出登录失败:', error);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="visible" width="80%" @close="handleClose">
|
||||
<el-dialog :visible.sync="localVisible" width="80%" @close="handleClose">
|
||||
<el-row class="main-container">
|
||||
<el-col :span="4">
|
||||
<el-menu class="model-menu" :default-active="activeModel" mode="vertical" @select="handleModelSelect">
|
||||
@@ -57,6 +57,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localVisible: this.visible,
|
||||
activeModel: 'EdgeTTS',
|
||||
searchQuery: '',
|
||||
editDialogVisible: false,
|
||||
@@ -72,6 +73,11 @@ export default {
|
||||
total: 20
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible(newVal) {
|
||||
this.localVisible = newVal;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredTtsModels() {
|
||||
return this.ttsModels.filter(model =>
|
||||
@@ -81,6 +87,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
this.localVisible = false;
|
||||
this.$emit('update:visible', false);
|
||||
},
|
||||
handleModelSelect(index) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'element-ui/lib/theme-chalk/index.css';
|
||||
import './styles/global.scss'
|
||||
|
||||
Vue.use(ElementUI);
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
|
||||
@@ -54,7 +54,8 @@ export function showDanger(msg) {
|
||||
}
|
||||
Message({
|
||||
message: msg,
|
||||
type: 'error'
|
||||
type: 'error',
|
||||
showClose: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,7 +69,8 @@ export function showWarning(msg) {
|
||||
}
|
||||
Message({
|
||||
message: msg,
|
||||
type: 'warning'
|
||||
type: 'warning',
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,7 +83,8 @@ export function showWarning(msg) {
|
||||
export function showSuccess(msg) {
|
||||
Message({
|
||||
message: msg,
|
||||
type: 'success'
|
||||
type: 'success',
|
||||
showClose: true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -124,31 +124,32 @@ export default {
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val;
|
||||
},
|
||||
fetchBindDevices(agentId) {
|
||||
this.loading = true;
|
||||
import('@/apis/module/user').then(({ default: userApi }) => {
|
||||
userApi.getAgentBindDevices(agentId, ({ data }) => {
|
||||
fetchBindDevices(agentId) {
|
||||
this.loading = true;
|
||||
import('@/apis/module/device').then(({ default: deviceApi }) => {
|
||||
deviceApi.getAgentBindDevices(agentId, ({ data }) => {
|
||||
this.loading = false;
|
||||
if (data.code === 0) {
|
||||
this.deviceList = data.data[0].list.map(device => ({
|
||||
device_id: device.id,
|
||||
model: device.device_type,
|
||||
firmwareVersion: device.app_version,
|
||||
macAddress: device.mac_address,
|
||||
lastConversation: device.recent_chat_time,
|
||||
remark: '',
|
||||
isEdit: false,
|
||||
otaSwitch: device.ota_upgrade === 1
|
||||
}));
|
||||
} else {
|
||||
this.$message.error(data.msg || '获取设备列表失败');
|
||||
}
|
||||
});
|
||||
}).catch(error => {
|
||||
console.error('模块加载失败:', error);
|
||||
this.$message.error('功能模块加载失败');
|
||||
this.deviceList = data.data.map(device => ({
|
||||
device_id: device.id,
|
||||
model: device.board,
|
||||
firmwareVersion: device.appVersion,
|
||||
macAddress: device.macAddress,
|
||||
bindTime: device.createDate,
|
||||
lastConversation: device.lastConnectedAt,
|
||||
remark: device.alias,
|
||||
isEdit: false,
|
||||
otaSwitch: device.autoUpdate === 1
|
||||
}));
|
||||
} else {
|
||||
this.$message.error(data.msg || '获取设备列表失败');
|
||||
}
|
||||
});
|
||||
},
|
||||
}).catch(error => {
|
||||
console.error('模块加载失败:', error);
|
||||
this.$message.error('功能模块加载失败');
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
<ModelEditDialog :visible.sync="editDialogVisible" :modelData="editModelData" @save="handleModelSave"/>
|
||||
<TtsModel :visible.sync="ttsDialogVisible" />
|
||||
<AddModelDialog :visible.sync="addDialogVisible" @confirm="handleAddConfirm"/>
|
||||
<AddModelDialog :modelType="activeTab" :visible.sync="addDialogVisible" @confirm="handleAddConfirm"/>
|
||||
</div>
|
||||
|
||||
<div class="copyright">
|
||||
@@ -234,6 +234,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .el-table tr{
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
min-width: 900px;
|
||||
min-height: 506px;
|
||||
@@ -241,8 +245,8 @@ export default {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(to bottom right, #dce8ff, #e4eeff, #e6cbfd) center;
|
||||
background-size: cover;
|
||||
background: linear-gradient(to bottom right, #dce8ff, #e4eeff, #e6cbfd) center;
|
||||
-webkit-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
}
|
||||
@@ -349,6 +353,7 @@ export default {
|
||||
height: 100%;
|
||||
min-width: 600px;
|
||||
overflow-x: auto;
|
||||
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
@@ -365,12 +370,6 @@ export default {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.action-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -386,33 +385,31 @@ export default {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.search-input .el-input__inner::placeholder {
|
||||
::v-deep .search-input .el-input__inner::placeholder {
|
||||
color: black;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.search-input .el-input__inner {
|
||||
::v-deep .search-input .el-input__inner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
background: linear-gradient(135deg, #6B8CFF, #A966FF);
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.data-table {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.data-table .el-table__row {
|
||||
.data-table /deep/ .el-table__row {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.data-table .el-table__header-wrapper {
|
||||
border-bottom: 1px solid rgb(224,227,237);
|
||||
}
|
||||
|
||||
.data-table .el-table__body td {
|
||||
border-bottom: 1px solid rgb(224,227,237) !important;
|
||||
}
|
||||
|
||||
.table-header th {
|
||||
background-color: transparent !important;
|
||||
color: #606266;
|
||||
@@ -433,11 +430,6 @@ export default {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
text-align: center;
|
||||
color: #979db1;
|
||||
@@ -452,16 +444,6 @@ export default {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.el-button {
|
||||
img {
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
padding-right: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
background: #cce5f9;
|
||||
width: 75px;
|
||||
@@ -470,12 +452,94 @@ export default {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
background: linear-gradient(135deg, #6B8CFF, #A966FF);
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.batch-actions .el-button:first-child {
|
||||
background: linear-gradient(135deg, #409EFF, #6B8CFF);
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.batch-actions .el-button:first-child:hover {
|
||||
background: linear-gradient(135deg, #3A8EE6, #5A7CFF);
|
||||
}
|
||||
|
||||
.el-table th /deep/ .el-table__cell {
|
||||
overflow: hidden;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
::v-deep .el-table .custom-selection-header .cell .el-checkbox__inner {
|
||||
display: none !important; /* 使表头复选框不可见 */
|
||||
}
|
||||
|
||||
::v-deep .el-table .custom-selection-header .cell::before {
|
||||
content: '选择';
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 0;
|
||||
color: black;
|
||||
margin-top: 23px;
|
||||
}
|
||||
|
||||
::v-deep .el-table__body .el-checkbox__inner {
|
||||
display: inline-block !important;
|
||||
background: #e6edfa;
|
||||
}
|
||||
|
||||
::v-deep .el-table thead th:not(:first-child) .cell {
|
||||
color: #303133 !important;
|
||||
}
|
||||
|
||||
::v-deep .nav-panel .el-menu-item.is-active .menu-text {
|
||||
color: #409EFF !important;
|
||||
}
|
||||
|
||||
::v-deep .data-table {
|
||||
&.el-table::before,
|
||||
&.el-table::after,
|
||||
&.el-table__inner-wrapper::before {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .data-table .el-table__header-wrapper {
|
||||
border-bottom: 1px solid rgb(224,227,237);
|
||||
}
|
||||
|
||||
::v-deep .data-table .el-table__body td {
|
||||
border-bottom: 1px solid rgb(224,227,237) !important;
|
||||
}
|
||||
|
||||
.el-button img{
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
padding-right: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
::v-deep .el-checkbox__inner {
|
||||
border-color: #cfcfcf !important;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
::v-deep .el-checkbox__input.is-checked .el-checkbox__inner {
|
||||
background-color: #409EFF !important;
|
||||
border-color: #409EFF !important;
|
||||
}
|
||||
|
||||
.voice-management-btn {
|
||||
background: #9db3ea;
|
||||
color: white;
|
||||
@@ -487,75 +551,27 @@ export default {
|
||||
}
|
||||
|
||||
.voice-management-btn:hover {
|
||||
background: #8aa2e0;
|
||||
background: #8aa2e0; /* 悬停时颜色加深 */
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
::v-deep .el-table .el-table-column--selection .cell {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
|
||||
::v-deep .el-table .el-table__fixed-right .cell {
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
.edit-btn, .delete-btn {
|
||||
margin: 0 8px;
|
||||
color: #7079aa !important;
|
||||
}
|
||||
|
||||
/* 深度选择器合并 */
|
||||
::v-deep {
|
||||
.el-table tr {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.el-table .custom-selection-header .cell .el-checkbox__inner {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.el-table .custom-selection-header .cell::before {
|
||||
content: '选择';
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 0;
|
||||
color: black;
|
||||
margin-top: 23px;
|
||||
}
|
||||
|
||||
.el-table__body .el-checkbox__inner {
|
||||
display: inline-block !important;
|
||||
background: #e6edfa;
|
||||
}
|
||||
|
||||
.el-table thead th:not(:first-child) .cell {
|
||||
color: #303133 !important;
|
||||
}
|
||||
|
||||
.nav-panel .el-menu-item.is-active .menu-text {
|
||||
color: #409EFF !important;
|
||||
}
|
||||
|
||||
.el-checkbox__inner {
|
||||
border-color: #cfcfcf !important;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.el-checkbox__input.is-checked .el-checkbox__inner {
|
||||
background-color: #409EFF !important;
|
||||
border-color: #409EFF !important;
|
||||
}
|
||||
|
||||
.el-table .el-table-column--selection .cell {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
|
||||
.el-table .el-table__fixed-right .cell {
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
.el-table .cell {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.data-table.el-table::before,
|
||||
.data-table.el-table::after,
|
||||
.data-table.el-table__inner-wrapper::before {
|
||||
display: none !important;
|
||||
}
|
||||
::v-deep .el-table .cell {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user