applications/drone-command/src/views/permissionManage/permissionRole/RolePermissionDialog.vue
@@ -20,28 +20,28 @@ :props="treeProps" /> </el-tab-pane> <el-tab-pane label="任务工单"> <el-tree class="command-tree" ref="workRef" :data="menuGrantListWord" show-checkbox node-key="id" :default-checked-keys="menuTreeObjWork" :props="treeProps" /> </el-tab-pane> <el-tab-pane label="移动app"> <el-tree class="command-tree" ref="treeMenuApp" :data="menuGrantListApp" show-checkbox node-key="id" :default-checked-keys="menuTreeObjApp" :props="treeProps" /> </el-tab-pane> <!-- <el-tab-pane label="任务工单">--> <!-- <el-tree--> <!-- class="command-tree"--> <!-- ref="workRef"--> <!-- :data="menuGrantListWord"--> <!-- show-checkbox--> <!-- node-key="id"--> <!-- :default-checked-keys="menuTreeObjWork"--> <!-- :props="treeProps"--> <!-- />--> <!-- </el-tab-pane>--> <!-- <el-tab-pane label="移动app">--> <!-- <el-tree--> <!-- class="command-tree"--> <!-- ref="treeMenuApp"--> <!-- :data="menuGrantListApp"--> <!-- show-checkbox--> <!-- node-key="id"--> <!-- :default-checked-keys="menuTreeObjApp"--> <!-- :props="treeProps"--> <!-- />--> <!-- </el-tab-pane>--> </el-tabs> <template #footer> <el-button color="#2B2B4C" @click="visible = false">取消</el-button> applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
@@ -449,8 +449,8 @@ log('✅ 已点击接听,发送 accept 给', incomingFrom) // 停止铃声 const transmitData = { data: { type: 'stopVoice' } } uni.postMessage(transmitData) // const transmitData = { data: { type: 'stopVoice' } } // uni.postMessage(transmitData) state.value = 'calling' // 如果 offer 已经提前到达(我们暂存了),立刻 answer @@ -468,8 +468,8 @@ log('❌ 已拒绝来电,发送 busy 给', incomingFrom) // 停止铃声 const transmitData = { data: { type: 'stopVoice' } } uni.postMessage(transmitData) // const transmitData = { data: { type: 'stopVoice' } } // uni.postMessage(transmitData) incomingFrom = null acceptedByMe = false @@ -522,8 +522,8 @@ function hangup() { // 停止铃声 const transmitData = { data: { type: 'stopVoice' } } uni.postMessage(transmitData) // const transmitData = { data: { type: 'stopVoice' } } // uni.postMessage(transmitData) cleanup(true) } applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/FormDiaLog.vue
New file @@ -0,0 +1,142 @@ <template> <el-dialog class="gd-dialog" v-model="visible" :title="dialogTitle" @closed="handleClosed" destroy-on-close :close-on-click-modal="false"> <!-- <div class="detail-row-view" v-if="dialogReadonly">--> <el-table :data="list" class="gd-dialog-table"> <el-table-column prop="resultCode" show-overflow-tooltip label="序号" /> <el-table-column prop="resultCode" show-overflow-tooltip label="设备状态" /> <el-table-column prop="shootTime" show-overflow-tooltip label="发生时间" /> </el-table> </el-dialog> </template> <script setup> import { computed, onMounted, ref } from 'vue' import { ElMessage } from 'element-plus' import { add, getUser, update } from '@/api/system/user' import { getDeptTree } from '@/api/system/dept' import { getRoleTree } from '@/api/system/role' import func from '@/utils/func' import { saveOperationLog } from '@ztzf/apis' import { useRoute } from 'vue-router' const list = ref([]) const initForm = () => ({ account: '', password: '', password2: '', realName: '', phone: '', email: '', sex: null, birthday: '', code: '', roleId: '', deptId: '', // sysType: 6 }) const treeProps = { label: 'title', children: 'children', } const deptTreeSelectProps = { label: 'name', value: 'id', children: 'children', } const emit = defineEmits(['success']) const formRef = ref(null) const formData = ref(initForm()) const visible = ref(false) const dialogMode = ref('add') const submitting = ref(false) const dialogReadonly = computed(() => dialogMode.value === 'view') const dialogTitle = computed(() => { if (dialogMode.value === 'edit') return '编辑' if (dialogMode.value === 'view') return '查看' return '新增' }) const roleTree = ref([]) const deptTree = ref([]) const route = useRoute() const validatePass = (rule, value, callback) => { if (value === '') { callback(new Error('请输入密码')) } else { callback() } } const validatePass2 = (rule, value, callback) => { if (value === '') { callback(new Error('请再次输入密码')) } else if (value !== formData.value.password) { callback(new Error('两次输入密码不一致')) } else { callback() } } async function getRoleTreeData() { const res = await getRoleTree('000000') roleTree.value = res.data.data } async function getDeptTreeData() { const res = await getDeptTree('000000') deptTree.value = res.data.data } function handleCancel() { visible.value = false } async function loadDetail() { if (!formData.value.id) return const res = await getUser(formData.value.id) const data = res?.data?.data ?? {} if (data.roleId) { data.roleId = func.split(data.roleId)[0] || data.roleId } formData.value = data } function handleClosed() { formData.value = initForm() } async function open({ mode, row } = {}) { dialogMode.value = mode || 'add' visible.value = true if (dialogMode.value === 'add') { formData.value = initForm() return } formData.value = { id: row.id } await loadDetail() } onMounted(() => { getRoleTreeData() getDeptTreeData() }) defineExpose({ open }) </script> <style scoped lang="scss"> :deep(.el-select) { width: 100%; } :deep(.el-date-editor) { width: 100%; } :deep(.el-tree-select) { width: 100%; } </style> applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue
New file @@ -0,0 +1,211 @@ <template> <basic-container> <el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form"> <el-form-item label="登录账号" prop="account"> <el-input class="gd-input gray" v-model="searchParams.account" placeholder="请输入" clearable @clear="handleSearch" /> </el-form-item> <el-form-item label="用户姓名" prop="realName"> <el-input class="gd-input gray" v-model="searchParams.realName" placeholder="请输入" clearable @clear="handleSearch" /> </el-form-item> <el-form-item label="所属部门" prop="deptId"> <el-tree-select class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.deptId" :data="deptTree" :props="treeProps" node-key="id" check-strictly clearable @change="handleSearch" /> </el-form-item> <el-form-item class="gd-search-actions"> <el-button :icon="RefreshRight" @click="resetForm"></el-button> <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button> </el-form-item> </el-form> <div class="gd-table-toolbar"> <el-button v-if="permission.orderUser_add" :icon="Plus" color="#4C34FF" type="primary" @click="handleAdd"> 新增 </el-button> <el-button v-if="permission.orderUser_remove" :icon="Delete" :disabled="!selectedIds.length" @click="handleDelete()" > 删除 </el-button> </div> <div class="gd-table-container" v-loading="loading"> <div class="gd-table-content gd-table-content-bg"> <el-table class="gd-table" :data="list" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="46" /> <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> <el-table-column prop="account" show-overflow-tooltip label="任务名称" /> <el-table-column prop="realName" show-overflow-tooltip label="发起任务部门" /> <el-table-column prop="roleName" show-overflow-tooltip label="任务发起人" /> <el-table-column prop="deptName" show-overflow-tooltip label="飞行时长" /> <el-table-column prop="phone" show-overflow-tooltip label="飞行里程(m)" /> <el-table-column prop="phone" show-overflow-tooltip label="执行设备" /> <el-table-column prop="phone" show-overflow-tooltip label="计划执行时间" /> <el-table-column prop="phone" show-overflow-tooltip label="实际执行时间" /> <el-table-column label="操作" class-name="operation-btns" width="180"> <template v-slot="{ row }"> <el-link @click="handleView(row)">查看</el-link> </template> </el-table-column> </el-table> </div> <div class="gd-pagination-parent"> <el-pagination popper-class="gd-select-popper" v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" layout="total, prev, pager, next, sizes" :total="total" @change="getList" /> </div> </div> <FormDiaLog ref="dialogRef" @success="getList" /> </basic-container> </template> <script setup> import { Delete, Plus, RefreshRight, Search } from '@element-plus/icons-vue' import { computed, onMounted, ref } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { getDeptTree } from '@/api/system/dept' import { getList as getUserList, remove } from '@/api/system/user' import { useStore } from 'vuex' import FormDiaLog from './FormDiaLog.vue' import { saveOperationLog } from '@ztzf/apis' import { useRoute } from 'vue-router' const initSearchParams = () => ({ account: '', realName: '', deptId: '', current: 1, size: 10, // sysType: 6 }) const searchParams = ref(initSearchParams()) const loading = ref(true) const list = ref([]) const total = ref(0) const selectedIds = ref([]) const queryParamsRef = ref(null) const dialogRef = ref(null) const deptTree = ref([]) const treeProps = { label: 'name', children: 'children', } const store = useStore() const permission = computed(() => store.getters.permission || {}) const route = useRoute() async function getList() { loading.value = true try { const res = await getUserList( searchParams.value.current, searchParams.value.size, // searchParams.value.sysType, { account: searchParams.value.account, realName: searchParams.value.realName, }, searchParams.value.deptId ) list.value = res?.data?.data?.records ?? [] total.value = res?.data?.data?.total ?? 0 } finally { loading.value = false } } function handleSearch() { searchParams.value.current = 1 getList() } function resetForm() { queryParamsRef.value?.resetFields() searchParams.value.current = 1 searchParams.value.deptId = '' getList() } function handleAdd() { dialogRef.value?.open({ mode: 'add' }) } function handleView(row) { dialogRef.value?.open({ mode: 'view', row: { ...row } }) } function handleEdit(row) { dialogRef.value?.open({ mode: 'edit', row: { ...row } }) } async function handleDelete(row) { const tips = row ? '该条' : '选中的项' await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning', customClass: 'command-page-view-message-box', confirmButtonClass: 'command-message-box-confirm', cancelButtonClass: 'command-message-box-cancel', }) const ids = row ? row.id : selectedIds.value.join(',') await remove(ids) saveOperationLog({ requestUri: route.path, title: `${route.name || '用户管理'}-删除`, type: 1 }) ElMessage.success('删除成功') selectedIds.value = [] getList() } function handleSelectionChange(rows) { selectedIds.value = rows.map(item => item.id) } function getDeptTreeList() { getDeptTree().then(res => { deptTree.value = res?.data?.data ?? [] }) } onMounted(() => { getList() getDeptTreeList() }) </script> <style scoped lang="scss"></style> applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/FormDiaLog.vue
applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/equipmentResourceApi.js
applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/index.vue
applications/task-work-order/src/views/orderView/organizational/roleMange/FormDiaLog.vue
applications/task-work-order/src/views/orderView/organizational/roleMange/RolePermissionDialog.vue
File was renamed from applications/task-work-order/src/views/orderView/systemMange/roleMange/RolePermissionDialog.vue @@ -31,17 +31,17 @@ :props="treeProps" /> </el-tab-pane> <!-- <el-tab-pane label="移动app">--> <!-- <el-tree--> <!-- class="command-tree"--> <!-- ref="treeMenuApp"--> <!-- :data="menuGrantListApp"--> <!-- show-checkbox--> <!-- node-key="id"--> <!-- :default-checked-keys="menuTreeObjApp"--> <!-- :props="treeProps"--> <!-- />--> <!-- </el-tab-pane>--> <el-tab-pane label="移动app"> <el-tree class="command-tree" ref="treeMenuApp" :data="menuGrantListApp" show-checkbox node-key="id" :default-checked-keys="menuTreeObjApp" :props="treeProps" /> </el-tab-pane> </el-tabs> <template #footer> <el-button color="#F2F3F5" @click="visible = false">取消</el-button> applications/task-work-order/src/views/orderView/organizational/roleMange/index.vue
applications/task-work-order/src/views/orderView/organizational/userMange/FormDiaLog.vue
applications/task-work-order/src/views/orderView/organizational/userMange/index.vue
uniapps/work-app/src/hooks/useGlobalWS.js
@@ -1,8 +1,9 @@ import { useUserStore } from "@/store/index.js"; import useAppStore from "../store/modules/app/index.js"; import websocketService from "@/utils/websocket.js"; // #ifdef APP-PLUS import { openDialog, allowFloat, getBatteryCapacity } from '@/uni_modules/lgh-dialog' // #endif export function useGlobalWS() { const userStore = useUserStore(); const appStore = useAppStore(); @@ -27,7 +28,7 @@ if (t === 'call') { console.log('📞 全局收到来电 call,来自', payload.from) // 播放铃声 playRingtone(); // playRingtone(); // 触发震动 triggerVibration(); // 构建来电参数 @@ -36,8 +37,9 @@ from: payload.from, type: 'incoming' }; // #ifdef APP-PLUS openDialog() // #endif // 转义参数以便在URL中传递 const encodedParams = encodeURIComponent(JSON.stringify(callParams)); @@ -58,21 +60,21 @@ } // 播放来电铃声 - 定义在 messageHandler 外部 function playRingtone() { try { if (typeof uni !== 'undefined' && uni.createInnerAudioContext) { const ringtone = uni.createInnerAudioContext(); // 使用默认铃声,注意路径写法 ringtone.src = '/static/audio/ringtone.mp3'; ringtone.loop = true; ringtone.volume = 0.8; ringtone.play(); // 存储铃声实例 ringtoneInstance = ringtone; // 使用局部变量而不是window } } catch (error) { } } // function playRingtone() { // try { // if (typeof uni !== 'undefined' && uni.createInnerAudioContext) { // const ringtone = uni.createInnerAudioContext(); // // 使用默认铃声,注意路径写法 // ringtone.src = '/static/audio/ringtone.mp3'; // ringtone.loop = true; // ringtone.volume = 0.8; // ringtone.play(); // // 存储铃声实例 // ringtoneInstance = ringtone; // 使用局部变量而不是window // } // } catch (error) { // } // } // 触发震动 function triggerVibration() { @@ -113,32 +115,32 @@ } // 停止铃声 function stopRingtone() { try { if (ringtoneInstance) { ringtoneInstance.stop(); ringtoneInstance.destroy(); ringtoneInstance = null; } } catch (error) { // 即使出错也重置实例 ringtoneInstance = null; } } // 监听停止铃声事件 if (typeof uni !== 'undefined' && uni.$on) { uni.$on('stopRingtone', stopRingtone); // 监听WebView消息事件 uni.$on('webViewMessage', (data) => { // 检查是否是停止铃声消息 if (data?.type === 'stopVoice') { stopRingtone(); console.log('📳 收到WebView停止铃声消息,已停止铃声'); } }); } // function stopRingtone() { // try { // if (ringtoneInstance) { // ringtoneInstance.stop(); // ringtoneInstance.destroy(); // ringtoneInstance = null; // } // } catch (error) { // // 即使出错也重置实例 // ringtoneInstance = null; // } // } // // // 监听停止铃声事件 // if (typeof uni !== 'undefined' && uni.$on) { // uni.$on('stopRingtone', stopRingtone); // // 监听WebView消息事件 // uni.$on('webViewMessage', (data) => { // // 检查是否是停止铃声消息 // if (data?.type === 'stopVoice') { // stopRingtone(); // console.log('📳 收到WebView停止铃声消息,已停止铃声'); // // } // }); // } // 初始化WebSocket连接 function initWS() { uniapps/work-app/src/pages/map/index.vue
@@ -23,9 +23,6 @@ const userParams = userStore?.userInfo ? JSON.stringify(userStore.userInfo) : '{}'; const updateKey = ref(0); // const viewUrl = computed(() => { // return `https://192.168.1.157:5176/mobile-web-view/#/webViewWrapper/defaultMap?params=${encodeURIComponent(userParams)}&isWeb=${envParam}&updateKey=${updateKey.value}`; // }); const viewUrl = computed(() => { return getWebViewUrl("/defaultMap", { isWeb: envParam, @@ -34,40 +31,6 @@ }); const onPostMessage = (data) => { // #ifdef MP-WEIXIN if (data.type === "scanCode") { } else if (data.type === "jumpAddWork") { } else if (data.type === "jumpMapNav") { //事件导航 } else if (data.type === "workid") { //事件详情 } // #endif // #ifndef MP-WEIXIN if (data.type === "scanCode") { uni.navigateTo({ url: "/subPackages/qrCode/index", }); } else if (data.type === "jumpAddWork") { //新建任务 const encodedData = encodeURIComponent(JSON.stringify(data.rowItem)); uni.setStorageSync("webview_params", encodedData); uni.navigateTo({ url: `/subPackages/taskDetail/addTask/index`, }); } else if (data.type === "jumpMapNav") { //事件导航 uni.navigateTo({ url: `/subPackages/workDetail/mapWork/index?currentItem=${data.eventNum}`, }); } else if (data.type === "workid") { //事件详情 uni.navigateTo({ url: `/subPackages/workDetail/index?eventNum=${data.eventNum}`, }); } // #endif }; onShow(() => { uniapps/work-app/src/subPackages/voiceCallDetail/index.vue
@@ -74,15 +74,14 @@ const contact = options.contact ? JSON.parse(decodeURIComponent(options.contact)) : null; // 构建viewUrl,将contact参数拼接到URL中 const contactParam = contact ? encodeURIComponent(JSON.stringify(contact)) : ''; // viewUrl.value = `https://192.168.1.157:5176/mobile-web-view/#/webViewWrapper/voiceCallDetail?params=${encodeURIComponent(userParams)}&contact=${contactParam}`; viewUrl.value = getWebViewUrl("/voiceCallDetail", { contact: options.contact ,voiceparams: options.voiceparams}); }); function onPostMessage(data) { // 将WebView消息传递给全局WebSocket处理 if (typeof uni !== 'undefined' && uni.$emit) { uni.$emit('webViewMessage', data); } // if (typeof uni !== 'undefined' && uni.$emit) { // uni.$emit('webViewMessage', data); // } } </script> uniapps/work-app/src/utils/common/index.js
@@ -72,8 +72,12 @@ // 1. 处理用户参数 const userParams = userStore?.userInfo ? JSON.stringify(userStore.userInfo) : '{}' // 2. 构建查询参数字符串 let queryString = `params=${encodeURIComponent(userParams)}&topMargin=${statusBarHeight}&uniPlatform=${uniPlatform}` let queryString = null if(targetUrl === '/workDetail') { queryString = `topMargin=${statusBarHeight}&uniPlatform=${uniPlatform}` }else{ queryString = `params=${encodeURIComponent(userParams)}&topMargin=${statusBarHeight}&uniPlatform=${uniPlatform}` } // 3. 处理 otherParams 对象 if (otherParams && typeof otherParams === 'object') { Object.keys(otherParams).forEach(key => {