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

527 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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>
<van-notice-bar mode="link" v-if="pendingConfirmList.length" @click="handleConfirm">{{ pendingConfirmList.length
}}个物资待确认</van-notice-bar>
<div class="content">
<van-cell-group>
<van-cell v-for="(item, index) in materialList" :key="index" :title="item.wzmc" is-link
:label="`余量:${item.ye} (${item.dw})`" :to="{
name: 'MaterialDetail',
params: {
data: encodeURIComponent(
JSON.stringify({
yhzDetail: yhzDetail,
material: item,
isConfirm: false,
})
),
},
}">
</van-cell>
</van-cell-group>
<van-button type="primary" class="add-btn" icon="plus" @click="handleAdd">
添加物资
</van-button>
</div>
<!-- 弹出层 -->
<van-popup :show="showPopup" position="bottom" closeable close-on-click-overlay @close="onPopupClose">
<van-form class="materialAddForm" label-align="left" colon>
<h3>添加物资</h3>
<!-- 物资名称 -->
<van-field v-model="form.material.wzmc" label="物资名称" placeholder="请输入物资名称"
:rules="[{ required: true, message: '请填写物资名称' }]" maxlength="20" show-word-limit>
</van-field>
<!-- 数量 -->
<van-field v-model="form.material.sl" label="数量" placeholder="请输入数量" type="number"
:rules="[{ required: true, message: '请填写物资数量' }]"></van-field>
<!-- 单位 -->
<van-field v-model="form.material.dw" is-link arrow-direction="down" label="单位" placeholder="物资单位"
@click="showDwPicker = true" ref="dwField" />
<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>
<!-- 物资经度 -->
<van-field v-model="form.material.jd" label="物资经度" placeholder="请输入物资经度">
<template #button>
<van-button size="small" type="primary" @click.stop="handleGetLocation">获取位置</van-button>
</template>
</van-field>
<!-- 物资纬度 -->
<van-field v-model="form.material.wd" label="物资纬度" placeholder="请输入物资纬度">
<template #button>
<van-button size="small" type="primary" @click.stop="handleGetLocation">获取位置</van-button>
</template>
</van-field>
<!-- 负责人 -->
<van-field v-model="form.material.fzr" is-link arrow-direction="down" readonly label="负责人" placeholder="请选择负责人"
@click="showFzrPicker = true" />
<!-- 负责人弹窗 -->
<van-popup :show="showFzrPicker" round position="bottom" close-on-click-overlay @close="showFzrPicker = false">
<van-picker title="选择设备管理员" :columns="fzrOptions" @confirm="onFzrConfirm" @cancel="showFzrPicker = false" />
</van-popup>
<!-- 备注 -->
<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>
</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>
</div>
</van-popup>
</div>
</template>
<script setup>
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";
import { loadAMap } from "../../../../shared/utils/aMap";
const router = useRouter();
const route = useRoute();
const searchValue = ref(""); // 搜索框输入值
const showPopup = ref(false); // 控制弹出层显示隐藏
const yhzDetail = ref({}); // 养护站详情数据
const materialList = ref([]); // 物资列表数据
const getInitForm = () => ({
material: {
jd: "", // 物资经度
wd: "", // 物资纬度
rkrq: "", // 入库日期
rkdw: "", // 入库单位
sl: 0, // 数量
dw: "", // 单位
cfdd: "", // 存放地点
fzr: "", // 负责人
lxdh: "", // 联系电话
ye: "", // 余量
qxmc: "", // 区县名称
wzmc: "", // 物资名称
fzrid: "", // 负责人id
fzr: "", // 负责人名称
yhzid: "", // 养护站id
remark: "", // 备注
},
photos: [],
});
const form = reactive(getInitForm());
const pendingConfirmList = ref([]); // 待确认物资列表
// 获取待确认物资列表
const getPendingConfirmList = async () => {
try {
const data = {
yhzid: yhzDetail.value.id,
pageNum: 1,
pageSize: 9999,
};
const res = await request({
url: "/snow-ops-platform/yjwz/pendingConfirmList",
method: "GET",
params: data,
});
if (res.code === "00000") {
pendingConfirmList.value = res.data.records;
} else {
throw new Error(res.message);
}
} catch (error) {
showToast({
type: "fail",
message: error.message || "获取待确认物资列表失败",
});
}
};
// 跳转到确认物资页面
const handleConfirm = () => {
if (yhzDetail.value.isManager) {
router.push({
name: "MaterialConfirm",
params: {
data: encodeURIComponent(JSON.stringify(yhzDetail.value)),
},
});
} else {
handleMessage();
}
};
// 弹出提示
const handleMessage = () => {
showToast({
type: "fail",
message: "您不是站长,无法确认设备",
});
};
// 根据养护站rid获取物资列表
const getMaterialList = async (wzmc) => {
try {
const yhzid = yhzDetail.value.id;
if (!yhzid) {
return;
}
const data = {
yhzid,
wzmc,
paageNum: 1,
paageSize: 9999,
requestSource: 'app', // web: Web端请求app移动端请求
};
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 || "获取物资列表失败",
});
}
};
// 组件挂载时获取数据
onMounted(() => {
yhzDetail.value = JSON.parse(decodeURIComponent(route.params.data));
console.log("yhzDetail", toRaw(yhzDetail.value));
getMaterialList();
getPendingConfirmList();
});
// 购置日期相关
const showTimePicker = ref(false);
// 选择单位相关
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;
}
};
const handleSubmit = async () => {
try {
showLoadingToast({
message: "正在保存",
forbidClick: true,
loadingType: "spinner",
});
form.material.yhzid = yhzDetail.value.id;
form.material.qxmc = yhzDetail.value.qxmc;
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();
getMaterialList(searchValue.value);
getPendingConfirmList();
} else {
throw new Error(res.message);
}
} catch (error) {
console.log(error);
showToast({
type: "error",
message: error.message || "新增失败",
});
}
};
// 负责人相关
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 = async () => {
const location = await request({
url: "/v3/ip",
method: "get",
params: {
key: 'c30e9ebd414fd6a4dfcc1ba8c2060dbb'
},
isThirdPartyAPI: true // 添加标识
});
console.log("location", toRaw(location));
// // 确保AMap完成加载
// if (!window.AMap) {
// await loadAMap();
// }
// const loadingToast = showLoadingToast({
// message: "正在获取位置",
// forbidClick: true,
// duration: 0, // 设置为0表示不会自动关闭
// zIndex: 9999,
// });
// AMap.plugin("AMap.Geolocation", () => {
// const geolocation = new AMap.Geolocation({
// enableHighAccuracy: true,
// timeout: 5000,
// showMarker: false,
// zoomToAccuracy: true,
// });
// geolocation.getCurrentPosition((status, result) => {
// if (status === "complete") {
// form.material.jd = result.position.lng.toFixed(6);
// form.material.wd = result.position.lat.toFixed(6);
// loadingToast.close();
// } else {
// loadingToast.close();
// showToast("定位失败 请检查网络情况后重试");
// console.log("result", result);
// }
// });
// });
};
watch(
() => searchValue.value,
(newVal, oldVal) => {
if (newVal !== oldVal) {
getMaterialList(newVal);
}
}
);
const onClickLeft = () => {
router.push("/");
};
// 获取养护站人员列表
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();
showPopup.value = true;
};
const onPopupClose = () => {
Object.assign(form, getInitForm());
fileList.value = [];
[showDwPicker, showFzrPicker].forEach((v) => (v.value = false));
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;
}
.materialAddForm {
padding: 16px 16px 80px 16px;
}
</style>