Your Name
2022-11-30 bb7db62b1663c3b30830e1604731c2197f46af75
物资
已修改5个文件
已添加13个文件
已删除2个文件
9479 ■■■■ 文件已修改
.env.development 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/shelf/Uncommitted_changes_before_Update_at_2022_10_13_14_41_[Default_Changelist]/shelved.patch 6817 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/shelf/Uncommitted_changes_before_Update_at_2022_10_13_14_41__Default_Changelist_.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/facilityManagement/goodsDetailManage/index.ts 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/facilityManagement/safetyGoodsAndEquipment/index.ts 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/interface/index.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/userInfo.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/toolsValidate.ts 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/goodsDetailManage/components/checkOut.vue 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/goodsDetailManage/components/goodsDetailAdd.vue 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/goodsDetailManage/components/goodsDetailEdit.vue 224 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/goodsDetailManage/index.ts 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/goodsDetailManage/index.vue 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/safetyGoodsAndEquipment/components/addGoodsDialog.vue 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/safetyGoodsAndEquipment/components/batchInStorage.vue 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/safetyGoodsAndEquipment/components/batchOutStorage.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/safetyGoodsAndEquipment/components/safetyGoodsAndEquipmentDialog.vue 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/safetyGoodsAndEquipment/index.ts 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/facilityManagement/safetyGoodsAndEquipment/index.vue 326 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
static/loginPage.js/login.js 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -29,6 +29,9 @@
#本地外包预发接口地址
VITE_API_URL_OUT = 'http://192.168.0.50:8009'
#张凤外包接口地址
#VITE_API_URL_OUT = 'http://192.168.0.52:7021/safeplatform-out'
.idea/shelf/Uncommitted_changes_before_Update_at_2022_10_13_14_41_[Default_Changelist]/shelved.patch
文件已删除
.idea/shelf/Uncommitted_changes_before_Update_at_2022_10_13_14_41__Default_Changelist_.xml
文件已删除
src/api/facilityManagement/goodsDetailManage/index.ts
对比新文件
@@ -0,0 +1,89 @@
import request from '/@/utils/request';
export function goodsDetailApi() {
    return {
        // 设备设施类型管理 查询单条数据
        getGoodsDetailList: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/page/list`,
                method: 'post',
                data
            });
        },
        addGoodsDetail: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/save`,
                method: 'post',
                data
            });
        },
        checkOutBySingle: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/single/delivery`,
                method: 'post',
                data
            });
        },
        checkOutByMore: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/batch/delivery/ids`,
                method: 'post',
                data
            });
        },
        updateGoodsDetail: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/update`,
                method: 'post',
                data
            });
        },
        getGoodsListByLevel: () => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/safeMaterial/list`,
                method: 'post',
            });
        },
        checkOutOne: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/single/delivery`,
                method: 'post',
                data
            });
        },
        checkOutMore: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/batch/delivery/ids`,
                method: 'post',
                data
            });
        },
        checkInOne: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/single/receipt`,
                method: 'post',
                data
            });
        },
        checkInMore: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/batch/receipt`,
                method: 'post',
                data
            });
        },
        deleteSingleGoods: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/delete`,
                method: 'post',
                data
            });
        },
        deleteBatchGoods: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/deleteBatch`,
                method: 'post',
                data
            });
        },
    }
}
src/api/facilityManagement/safetyGoodsAndEquipment/index.ts
对比新文件
@@ -0,0 +1,82 @@
import request from '/@/utils/request';
export function goodsAndEquipmentApi() {
    return {
        // 设备设施类型管理 查询单条数据
        getGoodsEquipmentData: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/safeMaterial/page/list`,
                method: 'post',
                data
            });
        },
        getAllSafetyEquipment: () => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/classify/list`,
                method: 'post',
            });
        },
        getAllSafetyEquipmentByPage: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/classify/page/list`,
                method: 'post',
                data
            });
        },
        addGoodsEquipment: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/safeMaterial/save`,
                method: 'post',
                data
            });
        },
        updateGoodsEquipment: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/safeMaterial/update`,
                method: 'post',
                data
            });
        },
        deleteGoodsEquipment: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/safeMaterial/delete`,
                method: 'post',
                data
            });
        },
        addGoodsClassify: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/classify/save`,
                method: 'post',
                data
            });
        },
        updateGoodsClassify: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/classify/update`,
                method: 'post',
                data
            });
        },
        deleteGoodsClassify: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/classify/delete`,
                method: 'post',
                data
            });
        },
        batchInStorageGoods: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/saveBatch`,
                method: 'post',
                data
            });
        },
        batchOutStorageGoods: (data: {}) => {
            return request({
                url: import.meta.env.VITE_API_URL_OUT + `/equipment/smDetail/batch/delivery/random`,
                method: 'post',
                data
            });
        },
    }
}
src/stores/interface/index.ts
@@ -11,6 +11,7 @@
    time: number;
    userName: string;
    uid: string;
    depId: string;
    projectId: string;
    dataList: [];
}
src/stores/userInfo.ts
@@ -15,6 +15,7 @@
            roles: [],
            authBtnList: [],
            uid: '',
            depId: '',
            projectId: '',
            dataList: []
        }
@@ -25,6 +26,7 @@
            this.userInfos.userName = value.realName;
            this.userInfos.uid = value.uid;
            this.userInfos.roles = value.role;
            this.userInfos.depId = value.depId
            // const userName = Cookies.get('userName');
            // // 模拟数据
            // let defaultRoles: Array<string> = [];
src/utils/toolsValidate.ts
@@ -60,6 +60,26 @@
}
/**
 * 0到9
 * @param val 当前值字符串
 * @returns 返回处理后的字符串
 */
export function verifyString(val: string) {
    let v = val.replace(/(^\s*)|(\s*$)/g, '');
    // 只能是数字和小数点,不能是其他输入
    v = v.replace(/[^\d.]/g, '');
    // 以0开始只能输入一个
    v = v.replace(/^\./g, '');
    // 小数只能出现1位
    v = v.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
    // 小数点后面保留2位
    v = v.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3');
    // 返回结果
    return v;
}
/**
 * 正整数验证
 * @param val 当前值字符串
 * @returns 返回处理后的字符串
src/views/facilityManagement/goodsDetailManage/components/checkOut.vue
对比新文件
@@ -0,0 +1,133 @@
<template>
    <div>
        <el-dialog :title="checkOutState.title" :close-on-click-modal="false"  v-model="checkOutState.checkOutDialogVisible" width="30%">
            <el-form
                :model="checkOutState.checkOutForm"
                ref="checkOutFormRef"
                size="default"
                v-loading="checkOutState.loading"
                element-loading-text="Loading..."
                label-width="150px">
                <el-row>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="当前所选物资:">
                            <el-input v-model="checkOutState.materialName" :readonly="true" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="认领人:" prop="claimantId">
                            <el-select class="input-add" v-model="checkOutState.checkOutForm.claimantId" placeholder="选择认领人">
                                <el-option
                                    v-for="item in checkOutState.userList"
                                    :key="item.uid"
                                    :value="item.uid"
                                    :label="item.realName"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button :disabled="checkOutState.loading" @click="checkOutState.batchOutStorageDialogVisible = !checkOutState.batchOutStorageDialogVisible" size="default">取 消</el-button>
                    <el-button :disabled="checkOutState.loading" type="primary" @click="submitCheckOutForm" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script setup lang="ts">
import {defineEmits, reactive} from "vue";
import {checkOutStateType, GoodsDetailDataType} from "/@/views/facilityManagement/goodsDetailManage/index";
import {teamManageApi} from "/@/api/systemManage/basicDateManage/personShiftManage/teamManage";
import {ElMessage} from "element-plus/es";
import {goodsDetailApi} from "/@/api/facilityManagement/goodsDetailManage";
const checkOutState = reactive<checkOutStateType>({
    title: '',
    loading: false,
    checkOutDialogVisible: false,
    materialName: '',
    checkOutForm: {
        id: null,
        claimantId: null,
        ids: [],
    },
    userList: [],
})
const openCheckOutDialog = (title: string, value: GoodsDetailDataType, ids:Array<number>, checkOutName: null | string) => {
    checkOutState.title = title;
    checkOutState.checkOutDialogVisible = true;
    checkOutState.checkOutForm.claimantId = null;
    getUserByDepartment(1 as number)
    if(title === '单独出库'){
        checkOutState.materialName = value.name as string
        checkOutState.checkOutForm.id = value.id;
    }else{
        checkOutState.materialName = checkOutName as string
        checkOutState.checkOutForm.ids = ids
    }
}
const submitCheckOutForm = async () => {
    if(checkOutState.checkOutForm.claimantId === null){
        ElMessage({
            type: 'warning',
            message: '请选择认领人'
        })
    }else{
        checkOutState.loading = true
        let res = await (checkOutState.title === '单独出库' ? goodsDetailApi().checkOutBySingle(checkOutState.checkOutForm) : goodsDetailApi().checkOutByMore(checkOutState.checkOutForm))
        if(res.data.code === '200'){
            checkOutState.checkOutDialogVisible = false
            emit('refreshGoodsDetail')
            ElMessage({
                type: 'success',
                message:'认领成功'
            })
        }else{
            ElMessage({
                type: 'warning',
                message: res.data.msg
            })
        }
        checkOutState.loading = false
    }
}
const getUserByDepartment = async (value: number) => {
    let res = await teamManageApi().getAllMember(value);
    if (res.data.code === '200') {
        checkOutState.userList = JSON.parse(JSON.stringify(res.data.data));
    } else {
        ElMessage({
            type: 'warning',
            message: res.data.msg
        });
    }
}
const emit = defineEmits(['refreshGoodsDetail'])
defineExpose({
    openCheckOutDialog
})
</script>
<style scoped>
:deep(.el-dialog__header) {
    padding: var(--el-dialog-padding-primary);
    padding-bottom: 10px;
    margin-right: 16px;
    word-break: break-all;
    text-align: center !important;
}
</style>
src/views/facilityManagement/goodsDetailManage/components/goodsDetailAdd.vue
对比新文件
@@ -0,0 +1,273 @@
<template>
    <div class="system-add-menu-container">
        <el-dialog :title="goodsDetailAddState.title" :close-on-click-modal="false" v-model="goodsDetailAddState.goodsDetailAddVisible" width="30%">
            <el-form
                :model="goodsDetailAddState.goodsDetailForm"
                :rules="goodsDetailAddState.goodsDetailRules"
                ref="goodsDetailFormRef"
                size="default"
                v-loading="goodsDetailAddState.loading"
                element-loading-text="Loading..."
                label-width="120px">
                <el-row>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="选择物资" prop="smId">
                            <el-row :gutter="6">
                                <el-col :span="8">
                                    <el-select
                                        filterable
                                        placeholder="请选择部门"
                                        clearable
                                        @change="changeDepartment"
                                        v-model="goodsDetailAddState.depId">
                                        <el-option
                                            v-for="item in goodsDetailAddState.departmentList"
                                            :key="item.depId"
                                            :value="item.depId"
                                            :label="item.depName"
                                        ></el-option>
                                    </el-select>
                                </el-col>
                                <el-col :span="8">
                                    <el-select v-model="goodsDetailAddState.classifyId" placeholder="选择分类" @change="changeClassify" filterable clearable>
                                        <el-option
                                            v-for="item in goodsDetailAddState.classifyList"
                                            :key="item.materialClassifyId"
                                            :value="item.materialClassifyId"
                                            :label="item.materialClassifyName"
                                        ></el-option>
                                    </el-select>
                                </el-col>
                                <el-col :span="8">
                                    <el-select v-model="goodsDetailAddState.goodsDetailForm.smId" placeholder="选择物资" filterable clearable>
                                        <el-option
                                            v-for="item in goodsDetailAddState.goodsList"
                                            :key="item.smId"
                                            :value="item.smId"
                                            :label="item.materialName"
                                        ></el-option>
                                    </el-select>
                                </el-col>
                            </el-row>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-row :gutter="6">
                            <el-col :span="12">
                                <el-form-item label="RFID起:" prop="startRfid">
                                    <el-input v-model="goodsDetailAddState.RFID" placeholder="选填">
                                    </el-input>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-input v-model="goodsDetailAddState.startRfid" @blur="checkLength('start')" @input="onVerifiyNumberInteger($event, 'start')" placeholder="选填">
                                </el-input>
                            </el-col>
                        </el-row>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-row :gutter="6">
                            <el-col :span="12">
                                <el-form-item label="RFID止:" prop="endRfid">
                                    <el-input v-model="goodsDetailAddState.RFID" placeholder="选填">
                                    </el-input>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-input @blur="checkLength('end')" @input="onVerifiyNumberInteger($event, 'end')" v-model="goodsDetailAddState.endRfid" placeholder="选填">
                                </el-input>
                            </el-col>
                        </el-row>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="入库数量:" prop="wareHousingCount">
                            <el-input @input="onVerifiyNumberInteger($event, 'wareHousingCount')"  v-model="goodsDetailAddState.goodsDetailForm.wareHousingCount" placeholder="入库总数">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="有效期类型:" prop="validType">
                            <el-radio-group v-model="goodsDetailAddState.goodsDetailForm.validType">
                                <el-radio :label="0">长期</el-radio>
                                <el-radio :label="1">非长期</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20" v-if="goodsDetailAddState.goodsDetailForm.validType === 1">
                        <el-form-item label="有效期至:" prop="validTime">
                            <el-date-picker
                                v-model="goodsDetailAddState.goodsDetailForm.validTime"
                                type="datetime"
                                format="YYYY-MM-DD HH:mm:ss"
                                value-format="YYYY-MM-DD HH:mm:ss"
                                placeholder="选择日期时间"
                                style="width: 100%" />
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="goodsDetailAddState.goodsDetailAddVisible = !goodsDetailAddState.goodsDetailAddVisible" size="default">取 消</el-button>
                    <el-button type="primary" @click="submitGoodsDetail" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script lang="ts" setup>
import {reactive, ref, watch} from 'vue'
import {
    BaseMaterialListType,
    ClassificationListType,
    DepartmentType,
    GoodsDetailDataType,
    GoodsDetailAddType
} from "/@/views/facilityManagement/goodsDetailManage/index";
import {isValidKey} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import {ElMessage} from "element-plus/es";
import {goodsDetailApi} from "/@/api/facilityManagement/goodsDetailManage";
import {verifiyNumberInteger, verifyString} from "/@/utils/toolsValidate";
const goodsDetailFormRef = ref()
const goodsDetailAddState = reactive<GoodsDetailAddType>({
    title: '新增入库',
    RFID: 'RFIDXXX',
    startRfid: '',
    endRfid: '',
    depId: null,
    loading: false,
    classifyId: null,
    goodsDetailAddVisible: false,
    goodsDetailForm: {
        id: null,
        smId: null,
        validType: null,
        validTime: null,
        startRfid:  null,
        endRfid:  null ,
        wareHousingCount:  null,
    },
    goodsDetailRules: {
        smId: [{ required: true, message: '请选择物资名称', trigger: 'change' }],
        validType: [{ required: true, message: '请选择时间类型', trigger: 'change' }],
        validTime: [{ required: true, message: '请选择有效时间', trigger: 'change' }],
        wareHousingCount: [{ required: true, message: '请填写入库数量', trigger: 'blur' }],
    },
    departmentList: [],
    classifyList: [],
    goodsList: [],
})
watch(() => [goodsDetailAddState.startRfid,goodsDetailAddState.endRfid],(newVal, oldVal) => {
    if(goodsDetailAddState.startRfid.length === 8 && goodsDetailAddState.endRfid.length === 8){
        goodsDetailAddState.goodsDetailForm.wareHousingCount = Number(goodsDetailAddState.endRfid) - Number(goodsDetailAddState.startRfid) + 1
    }
},{immediate :false});
const openGoodsDetailAddDialog = async (title: string, value: GoodsDetailDataType, departmentList: DepartmentType []) => {
    goodsDetailAddState.goodsDetailAddVisible = true;
    goodsDetailAddState.departmentList = departmentList;
    setTimeout(() => {
        goodsDetailFormRef.value.clearValidate();
    });
    goodsDetailAddState.startRfid = ''
    goodsDetailAddState.endRfid = ''
    goodsDetailAddState.goodsDetailForm = {
        id: null,
        smId: null,
        validType: null,
        validTime: null,
        startRfid:  null,
        endRfid:  null ,
        wareHousingCount:  null,
    }
}
const changeDepartment = (value: number | null) => {
    goodsDetailAddState.classifyId = null
    goodsDetailAddState.goodsDetailForm.smId = null
    goodsDetailAddState.classifyList = goodsDetailAddState.departmentList.find(item => item.depId === value)?.classificationList as Array<ClassificationListType>
}
const changeClassify = (value: number | null) => {
    goodsDetailAddState.goodsDetailForm.smId = null
    goodsDetailAddState.goodsList = goodsDetailAddState.classifyList.find(item => item.materialClassifyId === value)?.baseMaterialList as Array<BaseMaterialListType>
}
const submitGoodsDetail = () => {
    goodsDetailFormRef.value.validate(async (valid: boolean) => {
        if(valid){
            goodsDetailAddState.goodsDetailForm.startRfid = `RFID${goodsDetailAddState.startRfid}`
            goodsDetailAddState.goodsDetailForm.endRfid = `RFID${goodsDetailAddState.endRfid}`
            goodsDetailAddState.loading = true
            let res = await goodsDetailApi().addGoodsDetail(goodsDetailAddState.goodsDetailForm)
            if(res.data.code === '200'){
                goodsDetailAddState.goodsDetailAddVisible = false
                emit('refreshData')
                ElMessage({
                    type: 'success',
                    message: '物资新增成功',
                    duration: 2000
                });
            }else{
                ElMessage({
                    type:'warning',
                    message:res.data.msg
                })
            }
            goodsDetailAddState.loading = false
        }else{
            ElMessage({
                type: 'warning',
                message: '请完善基本信息'
            })
        }
    })
}
const checkLength = (value: string) => {
    if(value === 'start' && goodsDetailAddState.startRfid.length !== 8){
        ElMessage({
            type:'warning',
            message: 'RFID起不符合规范,请重新填入'
        })
        goodsDetailAddState.startRfid = ''
        goodsDetailAddState.goodsDetailForm.wareHousingCount = null
    }else if(value === 'end' && goodsDetailAddState.endRfid.length !== 8){
        ElMessage({
            type:'warning',
            message: 'RFID止不符合规范,请重新填入'
        })
        goodsDetailAddState.endRfid = ''
        goodsDetailAddState.goodsDetailForm.wareHousingCount = null
    }else{
        return
    }
}
const onVerifiyNumberInteger = (val: number, title: string) => {
    if(title === 'wareHousingCount'){
        goodsDetailAddState.goodsDetailForm.wareHousingCount = Number(verifiyNumberInteger(val.toString())) === 0 ? null : Number(verifiyNumberInteger(val.toString()));
    }else if(title === 'start'){
        goodsDetailAddState.startRfid = verifyString(val.toString());
    }else{
        goodsDetailAddState.endRfid = verifyString(val.toString());
    }
};
const emit = defineEmits(['refreshData',])
defineExpose({
    openGoodsDetailAddDialog
})
</script>
<style scoped>
</style>
src/views/facilityManagement/goodsDetailManage/components/goodsDetailEdit.vue
对比新文件
@@ -0,0 +1,224 @@
<template>
    <div class="system-add-menu-container">
        <el-dialog :title="goodsDetailEditState.title" :close-on-click-modal="false" v-model="goodsDetailEditState.goodsDetailEditVisible" width="30%">
            <el-form
                :model="goodsDetailEditState.goodsDetailForm"
                :rules="goodsDetailEditState.goodsDetailRules"
                ref="goodsDetailFormRef"
                size="default"
                v-loading="goodsDetailEditState.loading"
                element-loading-text="Loading..."
                label-width="120px">
                <el-row>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="选择物资" prop="smId">
                            <el-row :gutter="6">
                                <el-col :span="8">
                                    <el-select
                                        filterable
                                        placeholder="请选择部门"
                                        clearable
                                        @change="changeDepartment"
                                        v-model="goodsDetailEditState.depId">
                                        <el-option
                                        v-for="item in goodsDetailEditState.departmentList"
                                        :key="item.depId"
                                        :value="item.depId"
                                        :label="item.depName"
                                        ></el-option>
                                    </el-select>
                                </el-col>
                                <el-col :span="8">
                                    <el-select v-model="goodsDetailEditState.classifyId" placeholder="选择分类" @change="changeClassify" filterable clearable>
                                        <el-option
                                        v-for="item in goodsDetailEditState.classifyList"
                                        :key="item.materialClassifyId"
                                        :value="item.materialClassifyId"
                                        :label="item.materialClassifyName"
                                        ></el-option>
                                    </el-select>
                                </el-col>
                                <el-col :span="8">
                                    <el-select v-model="goodsDetailEditState.goodsDetailForm.smId" placeholder="选择物资" filterable clearable>
                                        <el-option
                                            v-for="item in goodsDetailEditState.goodsList"
                                            :key="item.smId"
                                            :value="item.smId"
                                            :label="item.materialName"
                                        ></el-option>
                                    </el-select>
                                </el-col>
                            </el-row>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="按RFID标记:" prop="rfid">
                            <el-input v-model="goodsDetailEditState.goodsDetailForm.rfid" placeholder="选填">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="有效期类型:" prop="validType">
                            <el-radio-group v-model="goodsDetailEditState.goodsDetailForm.validType">
                                <el-radio :label="0">长期</el-radio>
                                <el-radio :label="1">非长期</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20" v-if="goodsDetailEditState.goodsDetailForm.validType === 1">
                        <el-form-item label="有效期至:" prop="validTime">
                            <el-date-picker
                                v-model="goodsDetailEditState.goodsDetailForm.validTime"
                                type="datetime"
                                format="YYYY-MM-DD HH:mm:ss"
                                value-format="YYYY-MM-DD HH:mm:ss"
                                placeholder="选择日期时间"
                                style="width: 100%" />
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="goodsDetailEditState.goodsDetailEditVisible = !goodsDetailEditState.goodsDetailEditVisible" size="default">取 消</el-button>
                    <el-button type="primary" @click="submitGoodsDetail" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script lang="ts" setup>
import {reactive, ref, watch} from 'vue'
import {
    BaseMaterialListType,
    ClassificationListType,
    DepartmentType,
    GoodsDetailDataType,
    GoodsDetailEditType
} from "/@/views/facilityManagement/goodsDetailManage/index";
import {isValidKey} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import {ElMessage} from "element-plus/es";
import {goodsDetailApi} from "/@/api/facilityManagement/goodsDetailManage";
const goodsDetailFormRef = ref()
const goodsDetailEditState = reactive<GoodsDetailEditType>({
    title: '编辑',
    depId: null,
    loading: false,
    classifyId: null,
    goodsDetailEditVisible: false,
    goodsDetailForm: {
        id: null,
        smId: null,
        rfid: null,
        validType: null,
        validTime: null,
    },
    goodsDetailRules: {
        smId: [{ required: true, message: '请选择物资名称', trigger: 'change' }],
        validType: [{ required: true, message: '请选择时间类型', trigger: 'change' }],
        validTime: [{ required: true, message: '请选择有效时间', trigger: 'change' }],
    },
    departmentList: [],
    classifyList: [],
    goodsList: [],
})
// watch(() => goodsDetailEditState.depId ,(newVal, oldVal) => {
//     debugger
//     goodsDetailEditState.classify = null
//     goodsDetailEditState.goodsDetailForm.smId = null
//     goodsDetailEditState.classifyList = goodsDetailEditState.departmentList.find(item => item.depId === newVal)?.classificationList as Array<ClassificationListType>
// },{immediate :false});
const openGoodsDetailEditDialog = async (title: string, value: GoodsDetailDataType, departmentList: DepartmentType []) => {
    goodsDetailEditState.goodsDetailEditVisible = true;
    goodsDetailEditState.departmentList = departmentList;
    setTimeout(() => {
        goodsDetailFormRef.value.clearValidate();
    });
    await changeDepartment(value.depId)
    await changeClassify(value.bigClassifyId)
    goodsDetailEditState.depId = value.depId
    goodsDetailEditState.classifyId = value.bigClassifyId
    for(let i in goodsDetailEditState.goodsDetailForm){
        if(isValidKey(i, goodsDetailEditState.goodsDetailForm)) {
            goodsDetailEditState.goodsDetailForm[i] = value[i];
        }
    }
}
const changeDepartment = (value: number | null) => {
    goodsDetailEditState.classifyId = null
    goodsDetailEditState.goodsDetailForm.smId = null
    goodsDetailEditState.classifyList = goodsDetailEditState.departmentList.find(item => item.depId === value)?.classificationList as Array<ClassificationListType>
}
const changeClassify = (value: number | null) => {
    goodsDetailEditState.goodsDetailForm.smId = null
    goodsDetailEditState.goodsList = goodsDetailEditState.classifyList.find(item => item.materialClassifyId === value)?.baseMaterialList as Array<BaseMaterialListType>
}
const submitGoodsDetail = () => {
    goodsDetailFormRef.value.validate(async (valid: boolean) => {
        if(valid){
            goodsDetailEditState.loading = true
            if(goodsDetailEditState.title === '新增入库') {
                let res = await goodsDetailApi().addGoodsDetail(goodsDetailEditState.goodsDetailForm)
                if(res.data.code === '200'){
                    goodsDetailEditState.goodsDetailEditVisible = false
                    emit('refreshData')
                    ElMessage({
                        type: 'success',
                        message: '物资新增成功',
                        duration: 2000
                    });
                }else{
                    ElMessage({
                        type:'warning',
                        message:res.data.msg
                    })
                }
            }else{
                let res = await goodsDetailApi().updateGoodsDetail(goodsDetailEditState.goodsDetailForm)
                if(res.data.code === '200'){
                    goodsDetailEditState.goodsDetailEditVisible = false
                    emit('refreshData')
                    ElMessage({
                        type: 'success',
                        message: '物资编辑成功',
                        duration: 2000
                    });
                }else{
                    ElMessage({
                        type:'warning',
                        message:res.data.msg
                    })
                }
            }
            goodsDetailEditState.loading = false
        }else{
            ElMessage({
                type: 'warning',
                message: '请完善基本信息'
            })
        }
    })
}
const emit = defineEmits(['refreshData',])
defineExpose({
    openGoodsDetailEditDialog
})
</script>
<style scoped>
</style>
src/views/facilityManagement/goodsDetailManage/index.ts
对比新文件
@@ -0,0 +1,101 @@
export interface GoodsDetailStateType {
    goodsDetailData: GoodsDetailDataType [];
    departmentList: DepartmentType [];
    irStatusList: Type [];
    listQuery:{
        pageSize: number;
        pageIndex: number;
        searchParams: {
            irStatus: number | null;
            rfid: string | null;
            smId: number | null;
        }
    },
    checkOutQuery: {
        id: null | number;
        claimantId: null | boolean;
    };
    checkInQuery: {
        id?: null | number;
        ids?: Array<number>;
    };
    checkOutNames: string;
    total: number;
}
export interface GoodsDetailEditType {
    title: string;
    depId: null | number;
    loading: boolean;
    classifyId: null | number;
    goodsDetailEditVisible?: boolean;
    goodsDetailForm: GoodsDetailEditFormType;
    goodsDetailRules: {};
    departmentList: DepartmentType [];
    classifyList: Array<ClassificationListType>;
    goodsList: Array<BaseMaterialListType>;
}
export interface GoodsDetailAddType extends GoodsDetailEditType{
    goodsDetailAddVisible: boolean;
    RFID: string;
    startRfid: string;
    endRfid: string;
}
export interface GoodsDetailEditFormType {
    id:  null | number;
    rfid?:  null | string;
    startRfid?:  null | string;
    endRfid?:  null | string;
    wareHousingCount?:  null | number;
    smId: null | number;
    validType: null | number;
    validTime: null | string;
}
export interface GoodsDetailDataType extends GoodsDetailEditFormType{
    name: string | null;
    depId: null | number;
    bigClassifyId: null | number;
}
export interface Type {
    id: number;
    name: string;
}
export interface DepartmentType {
    depId: number;
    depName: string;
    classificationList: Array<ClassificationListType>;
}
export interface ClassificationListType {
    baseMaterialList: Array<BaseMaterialListType>;
    materialClassifyId: number;
    materialClassifyName: string;
}
export interface BaseMaterialListType {
    materialName: string;
    smId: number;
}
export interface checkOutStateType {
    title: string;
    loading: boolean;
    checkOutDialogVisible: boolean;
    materialName: string;
    checkOutForm: {
        id?: null | number;
        claimantId: null | number;
        ids?: Array<number>;
    };
    // checkOutMoreForm: {
    //     ids: Array<number>;
    //     claimantId: null | boolean;
    // }
    userList: []
}
src/views/facilityManagement/goodsDetailManage/index.vue
对比新文件
@@ -0,0 +1,444 @@
<template>
    <div class="home-container">
        <div style="height: 100%">
            <el-row class="homeCard">
                <div class="basic-line">
                    <span>在库状态:</span>
                    <el-select class="input-box" v-model="goodsDetailState.listQuery.searchParams.irStatus" placeholder="请选择在库状态" clearable filterable>
                        <el-option
                        v-for="item in goodsDetailState.irStatusList"
                        :key="item.id"
                        :value="item.id"
                        :label="item.name"
                        >
                        </el-option>
                    </el-select>
                </div>
                <div class="basic-line">
                    <span>rfid:</span>
                    <el-input class="input-box" v-model="goodsDetailState.listQuery.searchParams.rfid" placeholder="rfid" clearable> </el-input>
                </div>
                <div style="padding-bottom: 10px">
                    <el-button size="large" type="primary" class="ml10" v-throttle @click="refreshGoodsDetailData">
                        <el-icon>
                            <ele-Search />
                        </el-icon>
                        查询
                    </el-button>
                </div>
            </el-row>
            <div class="homeCard">
                <el-row class="cardTop">
                    <el-col :span="12" class="mainCardBtn">
                        <el-button type="primary" size="default" @click="openGoodsDetailAdd('新增入库','')">新增入库</el-button>
                        <el-button type="danger" size="default" @click="deleteBatchGoodsDetail('批量删除','')">批量删除</el-button>
                        <el-button type="warning" size="default" @click="checkInAndOut('批量出库','')">批量出库</el-button>
                        <el-button type="success" size="default" @click="checkInAndOut('批量重新入库','')">批量重新入库</el-button>
                    </el-col>
                </el-row>
                <div class="main-card">
                    <el-table
                        :data="goodsDetailState.goodsDetailData"
                        style="width: 100%" height="calc(100% - 100px)"
                        :header-cell-style="{ background: '#fafafa' }"
                        @selection-change="handleSelectionChange"
                    >
                        <el-table-column type="selection" width="55" />
                        <el-table-column prop="materialNo" label="物资编号" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="bigClassifyName" label="分类" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="depName" label="仓库/部门" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="name" label="物资名称" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="rfid" label="绑定RFID" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="consumableName" label="是否是耗材" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="validTypeName" label="保质期" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="irStatusName" label="当前状态" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="wareHousingTime" label="入库时间" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="deliveryTime" label="出库时间" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="validStatusName" label="有效" show-overflow-tooltip></el-table-column>
                        <el-table-column label="操作" width="250" align="center">
                            <template #default="scope">
                                <el-button size="small" text type="primary" :icon="Edit" @click="openGoodsDetailEdit('编辑', scope.row)">编辑</el-button>
                                <el-button v-if="scope.row.irStatus === 1" size="small" text type="success" :icon="Edit" @click="checkInAndOut('重新入库', scope.row)">重新入库</el-button>
                                <el-button v-if="scope.row.irStatus === 0" size="small" text type="warning" :icon="Edit" @click="checkInAndOut('单独出库', scope.row)">单独出库</el-button>
                                <el-button size="small" text type="danger" :icon="Delete" @click="deleteSingleGoodsDetail(scope.row)">删除</el-button>
                            </template>
                        </el-table-column>
                    </el-table>
                    <br />
                    <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="goodsDetailState.listQuery.pageIndex" background v-model:page-size="goodsDetailState.listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="goodsDetailState.total" class="page-position"> </el-pagination>
                </div>
            </div>
        </div>
        <goods-detail-edit ref="goodsDetailEditRef" @refreshData="initGoodsDetailData"></goods-detail-edit>
        <goods-detail-add ref="goodsDetailAddRef" @refreshData="initGoodsDetailData"></goods-detail-add>
        <check-out ref="checkOutRef" @refreshGoodsDetail="initGoodsDetailData"></check-out>
    </div>
</template>
<script setup lang="ts">
import {onMounted, reactive, ref} from 'vue'
import { Edit, Delete, } from '@element-plus/icons-vue';
import {ElMessage, ElMessageBox} from "element-plus";
import {
    GoodsDetailDataType,
    GoodsDetailStateType
} from "/@/views/facilityManagement/goodsDetailManage/index";
import {goodsDetailApi} from "/@/api/facilityManagement/goodsDetailManage";
import { useRoute } from "vue-router";
import GoodsDetailEdit from './components/goodsDetailEdit.vue'
import CheckOut from "/@/views/facilityManagement/goodsDetailManage/components/checkOut.vue";
import GoodsDetailAdd from "/@/views/facilityManagement/goodsDetailManage/components/goodsDetailAdd.vue";
const route = useRoute()
const goodsDetailEditRef = ref()
const goodsDetailAddRef = ref()
const checkOutRef = ref()
const goodsDetailState = reactive<GoodsDetailStateType>({
    goodsDetailData:[],
    departmentList:[],
    irStatusList:[{id: 0, name:'在库'}, {id: 1, name:'已出库'}],
    listQuery:{
        pageSize: 10,
        pageIndex: 1,
        searchParams: {
            irStatus: null,
            rfid: null,
            smId: null
        }
    },
    checkOutQuery: {
        id: null,
        claimantId: null,
    },
    checkInQuery: {
        ids: [],
    },
    checkOutNames: '',
    total:0,
})
const initGoodsDetailData = async () => {
    let res = await goodsDetailApi().getGoodsDetailList(goodsDetailState.listQuery)
    if(res.data.code === '200'){
        goodsDetailState.goodsDetailData = res.data.data;
        goodsDetailState.total = res.data.total;
    }else{
        ElMessage({
            type:'warning',
            message:res.data.msg
        })
    }
};
const openGoodsDetailEdit = (title: string, value: GoodsDetailDataType) => {
    goodsDetailEditRef.value.openGoodsDetailEditDialog(title, value, goodsDetailState.departmentList)
};
const openGoodsDetailAdd = (title: string, value: GoodsDetailDataType) => {
    goodsDetailAddRef.value.openGoodsDetailAddDialog(title, value, goodsDetailState.departmentList)
};
const checkInAndOut = (title: string, value:GoodsDetailDataType) => {
    if(title === '重新入库'){
        goodsDetailState.checkInQuery = {}
        goodsDetailState.checkInQuery.id = value.id
        ElMessageBox.confirm(`此操作将重新入库:“${value.name}”,是否继续?`, '提示', {
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning'
        })
            .then(async () => {
                let res = await goodsDetailApi().checkInOne(goodsDetailState.checkInQuery);
                if (res.data.code === '200') {
                    ElMessage({
                        type: 'success',
                        duration: 2000,
                        message: '重新入库成功'
                    });
                    await initGoodsDetailData();
                } else {
                    ElMessage({
                        type: 'warning',
                        message: res.data.msg
                    });
                }
            })
            .catch(() => {});
    }else if(title === '批量重新入库'){
        if(goodsDetailState.checkInQuery.ids?.length){
            ElMessageBox.confirm(`此操作将把所选中全部重新入库,是否继续?`, '提示', {
                confirmButtonText: '确认',
                cancelButtonText: '取消',
                type: 'warning'
            })
                .then(async () => {
                    let res = await goodsDetailApi().checkInMore(goodsDetailState.checkInQuery);
                    if (res.data.code === '200') {
                        ElMessage({
                            type: 'success',
                            duration: 2000,
                            message: '批量重新入库成功'
                        });
                        await initGoodsDetailData();
                    } else {
                        ElMessage({
                            type: 'warning',
                            message: res.data.msg
                        });
                    }
                })
                .catch(() => {});
        }else{
            ElMessage({
                type:'warning',
                message: '请选择要批量重新入库的物资'
            })
        }
    }else if(title ==='单独出库'){
        checkOutRef.value.openCheckOutDialog(title, value, [], null);
    }else{
        if(goodsDetailState.checkInQuery.ids?.length){
            checkOutRef.value.openCheckOutDialog(title, null, goodsDetailState.checkInQuery.ids, goodsDetailState.checkOutNames);
        }else{
            ElMessage({
                type:'warning',
                message: '请选择要出库的物资'
            })
        }
    }
}
const handleSelectionChange = (val: Array<GoodsDetailDataType>) => {
    goodsDetailState.checkInQuery.ids = val.map((item) => {
        return item.id;
    }) as Array<number>;
    goodsDetailState.checkOutNames = val.map((item) => {
        return item.name
    }).join(',')
};
const getGoodsByLevel = async () => {
    let res = await goodsDetailApi().getGoodsListByLevel();
    if (res.data.code === '200') {
        goodsDetailState.departmentList = res.data.data;
    } else {
        ElMessage({
            type: 'warning',
            message: res.data.msg
        });
    }
};
const deleteSingleGoodsDetail = (row: any) => {
    ElMessageBox.confirm(`此操作将永久删除该物资:“${row.name}”,是否继续?`, '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
    })
        .then(async () => {
            let res = await goodsDetailApi().deleteSingleGoods({ id: row.id });
            if (res.data.code === '200') {
                ElMessage({
                    type: 'success',
                    duration: 2000,
                    message: '删除成功'
                });
                await initGoodsDetailData();
            } else {
                ElMessage({
                    type: 'warning',
                    message: res.data.msg
                });
            }
        })
        .catch(() => {});
};
const deleteBatchGoodsDetail = (row: any) => {
    ElMessageBox.confirm(`此操作将永久删除这些物资,是否继续?`, '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
    })
        .then(async () => {
            let res = await goodsDetailApi().deleteBatchGoods({ ids: goodsDetailState.checkInQuery.ids });
            if (res.data.code === '200') {
                ElMessage({
                    type: 'success',
                    duration: 2000,
                    message: '删除成功'
                });
                await initGoodsDetailData();
            } else {
                ElMessage({
                    type: 'warning',
                    message: res.data.msg
                });
            }
        })
        .catch(() => {});
};
const refreshGoodsDetailData = () => {
    initGoodsDetailData();
};
// 分页改变
const onHandleSizeChange = (val: number) => {
    goodsDetailState.listQuery.pageSize = val;
    initGoodsDetailData();
};
// 分页改变
const onHandleCurrentChange = (val: number) => {
    goodsDetailState.listQuery.pageIndex = val;
    initGoodsDetailData();
};
// const getDepartmentData = async () => {
//     let res = await departmentApi().getDepartmentList();
//     if (res.data.code === '200') {
//         goodsDetailState.departmentList = res.data.data;
//     } else {
//         ElMessage({
//             type: 'warning',
//             message: res.data.msg
//         });
//     }
// };
onMounted(() => {
    goodsDetailState.listQuery.searchParams.smId = (Number(route.query.id) || null)
    initGoodsDetailData();
    // getDepartmentData();
    getGoodsByLevel();
})
</script>
<style scoped lang="scss">
$homeNavLengh: 8;
.home-container {
    height: calc(100vh - 144px);
    box-sizing: border-box;
    overflow: hidden;
    .homeCard {
        width: 100%;
        padding: 20px;
        box-sizing: border-box;
        background: #fff;
        border-radius: 4px;
        .main-card {
            width: 100%;
            height: 100%;
            .cardTop {
                display: flex;
                align-items: center;
                justify-content: space-between;
                margin-bottom: 20px;
                .mainCardBtn {
                    margin: 0;
                }
            }
            .pageBtn {
                height: 60px;
                display: flex;
                align-items: center;
                justify-content: right;
                .demo-pagination-block + .demo-pagination-block {
                    margin-top: 10px;
                }
                .demo-pagination-block .demonstration {
                    margin-bottom: 16px;
                }
            }
        }
        &:last-of-type {
            height: calc(100% - 100px);
        }
    }
    .el-row {
        display: flex;
        align-items: center;
        margin-bottom: 20px;
        &:last-child {
            margin-bottom: 0;
        }
        .grid-content {
            align-items: center;
            min-height: 36px;
        }
        .topInfo {
            display: flex;
            align-items: center;
            font-size: 16px;
            font-weight: bold;
            & > div {
                white-space: nowrap;
                margin-right: 20px;
            }
        }
    }
}
.stepItem {
    width: 100%;
    display: flex;
    align-items: flex-start;
    margin-bottom: 30px;
    margin-left: 30px;
    padding-bottom: 30px;
    border-left: 2px solid #ccc;
    &:first-of-type {
        margin-top: 30px;
    }
    &:last-of-type {
        margin-bottom: 0;
        border-left: none;
    }
    .stepNum {
        width: 30px;
        height: 30px;
        border-radius: 15px;
        box-sizing: border-box;
        color: #333;
        border: 1px solid #999;
        line-height: 28px;
        text-align: center;
        margin-right: 10px;
        margin-left: -16px;
        margin-top: -30px;
    }
    .stepCard {
        width: 100%;
        margin-top: -30px;
        .box-card {
            width: 100%;
            &:deep(.el-card__header) {
                padding: 10px 15px;
            }
            .card-header {
                width: 100%;
                display: flex;
                justify-content: space-between;
                align-items: center;
                & > div:first-of-type {
                    margin-right: 80px;
                    font-size: 18px;
                    font-weight: bold;
                }
            }
        }
    }
    &:hover .card-header {
        color: #0098f5;
    }
    &:hover .stepNum {
        border: 2px solid #0098f5;
        color: #0098f5;
    }
}
</style>
src/views/facilityManagement/safetyGoodsAndEquipment/components/addGoodsDialog.vue
对比新文件
@@ -0,0 +1,267 @@
<template>
    <div class="system-add-menu-container">
        <el-dialog :title="addGoodsState.title" :close-on-click-modal="false" v-model="addGoodsState.showAddGoodsDialog" width="50%">
            <el-tabs class="active" v-model="addGoodsState.activeName">
                <el-tab-pane label="物资信息" name="goodsInformation">
                    <div class="filter-container" style="padding-bottom: 20px">
                        <el-button size="default" type="primary" @click="onOpenGoodsClassifyDialog('新增', '')">
                            <el-icon>
                                <ele-FolderAdd />
                            </el-icon>
                            新增分类
                        </el-button>
                    </div>
                    <el-table
                        :data="addGoodsState.goodsData"
                        border fit highlight-current-row lazy
                        row-key="id"
                        :load="load"
                        :row-class-name="tableRowClassName"
                        :header-cell-style="{ background: '#fafafa' }"
                        :tree-props="{ children: 'childList', hasChildren: true }"
                        style="width: 100%">
                        <el-table-column prop="materialClassifyName" label="分类名称" show-overflow-tooltip align="center"/>
                        <el-table-column prop="materialClassifyName" label="类别" show-overflow-tooltip align="center">
                            <template #default="scope">
                                <div v-if="scope.row.parentId === 0">{{'分类名称'}}</div>
                                <div v-if="scope.row.parentId !== 0">{{'物资名称'}}</div>
                            </template>
                        </el-table-column>
                        <el-table-column label="操作" width="150" align="center">
                            <template #default="scope">
                                <el-button v-if="scope.row.parentId === 0" size="small" text type="primary" @click="onOpenGoodsClassifyDialog('新增物资', scope.row)">
                                    <el-icon>
                                        <ele-FolderAdd />
                                    </el-icon>
                                    新增物资
                                </el-button>
                                <el-button size="small" text type="primary" :icon="Edit" @click="onOpenGoodsClassifyDialog('编辑', scope.row)">编辑</el-button>
                                <el-button size="small" text type="danger" :icon="Delete" @click="deleteGoodsClassify(scope.row)">删除</el-button>
                            </template>
                        </el-table-column>
                    </el-table>
                    <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[5, 10, 20]" v-model:current-page="addGoodsState.listQuery.pageIndex" background v-model:page-size="addGoodsState.listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="addGoodsState.total" class="page-position" style="padding-top: 20px;"> </el-pagination>
                </el-tab-pane>
            </el-tabs>
        </el-dialog>
        <el-dialog :title="addGoodsState.goodsClassifyTitle" :close-on-click-modal="false" v-model="addGoodsState.showAddGoodsClassifyDialog" width="30%">
            <el-form
                :model="addGoodsState.goodsClassifyForm"
                :rules="addGoodsState.goodsClassifyRules"
                ref="goodsClassifyRef"
                size="default"
                label-width="120px">
                <el-row>
                    <el-col :span="24" class="mb20" v-if="!addGoodsState.goodsClassifyForm.parentId">
                        <el-form-item label="分类名称" prop="materialClassifyName">
                            <el-input v-model="addGoodsState.goodsClassifyForm.materialClassifyName" placeholder="输入分类名称" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20" v-if="addGoodsState.goodsClassifyForm.parentId">
                        <el-form-item label="物资名称" prop="materialClassifyName">
                            <el-input v-model="addGoodsState.goodsClassifyForm.materialClassifyName" placeholder="输入物资名称" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="addGoodsState.showAddGoodsClassifyDialog = !addGoodsState.showAddGoodsClassifyDialog" size="default">取 消</el-button>
                    <el-button type="primary" @click="submitGoodsClassify" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script setup lang="ts">
import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue'
import { Edit, Delete, } from '@element-plus/icons-vue';
import {AddGoodsStateType, BigClassifyType} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import {mount} from "sortablejs";
import {goodsAndEquipmentApi} from "/@/api/facilityManagement/safetyGoodsAndEquipment";
import {ElMessage, valueEquals} from "element-plus/es";
import {ElMessageBox} from "element-plus";
import {inspectTaskApi} from "/@/api/intellectInspectSystem/inspectTask";
const addGoodsState = reactive<AddGoodsStateType>({
    title:'',
    goodsClassifyTitle:'',
    showAddGoodsDialog: false,
    showAddGoodsClassifyDialog: false,
    activeName: 'goodsInformation',
    goodsData: [],
    goodsBigClassifyList: [],
    total:0,
    listQuery:{
        pageSize: 5,
        pageIndex: 1,
        searchParams: {
            classifyName:''
        }
    },
    goodsClassifyForm: {
        id: null,
        materialClassifyName: '',
        parentId: null,
    },
    goodsClassifyRules: {
    },
});
const openAddGoodsDialog = (goodsBigClassifyList: BigClassifyType []) => {
    addGoodsState.showAddGoodsDialog = true
    addGoodsState.goodsBigClassifyList = goodsBigClassifyList
    getGoodsClassifyDataByPage()
}
const onOpenGoodsClassifyDialog = (title: string, value:BigClassifyType ) => {
    addGoodsState.showAddGoodsClassifyDialog = true
    addGoodsState.goodsClassifyForm = {
        id: null,
        materialClassifyName: '',
        parentId: null,
    }
    if(title === '新增') {
        addGoodsState.goodsClassifyTitle = '新增分类'
    }else if(title === '新增物资'){
        addGoodsState.goodsClassifyTitle = `新增${value.materialClassifyName}`
        addGoodsState.goodsClassifyForm.parentId = value.id
    } else if(title === '编辑' && value.parentId === 0){
        addGoodsState.goodsClassifyTitle = '编辑分类'
        addGoodsState.goodsClassifyForm = {
            id: value.id,
            materialClassifyName: value.materialClassifyName,
            parentId: null,
        }
    }else {
        addGoodsState.goodsClassifyTitle = `编辑${addGoodsState.goodsBigClassifyList.find(item => item.id === value.parentId)?.materialClassifyName as string}`
        addGoodsState.goodsClassifyForm.parentId = addGoodsState.goodsBigClassifyList.find(item => item.id === value.parentId)?.id as number
        addGoodsState.goodsClassifyForm.materialClassifyName = value.materialClassifyName
        addGoodsState.goodsClassifyForm.id = value.id
    }
}
const submitGoodsClassify = async () => {
    if(addGoodsState.goodsClassifyTitle.substring(0,2) === '新增'){
        let res = await goodsAndEquipmentApi().addGoodsClassify(addGoodsState.goodsClassifyForm);
        if(res.data.code === '200'){
            addGoodsState.showAddGoodsClassifyDialog = false;
            await getGoodsClassifyDataByPage();
            ElMessage({
                type: 'success',
                message: '新增成功',
                duration: 2000
            });
        }else{
            ElMessage({
                type:'warning',
                message:res.data.msg
            })
        }
    }else{
        let res = await goodsAndEquipmentApi().updateGoodsClassify(addGoodsState.goodsClassifyForm);
        if(res.data.code === '200'){
            addGoodsState.showAddGoodsClassifyDialog = false;
            await getGoodsClassifyDataByPage();
            ElMessage({
                type: 'success',
                message: '编辑成功',
                duration: 2000
            });
        }else{
            ElMessage({
                type:'warning',
                message:res.data.msg
            })
        }
    }
};
const deleteGoodsClassify = (row: BigClassifyType) => {
    ElMessageBox.confirm(`此操作将永久删除该:“${row.materialClassifyName}”,是否继续?`, '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
    })
        .then(async () => {
            let res = await goodsAndEquipmentApi().deleteGoodsClassify({ id: row.id });
            if (res.data.code === '200') {
                ElMessage({
                    type: 'success',
                    duration: 2000,
                    message: '删除成功'
                });
                await getGoodsClassifyDataByPage();
            } else {
                ElMessage({
                    type: 'warning',
                    message: res.data.msg
                });
            }
        })
        .catch(() => {});
};
const getGoodsClassifyDataByPage = async () => {
    let res = await goodsAndEquipmentApi().getAllSafetyEquipmentByPage(addGoodsState.listQuery);
    if(res.data.code === '200'){
        addGoodsState.goodsData = res.data.data
        addGoodsState.total = res.data.total
    }else{
        ElMessage({
            message:res.data.msg,
            type:'warning'
        })
    }
}
const tableRowClassName = ( row: {rowIndex: number, row: BigClassifyType } ) => {
    if (row.row.parentId === 0) {
        return 'big-row';
    } else{
        return 'small-row';
    }
}
const onHandleSizeChange = (val: number) => {
    addGoodsState.listQuery.pageSize = val
    getGoodsClassifyDataByPage()
}
const onHandleCurrentChange = (val: number) => {
    addGoodsState.listQuery.pageIndex = val
    getGoodsClassifyDataByPage()
}
const load = (
    row: BigClassifyType,
    treeNode: unknown,
    resolve: (date: BigClassifyType[]) => void
) => {
    setTimeout(() => {
        resolve([])
    }, 1000)
}
defineExpose({
    openAddGoodsDialog,
});
</script>
<style scoped>
/*:deep(.el-overlay .el-overlay-dialog .el-dialog .el-dialog__body) {*/
/*    padding-bottom: 20px !important;*/
/*}*/
:deep(.el-table .big-row) {
    font-size: 16px !important;
    font-weight: 700;
}
</style>
src/views/facilityManagement/safetyGoodsAndEquipment/components/batchInStorage.vue
对比新文件
@@ -0,0 +1,144 @@
<template>
    <div>
        <el-dialog :title="batchInStorageState.title" :close-on-click-modal="false"  v-model="batchInStorageState.batchInStorageDialogVisible" width="30%">
            <el-form
                :model="batchInStorageState.inStorageData"
                :rules="batchInStorageState.inStorageDataRules"
                ref="inStorageDataRef"
                size="default"
                v-loading="batchInStorageState.loading"
                element-loading-text="Loading..."
                label-width="150px">
                <el-row>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="当前所选物资/设备:">
                            <el-input v-model="batchInStorageState.materialName" :readonly="true" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="按RFID标记:" prop="rfid">
                            <el-input v-model="batchInStorageState.inStorageData.rfid" placeholder="选填" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="入库数量:" prop="wareHousingCount">
                            <el-input @input="onVerifiyNumberInteger($event, 'noticeTime')"  v-model="batchInStorageState.inStorageData.wareHousingCount" placeholder="输入入库数量" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="有效期类型:" prop="validType">
                            <el-radio-group v-model="batchInStorageState.inStorageData.validType">
                                <el-radio :label="0">长期</el-radio>
                                <el-radio :label="1">非长期</el-radio>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20" v-if="batchInStorageState.inStorageData.validType === 1">
                        <el-form-item label="有效期至:" prop="validTime">
                            <el-date-picker
                                v-model="batchInStorageState.inStorageData.validTime"
                                format="YYYY-MM-DD"
                                value-format="YYYY-MM-DD"
                                placeholder="选择日期时间"
                                style="width: 90%" />
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button :disabled="batchInStorageState.loading" @click="batchInStorageState.batchInStorageDialogVisible = !batchInStorageState.batchInStorageDialogVisible" size="default">取 消</el-button>
                    <el-button :disabled="batchInStorageState.loading" type="primary" @click="submitInStorageData" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script setup lang="ts">
import { reactive, ref} from 'vue'
import {BatchInStorageStateType, DataType} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import {verifiyNumberInteger} from "/@/utils/toolsValidate";
import {ElMessage} from "element-plus";
import { goodsAndEquipmentApi } from '../../../../api/facilityManagement/safetyGoodsAndEquipment/index'
const inStorageDataRef = ref()
const batchInStorageState = reactive<BatchInStorageStateType>({
    title: '批量入库',
    loading: false,
    materialName: '',
    batchInStorageDialogVisible: false,
    inStorageData:{
        smId: null,
        wareHousingCount: null,
        validType: null,
        validTime: null,
        rfid: null,
    },
    inStorageDataRules: {
        wareHousingCount: [{ required: true, message: '请填写物资数量', trigger: 'blur' }],
        validType: [{ required: true, message: '请选择有效期类型', trigger: 'change' }],
        validTime: [{ required: true, message: '请选择有效期至', trigger: 'change' }],
    },
})
const openBatchInStorageDialog = (value: DataType) => {
    batchInStorageState.batchInStorageDialogVisible = true
    batchInStorageState.inStorageData.smId = value.id
    batchInStorageState.materialName = value.materialName
}
const submitInStorageData = () => {
    inStorageDataRef.value.validate(async (valid: boolean) => {
        if(valid){
            batchInStorageState.loading = true;
            let res = await goodsAndEquipmentApi().batchInStorageGoods(batchInStorageState.inStorageData);
            if(res.data.code === '200'){
                batchInStorageState.batchInStorageDialogVisible = false;
                emit('refreshData')
                ElMessage({
                    type: 'success',
                    message: '入库成功',
                    duration: 2000
                });
            }else{
                ElMessage({
                    type: 'warning',
                    message:res.data.msg
                });
            }
            batchInStorageState.loading = false
        }else{
            ElMessage({
                type: 'warning',
                message: '请完善基本信息'
            });
        }
    });
};
const emit = defineEmits(['refreshData',]);
defineExpose({
    openBatchInStorageDialog,
})
const onVerifiyNumberInteger = (val: number, title: string) => {
    batchInStorageState.inStorageData.wareHousingCount = Number(verifiyNumberInteger(val.toString())) === 0 ? null : Number(verifiyNumberInteger(val.toString()));
};
</script>
<style scoped>
:deep(.el-dialog__header) {
    padding: var(--el-dialog-padding-primary);
    padding-bottom: 10px;
    margin-right: 16px;
    word-break: break-all;
    text-align: center !important;
}
</style>
src/views/facilityManagement/safetyGoodsAndEquipment/components/batchOutStorage.vue
对比新文件
@@ -0,0 +1,154 @@
<template>
    <div>
        <el-dialog :title="batchOutStorageState.title" :close-on-click-modal="false"  v-model="batchOutStorageState.batchOutStorageDialogVisible" width="30%">
            <el-form
                :model="batchOutStorageState.outStorageData"
                :rules="batchOutStorageState.outStorageDataRules"
                ref="outStorageDataRef"
                size="default"
                v-loading="batchOutStorageState.loading"
                element-loading-text="Loading..."
                label-width="150px">
                <el-row>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="当前所选物资/设备:">
                            <el-input v-model="batchOutStorageState.materialName" :readonly="true" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="按RFID标记:" prop="rfid">
                            <el-input v-model="batchOutStorageState.outStorageData.rfid" placeholder="选填" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="出库数量:" prop="count">
                            <el-input @Output="onVerifiyNumberInteger($event, 'noticeTime')"  v-model="batchOutStorageState.outStorageData.count" placeholder="输入出库数量" class="input-add">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24" class="mb20">
                        <el-form-item label="认领人:" prop="claimantId">
                            <el-select class="input-add" v-model="batchOutStorageState.outStorageData.claimantId" placeholder="选择认领人">
                                <el-option
                                v-for="item in batchOutStorageState.userList"
                                :key="item.uid"
                                :value="item.uid"
                                :label="item.realName"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button :disabled="batchOutStorageState.loading" @click="batchOutStorageState.batchOutStorageDialogVisible = !batchOutStorageState.batchOutStorageDialogVisible" size="default">取 消</el-button>
                    <el-button :disabled="batchOutStorageState.loading" type="primary" @click="submitOutStorageData" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script setup lang="ts">
import {onMounted, reactive, ref} from 'vue'
import {BatchOutStorageStateType, DataType} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import {verifiyNumberInteger} from "/@/utils/toolsValidate";
import {ElMessage} from "element-plus";
import { goodsAndEquipmentApi } from '../../../../api/facilityManagement/safetyGoodsAndEquipment/index'
import {teamManageApi} from "/@/api/systemManage/basicDateManage/personShiftManage/teamManage";
const outStorageDataRef = ref()
const batchOutStorageState = reactive<BatchOutStorageStateType>({
    title: '批量出库',
    loading: false,
    materialName: '',
    batchOutStorageDialogVisible: false,
    outStorageData:{
        smId: null,
        count: null,
        claimantId: null,
        rfid: null,
    },
    outStorageDataRules: {
        count: [{ required: true, message: '请填写出库数量', trigger: 'blur' }],
        claimantId: [{ required: true, message: '请选择认领人', trigger: 'change' }],
    },
    userList: [],
})
const openBatchOutStorageDialog = (value: DataType) => {
    batchOutStorageState.batchOutStorageDialogVisible = true
    batchOutStorageState.outStorageData.smId = value.id
    batchOutStorageState.materialName = value.materialName
}
const submitOutStorageData = () => {
    outStorageDataRef.value.validate(async (valid: boolean) => {
        if(valid){
            batchOutStorageState.loading = true;
            let res = await goodsAndEquipmentApi().batchOutStorageGoods(batchOutStorageState.outStorageData);
            if(res.data.code === '200'){
                batchOutStorageState.batchOutStorageDialogVisible = false;
                emit('refreshData')
                ElMessage({
                    type: 'success',
                    message: '出库成功',
                    duration: 2000
                });
            }else{
                ElMessage({
                    type: 'warning',
                    message:res.data.msg
                });
            }
            batchOutStorageState.loading = false
        }else{
            ElMessage({
                type: 'warning',
                message: '请完善基本信息'
            });
        }
    });
};
const emit = defineEmits(['refreshData',]);
defineExpose({
    openBatchOutStorageDialog,
})
const onVerifiyNumberInteger = (val: number, title: string) => {
    batchOutStorageState.outStorageData.count = Number(verifiyNumberInteger(val.toString())) === 0 ? null : Number(verifiyNumberInteger(val.toString()));
};
const getUserByDepartment = async () => {
    let res = await teamManageApi().getAllMember(1);
    if (res.data.code === '200') {
        batchOutStorageState.userList = JSON.parse(JSON.stringify(res.data.data));
    } else {
        ElMessage({
            type: 'warning',
            message: res.data.msg
        });
    }
}
onMounted(() => {
    getUserByDepartment()
})
</script>
<style scoped>
:deep(.el-dialog__header) {
    paddOutg: var(--el-dialog-padding-primary);
    paddOutg-bottom: 10px;
    margOut-right: 16px;
    word-break: break-all;
    text-align: center !important;
}
</style>
src/views/facilityManagement/safetyGoodsAndEquipment/components/safetyGoodsAndEquipmentDialog.vue
对比新文件
@@ -0,0 +1,221 @@
<template>
    <div class="system-add-menu-container">
        <el-dialog :title="dialogState.title" :close-on-click-modal="false" v-model="dialogState.showSafetyGoodsAndEquipmentDialog" width="600px">
            <el-form
                :model="dialogState.safetyGoodsAndEquipmentForm"
                :rules="dialogState.safetyGoodsAndEquipmentRules"
                ref="safetyGoodsAndEquipmentRef"
                size="default"
                v-loading="dialogState.loading"
                element-loading-text="Loading..."
                label-width="120px">
                <el-row>
                    <el-col :span="18" class="mb20">
                        <el-form-item label="物资大类" prop="bigClassifyId">
                            <el-select v-model="dialogState.safetyGoodsAndEquipmentForm.bigClassifyId" @change="changeSmallClassify(null)" placeholder="物资大类" class="input-add">
                                <el-option
                                v-for="item in dialogState.goodsBigClassifyList"
                                :key="item.id"
                                :value="item.id"
                                :label="item.materialClassifyName"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="5">
                        <el-button type="primary" @click="openAddGoods">添加物资</el-button>
                    </el-col>
                    <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
                        <el-form-item label="物资小类" prop="smallClassifyId">
                            <el-select class="input-add" v-model="dialogState.safetyGoodsAndEquipmentForm.smallClassifyId" placeholder="请先选择物资大类">
                                <el-option
                                    v-for="item in dialogState.goodsSmallClassifyList"
                                    :key="item.id"
                                    :value="item.id"
                                    :label="item.materialClassifyName"
                                ></el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
                        <el-form-item label="部门" prop="depId">
                            <el-cascader
                                :options="dialogState.departmentList"
                                :props="{ emitPath: false, checkStrictly: true, value: 'depId', label: 'depName' }"
                                placeholder="请选择部门"
                                clearable
                                class="input-add"
                                v-model="dialogState.safetyGoodsAndEquipmentForm.depId">
                            </el-cascader>
                        </el-form-item>
                    </el-col>
                    <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
                        <el-form-item label="是否耗材" prop="consumable">
                            <el-select class="input-add" v-model="dialogState.safetyGoodsAndEquipmentForm.consumable" placeholder="是否耗材" clearable filterable>
                                <el-option
                                    v-for="item in dialogState.consumableList"
                                    :key="item.id"
                                    :value="item.id"
                                    :label="item.name"
                                >
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="dialogState.showSafetyGoodsAndEquipmentDialog = !dialogState.showSafetyGoodsAndEquipmentDialog" size="default">取 消</el-button>
                    <el-button type="primary" @click="submitSafetyGoodsAndEquipment" v-throttle size="default">确 定</el-button>
                </span>
            </template>
        </el-dialog>
        <add-goods-dialog ref="addGoodsDialogRef"></add-goods-dialog>
    </div>
</template>
<script setup lang="ts">
import {computed, nextTick, reactive, ref, watch} from 'vue'
import {
    BigClassifyType,
    DataType, DepartmentType,
    isValidKey,
    SafetyGoodsAndEquipmentDialogStateType, safetyGoodsAndEquipmentFormType
} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import { goodsAndEquipmentApi } from "/@/api/facilityManagement/safetyGoodsAndEquipment";
import {ElMessage} from "element-plus";
import AddGoodsDialog from "./addGoodsDialog.vue";
const safetyGoodsAndEquipmentRef = ref();
const addGoodsDialogRef = ref()
const dialogState = reactive<SafetyGoodsAndEquipmentDialogStateType>({
    safetyGoodsAndEquipmentForm: {
        id: null,
        bigClassifyId: null,
        smallClassifyId: null,
        depId: null,
        consumable: null,
    },
    safetyGoodsAndEquipmentRules: {
        bigClassifyId: [{ required: true, message: '请选择物资大类', trigger: 'change' }],
        smallClassifyId: [{ required: true, message: '请选择物资小类', trigger: 'change' }],
        depId: [{ required: true, message: '请选择部门', trigger: 'change' }],
        consumable: [{ required: true, message: '请选择是否耗材', trigger: 'change' }],
    },
    showSafetyGoodsAndEquipmentDialog: false,
    title: '',
    loading: false,
    depList: [],
    goodsBigClassifyList: [],
    goodsSmallClassifyList: [],
    departmentList: [],
    consumableList: [
        {id: 0, name: '是'},
        {id: 1, name: '否'},
    ],
});
watch(() => dialogState.safetyGoodsAndEquipmentForm.bigClassifyId ,(newVal, oldVal) => {
},);
const openAddGoods = () => {
    addGoodsDialogRef.value.openAddGoodsDialog(dialogState.goodsBigClassifyList)
}
const openSafetyGoodsAndEquipmentDialog =
    (title: string, value: safetyGoodsAndEquipmentFormType, goodsBigClassifyList: BigClassifyType [], departmentList : DepartmentType []) => {
    dialogState.title = title;
    dialogState.showSafetyGoodsAndEquipmentDialog = true;
    dialogState.goodsBigClassifyList = goodsBigClassifyList;
    dialogState.departmentList = departmentList;
    dialogState.safetyGoodsAndEquipmentForm = {
        id: null,
        bigClassifyId: null,
        smallClassifyId: null,
        depId: null,
        consumable: null,
    };
    if(title === '新增') {
        dialogState.title = '新增'
    }else {
        dialogState.title = '编辑'
        changeSmallClassify(value.bigClassifyId)
        for(let key in dialogState.safetyGoodsAndEquipmentForm) {
            if(isValidKey(key, dialogState.safetyGoodsAndEquipmentForm)){
                dialogState.safetyGoodsAndEquipmentForm[key] = value[key];
            }
        }
    }
};
const changeSmallClassify = (id: number | null) => {
    dialogState.safetyGoodsAndEquipmentForm.smallClassifyId = null;
    dialogState.goodsSmallClassifyList = dialogState.goodsBigClassifyList[dialogState.goodsBigClassifyList.
    findIndex(item => item.id === (dialogState.safetyGoodsAndEquipmentForm.bigClassifyId || id))].childList as Array<BigClassifyType>;
}
const submitSafetyGoodsAndEquipment = () => {
    safetyGoodsAndEquipmentRef.value.validate(async (valid: boolean) => {
        if(valid){
            dialogState.loading = true
            if(dialogState.title === '新增') {
                let res = await goodsAndEquipmentApi().addGoodsEquipment(dialogState.safetyGoodsAndEquipmentForm)
                if(res.data.code === '200'){
                    dialogState.showSafetyGoodsAndEquipmentDialog = false
                    emit('refreshData')
                    ElMessage({
                        type: 'success',
                        message: '安全物资设备新增成功',
                        duration: 2000
                    });
                }else{
                    ElMessage({
                        type:'warning',
                        message:res.data.msg
                    })
                }
            }else{
                let res = await goodsAndEquipmentApi().updateGoodsEquipment(dialogState.safetyGoodsAndEquipmentForm)
                if(res.data.code === '200'){
                    dialogState.showSafetyGoodsAndEquipmentDialog = false
                    emit('refreshData')
                    ElMessage({
                        type: 'success',
                        message: '安全物资设备编辑成功',
                        duration: 2000
                    });
                }else{
                    ElMessage({
                        type:'warning',
                        message:res.data.msg
                    })
                }
            }
            dialogState.loading = false
        }else{
            ElMessage({
                type: 'warning',
                message: '请完善基本信息'
            })
        }
    })
};
const emit = defineEmits(['refreshData',])
defineExpose({
    openSafetyGoodsAndEquipmentDialog,
});
</script>
<style scoped>
.input-length{
    width: 100% !important;
}
</style>
src/views/facilityManagement/safetyGoodsAndEquipment/index.ts
对比新文件
@@ -0,0 +1,126 @@
export type TableDataType = {
    goodsAndEquipmentData: DataType [];
    goodsBigClassifyList: BigClassifyType [];
    departmentList: DepartmentType [];
    listQuery: {
        pageSize: number;
        pageIndex: number;
        searchParams: {
            bigClassifyId: number | null;
            materialName: string;
        }
    };
    total: number;
}
export type SafetyGoodsAndEquipmentDialogStateType = {
    safetyGoodsAndEquipmentForm: safetyGoodsAndEquipmentFormType,
    safetyGoodsAndEquipmentRules: {
    },
    showSafetyGoodsAndEquipmentDialog: Boolean,
    title: string,
    loading: Boolean,
    depList: DepartmentType [];
    consumableList: Type [];
    departmentList: DepListType [];
    goodsBigClassifyList: BigClassifyType [];
    goodsSmallClassifyList: BigClassifyType [];
}
export type AddGoodsStateType = {
    title: string;
    goodsClassifyTitle: string;
    showAddGoodsDialog: boolean;
    showAddGoodsClassifyDialog: boolean;
    activeName: string;
    goodsData: BigClassifyType [];
    goodsBigClassifyList: BigClassifyType [];
    total: number;
    listQuery: {
        pageSize: number;
        pageIndex: number;
        searchParams: {
            classifyName: string;
        }
    };
    goodsClassifyForm: {
        id: null | number;
        materialClassifyName: string;
        parentId: number | null;
    };
    goodsClassifyRules: {
    }
}
export type BatchInStorageStateType = {
    title: string;
    loading: boolean;
    materialName: string;
    batchInStorageDialogVisible: boolean;
    inStorageData: {
        smId: null | number,
        wareHousingCount: null | number,
        validType: null | number,
        validTime: null | string,
        rfid: null | string,
    },
    inStorageDataRules: {
    },
}
export type BatchOutStorageStateType = {
    title: string;
    loading: boolean;
    materialName: string;
    batchOutStorageDialogVisible: boolean;
    outStorageData: {
        smId: null | number,
        count: null | number,
        claimantId: null | number,
        rfid: null | string,
    };
    outStorageDataRules: {
    };
    userList: [];
}
export type Type = {
    id: number;
    name: string;
}
export type safetyGoodsAndEquipmentFormType = {
    id: null | number,
    bigClassifyId: null | number,
    smallClassifyId: null | number,
    depId: null | number,
    consumable: null | number,
}
export type DataType = {
    id: number | null;
    materialName: string;
}
export type DepListType = {
}
export function isValidKey(key: string | number | symbol, object:object): key is keyof typeof object{
    return key in object;
}
export type DepartmentType = {
}
export type BigClassifyType = {
    id: number;
    materialClassifyName: string;
    parentId?: number;
    childList?: BigClassifyType [];
}
src/views/facilityManagement/safetyGoodsAndEquipment/index.vue
对比新文件
@@ -0,0 +1,326 @@
<template>
    <div class="home-container">
        <div style="height: 100%">
            <el-row class="homeCard">
<!--                <div class="basic-line">-->
<!--                    <span>设备区域名称:</span>-->
<!--                    <el-input class="input-box" v-model="tableData.listQuery.regionName" placeholder="设备区域名称" clearable> </el-input>-->
<!--                </div>-->
<!--                <div class="basic-line">-->
<!--                    <span>设备区域类型:</span>-->
<!--                    <el-select class="input-box" v-model="tableData.listQuery.regionTypeId" placeholder="设备区域类型" filterable>-->
<!--                    </el-select>-->
<!--                </div>-->
                <div style="padding-bottom: 10px">
                    <el-button size="large" type="primary" class="ml10" v-throttle @click="refreshGoodsAndEquipmentData">
                        <el-icon>
                            <ele-Search />
                        </el-icon>
                        查询
                    </el-button>
                    <el-button size="large" type="success" class="ml10" @click="onOpenDialogRef('新增', '')">
                        <el-icon>
                            <ele-FolderAdd />
                        </el-icon>
                        新增
                    </el-button>
                    <el-button size="large" class="ml10" @click="openAddGoods()">
                        管理分类
                    </el-button>
                </div>
            </el-row>
            <div class="homeCard">
                <div class="main-card">
                    <el-table :data="tableData.goodsAndEquipmentData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
                        <el-table-column type="index" label="序号" width="60" />
                        <el-table-column prop="bigClassifyName" label="大类物资类型名称" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="materialName" label="物资名称" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="serialNum" label="序列号" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="depName" label="部门名称" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="consumableName" label="是否是耗材" show-overflow-tooltip></el-table-column>
                        <el-table-column prop="validStockCount" label="库存" show-overflow-tooltip></el-table-column>
                        <el-table-column label="操作" width="250" align="center">
                            <template #default="scope">
                                <el-button size="small" text type="success" :icon="Edit" @click="openBatchInStorage('批量入库', scope.row)">批量入库</el-button>
                                <el-button size="small" text type="warning" :icon="Edit" @click="openBatchOutStorage('批量出库', scope.row)">批量出库</el-button>
                                <el-button size="small" text type="primary" :icon="Edit" @click="linkToGoodsDetail('查看明细', scope.row)">查看明细</el-button>
                                <el-button size="small" text :icon="Edit" @click="onOpenDialogRef('编辑', scope.row)">编辑</el-button>
                                <el-button size="small" text type="danger" :icon="Delete" @click="onDelGoodsEquipment(scope.row)">删除</el-button>
                            </template>
                        </el-table-column>
                    </el-table>
                    <br />
                    <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="tableData.listQuery.pageIndex" background v-model:page-size="tableData.listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="tableData.total" class="page-position"> </el-pagination>
                </div>
            </div>
        </div>
        <safety-goods-and-equipment-dialog ref="safetyGoodsAndEquipmentDialogRef" @refreshData="refreshGoodsAndEquipmentData"></safety-goods-and-equipment-dialog>
        <batch-out-storage ref="batchOutStorageRef" @refreshData="refreshGoodsAndEquipmentData"></batch-out-storage>
        <batch-in-storage ref="batchInStorageRef" @refreshData="refreshGoodsAndEquipmentData"></batch-in-storage>
        <add-goods-dialog ref="addGoodsDialogRef"></add-goods-dialog>
    </div>
</template>
<script setup lang="ts">
import {onMounted, reactive, ref} from 'vue'
import {BigClassifyType, DataType, TableDataType} from "/@/views/facilityManagement/safetyGoodsAndEquipment/index";
import { Edit, View, Plus, Delete, Refresh, Search, Download } from '@element-plus/icons-vue';
import {goodsAndEquipmentApi} from "/@/api/facilityManagement/safetyGoodsAndEquipment";
import {ElMessage, ElMessageBox} from "element-plus";
import SafetyGoodsAndEquipmentDialog from './components/safetyGoodsAndEquipmentDialog.vue'
import {departmentApi} from "/@/api/systemManage/department";
import router from "/@/router";
import BatchInStorage from './components/batchInStorage.vue'
import BatchOutStorage from './components/batchOutStorage.vue'
import AddGoodsDialog from "./components/addGoodsDialog.vue";
const safetyGoodsAndEquipmentDialogRef = ref()
const batchInStorageRef = ref()
const batchOutStorageRef = ref()
const addGoodsDialogRef = ref()
const tableData = reactive<TableDataType>({
    goodsAndEquipmentData:[],
    goodsBigClassifyList:[],
    departmentList:[],
    listQuery:{
        pageSize: 10,
        pageIndex: 1,
        searchParams: {
            bigClassifyId:null,
            materialName:''
        }
    },
    total:0,
})
const initGoodsAndEquipmentData = async () => {
    let res = await goodsAndEquipmentApi().getGoodsEquipmentData(tableData.listQuery)
    if(res.data.code === '200'){
        tableData.goodsAndEquipmentData = res.data.data;
        tableData.total = res.data.total;
    }else{
        ElMessage({
            type:'warning',
            message:res.data.msg
        })
    }
};
const onOpenDialogRef = (title: string, value: DataType) => {
    safetyGoodsAndEquipmentDialogRef.value.openSafetyGoodsAndEquipmentDialog(title,value,tableData.goodsBigClassifyList, tableData.departmentList);
};
const openBatchInStorage = (title: string, value: DataType) => {
    batchInStorageRef.value.openBatchInStorageDialog(value)
}
const openBatchOutStorage = (title: string, value: DataType) => {
    batchOutStorageRef.value.openBatchOutStorageDialog(value)
}
const openAddGoods = () => {
    addGoodsDialogRef.value.openAddGoodsDialog(tableData.goodsBigClassifyList)
}
const linkToGoodsDetail = (title: string, value: DataType) => {
    router.push({ path: '/goodsDetailManage', query:{ id: value.id } });
}
const onDelGoodsEquipment = (value: DataType) => {
    ElMessageBox.confirm(`此操作将永久删除该:“${value.materialName}”,是否继续?`, '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
    })
        .then(async () => {
            let res = await goodsAndEquipmentApi().deleteGoodsEquipment({ id: value.id });
            if (res.data.code === '200') {
                ElMessage({
                    type: 'success',
                    duration: 2000,
                    message: '删除成功'
                });
                await initGoodsAndEquipmentData();
            } else {
                ElMessage({
                    type: 'warning',
                    message: res.data.msg
                });
            }
        })
        .catch(() => {});
};
const refreshGoodsAndEquipmentData = () => {
    initGoodsAndEquipmentData();
};
// 分页改变
const onHandleSizeChange = (val: number) => {
    tableData.listQuery.pageSize = val;
    initGoodsAndEquipmentData();
};
// 分页改变
const onHandleCurrentChange = (val: number) => {
    tableData.listQuery.pageIndex = val;
    initGoodsAndEquipmentData();
};
const getAllSafetyEquipmentList = async () => {
    let res = await goodsAndEquipmentApi().getAllSafetyEquipment();
    if(res.data.code === '200'){
        tableData.goodsBigClassifyList = res.data.data
    }else{
        ElMessage({
            message:res.data.msg,
            type:'warning'
        })
    }
}
const getDepartmentData = async () => {
    let res = await departmentApi().getDepartmentList();
    if (res.data.code === '200') {
        tableData.departmentList = res.data.data;
    } else {
        ElMessage({
            type: 'warning',
            message: res.data.msg
        });
    }
};
onMounted(() => {
    initGoodsAndEquipmentData();
    getAllSafetyEquipmentList();
    getDepartmentData();
})
</script>
<style scoped lang="scss">
$homeNavLengh: 8;
.home-container {
    height: calc(100vh - 144px);
    box-sizing: border-box;
    overflow: hidden;
.homeCard {
    width: 100%;
    padding: 20px;
    box-sizing: border-box;
    background: #fff;
    border-radius: 4px;
.main-card {
    width: 100%;
    height: 100%;
.cardTop {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 20px;
    .mainCardBtn {
        margin: 0;
    }
}
.pageBtn {
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: right;
.demo-pagination-block + .demo-pagination-block {
    margin-top: 10px;
}
.demo-pagination-block .demonstration {
    margin-bottom: 16px;
}
}
}
&:last-of-type {
     height: calc(100% - 100px);
 }
}
.el-row {
    display: flex;
    align-items: center;
    margin-bottom: 20px;
&:last-child {
     margin-bottom: 0;
 }
.grid-content {
    align-items: center;
    min-height: 36px;
}
.topInfo {
    display: flex;
    align-items: center;
    font-size: 16px;
    font-weight: bold;
& > div {
      white-space: nowrap;
      margin-right: 20px;
  }
}
}
}
.stepItem {
    width: 100%;
    display: flex;
    align-items: flex-start;
    margin-bottom: 30px;
    margin-left: 30px;
    padding-bottom: 30px;
    border-left: 2px solid #ccc;
&:first-of-type {
     margin-top: 30px;
 }
&:last-of-type {
     margin-bottom: 0;
     border-left: none;
 }
.stepNum {
    width: 30px;
    height: 30px;
    border-radius: 15px;
    box-sizing: border-box;
    color: #333;
    border: 1px solid #999;
    line-height: 28px;
    text-align: center;
    margin-right: 10px;
    margin-left: -16px;
    margin-top: -30px;
}
.stepCard {
    width: 100%;
    margin-top: -30px;
.box-card {
    width: 100%;
&:deep(.el-card__header) {
     padding: 10px 15px;
 }
.card-header {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
& > div:first-of-type {
      margin-right: 80px;
      font-size: 18px;
      font-weight: bold;
  }
}
}
}
&:hover .card-header {
     color: #0098f5;
 }
&:hover .stepNum {
     border: 2px solid #0098f5;
     color: #0098f5;
 }
}
</style>
static/loginPage.js/login.js
@@ -157,9 +157,9 @@
  pJS.fn.retinaInit = function(){
    if(pJS.retina_detect && window.devicePixelRatio > 1){
      pJS.canvas.pxratio = window.devicePixelRatio;
      pJS.canvas.pxratio = window.devicePixelRatio;
      pJS.tmp.retina = true;
    }
    }
    else{
      pJS.canvas.pxratio = 1;
      pJS.tmp.retina = false;
@@ -363,7 +363,7 @@
    this.vx_i = this.vx;
    this.vy_i = this.vy;
    /* if shape is image */
@@ -392,7 +392,7 @@
      }
    }
  };
@@ -402,7 +402,7 @@
    var p = this;
    if(p.radius_bubble != undefined){
      var radius = p.radius_bubble;
      var radius = p.radius_bubble;
    }else{
      var radius = p.radius;
    }
@@ -491,9 +491,9 @@
      pJS.canvas.ctx.lineWidth = pJS.particles.shape.stroke.width;
      pJS.canvas.ctx.stroke();
    }
    pJS.canvas.ctx.fill();
  };
@@ -664,7 +664,7 @@
    pJS.tmp.count_svg = 0;
    pJS.fn.particlesEmpty();
    pJS.fn.canvasClear();
    /* restart */
    pJS.fn.vendors.start();
@@ -684,14 +684,14 @@
      var opacity_line = pJS.particles.line_linked.opacity - (dist / (1/pJS.particles.line_linked.opacity)) / pJS.particles.line_linked.distance;
      if(opacity_line > 0){
      if(opacity_line > 0){
        /* style */
        var color_line = pJS.particles.line_linked.color_rgb_line;
        pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
        pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
        //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
        /* path */
        pJS.canvas.ctx.beginPath();
        pJS.canvas.ctx.moveTo(p1.x, p1.y);
@@ -725,7 +725,7 @@
      p2.vy += ay;
    }
  }
@@ -805,7 +805,7 @@
      if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
        if(ratio >= 0 && pJS.interactivity.status == 'mousemove'){
          /* size */
          if(pJS.interactivity.modes.bubble.size != pJS.particles.size.value){
@@ -854,7 +854,7 @@
      if(pJS.interactivity.status == 'mouseleave'){
        init();
      }
    }
    /* on click event */
@@ -933,7 +933,7 @@
          repulseRadius = pJS.interactivity.modes.repulse.distance,
          velocity = 100,
          repulseFactor = clamp((1/repulseRadius)*(-1*Math.pow(dist_mouse/repulseRadius,2)+1)*repulseRadius*velocity, 0, 50);
      var pos = {
        x: p.x + normVec.x * repulseFactor,
        y: p.y + normVec.y * repulseFactor
@@ -946,7 +946,7 @@
        p.x = pos.x;
        p.y = pos.y;
      }
    }
@@ -1001,7 +1001,7 @@
        // }else{
        //   process();
        // }
      }else{
@@ -1009,7 +1009,7 @@
          p.vx = p.vx_i;
          p.vy = p.vy_i;
        }
      }
@@ -1039,7 +1039,7 @@
          pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
          pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
          //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
          /* path */
          pJS.canvas.ctx.beginPath();
          pJS.canvas.ctx.moveTo(p.x, p.y);
@@ -1155,7 +1155,7 @@
        }
      });
    }
@@ -1359,7 +1359,7 @@
          pJS.fn.vendors.init();
          pJS.fn.vendors.draw();
        }
      }
    }else{
@@ -1406,7 +1406,7 @@
  pJS.fn.vendors.eventsListeners();
  pJS.fn.vendors.start();
};
@@ -1520,7 +1520,7 @@
};
window.particlesJS.load = function(tag_id, path_config_json, callback){
debugger
  /* load json config */
  var xhr = new XMLHttpRequest();
  xhr.open('GET', path_config_json);
@@ -1542,4 +1542,4 @@
}
export {
  loginBg
}
}