冰雪App 人员管理

This commit is contained in:
huangchenhao 2025-11-20 16:27:59 +08:00
parent 695c4b75b0
commit 1b24580628
8 changed files with 618 additions and 166 deletions

View File

@ -22,10 +22,15 @@ const routes = [
component: () => import('../views/Material/MaterialManagement.vue') component: () => import('../views/Material/MaterialManagement.vue')
}, },
{ {
path: '/staffManage', path: '/staffManage/:data',
name: 'StaffManage', name: 'StaffManage',
component: () => import('../views/Staff/StaffManagement.vue') component: () => import('../views/Staff/StaffManagement.vue')
}, },
{
path: '/staffDetail/:data',
name: 'StaffDetail',
component: () => import('../views/Staff/StaffDetail.vue')
},
{ {
path: '/equipDetail/:data', path: '/equipDetail/:data',
name: 'EquipDetail', name: 'EquipDetail',

View File

@ -6,7 +6,7 @@
<van-cell title="当前站点" :value="equipmentInfo.sbwz" /> <van-cell title="当前站点" :value="equipmentInfo.sbwz" />
</van-cell-group> </van-cell-group>
<div class="content"> <div class="content" v-if="equipmentDetailInfo">
<van-cell-group> <van-cell-group>
<van-cell <van-cell
title="设备信息" title="设备信息"
@ -657,7 +657,7 @@ const onSelect = (action) => {
}; };
const equipmentInfo = ref({}); const equipmentInfo = ref({});
const yhzInfo = ref({}); const yhzInfo = ref({});
const equipmentDetailInfo = ref({}); const equipmentDetailInfo = ref();
const photos = ref([]); const photos = ref([]);
const statusList = ref([]); const statusList = ref([]);

View File

@ -3,7 +3,7 @@
<van-nav-bar title="愉快政" fixed left-arrow /> <van-nav-bar title="愉快政" fixed left-arrow />
<van-cell-group> <van-cell-group>
<van-cell title="当前站点" :value="detailData.mc" /> <van-cell title="当前站点" :value="yhzinfo.mc" />
</van-cell-group> </van-cell-group>
<div class="content"> <div class="content">
@ -13,7 +13,7 @@
text="设备管理" text="设备管理"
:to="{ :to="{
name: 'EquipManage', name: 'EquipManage',
params: { data: encodeURIComponent(JSON.stringify(detailData)) }, params: { data: encodeURIComponent(JSON.stringify(yhzinfo)) },
}" }"
/> />
<van-grid-item <van-grid-item
@ -21,25 +21,46 @@
text="物资管理" text="物资管理"
:to="{ :to="{
name: 'MaterialManage', name: 'MaterialManage',
params: { data: encodeURIComponent(JSON.stringify(detailData)) }, params: { data: encodeURIComponent(JSON.stringify(yhzinfo)) },
}"
/>
<van-grid-item
icon="setting-o"
text="人员管理"
:to="{
name: 'StaffManage',
params: { data: encodeURIComponent(JSON.stringify(yhzinfo)) },
}" }"
/> />
<van-grid-item icon="setting-o" text="人员管理" to="/StaffManage" />
<van-grid-item <van-grid-item
icon="setting-o" icon="setting-o"
text="冰雪灾害" text="冰雪灾害"
:to="{ :to="{
name: 'IceEventManage', name: 'IceEventManage',
params: { data: encodeURIComponent(JSON.stringify(detailData)) }, params: { data: encodeURIComponent(JSON.stringify(yhzinfo)) },
}" }"
/> />
</van-grid> </van-grid>
</div> </div>
<van-popup
<!-- <van-tabbar v-model="active" route> :show="YHZConfirmpopup"
<van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item> position="center"
<van-tabbar-item icon="user-o" to="/user">我的</van-tabbar-item> round
</van-tabbar> --> close-on-click-overlay
:style="{ height: '20%', width: '80%' }"
@close="onYHZConfirmClose"
class="confirmpopup"
>
<div class="confirmpopup__content">
<h3>请在服务站授权定位</h3>
</div>
<div class="btn-box">
<van-button class="btn" @click="onYHZConfirmClose">取消</van-button>
<van-button class="btn" type="primary" @click="getLocation"
>授权定位</van-button
>
</div>
</van-popup>
</div> </div>
</template> </template>
@ -52,32 +73,11 @@ import { showToast } from "vant";
import { request } from "../../../shared/utils/request"; import { request } from "../../../shared/utils/request";
const router = useRouter(); const router = useRouter();
const active = ref(0);
const detailData = ref({});
const yhzinfo = ref({}); const yhzinfo = ref({});
//
const getYHZDetail = async () => {
try {
const res = await request({
url: `/snow-ops-platform/yhz/getById?id=${yhzinfo.value.id}`,
method: "GET",
});
if (res.code && res.code === "00000") {
detailData.value = res.data;
} else {
throw new Error(res.message);
}
} catch (error) {
showToast({
message: error.message,
type: "error",
});
}
};
const route = useRoute(); const route = useRoute();
const token = route.query.token; const token = route.query.token;
const YHZConfirmpopup = ref(false);
// //
const getYHZinfo = async () => { const getYHZinfo = async () => {
@ -99,6 +99,10 @@ const getYHZinfo = async () => {
} }
}; };
const onYHZConfirmClose = () => {
YHZConfirmpopup.value = false;
};
onMounted(async () => { onMounted(async () => {
if (token) { if (token) {
localStorage.setItem("token", token); localStorage.setItem("token", token);
@ -107,7 +111,12 @@ onMounted(async () => {
}); });
} }
await getYHZinfo(); await getYHZinfo();
await getYHZDetail(); if (
yhzinfo.value.isManager &&
(yhzinfo.value.jd === "" || yhzinfo.value.wd === "")
) {
YHZConfirmpopup.value = true;
}
}); });
const goToUser = () => { const goToUser = () => {
@ -117,7 +126,7 @@ const goToUser = () => {
<style scoped> <style scoped>
.home { .home {
padding-top: var(--van-nav-bar-height); /* 自动匹配导航栏高度 */ padding-top: var(--van-nav-bar-height);
} }
.content { .content {
@ -128,7 +137,17 @@ const goToUser = () => {
margin-top: 16px; margin-top: 16px;
} }
.btn-box {
width: 100%;
display: flex;
gap: 16px;
padding: 16px;
}
.btn { .btn {
margin-top: 24px; width: 50%;
}
.confirmpopup__content {
padding: 20px;
} }
</style> </style>

View File

@ -6,7 +6,7 @@
<van-cell title="当前站点" :value="yhzDetail.mc" /> <van-cell title="当前站点" :value="yhzDetail.mc" />
</van-cell-group> </van-cell-group>
<div class="content"> <div class="content" v-if="eventDetailData">
<van-cell-group> <van-cell-group>
<van-cell <van-cell
title="基本信息" title="基本信息"
@ -94,9 +94,11 @@
> >
</van-cell> </van-cell>
<van-cell <van-cell
v-if = 'eventDetailData?.traffic?.hasStrandedVehicles === 1' v-if="eventDetailData?.traffic?.hasStrandedVehicles === 1"
:title=" :title="
'滞留车辆数:' + eventDetailData?.traffic?.strandedVehicleCount + ' 辆' '滞留车辆数:' +
eventDetailData?.traffic?.strandedVehicleCount +
' 辆'
" "
> >
</van-cell> </van-cell>
@ -106,11 +108,7 @@
" "
> >
</van-cell> </van-cell>
<van-cell <van-cell :title="'附件: '">
:title="
'附件: '
"
>
<template #label> <template #label>
<van-image <van-image
v-for="(item, index) in eventDetailData?.photos" v-for="(item, index) in eventDetailData?.photos"
@ -118,6 +116,8 @@
:src="item.photoUrl" :src="item.photoUrl"
fit="cover" fit="cover"
width="100px" width="100px"
height="100px"
style="margin: 10px"
@click="showImage(item.photoUrl)" @click="showImage(item.photoUrl)"
></van-image> ></van-image>
</template> </template>
@ -138,7 +138,7 @@ const route = useRoute();
const yhzDetail = ref({}); const yhzDetail = ref({});
const event = ref(); const event = ref();
const eventDetailData = ref({}); // const eventDetailData = ref(); //
// //
const getEventDetailData = async () => { const getEventDetailData = async () => {

View File

@ -6,7 +6,7 @@
<van-cell title="当前站点" :value="yhzDetail.mc" /> <van-cell title="当前站点" :value="yhzDetail.mc" />
</van-cell-group> </van-cell-group>
<div class="content"> <div class="content" v-if="wzDetailData">
<van-cell-group> <van-cell-group>
<van-cell <van-cell
title="物资信息" title="物资信息"
@ -109,7 +109,7 @@ const route = useRoute();
const yhzDetail = ref({}); const yhzDetail = ref({});
const wzData = ref([]); const wzData = ref([]);
const wzDetailData = ref({}); // const wzDetailData = ref(); //
const photos = ref([]); // const photos = ref([]); //
onMounted(() => { onMounted(() => {

View File

@ -441,7 +441,7 @@ const handleGetLocation = async () => {
loadingToast.close(); loadingToast.close();
} else { } else {
loadingToast.close(); loadingToast.close();
showToast(result); showToast("定位失败 请检查网络情况后重试");
console.log("result", result); console.log("result", result);
} }
}); });

View File

@ -0,0 +1,239 @@
<template>
<div class="home">
<van-nav-bar title="人员管理" fixed left-arrow @click-left="onClickLeft" />
<van-cell-group>
<van-cell title="当前站点" :value="yhzDetail.mc" />
</van-cell-group>
<div class="content" v-if="staffDetailData">
<van-cell-group>
<van-cell
title="人员信息"
style="font-size: 18px; font-weight: bold; line-height: inherit"
>
</van-cell>
<van-cell :title="'姓名: ' + staffDetailData.xm"></van-cell>
<van-cell :title="'手机号码: ' + staffDetailData.sjhm"> </van-cell>
<van-cell :title="'岗位: ' + staffDetailData.gw"> </van-cell>
<van-cell :title="'登记日期: ' + staffDetailData.cjsj"> </van-cell>
<van-cell
:title="
'人员角色: ' +
(staffDetailData.ryjs === 1
? '负责人'
: staffDetailData.ryjs === 2
? '一般工作人员'
: '未知角色')
"
>
</van-cell>
</van-cell-group>
</div>
<van-tabbar>
<van-tabbar-item>
<template #default>
<van-button
type="primary"
style="width: 100px; border-radius: 10px"
@click="onEditPopupOpen"
>
编辑
</van-button>
</template>
</van-tabbar-item>
<van-tabbar-item>
<template #default>
<van-button
type="primary"
style="width: 100px; border-radius: 10px"
@click="onEditPopupOpen"
>
重置密码
</van-button>
</template>
</van-tabbar-item>
<van-tabbar-item>
<template #default>
<van-button
type="danger"
style="width: 100px; border-radius: 10px"
@click="onDeletePopupOpen"
>
删除人员
</van-button>
</template>
</van-tabbar-item>
</van-tabbar>
<van-popup
:show="showDeletePopup"
position="bottom"
closeable
close-on-click-overlay
:style="{ height: '20%' }"
@close="onDeletePopupClose"
>
<div
style="
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 16px;
"
>
<h1
style="
margin: 0 0 20px 0;
font-size: 18px;
color: #333;
text-align: center;
"
>
确认删除
</h1>
<div style="display: flex; gap: 20px; width: 100%">
<van-button
type="default"
style="flex: 1; border-radius: 8px"
@click="onDeletePopupClose"
>
取消
</van-button>
<van-button
type="primary"
style="flex: 1; border-radius: 8px"
@click="onDeleteConfirm"
>
确认
</van-button>
</div>
</div>
</van-popup>
</div>
</template>
<script setup>
import { ref, onMounted, toRaw, reactive } from "vue";
import { useRouter, useRoute } from "vue-router";
import { showToast, showLoadingToast, showImagePreview } from "vant";
import { request } from "../../../../shared/utils/request";
const router = useRouter();
const route = useRoute();
const yhzDetail = ref({});
const staffData = ref([]);
const staffDetailData = ref(); //
onMounted(() => {
const data = JSON.parse(decodeURIComponent(route.params.data));
yhzDetail.value = data.yhzDetail;
staffData.value = data.staffData;
console.log("传递过来的参数:", data);
getStaffDetail();
});
const onClickLeft = () => {
router.push({
name: "StaffManage",
params: { data: encodeURIComponent(JSON.stringify(yhzDetail.value)) },
});
};
//
const getStaffDetail = async () => {
try {
const res = await request({
url: `/snow-ops-platform/yhzry/getById?id=${staffData.value.id}`,
method: "GET",
});
if (res.code === "00000") {
staffDetailData.value = res.data;
} else {
throw new Error(res.message);
}
} catch (error) {
showToast({ type: "fail", message: error.message });
}
};
//
const showDeletePopup = ref(false);
const onDeletePopupOpen = () => {
showDeletePopup.value = true;
};
const onDeletePopupClose = () => {
showDeletePopup.value = false;
};
const onDeleteConfirm = async () => {
try {
showLoadingToast({
message: "删除中...",
forbidClick: true,
loadingType: "spinner",
});
const res = await request({
url: `/snow-ops-platform/yhzry/delete`,
method: "POST",
data: {
id: staffData.value.id,
},
});
if (res.code === "00000") {
showToast({ type: "success", message: "删除成功" });
router.push({
name: "StaffManage",
params: {
data: encodeURIComponent(JSON.stringify(yhzDetail.value)),
},
});
} else {
throw new Error(res.data.message);
}
} catch (error) {
showToast({ type: "error", message: "删除失败" });
console.log("error", error);
}
showDeletePopup.value = false;
};
</script>
<style scoped>
.home {
padding-top: var(--van-nav-bar-height); /* 自动匹配导航栏高度 */
}
.content {
padding: 16px 16px 80px 16px;
}
.grid {
margin-top: 16px;
}
.btn {
margin-top: 24px;
}
.status-tag {
display: inline-block;
padding: 3px 8px;
border-radius: 4px;
color: white;
font-size: 12px;
}
.status-good {
background-color: #07c160;
}
.status-warning {
background-color: #ff976a;
}
.status-danger {
background-color: #ee0a24;
}
</style>

View File

@ -4,35 +4,44 @@
</van-nav-bar> </van-nav-bar>
<van-search <van-search
shape="round" shape="round"
:value="searchValue" v-model="searchValue"
:show-action="false" :show-action="false"
placeholder="请输入人员" placeholder="请输入人员名"
/> />
<van-cell-group> <van-cell-group>
<van-cell title="当前站点" value="李家坝仓库" /> <van-cell title="当前站点" :value="yhzDetail.mc" />
</van-cell-group> </van-cell-group>
<div class="content"> <div class="content">
<van-cell-group> <van-cell-group>
<van-cell <van-cell
title="张三" v-for="(item, index) in staffList"
:key="index"
:title="item.xm"
is-link is-link
value="作业人员" :value="
> item.ryjs === 1
</van-cell> ? '负责人'
<van-cell title="李四" is-link value="站长"> : item.ryjs === 2
</van-cell> ? '一般工作人员'
<van-cell title="王麻子" is-link value="站长,作业人员"> : '其他'
</van-cell> "
:to="{
name: 'StaffDetail',
params: {
data: encodeURIComponent(
JSON.stringify({
yhzDetail: yhzDetail,
staffData: item,
})
),
},
}"
></van-cell>
</van-cell-group> </van-cell-group>
</div> </div>
<van-button <van-button type="primary" class="add-btn" icon="plus" @click="handleAdd">
type="primary"
class="add-btn"
icon="plus"
@click="handleAdd"
>
添加人员 添加人员
</van-button> </van-button>
@ -46,49 +55,222 @@
@close="onPopupClose" @close="onPopupClose"
> >
<div class="popup-content"> <div class="popup-content">
<h3>添加新人员</h3> <h3>添加人员</h3>
<van-search
shape="round"
v-model="addSearchValue"
:show-action="false"
placeholder="请输入电话号码或姓名"
/>
<van-cell-group class="add-cell-group">
<van-cell
v-for="item in personList"
:key="item.userId"
:title="item.realName"
:label="`电话:${item.phone}`"
clickable
@click="handleRadioClick(item)"
>
<template #right-icon>
<van-radio
:name="item.userId"
v-model="selectedUserId"
@click.stop="handleRadioClick(item)"
/>
</template>
</van-cell>
</van-cell-group>
<div
style="
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 16px;
background: white;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 100;
"
>
<van-button
round
block
type="primary"
native-type="submit"
@click="handleConfirmAdd"
>
确认添加
</van-button>
</div>
</div> </div>
</van-popup> </van-popup>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, onMounted, reactive, toRaw, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { showToast } from "vant"; import { showToast } from "vant";
import { request } from "../../../../shared/utils/request";
const route = useRoute();
const router = useRouter();
const searchValue = ref(""); //
const showPopup = ref(false); //
const yhzDetail = ref({}); //
const staffList = ref([]); //
const addSearchValue = ref(""); //
const personList = ref([]); //
const selectedUserId = ref(null); // id
const selectedUser = ref(null); //
const router = useRouter(); //
const searchValue = ref(""); // const getStaffList = async (xm) => {
const showPopup = ref(false); // try {
const yhzid = yhzDetail.value.id;
if (!yhzid) {
return;
}
const data = {
pageNum: 1,
pageSize: 9999,
yhzid,
xm,
};
const res = await request({
url: "/snow-ops-platform/yhzry/list",
method: "get",
params: data,
});
if (res.code === "00000") {
staffList.value = res.data.records;
}
} catch (error) {}
};
const onClickLeft = () => { //
onMounted(() => {
yhzDetail.value = JSON.parse(decodeURIComponent(route.params.data));
getStaffList();
});
watch(
() => searchValue.value,
(newVal, oldVal) => {
if (newVal !== oldVal) {
getStaffList(newVal);
}
}
);
const onClickLeft = () => {
router.push("/"); router.push("/");
}; };
const handleAdd = () => { //
const getPersonList = async (key) => {
try {
const keyword = key;
let url = "";
if (keyword) {
url = `/snow-ops-platform/yhzry/getUserByKey?key=${keyword}`;
} else {
url = `/snow-ops-platform/yhzry/getUserByKey?key=`;
}
const res = await request({
url: url,
method: "GET",
});
if (res.code === "00000") {
personList.value = res.data;
} else {
throw new Error(res.message);
}
} catch (error) {
showToast({
type: "error",
message: error.message || "获取人员列表失败",
});
}
};
//
const handleAdd = async () => {
await getPersonList();
showPopup.value = true; showPopup.value = true;
}; };
const onPopupClose = () => { //
showPopup.value = false; const handleRadioClick = (item) => {
selectedUserId.value = item.userId;
selectedUser.value = {
xm: item.realName,
sjhm: item.phone,
yhzid: yhzDetail.value.id,
ryjs: 2,
userId: item.userId,
}; };
</script> };
watch(
() => addSearchValue.value,
(newVal, oldVal) => {
if (newVal !== oldVal) {
getPersonList(newVal);
}
}
);
const onPopupClose = () => {
selectedUserId.value = null;
selectedUser.value = null;
addSearchValue.value = "";
personList.value = [];
showPopup.value = false;
};
//
const handleConfirmAdd = async () => {
try {
// console.log('toRaw(selectedUser.value)',toRaw(selectedUser.value));
const res = await request({
url: "/snow-ops-platform/yhzry/add",
method: "POST",
data: toRaw(selectedUser.value),
});
if (res.code === "00000") {
showToast({
type: "success",
message: "添加人员成功",
});
onPopupClose();
getStaffList(searchValue.value);
} else {
throw new Error(res.message);
}
} catch (error) {
showToast({
type: "fail",
message: error.message || "添加人员失败",
});
}
};
</script>
<style scoped> <style scoped>
.home { .home {
padding-top: var(--van-nav-bar-height); /* 自动匹配导航栏高度 */ padding-top: var(--van-nav-bar-height); /* 自动匹配导航栏高度 */
} }
.content { .content {
padding: 16px; padding: 16px;
} }
.content .van-cell-group .van-cell { .content .van-cell-group .van-cell {
margin-bottom: 10px; margin-bottom: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
} }
.add-btn { .add-btn {
position: fixed; position: fixed;
bottom: 20px; bottom: 20px;
left: 16px; left: 16px;
@ -99,31 +281,38 @@
font-size: 16px; font-size: 16px;
height: 44px; height: 44px;
z-index: 999; z-index: 999;
} }
.grid { .grid {
margin-top: 16px; margin-top: 16px;
} }
.btn { .btn {
margin-top: 24px; margin-top: 24px;
} }
.status-tag { .status-tag {
display: inline-block; display: inline-block;
padding: 3px 8px; padding: 3px 8px;
border-radius: 4px; border-radius: 4px;
color: white; color: white;
font-size: 12px; font-size: 12px;
} }
.status-good { .status-good {
background-color: #07c160; background-color: #07c160;
} }
.status-warning { .status-warning {
background-color: #ff976a; background-color: #ff976a;
} }
.status-danger { .status-danger {
background-color: #ee0a24; background-color: #ee0a24;
} }
</style> .popup-content {
padding: 16px 16px 80px 16px;
}
.add-cell-group {
height: calc(100vh * 0.8 - 200px);
overflow-y: auto;
}
</style>