Merge branch 'master' of http://139.196.74.78:10010/r/jagzwxm/ja_web
17 files modified
8 files renamed
1 files copied
2 files added
| | |
| | | import request from '@/axios'; |
| | | |
| | | export const getList = (current, size,sysType, params, deptId) => { |
| | | export const getList = (current, size,params, deptId) => { |
| | | return request({ |
| | | url: '/blade-system/user/page', |
| | | method: 'get', |
| | |
| | | ...params, |
| | | current, |
| | | size, |
| | | sysType, |
| | | deptId, |
| | | }, |
| | | }); |
| | |
| | | |
| | | // 新增模式绘制 |
| | | function addPolygon () { |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample = new DrawPolygon() |
| | | drawPolygonExample.initHandler(viewer) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | } |
| | |
| | | if (!formData.value?.geom) return |
| | | pointList = geomAnalysis(formData.value.geom) |
| | | drawPolygonExample?.destroy() |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample = new DrawPolygon() |
| | | let noClosedList = _.cloneDeep(pointList) |
| | | noClosedList.pop() |
| | | drawPolygonExample.initPolygon( |
| | |
| | | |
| | | // 新增模式绘制 |
| | | function addPolygon () { |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample = new DrawPolygon() |
| | | drawPolygonExample.initHandler(viewer) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | } |
| | |
| | | if (!formData.value?.geom) return |
| | | pointList = geomAnalysis(formData.value.geom) |
| | | drawPolygonExample?.destroy() |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample = new DrawPolygon() |
| | | let pointList1 = _.cloneDeep(pointList) |
| | | pointList1.pop() |
| | | drawPolygonExample.initPolygon( |
| | |
| | | :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> |
| | |
| | | code: '', |
| | | roleId: '', |
| | | deptId: '', |
| | | sysType: 5 |
| | | // sysType: 5 |
| | | }) |
| | | |
| | | const treeProps = { |
| | |
| | | deptId: '', |
| | | current: 1, |
| | | size: 10, |
| | | sysType: 5, |
| | | // sysType: 5, |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) |
| | |
| | | const res = await getUserList( |
| | | searchParams.value.current, |
| | | searchParams.value.size, |
| | | searchParams.value.sysType, |
| | | // searchParams.value.sysType, |
| | | { |
| | | account: searchParams.value.account, |
| | | realName: searchParams.value.realName, |
| | |
| | | <strong v-if="callEnded" class="status-text ended-status">{{ endMessage }}</strong> |
| | | </div> |
| | | <div class="button-group"> |
| | | <button v-if="state === 'idle' && !receiveParameters" @click="requestCall" :disabled="!connected" class="btn btn-call">呼叫</button> |
| | | <!-- <button v-if="state === 'idle' && !receiveParameters && !callEnded" @click="requestCall" :disabled="!connected" class="btn btn-call">呼叫</button> --> |
| | | |
| | | <button v-if="state==='ringing'" @click="acceptCall" class="btn btn-accept incoming-accept">接听</button> |
| | | <button v-if="state==='ringing'" @click="rejectCall" class="btn btn-reject incoming-reject">拒绝</button> |
| | |
| | | send('accept', incomingFrom, null) |
| | | log('✅ 已点击接听,发送 accept 给', incomingFrom) |
| | | |
| | | // 停止铃声 |
| | | // const transmitData = { data: { type: 'stopVoice' } } |
| | | // uni.postMessage(transmitData) |
| | | state.value = 'calling' |
| | | |
| | | // 如果 offer 已经提前到达(我们暂存了),立刻 answer |
| | |
| | | // 你后端没有 reject,用 busy 表示拒绝/不可接听 |
| | | send('busy', incomingFrom, null) |
| | | log('❌ 已拒绝来电,发送 busy 给', incomingFrom) |
| | | |
| | | // 停止铃声 |
| | | // const transmitData = { data: { type: 'stopVoice' } } |
| | | // uni.postMessage(transmitData) |
| | | |
| | | incomingFrom = null |
| | | acceptedByMe = false |
| | |
| | | } |
| | | |
| | | function hangup() { |
| | | // 停止铃声 |
| | | // const transmitData = { data: { type: 'stopVoice' } } |
| | | // uni.postMessage(transmitData) |
| | | cleanup(true) |
| | | } |
| | | |
| | |
| | | } |
| | | // 重置通话结束状态 |
| | | callEnded.value = false |
| | | }, 5000) |
| | | }, 3000) |
| | | } |
| | | } |
| | | |
| | |
| | | const imageArr = [] |
| | | const detail = workDetailData.value |
| | | if (detail.eventImageUrl) { |
| | | const smallUrl = getSmallImg(detail.eventImageUrl) |
| | | const smallUrl = detail.eventImageUrl |
| | | imageArr.push(smallUrl) |
| | | } |
| | | return imageArr |
| | | }) |
| | | const openPreview = index => { |
| | | const detail = workDetailData.value |
| | | const showUrl = getShowImg(detail.eventImageUrl) |
| | | const showUrl = detail.eventImageUrl |
| | | showImagePreview({ |
| | | images: [showUrl], |
| | | startPosition: 0, |
| | |
| | | import request from '@/axios'; |
| | | |
| | | export const getList = (current, size, sysType, params, deptId) => { |
| | | export const getList = (current, size, params, deptId) => { |
| | | return request({ |
| | | url: '/blade-system/user/page', |
| | | method: 'get', |
| | |
| | | ...params, |
| | | current, |
| | | size, |
| | | sysType, |
| | | deptId, |
| | | }, |
| | | }); |
| New file |
| | |
| | | <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> |
copy from applications/task-work-order/src/views/orderView/systemMange/userMange/index.vue
copy to applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue
| File was copied from applications/task-work-order/src/views/orderView/systemMange/userMange/index.vue |
| | |
| | | <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 width="120" 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> |
| | | <el-link v-if="permission.orderUser_edit" @click="handleEdit(row)">编辑</el-link> |
| | | <el-link v-if="permission.orderUser_remove" type="danger" @click="handleDelete(row)">删除</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | deptId: '', |
| | | current: 1, |
| | | size: 10, |
| | | sysType: 6 |
| | | // sysType: 6 |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) |
| | |
| | | const res = await getUserList( |
| | | searchParams.value.current, |
| | | searchParams.value.size, |
| | | searchParams.value.sysType, |
| | | // searchParams.value.sysType, |
| | | { |
| | | account: searchParams.value.account, |
| | | realName: searchParams.value.realName, |
| | |
| | | const suddenlyEdit = ref(false) |
| | | const processList = ref([]) |
| | | let viewPlane |
| | | let allDeviceList = [] |
| | | const hasPatrolTaskList = computed(() => ['30', '40', '50', '60'].includes(String(formData.value.workOrderStatus))) |
| | | |
| | | const gdStatusObj = { |
| | |
| | | |
| | | // 新增模式绘制 |
| | | function addPolygon() { |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample = new DrawPolygon({ deviceList: allDeviceList }) |
| | | drawPolygonExample.initHandler(viewer) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | } |
| | |
| | | if (!formData.value?.geom) return |
| | | pointList.value = geomAnalysis(formData.value.geom) |
| | | drawPolygonExample?.destroy() |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample = new DrawPolygon({ deviceList: allDeviceList }) |
| | | let noClosedList = _.cloneDeep(pointList.value) |
| | | noClosedList.pop() |
| | | drawPolygonExample.initPolygon( |
| | |
| | | }) |
| | | } |
| | | |
| | | // 生成圆形坐标点 |
| | | function buildCirclePositions(center, radius, segments = 120) { |
| | | const cartographic = Cesium.Cartographic.fromCartesian(center) |
| | | const positions = [] |
| | | for (let i = 0; i < segments; i++) { |
| | | const angle = (i / segments) * 2 * Math.PI |
| | | const lat = cartographic.latitude + (radius / 6378137) * Math.cos(angle) |
| | | const lon = cartographic.longitude + (radius / (6378137 * Math.cos(cartographic.latitude))) * Math.sin(angle) |
| | | positions.push(Cesium.Cartesian3.fromRadians(lon, lat)) |
| | | } |
| | | return positions |
| | | } |
| | | |
| | | // 渲染 |
| | | function renderingAllDevice(list) { |
| | | list.forEach(item => { |
| | |
| | | pixelOffset: new Cesium.Cartesian2(0, -20), |
| | | }, |
| | | }) |
| | | // 覆盖范围 - 5km圆形区域 |
| | | viewer.entities.add({ |
| | | position: position, |
| | | ellipse: { |
| | | semiMajorAxis: 5000, |
| | | semiMinorAxis: 5000, |
| | | material: Cesium.Color.fromBytes(45, 140, 240, 80), |
| | | outline: false, |
| | | heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, |
| | | }, |
| | | }) |
| | | // 覆盖范围描边线 - 贴地 |
| | | const circlePositions = buildCirclePositions(position, 5000) |
| | | viewer.entities.add({ |
| | | polyline: { |
| | | positions: [...circlePositions, circlePositions[0]], |
| | | clampToGround: true, |
| | | width: 2, |
| | | material: Cesium.Color.fromBytes(45, 140, 240, 255), |
| | | }, |
| | | }) |
| | | }) |
| | | } |
| | | |
| | |
| | | initMap() |
| | | const allDeviceRes = await gdManageDeviceListApi() |
| | | formData.value = dialogMode.value === 'add' ? initForm() : row |
| | | renderingAllDevice(allDeviceRes?.data?.data || []) |
| | | allDeviceList = allDeviceRes?.data?.data || [] |
| | | renderingAllDevice(allDeviceList) |
| | | if (dialogMode.value === 'add') { |
| | | addPolygon() |
| | | } else { |
| File was renamed from applications/task-work-order/src/views/orderView/systemMange/roleMange/RolePermissionDialog.vue |
| | |
| | | :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> |
| File was renamed from applications/task-work-order/src/views/orderView/systemMange/userMange/FormDiaLog.vue |
| | |
| | | code: '', |
| | | roleId: '', |
| | | deptId: '', |
| | | sysType: 6 |
| | | // sysType: 6 |
| | | }) |
| | | |
| | | const treeProps = { |
| File was renamed from applications/task-work-order/src/views/orderView/systemMange/userMange/index.vue |
| | |
| | | deptId: '', |
| | | current: 1, |
| | | size: 10, |
| | | sysType: 6 |
| | | // sysType: 6 |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) |
| | |
| | | const res = await getUserList( |
| | | searchParams.value.current, |
| | | searchParams.value.size, |
| | | searchParams.value.sysType, |
| | | // searchParams.value.sysType, |
| | | { |
| | | account: searchParams.value.account, |
| | | realName: searchParams.value.realName, |
| | |
| | | * - 外部订阅/通知机制 |
| | | */ |
| | | export class DrawPolygon { |
| | | constructor() { |
| | | constructor(options = {}) { |
| | | // 设备覆盖范围列表(经纬度 + 5000m半径) |
| | | this.deviceList = options.deviceList || [] |
| | | this.coverageRadius = 5000 |
| | | // 图斑预览模式标记 |
| | | this.isPureSpotPreview = false |
| | | // 是否删除测区 |
| | |
| | | handleLeftUp() { |
| | | if (!(this.editingMode && this.curPolygon?.positions && this.draggedEntity)) return |
| | | |
| | | // 检查松手位置是否在设备覆盖范围内 |
| | | if (this.isDragging && !this.isWithinDeviceCoverage(this.curPolygon.positions[this.draggedEntity?.customData.ind])) { |
| | | ElMessage.warning('该位置不在设备覆盖范围内,请在设备5公里范围内绘制') |
| | | // 回弹到拖拽前的位置 |
| | | this.draggedEntity.position = this.currentDragPointPosition |
| | | this.curPolygon.positions[this.draggedEntity?.customData.ind] = this.currentDragPointPosition |
| | | this.isDragging = false |
| | | this.draggedEntity = null |
| | | this.enableMapControl() |
| | | this.rebuildMidPoints() |
| | | return |
| | | } |
| | | |
| | | if (this.currentDragPointIsValid && this.isDragging) { |
| | | // 更新点位置 |
| | | this.draggedEntity.position = this.currentDragPointPosition |
| | |
| | | // 添加新的点 |
| | | const cartesian = this.viewer.scene.pickPosition(click.position) |
| | | if (!cartesian) return |
| | | |
| | | // 检查点击位置是否在设备覆盖范围内 |
| | | if (!this.isWithinDeviceCoverage(cartesian)) { |
| | | ElMessage.warning('该位置不在设备覆盖范围内,请在设备5公里范围内绘制') |
| | | return |
| | | } |
| | | |
| | | let arr = [...this.curPolygon.positions] |
| | | arr.pop() |
| | |
| | | |
| | | const menuItems = |
| | | type === 'polygon' |
| | | ? [{ title: '删除测区', class: 'del-planar-polygon' }] |
| | | ? [{ title: '删除范围', class: 'del-planar-polygon' }] |
| | | : [{ title: '删除端点', class: 'del-planar-point' }] |
| | | |
| | | menuItems.forEach(item => { |
| | |
| | | |
| | | return intersections.features.length === 0 |
| | | } |
| | | |
| | | // 检查位置是否在任意设备的覆盖范围内(5km) |
| | | isWithinDeviceCoverage(cartesian) { |
| | | if (!this.deviceList || this.deviceList.length === 0) return true |
| | | const cartographic = Cesium.Cartographic.fromCartesian(cartesian) |
| | | const clickPoint = turf.point([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)]) |
| | | return this.deviceList |
| | | .filter(item => item.latitude) |
| | | .some(item => { |
| | | const rangePoint = turf.point([item.longitude, item.latitude]) |
| | | const distance = turf.distance(rangePoint, clickPoint, { units: 'kilometers' }) |
| | | return distance <= 5 |
| | | }) |
| | | } |
| | | // 初始化已有多边形 |
| | | async initPolygon(viewer, positions, isPurePreview = false) { |
| | | this.initHandler(viewer) |
| | |
| | | allowFloat() |
| | | // #endif |
| | | |
| | | |
| | | useGlobalWS() |
| | | |
| | | onShow(async () => { |
| | |
| | | // #ifdef APP-PLUS |
| | | keepAliveStart() |
| | | // 请求用户允许忽略电池优化(重要:用于保活) |
| | | setTimeout(requestIgnoreBatteryOptimization, 120000) |
| | | setTimeout(requestIgnoreBatteryOptimization, 10000) |
| | | // #endif |
| | | } |
| | | |
| | |
| | | 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(); |
| | | const callStatus = ref(null) |
| | | // token 存储 |
| | | const accessToken = ref('') |
| | | // 存储铃声实例 |
| | | let ringtoneInstance = null |
| | | |
| | | // 设置默认用户ID为3 |
| | | const defaultUserId = '2021474815063486465'; |
| | |
| | | // 处理语音通话请求 |
| | | if (t === 'call') { |
| | | console.log('📞 全局收到来电 call,来自', payload.from) |
| | | // 播放铃声 |
| | | // playRingtone(); |
| | | // 触发震动 |
| | | triggerVibration(); |
| | | // 构建来电参数 |
| | | const callParams = { |
| | | peerUid: payload.from, |
| | | from: payload.from, |
| | | type: 'incoming' |
| | | }; |
| | | |
| | | // #ifdef APP-PLUS |
| | | openDialog() |
| | | // #endif |
| | | // 转义参数以便在URL中传递 |
| | | const encodedParams = encodeURIComponent(JSON.stringify(callParams)); |
| | | |
| | |
| | | } |
| | | return |
| | | } |
| | | |
| | | // 然后处理biz_code格式的消息 |
| | | // switch (bizCode) { |
| | | // case 'JOB_ISREFRESH': |
| | | // appStore.setJobUpdateKeyAdd() |
| | | // break |
| | | // case 'DEVICE_ISREFRESH': |
| | | // appStore.setDeviceUpdateKeyAdd() |
| | | // break |
| | | // case 'DOWNLOAD_PROGRESS': |
| | | // break |
| | | // case 'LOGOUT_USER': |
| | | // userStore.setUserInfo(null) |
| | | // uni.reLaunch({ |
| | | // url: '/pages/login/index' |
| | | // }) |
| | | // break |
| | | // case 'VoiceCall': |
| | | // // enterRoom(payload, userId.value) |
| | | // break |
| | | // default: |
| | | // // 记录未处理的消息 |
| | | // console.log('未处理的WebSocket消息:', payload) |
| | | // break; |
| | | // } |
| | | } |
| | | |
| | | // 播放来电铃声 - 定义在 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 triggerVibration() { |
| | | try { |
| | | if (typeof uni !== 'undefined') { |
| | | // 方法1:使用uni.vibrate(现代API) |
| | | if (uni.vibrate) { |
| | | // 震动400ms |
| | | uni.vibrate({ |
| | | duration: 400, |
| | | success: () => { |
| | | console.log('📳 震动已触发'); |
| | | }, |
| | | fail: (error) => { |
| | | // 方法2:使用uni.vibrateLong(兼容旧设备) |
| | | if (uni.vibrateLong) { |
| | | uni.vibrateLong({ |
| | | success: () => { |
| | | console.log('📳 兼容模式震动已触发'); |
| | | }, |
| | | fail: (err) => { |
| | | console.error('兼容模式震动失败:', err); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | // 方法3:使用plus API(H5+) |
| | | if (typeof plus !== 'undefined' && plus.device && plus.device.vibrate) { |
| | | plus.device.vibrate(400); |
| | | console.log('📳 H5+ 震动已触发'); |
| | | } |
| | | } |
| | | } catch (error) { |
| | | console.error('触发震动失败:', error); |
| | | } |
| | | } |
| | | |
| | | // 停止铃声 |
| | | // 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() { |
| | | const userStore = useUserStore() |
| | |
| | | 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, |
| | |
| | | }); |
| | | |
| | | 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(() => { |
| | |
| | | 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) {} |
| | | function onPostMessage(data) { |
| | | // 将WebView消息传递给全局WebSocket处理 |
| | | // if (typeof uni !== 'undefined' && uni.$emit) { |
| | | // uni.$emit('webViewMessage', data); |
| | | // } |
| | | } |
| | | |
| | | </script> |
| | | |
| | |
| | | // 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 => { |