2025年04月15日10:51:09

This commit is contained in:
luojiayi 2025-04-15 10:51:12 +08:00
parent 6b04c453d9
commit 69da74f447
11 changed files with 126 additions and 25 deletions

View File

@ -1,4 +1,4 @@
import { createApp } from 'vue'; import { createApp, Directive, DirectiveBinding } from 'vue';
import { createPinia } from 'pinia'; import { createPinia } from 'pinia';
import * as ElementPlusIconsVue from '@element-plus/icons-vue'; import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import App from './App.vue'; import App from './App.vue';
@ -30,4 +30,81 @@ app.directive('permiss', {
}, },
}); });
// 注册自定义指令 v-prevent-reclick
app.directive('prevent-reclick', {
beforeMount(el, binding) {
el.disabled = false; // 初始化时启用按钮
el.addEventListener('click', (e) => {
el.disabled = true; // 点击后禁用按钮
setTimeout(() => {
el.disabled = false; // 在指定的时间后重新启用按钮
}, binding.value || 2000); // 使用 binding.value 来设置等待时间,默认为 2000 毫秒
});
},
unmounted(el) {
// 组件卸载时移除事件监听器
el.removeEventListener('click');
},
});
interface ReturnPromiseFn {
(...args: any[]): Promise<any>
}
interface objectType {
fn: ReturnPromiseFn
params?: any[]
}
const directiveBindingDirective: Directive = {
mounted(el, binding: DirectiveBinding<ReturnPromiseFn & objectType>) {
if (!binding.value) {
throw new Error('v-prevent-dup-click must pass a parameter')
}
if (typeof binding.value !== 'function' && typeof binding.value !== 'object') {
throw new Error('v-prevent-dup-click requires a function or an object with a function `fn`')
}
// 一开始是未点击状态
el.isClicked = false
const handerClick = function (event) {
// 如果已经点击过,则阻止事件
if (el.isClicked === 'true') {
event.preventDefault()
event.stopPropagation()
return
}
// 标记为已点击
el.isClicked = 'true'
// 调用传入的函数
let fn: ReturnPromiseFn
let params: any[] = []
//如果只传函数名
if (typeof binding.value == 'function') {
fn = binding.value
} else {
//如果传对象{fn:submit,params:[1,2,3]}或者{fn:submit}
fn = (binding.value as objectType).fn
params = (binding.value as objectType)?.params ?? []
}
console.log(params, 'params')
try {
fn(...params).finally(() => {
el.isClicked = false
})
} catch (error) {
throw new Error('binding.value或 binding.value.fn必须是返回Promise类型的函数')
}
}
el.hander = handerClick
el.addEventListener('click', handerClick)
},
//销毁事件
beforeUnmount(el) {
if (el.hander) {
el.removeEventListener('click', el.hander)
}
}
}
app.directive('preventDupClick', directiveBindingDirective)
app.mount('#app'); app.mount('#app');

View File

@ -58,12 +58,10 @@ export const debounce = (fn: Function, time: number = 300) => {
export const throttle = (fn: Function, time: number = 300) => { export const throttle = (fn: Function, time: number = 300) => {
let flag = true let flag = true
return function (...argu) { return function (...argu) {
if (!flag) { if (!flag) return
return
}
flag = false flag = false
let timer = setTimeout(() => {
fn(...argu) fn(...argu)
let timer = setTimeout(() => {
flag = true flag = true
clearTimeout(timer) clearTimeout(timer)
timer = null timer = null

View File

@ -2,6 +2,11 @@ import axios, { AxiosInstance, AxiosError, AxiosResponse, InternalAxiosRequestCo
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useCommonStore } from "@/store/common"; import { useCommonStore } from "@/store/common";
import router from "@/router/index"; import router from "@/router/index";
import { debounce, throttle } from '.';
const showErrorNotification = throttle((message: string) => {
ElMessage.error(message)
}, 2000); // 设置防抖的等待时间,比如 2000 毫秒
const service: AxiosInstance = axios.create({ const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_URL, baseURL: import.meta.env.VITE_APP_URL,
@ -25,13 +30,12 @@ service.interceptors.response.use(
if (headers['content-type'] === "application/vnd.ms-excel;charset=utf-8") return data if (headers['content-type'] === "application/vnd.ms-excel;charset=utf-8") return data
if (data.code !== 200) { if (data.code !== 200) {
ElMessage.error(data.msg)
if (data.code === 1003) { if (data.code === 1003) {
const comm = useCommonStore(); const comm = useCommonStore();
comm.clearStore() comm.clearStore()
router.replace('/login'); router.replace('/login');
} }
showErrorNotification(data.msg, 'error');
return Promise.reject(data); return Promise.reject(data);
} else { } else {
return data.data return data.data
@ -39,6 +43,9 @@ service.interceptors.response.use(
}, },
(error: AxiosError) => { (error: AxiosError) => {
let { message } = error;
const currentTime = Date.now();
showErrorNotification(message, 'error');
return Promise.reject(); return Promise.reject();
} }
); );

View File

@ -272,7 +272,9 @@ const handleResize = debounce(() => {
}, 200); }, 200);
onMounted(() => { onMounted(() => {
getData(); getData();
try {
map = new MapCustom({ dom: "mapcontainer", center: [116.406315, 39.908775] }); map = new MapCustom({ dom: "mapcontainer", center: [116.406315, 39.908775] });
} catch (error) {}
if (chartRef.value) { if (chartRef.value) {
myChart = echarts.init(chartRef.value); myChart = echarts.init(chartRef.value);
myChart.setOption(options); myChart.setOption(options);

View File

@ -71,11 +71,11 @@ const submitForm = async (formEl: FormInstance | undefined) => {
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@media screen and (max-width: 1350px) { // @media screen and (max-width: 950px) {
.img { // .img {
display: none; // display: none;
} // }
} // }
.login-container { .login-container {
height: 100vh; height: 100vh;

View File

@ -227,7 +227,9 @@ onMounted(() => {
getStatisticsWarningApi(); getStatisticsWarningApi();
getStatisticsUseCount(); getStatisticsUseCount();
try {
new MapCustom({ dom: "mapcontainer" }); new MapCustom({ dom: "mapcontainer" });
} catch (error) {}
if (chartRef.value) { if (chartRef.value) {
myChart = echarts.init(chartRef.value); myChart = echarts.init(chartRef.value);

View File

@ -133,9 +133,9 @@ const rules = reactive<FormRules<typeof ruleForm>>({
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
try {
mapInfo = new MapCustom({ dom: "mapcontainer" }); mapInfo = new MapCustom({ dom: "mapcontainer" });
console.log(ruleForm, "ruleForm"); } catch (error) {}
mapInfo.polyEditor(ruleForm.rails, (res) => { mapInfo.polyEditor(ruleForm.rails, (res) => {
ruleForm.rails = res; ruleForm.rails = res;
}); });

View File

@ -212,9 +212,13 @@ const handelSwitch = (val: TDevice.IListRes, type: number) => {
api({ api({
deviceId: val.deviceId, deviceId: val.deviceId,
status: type == 1 ? val.useStatus : val.deviceSwitch, status: type == 1 ? val.useStatus : val.deviceSwitch,
}).then(() => { })
.then(() => {
getData(); getData();
ElMessage.success("操作成功"); ElMessage.success("操作成功");
})
.catch(() => {
getData();
}); });
}; };

View File

@ -120,7 +120,10 @@ const getLocateRecord = () => {
}; };
onMounted(() => { onMounted(() => {
try {
newMap = new MapCustom({ dom: "mapcontainer" }); newMap = new MapCustom({ dom: "mapcontainer" });
} catch (error) {}
getLocateRecord(); getLocateRecord();
}); });
</script> </script>

View File

@ -197,7 +197,7 @@ const updateData = (res) => {
const handleResetPwd = (res) => { const handleResetPwd = (res) => {
passwordReset({ ...res, id: rowData.value.id }).then((res) => { passwordReset({ ...res, id: rowData.value.id }).then((res) => {
ElMessage.success("密码重置成功"); ElMessage.success("密码重置成功");
visible1.value = true; visible1.value = false;
}); });
}; };
const saveType = (row: TRoleModify.Ireq) => { const saveType = (row: TRoleModify.Ireq) => {

View File

@ -12,7 +12,7 @@
<template #default="{ row }"> <template #default="{ row }">
<el-checkbox value="Value 1" size="large"> <el-checkbox value="Value 1" size="large">
<template #default> <template #default>
<div class="box box1" v-if="!isCheck(ite, row)" @click="clickItem(ite, row)"> <div class="box box1" :class="{ disabled: disabled(ite, row) }" v-if="!isCheck(ite, row)" @click="clickItem(ite, row)">
<el-icon><CloseBold style="color: red" /></el-icon> <el-icon><CloseBold style="color: red" /></el-icon>
</div> </div>
<div class="box box2" v-else @click="clickItem(ite, row)"> <div class="box box2" v-else @click="clickItem(ite, row)">
@ -24,7 +24,7 @@
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column prop="date" label="操作" width="200" align="center"> <el-table-column prop="date" label="操作" width="100" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-button link type="primary" size="small" @click="handleComplete(row)">保存</el-button> <el-button link type="primary" size="small" @click="handleComplete(row)">保存</el-button>
</template> </template>
@ -65,6 +65,7 @@ const isCheck = (ite, row) => {
return flag; return flag;
}; };
const clickItem = (val, e) => { const clickItem = (val, e) => {
if (val.id == 1 && e.id <= 3) return;
let flag = e.roleMenu.some((item) => val.id == item.id); let flag = e.roleMenu.some((item) => val.id == item.id);
if (!flag) { if (!flag) {
e.roleMenu.push(val); e.roleMenu.push(val);
@ -72,6 +73,10 @@ const clickItem = (val, e) => {
e.roleMenu = e.roleMenu.filter((item) => item.id != val.id); e.roleMenu = e.roleMenu.filter((item) => item.id != val.id);
} }
}; };
const disabled = (ite, row) => {
if (ite.id == 1 && row.id <= 3) return true;
return false;
};
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@ -86,6 +91,9 @@ const clickItem = (val, e) => {
.box1 { .box1 {
background-color: #fff; background-color: #fff;
} }
.disabled {
background-color: #bababa;
}
.box2 { .box2 {
background-color: #02174f; background-color: #02174f;
} }