|
|
@@ -0,0 +1,839 @@
|
|
|
+<template>
|
|
|
+ <view>
|
|
|
+ <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue">
|
|
|
+ <block slot="content">领用申请</block>
|
|
|
+ </cu-custom>
|
|
|
+
|
|
|
+ <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules"
|
|
|
+ ref="inputForm">
|
|
|
+ <u-form-item label="领用编号" borderBottom prop="collectNo">
|
|
|
+ <u--input placeholder="自动生成" v-model="inputForm.collectNo" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="经办人" borderBottom prop="handledBy">
|
|
|
+ <u--input v-model="inputForm.handledBy" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="经办部门" borderBottom prop="handledByOfficeName">
|
|
|
+ <u--input v-model="inputForm.handledByOfficeName" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="领用时间" borderBottom prop="collectDate" :required="true">
|
|
|
+ <el-date-picker v-model="inputForm.collectDate" type="date" placeholder="请选择领用时间" style="width:100%"
|
|
|
+ placement="bottom-start" clearable :disabled="nodeFlag">
|
|
|
+ </el-date-picker>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="备注" borderBottom prop="remarks">
|
|
|
+ <u--textarea placeholder="请填写备注信息" :rows="4" :maxlength="500" v-model="inputForm.remarks"
|
|
|
+ :disabled="nodeFlag"></u--textarea>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <view class="section-wrap">
|
|
|
+ <view class="section-title">领用详情</view>
|
|
|
+ <view class="section-tip"></view>
|
|
|
+
|
|
|
+ <view v-for="(item, index) in inputForm.detailInfos" :key="item.id || index" class="detail-card">
|
|
|
+ <view class="detail-card-title">领用详情 {{ index + 1 }}</view>
|
|
|
+
|
|
|
+ <u-form-item label="领用人" :prop="'detailInfos[' + index + '].recipientAgent'" :required="true">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].recipientAgent" placeholder="请选择领用人"
|
|
|
+ :disabled="nodeFlag" @focus="openUserPullForm(index)" clearable></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="领用人部门" :prop="'detailInfos[' + index + '].recipientOffice'">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].recipientOffice" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="领用类型" :prop="'detailInfos[' + index + '].collectType'" :required="true">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].collectType" placeholder="请选择领用类型"
|
|
|
+ :disabled="nodeFlag" @focus="openTypePicker(index)" clearable></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <!-- <u-form-item label="物品名称" :prop="'detailInfos[' + index + '].goodsName'" :required="true"> -->
|
|
|
+ <!-- <u--input :value="inputForm.detailInfos[index].goodsName" placeholder="请选择物品名称"
|
|
|
+ :disabled="nodeFlag" @focus="openPicker(index)"></u--input> -->
|
|
|
+ <!-- </u-form-item> -->
|
|
|
+ <collect-goods-selector ref="goodsSelect" :rowIndex="index" :inputForm="inputForm"
|
|
|
+ :disabled="nodeFlag" @selected="handleGoodsSelected"></collect-goods-selector>
|
|
|
+ <u-form-item label="领用数量" :prop="'detailInfos[' + index + '].collectNumber'" :required="true">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].collectNumber" placeholder="请输入领用数量"
|
|
|
+ :disabled="nodeFlag" @blur="handleCollectNumberBlur(index)"></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="库存数量" :prop="'detailInfos[' + index + '].kc'">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].kc" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="单位" :prop="'detailInfos[' + index + '].company'">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].company" placeholder="请输入单位"
|
|
|
+ :disabled="true"></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="包装规格" :prop="'detailInfos[' + index + '].spec'">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].spec" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+
|
|
|
+ <u-form-item label="备注" :prop="'detailInfos[' + index + '].remarks'">
|
|
|
+ <u--input v-model="inputForm.detailInfos[index].remarks" placeholder="请输入备注"
|
|
|
+ :disabled="nodeFlag"></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="附件上传">
|
|
|
+ <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
|
|
|
+ @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, index, fileIndex, 'detail')"
|
|
|
+ @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, index, 'detail')"
|
|
|
+ :fileList="inputForm.detailInfos[index].fileInfoLost" :limit="3" :isDelete="nodeFlag"
|
|
|
+ :isUpload="nodeFlag">
|
|
|
+ </UploadComponent>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="" v-if="!nodeFlag">
|
|
|
+ <el-button style="width: 100%" type="danger" plain @click="removeDetail(index)">
|
|
|
+ 删除领用详情
|
|
|
+ </el-button>
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <u-form-item label="" v-if="!nodeFlag">
|
|
|
+ <el-button style="width: 100%" type="primary" @click="addDetail()" plain>新增领用详情</el-button>
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section-wrap" v-if="nodeFlag">
|
|
|
+ <view class="section-title">领用分配详情</view>
|
|
|
+
|
|
|
+ <view v-for="(item, index) in inputForm.recordList" :key="item.id || index" class="detail-card">
|
|
|
+ <view class="detail-card-title">领用分配详情 {{ index + 1 }}</view>
|
|
|
+
|
|
|
+ <u-form-item label="领用人" :prop="'recordList[' + index + '].recipientAgent'" :required="true">
|
|
|
+ <u--input v-model="inputForm.recordList[index].recipientAgent" placeholder="请选择领用人"
|
|
|
+ :disabled="nodeFlag" @focus="openUserPullForm(index)" clearable></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="领用人部门" :prop="'recordList[' + index + '].recipientOffice'">
|
|
|
+ <u--input v-model="inputForm.recordList[index].recipientOffice" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="领用类型" :prop="'recordList[' + index + '].collectType'" :required="true">
|
|
|
+ <u--input v-model="inputForm.recordList[index].collectType" placeholder="请选择领用类型"
|
|
|
+ :disabled="nodeFlag" @focus="openTypePicker(index)" clearable></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="物品名称" :prop="'recordList[' + index + '].goodsName'" :required="true">
|
|
|
+ <u--input v-model="inputForm.recordList[index].goodsName" placeholder="请选择物品名称"
|
|
|
+ :disabled="nodeFlag" clearable></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="分配生产日期" :prop="'recordList[' + index + '].fpDate'" :required="true">
|
|
|
+ <u--input v-model="inputForm.recordList[index].fpDate" placeholder="请选择分配生产日期"
|
|
|
+ :disabled="nodeFlag" clearable></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="领用数量" :prop="'recordList[' + index + '].collectNumber'" :required="true">
|
|
|
+ <u--input v-model="inputForm.recordList[index].collectNumber" placeholder="请输入领用数量"
|
|
|
+ :disabled="nodeFlag" @blur="handleCollectNumberBlur(index)"></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ <u-form-item label="库存数量" :prop="'recordList[' + index + '].kc'">
|
|
|
+ <u--input v-model="inputForm.recordList[index].kc" disabled></u--input>
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </u--form>
|
|
|
+
|
|
|
+ <user-select ref="userPicker" @input="handleUserSelected"></user-select>
|
|
|
+ <ba-tree-picker ref="treePicker" :multiple="false" @select-change="selectTypeChange" title="类型选择"
|
|
|
+ :localdata="listData" :selectedData="typeSelectedData" valueKey="value" textKey="label"
|
|
|
+ childrenKey="children" />
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { mapState } from 'vuex'
|
|
|
+import userSelect from '@/components/user-select/user-select-radio.vue'
|
|
|
+import baTreePicker from '@/components/ba-tree-picker/ba-tree-picker.vue'
|
|
|
+import UploadComponent from '@/pages/common/UploadComponent.vue'
|
|
|
+import upload from '@/utils/upload.js'
|
|
|
+import MaterialTypeService from '@/api/psi/MaterialTypeService'
|
|
|
+import WareHouseService from '@/api/psi/WareHouseService'
|
|
|
+import CollectService from '@/api/psi/CollectService'
|
|
|
+import CommonApi from '@/api/common/CommonApi'
|
|
|
+import CollectGoodsSelector from './CollectGoodsSelector.vue'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'PsiCollectForm',
|
|
|
+ components: {
|
|
|
+ userSelect,
|
|
|
+ baTreePicker,
|
|
|
+ UploadComponent,
|
|
|
+ CollectGoodsSelector
|
|
|
+ },
|
|
|
+ computed: mapState({
|
|
|
+ userInfo: (state) => state.user.userInfo
|
|
|
+ }),
|
|
|
+ props: {
|
|
|
+ businessId: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ formReadOnly: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ status: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ uploadUrl: upload.UPLOAD_URL,
|
|
|
+ nodeFlag: false,
|
|
|
+ loading: false,
|
|
|
+ listData: [],
|
|
|
+ materialList: [],
|
|
|
+ typeSelectedData: [],
|
|
|
+ inputForm: this.createInputForm(),
|
|
|
+ rules: {
|
|
|
+ collectDate: [
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ message: '领用时间不能为空',
|
|
|
+ trigger: ['change']
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ materialTypeService: null,
|
|
|
+ wareHouseService: null,
|
|
|
+ collectService: null,
|
|
|
+ commonApi: null,
|
|
|
+ created() {
|
|
|
+ this.ensureServices()
|
|
|
+ this.loadMaterialTypes()
|
|
|
+ this.fillUserInfo()
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ businessId: {
|
|
|
+ handler() {
|
|
|
+ if (this.businessId) {
|
|
|
+ this.init(this.businessId)
|
|
|
+ } else {
|
|
|
+ this.resetForm()
|
|
|
+ this.nodeFlag = this.formReadOnly || this.status === 'taskFormDetail' || this.status === 'testSee'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ deep: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ createInputForm() {
|
|
|
+ return {
|
|
|
+ id: '',
|
|
|
+ procInsId: '',
|
|
|
+ processDefinitionId: '',
|
|
|
+ status: '',
|
|
|
+ collectNo: '',
|
|
|
+ collectDate: '',
|
|
|
+ remarks: '',
|
|
|
+ handledBy: '',
|
|
|
+ handledById: '',
|
|
|
+ handledByOffice: '',
|
|
|
+ handledByOfficeName: '',
|
|
|
+ userId: '',
|
|
|
+ files: [],
|
|
|
+ detailInfos: [],
|
|
|
+ recordList: [],
|
|
|
+ returnId: '',
|
|
|
+ statusReturn: '',
|
|
|
+ procInsIdReturn: '',
|
|
|
+ processDefinitionIdReturn: '',
|
|
|
+ returnCause: '',
|
|
|
+ returnFiles: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ createDetailRow() {
|
|
|
+ return {
|
|
|
+ id: '',
|
|
|
+ recipientAgent: (this.userInfo && this.userInfo.name) || '',
|
|
|
+ recipientAgentId: (this.userInfo && this.userInfo.id) || '',
|
|
|
+ recipientOffice: (this.userInfo && this.userInfo.officeDTO && this.userInfo.officeDTO.name) || '',
|
|
|
+ collectType: '',
|
|
|
+ collectTypeId: '',
|
|
|
+ goodsName: '',
|
|
|
+ surplusNumber: '',
|
|
|
+ currentInventory: '',
|
|
|
+ collectNumber: '',
|
|
|
+ company: '',
|
|
|
+ remarks: '',
|
|
|
+ spec: '',
|
|
|
+ produceDate: '',
|
|
|
+ shelfLife: '',
|
|
|
+ shelfLifeUnit: '',
|
|
|
+ fileInfoLost: [],
|
|
|
+ isReturn: '0'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ensureServices() {
|
|
|
+ if (!this.materialTypeService) {
|
|
|
+ this.materialTypeService = new MaterialTypeService()
|
|
|
+ }
|
|
|
+ if (!this.wareHouseService) {
|
|
|
+ this.wareHouseService = new WareHouseService()
|
|
|
+ }
|
|
|
+ if (!this.collectService) {
|
|
|
+ this.collectService = new CollectService()
|
|
|
+ }
|
|
|
+ if (!this.commonApi) {
|
|
|
+ this.commonApi = new CommonApi()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async loadMaterialTypes() {
|
|
|
+ try {
|
|
|
+ const data = await this.materialTypeService.cgList()
|
|
|
+ this.materialList = data || []
|
|
|
+ this.listData = this.buildTree(this.materialList)
|
|
|
+ } catch (e) {
|
|
|
+ this.materialList = []
|
|
|
+ this.listData = []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fillUserInfo() {
|
|
|
+ if (!this.userInfo) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.inputForm.handledBy = this.inputForm.handledBy || this.userInfo.name
|
|
|
+ this.inputForm.handledById = this.inputForm.handledById || this.userInfo.id
|
|
|
+ this.inputForm.userId = this.inputForm.userId || this.userInfo.id
|
|
|
+ this.inputForm.handledByOffice = this.inputForm.handledByOffice || (this.userInfo.officeDTO && this.userInfo.officeDTO.id) || ''
|
|
|
+ this.inputForm.handledByOfficeName = this.inputForm.handledByOfficeName || (this.userInfo.officeDTO && this.userInfo.officeDTO.name) || ''
|
|
|
+ },
|
|
|
+ resetForm() {
|
|
|
+ this.inputForm = this.createInputForm()
|
|
|
+ this.fillUserInfo()
|
|
|
+ },
|
|
|
+ async init(id) {
|
|
|
+ this.ensureServices()
|
|
|
+ this.resetForm()
|
|
|
+ this.inputForm.id = id
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ const data = await this.collectService.findById(id)
|
|
|
+ this.inputForm = this.normalizeFormData(this.recover(this.createInputForm(), data))
|
|
|
+ this.inputForm.detailInfos.forEach(detail => {
|
|
|
+ if (detail.surplusNumber && detail.spec) {
|
|
|
+ detail.kc = this.formatNumber(Number(detail.surplusNumber) * Number(detail.spec))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.inputForm.recordList.forEach(record => {
|
|
|
+ if (record.surplusNumber && record.spec) {
|
|
|
+ record.kc = this.formatNumber(Number(record.surplusNumber) * Number(record.spec))
|
|
|
+ }
|
|
|
+ record.fpDate = `${record.goodsName}(生产日期:${record.produceDate})`
|
|
|
+ })
|
|
|
+ this.fillUserInfo()
|
|
|
+ this.nodeFlag = await this.resolveNodeFlag(data)
|
|
|
+ } catch (e) {
|
|
|
+ this.nodeFlag = true
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async resolveNodeFlag(data) {
|
|
|
+ if ((this.formReadOnly || this.status === 'taskFormDetail' || this.status === 'testSee')) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const taskName = await this.commonApi.getTaskNameByProcInsId((data && data.procInsId) || this.inputForm.procInsId)
|
|
|
+ if (this.isNotEmpty(taskName)) {
|
|
|
+ return taskName !== '发起人重新发起申请'
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ },
|
|
|
+ normalizeFormData(data) {
|
|
|
+ const form = data || this.createInputForm()
|
|
|
+ if (this.isNotEmpty(form.collectDate)) {
|
|
|
+ form.collectDate = new Date(form.collectDate)
|
|
|
+ }
|
|
|
+ form.files = form.files || []
|
|
|
+ form.detailInfos = (form.detailInfos || []).map(item => ({
|
|
|
+ ...item,
|
|
|
+ fileInfoLost: item.fileInfoLost || [],
|
|
|
+ produceDate: this.isNotEmpty(item.produceDate) ? new Date(item.produceDate) : '',
|
|
|
+ surplusNumber: this.isNotEmpty(item.surplusNumber) ? this.formatNumber(item.surplusNumber) : '',
|
|
|
+ currentInventory: this.isNotEmpty(item.currentInventory) ? this.formatNumber(item.currentInventory) : ''
|
|
|
+ }))
|
|
|
+ form.recordList = form.recordList || []
|
|
|
+ return form
|
|
|
+ },
|
|
|
+ buildTree(nodes, parentId = '0') {
|
|
|
+ const tree = []
|
|
|
+ for (const node of nodes || []) {
|
|
|
+ if (node.parentId === parentId) {
|
|
|
+ const children = this.buildTree(nodes, node.id)
|
|
|
+ if (children.length) {
|
|
|
+ node.children = children
|
|
|
+ }
|
|
|
+ tree.push(node)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return tree
|
|
|
+ },
|
|
|
+ isEmpty(value) {
|
|
|
+ if (value === null || value === undefined) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if (typeof value === 'string' && value.trim() === '') {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if (Array.isArray(value) && value.length === 0) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ },
|
|
|
+ isNotEmpty(value) {
|
|
|
+ return !this.isEmpty(value)
|
|
|
+ },
|
|
|
+ formatDate(date) {
|
|
|
+ if (this.isEmpty(date)) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ const dateValue = new Date(date)
|
|
|
+ if (Number.isNaN(dateValue.getTime())) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ const year = dateValue.getFullYear()
|
|
|
+ const month = `${dateValue.getMonth() + 1}`.padStart(2, '0')
|
|
|
+ const day = `${dateValue.getDate()}`.padStart(2, '0')
|
|
|
+ return `${year}-${month}-${day}`
|
|
|
+ },
|
|
|
+ normalizeDateFieldsBeforeValidate() {
|
|
|
+ if (this.isNotEmpty(this.inputForm.collectDate)) {
|
|
|
+ this.inputForm.collectDate = this.formatDate(this.inputForm.collectDate)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ formatNumber(value) {
|
|
|
+ const numberValue = Number(value || 0)
|
|
|
+ if (Number.isNaN(numberValue)) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ return numberValue % 1 === 0 ? String(numberValue) : numberValue.toFixed(2).replace(/\.?0+$/, '')
|
|
|
+ },
|
|
|
+ formatNumberInput(inputValue, decimalLimit = 2) {
|
|
|
+ if (this.isEmpty(inputValue)) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ const valueText = String(inputValue)
|
|
|
+ if (!/^\d*\.?\d*$/.test(valueText)) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ let value = valueText.replace(/[^\d.]/g, '')
|
|
|
+ const dotIndex = value.indexOf('.')
|
|
|
+ if (dotIndex !== -1) {
|
|
|
+ const substr = value.substr(dotIndex + 1)
|
|
|
+ if (substr.indexOf('.') !== -1) {
|
|
|
+ value = value.substr(0, dotIndex + 1) + substr.replace(/\./g, '')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (dotIndex !== -1) {
|
|
|
+ const integerPart = value.substring(0, dotIndex)
|
|
|
+ const decimalPart = value.substring(dotIndex + 1, dotIndex + 1 + decimalLimit)
|
|
|
+ value = integerPart + '.' + decimalPart
|
|
|
+ }
|
|
|
+ return value
|
|
|
+ },
|
|
|
+ addDetail() {
|
|
|
+ this.inputForm.detailInfos.push(this.createDetailRow())
|
|
|
+ },
|
|
|
+ removeDetail(index) {
|
|
|
+ this.inputForm.detailInfos.splice(index, 1)
|
|
|
+ },
|
|
|
+ patchDetail(index, patch) {
|
|
|
+ const detail = (this.inputForm.detailInfos || [])[index] || {}
|
|
|
+ this.$set(this.inputForm.detailInfos, index, {
|
|
|
+ ...detail,
|
|
|
+ ...patch
|
|
|
+ })
|
|
|
+ },
|
|
|
+ openUserPullForm(index) {
|
|
|
+ if (this.nodeFlag) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.$refs.userPicker.open(index, 'detail')
|
|
|
+ },
|
|
|
+ handleUserSelected(data, index, type) {
|
|
|
+ if (type !== 'detail') {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.patchDetail(index, {
|
|
|
+ recipientAgentId: data.id,
|
|
|
+ recipientAgent: data.label,
|
|
|
+ recipientOffice: data.parentLabel
|
|
|
+ })
|
|
|
+ },
|
|
|
+ openTypePicker(index) {
|
|
|
+ if (this.nodeFlag) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const detail = (this.inputForm.detailInfos || [])[index] || {}
|
|
|
+ this.typeSelectedData = detail.collectTypeId ? [detail.collectTypeId] : []
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const treePicker = this.$refs.treePicker
|
|
|
+ if (!treePicker) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (treePicker._initTree) {
|
|
|
+ treePicker._initTree()
|
|
|
+ }
|
|
|
+ treePicker._show(index)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ selectTypeChange(ids, names, index) {
|
|
|
+ this.patchDetail(index, {
|
|
|
+ collectType: names,
|
|
|
+ collectTypeId: ids[0],
|
|
|
+ goodsName: '',
|
|
|
+ surplusNumber: '',
|
|
|
+ currentInventory: '',
|
|
|
+ collectNumber: '',
|
|
|
+ company: '',
|
|
|
+ kc: '',
|
|
|
+ spec: '',
|
|
|
+ produceDate: '',
|
|
|
+ shelfLife: '',
|
|
|
+ shelfLifeUnit: ''
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async handleGoodsSelected({ index, item }) {
|
|
|
+ this.patchDetail(index, {
|
|
|
+ goodsName: item.tradeName || '',
|
|
|
+ kc: this.formatNumber(Number(item.tradeNumber) * Number(item.spec))
|
|
|
+ })
|
|
|
+ await this.syncDetailStock(index)
|
|
|
+ },
|
|
|
+ async syncDetailStock(index) {
|
|
|
+ const detail = (this.inputForm.detailInfos || [])[index]
|
|
|
+ if (!detail || this.isEmpty(detail.goodsName) || this.isEmpty(detail.collectTypeId)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const data = await this.wareHouseService.getByProduceDateNotMerge({
|
|
|
+ current: 1,
|
|
|
+ size: 1000,
|
|
|
+ tradeName: detail.goodsName,
|
|
|
+ wareHouseType: detail.collectTypeId
|
|
|
+ })
|
|
|
+ const records = (data && data.records) || []
|
|
|
+ const totalBottle = records.reduce((sum, item) => {
|
|
|
+ const currentInventory = Number(item.currentInventory || 0)
|
|
|
+ const spec = Number(item.spec || 1)
|
|
|
+ return sum + currentInventory * (spec > 0 ? spec : 1)
|
|
|
+ }, 0)
|
|
|
+ const firstRecord = records[0] || {}
|
|
|
+ this.patchDetail(index, {
|
|
|
+ surplusNumber: this.formatNumber(totalBottle),
|
|
|
+ currentInventory: this.formatNumber(totalBottle),
|
|
|
+ company: firstRecord.company || detail.company || '',
|
|
|
+ spec: firstRecord.spec || '',
|
|
|
+ produceDate: this.isNotEmpty(firstRecord.produceDate) ? new Date(firstRecord.produceDate) : '',
|
|
|
+ shelfLife: firstRecord.shelfLife || '',
|
|
|
+ shelfLifeUnit: firstRecord.shelfLifeUnit || ''
|
|
|
+ })
|
|
|
+ } catch (e) {
|
|
|
+ this.patchDetail(index, {
|
|
|
+ surplusNumber: '',
|
|
|
+ currentInventory: ''
|
|
|
+ })
|
|
|
+ uni.showToast({
|
|
|
+ title: '库存数量加载失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleCollectNumberBlur(index) {
|
|
|
+ const detail = (this.inputForm.detailInfos || [])[index]
|
|
|
+ if (!detail) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ detail.collectNumber = this.formatNumberInput(detail.collectNumber)
|
|
|
+ if (this.isNotEmpty(detail.surplusNumber) && this.isNotEmpty(detail.collectNumber) &&
|
|
|
+ Number(detail.collectNumber) > Number(detail.surplusNumber)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '领用数量不能大于库存数量',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ detail.collectNumber = ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleUploadSuccess(file, fileList, index, type) {
|
|
|
+ if (type === 'detail') {
|
|
|
+ this.inputForm.detailInfos[index].fileInfoLost = fileList
|
|
|
+ } else {
|
|
|
+ this.inputForm.files = fileList
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleRemove(file, fileList, lineIndex, fileIndex, type) {
|
|
|
+ if (type === 'detail') {
|
|
|
+ this.inputForm.detailInfos[lineIndex].fileInfoLost.splice(fileIndex, 1)
|
|
|
+ } else {
|
|
|
+ this.inputForm.files.splice(fileIndex, 1)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ validateDetailInfos() {
|
|
|
+ if (this.isEmpty(this.inputForm.detailInfos)) {
|
|
|
+ this.$message.error('至少填写一条领用详情信息')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ for (let i = 0; i < this.inputForm.detailInfos.length; i++) {
|
|
|
+ const detail = this.inputForm.detailInfos[i]
|
|
|
+ const lineNo = i + 1
|
|
|
+ if (this.isEmpty(detail.recipientAgentId)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: `领用详情第${lineNo}行请选择领用人`,
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.isEmpty(detail.collectTypeId)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: `领用详情第${lineNo}行请选择领用类型`,
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.isEmpty(detail.goodsName)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: `领用详情第${lineNo}行请选择物品名称`,
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.isEmpty(detail.collectNumber)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: `领用详情第${lineNo}行请输入领用数量`,
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.isNotEmpty(detail.surplusNumber) && Number(detail.collectNumber) > Number(detail.surplusNumber)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: `领用详情第${lineNo}行领用数量不能大于库存数量`,
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ },
|
|
|
+ toSubmitData() {
|
|
|
+ const data = JSON.parse(JSON.stringify(this.inputForm))
|
|
|
+ data.collectDate = this.formatDate(this.inputForm.collectDate)
|
|
|
+ data.detailInfos = (this.inputForm.detailInfos || []).map(item => ({
|
|
|
+ ...JSON.parse(JSON.stringify(item)),
|
|
|
+ produceDate: this.formatDate(item.produceDate)
|
|
|
+ }))
|
|
|
+ return data
|
|
|
+ },
|
|
|
+ async saveForm(callback) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // 表单规则验证
|
|
|
+ // ...
|
|
|
+
|
|
|
+ let errors = [];
|
|
|
+
|
|
|
+ if (this.isNotEmpty(this.inputForm.collectDate)) {
|
|
|
+ this.inputForm.collectDate = this.formatDate(this.inputForm.collectDate);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.isEmpty(this.inputForm.detailInfos)) {
|
|
|
+ errors.push('至少填写一条领用详情信息');
|
|
|
+ } else {
|
|
|
+ let i = this.inputForm.detailInfos.length;
|
|
|
+ for (let j = 0; j < i; j++) {
|
|
|
+ let k = j + 1;
|
|
|
+ if (this.isEmpty(this.inputForm.detailInfos[j].recipientAgent)) {
|
|
|
+ errors.push('领用详情第' + k + '行请选择领用人');
|
|
|
+ } else if (this.isEmpty(this.inputForm.detailInfos[j].collectType)) {
|
|
|
+ errors.push('领用详情第' + k + '行请选择领用类型');
|
|
|
+ } else if (this.isEmpty(this.inputForm.detailInfos[j].goodsName)) {
|
|
|
+ errors.push('领用详情第' + k + '行请选择物品名称');
|
|
|
+ } else if (this.isEmpty(this.inputForm.detailInfos[j].collectNumber)) {
|
|
|
+ errors.push('领用详情第' + k + '行请输入领用数量');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (parseFloat(this.inputForm.detailInfos[j].collectNumber) > parseFloat(this.inputForm.detailInfos[j].surplusNumber) * parseFloat(this.inputForm.detailInfos[j].spec)) {
|
|
|
+ errors.push('领用详情第' + k + '行请输入领用数量');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (errors.length > 0) {
|
|
|
+ // 存在错误,显示提示信息
|
|
|
+ errors.forEach(error => {
|
|
|
+ uni.showToast({
|
|
|
+ title: error,
|
|
|
+ icon: 'none',
|
|
|
+ duration: 2000
|
|
|
+ });
|
|
|
+ });
|
|
|
+ reject('Form validation failed');
|
|
|
+ } else {
|
|
|
+ // 所有验证通过,执行保存操作
|
|
|
+ this.$refs.inputForm.validate().then(async () => {
|
|
|
+ uni.showLoading();
|
|
|
+ try {
|
|
|
+ const submitData = this.toSubmitData()
|
|
|
+ submitData.status = '2'
|
|
|
+ this.inputForm.status = '2'
|
|
|
+ const data = await this.collectService.save(submitData)
|
|
|
+ callback(data.businessTable, data.businessId, submitData)
|
|
|
+ resolve('Form saved successfully');
|
|
|
+ } finally {
|
|
|
+ reject('Save operation failed');
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ reject('Form validation failed');
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async startForm(callback) {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ if (this.isNotEmpty(this.inputForm.id)) {
|
|
|
+ const data = await this.collectService.findById(this.inputForm.id)
|
|
|
+ if (this.isNotEmpty(data.status) && !['0', '1', '3'].includes(data.status)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ throw new Error('invalid status')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await this.startFormTrue(callback)
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async startFormTrue(callback) {
|
|
|
+ this.normalizeDateFieldsBeforeValidate()
|
|
|
+ await this.$refs.inputForm.validate()
|
|
|
+ if (!this.validateDetailInfos()) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const submitData = this.toSubmitData()
|
|
|
+ submitData.status = '2'
|
|
|
+ this.inputForm.status = '2'
|
|
|
+ const data = await this.collectService.save(submitData)
|
|
|
+ this.inputForm.id = data.businessId
|
|
|
+ callback(data.businessTable, data.businessId, submitData)
|
|
|
+ },
|
|
|
+ async reapplyForm(callback) {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ const data = await this.collectService.findById(this.inputForm.id)
|
|
|
+ if (data.status !== '4') {
|
|
|
+ uni.showToast({
|
|
|
+ title: '任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ throw new Error('invalid status')
|
|
|
+ }
|
|
|
+ await this.startFormTrue(callback)
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async agreeForm(callback) {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ this.normalizeDateFieldsBeforeValidate()
|
|
|
+ await this.$refs.inputForm.validate()
|
|
|
+ if (!this.validateDetailInfos()) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const submitData = this.toSubmitData()
|
|
|
+ try {
|
|
|
+ const taskName = await this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId)
|
|
|
+ if (this.isNotEmpty(taskName) && taskName === '仓库管理员审核') {
|
|
|
+ submitData.status = '5'
|
|
|
+ this.inputForm.status = '5'
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ }
|
|
|
+ const data = await this.collectService.save(submitData)
|
|
|
+ callback(data.businessTable, data.businessId, submitData)
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async updateStatusById(type, callback) {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ if (type === 'reject' || type === 'reback') {
|
|
|
+ const data = await this.collectService.findById(this.inputForm.id)
|
|
|
+ if (data.status !== '2') {
|
|
|
+ this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
|
|
|
+ throw new Error('invalid status')
|
|
|
+ }
|
|
|
+ const nextStatus = type === 'reject' ? '4' : '3'
|
|
|
+ this.inputForm.status = nextStatus
|
|
|
+ await this.collectService.updateStatusById({
|
|
|
+ status: nextStatus,
|
|
|
+ id: this.inputForm.id
|
|
|
+ })
|
|
|
+ callback()
|
|
|
+ } else if (type === 'hold') {
|
|
|
+ const data = await this.collectService.findById(this.inputForm.id)
|
|
|
+ if (data.status !== '4') {
|
|
|
+ this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
|
|
|
+ throw new Error('invalid status')
|
|
|
+ }
|
|
|
+ this.inputForm.status = '1'
|
|
|
+ await this.collectService.updateStatusById({
|
|
|
+ status: '1',
|
|
|
+ id: this.inputForm.id
|
|
|
+ })
|
|
|
+ callback()
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async openPicker(index) {
|
|
|
+ if (this.isEmpty(this.inputForm.detailInfos[index].collectTypeId)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '请先选择领用类型',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ await this.$refs.goodsSelect.loadGoodsList()
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.section-wrap {
|
|
|
+ margin-top: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+ padding-left: 8rpx;
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #1f2937;
|
|
|
+ border-left: 6rpx solid #2979ff;
|
|
|
+}
|
|
|
+
|
|
|
+.section-tip {
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #64748b;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-card {
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ box-shadow: 0 10rpx 30rpx rgba(15, 23, 42, 0.05);
|
|
|
+}
|
|
|
+
|
|
|
+.detail-card-title {
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #0f172a;
|
|
|
+}
|
|
|
+</style>
|