bxztApp/packages/mobile/src/views/Material/MaterialManagement.vue

572 lines
14 KiB
Vue
Raw Normal View History

2025-10-16 16:44:08 +08:00
<template>
2025-11-05 17:29:08 +08:00
<div class="home">
<van-nav-bar title="物资管理" fixed left-arrow @click-left="onClickLeft">
</van-nav-bar>
<van-search
shape="round"
v-model="searchValue"
:show-action="false"
placeholder="请输入物资名称"
/>
<van-cell-group>
<van-cell title="当前站点" :value="yhzDetail.mc" />
</van-cell-group>
<div class="content">
2025-10-16 16:44:08 +08:00
<van-cell-group>
2025-11-05 17:29:08 +08:00
<van-cell
v-for="(item, index) in materialList"
:key="index"
:title="item.wzmc"
is-link
2025-11-12 17:28:02 +08:00
:label="`余量:${item.ye} (${item.dw})`"
2025-11-05 17:29:08 +08:00
:to="{
name: 'MaterialDetail',
params: {
2025-11-05 17:58:35 +08:00
data: encodeURIComponent(
JSON.stringify({
yhzDetail: yhzDetail,
material: item,
})
),
2025-11-05 17:29:08 +08:00
},
}"
>
</van-cell>
2025-10-16 16:44:08 +08:00
</van-cell-group>
</div>
2025-11-05 17:29:08 +08:00
<van-button type="primary" class="add-btn" icon="plus" @click="handleAdd">
添加物资
</van-button>
<!-- 弹出层 -->
<van-popup
:show="showPopup"
position="bottom"
closeable
close-on-click-overlay
@close="onPopupClose"
>
2025-11-06 09:40:14 +08:00
<van-form class="materialAddForm" label-align="left" colon>
<h3>设备信息</h3>
<!-- 物资名称 -->
<van-field
2025-11-12 17:28:02 +08:00
v-model="form.material.wzmc"
2025-11-06 09:40:14 +08:00
label="物资名称"
placeholder="请输入物资名称"
:rules="[{ required: true, message: '请填写物资名称' }]"
2025-11-12 17:28:02 +08:00
maxlength="20"
show-word-limit
2025-11-06 09:40:14 +08:00
>
</van-field>
<!-- 数量 -->
<van-field
2025-11-12 17:28:02 +08:00
v-model="form.material.sl"
2025-11-06 09:40:14 +08:00
label="数量"
placeholder="请输入数量"
type="number"
:rules="[{ required: true, message: '请填写物资数量' }]"
2025-11-12 17:28:02 +08:00
></van-field>
2025-11-06 09:40:14 +08:00
<!-- 单位 -->
<van-field
2025-11-12 17:28:02 +08:00
v-model="form.material.dw"
is-link
arrow-direction="down"
label="单位"
placeholder="物资单位"
@click="showDwPicker = true"
ref="dwField"
2025-11-06 09:40:14 +08:00
/>
2025-11-12 17:28:02 +08:00
<van-popup
:show="showDwPicker"
round
position="bottom"
close-on-click-overlay
@close="showDwPicker = false"
>
<van-picker
title="选择物资单位"
:columns="dwOptions"
@confirm="onDwConfirm"
@cancel="showDwPicker = false"
/>
</van-popup>
2025-11-06 09:40:14 +08:00
2025-11-12 17:28:02 +08:00
<!-- 物资经度 -->
2025-11-06 09:40:14 +08:00
<van-field
2025-11-12 17:28:02 +08:00
v-model="form.material.jd"
label="物资经度"
placeholder="请输入物资经度"
>
<template #button>
<van-button
size="small"
type="primary"
@click.stop="handleGetLocation"
>获取位置</van-button
>
</template>
</van-field>
<!-- 物资纬度 -->
2025-11-06 09:40:14 +08:00
<van-field
2025-11-12 17:28:02 +08:00
v-model="form.material.wd"
label="物资纬度"
placeholder="请输入物资纬度"
>
<template #button>
<van-button
size="small"
type="primary"
@click.stop="handleGetLocation"
>获取位置</van-button
>
</template>
</van-field>
2025-11-06 09:40:14 +08:00
2025-11-12 17:28:02 +08:00
<!-- 负责人 -->
2025-11-06 09:40:14 +08:00
<van-field
2025-11-12 17:28:02 +08:00
v-model="form.material.fzr"
2025-11-06 09:40:14 +08:00
is-link
arrow-direction="down"
readonly
2025-11-12 17:28:02 +08:00
label="负责人"
placeholder="请选择负责人"
@click="showFzrPicker = true"
2025-11-06 09:40:14 +08:00
/>
2025-11-12 17:28:02 +08:00
<!-- 负责人弹窗 -->
2025-11-06 09:40:14 +08:00
<van-popup
2025-11-12 17:28:02 +08:00
:show="showFzrPicker"
2025-11-06 09:40:14 +08:00
round
position="bottom"
close-on-click-overlay
2025-11-12 17:28:02 +08:00
@close="showFzrPicker = false"
2025-11-06 09:40:14 +08:00
>
2025-11-12 17:28:02 +08:00
<van-picker
title="选择设备管理员"
:columns="fzrOptions"
@confirm="onFzrConfirm"
@cancel="showFzrPicker = false"
2025-11-06 09:40:14 +08:00
/>
</van-popup>
2025-11-12 17:28:02 +08:00
<!-- 备注 -->
<van-field
v-model="form.material.remark"
label="备注"
type="textarea"
placeholder=""
maxlength="20"
show-word-limit
>
</van-field>
<!-- -->
<van-field label="物资照片" center>
<template #input>
<van-uploader
v-model="fileList"
@delete="handleDelete"
name="photos"
:file-list="fileList"
:file-type="['image/jpeg', 'image/png']"
:after-read="afterRead"
multiple
:max-count="6"
/>
</template>
</van-field>
2025-11-06 09:40:14 +08:00
</van-form>
<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="handleSubmit"
>
保存
</van-button>
2025-11-05 17:29:08 +08:00
</div>
</van-popup>
</div>
</template>
2025-10-16 16:44:08 +08:00
<script setup>
2025-11-05 17:29:08 +08:00
import "vant/es/toast/style";
import "vant/es/popup/style";
import { ref, onMounted, reactive, toRaw, watch } from "vue";
import { useRouter, useRoute } from "vue-router";
import { showToast, showLoadingToast } from "vant";
import { request } from "../../../../shared/utils/request";
const router = useRouter();
const route = useRoute();
const searchValue = ref(""); // 搜索框输入值
const showPopup = ref(false); // 控制弹出层显示隐藏
const yhzDetail = ref({}); // 养护站详情数据
const materialList = ref([]); // 物资列表数据
2025-11-06 09:40:14 +08:00
const INIT_FORM = {
2025-11-12 17:28:02 +08:00
material: {
jd: "", // 物资经度
wd: "", // 物资纬度
rkrq: "", // 入库日期
rkdw: "", // 入库单位
sl: 0, // 数量
dw: "", // 单位
cfdd: "", // 存放地点
fzr: "", // 负责人
lxdh: "", // 联系电话
ye: "", // 余量
qxmc: "", // 区县名称
wzmc: "", // 物资名称
fzrid: "", // 负责人id
fzr: "", // 负责人名称
yhzid: "", // 养护站id
remark: "", // 备注
},
photos: [],
2025-11-06 09:40:14 +08:00
};
const form = reactive({ ...INIT_FORM }); // 表单
2025-11-05 17:29:08 +08:00
// 根据养护站rid获取物资列表
const getMaterialList = async (wzmc) => {
try {
const yhzid = yhzDetail.value.id;
if (!yhzid) {
return;
}
const data = {
yhzid,
wzmc,
paageNum: 1,
paageSize: 9999,
};
const res = await request({
url: "/snow-ops-platform/yjwz/list",
method: "GET",
params: data,
});
if (res.code && res.code === "00000") {
materialList.value = res.data.records;
} else {
throw new Error(res.message);
}
} catch (error) {
showToast({
type: "error",
message: error.message || "获取物资列表失败",
});
2025-10-16 16:44:08 +08:00
}
2025-11-05 17:29:08 +08:00
};
// 组件挂载时获取数据
onMounted(() => {
yhzDetail.value = JSON.parse(decodeURIComponent(route.params.data));
2025-11-06 09:40:14 +08:00
console.log("yhzDetail", toRaw(yhzDetail.value));
2025-11-05 17:29:08 +08:00
getMaterialList();
});
2025-11-12 17:28:02 +08:00
// 购置日期相关
2025-11-06 09:40:14 +08:00
const showTimePicker = ref(false);
const currentDate = ref([
new Date().getFullYear(),
new Date().getMonth() + 1,
new Date().getDate(),
]);
const onDateConfirm = ({ selectedValues }) => {
form.rkrq = selectedValues.join("-");
showTimePicker.value = false;
};
2025-11-12 17:28:02 +08:00
// 选择单位相关
const dwField = ref(null);
const showDwPicker = ref(false);
const dwOptions = [
{ text: "辆", value: "辆" },
{ text: "米", value: "米" },
{ text: "桶", value: "桶" },
{ text: "把", value: "把" },
{ text: "吨", value: "吨" },
{ text: "双", value: "双" },
{ text: "件", value: "件" },
{ text: "付", value: "付" },
{ text: "个", value: "个" },
{ text: "件", value: "件" },
{ text: "自定义", value: "自定义" },
];
const onDwConfirm = (value) => {
if (value.selectedValues[0] === "自定义") {
showDwPicker.value = false;
dwField.value.focus();
} else {
form.material.dw = value.selectedValues[0];
showDwPicker.value = false;
}
};
2025-11-06 09:40:14 +08:00
const handleSubmit = async () => {
try {
showLoadingToast({
message: "正在保存",
forbidClick: true,
loadingType: "spinner",
});
2025-11-12 17:28:02 +08:00
form.material.yhzid = yhzDetail.value.id;
form.material.qxmc = yhzDetail.value.qxmc;
2025-11-06 09:40:14 +08:00
console.log("form", toRaw(form));
const res = await request({
url: "/snow-ops-platform/yjwz/add",
method: "post",
data: toRaw(form),
});
if (res.code && res.code === "00000") {
showToast({
type: "success",
message: "新增成功",
});
onPopupClose();
Object.assign(form, { ...INIT_FORM });
getMaterialList(searchValue.value);
} else {
throw new Error(res.message);
}
} catch (error) {
console.log(error);
showToast({
type: "error",
message: error.message || "新增失败",
});
}
};
2025-11-12 17:28:02 +08:00
// 负责人相关
const showFzrPicker = ref(false);
const fzrOptions = ref([]);
const onFzrConfirm = (value) => {
// 获取选中的负责人ID
const selectedId = value.selectedValues[0];
// 在fzrOptions中查找对应的负责人名称
const selectedPerson = fzrOptions.value.find(
(item) => item.value === selectedId
);
// 同时设置id和名称
if (selectedPerson) {
form.material.fzrid = selectedId;
form.material.fzr = selectedPerson.text;
} else {
form.material.fzrid = "";
form.material.fzr = "";
}
showFzrPicker.value = false;
};
// 图片上传相关
const fileList = ref([]);
// 文件删除
const handleDelete = (file) => {
if (file.serverUrl) {
const index = form.photos.findIndex((p) => p.photoUrl === file.serverUrl);
if (index !== -1) {
form.photos.splice(index, 1);
}
}
};
// 文件上传
const afterRead = async (file) => {
try {
const toast = showLoadingToast({
message: "上传中...",
forbidClick: true,
duration: 0, // 设置为0表示不会自动关闭
});
const formData = new FormData();
formData.append("file", file.file);
const res = await request({
url: "/snow-ops-platform/file/upload",
method: "post",
data: formData,
});
toast.close();
if (res.code === "00000") {
form.photos.push({ photoUrl: res.data });
const index = fileList.value.findIndex((f) => f.file === file.file);
if (index !== -1) {
fileList.value[index].serverUrl = res.data;
}
console.log("form.photos", toRaw(form.photos));
console.log("fileList.value", fileList.value);
} else {
throw new Error(res.message);
}
} catch (error) {
toast.close();
showToast({
type: "fail",
message: error.message,
});
}
};
// 获取经纬度
const handleGetLocation = () => {
if (!navigator.geolocation) {
showToast("您的浏览器不支持地理位置获取");
return;
}
showLoadingToast({
message: "定位中...",
forbidClick: true,
});
navigator.geolocation.getCurrentPosition(
(position) => {
form.material.jd = position.coords.longitude.toFixed(6);
form.material.wd = position.coords.latitude.toFixed(6);
showToast("定位成功");
},
(error) => {
const errorMessage =
{
1: "位置服务被拒绝",
2: "暂时无法获取位置",
3: "定位超时",
}[error.code] || "定位失败";
showToast(errorMessage);
},
{
enableHighAccuracy: true, // 高精度模式
timeout: 5000, // 超时时间
maximumAge: 0, // 不缓存位置
}
);
};
2025-11-05 17:29:08 +08:00
watch(
() => searchValue.value,
(newVal, oldVal) => {
if (newVal !== oldVal) {
getMaterialList(newVal);
}
2025-10-16 16:44:08 +08:00
}
2025-11-05 17:29:08 +08:00
);
const onClickLeft = () => {
router.push("/");
};
2025-11-12 17:28:02 +08:00
// 获取养护站人员列表
const getPersonList = async () => {
try {
const data = {
pageNum: 1,
pageSize: 9999,
yhzid: yhzDetail.value.id,
};
const res = await request({
url: "/snow-ops-platform/yhzry/list",
method: "get",
params: data,
});
if (res.code === "00000") {
fzrOptions.value = res.data.records.map((item) => ({
text: item.xm,
value: item.userId,
}));
} else {
throw new Error("人员信息获取失败");
}
} catch (error) {
console.log(error);
showToast({
type: "fail",
message: error.message,
});
}
};
const handleAdd = async () => {
await getPersonList();
handleGetLocation();
2025-11-05 17:29:08 +08:00
showPopup.value = true;
};
const onPopupClose = () => {
showPopup.value = false;
};
</script>
<style scoped>
.home {
padding-top: var(--van-nav-bar-height); /* 自动匹配导航栏高度 */
}
.content {
padding: 16px 16px 80px 16px;
}
.content .van-cell-group .van-cell {
margin-bottom: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.add-btn {
position: fixed;
bottom: 20px;
left: 16px;
right: 16px;
width: calc(100% - 32px);
margin: 0 auto;
border-radius: 24px;
font-size: 16px;
height: 44px;
z-index: 999;
}
.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;
}
2025-11-06 09:40:14 +08:00
.materialAddForm {
padding: 16px 16px 80px 16px;
}
2025-11-05 17:29:08 +08:00
</style>
2025-10-16 16:44:08 +08:00