|
@@ -1,9 +1,369 @@
|
|
<template>
|
|
<template>
|
|
- <div>首件工程上报</div>
|
|
|
|
|
|
+ <n-divider dashed title-placement="left">
|
|
|
|
+ <span class="text-hover" @click="goToBack()">首件工程</span>
|
|
|
|
+ <span class="ml-2">/</span>
|
|
|
|
+ <span class="ml-2">上报首件</span>
|
|
|
|
+ </n-divider>
|
|
|
|
+ <div class="hc-layout-box">
|
|
|
|
+ <div class="hc-layout-content-box">
|
|
|
|
+ <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
|
|
|
|
+ <div class="table-form-box">
|
|
|
|
+ <div :id="`table-form-${contractId}`"></div>
|
|
|
|
+ </div>
|
|
|
|
+ </n-card>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="hc-layout-card-box">
|
|
|
|
+ <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
|
|
|
|
+ <template #header>
|
|
|
|
+ <div class="hc-card-header flex items-center">
|
|
|
|
+ <div>上传总结报告:</div>
|
|
|
|
+ <div class="ml-2">
|
|
|
|
+ <n-upload :action="action" :headers="getTokenHeader()" :data="upData" :accept="accept" :disabled="!pkeyId"
|
|
|
|
+ :show-file-list="false" @before-upload="beforeUpload" @finish="uploadFinish">
|
|
|
|
+ <n-button type="primary" class="px-4" :loading="uploadLoading">选择文件</n-button>
|
|
|
|
+ </n-upload>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="ml-5 text-purple" v-if="pkeyId">{{fileName}}</div>
|
|
|
|
+ <div class="ml-5 text-purple" v-else>表单异常,暂时无法使用上传</div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ <n-data-table :columns="tableColumns" :data="tableData" :row-key="row => row.id" :pagination="false" :single-line="false" striped/>
|
|
|
|
+ <template #action>
|
|
|
|
+ <div class="text-center">
|
|
|
|
+ <n-button class="px-5" @click="goToBack">取消</n-button>
|
|
|
|
+ <n-button type="primary" class="px-5 ml-6" :disabled="!pkeyId" @click="saveBussData">保存</n-button>
|
|
|
|
+ <n-button type="primary" strong secondary class="px-5 ml-6" :disabled="!pkeyId" @click="bussPdfInfo">预览</n-button>
|
|
|
|
+ <n-button type="primary" strong secondary class="px-5 ml-6" :disabled="!pkeyId" @click="reportModalClick">上报</n-button>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </n-card>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <!--上报审批-->
|
|
|
|
+ <HcReportModal title="上报审批" url="informationWriteQuery/taskOne" :show="showReportModal" :projectId="projectId" :contractId="contractId"
|
|
|
|
+ :taskName="reportTaskName" :ids="reportIds" :addition="reportAddition" @hide="showReportModal= false" @finish="showReportFinish"/>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
|
+import {h, onMounted, ref, watch} from 'vue'
|
|
|
|
+import {createApp} from "vue/dist/vue.esm-bundler.js";
|
|
|
|
+import {getTokenHeader} from '~src/api/request/header';
|
|
|
|
+import HcReportModal from "~com/reportModal/index.vue"
|
|
|
|
+import firstItemApi from '~api/other/first-item';
|
|
|
|
+import {isObject,isObjNull} from "~src/utils/lib/isApp";
|
|
|
|
+import {ElButton,ElTooltip,ElInput,ElDatePicker,ElUpload,ElInputNumber,ElTimePicker,ElSelect,ElOption,ElRadioGroup,ElRadio,ElCheckbox,ElCheckboxGroup} from 'element-plus'
|
|
|
|
|
|
|
|
+//参数
|
|
|
|
+const props = defineProps({
|
|
|
|
+ rows: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: () => ([])
|
|
|
|
+ },
|
|
|
|
+ wbsId: {
|
|
|
|
+ type: [String,Number],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ relation: {
|
|
|
|
+ type: [String,Number],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ projectId: {
|
|
|
|
+ type: [String,Number],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ contractId: {
|
|
|
|
+ type: [String,Number],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+//初始变量
|
|
|
|
+const primaryKeyId = ref(props.wbsId)
|
|
|
|
+const relation = ref(props.relation)
|
|
|
|
+const projectId = ref(props.projectId)
|
|
|
|
+const contractId = ref(props.contractId)
|
|
|
|
+//监听
|
|
|
|
+watch(() => [
|
|
|
|
+ props.rows,
|
|
|
|
+ props.wbsId,
|
|
|
|
+ props.relation,
|
|
|
|
+ props.projectId,
|
|
|
|
+ props.contractId
|
|
|
|
+], ([rows,wid,rid,pid,cid]) => {
|
|
|
|
+ tableData.value = rows
|
|
|
|
+ primaryKeyId.value = wid
|
|
|
|
+ relation.value = rid
|
|
|
|
+ projectId.value = pid
|
|
|
|
+ contractId.value = cid
|
|
|
|
+ if (cid) getExcelHtmlData()
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+//渲染完成
|
|
|
|
+onMounted(() => {
|
|
|
|
+ if (contractId.value) {
|
|
|
|
+ getExcelHtmlData()
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+//表格表单渲染
|
|
|
|
+const pkeyId = ref(null)
|
|
|
|
+const tableFormData = ref({})
|
|
|
|
+const getExcelHtmlData = () => {
|
|
|
|
+ pkeyId.value = null
|
|
|
|
+ const cid = contractId.value
|
|
|
|
+ firstItemApi.getFirstExcelHtml({
|
|
|
|
+ contractId: cid
|
|
|
|
+ }).then(({data}) => {
|
|
|
|
+ const temp = data?.data?.data
|
|
|
|
+ if (!isObjNull(data.data) && temp) {
|
|
|
|
+ pkeyId.value = data?.data?.id ?? null
|
|
|
|
+ HTableForm(temp,tableFormData.value,cid)
|
|
|
|
+ //getBussDataInfo(data?.data?.id)
|
|
|
|
+ } else {
|
|
|
|
+ window?.$message?.warning(data.msg || '暂无表单')
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//渲染表格表单
|
|
|
|
+const HTableForm = (templateData, tableForm, cid) => {
|
|
|
|
+ const app = createApp({
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ getTokenHeader: getTokenHeader(),
|
|
|
|
+ formData: tableForm,
|
|
|
|
+ formUploadLoading: false,
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ template: templateData,
|
|
|
|
+ components: {ElButton,ElTooltip,ElInput,ElDatePicker,ElUpload,ElInputNumber,ElTimePicker,ElSelect,ElOption,ElRadioGroup,ElRadio,ElCheckbox,ElCheckboxGroup},
|
|
|
|
+ watch: {
|
|
|
|
+ tableForm: {
|
|
|
|
+ handler(obj) {
|
|
|
|
+ this.formData = obj
|
|
|
|
+ },
|
|
|
|
+ deep: true
|
|
|
|
+ },
|
|
|
|
+ formData: {
|
|
|
|
+ handler(obj) {
|
|
|
|
+ tableFormData.value = obj
|
|
|
|
+ },
|
|
|
|
+ deep: true
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ RightClick(a,b,c,d,e,f,event) {
|
|
|
|
+ event.preventDefault();
|
|
|
|
+ },
|
|
|
|
+ getInformation() {},
|
|
|
|
+ datePickerChange(val,key) {
|
|
|
|
+ this.formData[key] = val
|
|
|
|
+ },
|
|
|
|
+ //上传进度
|
|
|
|
+ uploadprogress() {
|
|
|
|
+ this.formUploadLoading = true
|
|
|
|
+ },
|
|
|
|
+ //上传完成
|
|
|
|
+ formUploadSuccess(res,key) {
|
|
|
|
+ this.formUploadLoading = false
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.formData[key] = res.data?.link || ''
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ //上传失败
|
|
|
|
+ formUploadError() {
|
|
|
|
+ this.formUploadLoading = false
|
|
|
|
+ },
|
|
|
|
+ //格式错误
|
|
|
|
+ formUploadExceed() {
|
|
|
|
+ this.formUploadLoading = false
|
|
|
|
+ },
|
|
|
|
+ //删除上传的文件
|
|
|
|
+ delTableFormFile(key) {
|
|
|
|
+ this.formData[key] = ''
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ app.mount(`#table-form-${cid}`)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//获取表单数据
|
|
|
|
+const getBussDataInfo = async (pkeyId) => {
|
|
|
|
+ if (pkeyId) {
|
|
|
|
+ const { data } = await firstItemApi.getFirstBussDataInfo({pkeyId: pkeyId + ''})
|
|
|
|
+ const valRes = isObject(data?.data) ? data?.data : {}
|
|
|
|
+ if (!isObjNull(valRes)) {
|
|
|
|
+ const pickerKey = valRes['pickerKey'] || ''
|
|
|
|
+ const pickerKeys = pickerKey.split(',')
|
|
|
|
+ for (let i = 0; i < pickerKeys.length; i++) {
|
|
|
|
+ const val = valRes[pickerKeys[i]] || ''
|
|
|
|
+ if (val) {
|
|
|
|
+ const data = val.replace(/'/g,'"');
|
|
|
|
+ valRes[pickerKeys[i]] = JSON.parse(data)
|
|
|
|
+ } else {
|
|
|
|
+ valRes[pickerKeys[i]] = []
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //有数据,关联数据
|
|
|
|
+ tableFormData.value = valRes
|
|
|
|
+ } else {
|
|
|
|
+ tableFormData.value = {}
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ tableFormData.value = {}
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//表格表头
|
|
|
|
+const tableData = ref(props.rows)
|
|
|
|
+const tableColumns = [
|
|
|
|
+ {title: '文件名称', key: 'name'},
|
|
|
|
+ {title: "操作", key: "actions", width: 80, align: 'center',
|
|
|
|
+ render(_, index) {
|
|
|
|
+ return h('span', {
|
|
|
|
+ class: 'text-red',
|
|
|
|
+ onClick: () => tableDelButton(index)
|
|
|
|
+ }, {
|
|
|
|
+ default: () => '删除'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+]
|
|
|
|
+
|
|
|
|
+//删除文件
|
|
|
|
+const tableDelButton = (index) => {
|
|
|
|
+ window?.$dialog?.warning({
|
|
|
|
+ title: "删除提醒",
|
|
|
|
+ content: "确定删除该文件吗?",
|
|
|
|
+ positiveText: "确定删除",
|
|
|
|
+ negativeText: "取消",
|
|
|
|
+ onPositiveClick: () => {
|
|
|
|
+ tableData.value.splice(index, 1)
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//文件上传
|
|
|
|
+const fileName = ref('')
|
|
|
|
+const upData = ref({})
|
|
|
|
+const action = '/api/blade-manager/first/add-first-buss-file';
|
|
|
|
+const accept = 'image/png,image/jpg,image/jpeg,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword';
|
|
|
|
+
|
|
|
|
+//上传前
|
|
|
|
+const uploadLoading = ref(false)
|
|
|
|
+const beforeUpload = ({file}) => {
|
|
|
|
+ let maxTrillion = 60;
|
|
|
|
+ let fileSizeData = file?.file?.size
|
|
|
|
+ let maxSize = maxTrillion * 1024 * 1024
|
|
|
|
+ if (fileSizeData > maxSize) {
|
|
|
|
+ window.$message?.warning(`文件大小,不能过${maxTrillion}M!`);
|
|
|
|
+ return false;
|
|
|
|
+ } else {
|
|
|
|
+ fileName.value = file.name
|
|
|
|
+ upData.value = {pkeyId: pkeyId.value}
|
|
|
|
+ uploadLoading.value = true
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+//上传完成
|
|
|
|
+const uploadFinish = ({event}) => {
|
|
|
|
+ uploadLoading.value = false
|
|
|
|
+ let res = JSON.parse(event?.target?.response);
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ window.$message?.success('上传成功');
|
|
|
|
+ } else {
|
|
|
|
+ window.$message?.error('上传失败');
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//填报数据保存
|
|
|
|
+const saveBussData = async () => {
|
|
|
|
+ const res = await saveExcelBussData(pkeyId.value + '')
|
|
|
|
+ if (res) {
|
|
|
|
+ getBussPdfInfo(pkeyId.value + '')
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//pdf预览
|
|
|
|
+const bussPdfInfo = () => {
|
|
|
|
+ getBussPdfInfo(pkeyId.value + '')
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//保存请求
|
|
|
|
+const saveExcelBussData = async (pkeyId) => {
|
|
|
|
+ const {data} = await firstItemApi.saveBussData({
|
|
|
|
+ ...tableFormData.value,
|
|
|
|
+ projectId: projectId.value,
|
|
|
|
+ contractId: contractId.value,
|
|
|
|
+ firstNodeId: primaryKeyId.value,
|
|
|
|
+ pkeyId: pkeyId,
|
|
|
|
+ classify: '1',
|
|
|
|
+ isFirst: 1
|
|
|
|
+ })
|
|
|
|
+ if(data && data.code === 200) {
|
|
|
|
+ window?.$message?.success('保存成功')
|
|
|
|
+ return true
|
|
|
|
+ } else {
|
|
|
|
+ window?.$message?.warning(data.msg || '保存失败')
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//预览PDF请求
|
|
|
|
+const getBussPdfInfo = (pkeyId) => {
|
|
|
|
+ const liunkIds = tableData.value.map((obj) => {
|
|
|
|
+ return obj?.id;
|
|
|
|
+ }).join(",")
|
|
|
|
+ //发起请求
|
|
|
|
+ firstItemApi.getFirstBussPdfInfo({
|
|
|
|
+ pkeyId: pkeyId,
|
|
|
|
+ liunkIds: liunkIds
|
|
|
|
+ }).then(({data}) => {
|
|
|
|
+ if(data.code === 200 && data?.data) {
|
|
|
|
+ window.open(data?.data,'_blank')
|
|
|
|
+ } else {
|
|
|
|
+ window.$message?.warning('暂无PDF')
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//事件
|
|
|
|
+const emit = defineEmits(['ToClose'])
|
|
|
|
+
|
|
|
|
+//批量上报
|
|
|
|
+const showReportModal = ref(false)
|
|
|
|
+const reportIds = ref('')
|
|
|
|
+const reportTaskName = ref('')
|
|
|
|
+const reportAddition = ref({})
|
|
|
|
+const reportModalClick = () => {
|
|
|
|
+ const rows = tableData.value
|
|
|
|
+ if (rows.length > 0) {
|
|
|
|
+ reportIds.value = rows.map((obj) => {
|
|
|
|
+ return obj?.id;
|
|
|
|
+ }).join(",")
|
|
|
|
+ reportTaskName.value = rows.length > 1?`${rows[0].name}等${rows.length}个文件`:rows[0].name
|
|
|
|
+ reportAddition.value = {
|
|
|
|
+ classify: 1,
|
|
|
|
+ isFirst: 1,
|
|
|
|
+ primaryKeyId: primaryKeyId.value,
|
|
|
|
+ contractIdRelation: relation.value ?? contractId.value,
|
|
|
|
+ }
|
|
|
|
+ showReportModal.value = true
|
|
|
|
+ } else {
|
|
|
|
+ window.$message?.warning('暂无相关数据')
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//上报完成
|
|
|
|
+const showReportFinish = () => {
|
|
|
|
+ showReportModal.value = false
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//关闭
|
|
|
|
+const goToBack = () => {
|
|
|
|
+ emit('ToClose')
|
|
|
|
+}
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
@@ -16,6 +376,19 @@
|
|
overflow: auto;
|
|
overflow: auto;
|
|
position: relative;
|
|
position: relative;
|
|
padding: 0 24px 15px 20px;
|
|
padding: 0 24px 15px 20px;
|
|
|
|
+ .table-form-box {
|
|
|
|
+ position: relative;
|
|
|
|
+ flex: 1;
|
|
|
|
+ overflow: auto;
|
|
|
|
+ height: 100%;
|
|
|
|
+ .hc-no-table-form {
|
|
|
|
+ position: relative;
|
|
|
|
+ height: 100%;
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ align-items: center;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
.hc-layout-card-box {
|
|
.hc-layout-card-box {
|
|
flex: 1;
|
|
flex: 1;
|
|
@@ -29,3 +402,25 @@
|
|
font-weight: initial;
|
|
font-weight: initial;
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|
|
|
|
+<style lang="scss">
|
|
|
|
+//设置表单样式
|
|
|
|
+.table-form-box {
|
|
|
|
+ td {
|
|
|
|
+ padding: 6px;
|
|
|
|
+ font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
|
|
|
|
+ .el-input {
|
|
|
|
+ background-color: #ffffff !important;
|
|
|
|
+ border-radius: 3px;
|
|
|
|
+ .el-input__wrapper {
|
|
|
|
+ background-color: inherit;
|
|
|
|
+ }
|
|
|
|
+ .el-input__wrapper.is-focus, .el-input__wrapper:hover {
|
|
|
|
+ box-shadow: 0 0 0 1.5px var(--el-input-focus-border-color) inset;
|
|
|
|
+ background-color: #eddac4;
|
|
|
|
+ }
|
|
|
|
+ //公式 #dcdcdc
|
|
|
|
+ //焦点 #eddac4
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|