2025年04月29日18:31:00

This commit is contained in:
luojiayi 2025-04-29 18:31:02 +08:00
parent 2b4a5a1002
commit 744295e916
21 changed files with 137 additions and 136 deletions

View File

@ -1,8 +1,8 @@
# VITE_APP_URL = 'http://192.168.3.116:8001/'
# VITE_APP_URL_WEBSOCKET = 'http://192.168.3.116:8000/api/websocket'
VITE_APP_URL = 'http://192.168.3.116:8001/'
VITE_APP_URL_WEBSOCKET = 'http://192.168.3.116:8000/api/websocket'
VITE_APP_URL = 'http://47.112.185.26:8001/'
VITE_APP_URL_WEBSOCKET = 'ws://47.112.185.26:8000/api/websocket'
# VITE_APP_URL = 'http://47.112.185.26:8001/'
# VITE_APP_URL_WEBSOCKET = 'ws://47.112.185.26:8000/api/websocket'
# VITE_APP_URL = 'http://api.handcuff.zhuhaiguangdun.cn'
# VITE_APP_URL_WEBSOCKET = 'ws://device.handcuff.zhuhaiguangdun.cn:8000/api/websocket'

1
components.d.ts vendored
View File

@ -44,7 +44,6 @@ declare module '@vue/runtime-core' {
ElUpload: typeof import('element-plus/es')['ElUpload']
Header: typeof import('./src/components/header.vue')['default']
InfoWindow: typeof import('./src/components/InfoWindow.vue')['default']
MyComm: typeof import('./src/components/MyComm.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Sidebar: typeof import('./src/components/sidebar.vue')['default']

View File

@ -12,7 +12,7 @@
securityJsCode: '83572bd6398cb4594c611f93f89b506a'
}</script>
<script
src="https://webapi.amap.com/maps?v=1.4.15&key=e1e6dde852b57c61bacdcf1af21a3d9a&plugin=AMap.MouseTool&plugin=AMap.PolygonEditor&plugin=AMap.PolyEditor&plugin=AMap.CircleEditor&plugin=AMap.MoveAnimation&plugin=AMap.PlaceSearch&plugin=AMap.AutoComplete&plugin=AMap.MoveAnimation"></script>
src="https://webapi.amap.com/maps?v=1.4.15&key=e1e6dde852b57c61bacdcf1af21a3d9a&plugin=AMap.MouseTool&plugin=AMap.MarkerClusterer=AMap.PolygonEditor&plugin=AMap.PolyEditor&plugin=AMap.CircleEditor&plugin=AMap.MoveAnimation&plugin=AMap.PlaceSearch&plugin=AMap.AutoComplete&plugin=AMap.MoveAnimation"></script>
<script src=https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js></script>
</head>

2
src/api/index.d.ts vendored
View File

@ -130,9 +130,11 @@ export namespace TLogin {
export namespace TAccount {
export interface IAdd {
id?: number | string;
username: string;
phone: string;
name: string;
password?: string;
orgId?: number | string;
roleId: number | string;
status: number;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -50,20 +50,20 @@ const onMessage = (res) => {
};
onMounted(() => {
// const isReload = localStorage.getItem("isReload");
// if (isReload !== "true") {
// ElMessageBox.alert("", "", {
// confirmButtonText: "OK",
// callback: () => {
// localStorage.setItem("isReload", "true");
// },
// });
// }
const isReload = localStorage.getItem("isReload");
if (isReload !== "true") {
ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
confirmButtonText: "OK",
callback: () => {
localStorage.setItem("isReload", "true");
},
});
}
// if (ws.socket == null) {
// ws.connect();
// }
// ws.onMessage(onMessage);
if (ws.socket == null) {
ws.connect();
}
ws.onMessage(onMessage);
window.addEventListener("beforeunload", handleBeforeUnload);
});

View File

@ -118,7 +118,6 @@ export class MapCustom {
// 创建marker
marker(option) {
return new AMap.Marker({
map: this.map,
offset: new AMap.Pixel(-13, -26),
...option
})

View File

@ -107,7 +107,7 @@ export default class WebSocketService {
onMessage = (callback) => {
this.socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data, 'onMessage');
// console.log(data, 'onMessage');
if (data.cmd == "webLogin" && !data.code == 200) return this.webScoketLogin()
callback && callback(data);

View File

@ -64,9 +64,9 @@
<el-form-item label="处理记录:" prop="content">
<el-input v-model="ruleForm.content" clearable :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" :disabled="disabled" />
</el-form-item>
<el-form-item label="处理图片:" prop="images">
<!-- <el-form-item label="处理图片:" prop="images">
<Upload v-model="ruleForm.images" :disabled="disabled" />
</el-form-item>
</el-form-item> -->
</el-form>
</div>
</div>
@ -127,7 +127,7 @@ const options = {
trigger: "axis",
formatter: function (params) {
let unit = { 0: "次/分", 1: "%", 2: "℃" };
var res = format(options.times[params[0].dataIndex]) + "<br/>";
var res = format(Number(params[0].name)) + "<br/>";
res += params
.map(function (param, index) {
return param.marker + param.seriesName + "" + param.value + unit[index] + "<br/>";
@ -149,8 +149,12 @@ const options = {
type: "category",
boundaryGap: false,
data: [],
axisLabel: {
formatter: function (item) {
return format(Number(item), "HH:mm:ss");
},
},
},
times: [],
yAxis: {
type: "value",
},
@ -270,8 +274,7 @@ const getData = async () => {
if (res.healthData && res.healthData.length) {
res.healthData.forEach((item) => {
options.times.push(item.time);
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
options.xAxis.data.push(item.time);
options.series[0].data.push(item.hr);
options.series[1].data.push(item.bo);
options.series[2].data.push(item.temp);

View File

@ -25,7 +25,7 @@ const options = {
trigger: "axis",
formatter: function (params) {
let unit = { 心率: "次/分", 血氧: "%", 体表温度: "℃" };
var res = format(options.times[params[0].dataIndex]) + "<br/>";
var res = format(Number(params[0].name)) + "<br/>";
res += params
.map(function (param, index) {
return param.marker + param.seriesName + "" + param.value + unit[param.seriesName] + "<br/>";
@ -34,10 +34,14 @@ const options = {
return res;
},
},
times: [],
xAxis: {
type: "category",
data: [],
axisLabel: {
formatter: function (item) {
return format(Number(item), "HH:mm:ss");
},
},
},
yAxis: {
type: "value",
@ -84,10 +88,10 @@ const options = {
const getOptionsData = (list: { time: string; value: number }[], name: string, color: string) => {
options.xAxis.data = [];
options.series.data = [];
if (list && list.length) {
list.forEach((item) => {
options.times.push(item.time);
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
options.xAxis.data.push(item.time);
options.series.data.push(item.value);
});
options.series.name = name;

View File

@ -54,6 +54,10 @@
<span class="lable">模式</span>
<el-tag :type="modeColor[item.mode]">{{ modeEnum[item.mode] }}</el-tag>
</div>
<div>
<span class="lable">佩戴者</span>
{{ item.userNumber || "--" }}
</div>
</div>
</template>
</el-popover>
@ -210,6 +214,10 @@ watch(
color: #787878;
font-size: 16px;
text-align: right;
width: 80px;
white-space: nowrap; //
overflow: hidden; //
text-overflow: ellipsis;
}
}
}

View File

@ -58,8 +58,9 @@ const getLocateRecord = () => {
image: ViaMarker,
size: [20, 29],
});
let markers = [];
list.forEach((item, index) => {
if (list.length < 50) {
let marker: any = "";
if (index == 0) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
@ -68,16 +69,41 @@ const getLocateRecord = () => {
} else {
marker = newMap.marker({ icon: ViaIcon, position: [item.lng, item.lat], zIndex: 12 });
}
marker.setMap(newMap.map);
marker.on("click", () => {
locationInfo.value = item;
InfoWin = newMap.infoWindow();
InfoWin.open(newMap.map, marker.getPosition());
});
markers.push(marker);
} else {
if (index % 5 == 0) {
let marker: any = "";
if (index == 0) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: startIcon, position: [item.lng, item.lat], zIndex: 13 });
} else {
marker = newMap.marker({ icon: ViaIcon, position: [item.lng, item.lat], zIndex: 12 });
}
marker.on("click", () => {
locationInfo.value = item;
InfoWin = newMap.infoWindow();
InfoWin.open(newMap.map, marker.getPosition());
});
markers.push(marker);
}
}
});
newMap.map.add(markers);
}
});
};
const fn = () => {
// this.cluster.on("click", this.clusterClickEvent);
};
onMounted(() => {
newMap = new MapCustom({ dom: "mapcontainer" });
getLocateRecord();

View File

@ -52,59 +52,6 @@ let funcList = ref([
{ title: "当前体表温度", en: "DANGQIANTIBIAOWENDU", icon: temperature, unit: "℃", num: 0, color: "#FF6905" },
]);
const options = {
tooltip: {
trigger: "axis",
formatter: function (params) {
let unit = { 心率: "次/分", 血氧: "%", 体表温度: "℃" };
var res = format(options.times[params[0].dataIndex]) + "<br/>";
res += params
.map(function (param, index) {
return param.marker + param.seriesName + "" + param.value + unit[param.seriesName] + "<br/>";
})
.join("");
return res;
},
},
times: [],
xAxis: {
type: "category",
data: [],
},
yAxis: {
type: "value",
},
grid: {
left: "5%",
right: "4%",
bottom: "20%",
},
dataZoom: [
{
show: true, //
start: 0, //
end: 10, //
bottom: "10px",
height: 25,
},
{
type: "inside",
start: 0,
end: 100,
},
],
series: {
name: "",
data: [],
type: "line",
showSymbol: false,
itemStyle: {
color: "#ff4567", // 线
},
smooth: true,
},
};
const devicePaging = reactive({
page: 1,
size: 10,
@ -135,7 +82,6 @@ const getHealthLatestData = () => {
funcList.value[0].num = res.hr;
funcList.value[1].num = res.bo;
funcList.value[2].num = res.temp;
handelRadio(devHisRef.value.radio);
});
};

View File

@ -79,6 +79,11 @@ const option = ref({
type: "category",
boundaryGap: false,
data: [],
axisLabel: {
formatter: function (item) {
return format(item, "MM-DD");
},
},
},
yAxis: {
type: "value",
@ -169,7 +174,8 @@ const getStatisticsUseCount = () => {
};
const getStatisticsContent = (req) => {
statisticsContent(req).then((res) => {
option.value.xAxis.data = res?.times;
if (res.times && res.times.length) {
option.value.xAxis.data = res.times;
option.value.series = [
{
stack: "Total",
@ -197,6 +203,7 @@ const getStatisticsContent = (req) => {
},
];
myChart.setOption(option.value);
}
});
};
const getStatisticsCount = () => {

View File

@ -7,18 +7,18 @@
<el-row :gutter="20">
<el-col :span="6">
<div class="item"><span>手铐序号</span>{{ query.id }}</div>
<div class="item"><span>绑定管理员</span>{{ query.name }}</div>
<div class="item"><span>绑定管理员</span>{{ query.adminName }}</div>
<div class="item"><span>设备状态</span>{{ statusEnum[query.status as string] }}</div>
</el-col>
<el-col :span="6">
<div class="item"><span>IMEI号</span>{{ query.deviceId }}</div>
<div class="item"><span>绑定管理者账号</span>{{ query.username }}</div>
<div class="item"><span>绑定管理者账号</span>{{ query.adminUsername }}</div>
<div class="item"><span>当前电量</span>{{ query.battery }}%</div>
</el-col>
<el-col :span="6">
<div class="item"><span>首次绑定时间</span>{{ query.createTime }}</div>
<div class="item"><span>隶属组织</span>{{ query.orgName }}</div>
<div class="item"><span>联系电话</span>{{ query.phone }}</div>
<div class="item"><span>联系电话</span>{{ query.adminPhone }}</div>
</el-col>
<el-col :span="6">
<div class="item"><span>固件版本</span>{{ query.deviceVersion }}</div>
@ -33,6 +33,9 @@
<template #status="{ rows }">
{{ recordStatusEnum[rows.status] }}
</template>
<template #operator="{ rows }">
<el-button link type="primary" size="small"> 历史记录 </el-button>
</template>
</TableCustom>
</el-card>
<el-card class="baseInfo">
@ -95,6 +98,7 @@ let record = ref([
{ prop: "userNumber", label: "佩戴者" },
{ prop: "createTime", label: "开始使用时间" },
{ prop: "updateTime", label: "结束使用时间" },
{ prop: "operator", label: "操作" },
]);
//

View File

@ -93,7 +93,7 @@ const editOp = [
//
const query = reactive({});
const searchOpt = ref<FormOptionList[]>([
{ type: "input", label: "手铐SN", prop: "deviceId" },
{ type: "input", label: "IMEI", prop: "deviceId" },
{ type: "input", label: "警察名称:", prop: "name" },
{
type: "select",

View File

@ -16,7 +16,7 @@
</el-col>
<el-col :span="12">
<el-form-item style="width: 100%" prop="userNumber" label="佩戴者编号:">
<el-input v-model="ruleForm.userNumber" placeholder="请输入佩戴者编号" clearable />
<el-input v-model="ruleForm.userNumber" :maxlength="10" placeholder="请输入佩戴者编号" clearable />
</el-form-item>
</el-col>
</el-row>

View File

@ -9,6 +9,9 @@
<el-form-item label="警员号" prop="username">
<el-input :maxlength="20" v-model="ruleForm.username" placeholder="请输入警员号" />
</el-form-item>
<el-form-item label="密码" prop="password" v-if="!ruleForm.id">
<el-input :maxlength="20" v-model="ruleForm.password" type="password" show-password placeholder="请输入警员号" />
</el-form-item>
<el-form-item label="类型" prop="roleId">
<el-select v-model="ruleForm.roleId" placeholder="请选择人员">
<el-option v-for="item in comm.roleList" :label="item.name" :value="item.id" />
@ -45,8 +48,8 @@ const { orgAllData, formData, api } = defineProps({
dfault: () => {},
},
formData: {
type: Object,
required: true,
type: Object as PropType<TAccount.IListRes>,
default: () => {},
},
api: {
type: Function,
@ -54,20 +57,20 @@ const { orgAllData, formData, api } = defineProps({
});
const emit = defineEmits(["close"]);
const ruleForm = reactive(
const ruleForm = reactive<TAccount.IAdd>(
formData
? { ...formData }
: {
name: "",
phone: "",
username: "",
password: "111111",
roleId: "",
orgId: "",
status: 1,
}
);
onMounted(() => {});
const rules = reactive<FormRules<typeof ruleForm>>({
name: [{ required: true, message: "请输入用户名称", trigger: "blur" }],
phone: [

View File

@ -1,7 +1,7 @@
<template>
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="100px">
<el-form-item label="新密码" prop="password">
<el-input v-model="ruleForm.password" type="password" placeholder="请输入新密码" />
<el-input v-model="ruleForm.password" type="password" autocomplete="new-password" show-password placeholder="请输入新密码" />
</el-form-item>
<el-form-item class="footr">