Просмотр исходного кода

试验,材料进场,接口调试

iZaiZaiA 2 лет назад
Родитель
Сommit
1d4d89c4a1

+ 76 - 0
src/api/modules/tentative/material/approach.js

@@ -0,0 +1,76 @@
+import {httpApi} from "../../../request/httpApi";
+
+export default {
+    //进场材料分页条件查询
+    async queryPage(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/material/mobilization/page',
+            method: 'get',
+            params: form
+        }, msg);
+    },
+    //进场材料新增或修改
+    async submitForm(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/material/mobilization/submit',
+            method: 'post',
+            data: form
+        }, msg);
+    },
+    //进场材料批量删除
+    async removeData(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/material/mobilization/remove',
+            method: 'post',
+            params: form
+        }, msg);
+    },
+    //校验材料编号是否唯一
+    async verification(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/material/mobilization/verification',
+            method: 'get',
+            params: form
+        }, msg);
+    },
+    //进场材料批量复制
+    async copyData(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/material/mobilization/copy',
+            method: 'post',
+            data: form
+        }, msg);
+    },
+    //批量审批
+    async batchCompleteApprovalTask(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/task/batch-complete-approval-task',
+            method: 'post',
+            data: form
+        }, msg);
+    },
+    //获取发起
+    async queryUserStartFlow(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/task/query-user-start-flow',
+            method: 'get',
+            params: form
+        }, msg);
+    },
+    //批量页详情
+    async queryTaskInfo(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/task/batch-approval-parameter',
+            method: 'get',
+            params: form
+        }, msg);
+    },
+    //校验电签短信验证码
+    async checkSmsCode(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-business/task/check-sms-code',
+            method: 'post',
+            data: form
+        }, msg);
+    },
+}

+ 22 - 5
src/global/components/hc-new-switch/index.vue

@@ -1,5 +1,5 @@
 <template>
-    <div class="hc-new-switch" :class="[`size-${size ?? 'large'}`, round ? 'round' : '']">
+    <div class="hc-new-switch" :class="[`size-${size ?? 'large'}`, round ? 'round' : '', isDisabled ? 'disabled' : '']">
         <template v-for="item in datas">
             <div class="switch-bg" :class="item?.key == keyVal?'dots':''" @click="switchClick(item)">{{item?.name}}</div>
         </template>
@@ -25,21 +25,32 @@ const props = defineProps({
         type: Boolean,
         default: true
     },
+    disabled: {
+        type: Boolean,
+        default: false
+    },
 })
 
 //监听
 const keyVal = ref(props.keys)
+const isDisabled = ref(props.disabled)
+
+//监听
 watch(() => [
-    props.keys
-], ([keys]) => {
+    props.keys,
+    props.disabled
+], ([keys, disabled]) => {
     keyVal.value = keys;
+    isDisabled.value = disabled;
 })
 
 //事件
 const emit = defineEmits(['change'])
 const switchClick = (item) => {
-    if (item?.key == keyVal.value) return;
-    emit('change', item)
+    if (!isDisabled.value) {
+        if (item?.key == keyVal.value) return;
+        emit('change', item)
+    }
 }
 </script>
 
@@ -87,5 +98,11 @@ const switchClick = (item) => {
             height: 25px;
         }
     }
+    &.disabled {
+        .switch-bg {
+            opacity: 0.5;
+            cursor: no-drop;
+        }
+    }
 }
 </style>

+ 5 - 0
src/styles/app/element.scss

@@ -622,6 +622,11 @@
     }
 }
 
+//下拉框的滚动条
+.el-select__popper.el-popper .el-select-dropdown .el-scrollbar .el-scrollbar__bar.is-vertical {
+    right: 1px;
+}
+
 //设置表单样式
 .hc-excel-table-form-view {
     position: relative;

+ 321 - 96
src/views/tentative/material/approach.vue

@@ -9,25 +9,25 @@
                     </el-button>
                 </HcTooltip>
                 <HcTooltip keys="tentative_material_approach_edit">
-                    <el-button hc-btn @click="editFormModalClick">
+                    <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="editFormModalClick">
                         <HcIcon name="edit"/>
                         <span>编辑</span>
                     </el-button>
                 </HcTooltip>
                 <HcTooltip keys="tentative_material_approach_copy">
-                    <el-button hc-btn @click="copyTableModalClick">
+                    <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="copyTableModalClick">
                         <HcIcon name="file-copy-2"/>
                         <span>复制</span>
                     </el-button>
                 </HcTooltip>
                 <HcTooltip keys="tentative_material_approach_del">
-                    <el-button hc-btn @click="delModalClick">
+                    <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="delModalClick">
                         <HcIcon name="delete-bin-2"/>
                         <span>删除</span>
                     </el-button>
                 </HcTooltip>
                 <HcTooltip keys="tentative_material_approach_printer">
-                    <el-button hc-btn>
+                    <el-button :disabled="tableCheckedKeys.length <= 0" hc-btn>
                         <HcIcon name="printer"/>
                         <span>打印</span>
                     </el-button>
@@ -41,8 +41,8 @@
             </template>
             <template #search>
                 <div class="w-40">
-                    <el-select v-model="searchForm.type" placeholder="请选择材料类型" clearable>
-                        <el-option v-for="item in typeData" :key="item.value" :label="item['label']" :value="item['value']"/>
+                    <el-select v-model="searchForm.materialType" placeholder="请选择材料类型" clearable>
+                        <el-option v-for="item in typeData" :key="item.value" :label="item['dictValue']" :value="item['dictKey']"/>
                     </el-select>
                 </div>
                 <div class="w-64 ml-2">
@@ -59,6 +59,7 @@
                 </div>
             </template>
             <HcTable ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" isCheck @selection-change="tableSelection">
+                <template #materialType="{row}">{{getRowTableMaterialType(row['materialType'])}}</template>
                 <template #action="{row}">
                     <HcTooltip keys="tentative_material_approach_annex">
                         <el-button type="primary" size="small" plain @click="viewAttachmentModalClick(row)">附件</el-button>
@@ -74,66 +75,66 @@
         </HcCard>
 
         <!--新增/编辑-->
-        <HcDialog :show="addEditFormModal" title="新增/编辑 材料进场" widths="45rem" :loading="addEditFormLoading" @close="addEditFormModalClose" @save="addEditFormClick">
+        <HcDialog :show="addEditFormModal" :title="`${addEditFormModel.id?'编辑':'新增'}材料进场`" widths="45rem" :loading="addEditFormLoading" @close="addEditFormModalClose" @save="addEditFormClick">
             <el-form ref="addEditFormRef" :model="addEditFormModel" :rules="addEditFormRules" label-width="auto" size="large">
                 <div class="hc-form-item">
-                    <el-form-item label="材料类型">
-                        <el-select v-model="addEditFormModel.key1" block>
-                            <el-option v-for="item in typeData" :label="item.label" :value="item.value"/>
+                    <el-form-item label="材料类型" prop="materialType">
+                        <el-select v-model="addEditFormModel.materialType" block>
+                            <el-option v-for="item in typeData" :label="item['dictValue']" :value="item['dictKey']"/>
                         </el-select>
                     </el-form-item>
-                    <el-form-item label="材料单价" prop="key2">
-                        <el-input v-model="addEditFormModel.key2"/>
+                    <el-form-item label="材料单价">
+                        <el-input v-model="addEditFormModel.materialPrice"/>
                     </el-form-item>
                 </div>
                 <div class="hc-form-item">
-                    <el-form-item label="材料名称" prop="key3">
-                        <el-input v-model="addEditFormModel.key3"/>
+                    <el-form-item label="材料名称" prop="materialName">
+                        <el-input v-model="addEditFormModel.materialName"/>
                     </el-form-item>
-                    <el-form-item label="材料数量" prop="key4">
-                        <el-input v-model="addEditFormModel.key4"/>
+                    <el-form-item label="材料数量">
+                        <el-input v-model="addEditFormModel.materialCount"/>
                     </el-form-item>
                 </div>
                 <div class="hc-form-item">
-                    <el-form-item label="规格型号" prop="key5">
-                        <el-input v-model="addEditFormModel.key5"/>
+                    <el-form-item label="规格型号" prop="specificationModel">
+                        <el-input v-model="addEditFormModel.specificationModel"/>
                     </el-form-item>
-                    <el-form-item label="计算单位" prop="key6">
-                        <el-input v-model="addEditFormModel.key6"/>
+                    <el-form-item label="计算单位">
+                        <el-input v-model="addEditFormModel.calculationUnit"/>
                     </el-form-item>
                 </div>
                 <div class="hc-form-item">
-                    <el-form-item label="材料编号" prop="key7">
-                        <el-input v-model="addEditFormModel.key7"/>
+                    <el-form-item label="材料编号" prop="materialNumber">
+                        <el-input v-model="addEditFormModel.materialNumber"/>
                     </el-form-item>
-                    <el-form-item label="生产批号" prop="key8">
-                        <el-input v-model="addEditFormModel.key8"/>
+                    <el-form-item label="生产批号">
+                        <el-input v-model="addEditFormModel.batchNumber"/>
                     </el-form-item>
                 </div>
                 <div class="hc-form-item">
-                    <el-form-item label="进场日期" prop="key9">
-                        <el-date-picker type="date" v-model="addEditFormModel.key9" class="block" value-format="YYYY-MM-DD" :clearable="false"/>
+                    <el-form-item label="进场日期">
+                        <el-date-picker type="date" v-model="addEditFormModel.mobilizationDate" class="block" value-format="YYYY-MM-DD" :clearable="false"/>
                     </el-form-item>
-                    <el-form-item label="拟用部位" prop="key10">
-                        <el-input v-model="addEditFormModel.key10"/>
+                    <el-form-item label="拟用部位">
+                        <el-input v-model="addEditFormModel.proposedPosition"/>
                     </el-form-item>
                 </div>
                 <div class="hc-form-item">
-                    <el-form-item label="供应商单位" prop="key11">
-                        <el-input v-model="addEditFormModel.key11"/>
+                    <el-form-item label="供应商单位">
+                        <el-input v-model="addEditFormModel.supplierUnit"/>
                     </el-form-item>
-                    <el-form-item label="生产地/厂家" prop="key12">
-                        <el-input v-model="addEditFormModel.key12"/>
+                    <el-form-item label="生产地/厂家">
+                        <el-input v-model="addEditFormModel.placeOfProduction"/>
                     </el-form-item>
                 </div>
-                <el-form-item label="生产合格证" prop="key13">
-                    <div class="form-item-dashed hover">上传文件(待定,看后端接口后,再定)</div>
+                <el-form-item label="生产合格证">
+                    <FormItemUpload v-model="addEditFormModel.productionCertificate"/>
                 </el-form-item>
-                <el-form-item label="厂家质检报告" prop="key13">
-                    <div class="form-item-dashed hover">上传文件(待定,看后端接口后,再定)</div>
+                <el-form-item label="厂家质检报告">
+                    <FormItemUpload v-model="addEditFormModel.qualityInspectionReport"/>
                 </el-form-item>
-                <el-form-item label="其他附件" prop="key13">
-                    <div class="form-item-dashed hover">上传文件(待定,看后端接口后,再定)</div>
+                <el-form-item label="其他附件">
+                    <FormItemUpload v-model="addEditFormModel.otherAccessories"/>
                 </el-form-item>
             </el-form>
         </HcDialog>
@@ -141,11 +142,11 @@
         <!--复制材料登记信息-->
         <HcDialog :show="copyTableModal" title="复制材料登记信息" widths="60rem" isTable :loading="copyTableLoading" @close="copyTableModalClose" @save="copyTableClick">
             <HcTable :column="copyTableColumn" :datas="copyTableData">
-                <template #key1="{row}">
-                    <el-input v-model="row.key1" placeholder="请输入材料编号"/>
+                <template #materialNumber="{row}">
+                    <el-input v-model="row.materialNumber" :class="row.isMaterialNumber?'is-error':''" placeholder="请输入材料编号" @blur="materialNumberBlur(row)"/>
                 </template>
-                <template #action="{row}">
-                    <el-button type="danger" size="small" plain>删除</el-button>
+                <template #action="{index}">
+                    <el-button type="danger" size="small" plain @click="materialNumberDel(index)">删除</el-button>
                 </template>
             </HcTable>
         </HcDialog>
@@ -174,17 +175,16 @@
         <!--查看附件-->
         <HcDialog :show="viewAttachmentModal" title="查看附件" widths="70rem" :footer="false" isTable @close="viewAttachmentModalClose">
             <template #extra>
-                <HcNewSwitch :datas="tabTypeTab" :keys="tabTypeKey" @change="tabTypeChange"/>
+                <HcNewSwitch :datas="tabTypeTab" :keys="tabTypeKey" @change="tabTypeChange" :disabled="tableRowPdfDisabled"/>
             </template>
             <div class="hc-switch-tab-content">
                 <div class="h-full w-full">
-                    <iframe allow="display-capture" width='100%' height='100%' frameborder='1' :src="attachmentPdfUrl" v-if="attachmentPdfUrl"/>
+                    <iframe allow="display-capture" width='100%' height='100%' frameborder='1' :src="tableRowData[tabTypeKey]" v-if="tableRowData[tabTypeKey]"/>
                     <div class="hc-no-table-form" v-else>
                         <div class="table-form-no">
                             <img :src="notableform" alt=""/>
                             <div class="desc">暂无 PDF 数据,请上传</div>
-
-                            <HcDragUpload/>
+                            <HcDragUpload autoUpload @progress="tableRowPdfProgress" @finished="tableRowPdfFinished"/>
                         </div>
                     </div>
                 </div>
@@ -200,10 +200,14 @@
 </template>
 
 <script setup>
-import {ref,watch,onMounted} from "vue";
+import {ref, onMounted} from "vue";
 import {useAppStore} from "~src/store";
 import HcDragUpload from "./components/HcDragUpload.vue"
+import FormItemUpload from "./components/FormItemUpload.vue"
 import notableform from '~src/assets/view/notableform.svg';
+import approachApi from "~api/tentative/material/approach"
+import {formValidate, getArrValue, getIndex, deepClone, isIdCard} from "vue-utils-plus"
+import {getDictionary} from "~api/other";
 
 //初始变量
 const useAppState = useAppStore()
@@ -212,18 +216,47 @@ const useAppState = useAppStore()
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 
-const typeData = ref([
-    {label: '水泥', value: '1'}
-])
+//渲染完成
+onMounted(() => {
+    getMaterialType()
+    getTableData()
+})
+
+//获取材料类型
+const typeData = ref([])
+const getMaterialType = async () => {
+    const { data } = await getDictionary({
+        code: 'material_type'
+    })
+    typeData.value = getArrValue(data)
+    //dictValue, dictKey
+}
+
+//获取材料类型
+const getRowTableMaterialType = (type) => {
+    if (type > 0) {
+        const nodeData = typeData.value
+        const index = getIndex(nodeData, 'dictKey', type)
+        return nodeData[index]?.dictValue ?? type
+    } else {
+        return ''
+    }
+}
 
 //搜索表单
-const searchForm = ref({type: null, betweenTime: null, queryValue: null, current: 1, size: 20, total: 0})
+const searchForm = ref({
+    materialType: null, startTime: null, endTime: null, queryValue: null,
+    current: 1, size: 20, total: 0
+})
 
 //日期时间被选择
 const betweenTime = ref(null)
-const betweenTimeUpdate = ({arr,query}) => {
+const betweenTimeUpdate = ({arr}) => {
     betweenTime.value = arr
-    searchForm.value.betweenTime = query
+    if (arr.length > 0) {
+        searchForm.value.startTime = arr[0]
+        searchForm.value.endTime = arr[1]
+    }
 }
 
 //回车搜索
@@ -250,29 +283,42 @@ const pageChange = ({current, size}) => {
 //表格数据
 const tableRef = ref(null)
 const tableColumn = ref([
-    {key:'key1', name: '材料编号'},
-    {key:'key2', name: '进场日期'},
-    {key:'key3', name: '材料名称'},
-    {key:'key4', name: '材料类型'},
-    {key:'key5', name: '规格型号'},
-    {key:'key6', name: '供应商单位'},
-    {key:'key7', name: '材料单价'},
-    {key:'key8', name: '材料数量'},
-    {key:'key9', name: '计算单位'},
-    {key:'key10', name: '生产批号'},
-    {key:'key11', name: '生产地/厂家'},
-    {key:'key12', name: '拟用部位'},
-    {key:'key13', name: '记录人'},
+    {key:'materialNumber', name: '材料编号'},
+    {key:'mobilizationDate', name: '进场日期'},
+    {key:'materialName', name: '材料名称'},
+    {key:'materialType', name: '材料类型'},
+    {key:'specificationModel', name: '规格型号'},
+    {key:'supplierUnit', name: '供应商单位'},
+    {key:'materialPrice', name: '材料单价'},
+    {key:'materialCount', name: '材料数量'},
+    {key:'calculationUnit', name: '计算单位'},
+    {key:'batchNumber', name: '生产批号'},
+    {key:'placeOfProduction', name: '生产地/厂家'},
+    {key:'proposedPosition', name: '拟用部位'},
+    {key:'userName', name: '记录人'},
     {key:'action', name: '操作', width: 150, fixed: 'right', align: 'center'},
 ])
+const tableRowData = ref({})
 
 //获取数据
 const tableLoading = ref(false)
-const tableData = ref([
-    {}
-])
+const tableData = ref([])
 const getTableData = async () => {
-
+    tableLoading.value = true
+    const { error, code, data } = await approachApi.queryPage({
+        projectId: projectId.value,
+        contractId: contractId.value,
+        ...searchForm.value,
+    })
+    //处理数据
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableData.value = getArrValue(data['records'])
+        searchForm.value.total = data.total || 0
+    } else {
+        tableData.value = []
+        searchForm.value.total = 0
+    }
 }
 
 //多选
@@ -283,13 +329,21 @@ const tableSelection = (rows) => {
     })
 }
 
-//新增/编辑 材料进场
+//新增 材料进场
 const addEditFormModal = ref(false)
 const addFormModalClick = () => {
+    addEditFormModel.value = {}
     addEditFormModal.value = true
 }
+//编辑 材料进场
 const editFormModalClick = () => {
-    addEditFormModal.value = true
+    const keys = tableCheckedKeys.value
+    if (keys.length === 1) {
+        addEditFormModel.value = keys[0]
+        addEditFormModal.value = true
+    } else if (keys.length > 1) {
+        window?.$message?.warning('只能选择一条数据编辑')
+    }
 }
 const addEditFormModalClose = () => {
     addEditFormModal.value = false
@@ -297,38 +351,126 @@ const addEditFormModalClose = () => {
 
 //新增/编辑 表单
 const addEditFormRef = ref(null)
-const addEditFormModel = ref({})
+const addEditFormModel = ref({
+    materialType: null,
+    materialPrice: '',
+    materialName: '',
+    materialCount: '',
+    specificationModel: '',
+    calculationUnit: '',
+    materialNumber: '',
+    batchNumber: '',
+    mobilizationDate: null,
+    proposedPosition: '',
+    supplierUnit: '',
+    placeOfProduction: '',
+    productionCertificate: '',
+    qualityInspectionReport: '',
+    otherAccessories: '',
+})
 const addEditFormRules = {
-    key2: {
+    materialType: {
+        required: true,
+        trigger: 'change',
+        message: "请选择材料类型"
+    },
+    materialName: {
         required: true,
         trigger: 'blur',
-        message: "请输入"
+        message: "请输入材料名称"
+    },
+    specificationModel: {
+        required: true,
+        trigger: 'blur',
+        message: "请输入规格型号"
+    },
+    materialNumber: {
+        required: true,
+        validator: async (rule, value, callback) => {
+            if (!value) {
+                callback(new Error('请输入材料编号'))
+            } else {
+                const ver = await verification(value)
+                if (!ver) {
+                    callback(new Error('材料编号必须是惟一的'))
+                } else {
+                    callback()
+                }
+            }
+        },
+        trigger: 'blur'
     },
 }
 
+//校验材料编号是否唯一
+const verification = async (val) => {
+    const { error, code, data } = await approachApi.verification({
+        projectId: projectId.value,
+        contractId: contractId.value,
+        materialNumber: val,
+    })
+    if (!error && code === 200) {
+        return !data
+    } else {
+        return false
+    }
+}
+
 //新增/编辑 保存
 const addEditFormLoading = ref(false)
-const addEditFormClick = () => {
-
+const addEditFormClick = async () => {
+    const validate = await formValidate(addEditFormRef.value)
+    if (validate) {
+        addEditFormLoading.value = true
+        const { error, code } = await approachApi.submitForm({
+            ...addEditFormModel.value,
+            projectId: projectId.value,
+            contractId: contractId.value
+        })
+        //处理数据
+        addEditFormLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('操作成功')
+            addEditFormModal.value = false
+            await getTableData()
+        }
+    }
 }
 
+//复制表格
+const copyTableColumn = ref([
+    {key:'materialName', name: '材料名称'},
+    {key:'materialNumber', name: '材料编号'},
+    {key:'action', name: '操作', width: 100},
+])
+const copyTableData = ref([])
+
 //复制
 const copyTableModal = ref(false)
-
 const copyTableModalClick = () => {
+    copyTableData.value = deepClone(tableCheckedKeys.value)
     copyTableModal.value = true
 }
 
-//复制表格
-const copyTableColumn = ref([
-    {key:'key3', name: '材料名称'},
-    {key:'key1', name: '材料编号'},
-    {key:'action', name: '操作', width: 100},
-])
-const copyTableData = ref([
-    {key3: '名称', key1: '编号...'},
-    {key3: '名称1', key1: '编号1...'},
-])
+//效验材料编号
+const materialNumberBlur = async (row) => {
+    const number = row?.materialNumber ?? ''
+    if (number) {
+        const ver = await verification(number)
+        row.isMaterialNumber = !ver
+    } else {
+        row.isMaterialNumber = true
+    }
+}
+
+//删除
+const materialNumberDel = (index) => {
+    copyTableData.value.splice(index, 1);
+    const rows = copyTableData.value
+    if (rows.length <= 0) {
+        copyTableModal.value = false
+    }
+}
 
 const copyTableModalClose = () => {
     copyTableModal.value = false
@@ -337,7 +479,38 @@ const copyTableModalClose = () => {
 //复制 保存
 const copyTableLoading = ref(false)
 const copyTableClick = () => {
-    copyTableModal.value = false
+    const rows = copyTableData.value
+    if (rows.length > 0) {
+        //判断是否满足条件
+        const result = rows.every(({isMaterialNumber})=> {
+            return isMaterialNumber === false
+        })
+        //判断状态
+        if (result) {
+            for (let i = 0; i < rows.length; i++) {
+                rows[i].dataNumber = i
+            }
+            tableCopyData(rows)
+        } else {
+            window.$message?.warning('请先完善材料编号')
+        }
+    } else {
+        window.$message?.warning('请先在列表勾选要复制的数据')
+        copyTableModal.value = false
+    }
+}
+
+//复制数据请求
+const tableCopyData = async (rows) => {
+    copyTableLoading.value = true
+    const { error, code } = await approachApi.copyData(rows)
+    //处理数据
+    copyTableLoading.value = false
+    if (!error && code === 200) {
+        window?.$message?.success('操作成功')
+        copyTableModal.value = false
+        await getTableData()
+    }
 }
 
 //删除
@@ -349,12 +522,32 @@ const delModalClick = () => {
         type: 'warning',
         callback: (action) => {
             if (action === 'confirm') {
-                //removeContractTreeNode()
+                tableRemoveData()
             }
         }
     })
 }
 
+//批量删除
+const tableRemoveData = async () => {
+    const rows = tableCheckedKeys.value
+    if (rows.length > 0 ) {
+        const ids = rowsToId(rows)
+        //删除请求
+        const { error, code } = await approachApi.removeData({
+            projectId: projectId.value,
+            contractId: contractId.value,
+            ids: ids,
+        })
+        //处理数据
+        if (!error && code === 200) {
+            window?.$message?.success('操作成功')
+            searchClick()
+        }
+    }
+}
+
+
 //导入
 const importModal = ref(false)
 const importModalClick = () => {
@@ -376,22 +569,47 @@ const importModalClose = () => {
 //查看附件
 const viewAttachmentModal = ref(false)
 const viewAttachmentModalClick = (row) => {
+    tableRowData.value = row
     viewAttachmentModal.value = true
 }
 
-const attachmentPdfUrl = ref('')
-
 //类型tab数据和相关处理
-const tabTypeKey = ref('tab1')
+const tabTypeKey = ref('productionCertificate')
 const tabTypeTab = ref([
-    {key:'tab1',  name: '生产合格证'},
-    {key:'tab2', name: '厂家质检报告'},
-    {key:'tab3', name: '其他文件'},
+    {key:'productionCertificate',  name: '生产合格证'},
+    {key:'qualityInspectionReport', name: '厂家质检报告'},
+    {key:'otherAccessories', name: '其他文件'},
 ]);
 const tabTypeChange = (item) => {
     tabTypeKey.value = item?.key
 }
 
+//上传进度
+const tableRowPdfDisabled = ref(false)
+const tableRowPdfProgress = (res) => {
+    tableRowPdfDisabled.value = res
+}
+
+//上传完成
+const tableRowPdfFinished = async (data) => {
+    tableRowPdfDisabled.value = true
+    const row = tableRowData.value, key = tabTypeKey.value
+    row[key] = data?.pdfUrl
+    //保存请求
+    const { error, code } = await approachApi.submitForm({
+        ...row,
+        projectId: projectId.value,
+        contractId: contractId.value
+    })
+    //处理数据
+    tableRowData.value = row
+    tableRowPdfDisabled.value = false
+    if (!error && code === 200) {
+        window?.$message?.success('操作成功')
+        await getTableData()
+    }
+}
+
 //关闭查看附件
 const viewAttachmentModalClose = () => {
     viewAttachmentModal.value = false
@@ -420,6 +638,13 @@ const samplingTableLoading = ref(false)
 const samplingRecordModalClose = () => {
     samplingRecordModal.value = false
 }
+
+//拼接ID
+const rowsToId = (rows) => {
+    return rows.map((obj) => {
+        return obj.id;
+    }).join(",")
+}
 </script>
 
 <style lang="scss" scoped>

+ 208 - 0
src/views/tentative/material/components/FormItemUpload.vue

@@ -0,0 +1,208 @@
+<template>
+    <div class="form-item-dashed hover flex" @click="importModalClick">
+        <div class="flex-1 truncate" v-if="uploadValue">{{fileNameValue}}</div>
+        <div class="flex-1" v-else>点此上传文件</div>
+        <div class="text-hover" @click.stop="previewClick" v-if="uploadValue">预览文件</div>
+    </div>
+
+    <!--上传-->
+    <HcDialog :show="importModal" title="上传文件" widths="38rem" saveText="确认上传" :loading="uploadDisabled" @close="importModalClose" @save="importModalYesClick">
+        <el-upload ref="uploadRef" class="hc-upload-border approach" drag :action="api + action" :headers="getTokenHeader()" :data="uploadData" :accept="accept" :disabled="uploadDisabled" :limit="1" :show-file-list="false"
+                   :before-upload="beforeUpload" :on-exceed="uploadExceed" :on-progress="uploadprogress" :on-success="uploadSuccess" :on-error="uploadError" :on-change="uploadChange" :auto-upload="false">
+            <div class="hc-upload-loading upload-file-info" v-loading="uploadDisabled" element-loading-text="上传中...">
+                <template v-if="uploadFileInfo?.name">
+                    <HcIcon name="file-text" class="upload-file-icon"/>
+                    <div class="upload-file-name">{{uploadFileInfo?.name}}</div>
+                </template>
+                <template v-else>
+                    <HcIcon name="upload-cloud" class="upload-icon"/>
+                    <div class="el-upload__text">拖动文件到这里 或 <em>点击这里选择文件</em> 并上传</div>
+                </template>
+            </div>
+            <template #tip>
+                <div class="el-upload__tip">允许格式:{{formatTip}}, 文件大小 小于 {{size}}MB</div>
+            </template>
+        </el-upload>
+    </HcDialog>
+</template>
+
+<script setup>
+import {ref, watch, onMounted} from "vue";
+import {getTokenHeader} from '~src/api/request/header';
+import {isSize} from "vue-utils-plus"
+import {genFileId} from "element-plus";
+const props = defineProps({
+    modelValue: {
+        type: String,
+        default: ''
+    },
+    datas: {
+        type: Object,
+        default: () => ({})
+    },
+    action: {
+        type: String,
+        default: "upload-file"
+    },
+    accept: {
+        type: String,
+        default: "image/png,image/jpg,image/jpeg,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword"
+    },
+    size: {
+        type: Number,
+        default: 20
+    },
+    formatTip: {
+        type: String,
+        default: "png/jpg/jpeg/excel/pdf/doc/docx"
+    },
+})
+
+//变量
+const uploadRef = ref(null)
+const uploadData = ref(props.datas)
+const uploadFileInfo = ref({})
+const uploadDisabled = ref(false)
+const uploadValue = ref(props.modelValue)
+
+const api = '/api/blade-resource/oss/endpoint/';
+
+//监听
+watch(() => [
+    props.datas,
+    props.modelValue
+], ([datas,val]) => {
+    uploadData.value = datas
+    uploadValue.value = val
+    getFileName(val)
+})
+
+onMounted(() => {
+    getFileName(props.modelValue)
+})
+
+//事件
+const emit = defineEmits(['progress', 'change', 'update:modelValue'])
+
+//上传弹窗
+const importModal = ref(false)
+const importModalClick = () => {
+    importModal.value = true
+}
+
+//确认上传
+const importModalYesClick = () => {
+    uploadRef.value?.submit()
+}
+
+//关闭上传
+const importModalClose = () => {
+    uploadRef.value?.clearFiles()
+    importModal.value = false
+}
+
+//获取文件名
+const fileNameValue = ref('')
+const getFileName = (url) => {
+    if (url) {
+        let num = url.lastIndexOf('/') + 1
+        fileNameValue.value = url.substring(num)
+    } else {
+        fileNameValue.value = ''
+    }
+}
+
+
+//上传前
+const beforeUpload = async (file) => {
+    if (isSize(file?.size,props.size)) {
+        return true;
+    } else {
+        window?.$message?.warning('文件大小, 不能过' + props.size + 'M!');
+        return false;
+    }
+}
+
+//超出限制时
+const uploadExceed = (files) => {
+    uploadRef.value?.clearFiles()
+    const file = files[0]
+    file.uid = genFileId()
+    uploadRef.value?.handleStart(file)
+}
+
+//上传中
+const uploadprogress = () => {
+    uploadDisabled.value = true
+    emit('progress', true)
+}
+
+//上传完成
+const uploadSuccess = ({code, data}) => {
+    uploadDisabled.value = false
+    emit('progress', false)
+    const pdfUrl = data?.pdfUrl ?? ''
+    if (code === 200 && pdfUrl) {
+        uploadValue.value = pdfUrl
+        window?.$message?.success('上传成功');
+        importModal.value = false
+        getFileName(pdfUrl)
+        //事件
+        emit('update:modelValue', pdfUrl)
+        emit('change', pdfUrl)
+    } else {
+        window?.$message?.error('上传失败');
+    }
+}
+
+//上传失败
+const uploadError = () => {
+    uploadDisabled.value = false
+    emit('progress', false)
+    window?.$message?.error('上传失败');
+}
+
+//文件改变时
+const uploadChange = (file) => {
+    uploadFileInfo.value = file
+}
+
+//预览文件
+const previewClick = () => {
+    const pdfUrl = uploadValue.value ?? ''
+    if (pdfUrl) window.open(pdfUrl,'_blank')
+}
+</script>
+
+<style lang="scss">
+.hc-upload-border.approach {
+    .el-upload-dragger {
+        padding: 24px;
+    }
+    .hc-upload-loading.upload-file-info {
+        .hc-icon-i {
+            font-size: 40px;
+        }
+        .upload-icon {
+            color: var(--el-text-color-placeholder);
+        }
+        .upload-file-icon {
+            color: var(--el-color-primary-light-5);
+        }
+        .el-upload__text {
+            margin-top: 10px;
+        }
+        .upload-file-name {
+            margin-top: 10px;
+            font-size: 14px;
+            text-align: center;
+            color: var(--el-color-primary);
+        }
+    }
+    .el-upload__tip {
+        font-size: 14px;
+        margin-top: 16px;
+        color: var(--el-text-color-placeholder);
+    }
+}
+</style>

+ 35 - 21
src/views/tentative/material/components/HcDragUpload.vue

@@ -1,7 +1,6 @@
 <template>
-    <el-upload ref="uploadRef" class="hc-upload-border approach" drag :action="action" :headers="getTokenHeader()" :data="uploadData" :accept="accept" :disabled="uploadDisabled" :limit="1" :show-file-list="false"
-               :before-upload="beforeUpload" :on-exceed="uploadExceed" :on-progress="uploadprogress" :on-success="uploadSuccess" :on-error="uploadError" :on-change="uploadChange" :auto-upload="false">
-
+    <el-upload ref="uploadRef" class="hc-upload-border approach" drag :action="api + action" :headers="getTokenHeader()" :data="uploadData" :accept="accept" :disabled="uploadDisabled" :limit="1" :show-file-list="false"
+               :before-upload="beforeUpload" :on-exceed="uploadExceed" :on-progress="uploadprogress" :on-success="uploadSuccess" :on-error="uploadError" :on-change="uploadChange" :auto-upload="autoUpload">
         <div class="hc-upload-loading upload-file-info" v-loading="uploadDisabled" element-loading-text="上传中...">
             <template v-if="uploadFileInfo?.name">
                 <HcIcon name="file-text" class="upload-file-icon"/>
@@ -14,7 +13,7 @@
         </div>
 
         <template #tip>
-            <div class="el-upload__tip">允许格式:excel, 文件大小 小于 60MB</div>
+            <div class="el-upload__tip">允许格式:{{formatTip}}, 文件大小 小于 {{size}}MB</div>
         </template>
     </el-upload>
 </template>
@@ -29,6 +28,26 @@ const props = defineProps({
         type: Object,
         default: () => ({})
     },
+    action: {
+        type: String,
+        default: "upload-file"
+    },
+    accept: {
+        type: String,
+        default: "image/png,image/jpg,image/jpeg,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword"
+    },
+    size: {
+        type: Number,
+        default: 20
+    },
+    formatTip: {
+        type: String,
+        default: "png/jpg/jpeg/excel/pdf/doc/docx"
+    },
+    autoUpload: {
+        type: Boolean,
+        default: false
+    },
 })
 
 //变量
@@ -37,8 +56,7 @@ const uploadData = ref(props.datas)
 const uploadFileInfo = ref({})
 const uploadDisabled = ref(false)
 
-const action = '/api/blade-manager/exceltab/add-buss-file';
-const accept = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel';
+const api = '/api/blade-resource/oss/endpoint/';
 
 //监听
 watch(() => [
@@ -47,16 +65,15 @@ watch(() => [
     uploadData.value = datas
 })
 
-
 //事件
 const emit = defineEmits(['progress', 'finished', 'change'])
 
 //上传前
 const beforeUpload = async (file) => {
-    if (isSize(file?.size,60)) {
+    if (isSize(file?.size, props.size)) {
         return true;
     } else {
-        window?.$message?.warning('文件大小, 不能过60M!');
+        window?.$message?.warning('文件大小, 不能过' + props.size + 'M!');
         return false;
     }
 }
@@ -76,29 +93,26 @@ const uploadprogress = () => {
 }
 
 //上传完成
-const uploadSuccess = (res) => {
+const uploadSuccess = ({code, data}) => {
     uploadDisabled.value = false
     emit('progress', false)
-    emit('finished', {
-        type: 'success',
-        data: getObjValue(res?.data)
-    })
+    if (code === 200) {
+        window?.$message?.success('上传成功');
+        emit('finished', data)
+    } else {
+        window?.$message?.error('上传失败');
+    }
 }
 
 //上传失败
-const uploadError = (res) => {
+const uploadError = () => {
     uploadDisabled.value = false
     emit('progress', false)
-    emit('finished', {
-        type: 'error',
-        data: getObjValue(res?.data)
-    })
-    window?.$message?.error('导入失败');
+    window?.$message?.error('上传失败');
 }
 
 //文件改变时
 const uploadChange = (file) => {
-    console.log(file)
     uploadFileInfo.value = file
     emit('change', file)
 }