bonus-material-app/src/pages/business/leaseApply.vue

839 lines
26 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>
<view class="accept page-common">
<div class="card">
<uni-forms :model="formData" ref="form" label-width="200rpx" :rule="rules.value" :border="true" >
<uni-forms-item label="领用单位" name="unitId" required>
<eselect
style="width: 100%; height: 90rpx"
v-model="formData.unitId"
ref="treeSelect"
:options="unitList"
@change="getProject"
@clear="clearUnit"
></eselect>
</uni-forms-item>
<uni-forms-item label="领用工程" name="proId" required>
<eselect
style="width: 100%; height: 90rpx"
v-model="formData.proId"
ref="treeSelect2"
:options="proList"
@change="changePro"
@clear="clearPro"
></eselect>
</uni-forms-item>
<uni-forms-item label="采购申请编号" name="applyCode" required>
<uni-easyinput v-model="formData.applyCode" maxlength="10" placeholder="请输入领料人" />
</uni-forms-item>
<uni-forms-item label="领料人" name="leasePerson" required>
<uni-easyinput v-model="formData.leasePerson" maxlength="10" placeholder="请输入领料人" />
</uni-forms-item>
<uni-forms-item label="联系电话" name="phone" required>
<uni-easyinput v-model="formData.phone" maxlength="11" placeholder="请输入联系电话" />
</uni-forms-item>
<uni-forms-item label="标准配置" name="configId" >
<eselect
style="width: 100%; height: 90rpx"
v-model="formData.configId"
ref="treeSelect"
:options="configList"
@change="getConfigChange"
@clear="clearConfig"
></eselect>
</uni-forms-item>
<uni-forms-item label="附件" label-width="100rpx" v-if="flagFile">
<div class="upload-wrapper" style="display: flex; flex-wrap: wrap;">
<!-- 上传按钮,仅当上传图片数量少于 3 张时显示 -->
<div class="upload" @click="uploadImg" v-if="bmFileInfos.length < 3">+</div>
<!-- 动态展示已上传的图片 -->
<div class="upload" @click="uploadImg" v-for="(img, index) in bmFileInfos" :key="index">
<div class="image-container">
<image :src="img.urlTemp" style="width: 160rpx;height: 160rpx;" mode=""></image>
<!-- 删除 logo这里用一个 span 模拟,可替换为实际的 logo 图片 -->
<span class="delete-logo" @click.stop="deleteImg(index)">&times;</span>
</div>
</div>
</div>
</uni-forms-item>
</uni-forms>
</div>
<div class="card">
<div class="select-area">
<uni-row :gutter="24" style="display: flex; align-items: center">
<uni-col :span="10">
<view>
<uni-data-select v-model="typeId"
placeholder="请选择物资类型"
:localdata="maTypeSelectList" @change="getMaCode" >
</uni-data-select>
</view>
</uni-col>
<uni-col :span="10">
<view>
<uni-data-select v-model="typeCode"
placeholder="请选择规格型号"
:localdata="maCodeSelectList" @change="selectMaCode" >
</uni-data-select>
</view>
</uni-col>
</uni-row>
</div>
<div class="table-area">
<uni-table border stripe emptyText="暂无更多数据">
<!-- 表头行 -->
<uni-tr>
<uni-th width="100px" style="font-size: 24rpx;" align="center">类型名称</uni-th>
<uni-th width="100px" style="font-size: 24rpx;" align="center">规格型号</uni-th>
<uni-th width="90px" style="font-size: 24rpx;" align="center">计量单位</uni-th>
<uni-th width="90px" style="font-size: 24rpx;" align="center">预领数量</uni-th>
<uni-th width="90px" style="font-size: 24rpx;" align="center">备注</uni-th>
<uni-th width="70px" style="font-size: 24rpx;" align="center">操作</uni-th>
</uni-tr>
<!-- 表格数据行 -->
<uni-tr v-for="(item,index) in typeList" :key="item.id">
<uni-td style="font-size: 24rpx;text-align: center;">{{item.maTypeName}}</uni-td>
<uni-td style="font-size: 24rpx;text-align: center;">{{item.typeName}}</uni-td>
<uni-td style="font-size: 24rpx;text-align: center;">{{item.unitName}}</uni-td>
<uni-td style="font-size: 24rpx;text-align: center;">
<uni-easyinput
placeholder="预领数量"
v-model="item.preNum"
type="number"
:clearable="false"
@input="onChangeNumber(item)"
:styles="{width: '100rpx'}"
/>
</uni-td>
<uni-td style="font-size: 24rpx;text-align: center;">
<uni-easyinput
placeholder="备注"
v-model="item.remark"
:clearable="false"
:styles="{width: '100rpx'}"
/>
</uni-td>
<uni-td style="font-size: 24rpx;text-align: center;">
<view class="uni-group">
<!-- <view class="action-btn" @click="uploadImg(item)">
<uni-icons type="camera" size="20" style="color: #3784fb;"/>
</view> -->
<view class="action-btn delete" @click="delRow(index)">
<uni-icons type="trash-filled" size="20" style="color: red;margin-left:10px;"/>
</view>
</view>
</uni-td>
</uni-tr>
</uni-table>
</div>
</div>
<div class="footer-btn">
<button class="btn-cont" @click="submitNum">发起申请</button>
</div>
</view>
</template>
<script setup >
import { ref, reactive } from 'vue'
import eselect from '@/components/tree-select/eselect.vue'
import { onLoad,onReady } from '@dcloudio/uni-app'
import { getUnitList,getProjectList,getConfigList,getLevelThreeType,insertApp,getAgreementInfoById,getListsByConfigId,getTypeDataList,leaseTask } from '../../services/back.js';
const taskInfo = ref({})
const treeSelect = ref(null)
const treeSelect2 = ref(null)
const formData = ref({
value: {
unitId: '',
proId: '',
leasePerson: '',
phone: '',
configId: '',
applyCode: '',
}
})
const unitList = ref([])
const proList = ref([])
const configList = ref([])
const unitId = ref('')
const proId = ref('')
const configId = ref('')
const agreementId = ref('')
const maTypeSelectList = ref([])
const typeId = ref("")//类型
const maCodeSelectList = ref([])
const typeCode = ref("")//规格型号
const typeList = ref([])
const bmFileInfos = ref([])//图片数组
// 定义 form 引用
const form = ref(null)
const flagFile = ref(false)
// 定义表单验证规则
const rules = ref({
unitId: {
rules: [
{
required: true,
errorMessage: '领用单位为必填项',
trigger: 'change'
}
]
},
proId: {
rules: [
{
required: true,
errorMessage: '领用工程为必填项',
trigger: 'change'
}
]
},
applyCode: {
rules: [
{
required: true,
errorMessage: '采购申请编号为必填项',
trigger: 'blur'
}
]
},
leasePerson: {
rules: [
{
required: true,
errorMessage: '领料人为必填项',
trigger: 'blur'
}
]
},
phone: {
rules: [
{
required: true,
errorMessage: '联系电话为必填项',
trigger: 'blur'
},
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
errorMessage: '请输入正确的手机号码',
trigger: 'blur'
}
]
},
})
//单位
const getUnit = () => {
// proId.value=e.id;
let obj = {
projectId: proId.value,
}
getUnitList(obj)
.then((res) => {
console.log(res)
unitList.value = res.data
// getAgreement()
if (unitId.value && proId.value) {
getAgreement()
}
})
.catch((error) => {
console.log(error)
})
}
//工程
const getProject = async (e) => {
flagFile.value = false
if (e.typeKey == 'fbs') {
flagFile.value = true
}
console.log('🚀 ~ getProject ~ e:', e)
unitId.value = e?.id || ''
formData.value.unitId = e?.id || ''
let obj = {
unitId: unitId.value,
// "isApp":true
}
try {
const res = await getProjectList(obj);
proList.value = res.data;
// proId.value=""
// treeSelect2.value.clearInput();
agreementId.value = '';
if (unitId.value && proId.value) {
await getAgreement();
// getMaType();
}
} catch (error) {
console.log(error);
}
}
//标准配置
const getConfig = () => {
let obj = {
unitId: null,
}
getConfigList(obj)
.then((res) => {
configList.value = res.data
})
.catch((error) => {
console.log(error)
})
}
//标准配置
const getConfigChange = (e) => {
configId.value = e?.id || ''
formData.value.configId = e?.id || ''
let obj = {
configId: e?.id || '',
}
getListsByConfigId(obj)
.then((res) => {
console.log(res)
if (res.code == 200 && res.data.length > 0) {
res.data.forEach(item => {
let param = {
typeId: item.typeId,
typeName: item.typeName,
maTypeName: item.maTypeName,
unitName: item.unitName,
remark: '',
preNum: item.num,
}
// 检查 typeList 中是否已经存在相同 typeId 的项
const exists = typeList.value.some(existingItem => existingItem.typeId === param.typeId);
if (!exists) {
typeList.value.push(param);
}
})
}
// configList.value = res.data
})
.catch((error) => {
console.log(error)
})
}
//工程选择
const changePro = (e) => {
console.log(e)
proId.value = e.id
formData.value.proId = e.id
getUnit()
// getAgreement()
}
//协议
const getAgreement = async () => {
let obj = {
unitId: unitId.value,
projectId: proId.value,
}
getAgreementInfoById(obj)
.then((res) => {
console.log(res)
if (res.code == 200) {
agreementId.value = res.data.agreementId
} else {
agreementId.value = ''
}
})
.catch((error) => {
console.log(error)
})
}
//类下拉选
const getMaType = () => {
console.log('sdadasda',agreementId.value)
let obj = {
"level":3,
}
getLevelThreeType(obj).then(res => {
console.log(res)
maTypeSelectList.value = res.data.map(option => {
return {
value:option.typeId,
text:option.name,
}
});
}).catch(error => {
console.log(error)
})
}
//规格
const getMaCode = () => {
let obj = {
"typeId":typeId.value
}
getTypeDataList(obj).then(res => {
console.log(res)
maCodeSelectList.value = res.data.map(option => {
let obj = {
...option,
value:option.typeId,
text:option.typeName,
}
return obj
});
}).catch(error => {
console.log(error)
})
}
//选择规格型号
const selectMaCode = (e) => {
console.log(e)
// 检查 typeList 中是否已经存在相同 typeId 的项
const exists = typeList.value.some(existingItem => existingItem.typeId === e);
if (exists) {
let name = ''
maCodeSelectList.value.forEach(item => {
if (item.typeId === e) {
name = item.typeName
}
})
uni.showToast({
title: `${name} 已添加到列表中`,
icon: 'none',
duration: 1000
})
return
}
maCodeSelectList.value.forEach(item=>{
console.log(item)
if(item.typeId==e){
let param = {
typeId:item.typeId,
typeName:item.typeName,
maTypeName:item.maTypeName,
unitName:item.unitName,
remark:'',
preNum:item.num,
}
typeList.value.push(param)
}
})
console.log(typeList.value)
}
//提交
const submitNum = async() => {
console.log(typeList.value)
// 直接使用引用调用验证方法
form.value.validate(async(valid)=>{
console.log('🚀 ~ submitNum ~ valid:', valid)
if(!valid){
if(flagFile.value && bmFileInfos.value.length==0){
await uni.showToast({
title: '请上传附件',
icon: 'none',
duration: 1000
})
return
}
// 校验 preNum 必须大于 0
if (typeList.value.length === 0) {
console.log('🚀 ~ submitNum ~ typeList.value:', typeList.value)
await uni.showToast({
title: '请添加申请数据',
icon: 'none',
duration: 1000
})
return
}
for (let i = 0; i < typeList.value.length; i++) {
if (typeList.value[i].preNum <= 0 || !typeList.value[i].preNum) {
uni.showToast({
title: '预领数量不能为空或等于0',
icon: 'none',
duration: 1000
})
return
}
}
let obj = {
"leaseApplyInfo":{
"unitId":unitId.value,
"projectId":proId.value,
"agreementId":agreementId.value,
"leasePerson":formData.value.leasePerson,
"phone":formData.value.phone,
"standardConfigId":configId.value,
"applyCode":formData.value.applyCode,
"bmFileInfos": bmFileInfos.value,
},
"leaseApplyDetailsList":typeList.value
}
console.log(obj)
leaseTask(obj).then( res => {
console.log(res)
if(res.code==200){
console.log('xxxxxxxxxxxxxxxx')
uni.showToast({ title: '申请成功', icon: 'none',duration: 1000
})
setTimeout(() => {
uni.navigateBack({
delta: 1
});
}, 1000);
}else{
console.log('yyyyyyyyyyyyy')
uni.showToast({ title: res.msg, icon: 'none',duration: 1000 })
}
}).catch(error => {
console.log(error)
})
}else{
return;
}
})
}
onReady(() => {
if (form.value) {
// 设置表单验证规则
form.value.setRules(rules.value);
} else {
console.error('表单引用未正确初始化');
}
});
onLoad((options) => {
getUnit()
getProject()
getConfig()
getMaType()
// formData.value = JSON.parse(options.item)
})
//上传
const uploadImg = (item) => {
if(bmFileInfos.value.length>=3){
uni.showToast({
title: '最多上传3张图片',
icon: 'none',
})
return
}
uni.chooseImage({
count: 3 - bmFileInfos.value.length, //图片可选择数量
sizeType: ['original', 'compressed'], //original 原图compressed 压缩图,默认二者都有
sourceType: ['album', 'camera',], //album 从相册选图camera 使用相机,默认二者都有。
success: res => {
console.log(res)
let imgFiles = res.tempFilePaths //图片的本地文件路径列表
imgFiles.forEach((filePath) => {
console.log('2222222222222222222222')
bmFileInfos.value.push({urlTemp:filePath})
})
console.log('🚀 ~ uploadImg ~ imgFiles:', imgFiles)
// imgBeseUrl.value = imgFiles[0]
// console.log('本地地址', imgFiles)
// console.log('请求地址', baseURL+"/file/upload")
bmFileInfos.value.forEach((item,index) => {
uni.uploadFile({
// url: baseURL+"/file/upload",//app
url: "/file/upload",//h5
filePath: item.urlTemp,
name: 'file',
success: (res) => {
res = JSON.parse(res.data)
console.log('上传成功', res.code);
console.log('上传成功', res.data);
if(res.code&&res.code==200){
bmFileInfos.value[index] = {
...bmFileInfos.value[index],
name: res.data.name,
url: res.data.url
};
uni.showToast({ title: '上传成功', icon: 'none' })
}else{
uni.showToast({ title: '上传失败', icon: 'none' })
}
},
fail: (err) => {
console.error('上传失败', err);
}
});
});
// this.$refs.vForm.clearValidate()
}
})
}
const deleteImg = (index) => {
bmFileInfos.value.splice(index, 1);
// bmFileInfosTemp.value.splice(index, 1);
};
//删除
const delRow = (index) => {
console.log(index)
console.log(typeList.value)
typeList.value.splice(index,1)
}
// 数量框change事件
const onChangeNumber = (item) => {
// console.log(item)
// console.log(item.num)
// console.log(item.num)
// let maxNum = Number(item.num)
// // outboundNum.value
// setTimeout(()=>{
// if(item.unitValue==1){
// item.preNum = Number(String(item.preNum).replace(/[^\d.]/g,''))
// }else{
// item.preNum = Number(String(item.preNum).replace(/[^\d]/g,''))
// }
// if (Number(item.preNum)<= 0) {
// item.preNum = 0;
// }
// if (Number(item.preNum) > maxNum) {
// uni.showToast({
// title: '已达到当前资最大在用数量!',
// icon: 'none',
// })
// item.preNum = maxNum;
// }
// },500)
}
const changeNum = (row) => {
// console.log('🚀 ~ changeNum ~ row:', row)
// // 将badNum 和 goodNum 向上取整
// // 只能输入正整数 过滤掉除正整数外的东西
// if (row.badNum) {
// row.badNum = Math.ceil(String(row.badNum).replace(/[^\d]/g, ''))
// console.log('🚀 ~ changeNum ~ row.badNum:', row.badNum)
// }
// if (row.goodNum) {
// console.log('🚀 ~ changeNum ~ row.goodNum:', row.goodNum)
// row.goodNum = Math.ceil(String(row.goodNum).replace(/[^\d]/g, ''))
// }
// // 不能大于preNum
// if (Number(row.badNum) + Number(row.goodNum) > row.preNum) {
// console.log('🚀 ~ changeNum ~ row.badNum + row.goodNum > row.preNum:', row.badNum , row.goodNum)
// // this.$message.error('完好数量和不合格数量之和不能大于退料数量')
// uni.showToast({
// title: '完好数量和不合格数量之和不能大于退料数量',
// icon: 'none',
// })
// row.badNum = 0
// row.goodNum = 0
// }
}
const clearUnit = () => {
unitId.value = ''
agreementId.value = ''
getUnit()
getProject()
}
const clearPro = () => {
proId.value = ''
agreementId.value = ''
getProject()
}
const clearConfig = () => {
configId.value = ''
getConfig()
}
</script>
<style lang="scss">
.accept {
padding: 24rpx;
height: 95vh;
word-break: break-all;
background-color: #f7f8fa;
display: flex;
flex-direction: column;
// 卡片样式
.card {
padding: 32rpx;
background-color: #fff;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
margin-bottom: 24rpx;
// 卡片头部
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.title {
font-size: 32rpx;
font-weight: 600;
color: #262626;
position: relative;
padding-left: 24rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 28rpx;
background: #3784fb;
border-radius: 6rpx;
}
}
.header-right {
.tip {
font-size: 26rpx;
color: #8c8c8c;
}
}
}
// 操作按钮样式
.uni-group {
display: flex;
justify-content: center;
align-items: center;
.uni-icons {
padding: 8rpx;
border-radius: 8rpx;
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
opacity: 0.8;
}
}
}
// 选择区域
.select-area {
padding: 24rpx 0;
border-bottom: 2rpx solid #f5f5f5;
}
// // 表格区域
// .table-area {
// margin-top: 24rpx;
// margin: 24rpx -32rpx 0;
// overflow-x: auto;
// :deep(.uni-table) {
// width: 1080rpx;
// padding: 0 10rpx;
// .uni-table-tr {
// .uni-table-th {
// min-width: 140rpx;
// &:last-child {
// min-width: 120rpx;
// }
// }
// .uni-table-td {
// .action-btn {
// display: inline-flex;
// padding: 12rpx;
// border-radius: 8rpx;
// transition: all 0.3s ease;
// margin: 0 8rpx;
// &:active {
// background-color: rgba(0, 0, 0, 0.05);
// }
// &.delete:active {
// background-color: rgba(255, 77, 79, 0.05);
// }
// }
// }
// }
// }
// }
}
// 底部按钮
.footer-btn {
margin-top: auto;
padding: 32rpx;
background: #fff;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
.btn-cont {
width: 100%;
height: 88rpx;
line-height: 88rpx;
text-align: center;
background: linear-gradient(135deg, #4b8eff 0%, #3784fb 100%);
color: #fff;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
box-shadow: 0 6rpx 20rpx rgba(55, 132, 251, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
opacity: 0.9;
box-shadow: 0 2rpx 8rpx rgba(55, 132, 251, 0.2);
}
}
}
}
// 上传区域样式
.upload {
width: 160rpx;
height: 160rpx;
background-color: #f7f8fa;
border: 2rpx dashed #d9d9d9;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 48rpx;
color: #bfbfbf;
transition: all 0.3s ease;
&:active {
background-color: #f0f0f0;
border-color: #3784fb;
}
image {
width: 100%;
height: 100%;
border-radius: 12rpx;
object-fit: cover;
}
}
.image-container {
position: relative;
display: inline-block;
}
.delete-logo {
position: absolute;
top: 5px;
right: 5px;
font-size: 20px;
color: white;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
cursor: pointer;
}
</style>