Quellcode durchsuchen

feat: init

master
yxhc vor 1 Monat
Ursprung
Commit
85aeeb0b0c
100 geänderte Dateien mit 31625 neuen und 0 gelöschten Zeilen
  1. +3120
    -0
      src/pages/cockpit/index.vue
  2. +14
    -0
      src/pages/commonLogin/index.vue
  3. +266
    -0
      src/pages/declareManage/applicationRegist/index.vue
  4. +323
    -0
      src/pages/declareManage/constructionPlanDeclare/index.vue
  5. +466
    -0
      src/pages/declareManage/contractRecord/fillContractInfo/index.vue
  6. +224
    -0
      src/pages/declareManage/contractRecord/index.vue
  7. +132
    -0
      src/pages/declareManage/delayApply/components/applyDialog.vue
  8. +225
    -0
      src/pages/declareManage/delayApply/index.vue
  9. +794
    -0
      src/pages/declareManage/finalInspectionDeclare/declarationFinal/index.vue
  10. +210
    -0
      src/pages/declareManage/finalInspectionDeclare/index.vue
  11. +226
    -0
      src/pages/declareManage/initialInspectionRecord/index.vue
  12. +186
    -0
      src/pages/declareManage/initialInspectionRecord/uploadInitMaterials/components/actualPerformanceIndicatorsDialog.vue
  13. +581
    -0
      src/pages/declareManage/initialInspectionRecord/uploadInitMaterials/index.vue
  14. +69
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/applicationInfo.vue
  15. +186
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/applyInfo.vue
  16. +72
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/basicInfo.vue
  17. +59
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/coreBusiness.vue
  18. +139
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/empMaterials.vue
  19. +77
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/projectApprovalInfo.vue
  20. +94
    -0
      src/pages/declareManage/operationProjectRecord/detail/components/purchaseInfo.vue
  21. +142
    -0
      src/pages/declareManage/operationProjectRecord/detail/index.vue
  22. +201
    -0
      src/pages/declareManage/operationProjectRecord/index.vue
  23. +261
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/applicationInfo.vue
  24. +425
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/basicInfo.vue
  25. +110
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/budgetInfo.vue
  26. +193
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/coreBusiness.vue
  27. +559
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/empMaterials.vue
  28. +124
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/lineOrgDialog.vue
  29. +216
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/manageInfo.vue
  30. +263
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/otherMaterials.vue
  31. +69
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/progressInfo.vue
  32. +365
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/projectApprovalInfo.vue
  33. +198
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/projectContentDialog.vue
  34. +716
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/projectDeclareInfo.vue
  35. +720
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/purchaseInfo.vue
  36. +117
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/relatedIrsAppDialog.vue
  37. +171
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/relatedProjectDialog.vue
  38. +149
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/userDialog.vue
  39. +281
    -0
      src/pages/declareManage/operationProjectRecord/operationProjectEdit/index.vue
  40. +128
    -0
      src/pages/declareManage/preExaminationDeclare/components/preExaminationDialog.vue
  41. +261
    -0
      src/pages/declareManage/preExaminationDeclare/index.vue
  42. +252
    -0
      src/pages/declareManage/projectAdjustment/index.vue
  43. +298
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/accessory.vue
  44. +158
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/annualPaymentPlan.vue
  45. +460
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/appBasicInfo.vue
  46. +185
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/appResourceInfo.vue
  47. +85
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/appSafeInfo.vue
  48. +330
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/applicationInfo.vue
  49. +289
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/applications.vue
  50. +1162
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/basicInfo.vue
  51. +189
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/coreBusiness.vue
  52. +81
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/fundsAllocation.vue
  53. +189
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/fundsInfo.vue
  54. +106
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/hiddenAppForm.vue
  55. +103
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/newModuleForm.vue
  56. +92
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/projectImageProgress.vue
  57. +53
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/projectRemark.vue
  58. +179
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/provincialExamine.vue
  59. +81
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/reviewCheck.vue
  60. +143
    -0
      src/pages/declareManage/projectDeclare/declarePage/components/safetyInput.vue
  61. +870
    -0
      src/pages/declareManage/projectDeclare/declarePage/index.vue
  62. +61
    -0
      src/pages/declareManage/projectDeclare/draftDetails/index.vue
  63. +427
    -0
      src/pages/declareManage/projectDeclare/index.vue
  64. +154
    -0
      src/pages/declareManage/purchaseResults/components/implementPlanDialog.vue
  65. +355
    -0
      src/pages/declareManage/purchaseResults/fillPurchasingResult/index.vue
  66. +252
    -0
      src/pages/declareManage/purchaseResults/index.vue
  67. +289
    -0
      src/pages/declareManage/renewalProjectCapitalDeclare/index.vue
  68. +377
    -0
      src/pages/declareManage/renewalProjectCapitalDeclare/renewProjectDetail/index.vue
  69. +862
    -0
      src/pages/declareManage/renewalProjectCapitalDeclare/renewalCapitalDeclare/index.vue
  70. +431
    -0
      src/pages/expertEnroll/index.vue
  71. +124
    -0
      src/pages/expertManage/expertReview/components/leaveDialog.vue
  72. +171
    -0
      src/pages/expertManage/expertReview/components/meetingsLeaveDialog.vue
  73. +88
    -0
      src/pages/expertManage/expertReview/components/memberOpinion.vue
  74. +188
    -0
      src/pages/expertManage/expertReview/components/projectList.vue
  75. +157
    -0
      src/pages/expertManage/expertReview/components/reviewComments.vue
  76. +141
    -0
      src/pages/expertManage/expertReview/fillReviewComments/index.vue
  77. +66
    -0
      src/pages/expertManage/expertReview/handleExpertReview/index.vue
  78. +189
    -0
      src/pages/expertManage/expertReview/index.vue
  79. +546
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/components/basicInfo.vue
  80. +232
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/components/eduInfo.vue
  81. +80
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/components/expertOtherInfo.vue
  82. +315
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/components/jobInfo.vue
  83. +347
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/components/professionalInfo.vue
  84. +124
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/components/recommendInfo.vue
  85. +409
    -0
      src/pages/expertManage/expertStore/addOrEditExpert/index.vue
  86. +168
    -0
      src/pages/expertManage/expertStore/deputyActivityRecord/components/evaluateDialog.vue
  87. +147
    -0
      src/pages/expertManage/expertStore/deputyActivityRecord/index.vue
  88. +315
    -0
      src/pages/expertManage/expertStore/expertDetail/index.vue
  89. +249
    -0
      src/pages/expertManage/expertStore/index.vue
  90. +234
    -0
      src/pages/expertManage/expertVerify/index.vue
  91. +428
    -0
      src/pages/expertManage/expertVerify/verifyDetail/index.vue
  92. +218
    -0
      src/pages/expertManage/reviewMeeting/addMeeting/components/addExpertDialog.vue
  93. +149
    -0
      src/pages/expertManage/reviewMeeting/addMeeting/components/addProjectDialog.vue
  94. +1181
    -0
      src/pages/expertManage/reviewMeeting/addMeeting/index.vue
  95. +92
    -0
      src/pages/expertManage/reviewMeeting/components/meetingProjectDialog.vue
  96. +263
    -0
      src/pages/expertManage/reviewMeeting/index.vue
  97. +860
    -0
      src/pages/expertManage/reviewMeeting/meetingDetail/index.vue
  98. +251
    -0
      src/pages/expertManage/reviewTemplateConfig/index.vue
  99. +108
    -0
      src/pages/home/components/initialBootDialog.vue
  100. +2140
    -0
      src/pages/home/index.vue

+ 3120
- 0
src/pages/cockpit/index.vue
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 14
- 0
src/pages/commonLogin/index.vue Datei anzeigen

@@ -0,0 +1,14 @@
<script setup name="commonLogin">
import { onMounted } from 'vue'
import { singleLogin } from '@/http/apis/auth'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute(),
router = useRouter()
onMounted(async () => {
const postData = new URLSearchParams()
postData.append('credential', route.query.PROVINCE_FOREIGN_USER_TOKEN)
postData.append('platform', 'PROVINCIAL_BUREAU')
await singleLogin(postData)
router.replace('/')
})
</script>

+ 266
- 0
src/pages/declareManage/applicationRegist/index.vue Datei anzeigen

@@ -0,0 +1,266 @@
<script setup name="applicationRegist">
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
// import { declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
// import useExportExc from '@/utils/useExportExc'
import { list, pushProjectApp } from '@/http/apis/declareMange/applicationRegist'
import store from '@/store'
const router = useRouter(),
{ digitalModifySystem, projectTypeOptions } = store.dictStore.globalDicts,
{ proxy } = getCurrentInstance()
// 搜索栏表单数据
const searchForm = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
column = reactive([
{
type: 'expand'
},
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '批复时间',
key: 'approvalDate',
prop: 'approvalDate',
width: '110'
},
{
label: '批复金额(万元)',
key: 'approvedAmount',
prop: 'approvedAmount',
width: '140'
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '200'
},
{
label: '操作',
slot: 'action',
width: '120',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list({
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(2),
// 提交查询
search = () => {
getTableData()
},
// 重置
formReset = () => {
searchForm.projectYear = undefined
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.createOnMin = undefined
searchForm.createOnMax = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// // 导出excel文件
// { exportLoading, exportData } = useExportExc(),
// handleExcel = () => {
// exportData(() => declareExport(6, {
// ...searchForm,
// createOnMin: searchForm.times?.[0],
// createOnMax: searchForm.times?.[1],
// projectYear: searchForm.projectYear * 1 || undefined,
// times: undefined
// }))
// },
// 应用注册
visible = ref(false),
appData = ref(),
showDialog = (data) => {
visible.value = true
appData.value = data
}
onMounted(async () => {
getTableData()
window.onmessage = async (event) => {
if (event.data && event.data.msg === '编码已生成,请复制编码查询应用') {
console.log(event.data, '编码')
appData.value['appCode'] = event.data.data
await pushProjectApp(appData.value)
proxy.$message.success('注册成功')
visible.value = false
getTableData()
}
}
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<!-- <div>-->
<!-- <el-button-->
<!-- type="primary"-->
<!-- size="small"-->
<!-- plain-->
<!-- :loading="exportLoading"-->
<!-- @click="handleExcel"-->
<!-- >-->
<!-- 导出-->
<!-- </el-button>-->
<!-- </div>-->
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #expand="{scope}">
<div
v-for="(item,index) in scope.row.projectApplications"
:key="index"
class="flex py-8"
style="padding-left: 140px;border-bottom: 1px solid rgb(235, 238, 245)"
>
<p class="flex-1 pr-4">
应用名称:{{ item.applicationName ||item.relatedExistsApplication }}
</p>
<p class="flex-1 pr-4">
数改系统:{{ item.digitalModification&&item.digitalModification.split(',').map(i=>digitalModifySystem[i]).join(',')||'-' }}
</p>
<p class="flex-1 pr-4">
是否初次建设:{{ item.isFirst?'是':'否' }}
</p>
<p class="flex-1 pr-4">
是否注册:{{ item.isFirst&&item.appCode?'是':item.isFirst&&!item.appCode?'否':'--' }}
</p>
<p class="flex-1">
<a v-if="!item.appCode" @click="showDialog({projectCode:scope.row.projectCode,appId:item.id})">应用注册</a>
</p>
</div>
</template>
<template #action="{ scope }">
<a @click="router.push({name:'applicationRegistDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
<el-dialog
:model-value="visible"
title="应用注册"
width="80%"
@close="visible=false"
>
<iframe src="https://jdirs.zj.gov.cn/api/system/register-view?X-BG-HMAC-ACCESS-KEY=42bcb49bea174986a3bfdfba7d005566&path=Ovl4aua87eB" width="100%" height="700px"></iframe>
</el-dialog>
</template>
<style lang="less" scoped></style>

+ 323
- 0
src/pages/declareManage/constructionPlanDeclare/index.vue Datei anzeigen

@@ -0,0 +1,323 @@
<script setup name = 'constructionPlanDeclare'>
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { useRouter } from 'vue-router'
import { genFileId } from 'element-plus'
import store from '@/store'
import {
getConstructionDeclarePlan,
declareConstructionScheme,
declareExport
} from '@/http/apis/declareMange'
import { fileFormatVerification, handleFileSuccess, fileTypes, fileDesc, handleFilePreview } from '@/utils/uploadAction.js'
import useExportExc from '@/utils/useExportExc'
const { projectTypeOptions } = store.dictStore.globalDicts || {}
// 搜索栏表单数据
const { proxy } = getCurrentInstance(),
formInline = reactive({
projectName: '',
projectType: '',
projectYear: null,
startTime: '',
endTime: '',
createTimeArr: []
}),
router = useRouter(),
tableListRef = ref(),
selectData = ref([]),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await getConstructionDeclarePlan({
...pageParams,
...formInline,
startTime: formInline.createTimeArr?.length
? formInline.createTimeArr[0]
: undefined,
endTime: formInline.createTimeArr?.length
? formInline.createTimeArr[0]
: undefined,
createTimeArr: undefined
})
selectData.value = res.data.records
total.value = res.data.total
},
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: 80
},
{
label: '申报金额(万元)',
key: 'declaredAmount',
prop: 'declaredAmount',
width: '200'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '100'
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '250'
},
{
label: '操作',
slot: 'action',
width: '140',
fixed: 'right'
}
]),
// projectData = reactive([]),
rules = reactive({
constructionPlanFile: [
{ required: true, message: '请上传建设方案', trigger: 'blur' }
] }),
// 数据总数
total = ref(2),
checkDetail = (detailData) => {
// console.log('detailData', detailData)
router.push({ name: 'projectDeclareDetail', query: { id: detailData.id }})
},
// 提交查询
onSubmit = () => {
getTableData()
},
formReset = () => {
formInline.projectName = null
formInline.projectType = null
formInline.projectYear = null
formInline.startTime = null
formInline.endTime = null
formInline.createTimeArr = null
getTableData()
},
// 导出excel文件
tableDom = ref(),
handleTable = (value) => {
tableDom.value = value
},
// handleExcel = () => {
// exportExcel(tableDom.value)
// },
// 申报方案
// declarePlan = (val) => {
// projectId.value = val.id
// dialogVisible.value = true
// if (upload.value)upload.value.clearFiles()
// },
dialogVisible = ref(false),
handleClose = (done) => {
done()
},
// 文件上传
uploadUrl = store.dictStore.uploadUrl,
ruleForm = reactive({
constructionPlanFile: []
}),
upload = ref(),
planUploadRef = ref(),
constructionPlanRef = ref(),
handleExceed = (files) => {
upload.value.clearFiles()
const file = files[0]
file.uid = genFileId()
upload.value.handleStart(file)
},
projectId = ref(),
submitUpload = async (formEl) => {
if (!formEl) return
formEl.validate((valid) => {
if (valid) {
declareConstructionSchemeFunction()
} else {
console.log('error submit!')
}
})
},
declareConstructionSchemeFunction = async () => {
await declareConstructionScheme({
projectInfo: {
id: projectId.value,
constructionPlanFile: JSON.stringify(ruleForm.constructionPlanFile && ruleForm.constructionPlanFile.map(i => {
return {
fileId: i.response.data.id,
fileName: i.response.data.originalFileName
}
})[0])
}
})
dialogVisible.value = false
ruleForm.constructionPlanFile = []
proxy.$message.success('提交成功')
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(3, {
...formInline,
year: formInline.year * 1,
startTime: formInline.createTimeArr?.length
? formInline.createTimeArr[0]
: undefined,
endTime: formInline.createTimeArr?.length
? formInline.createTimeArr[0]
: undefined,
createTimeArr: undefined
}))
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="formInline" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input v-model="formInline.projectName" maxlength="50" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select v-model="formInline.projectType" placeholder="全部" class="w-full">
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="formInline.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="10">
<el-form-item label="创建时间">
<el-date-picker
v-model="formInline.createTimeArr"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="onSubmit">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>待申报的项目</span>
<div>
<el-button
type="primary"
plain
size="small"
:loading="exportLoading"
@click="handleExcel"
>导出</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="selectData"
:total="total"
@handle-table="handleTable"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="$router.push({name:'declarePlan',query:{id:scope.row.id}})">申报方案</a>
<a @click="checkDetail(scope.row)">详情</a>
</template>
</table-list>
</el-card>
<el-dialog
v-model="dialogVisible"
title="申报建设方案"
width="35%"
:before-close="handleClose"
>
<el-form
ref="constructionPlanRef"
:model="ruleForm"
:rules="rules"
label-position="right"
label-width="auto"
status-icon
>
<el-form-item label="建设方案:" prop="constructionPlanFile">
<el-upload
ref="planUploadRef"
v-model:file-list="ruleForm.constructionPlanFile"
:action="uploadUrl"
:limit="1"
:on-exceed="handleExceed"
:on-success="res => handleFileSuccess(res, ruleForm.constructionPlanFile, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="submitUpload(constructionPlanRef)">
提交
</el-button>
<el-button @click="dialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</template>
<style lang='less' scoped>

</style>

+ 466
- 0
src/pages/declareManage/contractRecord/fillContractInfo/index.vue Datei anzeigen

@@ -0,0 +1,466 @@
<script setup name="fillContractInfo">
import { getCurrentInstance, ref, onMounted } from 'vue'
import { changFilesParam, fileFormatVerification, handleFileSuccess, reviewFileParam, fileTypes, fileDesc, handleFilePreview } from '@/utils/uploadAction.js'
import store from '@/store'
import { useRouter, useRoute } from 'vue-router'
import { contractDetail, submitContract, supplement } from '@/http/apis/declareMange/contractRecord'

const uploadUrl = store.dictStore.uploadUrl,
{ proxy } = getCurrentInstance(),
router = useRouter(),
route = useRoute()
const formRef = ref(),
moneyValidator = (rule, value, callback) => {
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
} else {
callback()
}
},
rules = {
name: [{ required: true, message: '请输入合同名称' }],
totalAmount: [{ required: true, message: '请输入合同总金额' }, { validator: moneyValidator, trigger: 'blur' }],
supplierBank: [{ required: true, message: '请输入供应商收款开户行' }],
supplierAccount: [{ required: true, message: '请输入供应商收款账号' }],
warrantyPeriod: [{ required: true, message: '请输入质保期' }],
retentionMoney: [{ required: true, message: '请输入质保金' }, { validator: moneyValidator, trigger: 'blur' }],
contractTime: [{ required: true, message: '请选择合同签订完成时间' }],
deliveryTime: [{ required: true, message: '请选择交货日期' }],
attachment: [{ required: true, message: '请上传合同附件' }]
},
formData = ref({
attachment: [],
payments: []
}),
// 付款计划
column = ref([
{
label: '付款笔数',
key: 'number',
slot: 'number'
},
{
label: '付款计划',
key: 'planAmount',
slot: 'planAmount'
},
{
label: '付款比例(%)',
key: 'ratio',
slot: 'ratio'
},
{
label: '付款金额(万元)',
key: 'paymentAmount',
slot: 'paymentAmount'
},
{
label: '预计付款时间',
key: 'paymentTime',
slot: 'paymentTime'
},
{
label: '操作',
key: 'action',
slot: 'action',
width: 80
}
]),
// 添加付款计划
add = () => {
formData.value.payments.push({})
},
// 删除付款计划
del = (index) => {
formData.value.payments.splice(index, 1)
},
// 计算付款比例
blurMoney = (row) => {
row.ratio = Math.floor((row.paymentAmount / formData.value.totalAmount * 1) * 100 * 100) / 100
},
// 提交
submitLoading = ref(false),
submit = async (formEl) => {
console.log(formData.value)
if (!formEl) {
return
}
formEl.validate(async (valid, err) => {
if (valid) {
if (!route.query.isReplenishment) {
if (!formData.value.payments?.length) {
proxy.$message.warning('请至少添加一个付款计划')
return
}
const totalMoney = formData.value.payments.reduce((acc, cur) => {
return acc + cur.paymentAmount
}, 0)
if (totalMoney !== formData.value.totalAmount) {
proxy.$message.warning('付款金额总和必须等于合同总金额')
return
}
submitLoading.value = true
const postData = {
...formData.value,
projectId: route.query.id,
attachment: formData.value.attachment && JSON.stringify(changFilesParam(formData.value.attachment))
}
try {
await submitContract(postData)
submitLoading.value = false
proxy.$message.success('提交成功')
router.go(-1)
} catch (e) {
submitLoading.value = false
}
} else {
submitActualPaymentAmount()
}
}
})
},
// 提交补充金额
submitActualPaymentAmount = async () => {
submitLoading.value = true
try {
const postData = []
formData.value.payments.forEach(i => {
if ((i.actualPaymentAmount || i.actualPaymentAmount === 0) && !i.isReplenishment) {
postData.push({
actualPaymentAmount: i.actualPaymentAmount,
id: i.id,
projectCode: i.projectCode
})
}
})
await supplement(postData)
proxy.$message.success('提交成功')
router.go(-1)
submitLoading.value = false
} catch (e) {
submitLoading.value = false
}
},
// 获取详情
getDetail = async () => {
const res = await contractDetail(route.query.id)
if (res.data) {
formData.value = {
...res.data,
attachment: res.data.attachment ? reviewFileParam(JSON.parse(res.data.attachment)) : [],
payments: res.data.payments?.map(i => {
return {
...i,
isReplenishment: !!i.actualPaymentAmount
}
}) || []
}
}
},
validActualPaymentAmount = (rule, value, callback, index) => {
if (value < 0) {
callback('实际支付金额必须大于等于0')
} else if (index === 0) {
if (value > formData.value.payments[index].paymentAmount) {
callback('实际支付金额不能超过合同计划付款金额')
}
} else {
let maxData = formData.value.payments[index].paymentAmount
for (let i = 0; i < index; i++) {
maxData += formData.value.payments[i].paymentAmount - formData.value.payments[i]?.actualPaymentAmount || 0
}
if (value > maxData) {
callback(`实际支付金额不能超过${maxData}万元`)
}
}
callback()
}
onMounted(() => {
getDetail()
if (route.query.isReplenishment) {
column.value = [
{
label: '付款笔数',
key: 'number',
slot: 'number'
},
{
label: '付款计划',
key: 'planAmount',
slot: 'planAmount'
},
{
label: '付款比例(%)',
key: 'ratio',
slot: 'ratio'
},
{
label: '付款金额(万元)',
key: 'paymentAmount',
slot: 'paymentAmount'
},
{
label: '预计付款时间',
key: 'paymentTime',
slot: 'paymentTime'
},
{
label: '实际支付金额(万元)',
key: 'actualPaymentAmount',
slot: 'actualPaymentAmount',
width: 180
}
]
}
})
</script>
<template>
<div class="fillPurchasingResult footerPage">
<el-card class="w-full">
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item label="合同名称" prop="name">
<el-input
v-model="formData.name"
maxlength="50"
placeholder="请输入"
:disabled="!!$route.query.isReplenishment"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同总金额" prop="totalAmount">
<el-input
v-model.number="formData.totalAmount"
placeholder="请填写"
:disabled="!!$route.query.isReplenishment"
>
<template #suffix>万元</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商收款开户行" prop="supplierBank">
<el-input
v-model="formData.supplierBank"
maxlength="50"
placeholder="请输入"
:disabled="!!$route.query.isReplenishment"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商收款账号" prop="supplierAccount">
<el-input
v-model="formData.supplierAccount"
maxlength="50"
placeholder="请输入"
:disabled="!!$route.query.isReplenishment"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="质保期" prop="warrantyPeriod">
<el-input
v-model="formData.warrantyPeriod"
maxlength="50"
placeholder="请输入"
:disabled="!!$route.query.isReplenishment"
@input="formData.warrantyPeriod=formData.warrantyPeriod?.replace(/[^\d]/g,'')"
>
<template #suffix>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="质保金" prop="retentionMoney">
<el-input
v-model.number="formData.retentionMoney"
placeholder="请填写"
:disabled="!!$route.query.isReplenishment"
>
<template #suffix>万元</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="合同签订完成时间"
prop="contractTime"
>
<el-date-picker
v-model="formData.contractTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="交货日期"
prop="deliveryTime"
>
<el-date-picker
v-model="formData.deliveryTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="合同附件" prop="attachment">
<el-upload
v-model:file-list="formData.attachment"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.attachment)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<table-list
ref="tableListRef"
:column="column"
:data="formData.payments"
:pagination="false"
:empty-temp="false"
>
<template #number="{scope}">
<span>第{{ scope.$index+1 }}笔</span>
</template>
<template #planAmount="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`payments[${scope.$index}].planAmount`"
:rules="[{ required: true, message: '请输入' }]"
label-width="0"
style="margin-bottom: 0"
>
<el-input
v-model="scope.row.planAmount"
placeholder="请填写"
:disabled="!!$route.query.isReplenishment"
/>
</el-form-item>
</template>
<template #ratio="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`payments[${scope.$index}].ratio`"
:rules="[{ required: true, message: '请输入' }]"
label-width="0"
style="margin-bottom: 0"
>
<el-input v-model.number="scope.row.ratio" placeholder="自动计算" disabled />
</el-form-item>
</template>
<template #paymentAmount="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`payments[${scope.$index}].paymentAmount`"
:rules="[{ required: true, message: '请输入' }]"
label-width="0"
style="margin-bottom: 0"
>
<el-input-number
v-model="scope.row.paymentAmount"
placeholder="请填写"
:min="0"
:controls="false"
:disabled="!!$route.query.isReplenishment"
@mousewheel.prevent
@blur="blurMoney(scope.row)"
/>
</el-form-item>
</template>
<template #paymentTime="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`payments[${scope.$index}].paymentTime`"
:rules="[{ required: true, message: '请选择' }]"
label-width="0"
style="margin-bottom: 0"
>
<el-date-picker
v-model="scope.row.paymentTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
:disabled="!!$route.query.isReplenishment"
/>
</el-form-item>
</template>
<template #action="{scope}">
<a class="text-danger" @click="del(scope.$index)">删除</a>
</template>
<template #actualPaymentAmount="{scope}">
<el-form-item
v-if="scope.$index>=0"
label-width="0"
:prop="`payments[${scope.$index}].actualPaymentAmount`"
:rules="[{ validator: (rule,value,callback)=>validActualPaymentAmount(rule,value,callback,scope.$index)}]"
style="margin-bottom: 25px;margin-top: 20px"
>
<el-input-number
v-model="scope.row.actualPaymentAmount"
placeholder="请填写"
:min="0"
:controls="false"
:disabled="scope.row.isReplenishment"
@mousewheel.prevent
/>
</el-form-item>
</template>
</table-list>
<el-button
v-if="!$route.query.isReplenishment"
type="primary"
icon="Plus"
plain
class="w-full mt-8"
@click="add"
>添加付款计划</el-button>
<p v-if="$route.query.isReplenishment" class="text-danger text-14">温馨提示:请谨慎填写实际支付金额,填写后不允许修改</p>
</el-col>
</el-row>
</el-form>
</el-card>
<div class="footer">
<el-button @click="router.go(-1)"> 返回 </el-button>
<el-button type="primary" :loading="submitLoading" @click="submit(formRef)"> 提交 </el-button>
</div>
</div>
</template>

+ 224
- 0
src/pages/declareManage/contractRecord/index.vue Datei anzeigen

@@ -0,0 +1,224 @@
<script setup name="contractRecord">
import { ref, reactive, onMounted } from 'vue'
import { declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
import { list } from '@/http/apis/declareMange/contractRecord'
import store from '@/store'
const { projectTypeOptions } = store.dictStore.globalDicts || {}
const router = useRouter()
// 搜索栏表单数据
const searchForm = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
activeName = ref('1'),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '成交金额(万元)',
key: 'transactionAmount',
prop: 'transactionAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '成交时间',
key: 'transactionTime',
prop: 'transactionTime',
width: '120'
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '200'
},
{
label: '操作',
slot: 'action',
width: '190',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list(activeName.value, {
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(2),
// 提交查询
search = () => {
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
// 重置
formReset = () => {
searchForm.projectYear = undefined
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.createOnMin = undefined
searchForm.createOnMax = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
tabChange = (val) => {
activeName.value = val
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(7, {
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
}))
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8 tab-card">
<template #header>
<div class="flex justify-between items-center">
<el-tabs v-model="activeName" @tab-change="tabChange">
<el-tab-pane label="待完善合同信息" name="1" />
<el-tab-pane label="已完善合同信息" name="2" />
</el-tabs>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>
导出
</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a v-if="activeName==='1'" @click="router.push({ name: 'fillContractInfo', query: { id: scope.row.id }})">填写合同信息</a>
<a v-if="activeName==='2'&&!scope.row.supplemented" @click="router.push({ name: 'fillContractInfo', query: { id: scope.row.id,isReplenishment:true }})">补充实际付款金额</a>
<a @click="router.push({name:'contractRecordDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
</template>
<style lang="less" scoped></style>

+ 132
- 0
src/pages/declareManage/delayApply/components/applyDialog.vue Datei anzeigen

@@ -0,0 +1,132 @@
<script name="applyDialog" setup>
import { ref, getCurrentInstance, watch } from 'vue'
import { changFilesParam, fileFormatVerification, handleFileSuccess, fileTypes, fileDesc, handleFilePreview } from '@/utils/uploadAction.js'
import { delayedApply } from '@/http/apis/declareMange/delayApply'
import store from '@/store'
const { proxy } = getCurrentInstance(),
uploadUrl = store.dictStore.uploadUrl,
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object
}),
emits = defineEmits(['close']),
loading = ref(false),
dialogForm = ref({
supportingMaterials: []
}),
rules = {
'delayedMonth': [{ required: true, message: '请输入延期时长' }],
'delayedReason': [{ required: true, message: '请输入延期理由' }],
'supportingMaterials': [{ required: true, message: '请上传' }]
},
dialogFormRef = ref(),
submit = async (formEl) => {
if (!formEl) {
return
}
formEl.validate(async (valid) => {
if (valid) {
loading.value = true
try {
const postData = {
...dialogForm.value,
supportingMaterials: dialogForm.value?.supportingMaterials?.length && JSON.stringify(changFilesParam(dialogForm.value.supportingMaterials)) || undefined,
projectId: props.data.id
}
await delayedApply(postData)
proxy.$message.success('提交成功!')
loading.value = false
emits('close', true)
} catch (e) {
loading.value = false
}
}
}
)
}
watch(
() => props.visible,
async val => {
if (val) {
console.log('props.data', props.data)
} else {
dialogForm.value = { higherLineSuperOrgReviewComments: [] }
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="申请延期"
width="600px"
destroy-on-close
@close="emits('close')"
>
<el-form
ref="dialogFormRef"
:model="dialogForm"
:rules="rules"
label-width="auto"
status-icon
class="mt-16"
>
<el-form-item label="延期时长" prop="delayedMonth">
<el-input
v-model="dialogForm.delayedMonth"
placeholder="请填写需要延长几个月"
@input="dialogForm.delayedMonth=dialogForm.delayedMonth?.replace(/[^\d]/g,'')"
>
<template #suffix>月</template>
</el-input>
</el-form-item>
<el-form-item label="延期理由" prop="delayedReason">
<el-input
v-model="dialogForm.delayedReason"
type="textarea"
maxlength="1000"
show-word-limit
placeholder="请填写"
/>
</el-form-item>
<el-form-item label="佐证材料:" prop="supportingMaterials">
<el-upload
v-model:file-list="dialogForm.supportingMaterials"
class=" w-full"
:action="uploadUrl"
:limit="1"
:on-success="res => handleFileSuccess(res, dialogForm.supportingMaterials, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<el-button
type="primary"
:loading="loading"
@click="submit(dialogFormRef)"
>
提交
</el-button>
<el-button
@click="emits('close')"
>
关闭
</el-button>
</template>
</el-dialog>
</template>

+ 225
- 0
src/pages/declareManage/delayApply/index.vue Datei anzeigen

@@ -0,0 +1,225 @@
<script setup name="delayApply">
import { ref, reactive, onMounted } from 'vue'
import { declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
import { list } from '@/http/apis/declareMange/delayApply'
import ApplyDialog from './components/applyDialog.vue'
import store from '@/store'
const { projectTypeOptions } = store.dictStore.globalDicts || {}
const router = useRouter()
// 搜索栏表单数据
const searchForm = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '批复金额(万元)',
key: 'approvedAmount',
prop: 'approvedAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '计划验收时间',
key: 'planAcceptanceTime',
prop: 'planAcceptanceTime',
width: '200'
},
{
label: '操作',
slot: 'action',
width: '180',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list({
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(2),
// 提交查询
search = () => {
getTableData()
},
// 重置
formReset = () => {
searchForm.projectYear = undefined
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.createOnMin = undefined
searchForm.createOnMax = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(10, {
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
}))
},
// 申请延期
applyDelay = (data) => {
dialogData.visible = true
dialogData.data = data
},
dialogData = reactive({
visible: undefined,
data: undefined
}),
close = (flag) => {
dialogData.visible = false
flag && getTableData()
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="计划验收时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>
导出
</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a v-if="scope.row.canDelayApply" @click="applyDelay(scope.row)">申请延期</a>
<a @click="router.push({name:'delayApplyDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
<apply-dialog :visible="dialogData.visible" :data="dialogData.data" @close="close" />
</template>
<style lang="less" scoped></style>

+ 794
- 0
src/pages/declareManage/finalInspectionDeclare/declarationFinal/index.vue Datei anzeigen

@@ -0,0 +1,794 @@
<script name="declarationFinal" setup>
import { onMounted, ref, nextTick, getCurrentInstance, reactive } from 'vue'
import { fileFormatVerification, handleFileSuccess, handleFilePreview, fileTypes } from '@/utils/uploadAction.js'
import store from '@/store'
import * as echarts from 'echarts'
import { useRoute, useRouter } from 'vue-router'
import { submitFinal } from '@/http/apis/declareMange/finalInspectionDeclare'
import { projectDetail } from '@/http/apis/projectStoreManage/projectStore'
import ActualPerformanceIndicatorsDialog
from '@/pages/declareManage/initialInspectionRecord/uploadInitMaterials/components/actualPerformanceIndicatorsDialog.vue'
const uploadUrl = store.dictStore.uploadUrl,
route = useRoute(),
{ proxy } = getCurrentInstance(),
router = useRouter()
const collapseModal = ['1', '2', '3', '4', '5', '6', '7'],
formRef = ref(),
formData = ref({
finalAcceptanceMaterials: [
{
title: '一、项目前期材料',
data: [
{
name: '信息化项目立项批复文件',
isHave: true,
files: [],
reason: ''
},
{
name: '市政府采购计划表',
isHave: true,
files: [],
reason: ''
},
{
name: '采购需求',
isHave: true,
files: [],
reason: ''
},
{
name: '中标通知书',
isHave: true,
files: [],
reason: ''
},
{
name: '技术(软件、系统等)开发合同(协议)',
isHave: true,
files: [],
reason: ''
},
{
name: '设备采购合同(协议)含采购内容清单、以及合同上规定交付的所有文档',
isHave: true,
files: [],
reason: ''
},
{
name: '第三方监理合同(协议)',
isHave: true,
files: [],
reason: ''
},
{
name: '其他前期资料(含中标单位营业执照、工程相关资质等)',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '二、项目开工资料',
data: [
{
name: '工程开工报告单(工程名称、建设单位、承建单位、施工单位、计划开工和完工日期、工程实施主要内容、建设单位审批意见及盖章日期,承建单位、施工单位盖章日期)',
isHave: true,
files: [],
reason: ''
},
{
name: '软件类系统开发、部署等功能介绍',
isHave: true,
files: [],
reason: ''
},
{
name: '隐蔽工程类设计图、材料选材、施工计划等(可另作图册)',
isHave: true,
files: [],
reason: ''
},
{
name: '购置到位的设备产品证书、开箱证明、序列号等(可另附成册)',
isHave: true,
files: [],
reason: ''
},
{
name: '项目组名单及人员介绍资料',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '三、项目实施过程资料',
data: [
{
name: '设备安装时间、位置一览表等',
isHave: true,
files: [],
reason: ''
},
{
name: '软件类系统开发、部署等完成情况对照表',
isHave: true,
required: true,
files: [],
reason: ''
},
{
name: '历次多方讨论会议记录表、项目变更单等原始凭证',
isHave: true,
files: [],
reason: ''
},
{
name: '信息安全等级保护测评报告',
isHave: true,
required: true,
files: [],
reason: ''
},
{
name: '商业密码应用评估报告',
isHave: true,
files: [],
reason: ''
},
{
name: '财务审计报告',
isHave: true,
files: [],
reason: ''
},
{
name: '变更申请单',
isHave: true,
files: [],
reason: ''
},
{
name: '变更批复文件',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '四、项目试运行资料',
data: [
{
name: '试运行报告及整改情况(建设单位)',
isHave: true,
files: [],
reason: ''
},
{
name: '试运行情况业主单位意见(领导签字、单位盖章)',
isHave: true,
files: [],
reason: ''
},
{
name: '历次巡检流程及记录表等原始凭证',
isHave: true,
files: [],
reason: ''
},
{
name: '用户使用报告',
isHave: true,
required: true,
files: [],
reason: ''
},
{
name: 'IRS应用试运行报告',
isHave: true,
required: true,
files: [],
reason: ''
}
]
},
{
title: '五、项目完工资料',
data: [
{
name: '工程类竣工报告(建设单位)',
isHave: true,
files: [],
reason: ''
},
{
name: '完工整体运行情况报告',
isHave: true,
files: [],
reason: ''
},
{
name: '监理总结报告',
isHave: true,
files: [],
reason: ''
},
{
name: '第三方项目评测报告(另册)',
isHave: true,
files: [],
reason: ''
},
{
name: '业主单位组织的初验专家意见及名单,整改情况',
isHave: true,
files: [],
reason: ''
},
{
name: '各类系统、场地、设备使用的管理手册、操作手册、维护手册(可另册)',
isHave: true,
files: [],
reason: ''
},
{
name: '售后服务承诺等(建设单位)',
isHave: true,
files: [],
reason: ''
},
{
name: '终验意见',
isHave: true,
required: true,
files: [],
reason: ''
}
]
}
]
}),
// 材料表格
column = [
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '材料名称',
key: 'name',
prop: 'name'
},
{
label: '是否有材料',
key: 'isHave',
slot: 'isHave',
width: 100
},
{
label: '附件/说明(支持扩展名:.doc .docx .pdf)',
key: 'files',
slot: 'files'
}
],
applications = ref([
{
name: '应用1',
status: '运行中',
memoryRate: 11,
cpuRate: 33,
cpRate: 44
},
{
name: '应用2',
status: '运行中',
memoryRate: 68,
cpuRate: 43,
cpRate: 30
}
]),
applicationData = ref({})
let chart1, chart2, chart3
const chart1Ref = ref(), chart2Ref = ref(), chart3Ref = ref(),
getCirChartOptions = (precent, color, text) => {
const colorList = [color, 'rgba(0, 0, 0, 0.1)']
return {
legend: {
show: false
},
graphic: [
{
type: 'text',
left: 'center',
top: '48%',
style: {
text: `${precent}%`,
fill: '#333333', // 文字的颜色
fontSize: 16,
fontWeight: 'bold',
fontFamily: 'DINAlternate-Bold, DINAlternate'
}
},
{
type: 'text',
left: 'center',
bottom: '0',
style: {
text: `${text}`,
fill: '#333333', // 文字的颜色
fontSize: 12
}
}
],
series: [
{
type: 'pie',
radius: ['58%', '75%'],
center: ['50%', '50%'],
avoidLabelOverlap: false,
data: [
{
value: precent
},
{
value: 100 - precent
}
],
itemStyle: {
color: function (params) {
return colorList[params.dataIndex]
}
},
labelLine: {
show: false
}
}
]
}
},
initChart1 = () => {
if (!chart1) chart1 = echarts.init(chart1Ref.value)
const option = getCirChartOptions(applicationData.value.memoryRate, '#5ADE92',
'近三个月内存平均使用率')
chart1.setOption(option)
},
initChart2 = () => {
if (!chart2) chart2 = echarts.init(chart2Ref.value)
const option = getCirChartOptions(applicationData.value.cpuRate, '#0967FD',
'近三个月CPU平均使用率')
chart2.setOption(option)
},
initChart3 = () => {
if (!chart3) chart3 = echarts.init(chart3Ref.value)
const option = getCirChartOptions(applicationData.value.cpRate, '#ffae00',
'近三个月磁盘平均使用率')
chart3.setOption(option)
},
getChart = () => {
initChart1()
initChart2()
initChart3()
},
// 切换应用
tabName = ref(0),
changeApp = (index) => {
tabName.value = index
applicationData.value = applications.value[index]
getChart()
},
// 提交
submitLoading = ref(false),
submit = async (formEl) => {
if (!formEl) {
return
}
formEl.validate(async (valid, err) => {
if (valid) {
submitLoading.value = true
const postData = {
id: route.query.id,
isCompletedLogCollection: formData.value.isCompletedLogCollection,
finalAcceptanceMaterials: JSON.stringify(formData.value.finalAcceptanceMaterials),
actualPerformanceIndicators: formData.value.actualPerformanceIndicators && JSON.stringify(formData.value.actualPerformanceIndicators) || undefined
}
try {
await submitFinal(route.name === 'declarationFinal' ? 1 : 2, { projectInfo: postData })
submitLoading.value = false
proxy.$message.success('提交成功')
router.go(-1)
} catch (e) {
submitLoading.value = false
}
} else {
console.log(err)
}
})
},
getProjectDetail = async () => {
const res = await projectDetail(route.query.id)
formData.value = {
isCompletedLogCollection: res.data.isCompletedLogCollection,
finalAcceptanceMaterials: res.data.finalAcceptanceMaterials && JSON.parse(res.data.finalAcceptanceMaterials) || res.data.preliminaryInspectionMaterials && JSON.parse(res.data.preliminaryInspectionMaterials),
actualPerformanceIndicators: res.data.actualPerformanceIndicators && JSON.parse(res.data.actualPerformanceIndicators) || res.data.actualPerformanceIndicators && JSON.parse(res.data.actualPerformanceIndicators)
}
formData.value.finalAcceptanceMaterials = formData.value.finalAcceptanceMaterials.map(i => {
return {
...i,
data: i.data.map(j => {
return {
...j,
isHave: ['软件类系统开发、部署等完成情况对照表', '信息安全等级保护测评报告', '用户使用报告', 'IRS应用试运行报告', '终验意见'].includes(j.name) ? true : j.isHave,
required: ['软件类系统开发、部署等完成情况对照表', '信息安全等级保护测评报告', '用户使用报告', 'IRS应用试运行报告', '终验意见'].includes(j.name) ? true : j.required
}
})
}
})
if (res.data.projectApplications?.length) {
if (res.data.projectApplications.map(i => i.secrecyGrade).includes(3) || res.data.projectApplications.map(i => i.secrecyGrade).includes(4) || res.data.projectApplications.map(i => i.secrecyGrade).includes(5)) {
formData.value.finalAcceptanceMaterials = formData.value.finalAcceptanceMaterials.map(i => {
return {
...i,
data: i.data.map(j => {
return {
...j,
isHave: ['商业密码应用评估报告'].includes(j.name) ? true : j.isHave,
required: ['商业密码应用评估报告'].includes(j.name) ? true : j.required
}
})
}
})
}
}
applications.value = res.data.projectApplications?.map((i, index) => {
return {
name: i.applicationName || i.relatedExistsApplication,
status: '运行中',
finalIrsApps: res.data.finalIrsApps[index]
}
}) || []
applicationData.value = applications.value[0]
},
// 实际成效指标
column1 = [
{
label: '核心业务',
prop: 'businessName',
key: 'businessName'
},
{
label: '实际成效指标',
prop: 'name',
key: 'name'
},
{
label: '数值',
prop: 'nums',
key: 'nums'
},
{
label: '单位',
prop: 'unit',
key: 'unit'
},
{
label: '操作',
slot: 'action',
key: 'action'
}
],
projectContentDialogData = reactive({
visible: false,
data: undefined
}),
projectContentIndex = ref(),
showProjectContentDialog = (data, index) => {
projectContentDialogData.data = data
projectContentDialogData.visible = true
projectContentIndex.value = index
},
setContent = (data) => {
if (projectContentIndex.value === undefined) {
formData.value.actualPerformanceIndicators = formData.value.actualPerformanceIndicators?.length ? [...formData.value.actualPerformanceIndicators, ...data] : data
} else {
formData.value.actualPerformanceIndicators[projectContentIndex.value] = data[0]
}
},
delProjectContent = (index) => {
formData.value.actualPerformanceIndicators.splice(index, 1)
}
onMounted(async () => {
await nextTick()
// getChart()
getProjectDetail()
})

</script>

<template>
<div class="uploadInitfinalAcceptanceMaterials footerPage">
<el-form
ref="formRef"
:model="formData"
label-position="right"
label-width="90px"
label-suffix=":"
scroll-to-error
class="table-form"
>
<el-collapse v-model="collapseModal">
<el-collapse-item v-if="applications?.length" name="1" class="mb-16">
<template #title>
<div class="collapse-title">关联的应用信息</div>
</template>
<div class="pb-24">
<el-tabs v-model="tabName" tab-position="left" @tab-change="changeApp">
<el-tab-pane
v-for="(item,index) in applications"
:key="index"
:label="item.name"
:name="index"
/>
<div class="pl-24">
<p class="font-semibold text-14 mb-16">应用状态:<span class="text-primary">{{ applicationData.status }}</span></p>
<p class="font-semibold text-14">资源概览</p>
<div class="p-16">
<el-row class="mb-16">
<el-col :span="12">
<p class="mb-8">云资源使用情况</p>
<el-descriptions :column="1" border>
<el-descriptions-item label="云资源实例使用数">
{{ applicationData?.finalIrsApps?.cloudResourceUsage.instancesNum }}
</el-descriptions-item>
<el-descriptions-item label="云资源产品">
暂无
</el-descriptions-item>
<el-descriptions-item label="云资源利用率">
{{ applicationData?.finalIrsApps?.cloudResourceUsage.utilizationRate }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb-16">
<p class="mb-8">数据使用情况</p>
<el-descriptions :column="1" border>
<el-descriptions-item label="数据共享申请量">
{{ applicationData?.finalIrsApps?.dataUsage.sharedApplicationVolume }}
</el-descriptions-item>
<el-descriptions-item label="数据共享使用量">
{{ applicationData?.finalIrsApps?.dataUsage.sharedUsage }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="12" class="mb-16">
<p class="mb-31"></p>
<el-descriptions :column="1" border>
<el-descriptions-item label="协同接口调用量">
{{ applicationData?.finalIrsApps?.dataUsage.collaborativeInterfaceCallVolume }}
</el-descriptions-item>
<el-descriptions-item label="数据共享调用量">
{{ applicationData?.finalIrsApps?.dataUsage.sharedInterfaceCallVolume }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="12" class="mb-16">
<p class="mb-8">组件使用情况</p>
<el-descriptions :column="1" border>
<el-descriptions-item label="组件申请量">
{{ applicationData?.finalIrsApps?.componentUsage.applicationVolume }}
</el-descriptions-item>
<el-descriptions-item label="组件调用量">
{{ applicationData?.finalIrsApps?.componentUsage.callVolume }}
</el-descriptions-item>
<el-descriptions-item label="组件使用量">
{{ applicationData?.finalIrsApps?.componentUsage.useVolume }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="12" class="mb-16">
<p class="mb-31"></p>
<el-descriptions :column="1" border>
<el-descriptions-item label="统一组件调用量">
{{ applicationData?.finalIrsApps?.componentUsage.unifyCallolVolume }}
</el-descriptions-item>
<el-descriptions-item label="使用组件">
暂无
</el-descriptions-item>
<el-descriptions-item label="使用强制类组件">
暂无
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="12" class="mb-16">
<p class="mb-8">产生数据</p>
<el-descriptions :column="1" border>
<el-descriptions-item label="产生数据量">
{{ applicationData?.finalIrsApps?.generateData.volume }}
</el-descriptions-item>
<el-descriptions-item label="产生数据共享使用量">
{{ applicationData?.finalIrsApps?.generateData.sharedUseVolume }}
</el-descriptions-item>
<el-descriptions-item label="数据接口被调用量">
{{ applicationData?.finalIrsApps?.generateData.dataInterfaceCallsVolume }}
</el-descriptions-item>
<el-descriptions-item label="使用批量数据">
暂无
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="12" class="mb-16">
<p class="mb-31"></p>
<el-descriptions :column="1" border>
<el-descriptions-item label="产生数据共享申请量">
{{ applicationData?.finalIrsApps?.generateData.sharedApplicationVolume }}
</el-descriptions-item>
<el-descriptions-item label="产生数据审批通过率">
{{ applicationData?.finalIrsApps?.generateData.approvalPassRate }}
</el-descriptions-item>
<el-descriptions-item label="协同接口被调用量">
{{ applicationData?.finalIrsApps?.generateData.collaborativeInterfaceCallVolume }}
</el-descriptions-item>
<el-descriptions-item label="使用共享接口">
暂无
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="12">
<p class="mb-8">试运行报告</p>
<el-descriptions :column="1" border>
<el-descriptions-item label="试运行报告通过率">
{{ applicationData?.finalIrsApps?.operationReport.passRate }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</div>
<template v-if="false">
<p class="font-semibold text-14">云资源利用率</p>
<el-row>
<el-col :span="8">
<div ref="chart1Ref" style="height: 200px"></div>
</el-col>
<el-col :span="8">
<div ref="chart2Ref" style="height: 200px"></div>
</el-col>
<el-col :span="8">
<div ref="chart3Ref" style="height: 200px"></div>
</el-col>
</el-row>
</template>
</div>
</el-tabs>
</div>
</el-collapse-item>
<el-collapse-item name="7" class="mb-16">
<template #title>
<div class="collapse-title">实施信息</div>
</template>
<el-form-item
label="是否完成日志数据归集"
label-width="170"
prop="isCompletedLogCollection"
:rules="[{required:true,message:'请选择'}]"
>
<el-radio-group v-model="formData.isCompletedLogCollection">
<el-radio :label="true">是</el-radio>
<el-radio :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label="实际成效指标"
label-width="170"
prop="actualPerformanceIndicators"
:rules="[{required:true,message:'请选择'}]"
>
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="formData.actualPerformanceIndicators"
:empty-temp="false"
>
<template #action="{scope}">
<a @click="showProjectContentDialog(scope.row,scope.$index)">编辑</a>
<a class="text-danger" @click="delProjectContent(scope.$index)">删除</a>
</template>
</table-list>
<p class="text-right w-full mt-8">
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="()=>showProjectContentDialog()"
>添加</el-button>
</p>
</el-form-item>
</el-collapse-item>
<el-collapse-item
v-for="(item,index) in formData.finalAcceptanceMaterials"
:key="index"
:name="index+2+''"
class="mb-16"
>
<template #title>
<div class="collapse-title">{{ item.title }}</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="item.data"
:pagination="false"
:empty-temp="false"
>
<template #isHave="{scope}">
<el-switch v-model="scope.row.isHave" :disabled="scope.row.required" />
</template>
<template #files="{scope}">
<template v-if="scope.$index>=0">
<el-form-item
v-if="scope.row.isHave"
:prop="`finalAcceptanceMaterials[${index}].data[${scope.$index}].files`"
:rules="[{ required: true, message: '请上传' }]"
label-width="0"
style="margin-bottom: 0"
class="uploadFormItem"
>
<el-upload
v-model:file-list="scope.row.files"
class="w-full table-upload"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, scope.row.files)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain size="small">选择文件</el-button>
</el-upload>
</el-form-item>
<el-form-item
v-else
:prop="`finalAcceptanceMaterials[${index}].data[${scope.$index}].reason`"
:rules="[{ required: true, message: '请输入' }]"
label-width="0"
style="margin-bottom: 0"
>
<el-input v-model="scope.row.reason" placeholder="请填写缺少该材料的原因" maxlength="50" />
</el-form-item>
</template>
</template>
</table-list>
</el-collapse-item>
</el-collapse>
</el-form>
<div class="footer">
<el-button @click="router.go(-1)"> 返回 </el-button>
<el-button type="primary" :loading="submitLoading" @click="submit(formRef)"> 提交 </el-button>
</div>
</div>
<actual-performance-indicators-dialog
:visible="projectContentDialogData.visible"
:data="projectContentDialogData.data"
@set-content="setContent"
@close="projectContentDialogData.visible=false"
/>
</template>
<style lang="less">
.uploadInitfinalAcceptanceMaterials{
.table-form{
.uploadFormItem{
.el-form-item__error{
position: absolute;
left: 100px;
top:16px;
transform: translateY(-50%);
}
}
}
}
</style>

+ 210
- 0
src/pages/declareManage/finalInspectionDeclare/index.vue Datei anzeigen

@@ -0,0 +1,210 @@
<script setup name="finalInspectionDeclare">
import { ref, reactive, onMounted } from 'vue'
import { declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
import { list } from '@/http/apis/declareMange/finalInspectionDeclare'
import store from '@/store'
const router = useRouter()
const { projectTypeOptions } = store.dictStore.globalDicts || {}
// 搜索栏表单数据
const searchForm = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '批复金额(万元)',
key: 'approvedAmount',
prop: 'approvedAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '计划验收时间',
key: 'planAcceptanceTime',
prop: 'planAcceptanceTime',
width: '200'
},
{
label: '操作',
slot: 'action',
width: '180',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list({
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(0),
// 提交查询
search = () => {
getTableData()
},
// 重置
formReset = () => {
searchForm.projectYear = undefined
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.createOnMin = undefined
searchForm.createOnMax = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(9, {
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
}))
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="计划验收时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>
导出
</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="router.push({ name: 'declarationFinal', query: { id: scope.row.id }})">终验申报</a>
<a @click="router.push({name:'finalInspectionDeclareDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
</template>
<style lang="less" scoped></style>

+ 226
- 0
src/pages/declareManage/initialInspectionRecord/index.vue Datei anzeigen

@@ -0,0 +1,226 @@
<script setup name="initialInspectionRecord">
import { ref, reactive, onMounted } from 'vue'
import { declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
import { list } from '@/http/apis/declareMange/initialInspectionRecord'
import store from '@/store'
const { projectTypeOptions } = store.dictStore.globalDicts || {}
const router = useRouter()
// 搜索栏表单数据
const searchForm = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '年度预算(万元)',
key: 'annualPlanAmount',
prop: 'annualPlanAmount',
width: '150'
},
{
label: '成交金额(万元)',
key: 'transactionAmount',
prop: 'transactionAmount',
width: '150'
},
{
label: '合同金额(万元)',
key: 'contractAmount',
prop: 'contractAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '交货日期',
key: 'deliveryTime',
prop: 'deliveryTime',
width: '200'
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '200'
},
{
label: '操作',
slot: 'action',
width: '180',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list({
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(2),
// 提交查询
search = () => {
getTableData()
},
// 重置
formReset = () => {
searchForm.projectYear = undefined
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.createOnMin = undefined
searchForm.createOnMax = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(8, {
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
}))
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>
导出
</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="router.push({ name: 'uploadInitMaterials', query: { id: scope.row.id }})">上传初验材料</a>
<a @click="router.push({name:'initialInspectionRecordDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
</template>
<style lang="less" scoped></style>

+ 186
- 0
src/pages/declareManage/initialInspectionRecord/uploadInitMaterials/components/actualPerformanceIndicatorsDialog.vue Datei anzeigen

@@ -0,0 +1,186 @@
<script setup name="actualPerformanceIndicatorsDialog">
import { ref, watch } from 'vue'

const
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object
}),
form = ref({
perIndicator: []
}),
formRef = ref(),
rules = {
perIndicator: [{ required: true, message: '请至少添加一个实际成效指标' }]
},
column = [
{
label: '核心业务名称',
key: 'businessName',
slot: 'businessName',
width: 140
},
{
label: '实际成效指标名称',
key: 'name',
slot: 'name',
width: 140
},
{
label: '数值',
key: 'nums',
slot: 'nums'
},
{
label: '单位',
key: 'unit',
slot: 'unit'
},
{
label: '操作',
key: 'action',
slot: 'action',
width: 70
}
],
// 添加
add = () => {
form.value.perIndicator.push({})
},
del = (index) => {
form.value.perIndicator.splice(index, 1)
},
submit = async (formEl) => {
if (!formEl) {
return
}
await formEl.validate(async (valid) => {
if (valid) {
const data = JSON.parse(JSON.stringify(form.value.perIndicator))
emits('setContent', data)
emits('close', true)
}
})
},
isShowAdd = ref(true),
emits = defineEmits(['close', 'setContent'])
watch(
() => props.visible,
async (val) => {
if (val && props.data) {
isShowAdd.value = !props.data
form.value.perIndicator = [JSON.parse(JSON.stringify(props.data))]
} else {
isShowAdd.value = true
formRef.value?.resetFields()
form.value = {
perIndicator: []
}
}
}
)
</script>
<template>
<el-dialog
:model-value="visible"
title="添加"
:size="840"
@close="emits('close')"
>
<el-form
ref="formRef"
label-suffix=":"
:model="form"
:rules="rules"
label-width="160"
>
<el-button
v-if="isShowAdd"
type="primary"
plain
icon="Plus"
class="w-full mb-8"
@click="add"
>添加
</el-button>
<table-list
:pagination="false"
:column="column"
:empty-temp="false"
:data="form.perIndicator"
>
<template #businessName="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].businessName`"
:rules="[{required:true,message:' '}]"
label-width="0"
style="margin-bottom: 0"
>
<el-input
v-model="form.perIndicator[scope.$index].businessName"
placeholder="请输入"
maxlength="50"
/>
</el-form-item>
</template>
<template #name="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].name`"
:rules="[{required:true,message:' '}]"
label-width="0"
style="margin-bottom: 0"
>
<el-input
v-model="form.perIndicator[scope.$index].name"
placeholder="请输入"
maxlength="50"
/>
</el-form-item>
</template>
<template #nums="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].nums`"
label-width="0"
style="margin-bottom: 0"
>
<el-input-number
v-model="form.perIndicator[scope.$index].nums"
:controls="false"
class="flex-1 mr-8"
placeholder="请输入"
@mousewheel.prevent
/>
</el-form-item>
</template>
<template #unit="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].unit`"
label-width="0"
style="margin-bottom: 0"
>
<el-input
v-model="form.perIndicator[scope.$index].unit"
placeholder="请输入"
maxlength="10"
/>
</el-form-item>
</template>
<template #action="{scope}">
<a class="text-danger cursor-pointer" @click="del(scope.$index)">移除</a>
</template>
</table-list>
</el-form>
<template #footer>
<el-button type="primary" @click="submit(formRef)">提交</el-button>
<el-button @click="emits('close')">取消</el-button>
</template>
</el-dialog>
</template>

+ 581
- 0
src/pages/declareManage/initialInspectionRecord/uploadInitMaterials/index.vue Datei anzeigen

@@ -0,0 +1,581 @@
<script name="uploadInitpreliminaryInspectionMaterials" setup>
import { getCurrentInstance, onMounted, reactive, ref } from 'vue'
import { fileFormatVerification, handleFileSuccess, handleFilePreview, fileTypes } from '@/utils/uploadAction.js'
import store from '@/store'
import { preInsDetail, submitPreIns } from '@/http/apis/declareMange/initialInspectionRecord'
import { useRoute, useRouter } from 'vue-router'
import ActualPerformanceIndicatorsDialog
from '@/pages/declareManage/initialInspectionRecord/uploadInitMaterials/components/actualPerformanceIndicatorsDialog.vue'
import { projectDetail } from '@/http/apis/projectStoreManage/projectStore'
const uploadUrl = store.dictStore.uploadUrl,
route = useRoute(),
{ proxy } = getCurrentInstance(),
router = useRouter()
const collapseModal = ['1', '2', '3', '4', '5', '6', '7'],
formRef = ref(),
formData = ref({
acceptancePersons: [
{
personName: '',
unit: ''
}
],
actualPerformanceIndicators: [],
preliminaryInspectionMaterials: [
{
title: '一、项目前期材料',
data: [
{
name: '信息化项目立项批复文件',
isHave: true,
files: [],
reason: ''
},
{
name: '市政府采购计划表',
isHave: true,
files: [],
reason: ''
},
{
name: '采购需求',
isHave: true,
files: [],
reason: ''
},
{
name: '中标通知书',
isHave: true,
files: [],
reason: ''
},
{
name: '技术(软件、系统等)开发合同(协议)',
isHave: true,
files: [],
reason: ''
},
{
name: '设备采购合同(协议)含采购内容清单、以及合同上规定交付的所有文档',
isHave: true,
files: [],
reason: ''
},
{
name: '第三方监理合同(协议)',
isHave: true,
files: [],
reason: ''
},
{
name: '其他前期资料(含中标单位营业执照、工程相关资质等)',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '二、项目开工资料',
data: [
{
name: '工程开工报告单(工程名称、建设单位、承建单位、施工单位、计划开工和完工日期、工程实施主要内容、建设单位审批意见及盖章日期,承建单位、施工单位盖章日期)',
isHave: true,
files: [],
reason: ''
},
{
name: '软件类系统开发、部署等功能介绍',
isHave: true,
files: [],
reason: ''
},
{
name: '隐蔽工程类设计图、材料选材、施工计划等(可另作图册)',
isHave: true,
files: [],
reason: ''
},
{
name: '购置到位的设备产品证书、开箱证明、序列号等(可另附成册)',
isHave: true,
files: [],
reason: ''
},
{
name: '项目组名单及人员介绍资料',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '三、项目实施过程资料',
data: [
{
name: '设备安装时间、位置一览表等',
isHave: true,
files: [],
reason: ''
},
{
name: '软件类系统开发、部署等完成情况对照表',
isHave: true,
files: [],
reason: ''
},
{
name: '历次多方讨论会议记录表、项目变更单等原始凭证',
isHave: true,
files: [],
reason: ''
},
{
name: '信息安全等级保护测评报告',
isHave: true,
files: [],
reason: ''
},
{
name: '商业密码应用评估报告',
isHave: true,
files: [],
reason: ''
},
{
name: '财务审计报告',
isHave: true,
files: [],
reason: ''
},
{
name: '变更申请单',
isHave: true,
files: [],
reason: ''
},
{
name: '变更批复文件',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '四、项目试运行资料',
data: [
{
name: '试运行报告及整改情况(建设单位)',
isHave: true,
files: [],
reason: ''
},
{
name: '试运行情况业主单位意见(领导签字、单位盖章)',
isHave: true,
files: [],
reason: ''
},
{
name: '历次巡检流程及记录表等原始凭证',
isHave: true,
files: [],
reason: ''
},
{
name: '用户使用报告',
isHave: true,
files: [],
reason: ''
},
{
name: 'IRS应用试运行报告',
isHave: true,
files: [],
reason: ''
}
]
},
{
title: '五、项目完工资料',
data: [
{
name: '工程类竣工报告(建设单位)',
isHave: true,
files: [],
reason: ''
},
{
name: '完工整体运行情况报告',
isHave: true,
files: [],
reason: ''
},
{
name: '监理总结报告',
isHave: true,
files: [],
reason: ''
},
{
name: '第三方项目评测报告(另册)',
isHave: true,
files: [],
reason: ''
},
{
name: '业主单位组织的初验专家意见及名单,整改情况',
isHave: true,
files: [],
reason: ''
},
{
name: '各类系统、场地、设备使用的管理手册、操作手册、维护手册(可另册)',
isHave: true,
files: [],
reason: ''
},
{
name: '售后服务承诺等(建设单位)',
isHave: true,
files: [],
reason: ''
},
{
name: '终验意见',
isHave: true,
files: [],
reason: ''
}
]
}
]
}),
// 增加验收人员
add = () => {
formData.value.acceptancePersons.push({})
},
// 删除验收人员
del = (index) => {
formData.value.acceptancePersons.splice(index, 1)
},
// 材料表格
column = [
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '材料名称',
key: 'name',
prop: 'name'
},
{
label: '是否有材料',
key: 'isHave',
slot: 'isHave',
width: 100
},
{
label: '附件/说明(支持扩展名:.doc .docx .pdf)',
key: 'files',
slot: 'files'
}
],
// 获取详情
getDetail = async () => {
const res = await preInsDetail(route.query.id)
if (res.data) {
formData.value = {
...res.data,
acceptancePersons: res.data.acceptancePersons ? res.data.acceptancePersons : [
{
personName: '',
unit: ''
}
],
actualPerformanceIndicators: res.data.actualPerformanceIndicators && JSON.parse(res.data.actualPerformanceIndicators)?.length ? JSON.parse(res.data.actualPerformanceIndicators) : formData.value.actualPerformanceIndicators,
preliminaryInspectionMaterials: res.data.preliminaryInspectionMaterials && JSON.parse(res.data.preliminaryInspectionMaterials)?.length ? JSON.parse(res.data.preliminaryInspectionMaterials) : formData.value.preliminaryInspectionMaterials
}
}
},
// 提交
submitLoading = ref(false),
submit = async (formEl) => {
if (!formEl) {
return
}
formEl.validate(async (valid, err) => {
if (valid) {
submitLoading.value = true
const postData = {
...formData.value,
actualPerformanceIndicators: formData.value.actualPerformanceIndicators && JSON.stringify(formData.value.actualPerformanceIndicators),
preliminaryInspectionMaterials: JSON.stringify(formData.value.preliminaryInspectionMaterials)
}
try {
await submitPreIns(postData)
submitLoading.value = false
proxy.$message.success('提交成功')
router.go(-1)
} catch (e) {
submitLoading.value = false
}
} else {
console.log(err)
}
})
},
// 实际成效指标
column1 = [
{
label: '核心业务',
prop: 'businessName',
key: 'businessName'
},
{
label: '实际成效指标',
prop: 'name',
key: 'name'
},
{
label: '数值',
prop: 'nums',
key: 'nums'
},
{
label: '单位',
prop: 'unit',
key: 'unit'
},
{
label: '操作',
slot: 'action',
key: 'action'
}
],
projectContentDialogData = reactive({
visible: false,
data: undefined
}),
projectContentIndex = ref(),
showProjectContentDialog = (data, index) => {
projectContentDialogData.data = data
projectContentDialogData.visible = true
projectContentIndex.value = index
},
setContent = (data) => {
if (projectContentIndex.value === undefined) {
formData.value.actualPerformanceIndicators = [...formData.value.actualPerformanceIndicators, ...data]
} else {
formData.value.actualPerformanceIndicators[projectContentIndex.value] = data[0]
}
},
delProjectContent = (index) => {
formData.value.actualPerformanceIndicators.splice(index, 1)
},
getProjectDetail = async () => {
const res = await projectDetail(route.query.id)
if (res.data.projectApplications?.length) {
if (res.data.projectApplications.map(i => i.secrecyGrade).includes(3) || res.data.projectApplications.map(i => i.secrecyGrade).includes(4) || res.data.projectApplications.map(i => i.secrecyGrade).includes(5)) {
formData.value.preliminaryInspectionMaterials = formData.value.preliminaryInspectionMaterials.map(i => {
return {
...i,
data: i.data.map(j => {
return {
...j,
required: j.name === '商业密码应用评估报告' ? true : j.required
}
})
}
})
}
}
}
onMounted(() => {
getDetail()
getProjectDetail()
})
</script>

<template>
<div class="uploadInitpreliminaryInspectionMaterials footerPage">
<el-form
ref="formRef"
:model="formData"
label-position="right"
label-width="90px"
label-suffix=":"
scroll-to-error
class="table-form"
>
<el-collapse v-model="collapseModal">
<el-collapse-item name="1" class="mb-16">
<template #title>
<div class="collapse-title">验收人员信息</div>
</template>
<div class="p-24">
<el-row v-for="(item,index) in formData.acceptancePersons" :key="index" :gutter="40">
<el-col :span="12">
<el-form-item
label="验收人员"
:prop="`acceptancePersons[${index}].personName`"
:rules="[{ required: true, message: '请输入' }]"
>
<el-input v-model="item.personName" placeholder="请填写姓名" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="所在单位"
:prop="`acceptancePersons[${index}].unit`"
:rules="[{ required: true, message: '请输入' }]"
>
<el-input v-model="item.unit" placeholder="请填写单位" maxlength="50" />
</el-form-item>
</el-col>
<a
v-if="formData.acceptancePersons?.length>1"
class="text-danger absolute top-4"
style="right: -12px"
@click="del(index)"
>删除</a>
</el-row>
<el-button
type="primary"
plain
icon="Plus"
size="small"
@click="add"
>增加</el-button>
</div>
</el-collapse-item>
<el-collapse-item name="7" class="mb-16">
<template #title>
<div class="collapse-title">实施信息</div>
</template>
<el-form-item
label="是否完成日志数据归集"
label-width="170"
prop="isCompletedLogCollection"
:rules="[{required:true,message:'请选择'}]"
>
<el-radio-group v-model="formData.isCompletedLogCollection">
<el-radio :label="true">是</el-radio>
<el-radio :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label="实际成效指标"
label-width="170"
prop="actualPerformanceIndicators"
:rules="[{required:true,message:'请选择'}]"
>
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="formData.actualPerformanceIndicators"
:empty-temp="false"
>
<template #action="{scope}">
<a @click="showProjectContentDialog(scope.row,scope.$index)">编辑</a>
<a class="text-danger" @click="delProjectContent(scope.$index)">删除</a>
</template>
</table-list>
<p class="text-right w-full mt-8">
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="()=>showProjectContentDialog()"
>添加</el-button>
</p>
</el-form-item>
</el-collapse-item>
<el-collapse-item
v-for="(item,index) in formData.preliminaryInspectionMaterials"
:key="index"
:name="index+2+''"
class="mb-16"
>
<template #title>
<div class="collapse-title">{{ item.title }}</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="item.data"
:pagination="false"
:empty-temp="false"
>
<template #isHave="{scope}">
<el-switch v-model="scope.row.isHave" :disabled="scope.row.required" />
</template>
<template #files="{scope}">
<template v-if="scope.$index>=0">
<el-form-item
v-if="scope.row.isHave"
:prop="`preliminaryInspectionMaterials[${index}].data[${scope.$index}].files`"
:rules="[{ required: true, message: '请上传' }]"
label-width="0"
style="margin-bottom: 0"
class="uploadFormItem"
>
<el-upload
v-model:file-list="scope.row.files"
class="w-full table-upload"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, scope.row.files)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain size="small">选择文件</el-button>
</el-upload>
</el-form-item>
<el-form-item
v-else
:prop="`preliminaryInspectionMaterials[${index}].data[${scope.$index}].reason`"
:rules="[{ required: true, message: '请输入' }]"
label-width="0"
style="margin-bottom: 0"
>
<el-input v-model="scope.row.reason" placeholder="请填写缺少该材料的原因" maxlength="50" />
</el-form-item>
</template>
</template>
</table-list>
</el-collapse-item>
</el-collapse>
</el-form>
<div class="footer">
<el-button @click="router.go(-1)"> 返回 </el-button>
<el-button type="primary" :loading="submitLoading" @click="submit(formRef)"> 提交 </el-button>
</div>
</div>
<actual-performance-indicators-dialog
:visible="projectContentDialogData.visible"
:data="projectContentDialogData.data"
@set-content="setContent"
@close="projectContentDialogData.visible=false"
/>
</template>
<style lang="less">
.uploadInitpreliminaryInspectionMaterials{
.table-form{
.uploadFormItem{
.el-form-item__error{
position: absolute;
left: 100px;
top:16px;
transform: translateY(-50%);
}
}
}
}
</style>

+ 69
- 0
src/pages/declareManage/operationProjectRecord/detail/components/applicationInfo.vue Datei anzeigen

@@ -0,0 +1,69 @@
<script setup name="basicInfo">
import { onMounted, ref } from 'vue'
import { applicationList } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'
import store from '@/store'

const userInfo = storeToRefs(store.userStore).userInfo,
props = defineProps({
detailData: {
type: Object,
default: () => {}
}
}),
column = [
{
label: '序号',
type: 'index',
width: 60
},
{
label: '关联IRS应用名称',
prop: 'applicationName',
key: 'applicationName'
},
{
label: 'IRS应用编码',
prop: 'applicationCode',
key: 'applicationCode'
},
{
label: '一本账重大应用名称',
prop: 'baseAccountAppName',
key: 'baseAccountAppName'
},
{
label: '"领域大脑"一本账名称',
prop: 'baseBrainName',
key: 'baseBrainName'
}
],
data = ref([]),
appList = ref([])
onMounted(async () => {
const res = await applicationList({ areaCode: userInfo.value.regionCode })
appList.value = res.data
data.value = props?.detailData?.baseProjSysCode?.split(';')?.map((i, k) => {
return {
applicationCode: i,
applicationName: props?.detailData?.baseProjSys?.split(';')[k] || '',
baseAccountAppName: props?.detailData?.baseAccountAppName?.split(';')[k] || '',
baseBrainName: props?.detailData?.baseBrainName?.split(';')[k] || ''
}
}) || []
})
</script>

<template>
<el-descriptions :column="2" border>
<el-descriptions-item label="关联IRS应用名称">
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="data"
:empty-temp="false"
/>
</el-descriptions-item>
</el-descriptions>
</template>

+ 186
- 0
src/pages/declareManage/operationProjectRecord/detail/components/applyInfo.vue Datei anzeigen

@@ -0,0 +1,186 @@
<script setup name="applyInfo">
import { onMounted, ref } from 'vue'
import Accessory from '@/components/accessory/index.vue'

const props = defineProps({
detailData: {
type: Object,
default: () => {}
},
basicInfoData: {
type: Object,
default: () => {}
},
dictionaryList: Array
})
const column = [
{
label: '序号',
type: 'index',
width: 60
},
{
label: '项目名称',
prop: 'baseProjName',
key: 'baseProjName'
},
{
label: '预算年度',
prop: 'baseProjSetYear',
key: 'baseProjSetYear'
}
],
column1 = [
{
label: '项目主要内容',
prop: 'mainContent',
key: 'mainContent'
},
{
label: '业务对象',
prop: 'businessObject',
key: 'businessObject'
}
],
// 立项依据
buildBasisColumn = [
{
label: '序号',
type: 'index',
width: 60
},
{
label: '依据项',
key: 'title',
prop: 'title'
},
{
label: '依据文件名',
slot: 'fileName'
},
{
label: '文件(支持word、pdf格式)',
slot: 'action',
width: 300
}
],
buildBasisTableData = ref([]),
tableListRef = ref()
onMounted(() => {
buildBasisTableData.value = props.detailData?.baseProjBasis?.split(';')?.map((i, index) => {
const file = `[${props.detailData?.baseProjBasisFile.replace(/}];/g, '}],')}]`
return {
title: props.dictionaryList?.filter(k => k.type === 'PROJECT_BASIS')?.find(j => j.value === i)?.label,
fileList: props.detailData?.baseProjBasisFile ? JSON.parse(file)[index] : [],
value: i
}
})
})
</script>

<template>
<el-descriptions :column="2" border>
<el-descriptions-item label="发改编码">
{{ detailData?.baseDevelopCode ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="财政编码">
{{ detailData?.setProjCodeFinan ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目起止时间">
<span v-if="detailData?.baseProjStartTime&&detailData?.baseProjEndTime">{{ detailData?.baseProjStartTime?.split(' ')[0] }} ~ {{ detailData?.baseProjEndTime?.split(' ')[0] }}</span>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="预算年度">
{{ detailData?.baseProjSetYear ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目总投资">
{{ detailData?.baseProjTotalAmount ||'-' }}万元
</el-descriptions-item>
<el-descriptions-item label="申报年度预算">
{{ detailData?.baseProjDeclAmount ||'-' }}万元
</el-descriptions-item>
<el-descriptions-item label="建设层级">
{{ dictionaryList?.filter(i => i.type === 'BUILD_LEVEL').find(i=>i.value===detailData?.baseProjConsClass)?.label ||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="!(basicInfoData?.baseConstructionType?.split(';')?.includes('03')&&!basicInfoData?.baseConstructionType?.split(';')?.includes('01'))" label="贯通层级">
{{ dictionaryList?.filter(i => i.type === 'LINK_UP_LEVEL').find(i=>i.value===detailData?.baseLowestLevel)?.label ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="历年项目名称" :span="2">
<span v-if="detailData.missing">缺失</span>
<table-list
v-else
:pagination="false"
style="width: 100%"
:column="column"
:data="detailData.baseHistorProjs"
:empty-temp="false"
/>
</el-descriptions-item>
<el-descriptions-item label="预算来源" :span="2">
{{ detailData?.baseProjAmountOri?.split(';').map(i=>dictionaryList?.filter(j => j.type === 'BUDGET_SOURCE').find(k=>k.value===i)?.label).join('、') ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="预算来源说明" :span="2">
{{ detailData?.baseBasisAmountOri ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="立项依据" :span="2">
<table-list
ref="tableListRef"
:pagination="false"
style="width: 100%"
:column="buildBasisColumn"
:data="buildBasisTableData"
>
<template #fileName="{scope}">
{{ scope.row.fileList[0].originalFileName }}
</template>
<template #action="{scope}">
<p v-for="(file,fileIndex) in scope.row.fileList" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
</table-list>
</el-descriptions-item>
<el-descriptions-item label="立项依据说明" :span="2">
{{ detailData?.baseBasisEstablish ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目概述" :span="2">
{{ detailData?.baseProjIntro ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目内容与预期成效" :span="2">
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="detailData?.beseExpectedResults&&JSON.parse(detailData?.beseExpectedResults)"
:empty-temp="false"
/>
</el-descriptions-item>
<el-descriptions-item label="项目申报书" :span="2">
<template v-if="detailData?.baseProjApplyFile&&JSON.parse(detailData?.baseProjApplyFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseProjApplyFile&&JSON.parse(detailData?.baseProjApplyFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="basicInfoData?.baseProjType==='01'||basicInfoData?.baseProjType==='02'" label="可行性研究报告" :span="2">
<template v-if="detailData?.baseResearchReportFile&&JSON.parse(detailData?.baseResearchReportFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseResearchReportFile&&JSON.parse(detailData?.baseResearchReportFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="其他附件" :span="2">
<template v-if="detailData?.baseProjOtherFile&&JSON.parse(detailData?.baseProjOtherFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseProjOtherFile&&JSON.parse(detailData?.baseProjOtherFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">
{{ detailData?.baseProjRemark ||'-' }}
</el-descriptions-item>
</el-descriptions>
</template>

+ 72
- 0
src/pages/declareManage/operationProjectRecord/detail/components/basicInfo.vue Datei anzeigen

@@ -0,0 +1,72 @@
<script setup name="basicInfo">
import store from '@/store'

const { projectTypeOptions } = store.dictStore.globalDicts || {}
defineProps({
detailData: {
type: Object,
default: () => {}
},
dictionaryList: Array,
templateTypeListData: Array
})
</script>

<template>
<el-descriptions :column="2" border>
<!-- <el-descriptions-item label="是否涉密项目">-->
<!-- {{ dictionaryList?.filter(i => i.type === 'CLASSIFIED').find(i=>i.value===detailData?.baseProjIsConfidentiality)?.label ||'-' }}-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="项目是否归集省里" span="2">
{{ detailData?.push?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item label="项目名称" span="2">
{{ detailData?.baseProjName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目类型">
{{ detailData?.baseProjType&&projectTypeOptions[detailData?.baseProjType]||'-' }}
</el-descriptions-item>
<el-descriptions-item label="内容类别">
{{ detailData?.baseConstructionType?.split(';').map(i=>dictionaryList?.filter(j => j.type === 'CONTENT_TYPE').find(k=>k.value===i)?.label).join('、') ||'-' }}
</el-descriptions-item>
<!-- <el-descriptions-item label="项目状态">-->
<!-- {{ dictionaryList?.filter(i => i.type === 'PROJECT_STATUS').find(i=>i.value===detailData?.baseProjSetProg)?.label ||'-' }}-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="上级主管单位类型">
{{ detailData?.baseProvManDeprtType===1?'省级':detailData?.baseProvManDeprtType===2?'非省级':'-' }}
</el-descriptions-item>
<el-descriptions-item label="上级主管单位">
{{ detailData?.baseProvManDeprt ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="本级主管单位">
{{ detailData?.baseManDeprt ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="本级主管单位统一社会信用代码">
{{ detailData?.baseManDepartUsci ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="建设单位">
{{ detailData?.baseBuildDeprt ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="建设单位统一信用代码">
{{ detailData?.baseBuildDepartUsci ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目负责人">
{{ detailData?.baseProjPrincipal ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="负责人手机号码">
{{ detailData?.baseProjPrincipalCall ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目联系人">
{{ detailData?.baseProjContacts ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="联系人手机号码">
{{ detailData?.baseProjContactsCall ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="系统定位" :span="2">
{{ detailData?.systemPosition ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="绩效评价类型" :span="2">
{{ templateTypeListData?.find(i=>i.id===detailData?.templateType)?.name||"-" }}
</el-descriptions-item>
</el-descriptions>
</template>

+ 59
- 0
src/pages/declareManage/operationProjectRecord/detail/components/coreBusiness.vue Datei anzeigen

@@ -0,0 +1,59 @@
<script setup name="coreBusiness">
import { onMounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import store from '@/store'

const userInfo = storeToRefs(store.userStore).userInfo,
props = defineProps({
detailData: {
type: Object,
default: () => {}
}
}),
column = [
{
label: '序号',
type: 'index',
width: 60
},
// {
// label: '业务编号',
// key: 'oid',
// prop: 'oid'
// },
{
label: '业务名称',
key: 'matterName',
prop: 'matterName'
},
{
label: '所属单位',
key: 'orgName',
prop: 'orgName'
}
],
data = ref([])
onMounted(async () => {
data.value = props?.detailData?.baseCoreBusinessCode?.split(';')?.map((i, k) => {
return {
oid: i,
matterName: props?.detailData?.baseCoreBusiness?.split(';')[k],
orgName: userInfo.value.empPosUnitName
}
}) || []
})
</script>

<template>
<el-descriptions :column="2" border>
<el-descriptions-item label="核心业务">
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="data"
:empty-temp="false"
/>
</el-descriptions-item>
</el-descriptions>
</template>

+ 139
- 0
src/pages/declareManage/operationProjectRecord/detail/components/empMaterials.vue Datei anzeigen

@@ -0,0 +1,139 @@
<script setup name="empMaterials">
import Accessory from '@/components/accessory/index.vue'

defineProps({
detailData: {
type: Object,
default: () => {}
},
basicInfoData: {
type: Object
},
approvalInfoData: {
type: Object
},
baseProjSetYear: {
type: String,
default: ''
}
})
const column1 = [
{
label: '核心业务',
prop: 'businessName',
key: 'businessName'
},
{
label: '实际成效指标',
prop: 'name',
key: 'name'
},
{
label: '数值',
prop: 'nums',
key: 'nums'
},
{
label: '单位',
prop: 'unit',
key: 'unit'
}
]
</script>

<template>
<el-descriptions :column="2" border>
<el-descriptions-item label="是否完成日志数据归集" :span="2">
{{ detailData.baseLogAggregation==='1'?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item label="实际成效指标" :span="2">
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="detailData.baseBusinessMetrics&&JSON.parse(detailData.baseBusinessMetrics)||[]"
:empty-temp="false"
/>
</el-descriptions-item>
<el-descriptions-item v-if="(['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)&&basicInfoData?.baseConstructionType?.includes('01'))||!basicInfoData?.baseConstructionType?.includes('01')" label="信息安全等级保护测评报告" :span="2">
<template v-if="detailData?.baseInforLevelFile&&JSON.parse(detailData?.baseInforLevelFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseInforLevelFile&&JSON.parse(detailData?.baseInforLevelFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" label="商业密码应用评估报告" :span="2">
<template v-if="detailData?.basePasswAssessFile&&JSON.parse(detailData?.basePasswAssessFile)?.length">
<p v-for="(file,fileIndex) in detailData?.basePasswAssessFile&&JSON.parse(detailData?.basePasswAssessFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="第三方验收测试报告" :span="2">
<template v-if="detailData?.baseThirdAcceptFile&&JSON.parse(detailData?.baseThirdAcceptFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseThirdAcceptFile&&JSON.parse(detailData?.baseThirdAcceptFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="!['01','02','03','04'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" label="用户使用报告" :span="2">
<template v-if="detailData?.baseUserConsFile&&JSON.parse(detailData?.baseUserConsFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseUserConsFile&&JSON.parse(detailData?.baseUserConsFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="监理总结报告" :span="2">
<template v-if="detailData?.baseEstaSummFile&&JSON.parse(detailData?.baseEstaSummFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseEstaSummFile&&JSON.parse(detailData?.baseEstaSummFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="!['01','02','03','04'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" label="运维总结报告" :span="2">
<template v-if="detailData?.baseOperatMaintenSummFile&&JSON.parse(detailData?.baseOperatMaintenSummFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseOperatMaintenSummFile&&JSON.parse(detailData?.baseOperatMaintenSummFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="basicInfoData?.baseProjSetProg==='07'" label="终验意见" :span="2">
<template v-if="detailData?.baseFinalExpertOpinionFile&&JSON.parse(detailData?.baseFinalExpertOpinionFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseFinalExpertOpinionFile&&JSON.parse(detailData?.baseFinalExpertOpinionFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="项目延期申请表" :span="2">
<template v-if="detailData?.baseEngineerPostpoFile&&JSON.parse(detailData?.baseEngineerPostpoFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseEngineerPostpoFile&&JSON.parse(detailData?.baseEngineerPostpoFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="变更报告" :span="2">
<template v-if="detailData?.baseEngineerAlterFile&&JSON.parse(detailData?.baseEngineerAlterFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseEngineerAlterFile&&JSON.parse(detailData?.baseEngineerAlterFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="变更批复文件" :span="2">
<template v-if="detailData?.baseChanFile&&JSON.parse(detailData?.baseChanFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseChanFile&&JSON.parse(detailData?.baseChanFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
</el-descriptions>
</template>

+ 77
- 0
src/pages/declareManage/operationProjectRecord/detail/components/projectApprovalInfo.vue Datei anzeigen

@@ -0,0 +1,77 @@
<script setup name="projectApprovalInfo">
import Accessory from '@/components/accessory/index.vue'

defineProps({
detailData: {
type: Object,
default: () => {}
},
basicInfoData: {
type: Object
},
dictionaryList: Array
})
</script>

<template>
<el-descriptions :column="2" border>
<el-descriptions-item v-if="basicInfoData?.baseProjSetProg!=='01'" label="评审结果">
{{ dictionaryList?.filter(i => i.type === 'REVIEW_RESULTS').find(i=>i.value===detailData?.baseReviewResults)?.label ||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="basicInfoData?.baseProjIsConfidentiality === '01'&&!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" label="等保定级">
{{ dictionaryList?.filter(i => i.type === 'EQUAL_PROTECTION_RATING').find(i=>i.value===detailData?.equalProtectionLevel)?.label ||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="basicInfoData?.baseProjSetProg!=='01'" label="评审意见" :span="2">
{{ detailData?.baseReviewOpinion||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="basicInfoData?.baseProjSetProg!=='01'" label="评审意见附件" :span="2">
<template v-if="detailData?.baseReviewCommentsFile&&JSON.parse(detailData?.baseReviewCommentsFile)?.length">
<p v-for="(file,fileIndex) in detailData?.baseReviewCommentsFile&&JSON.parse(detailData?.baseReviewCommentsFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" label="立项批复文件" :span="2">
<template v-if="detailData?.approvalFile&&JSON.parse(detailData?.approvalFile)?.length">
<p v-for="(file,fileIndex) in detailData?.approvalFile&&JSON.parse(detailData?.approvalFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item v-if="!['01','03'].includes(basicInfoData?.baseProjSetProg)" label="建议总投资">
{{ detailData?.baseExpertTotalMoney||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="!['01','03'].includes(basicInfoData?.baseProjSetProg)" label="建议年度预算">
{{ detailData?.baseExpertYearMoney||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" label="建议批复总投资">
{{ detailData?.baseInitialReviewTotalMoney||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" label="建议批复年度预算">
{{ detailData?.baseProjReplyAmount||'-' }}
</el-descriptions-item>
<el-descriptions-item v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)" label="年度预算下达金额">
{{ detailData?.releaseYearMoney||'-' }}
</el-descriptions-item>
<template v-if="detailData?.baseProjReplyAmount>=5000&&['04','05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-descriptions-item label="初步设计方案" :span="2">
<template v-if="detailData?.preliminaryDesignScheme&&JSON.parse(detailData?.preliminaryDesignScheme)?.length">
<p v-for="(file,fileIndex) in detailData?.preliminaryDesignScheme&&JSON.parse(detailData?.preliminaryDesignScheme)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="初步设计方案批复函" :span="2">
<template v-if="detailData?.preliminaryDesignFile&&JSON.parse(detailData?.preliminaryDesignFile)?.length">
<p v-for="(file,fileIndex) in detailData?.preliminaryDesignFile&&JSON.parse(detailData?.preliminaryDesignFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</template>
<span v-else>-</span>
</el-descriptions-item>
</template>
</el-descriptions>
</template>

+ 94
- 0
src/pages/declareManage/operationProjectRecord/detail/components/purchaseInfo.vue Datei anzeigen

@@ -0,0 +1,94 @@
<script setup name="basicInfo">
import Accessory from '@/components/accessory/index.vue'
import NoData from '@/components/noData/index.vue'

defineProps({
detailData: {
type: Array,
default: () => []
},
basicInfoData: {
type: Object
},
baseProjSetYear: {
type: String,
default: ''
},
dictionaryList: {
type: Array,
default: () => []
}
})
</script>

<template>
<template v-if="detailData?.length">
<el-descriptions
v-for="(item,index) in detailData"
:key="index"
:column="2"
border
class="mb-16"
>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-descriptions-item label="标段名称">
{{ item?.baseBidName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="采购方式">
{{ dictionaryList?.filter(i => i.type === 'PURCHASE_METHOD').find(i=>i.value===item?.baseProjPurchaseWay)?.label ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="预算执行确认书编号">
{{ item?.basePurchaseCode ||'-' }}
</el-descriptions-item>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023">
<el-descriptions-item label="采购代理机构">
{{ item?.basePurchasingAgencies ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="采购代理机构统一社会信用代码">
{{ item?.baseUnifiedCreditCode ||'-' }}
</el-descriptions-item>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-descriptions-item label="中标(成交)时间">
{{ item?.baseWinningBidTime ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="中标(成交)金额">
{{ item?.baseProjPurchaseAmount ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="中标(成交)供应商名称">
{{ item?.baseConsDeprt ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="中标(成交)供应商统一社会信用代码">
{{ item?.baseConsDeprtUsci ||'-' }}
</el-descriptions-item>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023">
<el-descriptions-item label="项目款支付时间">
{{ item?.basePaymentTime ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="项目款支付金额">
{{ item?.paymentProgress ||'-' }}万元
</el-descriptions-item>
</template>
<template v-if="['05','06','07','00']?.includes(basicInfoData?.baseProjSetProg)">
<el-descriptions-item label="招标(采购)文件">
<p v-for="(file,fileIndex) in item?.purchaseFile&&JSON.parse(item?.purchaseFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</el-descriptions-item>
<el-descriptions-item label="中标(成交)通知">
<p v-for="(file,fileIndex) in item?.biddingFile&&JSON.parse(item?.biddingFile)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</el-descriptions-item>
<el-descriptions-item label="采购合同">
<p v-for="(file,fileIndex) in item?.purchaseContract&&JSON.parse(item?.purchaseContract)" :key="fileIndex" class="mb-4">
<accessory :file-name="file.originalFileName" :file-id="file.id" />
</p>
</el-descriptions-item>
</template>
</el-descriptions>
</template>
<no-data v-else />
</template>

+ 142
- 0
src/pages/declareManage/operationProjectRecord/detail/index.vue Datei anzeigen

@@ -0,0 +1,142 @@
<script setup name="projectCollectionEnterDetail">
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import BasicInfo from './components/basicInfo.vue'
import { dictionary } from '@/http/apis/projectCollection/projectCollectionEnter'
import { detail } from '@/http/apis/declareMange/operationProjectRecord'
import ApplyInfo from './components/applyInfo.vue'
import ApplicationInfo from './components/applicationInfo.vue'
import CoreBusiness from './components/coreBusiness.vue'
import ProjectApprovalInfo from './components/projectApprovalInfo.vue'
import EmpMaterials from './components/empMaterials.vue'
import PurchaseInfo from './components/purchaseInfo.vue'
import store from '@/store'
import { templateTypeList } from '@/http/apis/performanceEvaluation/indicatorTemplate'
const { statusGjOptions } = store.dictStore.globalDicts || {}
const
tabList = ref(['项目基本信息', '项目申报信息', '项目关联信息', '核心业务', '项目立项评审信息', '项目采购、资金支付信息', '实施材料信息']),
activeName = ref('项目基本信息'),
changeTab = (val) => {
activeName.value = val
},
route = useRoute(),
detailData = ref(),
getDetail = async () => {
const id = route.query.type === '1' ? route.query.id : route.query.draftId
const res = await detail(route.query.type, id)
detailData.value = {
...res.data,
apply: {
...res.data.apply,
baseHistorProjs: res.data.apply?.baseHistorProjId?.split(';').map((i, k) => {
return {
baseProjId: i,
baseProjName: res.data.apply?.baseHistorProjName.split(';')[k],
baseProjSetYear: res.data.apply?.baseHistorProjYear.split(';')[k]
}
}) || []
}
}
if ((detailData.value?.baseinfo?.baseConstructionType?.split(';')?.length === 1 && detailData.value?.baseinfo?.baseConstructionType?.split(';').includes('02'))) {
tabList.value = tabList.value.filter(i => i !== '项目关联信息')
}
if (detailData.value?.baseinfo?.baseProjSetProg === '01') {
tabList.value = tabList.value.filter(i => i !== '项目立项评审信息')
}
},
dictionaryList = ref([]),
templateTypeListData = ref(),
getTemplateTypeList = async () => {
const res = await templateTypeList()
templateTypeListData.value = res.data
}
onMounted(async () => {
getTemplateTypeList()
dictionaryList.value = (await dictionary()).data
getDetail()
})
</script>

<template>
<div class="px-20 pt-10 pb-20 overflow-auto">
<el-card shadow="never" class="mb-16">
<div class="card-header">
<div class="flex justify-between items-center">
<div class="flex-1">
<p class="font-bold">{{ detailData?.baseinfo?.baseProjName }}</p>
<div class="mt-8 search">
<el-form label-suffix=":">
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="建设单位">{{ detailData?.baseinfo?.baseBuildDeprt||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="主管单位">{{ detailData?.baseinfo?.baseManDeprt||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="创建时间">{{ detailData?.baseinfo?.createOn||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="更新时间">{{ detailData?.baseinfo?.updateOn||'-' }}</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
<div class="textRight">
<span :class="`text-${statusGjOptions[detailData?.baseinfo?.baseProjSetProg.slice(-1)]?.color}`">
{{ dictionaryList?.filter(i => i.type === 'PROJECT_STATUS').find(i=>i.value===detailData?.baseinfo?.baseProjSetProg)?.label ||'-' }}
</span>
<p>状态</p>
</div>
</div>
</div>
</el-card>
<el-card shadow="never" class="tab-card">
<template #header>
<el-tabs v-model="activeName" @tab-change="changeTab">
<el-tab-pane
v-for="(item,index) in tabList"
:key="index"
:label="item"
:name="item"
/>
</el-tabs>
</template>
<basic-info
v-if="activeName==='项目基本信息'"
:detail-data="detailData?.baseinfo"
:dictionary-list="dictionaryList"
:template-type-list-data="templateTypeListData"
/>
<apply-info
v-if="activeName==='项目申报信息'"
:detail-data="detailData?.apply"
:dictionary-list="dictionaryList"
:basic-info-data="detailData?.baseinfo"
/>
<application-info v-if="activeName==='项目关联信息'" :detail-data="detailData?.apply" />
<core-business v-if="activeName==='核心业务'" :detail-data="detailData?.apply" />
<project-approval-info
v-if="activeName==='项目立项评审信息'"
:detail-data="detailData?.approve"
:dictionary-list="dictionaryList"
:basic-info-data="detailData?.baseinfo"
/>
<purchase-info
v-if="activeName==='项目采购、资金支付信息'"
:basic-info-data="detailData?.baseinfo"
:base-proj-set-year="detailData?.apply?.baseProjSetYear"
:dictionary-list="dictionaryList"
:detail-data="detailData?.procures"
/>
<emp-materials
v-if="activeName==='实施材料信息'"
:detail-data="detailData?.mimplement"
:basic-info-data="detailData?.baseinfo"
:base-proj-set-year="detailData?.apply?.baseProjSetYear"
:approval-info-data="detailData?.approve"
/>
</el-card>
</div>
</template>

+ 201
- 0
src/pages/declareManage/operationProjectRecord/index.vue Datei anzeigen

@@ -0,0 +1,201 @@
<script setup name="operationProjectRecord">
import { getCurrentInstance, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import ElTree from '@/components/elTree/index.vue'
import { list, del } from '@/http/apis/declareMange/operationProjectRecord'
import { getIsShowRegionTree, getTreeParams } from '@/utils/getIsShowRegionTree'
import { storeToRefs } from 'pinia'
import store from '@/store'

const
userInfo = storeToRefs(store.userStore).userInfo,
{ proxy } = getCurrentInstance(),
router = useRouter(),
searchForm = reactive({
projectName: undefined,
buildOrg: undefined
}),
tableListRef = ref(),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '项目编号',
key: 'baseProjId',
prop: 'baseProjId'
},
{
label: '项目名称',
key: 'baseProjName',
prop: 'baseProjName'
},
{
label: '建设单位',
key: 'baseBuildDeprt',
prop: 'baseBuildDeprt'
},
{
label: '行政区划',
key: 'baseAreaName',
prop: 'baseAreaName'
},
{
label: '申报金额(万元)',
key: 'baseProjDeclAmount',
prop: 'baseProjDeclAmount',
width: '180'
},
{
label: '操作',
slot: 'action',
width: '160',
fixed: 'right'
}
]),
data = ref([]),
areaCode = ref(),
getTree = (value) => {
areaCode.value = value.regionLevel === 3 ? value.regionCode : undefined
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
activeName = ref('1'),
changeTab = (val) => {
activeName.value = val
reset()
},
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list(activeName.value, {
...pageParams,
...searchForm,
regionCode: areaCode.value
})
data.value = res.data.records
total.value = res.data.total
},
search = () => {
getTableData()
},
reset = () => {
searchForm.projectName = undefined
searchForm.buildOrg = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 删除·
deleteItem = (data) => {
proxy.$messageBox
.confirm('确定要删除该项吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await del(activeName.value, activeName.value === '1' ? data.baseProjId : data.draftId)
proxy.$message.success('删除成功!')
await getTableData()
})
}
onMounted(() => {
if (!getIsShowRegionTree(['SUPER_ADMIN', 'REGION_MANAGER'])) {
areaCode.value = userInfo.value.regionCode
getTableData(tableListRef.value.pageParams)
}
})
</script>
<template>
<el-container class="overflow-y-auto">
<div class="px-20 pt-10 pb-20 w-full">
<el-row>
<el-col
v-if="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER'])"
:span="4"
class="pr-16"
>
<elTree :params="getTreeParams({'SUPER_ADMIN':false,'REGION_MANAGER':false})" @get-tree="getTree" />
</el-col>
<el-col :span="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER'])?20:24">
<el-card class="w-full search">
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
>
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目单位">
<el-input
v-model="searchForm.buildOrg"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="search"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8 tab-card">
<template #header>

<div class="flex justify-between items-center">
<el-tabs v-model="activeName" @tab-change="changeTab">
<el-tab-pane label="项目列表" name="1" />
<el-tab-pane label="草稿箱" name="2" />
</el-tabs>
<div>
<el-button
type="primary"
size="small"
icon="Plus"
@click="router.push({ name: 'operationProjectEdit'})"
>录入项目</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="$router.push({name:'operationProjectRecordDetail', query: { id: scope.row.baseProjId,draftId: scope.row.draftId,type:activeName }})">查看</a>
<a @click="$router.push({ name: 'operationProjectEdit', query: { id: scope.row.baseProjId, draftId: scope.row.draftId, type: activeName }})">编辑</a>
<a class="text-danger" @click="deleteItem(scope.row)">删除</a>
</template>
</table-list>
</el-card>
</el-col>
</el-row>
</div>
</el-container>
</template>
<style lang='less' scoped>
</style>

+ 261
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/applicationInfo.vue Datei anzeigen

@@ -0,0 +1,261 @@
<script name="projectCollectionEnterBasicInfo" setup>
import { onMounted, ref, watch } from 'vue'
import { applicationList } from '@/http/apis/declareMange'
import store from '@/store'
import { storeToRefs } from 'pinia'
import { useRoute } from 'vue-router'

const userInfo = storeToRefs(store.userStore).userInfo,
route = useRoute(),
props = defineProps({
detail: {
type: Object
},
basicInfoData: {
type: Object
}
}),
{
accountAppNameOption,
domainBrainAccountOptions
} = store.dictStore.globalDicts || {},
formRef = ref(),
currentRules = ref(),
formData = ref({
applications: []
}),
column = [
{
label: '序号',
type: 'index',
width: 60
},
{
label: '关联IRS应用名称',
slot: 'application',
key: 'application'
},
{
label: 'IRS应用编码',
slot: 'applicationCode',
key: 'applicationCode'
},
{
label: '一本账重大应用名称',
slot: 'baseAccountAppName',
key: 'baseAccountAppName'
},
{
label: '"领域大脑"一本账名称',
slot: 'baseBrainName',
key: 'baseBrainName'
},
{
label: '操作',
slot: 'action',
key: 'action'
}
],
add = () => {
formData.value.applications.push({
application: undefined
})
},
del = (index) => {
formData.value.applications.splice(index, 1)
},
appList = ref([])
defineExpose({ formRef, formData })
watch(() => props.basicInfoData, val => {
if (val?.baseProjIsConfidentiality === '02' || val?.baseProjSetProg === '00') {
currentRules.value = {}
} else {
currentRules.value = {
applications: [{ required: true, message: '请至少关联一个应用' }]
}
}
formRef.value?.clearValidate()
}, { deep: true, immediate: true })
onMounted(async () => {
if (!route.query.id) {
const res = await applicationList({ areaCode: userInfo.value.regionCode })
appList.value = res.data
}
})
watch(() => props.detail, async val => {
if (val) {
const res = await applicationList({ areaCode: userInfo.value.regionCode })
appList.value = res.data
formData.value = {
applications: val.apply.baseProjSysCode?.split(';')?.map((i, k) => {
return {
application: appList.value?.find(j => j.applicationCode === i) || { applicationCode: i, applicationName: val.apply?.baseProjSys?.split(';')[k] || '' },
baseAccountAppName: val.apply?.baseAccountAppName?.split(';')[k] || '',
baseBrainName: val.apply?.baseBrainName?.split(';')[k] || ''
}
}) || []
}
}
})

</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="currentRules"
label-position="top"
label-suffix=":"
scroll-to-error
:validate-on-rule-change="false"
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item
v-if="basicInfoData?.baseConstructionType?.includes('01')&&!(basicInfoData?.baseProjType==='01'&&(basicInfoData?.baseProjSetProg==='01'||basicInfoData?.baseProjSetProg==='02'))"
key="applications1"
label="关联IRS应用名称"
prop="applications"
>
<p class="text-right w-full mb-8">
<el-button type="primary" @click="add">添加关联应用</el-button>
</p>
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="formData.applications"
:empty-temp="false"
>
<template #application="{scope}">
<el-form-item v-if="scope.$index>=0" :prop="`applications[${scope.$index}].application`" :rules="[{required:true,message:' '}]">
<el-select
v-model="formData.applications[scope.$index].application"
class="w-full"
placeholder="请选择"
value-key="applicationCode"
filterable
>
<el-option
v-for="(item, index) in appList"
:key="index"
:label="item.applicationName"
:value="item"
/>
</el-select>
</el-form-item>
</template>
<template #applicationCode="{scope}">
<el-form-item>
<el-input disabled :model-value="scope.row.application?.applicationCode" />
</el-form-item>
</template>
<template #baseAccountAppName="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`applications[${scope.$index}].baseAccountAppName`"
>
<el-select v-model="scope.row.baseAccountAppName">
<el-option
v-for="(item,index) in accountAppNameOption"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</template>
<template #baseBrainName="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`applications[${scope.$index}].baseBrainName`"
>
<el-select v-model="scope.row.baseBrainName">
<el-option
v-for="(item,index) in domainBrainAccountOptions"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</template>
<template #action="{scope}">
<a class="text-danger" @click="del(scope.$index)">删除</a>
</template>
</table-list>
</el-form-item>
<el-form-item v-else key="applications2" label="关联IRS应用名称">
<p class="text-right w-full mb-8">
<el-button type="primary" @click="add">添加关联应用</el-button>
</p>
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="formData.applications"
:empty-temp="false"
>
<template #application="{scope}">
<el-form-item v-if="scope.$index>=0" :prop="`applications[${scope.$index}].application`" :rules="[{required:true,message:' '}]">
<el-select
v-model="formData.applications[scope.$index].application"
class="w-full"
placeholder="请选择"
value-key="applicationCode"
filterable
>
<el-option
v-for="(item, index) in appList"
:key="index"
:label="item.applicationName"
:value="item"
/>
</el-select>
</el-form-item>
</template>
<template #applicationCode="{scope}">
<el-form-item>
<el-input disabled :model-value="scope.row.application?.applicationCode" />
</el-form-item>
</template>
<template #baseAccountAppName="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`applications[${scope.$index}].baseAccountAppName`"
>
<el-select v-model="scope.row.baseAccountAppName">
<el-option
v-for="(item,index) in accountAppNameOption"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</template>
<template #baseBrainName="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`applications[${scope.$index}].baseBrainName`"
>
<el-select v-model="scope.row.baseBrainName">
<el-option
v-for="(item,index) in domainBrainAccountOptions"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</template>
<template #action="{scope}">
<a class="text-danger" @click="del(scope.$index)">删除</a>
</template>
</table-list>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

+ 425
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/basicInfo.vue Datei anzeigen

@@ -0,0 +1,425 @@
<script name="projectCollectionEnterBasicInfo" setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { districtList, getOrganizationByCode } from '@/http/apis/commonApi'
import OrgTree from '@/components/orgTree/index.vue'
import UserDialog from '@/pages/projectCollection/projectCollectionEnter/components/userDialog.vue'
import { storeToRefs } from 'pinia'
import store from '@/store'
import LineOrgDialog from '@/pages/projectCollection/projectCollectionEnter/components/lineOrgDialog.vue'
import { templateTypePage } from '@/http/apis/performanceEvaluation/indicatorTemplate'
const { projectOpeOptions } =
store.dictStore.globalDicts || {}
const props = defineProps({
detail: {
type: Object
},
dictionaryList: {
type: Array,
default: () => []
}
}),
userInfo = storeToRefs(store.userStore).userInfo || {},
formRef = ref(),
formData = ref({
baseProjIsConfidentiality: '01',
// baseProjSetProg: '07',
push: true
// baseProjType: '04'
}),
userValidator = (rule, value, callback) => {
if (!value) callback()
if (formData.value.baseProjPrincipal === formData.value.baseProjContacts && formData.value.baseProjPrincipalCall === formData.value.baseProjContactsCall) {
callback('项目负责人与项目联系人不能相同')
} else {
callback()
}
},
currentRules = computed(() => {
if (formData.value.baseProjIsConfidentiality === '02') {
return {
baseProjIsConfidentiality: [{ required: true, message: '请选择是否涉密项目' }],
baseProjName: [{ required: true, message: '请填写项目名称', trigger: 'blur' }]
}
} else {
return {
push: [{ required: true, message: '请选择是否归集省里', type: Boolean }],
baseProjIsConfidentiality: [{ required: true, message: '请选择是否涉密项目' }],
baseProjName: [{ required: true, message: '请填写项目名称' }],
baseProjType: [{ required: true, message: '请选择项目类型' }],
baseArea: [{ required: true, message: '请选择所属区划' }],
baseConstructionType: [{ required: true, message: '请选择内容类别' }],
baseProjSetProg: [{ required: true, message: '请选择项目状态' }],
baseProvManDeprtType: [{ required: true, message: '请选择上级主管单位类型' }],
baseProvManDeprt: [{ required: true, message: '请选择上级主管单位' }],
baseManDeprt: [{ required: true, message: '请选择本级主管单位' }],
baseManDepartUsci: [{ required: true, message: '请填写本级主管单位统一社会信用代码' }],
baseBuildDeprt: [{ required: true, message: '请填写建设单位' }],
baseBuildDepartUsci: [{ required: true, message: '请填写建设单位统一信用代码' }],
baseProjPrincipal: [{ required: true, message: '请选择项目负责人' }, { validator: userValidator }],
baseProjPrincipalCall: [{ required: true, message: '请选择项目负责人' }],
baseProjContacts: [{ required: true, message: '请选择项目联系人' }, { validator: userValidator }],
baseProjContactsCall: [{ required: true, message: '请选择联系人手机号码' }],
systemPosition: [{ required: true, message: '请填写系统定位' }],
templateType: [{ required: true, message: '请选择绩效评价类型' }]
}
}
}),
isDisabledCreditCode = ref({}),
getCode = async (name, code) => {
const res = await getOrganizationByCode(code || userInfo.value.empPosUnitCode)
isDisabledCreditCode.value[name] = !!res.data.unifiedSocialCreditCode
formData.value[name] = res.data.unifiedSocialCreditCode || formData.value[name]
},
regionTree = ref([]),
// 单位选择
orgProps = reactive({
field: undefined,
unitVisible: false,
data: undefined,
title: undefined,
type: undefined,
params: undefined
}),
showOrgTree = (fieldName) => {
orgProps.fieldName = fieldName
orgProps.unitVisible = true
orgProps.title = '选择单位'
orgProps.type = 'UNIT'
orgProps.showCheckbox = true
orgProps.defaultProps = {
children: 'children',
label: 'title',
value: 'key',
isLeaf: 'isLeaf'
}
orgProps.params = {
onlyUnit: true
}
orgProps.data = formData.value[`${fieldName}Ding`] ? [{
key: formData.value[`${fieldName}Ding`],
title: formData.value[fieldName]
}] : []
console.log(orgProps.data)
},
closeOrg = () => {
orgProps.unitVisible = false
},
getOrgData = (data) => {
formData.value[orgProps.fieldName + 'Ding'] = data?.[0].key || undefined
formData.value[orgProps.fieldName] = data?.[0].title || undefined
if (orgProps.fieldName === 'baseManDeprt' || orgProps.fieldName === 'baseBuildDeprt') { getCode(orgProps.fieldName === 'baseManDeprt' ? 'baseManDepartUsci' : 'baseBuildDepartUsci', formData.value[orgProps.fieldName + 'Ding']) }
},
// 选择负责人、联系人
userDialogData = reactive({
visible: false,
params: {}
}),
filedName = ref(),
filedPhone = ref(),
showUserDialog = (name, phone) => {
userDialogData.visible = true
filedName.value = name
filedPhone.value = phone
},
getUserData = (data) => {
formData.value[filedName.value] = data.name
formData.value[filedPhone.value] = data.phoneNo
},
// 上级主管单位类型
changeBaseProvManDeprtType = (val, data) => {
formData.value.baseProvManDeprtDing = ''
formData.value.baseProvManDeprt = ''
},
lineOrgDialogData = reactive({
visible: false,
data: undefined
}),
showLineDialog = () => {
lineOrgDialogData.visible = true
lineOrgDialogData.data = {
businessStripCode: formData.value.baseProvManDeprtDing
}
},
getBaseProvManDeprt = (data) => {
formData.value.baseProvManDeprtDing = data.businessStripCode
formData.value.baseProvManDeprt = data.businessStripName
lineOrgDialogData.visible = false
},
emits = defineEmits(['getBasicInfoData']),
templateTypeListData = ref(),
getTemplateTypeList = async () => {
const res = await templateTypePage({
pageNumber: 1,
pageSize: 10000
})
templateTypeListData.value = res?.data?.records || []
}
defineExpose({ formRef, formData })
onMounted(async () => {
getTemplateTypeList()
const res = await districtList({ regionCode: 330500, regionLevel: 2 })
regionTree.value = res.data
})
watch(() => props.detail, val => {
if (val) {
formData.value = {
...val.baseinfo,
baseProjIsConfidentiality: '01',
// baseProjSetProg: '07',
baseProvManDeprtType: val.baseinfo?.baseProvManDeprtType + '' || '',
baseConstructionType: val.baseinfo?.baseConstructionType?.split(';') || []
}
}
})
watch(() => formData.value.baseProjIsConfidentiality, val => {
formRef.value.clearValidate()
})
watch(() => formData.value, val => {
emits('getBasicInfoData', formData.value)
}, { deep: true })

</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="currentRules"
label-position="top"
label-suffix=":"
scroll-to-error
:validate-on-rule-change="false"
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item prop="push" label="项目是否归集省里" class="flex-form-item">
<el-switch v-model="formData['push']" class="mr-8" />
<el-tooltip
class="box-item"
content="选择是的情况下,会将项目信息推送至省里进行归集;选择否的情况下,不会将项目信息推至省里。"
placement="top"
>
<div class="flex items-center">
<el-icon class="cursor-pointer"><QuestionFilled /></el-icon>
</div>
</el-tooltip>
</el-form-item>
</el-col>
<el-col v-if="false" :span="8">
<el-form-item label="是否涉密项目" prop="baseProjIsConfidentiality">
<el-select
v-model="formData.baseProjIsConfidentiality"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'CLASSIFIED')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目名称" prop="baseProjName">
<el-input v-model="formData.baseProjName" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型" prop="baseProjType">
<el-select
v-model="formData.baseProjType"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(v,k) in projectOpeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="false" :span="8">
<el-form-item label="所属区划" prop="baseArea">
<el-select v-model="formData.baseArea" value-key="baseAreaCode" class="w-full">
<el-option
v-for="(item,index) in regionTree?.children"
:key="index"
:label="item.name==='市本级'?'丽水市':item.name"
:value="{baseAreaCode:item.regionCode,baseAreaName:item.name==='市本级'?'丽水市':item.name}"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="内容类别" prop="baseConstructionType">
<el-checkbox-group v-model="formData.baseConstructionType">
<el-checkbox v-for="(item,index) in dictionaryList?.filter(i => i.type === 'CONTENT_TYPE')" :key="index" :label="item.value">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目状态" prop="baseProjSetProg">
<el-select
v-model="formData.baseProjSetProg"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'PROJECT_STATUS')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="上级主管单位类型" prop="baseProvManDeprtType">
<el-radio-group v-model="formData.baseProvManDeprtType" @change="changeBaseProvManDeprtType">
<el-radio label="1">省级</el-radio>
<el-radio label="2">非省级</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="上级主管单位" prop="baseProvManDeprt">
<el-input
v-if="formData.baseProvManDeprtType==='2'"
v-model="formData.baseProvManDeprt"
placeholder="请选择"
readonly
@click="showOrgTree('baseProvManDeprt')"
/>
<el-input
v-else
v-model="formData.baseProvManDeprt"
placeholder="请选择"
readonly
@click="showLineDialog"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="本级主管单位" prop="baseManDeprt">
<el-input
v-model="formData.baseManDeprt"
placeholder="请选择"
readonly
@click="showOrgTree('baseManDeprt',)"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="本级主管单位统一社会信用代码" prop="baseManDepartUsci">
<el-input v-model="formData.baseManDepartUsci" placeholder="请填写" :disabled="isDisabledCreditCode['baseManDepartUsci']" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="建设单位" prop="baseBuildDeprt">
<el-input
v-model="formData.baseBuildDeprt"
placeholder="请选择"
readonly
@click="showOrgTree('baseBuildDeprt',)"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="建设单位统一信用代码" prop="baseBuildDepartUsci">
<el-input v-model="formData.baseBuildDepartUsci" placeholder="请填写" :disabled="isDisabledCreditCode['baseBuildDepartUsci']" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目负责人" prop="baseProjPrincipal">
<el-input
v-model="formData.baseProjPrincipal"
readonly
placeholder="请选择,温馨提示:项目负责人请填写领导信息"
@click="showUserDialog('baseProjPrincipal','baseProjPrincipalCall')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="负责人手机号码" prop="baseProjPrincipalCall">
<el-input
v-model="formData.baseProjPrincipalCall"
readonly
placeholder="请选择"
@click="showUserDialog('baseProjPrincipal','baseProjPrincipalCall')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目联系人" prop="baseProjContacts">
<el-input
v-model="formData.baseProjContacts"
readonly
placeholder="请选择"
@click="showUserDialog('baseProjContacts','baseProjContactsCall')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系人手机号码" prop="baseProjContactsCall">
<el-input
v-model="formData.baseProjContactsCall"
readonly
placeholder="请选择"
@click="showUserDialog('baseProjContacts','baseProjContactsCall')"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="系统定位" prop="systemPosition">
<el-input
v-model="formData.systemPosition"
type="textarea"
show-word-limit
placeholder="请填写"
:maxlength="2000"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="绩效评价类型" prop="templateType">
<el-radio-group v-model="formData.templateType">
<el-radio
v-for="(v,k) in templateTypeListData"
:key="k"
:label="v.id"
>
{{ v.name }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<org-tree
:visible="orgProps.unitVisible"
:show-checkbox="false"
:default-data="orgProps.data"
:title="orgProps.title"
:type="orgProps.type"
:default-props="orgProps.defaultProps"
:params="orgProps.params"
@close="closeOrg"
@get-select-unit="getOrgData"
/>
<user-dialog
:visible="userDialogData.visible"
:params="userDialogData.params"
@close="userDialogData.visible=false"
@get-user-data="getUserData"
/>
<line-org-dialog
:visible="lineOrgDialogData.visible"
:data="lineOrgDialogData.data"
@close="lineOrgDialogData.visible=false"
@get-base-prov-man-deprt="getBaseProvManDeprt"
/>
</template>

+ 110
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/budgetInfo.vue Datei anzeigen

@@ -0,0 +1,110 @@
<script name="projectCollectionEnterBudgetInfo" setup>
import { ref, watch } from 'vue'
import store from '@/store'

const { budgetSourceOptions } = store.dictStore.globalDicts || {}
const props = defineProps({
detail: {
type: Object
}
}),
formRef = ref(),
moneyValidator = (rule, value, callback) => { // 金额校验
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
} else {
callback()
}
},
formData = ref({}),
rules = {
declareAmount: [{ required: true, message: '请填写申报金额', trigger: 'blur' }, { validator: moneyValidator, trigger: 'blur' }],
approvalAmount: [{ required: true, message: '请填写批复金额', trigger: 'blur' }, { validator: moneyValidator, trigger: 'blur' }],
budgetSource: [{ required: true, message: '请选择预算来源', trigger: 'change' }],
projectYear: [{ required: true, message: '请选择预算年度', trigger: 'blur' }]
}
defineExpose({ formRef, formData })
watch(() => props.detail, val => {
if (val) {
formData.value = {
declareAmount: val.declareAmount,
approvalAmount: val.approvalAmount,
budgetSource: val.budgetSource,
projectYear: `${val.projectYear}`
}
}
})
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="top"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="6">
<el-form-item label="申报金额" prop="declareAmount">
<el-input-number
v-model="formData.declareAmount"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="批复金额" prop="approvalAmount">
<el-input-number
v-model="formData.approvalAmount"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预算来源" prop="budgetSource">
<el-select
v-model="formData.budgetSource"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(v,k) in budgetSourceOptions"
:key="k"
:label="v"
:value="k*1"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预算年度" prop="projectYear">
<el-date-picker
v-model="formData.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>

</template>

+ 193
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/coreBusiness.vue Datei anzeigen

@@ -0,0 +1,193 @@
<script name="coreBusiness" setup>
import { reactive, ref, nextTick, watch } from 'vue'
import { getCoreBusinessData } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'
import store from '@/store'
const props = defineProps({
detail: {
type: Object
},
basicInfoData: {
type: Object
}
}),
userInfo = storeToRefs(store.userStore).userInfo || {},
formData = ref({}),
formRef = ref(),
rules = {
coreBusiness: [{ required: false, message: '请至少选择一个核心业务' }]
},
// 选择核心业务
selectCoreBusiness = () => {
coreBusinessvisible.value = true
getCoreBusinessTableData({ pageNumber: 1, pageSize: 10 }, true)
},
column = [
{
type: 'index',
label: '序号',
width: 60
},
// {
// label: '业务编号',
// key: 'oid',
// prop: 'oid'
// },
{
label: '业务名称',
key: 'matterName',
prop: 'matterName'
},
{
label: '所属单位',
key: 'orgName',
prop: 'orgName'
}
],
tableListRef = ref(),
coreBusinessData = ref([]),
coreBusinesstotal = ref(0),
column2 = [
{
type: 'selection'
},
// {
// label: '业务编号',
// prop: 'oid',
// key: 'oid'
// },
{
label: '业务名称',
prop: 'matterName',
key: 'matterName'
},
{
label: '所属单位',
prop: 'orgName',
key: 'orgName'
}
],
coreBusinessvisible = ref(false),
getCoreBusinessTableData = async (pageParams = tableListRef.value?.pageParams, flag) => {
var orgCode = []
props?.basicInfoData?.baseManDeprtDing && orgCode.push(props.basicInfoData.baseManDeprtDing)
props?.basicInfoData?.baseBuildDeprtDing && orgCode.push(props.basicInfoData.baseBuildDeprtDing)
const res = await getCoreBusinessData({
...pageParams,
businessName: coreBusinessParams.businessName,
orgCode: orgCode.join(',')
})
coreBusinessData.value = res.data.data
coreBusinesstotal.value = res.data.total
await nextTick()
if (flag) {
coreBusinessData.value && coreBusinessData.value.forEach(item => {
const dataIds = formData.value.coreBusiness && formData.value.coreBusiness.map(i => i.id * 1) || []
if (dataIds.includes(item.id)) {
tableListRef.value.toggleRowSelect(item, true)
} else {
tableListRef.value.toggleRowSelect(item, false)
}
})
}
},
searchCoreBussiness = () => {
getCoreBusinessTableData()
},
coreBusinessTempotary = ref(),
selectionCoreBusinessChange = (data) => {
coreBusinessTempotary.value = data
},
coreBusinessParams = reactive({
businessName: undefined
}),
handleReset = () => {
coreBusinessParams.businessName = ''
},
confirmCoreBusiness = () => {
formData.value.coreBusiness = coreBusinessTempotary.value
coreBusinessvisible.value = false
}
defineExpose({ formRef, formData })
watch(() => props.detail, val => {
if (val) {
formData.value = {
coreBusiness: val.apply?.baseCoreBusinessCode?.split(';')?.map((i, k) => {
return {
id: i,
matterName: val.apply?.baseCoreBusiness?.split(';')[k],
orgName: userInfo.value.empPosUnitName
}
}) || []
}
}
})
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="0"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="24" class="mb-16">
<el-button type="primary" class="float-right" @click="selectCoreBusiness">
选择核心业务
</el-button>
</el-col>
<el-col :span="24">
<el-form-item>
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="formData.coreBusiness"
:empty-temp="false"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-dialog
title="选择核心业务"
:close-on-click-modal="false"
:before-close="()=>coreBusinessvisible=false"
:model-value="coreBusinessvisible"
width="700px"
>
<el-row style="margin-bottom: 16px" :gutter="20">
<el-col :span="12">
<el-input v-model="coreBusinessParams.businessName" placeholder="请输入" />
</el-col>
<el-col :span="12">
<div class="flex">
<el-button type="primary" @click="searchCoreBussiness">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</div>
</el-col>
</el-row>
<table-list
ref="tableListRef"
:column="column2"
:data="coreBusinessData"
:total="coreBusinesstotal"
@selection-change="selectionCoreBusinessChange"
@get-table-data="getCoreBusinessTableData"
/>
<template #footer>
<el-button type="primary" @click="confirmCoreBusiness"> 提交 </el-button>
<el-button @click="coreBusinessvisible = false"> 关闭 </el-button>
</template>
</el-dialog>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 559
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/empMaterials.vue Datei anzeigen

@@ -0,0 +1,559 @@
<script name="empMaterials" setup>
import { reactive, ref, watch } from 'vue'
import { fileFormatVerification, handleFileError, handleFileSuccess, handleFilePreview, reviewFileParam, fileTypes, fileDesc } from '@/utils/uploadAction'
import store from '@/store'
import ActualPerformanceIndicatorsDialog
from '@/pages/declareManage/initialInspectionRecord/uploadInitMaterials/components/actualPerformanceIndicatorsDialog.vue'

const props = defineProps({
detail: {
type: Object
},
data: {
type: Object
},
basicInfoData: {
type: Object
},
approvalInfoData: {
type: Object
},
baseProjSetYear: {
type: String,
default: ''
}
}),
uploadUrl = store.dictStore.uploadUrl,
formRef = ref(),
formData = ref({
feasibilityStudyReport: [],
approvedFile: [],
purchaseFile: [],
acceptanceLetter: [],
purchaseContract: [],
acceptanceReport: [],
changeApprovalDoc: [],
baseBusinessMetrics: []
}),
fileRule = [{ required: true, message: '请选择文件' }],
currentRules = ref({
baseInitialOpinionFile: fileRule,
baseInforLevelFile: fileRule,
basePasswAssessFile: fileRule,
baseThirdAcceptFile: fileRule,
baseCheckFile: fileRule,
baseFinanlAuditFile: fileRule,
baseUserConsFile: fileRule,
baseEstaSummFile: fileRule,
baseOperatMaintenSummFile: fileRule,
baseFinalExpertOpinionFile: fileRule,
baseEngineerPostpoFile: fileRule,
baseEngineerAlterFile: fileRule,
baseChanFile: fileRule,
baseBusinessMetrics: [{ required: true, message: '请添加' }],
baseLogAggregation: [{ required: true, message: '请选择' }]
}),
// 实际成效指标
column1 = [
{
label: '核心业务',
prop: 'businessName',
key: 'businessName'
},
{
label: '实际成效指标',
prop: 'name',
key: 'name'
},
{
label: '数值',
prop: 'nums',
key: 'nums'
},
{
label: '单位',
prop: 'unit',
key: 'unit'
},
{
label: '操作',
slot: 'action',
key: 'action'
}
],
projectContentDialogData = reactive({
visible: false,
data: undefined
}),
projectContentIndex = ref(),
showProjectContentDialog = (data, index) => {
projectContentDialogData.data = data
projectContentDialogData.visible = true
projectContentIndex.value = index
},
setContent = (data) => {
if (projectContentIndex.value === undefined) {
formData.value.baseBusinessMetrics = [...formData.value.baseBusinessMetrics, ...data]
} else {
formData.value.baseBusinessMetrics[projectContentIndex.value] = data[0]
}
},
delProjectContent = (index) => {
formData.value.baseBusinessMetrics.splice(index, 1)
}

defineExpose({ formRef, formData })
watch(() => props.basicInfoData, val => {
if (val.baseProjIsConfidentiality === '02' || val?.baseProjSetProg === '00') {
currentRules.value = {}
} else {
currentRules.value = {
baseInitialOpinionFile: fileRule,
baseInforLevelFile: fileRule,
basePasswAssessFile: fileRule,
baseThirdAcceptFile: fileRule,
baseCheckFile: fileRule,
baseFinanlAuditFile: fileRule,
baseUserConsFile: fileRule,
baseEstaSummFile: fileRule,
baseOperatMaintenSummFile: fileRule,
baseFinalExpertOpinionFile: fileRule,
baseEngineerPostpoFile: fileRule,
baseEngineerAlterFile: fileRule,
baseChanFile: fileRule,
baseBusinessMetrics: [{ required: true, message: '请添加' }],
baseLogAggregation: [{ required: true, message: '请选择' }]
}
}
formRef.value.clearValidate()
}, { deep: true })
watch(() => props.detail, val => {
if (val) {
formData.value = {
...val.mimplement,
baseInitialOpinionFile: val.mimplement?.baseInitialOpinionFile ? reviewFileParam(JSON.parse(val.mimplement.baseInitialOpinionFile)) : [],
baseInforLevelFile: val.mimplement?.baseInforLevelFile ? reviewFileParam(JSON.parse(val.mimplement.baseInforLevelFile)) : [],
basePasswAssessFile: val.mimplement?.basePasswAssessFile ? reviewFileParam(JSON.parse(val.mimplement.basePasswAssessFile)) : [],
baseThirdAcceptFile: val.mimplement?.baseThirdAcceptFile ? reviewFileParam(JSON.parse(val.mimplement.baseThirdAcceptFile)) : [],
baseCheckFile: val.mimplement?.baseCheckFile ? reviewFileParam(JSON.parse(val.mimplement.baseCheckFile)) : [],
baseFinanlAuditFile: val.mimplement?.baseFinanlAuditFile ? reviewFileParam(JSON.parse(val.mimplement.baseFinanlAuditFile)) : [],
baseUserConsFile: val.mimplement?.baseUserConsFile ? reviewFileParam(JSON.parse(val.mimplement.baseUserConsFile)) : [],
baseEstaSummFile: val.mimplement?.baseEstaSummFile ? reviewFileParam(JSON.parse(val.mimplement.baseEstaSummFile)) : [],
baseOperatMaintenSummFile: val.mimplement?.baseOperatMaintenSummFile ? reviewFileParam(JSON.parse(val.mimplement.baseOperatMaintenSummFile)) : [],
baseFinalExpertOpinionFile: val.mimplement?.baseFinalExpertOpinionFile ? reviewFileParam(JSON.parse(val.mimplement.baseFinalExpertOpinionFile)) : [],
baseEngineerPostpoFile: val.mimplement?.baseEngineerPostpoFile ? reviewFileParam(JSON.parse(val.mimplement.baseEngineerPostpoFile)) : [],
baseEngineerAlterFile: val.mimplement?.baseEngineerAlterFile ? reviewFileParam(JSON.parse(val.mimplement.baseEngineerAlterFile)) : [],
baseChanFile: val.mimplement?.baseChanFile ? reviewFileParam(JSON.parse(val.mimplement.baseChanFile)) : [],
baseBusinessMetrics: val.mimplement?.baseBusinessMetrics && JSON.parse(val.mimplement?.baseBusinessMetrics) || []
}
}
})
watch(() => props.data, val => {
},
{ immediate: true, deep: true })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="currentRules"
label-position="top"
label-suffix=":"
scroll-to-error
:validate-on-rule-change="false"
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item
v-if="baseProjSetYear*1>=2024"
label="是否完成日志数据归集"
label-width="170"
prop="baseLogAggregation"
>
<el-radio-group v-model="formData.baseLogAggregation">
<el-radio label="1">是</el-radio>
<el-radio label="2">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-else
label="是否完成日志数据归集"
label-width="170"
>
<el-radio-group v-model="formData.baseLogAggregation">
<el-radio label="1">是</el-radio>
<el-radio label="2">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
v-if="baseProjSetYear*1>=2024"
label="实际成效指标"
label-width="170"
prop="baseBusinessMetrics"
>
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="formData.baseBusinessMetrics"
:empty-temp="false"
>
<template #action="{scope}">
<a @click="showProjectContentDialog(scope.row,scope.$index)">编辑</a>
<a class="text-danger" @click="delProjectContent(scope.$index)">删除</a>
</template>
</table-list>
<p class="text-right w-full mt-8">
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="()=>showProjectContentDialog()"
>添加</el-button>
</p>
</el-form-item>
<el-form-item
v-else
label="实际成效指标"
label-width="170"
>
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="formData.baseBusinessMetrics"
:empty-temp="false"
>
<template #action="{scope}">
<a @click="showProjectContentDialog(scope.row,scope.$index)">编辑</a>
<a class="text-danger" @click="delProjectContent(scope.$index)">删除</a>
</template>
</table-list>
<p class="text-right w-full mt-8">
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="()=>showProjectContentDialog()"
>添加</el-button>
</p>
</el-form-item>
</el-col>
<el-col v-if="(['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)&&basicInfoData?.baseConstructionType?.includes('01'))||!basicInfoData?.baseConstructionType?.includes('01')" :span="8">
<el-form-item
v-if="basicInfoData?.baseProjSetProg==='07'&&basicInfoData?.baseConstructionType?.includes('01')&&['03','04','05'].includes(approvalInfoData?.equalProtectionLevel)"
label="信息安全等级保护测评报告"
prop="baseInforLevelFile"
>
<el-upload
v-model:file-list="formData.baseInforLevelFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseInforLevelFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="信息安全等级保护测评报告"
>
<el-upload
v-model:file-list="formData.baseInforLevelFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseInforLevelFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" :span="8">
<el-form-item
v-if="['01','02'].includes(approvalInfoData?.equalProtectionLevel)||baseProjSetYear*1<2023"
label="商业密码应用评估报告"
>
<el-upload
v-model:file-list="formData.basePasswAssessFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.basePasswAssessFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="商业密码应用评估报告"
prop="basePasswAssessFile"
>
<el-upload
v-model:file-list="formData.basePasswAssessFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.basePasswAssessFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="第三方验收测试报告"
>
<el-upload
v-model:file-list="formData.baseThirdAcceptFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseThirdAcceptFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="!['01','02','03','04'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" :span="8">
<el-form-item
v-if="baseProjSetYear*1<2023||['05','06','07'].includes(basicInfoData?.baseProjSetProg)"
label="用户使用报告"
>
<el-upload
v-model:file-list="formData.baseUserConsFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseUserConsFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="用户使用报告"
prop="baseUserConsFile"
>
<el-upload
v-model:file-list="formData.baseUserConsFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseUserConsFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="监理总结报告"
>
<el-upload
v-model:file-list="formData.baseEstaSummFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseEstaSummFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="!['01','02','03','04'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" :span="8">
<el-form-item
v-if="basicInfoData?.baseProjSetProg==='07'&&baseProjSetYear*1>=2023"
label="运维总结报告"
prop="baseOperatMaintenSummFile"
>
<el-upload
v-model:file-list="formData.baseOperatMaintenSummFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseOperatMaintenSummFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="运维总结报告"
>
<el-upload
v-model:file-list="formData.baseOperatMaintenSummFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseOperatMaintenSummFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="basicInfoData?.baseProjSetProg==='07'" :span="8">
<el-form-item
label="终验意见"
prop="baseFinalExpertOpinionFile"
>
<el-upload
v-model:file-list="formData.baseFinalExpertOpinionFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseFinalExpertOpinionFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="项目延期申请表"
>
<el-upload
v-model:file-list="formData.baseEngineerPostpoFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseEngineerPostpoFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="变更报告"
>
<el-upload
v-model:file-list="formData.baseEngineerAlterFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseEngineerAlterFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="变更批复文件"
>
<el-upload
v-model:file-list="formData.baseChanFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseChanFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
<actual-performance-indicators-dialog
:visible="projectContentDialogData.visible"
:data="projectContentDialogData.data"
@set-content="setContent"
@close="projectContentDialogData.visible=false"
/>
</template>

+ 124
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/lineOrgDialog.vue Datei anzeigen

@@ -0,0 +1,124 @@
<script name="relatedIrsAppDialog" setup>
import { nextTick, ref, watch } from 'vue'
import { govStripList } from '@/http/apis/declareMange'

const
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object,
column: {
type: Array,
default: () => {
return [
{
type: 'radio',
key: 'businessStripCode',
width: '60'
},
{
label: '单位名称',
key: 'businessStripName',
prop: 'businessStripName',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '单位编码',
key: 'businessStripCode',
prop: 'businessStripCode',
minWidth: '150',
showOverflowTooltip: true
}
]
}
}
}),
searchForm = ref({
name: undefined
}),
// 表格数据
tableListRef = ref(),
total = ref(0),
tableData = ref([]),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await govStripList({ ...pageParams, ...searchForm.value })
tableData.value = res.data
await nextTick()
tableListRef.value.setRadio(props?.data?.businessStripCode || '')
},
// 搜索
search = () => {
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
reset = () => {
tableListRef.value.pageParams.pageNumber = 1
searchForm.value.businessStripName = undefined
getTableData()
},
selectData = ref(),
radioChange = (val) => {
selectData.value = val
},
submit = async () => {
emits('getBaseProvManDeprt', selectData.value)
emits('close', true)
},
emits = defineEmits(['close', 'getBaseProvManDeprt'])

watch(() => props.visible, async (val) => {
if (val) {
await nextTick()
await getTableData()
} else {
tableListRef.value.tableRef.clearSelection()
}
})
</script>

<template>
<el-dialog
:model-value="visible"
title="选择单位"
:width="840"
@close="emits('close')"
>
<el-form :model="searchForm" label-suffix=":">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="单位名称">
<el-input v-model="searchForm.businessStripName" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="search_btn">
<el-button type="primary" @click="search">搜索</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>

<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:total="total"
row-key="appId"
:pagination="false"
@radio-change="radioChange"
@get-table-data="getTableData"
/>

<template #footer>
<div class="flex justify-center">
<el-button type="primary" @click="submit">确定</el-button>
<el-button @click="emits('close')">取消</el-button>
</div>
</template>
</el-dialog>
</template>

+ 216
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/manageInfo.vue Datei anzeigen

@@ -0,0 +1,216 @@
<script name="projectCollectionEnterManageInfo" setup>
import { onMounted, reactive, ref, watch } from 'vue'
import OrgTree from '@/components/orgTree/index.vue'
import store from '@/store'
import { getTreeParams } from '@/utils/getIsShowRegionTree'
import { districtList } from '@/http/apis/commonApi'

const props = defineProps({
detail: {
type: Object
}
}),
{ baseProjConsClassOptions } = store.dictStore.globalDicts || {},
// 行政区划
areaOptions = ref([]),
formRef = ref(),
formData = ref({}),
// 手机号码校验
checkTelPhone = (rule, value, callback) => {
if (value === '') {
return callback(new Error('请输入正确的手机号'))
} else {
const regIdCard =
/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
if (regIdCard.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的手机号'))
}
}
},
rules = {
areaCode: [{ required: true, message: '请选择行政区划', trigger: 'change' }],
buildOrg: [{ required: true, message: '请选择建设单位', trigger: 'change' }],
responsibleMan: [{ required: true, message: '请填写项目负责人', trigger: 'blur' }],
responsibleManMobile: [
{ required: true, message: '请填写项目负责人手机号', trigger: 'blur' },
{ validator: checkTelPhone, trigger: 'blur' }
],
contactName: [{ required: true, message: '请填写项目联系人', trigger: 'blur' }],
contactPhone: [
{ required: true, message: '请填写项目联系人手机号', trigger: 'blur' },
{ validator: checkTelPhone, trigger: 'blur' }
],
higherSuperOrg: [{ required: true, message: '请选择上级业务主管部门', trigger: 'change' }],
superOrg: [{ required: true, message: '请选择本级业务主管部门', trigger: 'change' }],
constructionOrg: [{ required: true, message: '请选择建设单位', trigger: 'change' }],
buildLevel: [{ required: true, message: '请选择建设层级', trigger: 'change' }]
},
// 单位选择
orgProps = reactive({
field: undefined,
unitVisible: false,
data: undefined,
title: undefined,
type: undefined,
params: undefined
}),
showOrgTree = (field) => {
orgProps.field = field
orgProps.unitVisible = true
orgProps.title = '选择单位'
orgProps.type = 'UNIT'
orgProps.showCheckbox = true
orgProps.defaultProps = {
children: 'children',
label: 'title',
value: 'key',
isLeaf: 'isLeaf'
}
orgProps.params = {
onlyUnit: true
}
orgProps.data = formData.value[`${field}Code`] ? [{
key: formData.value[`${field}Code`],
title: formData.value[field]
}] : []
},
closeOrg = () => {
orgProps.unitVisible = false
},
getOrgData = (data) => {
formData.value[`${orgProps.field}Code`] = data?.[0].key || undefined
formData.value[orgProps.field] = data?.[0].title || undefined
}
defineExpose({ formRef, formData })
watch(() => props.detail, val => {
if (val) {
formData.value = {
areaCode: ['330500', val.areaCode],
responsibleMan: val.responsibleMan,
responsibleManMobile: val.responsibleManMobile,
contactName: val.contactName,
contactPhone: val.contactPhone,
higherSuperOrg: val.higherSuperOrg,
superOrg: val.superOrg,
constructionOrg: val.constructionOrg,
constructionOrgCreditCode: val.constructionOrgCreditCode,
buildLevel: val.buildLevel,
buildOrg: val.buildOrg,
buildOrgCode: val.buildOrgCode
}
}
})

onMounted(async () => {
areaOptions.value = [(await districtList(getTreeParams({ 'SUPER_ADMIN': false, 'REGION_MANAGER': false }))).data]
})
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="top"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="8">
<el-form-item label="行政区划" prop="areaCode">
<el-cascader
v-model="formData.areaCode"
class="w-full"
:props="{label:'name',value:'regionCode'}"
:options="areaOptions"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目负责人" prop="responsibleMan">
<el-input v-model="formData.responsibleMan" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目负责人手机号" prop="responsibleManMobile">
<el-input v-model="formData.responsibleManMobile" maxlength="11" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="项目联系人" prop="contactName">
<el-input v-model="formData.contactName" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="项目联系人手机号" prop="contactPhone">
<el-input v-model="formData.contactPhone" maxlength="11" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="上级业务主管部门" prop="higherSuperOrg">
<el-input
v-model="formData.higherSuperOrg"
placeholder="请选择"
readonly
@click="showOrgTree('higherSuperOrg')"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="本级业务主管部门" prop="superOrg">
<el-input
v-model="formData.superOrg"
placeholder="请选择"
readonly
@click="showOrgTree('superOrg')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="建设单位" prop="buildOrg">
<el-input
v-model="formData.buildOrg"
placeholder="请选择"
readonly
@click="showOrgTree('buildOrg')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="建设单位统一信用代码" prop="constructionOrgCreditCode">
<el-input v-model="formData.constructionOrgCreditCode" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="建设层级" prop="buildLevel">
<el-select
v-model="formData.buildLevel"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(value, key) in baseProjConsClassOptions"
:key="key"
:label="value"
:value="key*1"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<org-tree
:visible="orgProps.unitVisible"
:show-checkbox="false"
:default-data="orgProps.data"
:title="orgProps.title"
:type="orgProps.type"
:default-props="orgProps.defaultProps"
:params="orgProps.params"
@close="closeOrg"
@get-select-unit="getOrgData"
/>

</template>

+ 263
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/otherMaterials.vue Datei anzeigen

@@ -0,0 +1,263 @@
<script name="projectCollectionEnterOtherMaterials" setup>
import { ref, watch } from 'vue'
import { fileFormatVerification, handleFileError, handleFileSuccess, handleFilePreview, reviewFileParam, fileTypes, fileDesc } from '@/utils/uploadAction'
import store from '@/store'

const props = defineProps({
detail: {
type: Object
},
data: {
type: Object
}
}),
uploadUrl = store.dictStore.uploadUrl,
formRef = ref(),
formData = ref({
feasibilityStudyReport: [],
approvedFile: [],
purchaseFile: [],
acceptanceLetter: [],
purchaseContract: [],
acceptanceReport: [],
changeApprovalDoc: []
}),
fileRule = [{ required: true, message: '请选择文件' }],
rules = {
feasibilityStudyReport: fileRule,
approvedFile: fileRule,
purchaseFile: fileRule,
acceptanceLetter: fileRule,
purchaseContract: fileRule,
acceptanceReport: fileRule,
changeApprovalDoc: fileRule,
constructionOrg: [{ required: true, message: '请填写承建单位' }],
constructionOrgCreditCode: [{ required: true, message: '请填写承建单位统一信用代码' }]
}
defineExpose({ formRef, formData })
watch(() => props.detail, val => {
if (val) {
formData.value = {
feasibilityStudyReport: reviewFileParam(JSON.parse(val.feasibilityStudyReport)),
approvedFile: reviewFileParam(JSON.parse(val.approvedFile)),
purchaseFile: reviewFileParam(JSON.parse(val.purchaseFile)),
acceptanceLetter: reviewFileParam(JSON.parse(val.acceptanceLetter)),
purchaseContract: reviewFileParam(JSON.parse(val.purchaseContract)),
acceptanceReport: reviewFileParam(JSON.parse(val.acceptanceReport)),
changeApprovalDoc: reviewFileParam(JSON.parse(val.changeApprovalDoc)),
constructionOrg: val.constructionOrg,
constructionOrgCreditCode: val.constructionOrgCreditCode,
supervisorOrg: val.supervisorOrg,
supervisorOrgCreditCode: val.supervisorOrgCreditCode
}
}
})
watch(() => props.data, val => {
},
{ immediate: true, deep: true })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="top"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item
label="可行性研究报告(建设方案、运维方案)"
:prop="props.data.status===1||props.data.status===2?'':'feasibilityStudyReport'"
>
<el-upload
v-model:file-list="formData.feasibilityStudyReport"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.feasibilityStudyReport)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>

<el-col :span="8">
<el-form-item
label="立项批复文件"
prop="approvedFile"
>
<el-upload
v-model:file-list="formData.approvedFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.approvedFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="采购文件"
prop="purchaseFile"
>
<el-upload
v-model:file-list="formData.purchaseFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.purchaseFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="中标通知书"
prop="acceptanceLetter"
>
<el-upload
v-model:file-list="formData.acceptanceLetter"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.acceptanceLetter)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="采购合同"
prop="purchaseContract"
>
<el-upload
v-model:file-list="formData.purchaseContract"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.purchaseContract)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="验收报告"
prop="acceptanceReport"
>
<el-upload
v-model:file-list="formData.acceptanceReport"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.acceptanceReport)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="变更批复文件"
prop="changeApprovalDoc"
>
<el-upload
v-model:file-list="formData.changeApprovalDoc"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.changeApprovalDoc)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>

<el-col :span="6">
<el-form-item label="承建单位" :prop="props.data.status===3||props.data.status===4||props.data.status===6?'constructionOrg':''">
<el-input v-model="formData.constructionOrg" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="承建单位统一信用代码" :prop="props.data.status===3||props.data.status===4||props.data.status===6?'constructionOrgCreditCode':''">
<el-input v-model="formData.constructionOrgCreditCode" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="监理单位" prop="supervisorOrg">
<el-input v-model="formData.supervisorOrg" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="监理单位统一信用代码" prop="supervisorOrgCreditCode">
<el-input v-model="formData.supervisorOrgCreditCode" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
</el-row>
</el-form>

</template>

+ 69
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/progressInfo.vue Datei anzeigen

@@ -0,0 +1,69 @@
<script name="projectCollectionEnterProgressInfo" setup>
import { ref, watch } from 'vue'
import store from '@/store'

const props = defineProps({
detail: {
type: Object
}
}),
{ baseProjSetProgOptions } = store.dictStore.globalDicts || {},
formRef = ref(),
formData = ref({}),
rules = {
status: [{ required: true, message: '请选择项目状态', trigger: 'change' }]
}
defineExpose({ formRef, formData })
watch(() => props.detail, val => {
console.log(val)
if (val) {
formData.value = {
status: val.status,
applicationName: val.applicationName,
applicationIrsCode: val.applicationIrsCode
}
}
})
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="top"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="8">
<el-form-item label="项目状态" prop="status">
<el-select
v-model="formData.status"
class="w-full"
placeholder="请选择"
clearable
>
<el-option
v-for="(v,k) in baseProjSetProgOptions"
:key="k"
:label="v"
:value="k*1"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联应用" prop="applicationName">
<el-input v-model="formData.applicationName" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联应用IRS编码" prop="applicationIrsCode">
<el-input v-model="formData.applicationIrsCode" maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
</el-row>
</el-form>

</template>

+ 365
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/projectApprovalInfo.vue Datei anzeigen

@@ -0,0 +1,365 @@
<script name="projectApprovalInfo" setup>
import { ref, watch } from 'vue'
import { fileFormatVerification, handleFileError, handleFileSuccess, handleFilePreview, reviewFileParam, fileTypes, fileDesc } from '@/utils/uploadAction'
import store from '@/store'

const props = defineProps({
detail: {
type: Object
},
basicInfoData: {
type: Object
},
dictionaryList: {
type: Array,
default: () => []
}
}),
uploadUrl = store.dictStore.uploadUrl,
formRef = ref(),
formData = ref({
}),
currentRules = ref([])
defineExpose({ formRef, formData })
watch(() => props.detail, val => {
if (val) {
formData.value = {
...val.approve,
baseReviewCommentsFile: val.approve?.baseReviewCommentsFile && reviewFileParam(JSON.parse(val.approve.baseReviewCommentsFile)) || [],
approvalFile: val.approve?.approvalFile && reviewFileParam(JSON.parse(val.approve.approvalFile)) || [],
preliminaryDesignScheme: val.approve?.preliminaryDesignScheme && reviewFileParam(JSON.parse(val.approve.preliminaryDesignScheme)) || [],
preliminaryDesignFile: val.approve?.preliminaryDesignFile && reviewFileParam(JSON.parse(val.approve.preliminaryDesignFile)) || []
}
}
})
const fileRule = [{ required: true, message: '请上传' }],
emits = defineEmits(['getApprovalInfoData'])
watch(() => props.basicInfoData, val => {
if (val?.baseProjIsConfidentiality === '02') {
currentRules.value = {}
} else {
currentRules.value = {
baseReviewResults: [{ required: true, message: '请选择评审结果' }],
equalProtectionLevel: [{ required: true, message: '请选择等保定级' }],
baseReviewOpinion: [{ required: true, message: '请填写评审意见' }],
baseReviewCommentsFile: fileRule,
approvalFile: fileRule,
baseExpertTotalMoney: [{ required: true, message: '请填写建议总投资' }],
baseExpertYearMoney: [{ required: true, message: '请填写建议年度预算' }],
baseInitialReviewTotalMoney: [{ required: true, message: '请填写建议批复总投资' }],
baseProjReplyAmount: [{ required: true, message: '请填写建议批复年度预算' }],
releaseYearMoney: [{ required: true, message: '请填写年度预算下达金额' }],
preliminaryDesignScheme: fileRule,
preliminaryDesignFile: fileRule
}
}
formRef.value?.clearValidate()
}, { deep: true, immediate: true })
watch(() => formData.value, val => {
emits('getApprovalInfoData', val)
}, { deep: true })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="currentRules"
label-position="top"
label-suffix=":"
scroll-to-error
:validate-on-rule-change="false"
>
<el-row :gutter="40">
<el-col v-if="basicInfoData?.baseProjSetProg!=='01'" :span="8">
<el-form-item label="评审结果" prop="baseReviewResults">
<el-select v-model="formData.baseReviewResults" class="w-full">
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'REVIEW_RESULTS')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="basicInfoData?.baseProjIsConfidentiality === '01'&&!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item
v-if="basicInfoData?.baseConstructionType?.includes('01')&&basicInfoData?.baseProjSetProg!=='04'"
key="equalProtectionLevel1"
label="等保定级"
prop="equalProtectionLevel"
>
<el-select v-model="formData.equalProtectionLevel" class="w-full">
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'EQUAL_PROTECTION_RATING')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-else
key="equalProtectionLevel2"
label="等保定级"
>
<el-select v-model="formData.equalProtectionLevel" class="w-full">
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'EQUAL_PROTECTION_RATING')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="basicInfoData?.baseProjSetProg!=='01'" :span="24">
<el-form-item label="评审意见" prop="baseReviewOpinion">
<el-input
v-model="formData.baseReviewOpinion"
type="textarea"
show-word-limit
:maxlength="500"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col v-if="basicInfoData?.baseProjSetProg!=='01'" :span="8">
<el-form-item
label="评审意见附件"
prop="baseReviewCommentsFile"
>
<el-upload
v-model:file-list="formData.baseReviewCommentsFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseReviewCommentsFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item
label="立项批复文件"
prop="approvalFile"
>
<el-upload
v-model:file-list="formData.approvalFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.approvalFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="!['01','03'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item label="建议总投资" prop="baseExpertTotalMoney">
<el-input-number
v-model="formData.baseExpertTotalMoney"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col v-if="!['01','03'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item label="建议年度预算" prop="baseExpertYearMoney">
<el-input-number
v-model="formData.baseExpertYearMoney"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item label="建议批复总投资" prop="baseInitialReviewTotalMoney">
<el-input-number
v-model="formData.baseInitialReviewTotalMoney"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col v-if="!['01','02','03'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item label="建议批复年度预算" prop="baseProjReplyAmount">
<el-input-number
v-model="formData.baseProjReplyAmount"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item label="年度预算下达金额" prop="releaseYearMoney">
<el-input-number
v-model="formData.releaseYearMoney"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col v-if="formData.baseProjReplyAmount>=5000&&['04','05','06','07','00'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item
v-if="basicInfoData?.baseProjSetProg!=='04'"
key="preliminaryDesignScheme1"
label="初步设计方案"
prop="preliminaryDesignScheme"
>
<el-upload
v-model:file-list="formData.preliminaryDesignScheme"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.preliminaryDesignScheme)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
key="preliminaryDesignScheme2"
label="初步设计方案"
>
<el-upload
v-model:file-list="formData.preliminaryDesignScheme"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.preliminaryDesignScheme)"
:on-error="handleFileError"
:before-upload="
file =>
fileFormatVerification(file, {
types: [
'application/pdf',
]
})
"
accept=".pdf"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持格式:pdf</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="formData.baseProjReplyAmount>=5000&&['04','05','06','07','00'].includes(basicInfoData?.baseProjSetProg)" :span="8">
<el-form-item
v-if="basicInfoData?.baseProjSetProg!=='04'"
key="preliminaryDesignFile1"
label="初步设计方案批复函"
prop="preliminaryDesignFile"
>
<el-upload
v-model:file-list="formData.preliminaryDesignFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.preliminaryDesignFile)"
:on-error="handleFileError"
:before-upload="
file =>
fileFormatVerification(file, {
types: [
'application/pdf',
]
})
"
accept=".pdf"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持格式:pdf</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
key="preliminaryDesignFile2"
label="初步设计方案批复函"
>
<el-upload
v-model:file-list="formData.preliminaryDesignFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.preliminaryDesignFile)"
:on-error="handleFileError"
:before-upload="
file =>
fileFormatVerification(file, {
types: [
'application/pdf',
]
})
"
accept=".pdf"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持格式:pdf</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>

</template>


+ 198
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/projectContentDialog.vue Datei anzeigen

@@ -0,0 +1,198 @@
<script setup name="projectContentDialog">
import { ref, watch } from 'vue'

const
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object
}),
form = ref({
perIndicator: []
}),
formRef = ref(),
rules = {
mainContent: [{ required: true, message: '请输入项目主要内容' }],
businessObject: [{ required: true, message: '请输入业务对象' }],
perIndicator: [{ required: true, message: '请至少添加一个预期成效指标' }]
},
column = [
{
label: '预期成效指标名称',
key: 'name',
slot: 'name',
width: 140
},
{
label: '符号',
key: 'symbol',
slot: 'symbol'
},
{
label: '数值',
key: 'nums',
slot: 'nums'
},
{
label: '单位',
key: 'unit',
slot: 'unit'
},
{
label: '操作',
key: 'action',
slot: 'action',
width: 70
}
],
// 添加
add = () => {
form.value.perIndicator.push({})
},
del = (index) => {
form.value.perIndicator.splice(index, 1)
},
submit = async (formEl) => {
if (!formEl) {
return
}
await formEl.validate(async (valid) => {
if (valid) {
const data = JSON.parse(JSON.stringify(form.value))
emits('setContent', data)
emits('close', true)
}
})
},
emits = defineEmits(['close', 'setContent'])
watch(
() => props.visible,
async (val) => {
if (val && props.data) {
form.value = JSON.parse(JSON.stringify(props.data))
} else {
formRef.value?.resetFields()
form.value = {
perIndicator: []
}
}
}
)
</script>
<template>
<el-dialog
:model-value="visible"
title="添加"
:size="840"
@close="emits('close')"
>
<el-form
ref="formRef"
label-suffix=":"
:model="form"
:rules="rules"
label-width="160"
>
<el-form-item label="项目主要内容" prop="mainContent">
<el-input
v-model="form.mainContent"
placeholder="请输入"
maxlength="100"
/>
</el-form-item>
<el-form-item label="业务对象" prop="businessObject">
<el-input
v-model="form.businessObject"
placeholder="请输入"
maxlength="100"
/>
</el-form-item>
<el-button
type="primary"
plain
icon="Plus"
class="w-full mb-8"
@click="add"
>添加
</el-button>
<table-list
:pagination="false"
:column="column"
:empty-temp="false"
:data="form.perIndicator"
>
<template #name="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].name`"
:rules="[{required:true,message:' '}]"
label-width="0"
style="margin-bottom: 0"
>
<el-input
v-model="form.perIndicator[scope.$index].name"
placeholder="请输入"
maxlength="50"
/>
</el-form-item>
</template>
<template #symbol="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].symbol`"
label-width="0"
style="margin-bottom: 0"
>
<el-select v-model="form.perIndicator[scope.$index].symbol">
<el-option label="等于" value="等于" />
<el-option label="大于" value="大于" />
<el-option label="大于等于" value="大于等于" />
<el-option label="小于" value="小于" />
<el-option label="小于等于" value="小于等于" />
</el-select>
</el-form-item>
</template>
<template #nums="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].nums`"
label-width="0"
style="margin-bottom: 0"
>
<el-input-number
v-model="form.perIndicator[scope.$index].nums"
:controls="false"
class="flex-1 mr-8"
placeholder="请输入"
@mousewheel.prevent
/>
</el-form-item>
</template>
<template #unit="{scope}">
<el-form-item
v-if="scope.$index>=0"
:prop="`perIndicator[${scope.$index}].unit`"
label-width="0"
style="margin-bottom: 0"
>
<el-input
v-model="form.perIndicator[scope.$index].unit"
placeholder="请输入"
maxlength="10"
/>
</el-form-item>
</template>
<template #action="{scope}">
<a class="text-danger cursor-pointer" @click="del(scope.$index)">移除</a>
</template>
</table-list>
</el-form>
<template #footer>
<el-button type="primary" @click="submit(formRef)">提交</el-button>
<el-button @click="emits('close')">取消</el-button>
</template>
</el-dialog>
</template>

+ 716
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/projectDeclareInfo.vue Datei anzeigen

@@ -0,0 +1,716 @@
<script name="projectCollectionEnterBasicInfo" setup>
import { reactive, ref, watch } from 'vue'
import RelatedProjectDialog from '@/pages/projectCollection/projectCollectionEnter/components/relatedProjectDialog.vue'
import ProjectContentDialog from '@/pages/projectCollection/projectCollectionEnter/components/projectContentDialog.vue'
import { reviewFileParam, fileFormatVerification, handleFileSuccess, handleFileError, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction'
import store from '@/store'

const props = defineProps({
detail: {
type: Object
},
basicInfoData: {
type: Object
},
dictionaryList: {
type: Array,
default: () => []
}
}),
uploadUrl = store.dictStore.uploadUrl,
// { budgetSourceOptions } = store.dictStore.globalDicts || {},
formRef = ref(),
formData = ref({
baseHistorProjs: [],
beseExpectedResults: []
}),
currentRules = ref({
baseProjTime: [{ required: true, message: '请选择项目起止时间' }],
baseProjSetYear: [{ required: true, message: '请选择预算年度' }],
baseProjTotalAmount: [{ required: true, message: '请填写项目总投资' }],
baseProjDeclAmount: [{ required: true, message: '请填写申报年度预算' }],
baseProjConsClass: [{ required: true, message: '请选择建设层级' }],
baseLowestLevel: [{ required: true, message: '请选择贯通层级' }],
baseProjAmountOri: [{ required: true, message: '请选择预算来源' }],
baseBasisAmountOri: [{ required: true, message: '请填写预算来源说明' }],
baseProjBasis: [{ required: true, message: '请选择立项依据' }],
baseBasisEstablish: [{ required: true, message: '请填写立项依据说明' }],
baseProjIntro: [{ required: true, message: '请填写项目概述' }],
beseExpectedResults: [{ required: true, message: '请至少添加一个项目内容与预期成效' }],
baseOperatMaintenFile: [{ required: true, message: '请上传' }],
baseHistorProjs: [{ required: true, message: '请关联项目', type: 'array' }],
baseProjApplyFile: [{ required: true, message: '请上传' }]
}),
column = [
{
label: '序号',
type: 'index',
width: 60
},
{
label: '项目名称',
prop: 'baseProjName',
key: 'baseProjName'
},
{
label: '预算年度',
prop: 'baseProjSetYear',
key: 'baseProjSetYear'
},
{
label: '操作',
slot: 'action',
key: 'action'
}
],
// 立项依据
buildBasisColumn = [
{
type: 'selection'
},
{
label: '依据项',
key: 'title',
prop: 'title'
},
{
label: '依据文件名',
slot: 'fileName'
},
{
label: '文件(支持word、pdf格式)',
slot: 'action',
width: 300
}
],
buildBasisTableData = ref([
{
id: 1,
title: '政策、法规',
fileName: '',
fileList: []
},
{
id: 2,
title: '规划或决策部署',
fileName: '',
fileList: []
},
{
id: 3,
title: '上级下达任务',
fileName: '',
fileList: []
},
{
id: 4,
title: '领导批示',
fileName: '',
fileList: []
},
{
id: 5,
title: '单位核心业务或单位职能',
fileName: '',
fileList: []
},
{
id: 6,
title: '其他',
fileName: '',
fileList: []
}
]),
selectionChange = (val) => {
formData.value.baseProjBasis = val.map(i => i)
},
column1 = [
{
label: '项目主要内容',
prop: 'mainContent',
key: 'mainContent'
},
{
label: '业务对象',
prop: 'businessObject',
key: 'businessObject'
},
{
label: '操作',
slot: 'action',
key: 'action'
}
],
// 关联项目
relatedProjectDialogData = reactive({
visible: false
}),
showRelatedProjectDialog = () => {
relatedProjectDialogData.visible = true
relatedProjectDialogData.data = formData.value.baseHistorProjs
},
getProjectList = (data) => {
formData.value.baseHistorProjs = data.map(i => {
return {
baseProjName: i.projectName,
baseProjSetYear: i.projectYear,
baseProjId: i.id
}
})
},
delPro = (index) => {
formData.value.baseHistorProjs.splice(index, 1)
},
// 项目内容与预期成效
projectContentDialogData = reactive({
visible: false,
data: undefined
}),
projectContentIndex = ref(),
showProjectContentDialog = (data, index) => {
projectContentDialogData.data = data
projectContentDialogData.visible = true
projectContentIndex.value = index
},
setContent = (data) => {
if (projectContentIndex.value === undefined) {
formData.value.beseExpectedResults.push(data)
} else {
formData.value.beseExpectedResults[projectContentIndex.value] = data
}
},
delProjectContent = (index) => {
formData.value.beseExpectedResults.splice(index, 1)
},
emits = defineEmits(['getProYear']),
tableListRef = ref()
defineExpose({ formRef, formData })
watch(() => props.dictionaryList, val => {
if (val) {
buildBasisTableData.value = []
props.dictionaryList?.filter(i => i.type === 'PROJECT_BASIS').forEach(i => {
buildBasisTableData.value.push({
title: i.label,
fileName: '',
fileList: [],
value: i.value
})
})
}
})
watch(() => props.detail, val => {
if (val) {
formData.value = {
...val.apply,
baseProjTime: val.apply?.baseProjStartTime ? [val.apply?.baseProjStartTime.slice(0, 10), val.apply?.baseProjEndTime.slice(0, 10)] : [],
baseHistorProjs: val.apply?.baseHistorProjId?.split(';').map((i, k) => {
return {
baseProjId: i,
baseProjName: val.apply?.baseHistorProjName.split(';')[k],
baseProjSetYear: val.apply?.baseHistorProjYear.split(';')[k]
}
}) || [],
baseProjAmountOri: val.apply?.baseProjAmountOri && val.apply?.baseProjAmountOri?.split(';'),
baseProjBasis: val.apply?.baseProjBasis?.split(';')?.map((i, index) => {
const file = `[${val.apply?.baseProjBasisFile.replace(/}];/g, '}],')}]`
return {
title: buildBasisTableData.value?.find(j => j.value === i)?.title,
fileList: val.apply?.baseProjBasisFile ? reviewFileParam(JSON.parse(file)[index]) : [],
value: i
}
}),
beseExpectedResults: val.apply?.beseExpectedResults && JSON.parse(val.apply?.beseExpectedResults) || [],
baseProjApplyFile: val.apply?.baseProjApplyFile ? reviewFileParam(JSON.parse(val.apply.baseProjApplyFile)) : [],
baseOperatMaintenFile: val.apply?.baseOperatMaintenFile ? reviewFileParam(JSON.parse(val.apply.baseOperatMaintenFile)) : [],
baseProjOtherFile: val.apply?.baseProjOtherFile ? reviewFileParam(JSON.parse(val.apply.baseProjOtherFile)) : []
}
const baseProjBasis = formData.value.baseProjBasis ? JSON.parse(JSON.stringify(formData.value.baseProjBasis)) : []
if (val.apply?.baseProjBasis?.split(';')?.length) {
const dataIds = val.apply?.baseProjBasis?.split(';')
buildBasisTableData.value && buildBasisTableData.value.forEach(item => {
if (dataIds.includes(item.value)) {
item.fileList = baseProjBasis.find(i => i.value === item.value)?.fileList
item.fileName = baseProjBasis.find(i => i.value === item.value)?.fileName
tableListRef.value.toggleRowSelect(item, true)
}
})
}
}
})
watch(() => props.basicInfoData, val => {
if (val.baseProjIsConfidentiality === '02') {
currentRules.value = {}
} else {
currentRules.value = {
baseProjTime: [{ required: true, message: '请选择项目起止时间' }],
baseProjSetYear: [{ required: true, message: '请选择预算年度' }],
baseProjDeclAmount: [{ required: true, message: '请填写申报年度预算' }],
baseProjConsClass: [{ required: true, message: '请选择建设层级' }],
baseLowestLevel: [{ required: true, message: '请选择贯通层级' }],
baseProjAmountOri: [{ required: true, message: '请选择预算来源' }],
baseBasisAmountOri: [{ required: true, message: '请填写预算来源说明' }],
baseProjBasis: [{ required: true, message: '请选择立项依据' }],
baseBasisEstablish: [{ required: true, message: '请填写立项依据说明' }],
baseProjIntro: [{ required: true, message: '请填写项目概述' }],
beseExpectedResults: [{ required: true, message: '请至少添加一个项目内容与预期成效' }],
baseOperatMaintenFile: [{ required: true, message: '请上传' }],
baseHistorProjs: [{ required: true, message: '请关联项目', type: 'array' }],
baseProjApplyFile: [{ required: true, message: '请上传' }]
}
}
formRef.value?.clearValidate()
}, { deep: true })
watch(() => formData.value.baseProjSetYear, val => {
emits('getProYear', val)
})
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="currentRules"
label-position="top"
label-suffix=":"
scroll-to-error
:validate-on-rule-change="false"
>
<el-row :gutter="40">
<el-col :span="8">
<el-form-item label="发改编码" prop="baseDevelopCode">
<el-input v-model="formData.baseDevelopCode" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="财政编码" prop="setProjCodeFinan">
<el-input v-model="formData.setProjCodeFinan" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目起止时间" prop="baseProjTime">
<el-date-picker
v-model="formData.baseProjTime"
type="daterange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度" prop="baseProjSetYear">
<el-date-picker
v-model="formData.baseProjSetYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目总投资" prop="baseProjTotalAmount">
<el-input-number
v-model="formData.baseProjTotalAmount"
placeholder="请填写"
:min="0.000001"
:controls="false"
class="input-amount"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
v-if="formData.baseProjSetYear*1>=2023"
key="baseProjDeclAmount1"
label="申报年度预算"
prop="baseProjDeclAmount"
>
<el-input-number
v-model="formData.baseProjDeclAmount"
placeholder="请填写"
:min="0.000001"
:controls="false"
class="input-amount"
@mousewheel.prevent
/>
</el-form-item>
<el-form-item v-else key="baseProjDeclAmount2" label="申报年度预算">
<el-input-number
v-model="formData.baseProjDeclAmount"
placeholder="请填写"
:min="0.000001"
:controls="false"
class="input-amount"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="建设层级" prop="baseProjConsClass">
<el-select
v-model="formData.baseProjConsClass"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'BUILD_LEVEL')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="!(basicInfoData?.baseConstructionType?.includes('03')&&!basicInfoData?.baseConstructionType?.includes('01'))" :span="8">
<el-form-item v-if="basicInfoData?.baseConstructionType?.includes('01')" label="贯通层级" prop="baseLowestLevel">
<el-select
v-model="formData.baseLowestLevel"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'LINK_UP_LEVEL')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-else label="贯通层级">
<el-select
v-model="formData.baseLowestLevel"
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'LINK_UP_LEVEL')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item v-if="!formData.missing" label="历年项目名称" prop="baseHistorProjs">
<span class="text-[#666666]">是否缺失:</span>
<el-switch v-model="formData.missing" />
<p class="text-right w-full mb-8">
<el-button type="primary" @click="showRelatedProjectDialog">关联历年项目</el-button>
</p>
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="formData.baseHistorProjs"
:empty-temp="false"
>
<template #action="{scope}">
<a class="text-danger" @click="delPro(scope.$index)">删除</a>
</template>
</table-list>
</el-form-item>
<el-form-item v-else label="历年项目名称" prop="missing">
<span class="text-[#666666]">是否缺失:</span>
<el-switch v-model="formData.missing" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预算来源" prop="baseProjAmountOri">
<el-checkbox-group v-model="formData.baseProjAmountOri">
<el-checkbox
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'BUDGET_SOURCE')"
:key="index"
:label="item.value"
>
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item v-if="formData.baseProjAmountOri?.includes('00')" label="预算来源说明" prop="baseBasisAmountOri">
<el-input
v-model="formData.baseBasisAmountOri"
type="textarea"
show-word-limit
placeholder="请填写"
:maxlength="150"
/>
</el-form-item>
<el-form-item v-else label="预算来源说明">
<el-input
v-model="formData.baseBasisAmountOri"
type="textarea"
show-word-limit
placeholder="请填写"
:maxlength="150"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="立项依据" prop="baseProjBasis">
<table-list
ref="tableListRef"
:pagination="false"
style="width: 100%"
:column="buildBasisColumn"
:data="buildBasisTableData"
@selection-change="selectionChange"
>
<template #fileName="{scope}">
<el-form-item v-if="formData.baseProjBasis&&formData.baseProjBasis.map(i=>i.value).includes(scope.row.value)">
<el-input
:value="formData.baseProjBasis[formData.baseProjBasis.findIndex(i=>i.value===scope.row.value)]?.fileList?.[0]?.name"
placeholder="请输入"
:maxlength="50"
:disabled="true"
/>
</el-form-item>
<el-input v-else :disabled="true" />
</template>
<template #action="{scope}">
<el-form-item
v-if="formData.baseProjBasis&&formData.baseProjBasis.map(i=>i.value).includes(scope.row.value)"
class="basicUploadItem"
:rules="{required: true,message:'请上传'}"
:prop="`baseProjBasis[${formData.baseProjBasis.findIndex(i=>i.value===scope.row.value)}].fileList`"
>
<el-upload
ref="materialUploadRef"
v-model:file-list="formData.baseProjBasis[formData.baseProjBasis.findIndex(i=>i.value===scope.row.value)].fileList"
class="flex items-center flex-col w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseProjBasis[formData.baseProjBasis.findIndex(i=>i.value===scope.row.value)].fileList, true)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<template #trigger>
<div>
<a>上传</a>
</div>
</template>
</el-upload>
</el-form-item>
<span v-else class="text-info cursor-not-allowed">上传</span>
</template>
</table-list>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="立项依据说明" prop="baseBasisEstablish">
<el-input
v-model="formData.baseBasisEstablish"
type="textarea"
show-word-limit
placeholder="请填写"
:maxlength="150"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="项目概述" prop="baseProjIntro">
<el-input
v-model="formData.baseProjIntro"
type="textarea"
show-word-limit
placeholder="请填写"
:maxlength="2000"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item v-if="formData.baseProjSetYear*1>=2023" label="项目内容与预期成效" prop="beseExpectedResults">
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="formData.beseExpectedResults"
:empty-temp="false"
>
<template #action="{scope}">
<a @click="showProjectContentDialog(scope.row,scope.$index)">编辑</a>
<a class="text-danger" @click="delProjectContent(scope.$index)">删除</a>
</template>
</table-list>
<p class="text-right w-full mt-8">
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="()=>showProjectContentDialog()"
>添加</el-button>
</p>
</el-form-item>
<el-form-item v-else label="项目内容与预期成效">
<table-list
:pagination="false"
style="width: 100%"
:column="column1"
:data="formData.beseExpectedResults"
:empty-temp="false"
>
<template #action="{scope}">
<a @click="showProjectContentDialog(scope.row,scope.$index)">编辑</a>
<a class="text-danger" @click="delProjectContent(scope.$index)">删除</a>
</template>
</table-list>
<p class="text-right w-full mt-8">
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="()=>showProjectContentDialog()"
>添加</el-button>
</p>
</el-form-item>
</el-col>

<el-col :span="8">
<el-form-item
v-if="formData.baseProjSetYear*1<2023"
label="项目申报书"
>
<el-upload
v-model:file-list="formData.baseProjApplyFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseProjApplyFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else-if="formData.baseProjSetYear*1>=2023&&['01','02','04','05'].includes(basicInfoData?.baseProjType)"
label="项目申报书"
prop="baseProjApplyFile"
>
<el-upload
v-model:file-list="formData.baseProjApplyFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseProjApplyFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="false" :span="8">
<el-form-item
label="可行性研究报告"
prop="baseResearchReportFile"
>
<el-upload
v-model:file-list="formData.baseResearchReportFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseResearchReportFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="运维方案"
prop="baseOperatMaintenFile"
>
<el-upload
v-model:file-list="formData.baseOperatMaintenFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseOperatMaintenFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="其他附件"
>
<el-upload
v-model:file-list="formData.baseProjOtherFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.baseProjOtherFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4" plain>上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="备注"
>
<el-input
v-model="formData.baseProjRemark"
type="textarea"
placeholder="请输入"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<related-project-dialog
:visible="relatedProjectDialogData.visible"
:data="relatedProjectDialogData.data"
@get-project-list="getProjectList"
@close="relatedProjectDialogData.visible=false"
/>
<project-content-dialog
:visible="projectContentDialogData.visible"
:data="projectContentDialogData.data"
@set-content="setContent"
@close="projectContentDialogData.visible=false"
/>
</template>

+ 720
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/purchaseInfo.vue Datei anzeigen

@@ -0,0 +1,720 @@
<script name="purchaseInfo" setup>
import { ref, watch } from 'vue'
import { fileFormatVerification, handleFileError, handleFileSuccess, handleFilePreview, reviewFileParam, fileTypes, fileDesc } from '@/utils/uploadAction'
import store from '@/store'

const props = defineProps({
detail: {
type: Object
},
basicInfoData: {
type: Object
},
baseProjSetYear: {
type: String,
default: ''
},
dictionaryList: {
type: Array,
default: () => []
}
}),
uploadUrl = store.dictStore.uploadUrl,
formRef = ref(),
formData = ref({
sections: [{
purchaseFile: [],
biddingFile: [],
purchaseContract: []
}]
}),
currentRules = {},
add = () => {
formData.value.sections.push({})
},
del = (index) => {
formData.value.sections.splice(index, 1)
}
defineExpose({ formRef, formData })
watch(() => props.basicInfoData, val => {
if (val?.baseProjIsConfidentiality === '02' || val?.baseProjSetProg === '00') {
currentRules.value = {}
} else {
currentRules.value = {
sections: [{ required: true, message: '请至少添加一个标段' }]
}
}
formRef.value?.clearValidate()
}, { deep: true, immediate: true })
watch(() => props.detail, val => {
if (val) {
if (props.detail?.procures?.length) {
formData.value = {
sections: props.detail?.procures?.map(i => {
return {
...i,
purchaseFile: i.purchaseFile ? reviewFileParam(JSON.parse(i.purchaseFile)) : [],
biddingFile: i.biddingFile ? reviewFileParam(JSON.parse(i.biddingFile)) : [],
purchaseContract: i.purchaseContract ? reviewFileParam(JSON.parse(i.purchaseContract)) : []
}
}) || [{
purchaseFile: [],
biddingFile: [],
purchaseContract: []
}]
}
}
}
})
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="currentRules"
label-position="top"
label-suffix=":"
scroll-to-error
>
<template v-for="(item,index) in formData.sections" :key="index">
<el-button
v-if="formData.sections?.length>1"
type="danger"
icon="Delete"
link
class="float-right"
@click="del(index)"
>删除</el-button>
<template v-if="basicInfoData?.baseProjIsConfidentiality!=='02'&&basicInfoData?.baseProjSetProg!=='00'">
<el-row :gutter="40">
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-col :span="24">
<el-form-item label="标段名称" :prop="`sections[${index}].baseBidName`" :rules="[{required:true,message:'请填写'}]">
<el-input v-model="formData.sections[index].baseBidName" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购方式" :prop="`sections[${index}].baseProjPurchaseWay`" :rules="[{required:true,message:'请选择'}]">
<el-select v-model="formData.sections[index].baseProjPurchaseWay" class="w-full">
<el-option
v-for="(row,key) in dictionaryList?.filter(i => i.type === 'PURCHASE_METHOD')"
:key="key"
:label="row.label"
:value="row.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算执行确认书编号" :prop="`sections[${index}].basePurchaseCode`">
<el-input
v-model="formData.sections[index].basePurchaseCode"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023">
<template v-if="['01','02','03','04','06'].includes(item.baseProjPurchaseWay)&&baseProjSetYear*1>=2023">
<el-col :span="8">
<el-form-item label="采购代理机构" :prop="`sections[${index}].basePurchasingAgencies`" :rules="[{required:true,message:'请填写'}]">
<el-input
v-model="formData.sections[index].basePurchasingAgencies"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购代理机构统一社会信用代码" :prop="`sections[${index}].baseUnifiedCreditCode`" :rules="[{required:true,message:'请填写'}]">
<el-input
v-model="formData.sections[index].baseUnifiedCreditCode"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
<template v-else>
<el-col :span="8">
<el-form-item label="采购代理机构" :prop="`sections[${index}].basePurchaseCode`">
<el-input
v-model="formData.sections[index].basePurchasingAgencies"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购代理机构统一社会信用代码" :prop="`sections[${index}].baseUnifiedCreditCode`">
<el-input
v-model="formData.sections[index].baseUnifiedCreditCode"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-col :span="8">
<el-form-item
label="中标(成交)时间"
:prop="`sections[${index}].baseWinningBidTime`"
:rules="[{ required: true, message: '请选择' }]"
>
<el-date-picker
v-model="formData.sections[index].baseWinningBidTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="中标(成交)金额"
:prop="`sections[${index}].baseProjPurchaseAmount`"
:rules="[{ required: true, message: '请输入' }]"
>
<el-input-number
v-model="formData.sections[index].baseProjPurchaseAmount"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="中标(成交)供应商名称"
:prop="`sections[${index}].baseConsDeprt`"
:rules="[{ required: true, message: '请输入' }]"
>
<el-input
v-model="formData.sections[index].baseConsDeprt"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="中标(成交)供应商统一社会信用代码" :prop="`sections[${index}].baseConsDeprtUsci`" :rules="[{ required: true, message: '请输入' }]">
<el-input
v-model="formData.sections[index].baseConsDeprtUsci"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023">
<el-col :span="8">
<el-form-item
v-if="basicInfoData?.baseProjSetProg==='05'||baseProjSetYear*1<2023"
label="项目款支付时间"
:prop="`sections[${index}].basePaymentTime`"
>
<el-date-picker
v-model="formData.sections[index].basePaymentTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
<el-form-item
v-else
label="项目款支付时间"
:prop="`sections[${index}].basePaymentTime`"
:rules="[{ required: true, message: '请选择' }]"
>
<el-date-picker
v-model="formData.sections[index].basePaymentTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item v-if="basicInfoData?.baseProjSetProg==='05'||baseProjSetYear*1<2023" label="项目款支付金额" :prop="`sections[${index}].paymentProgress`">
<el-input-number
v-model="formData.sections[index].paymentProgress"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
<el-form-item
v-else
label="项目款支付金额"
:prop="`sections[${index}].paymentProgress`"
:rules="[{ required: true, message: '请选择' }]"
>
<el-input-number
v-model="formData.sections[index].paymentProgress"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
</template>
</el-row>
<el-row>
<template v-if="['05','06','07','00']?.includes(basicInfoData?.baseProjSetProg)">
<el-col :span="8">
<el-form-item
v-if="item.baseProjPurchaseWay==='00'"
label="招标(采购)文件"
:prop="`sections[${index}].purchaseFile`"
>
<el-upload
v-model:file-list="formData.sections[index].purchaseFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].purchaseFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="招标(采购)文件"
:prop="`sections[${index}].purchaseFile`"
:rules="[{required:true,message:'请上传'}]"
>
<el-upload
v-model:file-list="formData.sections[index].purchaseFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].purchaseFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
v-if="item.baseProjPurchaseWay==='00'||item.baseProjPurchaseWay==='05'"
label="中标(成交)通知"
:prop="`sections[${index}].biddingFile`"
>
<el-upload
v-model:file-list="formData.sections[index].biddingFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].biddingFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="中标(成交)通知"
:prop="`sections[${index}].biddingFile`"
:rules="[{required:true,message:'请上传'}]"
>
<el-upload
v-model:file-list="formData.sections[index].biddingFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].biddingFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:on-preview="handleFilePreview"
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="采购合同"
:prop="`sections[${index}].purchaseContract`"
:rules="[{required:true,message:'请上传'}]"
>
<el-upload
v-model:file-list="formData.sections[index].purchaseContract"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].purchaseContract)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</template>
</el-row>
</template>
<template v-else>
<el-row :gutter="40">
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-col :span="24">
<el-form-item label="标段名称" :prop="`sections[${index}].baseBidName`">
<el-input v-model="formData.sections[index].baseBidName" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购方式" :prop="`sections[${index}].baseProjPurchaseWay`" :rules="[{required:false,message:'请选择'}]">
<el-select v-model="formData.sections[index].baseProjPurchaseWay" class="w-full">
<el-option
v-for="(row,key) in dictionaryList?.filter(i => i.type === 'PURCHASE_METHOD')"
:key="key"
:label="row.label"
:value="row.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算执行确认书编号" :prop="`sections[${index}].basePurchaseCode`">
<el-input
v-model="formData.sections[index].basePurchaseCode"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023">
<template v-if="['01','02','03','04','06'].includes(item.baseProjPurchaseWay)&&baseProjSetYear*1>=2023">
<el-col :span="8">
<el-form-item label="采购代理机构" :prop="`sections[${index}].basePurchaseCode`" :rules="[{required:false,message:'请填写'}]">
<el-input
v-model="formData.sections[index].basePurchasingAgencies"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购代理机构统一社会信用代码" :prop="`sections[${index}].baseUnifiedCreditCode`" :rules="[{required:false,message:'请填写'}]">
<el-input
v-model="formData.sections[index].baseUnifiedCreditCode"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
<template v-else>
<el-col :span="8">
<el-form-item label="采购代理机构" :prop="`sections[${index}].basePurchaseCode`">
<el-input
v-model="formData.sections[index].basePurchasingAgencies"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购代理机构统一社会信用代码" :prop="`sections[${index}].baseUnifiedCreditCode`">
<el-input
v-model="formData.sections[index].baseUnifiedCreditCode"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)">
<el-col :span="8">
<el-form-item
label="中标(成交)时间"
:prop="`sections[${index}].baseWinningBidTime`"
:rules="[{ required: false, message: '请选择' }]"
>
<el-date-picker
v-model="formData.sections[index].baseWinningBidTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="中标(成交)金额"
:prop="`sections[${index}].baseProjPurchaseAmount`"
:rules="[{ required: false, message: '请输入' }]"
>
<el-input-number
v-model="formData.sections[index].baseProjPurchaseAmount"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="中标(成交)供应商名称"
:prop="`sections[${index}].baseConsDeprt`"
:rules="[{ required: false, message: '请输入' }]"
>
<el-input
v-model="formData.sections[index].baseConsDeprt"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="中标(成交)供应商统一社会信用代码" :prop="`sections[${index}].baseConsDeprtUsci`" :rules="[{ required: false, message: '请输入' }]">
<el-input
v-model="formData.sections[index].baseConsDeprtUsci"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</template>
<template v-if="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023">
<el-col :span="8">
<el-form-item
v-if="basicInfoData?.baseProjSetProg==='05'||baseProjSetYear*1<2023"
label="项目款支付时间"
:prop="`sections[${index}].basePaymentTime`"
>
<el-date-picker
v-model="formData.sections[index].basePaymentTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
<el-form-item
v-else
label="项目款支付时间"
:prop="`sections[${index}].basePaymentTime`"
:rules="[{ required: false, message: '请选择' }]"
>
<el-date-picker
v-model="formData.sections[index].basePaymentTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item v-if="basicInfoData?.baseProjSetProg==='05'||baseProjSetYear*1<2023" label="项目款支付金额" :prop="`sections[${index}].paymentProgress`">
<el-input-number
v-model="formData.sections[index].paymentProgress"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
<el-form-item
v-else
label="项目款支付金额"
:prop="`sections[${index}].paymentProgress`"
:rules="[{ required: false, message: '请选择' }]"
>
<el-input-number
v-model="formData.sections[index].paymentProgress"
class="input-amount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
>
<template #suffix>万元</template>
</el-input-number>
</el-form-item>
</el-col>
</template>
</el-row>
<el-row>
<template v-if="['05','06','07','00']?.includes(basicInfoData?.baseProjSetProg)">
<el-col :span="8">
<el-form-item
v-if="item.baseProjPurchaseWay==='00'"
label="招标(采购)文件"
:prop="`sections[${index}].purchaseFile`"
>
<el-upload
v-model:file-list="formData.sections[index].purchaseFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].purchaseFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="招标(采购)文件"
:prop="`sections[${index}].purchaseFile`"
:rules="[{required:false,message:'请上传'}]"
>
<el-upload
v-model:file-list="formData.sections[index].purchaseFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].purchaseFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
v-if="item.baseProjPurchaseWay==='00'"
label="中标(成交)通知"
:prop="`sections[${index}].biddingFile`"
>
<el-upload
v-model:file-list="formData.sections[index].biddingFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].biddingFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="中标(成交)通知"
:prop="`sections[${index}].biddingFile`"
:rules="[{required:false,message:'请上传'}]"
>
<el-upload
v-model:file-list="formData.sections[index].biddingFile"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].biddingFile)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="采购合同"
:prop="`sections[${index}].purchaseContract`"
>
<el-upload
v-model:file-list="formData.sections[index].purchaseContract"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].purchaseContract)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
multiple
:limit="10"
>
<el-button type="primary" class="mr-4">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</template>
</el-row>
</template>
<el-divider v-if="index<formData.sections?.length-1" />
</template>
</el-form>
<p>
<el-button
type="primary"
plain
icon="Plus"
class="w-full"
@click="add"
>添加标段</el-button>
</p>
</template>

+ 117
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/relatedIrsAppDialog.vue Datei anzeigen

@@ -0,0 +1,117 @@
<script name="relatedIrsAppDialog" setup>
import { nextTick, ref, watch } from 'vue'
import { applicationList } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'
import store from '@/store'

const userInfo = storeToRefs(store.userStore).userInfo || {},
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object,
column: {
type: Array,
default: () => {
return [
{
type: 'radio',
width: '55',
key: 'appId'
},
{
label: '应用名称',
prop: 'name',
key: 'name'
}
]
}
}
}),
searchForm = ref({
name: undefined
}),
// 表格数据
tableListRef = ref(),
total = ref(0),
tableData = ref([]),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await applicationList({ areaCode: userInfo.value.regionCode, ...searchForm.value })
tableData.value = res.data.records
total.value = res.data.total
await nextTick()
tableListRef.value.setRadio(props?.data?.appId || '')
},
// 搜索
search = () => {
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
reset = () => {
tableListRef.value.pageParams.pageNumber = 1
searchForm.value.name = undefined
getTableData()
},
selectData = ref(),
radioChange = (val) => {
selectData.value = val
},
submit = async () => {
emits('getIrsApp', selectData.value)
emits('close', true)
},
emits = defineEmits(['close', 'getIrsApp'])

watch(() => props.visible, async (val) => {
if (val) {
await nextTick()
await getTableData()
} else {
tableListRef.value.tableRef.clearSelection()
}
})
</script>

<template>
<el-dialog
:model-value="visible"
title="选择项目"
:width="840"
@close="emits('close')"
>
<el-form :model="searchForm" label-suffix=":">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="应用名称">
<el-input v-model="searchForm.name" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="search_btn">
<el-button type="primary" @click="search">搜索</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>

<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:total="total"
row-key="appId"
@radio-change="radioChange"
@get-table-data="getTableData"
/>

<template #footer>
<div class="flex justify-center">
<el-button type="primary" @click="submit">确定</el-button>
<el-button @click="emits('close')">取消</el-button>
</div>
</template>
</el-dialog>
</template>

+ 171
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/relatedProjectDialog.vue Datei anzeigen

@@ -0,0 +1,171 @@
<script name="relatedProjectDialog" setup>
import { nextTick, ref, watch, reactive } from 'vue'
import { list } from '@/http/apis/projectStoreManage/projectStore'

const
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object,
column: {
type: Array,
default: () => {
return [
{
type: 'selection',
reserveSelection: true,
width: '55',
fixed: 'left'
},
{
label: '项目名称',
prop: 'projectName',
key: 'projectName'
},
{
label: '预算年度',
prop: 'projectYear',
key: 'projectYear',
width: 80
}
]
}
}
}),
searchForm = reactive({
projectName: undefined,
projectYear: undefined
}),
// 表格数据
tableListRef = ref(),
total = ref(0),
tableData = ref([]),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await list({
...pageParams,
...searchForm
})
tableData.value = res.data.records
total.value = res.data.total
selectCopyData.value = JSON.parse(JSON.stringify(selectData.value))
if (selectCopyData.value?.length) {
tableData.value && tableData.value.forEach(item => {
const dataIds = selectCopyData.value.map(i => i.id)
if (dataIds.includes(item.id) && !tableListRef.value.getSelectRows().map(i => i.id).includes(item.id)) {
tableListRef.value.toggleRowSelect(item, true)
}
})
}
},
// 搜索
search = () => {
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
reset = () => {
searchForm.projectName = undefined
searchForm.projectYear = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 表格多选
selectData = ref([]),
selectCopyData = ref([]),
selectionChange = (val) => {
const ids = val.map(i => i.id)
tableData.value.forEach(row => {
if (ids.includes(row.id)) {
selectData.value.push(row)
} else {
selectData.value = selectData.value.filter(i => i.id !== row.id)
}
})
},
submit = async () => {
const obj = {}
const data = selectData.value.reduce((cur, next) => {
obj[next.id] ? '' : obj[next.id] = true && cur.push(next)
return cur
}, [])
emits('getProjectList', data)
emits('close', true)
},
emits = defineEmits(['close', 'getProjectList'])

watch(() => props.visible, async (val) => {
if (val) {
await nextTick()
if (props.data?.length) {
selectData.value = props.data.map(i => {
return {
id: i.baseProjId,
projectName: i.baseProjName,
projectYear: i.baseProjSetYear
}
})
}
reset()
} else {
tableListRef.value.tableRef.clearSelection()
}
})
</script>

<template>
<el-dialog
:model-value="visible"
title="选择项目"
:width="840"
@close="emits('close')"
>
<el-form :model="searchForm" label-suffix=":" size="small">
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input v-model="searchForm.projectName" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目预算年度" prop="projectYear">
<el-date-picker
v-model="searchForm.projectYear"
type="year"
value-format="YYYY"
placeholder="请选择"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">搜索</el-button>
<el-button @click="reset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>

<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:total="total"
row-key="id"
@selection-change="selectionChange"
@get-table-data="getTableData"
/>

<template #footer>
<div class="flex justify-center">
<el-button type="primary" @click="submit">确定</el-button>
<el-button @click="emits('close')">取消</el-button>
</div>
</template>
</el-dialog>
</template>

+ 149
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/components/userDialog.vue Datei anzeigen

@@ -0,0 +1,149 @@
<script setup name="userDialog">
import { reactive, ref, watch } from 'vue'
import { userList } from '@/http/apis/systemManage/userManage'

const props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: {
type: Array,
default: undefined
},
params: {
type: Object,
default: () => {
return {}
}
}
}),
emits = defineEmits(['close', 'getUserData']),
column = [
{
type: 'radio',
key: 'userId',
width: 60
},
{
label: '序号',
type: 'index',
width: 60
},
{
label: '姓名',
key: 'name',
prop: 'name'
},
{
label: '所属单位(主职)',
key: 'orgName',
prop: 'orgName',
showOverflowTooltip: true,
width: 250
},
{
label: '手机号码',
key: 'phoneNo',
prop: 'phoneNo',
width: '150'
}

],
tableListRef = ref(),
total = ref(0),
tableData = ref([]),
searchForm = reactive({
name: undefined
}),
getTableData = async (pageParams = tableListRef.value?.pageParams) => {
const res = await userList({
...pageParams,
...searchForm,
...props.params
})
total.value = res.data.total
tableData.value = res.data.records || []
},
search = () => {
getTableData()
},
reset = () => {
searchForm.name = undefined
searchForm.phoneNo = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
userData = ref(),
radioChange = (val) => {
userData.value = val
},
submit = () => {
emits('getUserData', userData.value)
emits('close')
}
watch(
() => props.visible,
async val => {
if (val) {
getTableData()
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="项目负责人/项目联系人"
width="70%"
destroy-on-close
@close="emits('close')"
>
<div class="search mb-16">
<el-form label-suffix=":" :model="searchForm" size="small">
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="用户姓名">
<el-input v-model="searchForm.name" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系电话">
<el-input v-model="searchForm.phoneNo" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="btn">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<table-list
ref="tableListRef"
:column="column"
class="mt-15"
:data="tableData"
:total="total"
row-key="userId"
@radio-change="radioChange"
@get-table-data="getTableData"
/>
<template #footer>
<span class="dialog-footer">
<el-button @click="emits('close')">关闭</el-button>
<el-button
type="primary"
@click="submit"
>
提交
</el-button>
</span>
</template>
</el-dialog>
</template>

+ 281
- 0
src/pages/declareManage/operationProjectRecord/operationProjectEdit/index.vue Datei anzeigen

@@ -0,0 +1,281 @@
<script name="projectCollectionEnter" setup>
import BasicInfo from './components/basicInfo.vue'
import { getCurrentInstance, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { changFilesParam } from '@/utils/uploadAction'
import ProjectDeclareInfo from './components/projectDeclareInfo.vue'
import ApplicationInfo from './components/applicationInfo.vue'
import CoreBusiness from './components/coreBusiness.vue'
import ProjectApprovalInfo from './components/projectApprovalInfo.vue'
import PurchaseInfo from './components/purchaseInfo.vue'
import EmpMaterials from './components/empMaterials.vue'
import { dictionary } from '@/http/apis/projectCollection/projectCollectionEnter'
import { detail, save, draftSave } from '@/http/apis/declareMange/operationProjectRecord'

const { proxy } = getCurrentInstance(),
route = useRoute(),
router = useRouter(),
collapseModal = ['1', '2', '3', '4', '5', '6', '7'],
formRefs = {},
submitLoading = ref(false),
dictionaryList = ref(),
detailData = ref(),
getDetail = async () => {
const id = route.query.type === '1' ? route.query.id : route.query.draftId
const res = await detail(route.query.type, id)
detailData.value = res.data
},
submit = async () => {
submitLoading.value = true
try {
const arr = Object.values(formRefs).map(async i => i?.formRef && await i.formRef.validate())
await Promise.all(arr)
const postData = changePostData()
// const postData = changePostData()
// console.log(postData)
// const formData = formRefs.map(i => i.formData).reduce((result, obj) => ({ ...result, ...obj }), {})
await save(postData)
submitLoading.value = false
proxy.$message.success('提交成功!')
router.go(-1)
} catch (e) {
submitLoading.value = false
}
},
basicInfoData = ref(),
getBasicInfoData = (data) => {
basicInfoData.value = data
},
baseProjSetYear = ref(),
getProYear = (data) => {
baseProjSetYear.value = data
},
approvalInfoData = ref(),
getApprovalInfoData = (data) => {
approvalInfoData.value = data
},

changePostData = () => {
const baseinfo = JSON.parse(JSON.stringify(formRefs['baseinfo'].formData))
const apply = JSON.parse(JSON.stringify(formRefs['apply'].formData))
const application = formRefs['application'] && JSON.parse(JSON.stringify(formRefs['application'].formData)) || {}
const baseCore = formRefs['baseCore'] && JSON.parse(JSON.stringify(formRefs['baseCore'].formData)) || {}
const approve = formRefs['approve'] && JSON.parse(JSON.stringify(formRefs['approve'].formData)) || {}
const procures = formRefs['procures'] && JSON.parse(JSON.stringify(formRefs['procures'].formData)) || []
const cimplement = formRefs['cimplement'] && JSON.parse(JSON.stringify(formRefs['cimplement'].formData)) || []
return {
baseProjId: route.query.id || '',
draftId: route.query.draftId * 1 || '',
baseinfo: {
...baseinfo,
baseProvManDeprtType: baseinfo?.baseProvManDeprtType * 1 || undefined,
baseConstructionType: baseinfo?.baseConstructionType?.join(';')
// baseAreaCode: baseinfo?.baseArea?.baseAreaCode || undefined,
// baseAreaName: baseinfo?.baseArea?.baseAreaName || undefined,
// baseArea: undefined
},
apply: {
...apply,
baseProjStartTime: apply?.baseProjTime?.length ? apply?.baseProjTime[0] + ' 00:00:00' : undefined,
baseProjEndTime: apply?.baseProjTime?.length ? apply?.baseProjTime[1] + ' 00:00:00' : undefined,
baseProjTime: undefined,
baseHistorProjId: apply?.missing ? '' : apply?.baseHistorProjs?.map(i => i.baseProjId)?.join(';'),
baseHistorProjName: apply?.missing ? '' : apply?.baseHistorProjs?.map(i => i.baseProjName)?.join(';'),
baseHistorProjYear: apply?.missing ? '' : apply?.baseHistorProjs?.map(i => i.baseProjSetYear)?.join(';'),
baseProjAmountOri: apply?.baseProjAmountOri?.join(';') || undefined,
baseProjBasis: apply?.baseProjBasis?.map(i => i.value)?.join(';') || undefined,
baseProjBasisFile: apply?.baseProjBasis?.map(i => i.fileList && JSON.stringify(changFilesParam(i.fileList)))?.join(';') || '',
beseExpectedResults: apply?.beseExpectedResults?.length && JSON.stringify(apply.beseExpectedResults) || '',
baseProjApplyFile: ((['01', '02', '04', '05'].includes(baseinfo?.baseProjType) && apply?.baseProjSetYear * 1 >= 2023) || apply?.baseProjSetYear * 1 < 2023) && apply?.baseProjApplyFile?.length ? JSON.stringify(changFilesParam(apply?.baseProjApplyFile)) : '',
baseOperatMaintenFile: apply?.baseOperatMaintenFile?.length ? JSON.stringify(changFilesParam(apply?.baseOperatMaintenFile)) : '',
baseProjOtherFile: apply?.baseProjOtherFile?.length ? JSON.stringify(changFilesParam(apply?.baseProjOtherFile)) : '',
baseHistorProjs: undefined,
...application,
baseProjSysCode: application?.applications?.map(i => i.application.applicationCode).join(';') || '',
baseProjSys: application?.applications?.map(i => i.application.applicationName).join(';') || '',
baseAccountAppName: application?.applications?.map(i => i.baseAccountAppName).join(';') || '',
baseBrainName: application?.applications?.map(i => i.baseBrainName).join(';') || '',
applications: undefined,
...baseCore,
baseCoreBusinessCode: baseCore?.coreBusiness?.map(i => i.id).join(';') || '',
baseCoreBusiness: baseCore?.coreBusiness?.map(i => i.matterName).join(';') || '',
baseCoreBusinessOrg: baseCore?.coreBusiness?.map(i => i.orgName).join(';') || '',
coreBusiness: undefined
},
approve: {
...approve,
baseReviewResults: baseinfo?.baseProjSetProg !== '01' ? approve?.baseReviewResults : '',
baseReviewOpinion: baseinfo?.baseProjSetProg !== '01' ? approve?.baseReviewOpinion : '',
baseReviewCommentsFile: baseinfo?.baseProjSetProg !== '01' ? approve?.baseReviewCommentsFile?.length && JSON.stringify(changFilesParam(approve?.baseReviewCommentsFile)) : '',
equalProtectionLevel: baseinfo?.baseProjIsConfidentiality === '01' && !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.equalProtectionLevel : '',
approvalFile: !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.approvalFile?.length && JSON.stringify(changFilesParam(approve?.approvalFile)) : '',
baseExpertTotalMoney: !['01', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseExpertTotalMoney : '',
baseExpertYearMoney: !['01', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseExpertYearMoney : '',
baseInitialReviewTotalMoney: !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseInitialReviewTotalMoney : '',
baseProjReplyAmount: !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseProjReplyAmount : '',
releaseYearMoney: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) ? approve?.releaseYearMoney : '',
preliminaryDesignScheme: approve?.baseProjReplyAmount >= 5000 && ['04', '05', '06', '07', '00'].includes(baseinfo.baseProjSetProg) ? approve?.preliminaryDesignScheme?.length && JSON.stringify(changFilesParam(approve.preliminaryDesignScheme)) : '',
preliminaryDesignFile: approve?.baseProjReplyAmount >= 5000 && ['04', '05', '06', '07', '00'].includes(baseinfo.baseProjSetProg) ? approve?.preliminaryDesignFile?.length && JSON.stringify(changFilesParam(approve.preliminaryDesignFile)) : ''
},
procures: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && procures?.sections?.map(i => {
return {
...i,
baseBidName: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseBidName || '',
baseProjPurchaseWay: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseProjPurchaseWay || '',
basePurchaseCode: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.basePurchaseCode || '',
basePurchasingAgencies: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.basePurchasingAgencies || '',
baseUnifiedCreditCode: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.baseUnifiedCreditCode || '',
baseWinningBidTime: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseWinningBidTime || '',
baseProjPurchaseAmount: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseProjPurchaseAmount || '',
baseConsDeprt: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseConsDeprt || '',
baseConsDeprtUsci: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseConsDeprtUsci || '',
basePaymentTime: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.basePaymentTime || '',
paymentProgress: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.paymentProgress || '',
purchaseFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.purchaseFile?.length ? JSON.stringify(changFilesParam(i.purchaseFile)) : '',
biddingFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.biddingFile?.length ? JSON.stringify(changFilesParam(i.biddingFile)) : '',
purchaseContract: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.purchaseContract?.length ? JSON.stringify(changFilesParam(i.purchaseContract)) : ''
}
}) || [],
mimplement: {
...cimplement,
baseInitialOpinionFile: cimplement?.baseInitialOpinionFile?.length ? JSON.stringify(changFilesParam(cimplement.baseInitialOpinionFile)) : '',
baseInforLevelFile: ((['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && baseinfo?.baseConstructionType?.includes('01')) || !baseinfo?.baseConstructionType?.includes('01')) && cimplement?.baseInforLevelFile?.length ? JSON.stringify(changFilesParam(cimplement.baseInforLevelFile)) : '',
basePasswAssessFile: (['04', '05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.basePasswAssessFile?.length ? JSON.stringify(changFilesParam(cimplement.basePasswAssessFile)) : '',
baseThirdAcceptFile: cimplement.baseThirdAcceptFile?.length ? JSON.stringify(changFilesParam(cimplement.baseThirdAcceptFile)) : '',
baseCheckFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && cimplement?.baseCheckFile?.length ? JSON.stringify(changFilesParam(cimplement.baseCheckFile)) : '',
baseFinanlAuditFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && approve?.releaseYearMoney * 1 >= 2000 && cimplement?.baseFinanlAuditFile?.length ? JSON.stringify(changFilesParam(cimplement.baseFinanlAuditFile)) : '',
baseUserConsFile: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.baseUserConsFile?.length ? JSON.stringify(changFilesParam(cimplement.baseUserConsFile)) : '',
baseEstaSummFile: cimplement?.baseEstaSummFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseEstaSummFile)) : '',
baseOperatMaintenSummFile: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.baseOperatMaintenSummFile?.length ? JSON.stringify(changFilesParam(cimplement.baseOperatMaintenSummFile)) : '',
baseFinalExpertOpinionFile: baseinfo?.baseProjSetProg === '07' && cimplement.baseFinalExpertOpinionFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseFinalExpertOpinionFile)) : '',
baseEngineerPostpoFile: cimplement?.baseEngineerPostpoFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseEngineerPostpoFile)) : '',
baseEngineerAlterFile: cimplement?.baseEngineerAlterFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseEngineerAlterFile)) : '',
baseChanFile: cimplement?.baseChanFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseChanFile)) : '',
baseBusinessMetrics: cimplement?.baseBusinessMetrics?.length ? JSON.stringify(cimplement?.baseBusinessMetrics) : ''
}
}
},
// 暂存
saveLoading = ref(false),
saveDraft = async () => {
saveLoading.value = true
const postData = changePostData()
try {
await draftSave(postData)
saveLoading.value = false
proxy.$message.success('暂存成功!')
router.go(-1)
} catch (e) {
saveLoading.value = false
}
}
onMounted(async () => {
dictionaryList.value = (await dictionary()).data
if (route.query.id) getDetail()
})

</script>

<template>
<div class="footerPage">
<div>
<el-collapse v-model="collapseModal">
<el-collapse-item name="1" class="mb-16">
<template #title>
<div class="collapse-title">项目基本信息</div>
</template>
<div class="pb-24">
<basic-info
:ref="el=>formRefs['baseinfo']=el"
:detail="detailData"
:dictionary-list="dictionaryList"
@get-basic-info-data="getBasicInfoData"
/>
</div>
</el-collapse-item>
<el-collapse-item name="2" class="mb-16">
<template #title>
<div class="collapse-title">项目申报信息</div>
</template>
<div class="pb-24">
<project-declare-info
:ref="el=>formRefs['apply']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:dictionary-list="dictionaryList"
@get-pro-year="getProYear"
/>
</div>
</el-collapse-item>
<el-collapse-item v-if="!(basicInfoData?.baseConstructionType?.length===1&&basicInfoData?.baseConstructionType.includes('02'))" name="3" class="mb-16">
<template #title>
<div class="collapse-title">项目关联信息</div>
</template>
<div class="pb-24">
<application-info :ref="el=>formRefs['application']=el" :detail="detailData" :basic-info-data="basicInfoData" />
</div>
</el-collapse-item>
<el-collapse-item name="4" class="mb-16">
<template #title>
<div class="collapse-title">核心业务</div>
</template>
<div class="pb-24">
<core-business :ref="el=>formRefs['baseCore']=el" :detail="detailData" :basic-info-data="basicInfoData" />
</div>
</el-collapse-item>
<el-collapse-item v-if="basicInfoData?.baseProjSetProg!=='01'" name="5" class="mb-16">
<template #title>
<div class="collapse-title">项目立项评审信息</div>
</template>
<div class="pb-24">
<project-approval-info
:ref="el=>formRefs['approve']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:dictionary-list="dictionaryList"
@get-approval-info-data="getApprovalInfoData"
/>
</div>
</el-collapse-item>
<el-collapse-item name="6" class="mb-16">
<template #title>
<div class="collapse-title">项目采购、资金支付信息</div>
</template>
<div class="pb-24">
<purchase-info
:ref="el=>formRefs['procures']=el"
:detail="detailData"
:dictionary-list="dictionaryList"
:base-proj-set-year="baseProjSetYear"
:basic-info-data="basicInfoData"
/>
</div>
</el-collapse-item>
<el-collapse-item name="7" class="mb-16">
<template #title>
<div class="collapse-title">实施材料信息</div>
</template>
<div class="pb-24">
<emp-materials
:ref="el=>formRefs['cimplement']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:base-proj-set-year="baseProjSetYear"
:approval-info-data="approvalInfoData"
/>
</div>
</el-collapse-item>
<div class="footer">
<el-button @click="$router.go(-1)"> 返回 </el-button>
<el-button
v-if="route.query.type!=='1'"
type="primary"
:loading="saveLoading"
plain
@click="saveDraft"
> 暂存 </el-button>
<el-button type="primary" :loading="submitLoading" @click="submit"> 提交 </el-button>
</div>
</el-collapse></div>
</div>
</template>

+ 128
- 0
src/pages/declareManage/preExaminationDeclare/components/preExaminationDialog.vue Datei anzeigen

@@ -0,0 +1,128 @@
<script name="approvalDialog" setup>
import { ref, getCurrentInstance, watch } from 'vue'
import { changFilesParam, fileFormatVerification, handleFileSuccess, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction.js'
import store from '@/store'
import { preExamineDeclare } from '@/http/apis/declareMange'
const { proxy } = getCurrentInstance(),
uploadUrl = store.dictStore.uploadUrl,
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: Object
}),
emits = defineEmits(['close']),
loading = ref(false),
dialogForm = ref({
higherLineSuperOrgReviewComments: []
}),
rules = {
'higherLineSuperOrgReviewComments': [{ required: true, message: '请选择' }]
},
dialogFormRef = ref(),
submit = async (formEl) => {
if (!formEl) {
save()
return
}
formEl.validate(async (valid) => {
if (valid) {
save()
}
}
)
},
save = async () => {
loading.value = true
try {
await preExamineDeclare({
projectInfo: {
...dialogForm.value,
higherLineSuperOrgReviewComments: dialogForm.value?.higherLineSuperOrgReviewComments?.length && JSON.stringify(changFilesParam(dialogForm.value.higherLineSuperOrgReviewComments)) || undefined,
id: props.data.id
}
})
proxy.$message.success('发起成功!')
loading.value = false
emits('close', true)
} catch (e) {
loading.value = false
}
}

watch(
() => props.visible,
async val => {
if (val) {
console.log('props.data', props.data)
} else {
dialogForm.value = { higherLineSuperOrgReviewComments: [] }
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="预审申报"
width="600px"
destroy-on-close
@close="emits('close')"
>
<div>
<p>根据《浙江省电子政务重大应用项目联审》要求,提交预审后:</p>
<p>1、市级大于1000万元的重大项目将由省级数改牵头部门及业务主管单位进行联审</p>
<p>2、区县申报项目将由市级数改牵头部门及业务主管单位进行联审,大于500万元的重大项目联审后会提交省里进行备案。</p>
</div>
<template v-if="false">
<p>提交后将发起项目预审流程,确定提交吗?</p>
<el-form
v-if="data.needUploadSuperLineFile"
ref="dialogFormRef"
:model="dialogForm"
:rules="rules"
label-position="top"
label-width="auto"
status-icon
class="mt-16"
>
<el-form-item label="上级条线主管单位审核意见:" prop="higherLineSuperOrgReviewComments">
<el-upload
v-model:file-list="dialogForm.higherLineSuperOrgReviewComments"
class=" w-full"
:action="uploadUrl"
:limit="1"
:on-success="res => handleFileSuccess(res, dialogForm.higherLineSuperOrgReviewComments, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-form>
</template>
<template #footer>
<el-button
type="primary"
:loading="loading"
@click="submit(dialogFormRef)"
>
提交
</el-button>
<el-button
@click="emits('close')"
>
关闭
</el-button>
</template>
</el-dialog>
</template>

+ 261
- 0
src/pages/declareManage/preExaminationDeclare/index.vue Datei anzeigen

@@ -0,0 +1,261 @@
<script setup name="preExaminationDeclare">
import { ref, reactive, onMounted, h } from 'vue'
import { getPreExamineList, declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
import PreExaminationDialog from './components/preExaminationDialog.vue'
import store from '@/store'
const { statusOptions, projectTypeOptions } = store.dictStore.globalDicts || {}
// 搜索栏表单数据
const
router = useRouter(),
searchForm = reactive({
projectName: undefined,
buildUnitName: undefined,
projectType: undefined,
year: undefined,
times: undefined
}),
tableListRef = ref(),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: 200,
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: 80
},
{
label: '申报金额(万元)',
key: 'declaredAmount',
prop: 'declaredAmount',
width: '150'
},
{
label: '申报单位',
key: 'buildOrg',
prop: 'buildOrg',
width: '120',
showOverflowTooltip: true
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '80'
},
{
label: '项目状态',
key: 'status',
prop: 'status',
showOverflowTooltip: true,
width: '180',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${statusOptions[row.status].color}`]
}),
h(
'span',
{
class: `text-${statusOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name + '-' + statusOptions[row.status]?.name
)
]
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '180'
},
{
label: '操作',
slot: 'action',
width: '160',
fixed: 'right'
}
]),
data = ref([]),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await getPreExamineList({
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0] || undefined,
createOnMax: searchForm.times?.[1] || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
search = () => {
getTableData()
},
reset = () => {
searchForm.projectName = undefined
searchForm.buildUnitName = undefined
searchForm.projectType = undefined
searchForm.projectYear = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(2, {
...searchForm,
createOnMin: searchForm.times?.[0] || undefined,
createOnMax: searchForm.times?.[1] || undefined,
times: undefined
}))
},
// 预审申报
preExamDeclare = (data) => {
dialogData.visible = true
dialogData.data = data
},
dialogData = reactive({
visible: undefined,
data: undefined
}),
close = (flag) => {
dialogData.visible = false
flag && getTableData()
},
checkDetail = (data) => {
router.push({ name: 'preExaminationDeclareDetail', query: { id: data.id }})
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-row>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input v-model="searchForm.projectName" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select v-model="searchForm.projectType" placeholder="全部" class="w-full">
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
type="year"
value-format="YYYY"
placeholder="请选择"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="10">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
:editable="false"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="reset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>待申报的项目</span>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>导出</el-button>
</div>
</div>
</template>
<div class="mb-8">
<el-alert
title="温馨提示"
:closable="false"
type="info"
description="一级单位用户有权限进行[申报预审]操作,若您无权操作,请联系您上级单位管理员"
show-icon
class="primary-alert"
/>
</div>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a v-if="scope.row.canPreDeclared" @click="preExamDeclare(scope.row)">申报预审</a>
<a @click="checkDetail(scope.row)">详情</a>
</template>
</table-list>
</el-card>
</el-row>
<pre-examination-dialog :visible="dialogData.visible" :data="dialogData.data" @close="close" />
</template>
<style lang='less' scoped>
.container{
position: relative;
.funcBtn{
position: absolute;
top: 0;
right: 26px;
}
}
:deep(.el-form--inline .el-form-item) {
display: inline-flex;
vertical-align: middle;
margin-right: 8px;
}
</style>

+ 252
- 0
src/pages/declareManage/projectAdjustment/index.vue Datei anzeigen

@@ -0,0 +1,252 @@
<script setup name="projectAdjustment">
import { ref, reactive, onMounted, h } from 'vue'
import { declareExport, projectAdjustmentList } from '@/http/apis/declareMange'
import store from '@/store'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
const { statusOptionsCascader, statusOptions, projectTypeOptions } =
store.dictStore.globalDicts || {},
router = useRouter()
// 搜索栏表单数据
const formInline = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '申报金额(万元)',
key: 'declaredAmount',
prop: 'declaredAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '项目状态',
key: 'status',
prop: 'status',
width: '220',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${statusOptions[row.status]?.color}`]
}),
h(
'span',
{
class: `text-${statusOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name + '-' + statusOptions[row.status]?.name
)
]
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
showOverflowTooltip: true,
width: '200'
},
{
label: '操作',
slot: 'action',
width: '150px',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await projectAdjustmentList({
...pageParams,
...formInline,
createOnMin: formInline.times?.[0],
createOnMax: formInline.times?.[1],
projectYear: formInline.projectYear * 1 || undefined,
status: formInline.status?.[formInline.status.length - 1],
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(2),
// 提交查询
search = () => {
getTableData()
},
// 重置
formReset = () => {
formInline.status = undefined
formInline.projectYear = undefined
formInline.projectName = undefined
formInline.projectType = undefined
formInline.createOnMin = undefined
formInline.createOnMax = undefined
formInline.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(4, {
...formInline,
createOnMin: formInline.times?.[0],
createOnMax: formInline.times?.[1],
projectYear: formInline.projectYear * 1 || undefined,
status: formInline.status?.[formInline.status.length - 1],
times: undefined
}))
},
reDeclare = (row) => {
if (row.status === 20005) {
router.push({ name: 'declarationFinal', query: { id: row.id }})
} else {
router.push({ name: 'declarePage', query: { id: row.id }})
}
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="formInline" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="formInline.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="formInline.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目状态">
<el-cascader
v-model="formInline.status"
class="w-full"
:props="{label:'name',value:'code'}"
:options="statusOptionsCascader.map(i=>{
return {
...i,
children:i?.children?.filter(j=>j.color==='danger')
}
})"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="formInline.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="formInline.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>待调整的项目</span>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>
导出
</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a v-if="scope.row.status!==10009" @click="reDeclare(scope.row)">重新申报</a>
<a @click="router.push({name:'projectDeclareDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
</template>
<style lang="less" scoped></style>

+ 298
- 0
src/pages/declareManage/projectDeclare/declarePage/components/accessory.vue Datei anzeigen

@@ -0,0 +1,298 @@
<script name="accessory" setup>
import { ref } from 'vue'
import { fileFormatVerification, handleFileSuccess, reviewFileParam, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction.js'
import store from '@/store'
defineProps({
detailData: {
type: Object,
default: () => {
return {}
}
},
projectType: {
type: String,
default: ''
},
declareAmount: {
type: Number
}
})
const uploadUrl = store.dictStore.uploadUrl,
formData = ref({
constructionPlanFile: [],
preliminaryPlanFile: [],
mainResponsibilitiesApplicantFile: [],
supportingMaterialsFile: [],
calculationTotalInvestmentFile: [],
projectApplicationForm: [],
mainAccusationDoc: []
}),
formRef = ref(),
rules = {
preliminaryPlanFile: [
{ required: true, message: '请上传初步方案', trigger: 'blur' }
],
supportingMaterialsFile: [
{ required: true, message: '请上传佐证材料', trigger: 'blur' }
],
calculationTotalInvestmentFile: [
{ required: true, message: '请上传项目总投资测算明细', trigger: 'blur' }
],
mainResponsibilitiesApplicantFile: [
{ required: true, message: '请上传申报单位主要职责(单位三定方案)', trigger: 'blur' }
],
projectApplicationForm: [{ required: true, message: '请上传项目申报书' }],
baseResearchReportFile: [{ required: true, message: '请上传可行性研究报告' }],
constructionPlanFile: [{ required: true, message: '请上传建设方案' }],
mainAccusationDoc: [{ required: true, message: '请上传申报单位主要职责(单位三定方案)', trigger: 'blur' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
constructionPlanFile: data.constructionPlanFile ? reviewFileParam(JSON.parse(data.constructionPlanFile)) : [],
preliminaryPlanFile: data.preliminaryPlanFile ? reviewFileParam(JSON.parse(data.preliminaryPlanFile)) : [],
mainResponsibilitiesApplicantFile: data.mainResponsibilitiesApplicantFile ? reviewFileParam(JSON.parse(data.mainResponsibilitiesApplicantFile)) : [],
supportingMaterialsFile: data.supportingMaterialsFile ? reviewFileParam(JSON.parse(data.supportingMaterialsFile)) : [],
baseResearchReportFile: data.baseResearchReportFile ? reviewFileParam(JSON.parse(data.baseResearchReportFile)) : [],
calculationTotalInvestmentFile: data.calculationTotalInvestmentFile ? reviewFileParam(JSON.parse(data.calculationTotalInvestmentFile)) : [],
projectApplicationForm: data.projectApplicationForm ? reviewFileParam(JSON.parse(data.projectApplicationForm)) : [],
baseProjOtherFile: data.baseProjOtherFile ? reviewFileParam(JSON.parse(data.baseProjOtherFile)) : [],
mainAccusationDoc: data.mainAccusationDoc ? reviewFileParam(JSON.parse(data.mainAccusationDoc)) : []
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item label="初步设计方案">
<el-upload
v-model:file-list="formData.preliminaryPlanFile"
class="w-full"
:action="uploadUrl"
:limit="1"
:on-success="res => handleFileSuccess(res, formData.preliminaryPlanFile, true)"
:before-upload="file=>fileFormatVerification(file, {
types: fileTypes
})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="false" :span="12">
<el-form-item
label="佐证材料"
prop="supportingMaterialsFile"
>
<el-upload
v-model:file-list="formData.supportingMaterialsFile"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.supportingMaterialsFile)"
:before-upload="file=>fileFormatVerification(file, {
types: fileTypes
})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="10"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="false" :span="12">
<el-form-item label="项目总投资测算明细" prop="calculationTotalInvestmentFile">
<el-upload
ref="investmentCalculationDetailsRef"
v-model:file-list="formData.calculationTotalInvestmentFile"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.calculationTotalInvestmentFile)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="10"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="false" :span="12">
<el-form-item
label="申报单位主要职责(单位三定方案)"
prop="mainResponsibilitiesApplicantFile"
>
<el-upload
v-model:file-list="formData.mainResponsibilitiesApplicantFile"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.mainResponsibilitiesApplicantFile)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="10"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="projectType!=='03'&&false" :span="12">
<el-form-item label="项目申报书" prop="projectApplicationForm">
<el-upload
v-model:file-list="formData.projectApplicationForm"
class="w-full"
:action="uploadUrl"
:limit="1"
:on-success="res => handleFileSuccess(res, formData.projectApplicationForm, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="projectType!=='03'" :span="12">
<el-form-item label="可行性研究报告" prop="baseResearchReportFile">
<el-upload
v-model:file-list="formData.baseResearchReportFile"
class="w-full"
:action="uploadUrl"
:limit="1"
:on-success="res => handleFileSuccess(res, formData.baseResearchReportFile, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col v-if="$route.name==='declarePlan'||[10012,10013,10016].includes(detailData?.status)" :span="12">
<el-form-item label="建设方案" prop="constructionPlanFile">
<el-upload
v-model:file-list="formData.constructionPlanFile"
class="w-full"
:action="uploadUrl"
:limit="1"
:on-success="res => handleFileSuccess(res, formData.constructionPlanFile, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="其他附件">
<el-upload
ref="baseProjOtherFileRef"
v-model:file-list="formData.baseProjOtherFile"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.baseProjOtherFile)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="10"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="declareAmount>=1000" label="申报单位主要职责文件(单位三定职责)" prop="mainAccusationDoc">
<el-upload
ref="mainAccusationDocRef"
v-model:file-list="formData.mainAccusationDoc"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.mainAccusationDoc)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="10"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 158
- 0
src/pages/declareManage/projectDeclare/declarePage/components/annualPaymentPlan.vue Datei anzeigen

@@ -0,0 +1,158 @@
<script name="annualPaymentPlan" setup>
import { ref } from 'vue'
const formData = ref({}),
formRef = ref(),
moneyValidator = (rule, value, callback) => {
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
} else {
callback()
}
},
rules = {
annualPlanAmount: [
{ required: true, message: '请输入年度支付金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
annualPlanHaveAmount: [
{ required: true, message: '请输入自有资金', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
annualPlanGovOwnFinanceAmount: [
{
required: true,
message: '请输入政府投资-本级财政资金',
trigger: 'blur'
},
{ validator: moneyValidator, trigger: 'blur' }
],
annualPlanGovSuperiorFinanceAmount: [
{
required: true,
message: '请输入政府投资-上级补助资金',
trigger: 'blur'
},
{ validator: moneyValidator, trigger: 'blur' }
],
annualPlanBankLendingAmount: [
{ required: true, message: '请输入银行贷款', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
annualPlanOtherAmount: [{ required: true, message: '请输入其他', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
annualPlanAmount: data.annualPlanAmount,
annualPlanHaveAmount: data.annualPlanHaveAmount,
annualPlanGovOwnFinanceAmount: data.annualPlanGovOwnFinanceAmount,
annualPlanGovSuperiorFinanceAmount: data.annualPlanGovSuperiorFinanceAmount,
annualPlanBankLendingAmount: data.annualPlanBankLendingAmount,
annualPlanOtherAmount: data.annualPlanOtherAmount
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item label="年度支付金额" prop="annualPlanAmount">
<el-input-number
v-model="formData.annualPlanAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="自有资金" prop="annualPlanHaveAmount">
<el-input-number
v-model="formData.annualPlanHaveAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="政府投资-本级财政资金"
prop="annualPlanGovOwnFinanceAmount"
>
<el-input-number
v-model="formData.annualPlanGovOwnFinanceAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="政府投资-上级补助资金"
prop="annualPlanGovSuperiorFinanceAmount"
>
<el-input-number
v-model="formData.annualPlanGovSuperiorFinanceAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="银行贷款" prop="annualPlanBankLendingAmount">
<el-input-number
v-model="formData.annualPlanBankLendingAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="其他" prop="annualPlanOtherAmount">
<el-input-number
v-model="formData.annualPlanOtherAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 460
- 0
src/pages/declareManage/projectDeclare/declarePage/components/appBasicInfo.vue Datei anzeigen

@@ -0,0 +1,460 @@
<script name="appBasicInfo" setup>
import { watch, ref } from 'vue'
import store from '@/store'
import { fileFormatVerification, handleFileSuccess, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction.js'
import { applicationList, piotTasks } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'

const {
accountAppNameOption,
constructionLevel,
applicationType,
businessField,
publisher,
useScope,
digitalModifySystem,
domainBrainAccountOptions
} = store.dictStore.globalDicts || {},
uploadUrl = store.dictStore.uploadUrl,
userInfo = storeToRefs(store.userStore).userInfo || {},
props = defineProps({
data: {
type: Object,
default: null
},
drawerVisible: {
type: Boolean,
default: false
},
isInnovateWholeProvinceShare: {
type: Boolean,
default: false
}
}),
formData = ref({
experimentsFile: []
}),
formRef = ref(),
rules = {
isFirst: [{ required: true, message: '请选择是否为首次建设' }],
applicationName: [
{ required: true, message: '请填写应用名称' }
],

relatedExistsApplication: [{ required: true, message: '请选择IRS注册应用' }],
relatedExistsApplicationCode: [{ required: true, message: '请选择IRS应用编码' }],
pilotTasksName: [{ required: true, message: '请选择试点任务名称' }],
pilotTasksCode: [{ required: true, message: '请选择试点任务编号' }],
importantTaskName: [{ required: true, message: '所属重大应用名称' }],
importantTaskCode: [{ required: true, message: '所属重大应用编码' }],
subSceneApplicationName: [{ required: true, message: '所属子场景应用名称' }],
experimentsFile: [{ required: true, message: '请上传试点文件' }],

applicationType: [{ required: true, message: '请选择应用类型' }],
buildLevel: [{ required: true, message: '请选择建设层级', trigger: 'change' }],
isUniteBuild: [{ required: true, message: '请选择是否为统建应用' }],
unionBuildKind: [{ required: true, message: '请选择统建类型' }],
isDigitalModification: [{ required: true, message: '请选择是否为数改系统' }],
digitalModification: [{ required: true, message: '请选择数改系统' }],
bizDomain: [{ required: true, message: '请选择业务领域' }],
publishSide: [{ required: true, message: '请选择发布端' }],
isAccountAppName: [{ required: true, message: '请选择是否S2一本账名称' }],
accountAppName: [{ required: true, message: '请选择S2一本账名称' }],
domainBrainAccount: [{ required: true, message: '请选择领域“大脑”一本账' }],
isBizCooperate: [{ required: true, message: '请选择是否为业务协同' }],
bizCooperateInfo: [{ required: true, message: '请填写业务协同描述' }],
usesRangeRemark: [{ required: true, message: '请选择使用范围' }],
applicationSummary: [{ required: true, message: '请填写应用简介' }],
applicationRemark: [{ required: true, message: '请填写应用备注' }],
applicationEstimateFile: [{ required: true, message: '请上传总投资测算明细' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 清空校验
clearValidate = () => {
formRef.value.clearValidate()
},
// 获取irs应用列表
applicationOptions = ref([]),
getApplicationOptions = async () => {
const res = await applicationList({ areaCode: userInfo.value.regionCode })
applicationOptions.value = res.data
},
// 获取试点任务列表
piotTasksOptions = ref([]),
getPiotTasksOptions = async () => {
const res = await piotTasks()
piotTasksOptions.value = res.data
},
// 修改关联应用
changeIrsApp = (data) => {
formData.value.relatedExistsApplicationCode = data.applicationCode
},
// 修改试点任务
changePilotTask = (data) => {
formData.value.pilotTasksCode = data.taskCode
formData.value.importantTaskName = data.importantTaskName
formData.value.importantTaskCode = data.importantTaskCode
formData.value.subSceneApplicationName = data.subSceneApplicationName
},
// 修改是否初次建设
changeIsFirst = () => {
if (formData.value.isFirst === 1) {
formData.value.relatedExistsApplication = undefined
formData.value.relatedExistsApplicationCode = undefined
} else {
formData.value.applicationName = undefined
}
}
watch(
() => props.drawerVisible,
val => {
if (val) {
formData.value = {
...props.data,
isFirst: props.data.isFirst || undefined
}
getApplicationOptions()
getPiotTasksOptions()
}
},
{ immediate: true }
)
defineExpose({ validForm, formData, clearValidate })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="20">
<el-col v-if="!props.isInnovateWholeProvinceShare" :span="12">
<el-form-item label="是否初次建设" prop="isFirst" @change="changeIsFirst">
<el-radio-group v-model="formData.isFirst">
<el-radio :label="1">是</el-radio>
<el-radio :label="2">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<template v-if="formData.isFirst===2||props.isInnovateWholeProvinceShare">
<el-col :span="12">
<el-form-item label="关联IRS已注册应用" prop="relatedExistsApplication">
<el-select
v-model="formData.relatedExistsApplication"
class="w-full"
placeholder="请选择"
value-key="applicationCode"
@change="changeIrsApp"
>
<el-option
v-for="(item, index) in applicationOptions"
:key="index"
:label="item.applicationName"
:value="{applicationCode:item.applicationCode,applicationName:item.applicationName}"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="IRS应用编码" prop="relatedExistsApplicationCode">
<el-input v-model="formData.relatedExistsApplicationCode" disabled />
</el-form-item>
</el-col>
</template>
<template v-if="props.isInnovateWholeProvinceShare">
<el-col :span="12">
<el-form-item label="试点任务名称" prop="pilotTasksName">
<el-select
v-model="formData.pilotTasksName"
class="w-full"
placeholder="请选择"
value-key="taskCode"
@change="changePilotTask"
>
<el-option
v-for="(item, index) in piotTasksOptions"
:key="index"
:label="item.taskName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="试点任务编号" prop="pilotTasksCode">
<el-input v-model="formData.pilotTasksCode" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属重大应用名称" prop="importantTaskName">
<el-input v-model="formData.importantTaskName" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属重大应用编码" prop="importantTaskCode">
<el-input v-model="formData.importantTaskCode" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属子场景应用名称" prop="subSceneApplicationName">
<el-input v-model="formData.subSceneApplicationName" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="试点文件" prop="experimentsFile">
<el-upload
ref="preliminaryPlanRef"
v-model:file-list="formData.experimentsFile"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.experimentsFile, true)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</template>
<el-col v-if="formData.isFirst===1&&!props.isInnovateWholeProvinceShare" :span="12">
<el-form-item label="应用名称" prop="applicationName">
<el-input
v-model="formData.applicationName"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="应用类型" prop="applicationType">
<el-select v-model="formData.applicationType" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in applicationType"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="建设层级" prop="buildLevel">
<el-radio-group v-model="formData.buildLevel">
<el-radio
v-for="(item, index) in constructionLevel"
:key="index"
:label="index*1"
>{{ item }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否统建应用" prop="isUniteBuild">
<el-radio-group v-model="formData.isUniteBuild">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="formData.isUniteBuild===1" label="统建类型" prop="unionBuildKind">
<el-radio-group v-model="formData.unionBuildKind">
<el-radio :label="1">全省统建</el-radio>
<el-radio :label="2">全市统建</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否数改系统" prop="isDigitalModification">
<el-radio-group v-model="formData.isDigitalModification">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="formData.isDigitalModification===1" label="数改系统" prop="digitalModification">
<el-select
v-model="formData.digitalModification"
multiple
collapse-tags
collapse-tags-tooltip
placeholder="请选择"
class="w-full"
>
<el-option
v-for="(v, k) in digitalModifySystem"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="业务领域" prop="bizDomain">
<el-select v-model="formData.bizDomain" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in businessField"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发布端" prop="publishSide">
<el-select v-model="formData.publishSide" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in publisher"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否S2一本账名称" prop="isAccountAppName">
<el-radio-group v-model="formData.isAccountAppName">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="formData.isAccountAppName === 1" label="S2一本账名称" prop="accountAppName">
<el-select
v-model="formData.accountAppName"
placeholder="请选择"
class="w-full"
clearable
>
<el-option
v-for="(item, index) in accountAppNameOption"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item v-if="formData.isAccountAppName === 1 && formData.isDigitalModification===1" label="领域“大脑”一本账" prop="domainBrainAccount">
<el-select v-model="formData.domainBrainAccount" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in domainBrainAccountOptions"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否业务协同" prop="isBizCooperate">
<el-radio-group v-model="formData.isBizCooperate">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
v-if="formData.isBizCooperate === 1"
label="业务协同描述"
prop="bizCooperateInfo"
><el-input
v-model="formData.bizCooperateInfo"
:autosize="{ minRows: 2, maxRows: 4 }"
maxlength="2000"
type="textarea"
placeholder="请填写"
/> </el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="使用范围" prop="usesRangeRemark">
<el-cascader
v-model="formData.usesRangeRemark"
:options="useScope"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="应用简介"
prop="applicationSummary"
><el-input
v-model="formData.applicationSummary"
:autosize="{ minRows: 2, maxRows: 4 }"
maxlength="2000"
type="textarea"
placeholder="请填写"
/> </el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="应用备注"
prop="applicationRemark"
><el-input
v-model="formData.applicationRemark"
:autosize="{ minRows: 2, maxRows: 4 }"
maxlength="2000"
type="textarea"
placeholder="请填写"
/> </el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="应用总投资测算明细"
prop="applicationEstimateFile"
>
<el-upload
v-model:file-list="formData.applicationEstimateFile"
class="upload-demo"
:action="uploadUrl"
multiple
:on-success="res => handleFileSuccess(res, formData.applicationEstimateFile, false)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="10"
:on-preview="handleFilePreview"
>
<el-button plain type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 185
- 0
src/pages/declareManage/projectDeclare/declarePage/components/appResourceInfo.vue Datei anzeigen

@@ -0,0 +1,185 @@
<script name="appResourceInfo" setup>
import { ref, watch } from 'vue'
import store from '@/store'
const {
netEnvOptions
} = store.dictStore.globalDicts || {}
const props = defineProps({
data: {
type: Object,
default: null
}
}),
formData = ref({}),
formRef = ref(),
rules = {
useGovCloud: [{ required: true, message: '请选择是否使用政务云资源' }],
cloudsType: [{ required: true, message: '请填写云资源类型' }],
cloudsFoundationSpecifications: [{ required: true, message: '请填写云资源基础规格' }],
cloudsNumber: [{ required: true, message: '请填写云资源台数' }],
cloudsDescription: [{ required: true, message: '请填写云资源台数' }],
netEnv: [{ required: true, message: '请选择网络环境' }],
useCommonData: [{ required: true, message: '请选择是否使用公共数据' }],
dataName: [{ required: true, message: '请输入公共数据名称' }],
useCommonComponent: [{ required: true, message: '请选择是否使用公共组件' }],
commonComponents: [{ required: true, message: '请输入公共组件名称' }],
produceCommonComponent: [{ required: true, message: '请选择是否使用公共组件' }],
produceCommonComponents: [{ required: true, message: '请填写预计组件名称' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 清空校验
clearValidate = () => {
formRef.value.clearValidate()
}
watch(
() => props.data,
val => {
formData.value = {
useGovCloud: props.data.useGovCloud,
cloudsType: props.data.cloudsType,
cloudsFoundationSpecifications: props.data.cloudsFoundationSpecifications,
cloudsNumber: props.data.cloudsNumber,
cloudsDescription: props.data.cloudsDescription,
netEnv: props.data.netEnv,
useCommonData: props.data.useCommonData,
dataName: props.data.dataName,
useCommonComponent: props.data.useCommonComponent,
commonComponents: props.data.commonComponents,
produceCommonComponent: props.data.produceCommonComponent,
produceCommonComponents: props.data.produceCommonComponents
}
},
{ immediate: true, deep: true }
)
defineExpose({ validForm, formData, clearValidate })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="是否使用政务云资源" prop="useGovCloud">
<el-radio-group v-model="formData.useGovCloud">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<template v-if="formData.useGovCloud === 1">
<el-col :span="12">
<el-form-item label="云资源类型" prop="cloudsType">
<el-input
v-model="formData.cloudsType"
placeholder="请填写"
:maxlength="50"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="云资源基础规格" prop="cloudsFoundationSpecifications">
<el-input
v-model="formData.cloudsFoundationSpecifications"
placeholder="请填写"
:maxlength="50"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="云资源台数" prop="cloudsNumber">
<el-input
v-model="formData.cloudsNumber"
placeholder="请填写"
maxlength="6"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="云资源用途描述" prop="cloudsDescription">
<el-input
v-model="formData.cloudsDescription"
placeholder="请填写"
:maxlength="50"
/>
</el-form-item>
</el-col>
</template>
<el-col :span="24">
<el-form-item label="网络环境" prop="netEnv">
<el-radio-group v-model="formData.netEnv">
<el-radio v-for="(v,k) in netEnvOptions" :key="k" :label="k*1">{{ v }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="是否使用公共数据" prop="useCommonData">
<el-radio-group v-model="formData.useCommonData">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item v-if="formData.useCommonData === 1" label="数据名称" prop="dataName">
<el-input
v-model="formData.dataName"
placeholder="请填写"
:maxlength="50"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="是否使用公共组件" prop="useCommonComponent">
<el-radio-group v-model="formData.useCommonComponent">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item v-if="formData.useCommonComponent === 1" label="使用公共组件名称" prop="commonComponents">
<el-input
v-model="formData.commonComponents"
placeholder="请填写"
:maxlength="50"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="是否产生公共组件" prop="produceCommonComponent">
<el-radio-group v-model="formData.produceCommonComponent">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item v-if="formData.produceCommonComponent === 1" label="预计产生组件名称" prop="produceCommonComponents">
<el-input
v-model="formData.produceCommonComponents"
placeholder="请填写"
:maxlength="50"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 85
- 0
src/pages/declareManage/projectDeclare/declarePage/components/appSafeInfo.vue Datei anzeigen

@@ -0,0 +1,85 @@
<script name="appSafeInfo" setup>
import { ref, watch } from 'vue'
import store from '@/store'
const {
insuranceLevel
} = store.dictStore.globalDicts || {}
const props = defineProps({
data: {
type: Object,
default: null
}
}),
formData = ref({}),
formRef = ref(),
rules = {
secrecyGrade: [{ required: true, message: '请选择等保级别' }],
passwordGrade: [{ required: true, message: '密码测评级别' }],
nationalItSpec: [{ required: true, message: '请选择是否符合相关规范' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 清空校验
clearValidate = () => {
formRef.value.clearValidate()
}
watch(
() => props.data,
val => {
formData.value = {
secrecyGrade: props.data.secrecyGrade,
passwordGrade: props.data.passwordGrade,
nationalItSpec: props.data.nationalItSpec
}
},
{ immediate: true, deep: true }
)
defineExpose({ validForm, formData, clearValidate })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="等保级别" prop="secrecyGrade">
<el-radio-group v-model="formData.secrecyGrade">
<el-radio v-for="(v,k) in insuranceLevel" :key="k" :label="k*1">{{ v }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="密码测评级别" prop="passwordGrade">
<el-radio-group v-model="formData.passwordGrade">
<el-radio v-for="(v,k) in insuranceLevel" :key="k" :label="k*1">{{ v }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否符合国家信息技术应用创新相关规范" prop="nationalItSpec">
<el-radio-group v-model="formData.nationalItSpec">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 330
- 0
src/pages/declareManage/projectDeclare/declarePage/components/applicationInfo.vue Datei anzeigen

@@ -0,0 +1,330 @@
<script name="appBasicInfo" setup>
import { watch, ref, getCurrentInstance } from 'vue'
import store from '@/store'
import { applicationList } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'

const {
publisher,
insuranceLevel,
applicationType,
accountAppNameOption,
domainBrainAccountOptions
} = store.dictStore.globalDicts || {},
userInfo = storeToRefs(store.userStore).userInfo || {},
{ proxy } = getCurrentInstance(),
props = defineProps({
data: {
type: Object,
default: null
},
drawerVisible: {
type: Boolean,
default: false
},
isFirst: {
type: Number,
default: undefined
},
coreBusiness: {
type: Array,
default: () => {
return []
}
}
}),
formData = ref({
coreBusinessList: [{}]
}),
formRef = ref(),
rules = {
applicationName: [
{ required: true, message: '请填写应用名称' }
],
relatedExistsApplication: [{ required: true, message: '请选择IRS注册应用' }],
relatedExistsApplicationCode: [{ required: true, message: '请选择IRS应用编码' }],
applicationType: [{ required: true, message: '请选择应用类型' }],
publishSide: [{ required: true, message: '请选择发布端' }],
applicationSummary: [{ required: true, message: '请填写应用简介' }],
secrecyGrade: [{ required: true, message: '请选择等保级别' }],
passwordGrade: [{ required: true, message: '请选择密码测评级别' }],
accountAppName: [{ required: true, message: '请选择' }],
domainBrainAccount: [{ required: true, message: '请选择' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate((valid) => {
callback(valid)
})
},
// 清空校验
clearValidate = () => {
formRef.value.clearValidate()
},
// 获取irs应用列表
applicationOptions = ref([]),
getApplicationOptions = async () => {
const res = await applicationList({ areaCode: userInfo.value.regionCode })
applicationOptions.value = res.data
},
// 修改关联应用
changeIrsApp = (data) => {
formData.value.relatedExistsApplicationCode = data.applicationCode
},
// 添加核心业务
addCore = () => {
if (props.coreBusiness?.length <= formData.value.coreBusinessList?.length) {
proxy.$message.warning(`最多添加${props.coreBusiness?.length || 1}个核心业务`)
return
}
formData.value.coreBusinessList.push({})
},
// 删除核心业务
delCore = (index) => {
formData.value.coreBusinessList.splice(index, 1)
}

watch(
() => props.drawerVisible,
val => {
if (val) {
formData.value = {
...props.data,
coreBusinessList: props.data.coreBusinessList?.length ? props.data.coreBusinessList : [{}]
}
getApplicationOptions()
}
},
{ immediate: true }
)
watch(
() => props.data,
val => {
formData.value = {
...props.data,
coreBusinessList: props.data.coreBusinessList?.length ? props.data.coreBusinessList : [{}]
}
},
{ immediate: true, deep: true }
)
defineExpose({ validForm, formData, clearValidate })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="20">
<template v-if="(props.isFirst===0&&userInfo.regionCode==='331123')||userInfo.regionCode!=='331123'">
<el-col :span="12">
<el-form-item label="关联IRS已注册应用" prop="relatedExistsApplication">
<el-select
v-model="formData.relatedExistsApplication"
class="w-full"
placeholder="请选择"
value-key="applicationCode"
@change="changeIrsApp"
>
<el-option
v-for="(item, index) in applicationOptions"
:key="index"
:label="item.applicationName"
:value="{applicationCode:item.applicationCode,applicationName:item.applicationName}"
/>
</el-select>
<p class="text-12 text-danger" style="line-height: 1.4">温馨提示:首次建设项目请先去IRS平台注册后再关联应用</p>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="IRS应用编码" prop="relatedExistsApplicationCode">
<el-input v-model="formData.relatedExistsApplicationCode" disabled />
</el-form-item>
</el-col>
</template>
<el-col v-else :span="12">
<el-form-item label="应用名称" prop="applicationName">
<el-input
v-model="formData.applicationName"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="应用类型" prop="applicationType">
<el-select v-model="formData.applicationType" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in applicationType"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发布端" prop="publishSide">
<el-select v-model="formData.publishSide" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in publisher"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="应用简介"
prop="applicationSummary"
><el-input
v-model="formData.applicationSummary"
:autosize="{ minRows: 2, maxRows: 4 }"
maxlength="2000"
type="textarea"
placeholder="请填写"
/> </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="一本账重大应用名称">
<el-select
v-model="formData.accountAppName"
placeholder="请选择"
class="w-full"
clearable
>
<el-option
v-for="(item, index) in accountAppNameOption"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="领域“大脑”一本账">
<el-select v-model="formData.domainBrainAccount" placeholder="请选择" class="w-full">
<el-option
v-for="(item, index) in domainBrainAccountOptions"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="等保级别" prop="secrecyGrade">
<el-radio-group v-model="formData.secrecyGrade">
<el-radio v-for="(v,k) in insuranceLevel" :key="k" :label="k*1">{{ v }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="密码测评级别" prop="passwordGrade">
<el-radio-group v-model="formData.passwordGrade">
<el-radio v-for="(v,k) in insuranceLevel" :key="k" :label="k*1">{{ v }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<div
v-for="(item,index) in formData.coreBusinessList"
:key="index"
class="py-24 pr-60 mb-16 relative"
style="background: rgb(245, 248, 250);"
>
<el-row>
<el-col :span="12">
<el-form-item label="核心业务" :prop="`coreBusinessList[${index}].coreBusiness`" :rules="[{required:true,message:'请选择'}]">
<el-select v-model="formData.coreBusinessList[index].coreBusiness" placeholder="请选择核心业务" class="w-full">
<el-option
v-for="(row,key) in props.coreBusiness"
:key="key"
:label="row.matterName"
:value="row.matterName"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="分值" :prop="`coreBusinessList[${index}].score`" :rules="[{required:true,message:'请输入'}]">
<el-input-number
v-model="formData.coreBusinessList[index].score"
class="input-amount f"
placeholder="请填写"
:min="0.01"
:max="10"
:precision="2"
:controls="false"
@mousewheel.prevent
>
<template #suffix>分</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="业务指标名称" :prop="`coreBusinessList[${index}].businessIndicatorName`" :rules="[{required:true,message:'请输入'}]">
<el-input v-model="formData.coreBusinessList[index].businessIndicatorName" :maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="业务指标描述" :prop="`coreBusinessList[${index}].businessIndicatorDescription`" :rules="[{required:true,message:'请输入'}]">
<el-input v-model="formData.coreBusinessList[index].businessIndicatorDescription" :maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="指标设计依据"
:prop="`coreBusinessList[${index}].indexDesignBasis`"
style="margin-bottom: 0"
:rules="[{required:true,message:'请输入'}]"
>
<el-input v-model="formData.coreBusinessList[index].indexDesignBasis" :maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="指标计算方法"
:prop="`coreBusinessList[${index}].indexCalculationMethod`"
style="margin-bottom: 0"
:rules="[{required:true,message:'请输入'}]"
>
<el-input v-model="formData.coreBusinessList[index].indexCalculationMethod" :maxlength="50" placeholder="请填写" />
</el-form-item>
</el-col>
</el-row>
<el-button
v-if="formData.coreBusinessList?.length>1"
type="danger"
link
plain
class="absolute top-10 right-8"
@click="delCore(index)"
>删除</el-button>
</div>
<p>
<el-button
type="primary"
size="small"
icon="Plus"
plain
class="ml-80 block"
@click="addCore"
>添加核心业务</el-button>
</p>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 289
- 0
src/pages/declareManage/projectDeclare/declarePage/components/applications.vue Datei anzeigen

@@ -0,0 +1,289 @@
<script name="applications" setup>
import { getCurrentInstance, ref, h, nextTick } from 'vue'
import AppBasicInfo from './appBasicInfo.vue'
import AppSafeInfo from './appSafeInfo.vue'
import AppResourceInfo from './appResourceInfo.vue'
import { ElMessageBox } from 'element-plus'
import { useRoute } from 'vue-router'
import ApplicationInfo from '@/pages/declareManage/projectDeclare/declarePage/components/applicationInfo.vue'
defineProps({
isInnovateWholeProvinceShare: {
type: Boolean,
default: false
},
isFirst: {
type: Number,
default: undefined
},
coreBusiness: {
type: Array,
default: () => {
return []
}
}
})
const route = useRoute(),
{ proxy } = getCurrentInstance(),
formData = ref({
applicationList: []
}),
formRef = ref(),
rules = {
includeApplication: [
{ required: true, message: '请选择是否包含应用', trigger: 'blur' }
],
applicationList: [
{ required: true, message: '请添加应用', trigger: 'blur' }
]
},
column = [
{
type: 'index',
label: '序号',
width: 60
},
{
label: '应用名称',
key: 'applicationName',
prop: 'applicationName',
render: row => h('span', row.applicationName || row.relatedExistsApplication?.applicationName || '')
},
// {
// label: '数改系统',
// key: 'digitalModification',
// prop: 'digitalModification',
// render: row => h('span', row.digitalModification?.map(i => digitalModifySystem[i]).join(','))
// },
{
label: '操作',
slot: 'action'
}
],
// 删除应用
deleteApplication = (index) => {
proxy.$messageBox
.confirm('确定要删除该项吗?', '提示!', {
type: 'warning'
})
.then(() => {
formData.value.applicationList.splice(index, 1)
})
},
// 编辑、新增应用
drawerVisible = ref(false),
collapseModal = ref(['1', '2', '3']),
applicationData = ref({}),
appBasicInfoRef = ref(),
appSafeInfoRef = ref(),
appResourceInfoRef = ref(),
applicationInfoRef = ref(),
isEdit = ref(false),
appIndex = ref(),
editApplication = async (index, row) => {
isEdit.value = true
appIndex.value = index
applicationData.value = row
drawerVisible.value = true
await nextTick()
applicationInfoRef.value.clearValidate()
},
addApplication = async () => {
isEdit.value = false
applicationData.value = {}
drawerVisible.value = true
await nextTick()
applicationInfoRef.value.clearValidate()
},
handleDrawerClose = () => {
ElMessageBox.confirm('确定要关闭应用编辑页面吗?')
.then(() => {
close()
})
.catch(() => {
})
},
close = () => {
// appSafeInfoRef.value.clearValidate()
// appResourceInfoRef.value.clearValidate()
// appBasicInfoRef.value.clearValidate()
applicationInfoRef.value.formData = {}
applicationInfoRef.value.clearValidate()
drawerVisible.value = false
},
// 暂存
save = () => {
if (!isEdit.value) {
formData.value.applicationList.push({
// ...appBasicInfoRef.value.formData,
// ...appSafeInfoRef.value.formData,
// ...appResourceInfoRef.value.formData
...applicationInfoRef.value.formData
})
} else {
formData.value.applicationList[appIndex.value] = {
// ...appBasicInfoRef.value.formData,
// ...appSafeInfoRef.value.formData,
// ...appResourceInfoRef.value.formData
...applicationInfoRef.value.formData
}
}
close()
},
// 提交
submitApplication = () => {
const form = []
// form.push(new Promise((resolve, reject) => {
// appBasicInfoRef.value.validForm((valid) => {
// if (valid) resolve()
// })
// }))
// form.push(new Promise((resolve, reject) => {
// appSafeInfoRef.value.validForm((valid) => {
// if (valid) resolve()
// })
// }))
// form.push(new Promise((resolve, reject) => {
// appResourceInfoRef.value.validForm((valid) => {
// if (valid) resolve()
// })
// }))
form.push(new Promise((resolve, reject) => {
applicationInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
Promise.all([...form]).then(() => {
save()
})
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
const appname = route.query.isDraft ? 'applicationList' : 'projectApplications'
formData.value = {
includeApplication: data.includeApplication,
applicationList: data[appname]?.length ? data[appname].map(i => {
return {
...i,
relatedExistsApplication: i.relatedExistsApplication ? { applicationCode: i.relatedExistsApplicationCode, applicationName: i.relatedExistsApplication } : undefined
}
}) : []
}
},
// 修改是否包含应用
changeIncludeApplication = () => {
formData.value.applicationList = []
}
defineExpose({ validForm, formData, applicationData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item
label="是否包含应用"
label-width="atuo"
prop="includeApplication"
>
<el-radio-group v-model="formData.includeApplication" @change="changeIncludeApplication">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="formData.includeApplication === 1" :span="24">
<el-form-item label="包含的应用" prop="applicationList">
<el-button
type="primary"
plain
class="w-full mb-10"
icon="Plus"
@click="addApplication"
>添加应用</el-button>
<table-list
class="w-full"
:pagination="false"
:data="formData.applicationList"
:column="column"
>
<template #action="{scope}">
<a
@click="editApplication(scope.$index, scope.row)"
>编辑</a>
<a
class="text-red-400"
@click="deleteApplication(scope.$index)"
>删除</a>
</template>
</table-list>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-drawer
v-model="drawerVisible"
title="添加应用"
:before-close="handleDrawerClose"
:size="1000"
>
<el-collapse v-if="false" v-model="collapseModal">
<el-collapse-item name="1">
<template #title>
<div class="collapse-title">基本信息</div>
</template>
<app-basic-info
ref="appBasicInfoRef"
:data="applicationData"
:is-innovate-whole-province-share="isInnovateWholeProvinceShare"
:drawer-visible="drawerVisible"
/>
</el-collapse-item>
<el-collapse-item name="2">
<template #title>
<div class="collapse-title">安全信息</div>
</template>
<app-safe-info ref="appSafeInfoRef" :data="applicationData" />
</el-collapse-item>
<el-collapse-item name="3">
<template #title>
<div class="collapse-title">资源信息</div>
</template>
<app-resource-info ref="appResourceInfoRef" :data="applicationData" />
</el-collapse-item>
</el-collapse>
<application-info
ref="applicationInfoRef"
:data="applicationData"
:is-first="isFirst"
:core-business="coreBusiness"
:drawer-visible="drawerVisible"
/>
<template #footer>
<div class="applyBottomBtn flexCenter marginTop">
<el-button @click="handleDrawerClose"> 关闭 </el-button>
<el-button type="primary" plain @click="save"> 暂存 </el-button>
<el-button type="primary" @click="submitApplication"> 确定 </el-button>
</div>
</template>
</el-drawer>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 1162
- 0
src/pages/declareManage/projectDeclare/declarePage/components/basicInfo.vue
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 189
- 0
src/pages/declareManage/projectDeclare/declarePage/components/coreBusiness.vue Datei anzeigen

@@ -0,0 +1,189 @@
<script name="coreBusiness" setup>
import { reactive, ref, nextTick } from 'vue'
import { getCoreBusinessData } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'
import store from '@/store'
const props = defineProps({
basicInfoData: {
type: Object
}
})
const userInfo = storeToRefs(store.userStore).userInfo || {},
formData = ref({}),
formRef = ref(),
rules = {
coreBusiness: [{ required: true, message: '请至少选择一个核心业务' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 选择核心业务
selectCoreBusiness = () => {
coreBusinessvisible.value = true
getCoreBusinessTableData({ pageNumber: 1, pageSize: 10 }, true)
},
column = [
{
type: 'index',
label: '序号',
width: 60
},
// {
// label: '业务编号',
// key: 'oid',
// prop: 'oid'
// },
{
label: '业务名称',
key: 'matterName',
prop: 'matterName'
},
{
label: '所属单位',
key: 'orgName',
prop: 'orgName'
}
],
tableListRef = ref(),
coreBusinessData = ref([]),
coreBusinesstotal = ref(0),
column2 = [
{
type: 'selection'
},
// {
// label: '业务编号',
// prop: 'oid',
// key: 'oid'
// },
{
label: '业务名称',
prop: 'matterName',
key: 'matterName'
},
{
label: '所属单位',
prop: 'orgName',
key: 'orgName'
}
],
coreBusinessvisible = ref(false),
getCoreBusinessTableData = async (pageParams = tableListRef.value?.pageParams, flag) => {
var orgCode = []
props?.basicInfoData?.superOrgCode && orgCode.push(props.basicInfoData.superOrgCode)
userInfo.value?.empPosUnitCode && orgCode.push(userInfo.value.empPosUnitCode)
const res = await getCoreBusinessData({
...pageParams,
businessName: coreBusinessParams.businessName,
orgCode: orgCode.join(',')
})
coreBusinessData.value = res.data.data
coreBusinesstotal.value = res.data.total
await nextTick()
if (flag) {
coreBusinessData.value && coreBusinessData.value.forEach(item => {
const dataIds = formData.value.coreBusiness && formData.value.coreBusiness.map(i => i.id) || []
if (dataIds.includes(item.id)) {
tableListRef.value.toggleRowSelect(item, true)
} else {
tableListRef.value.toggleRowSelect(item, false)
}
})
}
},
searchCoreBussiness = () => {
getCoreBusinessTableData()
},
coreBusinessTempotary = ref(),
selectionCoreBusinessChange = (data) => {
coreBusinessTempotary.value = data
},
coreBusinessParams = reactive({
businessName: undefined
}),
handleReset = () => {
coreBusinessParams.businessName = ''
},
confirmCoreBusiness = () => {
formData.value.coreBusiness = coreBusinessTempotary.value
coreBusinessvisible.value = false
},
// 回显
setFormData = (data) => {
formData.value = {
coreBusiness: data.coreBusiness ? JSON.parse(data.coreBusiness) : []
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="0"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="24" class="mb-16">
<el-button type="primary" class="float-right" @click="selectCoreBusiness">
选择核心业务
</el-button>
</el-col>
<el-col :span="24">
<el-form-item prop="coreBusiness">
<table-list
:pagination="false"
style="width: 100%"
:column="column"
:data="formData.coreBusiness"
:empty-temp="false"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-dialog
title="选择核心业务"
:close-on-click-modal="false"
:before-close="()=>coreBusinessvisible=false"
:model-value="coreBusinessvisible"
width="700px"
>
<el-row style="margin-bottom: 16px" :gutter="20">
<el-col :span="12">
<el-input v-model="coreBusinessParams.businessName" placeholder="请输入" />
</el-col>
<el-col :span="12">
<div class="flex">
<el-button type="primary" @click="searchCoreBussiness">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</div>
</el-col>
</el-row>
<table-list
ref="tableListRef"
:column="column2"
:data="coreBusinessData"
:total="coreBusinesstotal"
@selection-change="selectionCoreBusinessChange"
@get-table-data="getCoreBusinessTableData"
/>
<template #footer>
<el-button type="primary" @click="confirmCoreBusiness"> 提交 </el-button>
<el-button @click="coreBusinessvisible = false"> 关闭 </el-button>
</template>
</el-dialog>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 81
- 0
src/pages/declareManage/projectDeclare/declarePage/components/fundsAllocation.vue Datei anzeigen

@@ -0,0 +1,81 @@
<script name="fundsAllocation" setup>
import { ref } from 'vue'
const formData = ref({}),
formRef = ref(),
rules = {
softwareDevelopmentAmount: [{ required: true, message: '请输入软件开发', trigger: 'blur' }],
cloudHardwarePurchaseAmount: [
{ required: true, message: '请输入云资源、硬件配置', trigger: 'blur' }
],
thirdPartyAmount: [{ required: true, message: '请输入第三方服务', trigger: 'blur' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
softwareDevelopmentAmount: data.softwareDevelopmentAmount,
cloudHardwarePurchaseAmount: data.cloudHardwarePurchaseAmount,
thirdPartyAmount: data.thirdPartyAmount
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="8">
<el-form-item label="软件开发" prop="softwareDevelopmentAmount">
<el-input-number
v-model="formData.softwareDevelopmentAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="云资源、硬件配置" prop="cloudHardwarePurchaseAmount">
<el-input-number
v-model="formData.cloudHardwarePurchaseAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="第三方服务" prop="thirdPartyAmount">
<el-input-number
v-model="formData.thirdPartyAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 189
- 0
src/pages/declareManage/projectDeclare/declarePage/components/fundsInfo.vue Datei anzeigen

@@ -0,0 +1,189 @@
<script name="fundsInfo" setup>
import { ref } from 'vue'
defineProps({
detailData: {
type: Object,
default: () => {
return {}
}
}
})
const formData = ref({
}),
formRef = ref(),
moneyValidator = (rule, value, callback) => {
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
} else {
callback()
}
},
rules = {
projectYear: [{ required: true, message: '请选择预算年度' }],
declareAmount: [{ required: true, message: '请输入申报金额', trigger: 'blur' }, { validator: moneyValidator, trigger: 'blur' }],
declareHaveAmount: [{ required: true, message: '请输入自有资金', trigger: 'blur' }, { validator: moneyValidator, trigger: 'blur' }],
declareGovOwnFinanceAmount: [
{
required: true,
message: '请输入政府投资-本级财政资金',
trigger: 'blur'
},
{ validator: moneyValidator, trigger: 'blur' }
],
declareGovSuperiorFinanceAmount: [
{
required: true,
message: '请输入政府投资-上级补助资金',
trigger: 'blur'
},
{ validator: moneyValidator, trigger: 'blur' }
],
declareBankLendingAmount: [{ required: true, message: '请输入银行贷款', trigger: 'blur' }, { validator: moneyValidator, trigger: 'blur' }],
declareOtherAmount: [{ required: true, message: '请输入其他资金', trigger: 'blur' }, { validator: moneyValidator, trigger: 'blur' }],
consultancy: [{ required: true, message: '请填写咨询公司' }],
baseBasisAmountOri: [{ required: true, message: '请填写预算来源说明' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
projectYear: data.projectYear ? data.projectYear + '' : null,
declareAmount: data.declareAmount,
declareHaveAmount: data.declareHaveAmount,
declareGovOwnFinanceAmount: data.declareGovOwnFinanceAmount,
declareGovSuperiorFinanceAmount: data.declareGovSuperiorFinanceAmount,
declareBankLendingAmount: data.declareBankLendingAmount,
declareOtherAmount: data.declareOtherAmount,
baseBasisAmountOri: data.baseBasisAmountOri || '',
consultancy: data.consultancy || ''
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item label="预算年度" prop="projectYear">
<el-date-picker
v-model="formData.projectYear"
:disabled="$route.name==='declarePlan'||[10012,10013,10016].includes(detailData?.status)"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="申报金额" prop="declareAmount">
<el-input-number
v-model="formData.declareAmount"
placeholder="请填写"
:min="0.000001"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="自有资金" prop="declareHaveAmount">
<el-input-number
v-model="formData.declareHaveAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="政府投资-本级财政资金" prop="declareGovOwnFinanceAmount">
<el-input-number
v-model="formData.declareGovOwnFinanceAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="政府投资-上级补助资金" prop="declareGovSuperiorFinanceAmount">
<el-input-number
v-model="formData.declareGovSuperiorFinanceAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
><template #append>万元</template></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="银行贷款" prop="declareBankLendingAmount">
<el-input-number
v-model="formData.declareBankLendingAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="其他资金" prop="declareOtherAmount">
<el-input-number
v-model="formData.declareOtherAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col v-if="($route.name==='declarePlan'||[10012,10013,10016].includes(detailData?.status))&&formData.declareAmount>400" :span="12">
<el-form-item label="咨询公司" prop="consultancy">
<el-input
v-model="formData.consultancy"
placeholder="请填写"
maxlength="100"
/>
</el-form-item>
</el-col>
<el-col v-if="formData.declareOtherAmount>0" :span="24">
<el-form-item label="预算来源说明" prop="baseBasisAmountOri">
<el-input
v-model="formData.baseBasisAmountOri"
type="textarea"
show-word-limit
placeholder="请填写"
:maxlength="150"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 106
- 0
src/pages/declareManage/projectDeclare/declarePage/components/hiddenAppForm.vue Datei anzeigen

@@ -0,0 +1,106 @@
<script setup name="hiddenAppForm">
import { nextTick, ref, watch } from 'vue'
// import appBasicInfo from './appBasicInfo.vue'
// import appSafeInfo from './appSafeInfo.vue'
// import appResourceInfo from './appResourceInfo.vue'
import ApplicationInfo from '@/pages/declareManage/projectDeclare/declarePage/components/applicationInfo.vue'
const props = defineProps({
applicationList: Array,
isFirst: {
type: Number,
default: undefined
}
}),
// appBasicInfoRef = ref(),
// appSafeInfoRef = ref(),
// appResourceInfoRef = ref(),
applicationInfoRef = ref(),
applicationData = ref([]),
validCount = ref(0),
drawerVisible = ref(),
validAllAppForm = async (callback) => {
drawerVisible.value = true
validCount.value = 0
for (const item of props.applicationList) { // 不能用forEach,因为不会等异步的执行完成才执行下一条
await doAsyncOperation(item)
}
setTimeout(async () => {
drawerVisible.value = false
callback(validCount.value === props.applicationList.length)
})
},
doAsyncOperation = async (data) => {
applicationData.value = JSON.parse(JSON.stringify(data))
await nextTick() // 必须nextTick,不然赋值视图上不会更新
return new Promise((resolve, reject) => {
const form = []
// form.push(new Promise((resolve, reject) => {
// appBasicInfoRef.value.validForm((valid) => {
// if (valid) {
// resolve()
// } else {
// reject(false)
// }
// })
// }))
// form.push(new Promise((resolve, reject) => {
// appSafeInfoRef.value.validForm((valid) => {
// if (valid) {
// resolve()
// } else {
// reject(false)
// }
// })
// }))
// form.push(new Promise((resolve, reject) => {
// appResourceInfoRef.value.validForm((valid) => {
// if (valid) {
// resolve()
// } else {
// reject(false)
// }
// })
// }))
form.push(new Promise((resolve, reject) => {
applicationInfoRef.value.validForm((valid) => {
if (valid) {
resolve()
} else {
reject(false)
}
})
}))
Promise.all([...form]).then(() => {
validCount.value++
}).finally(() => {
resolve()
})
})
}
watch(
() => props.applicationList,
() => {
},
{ immediate: true, deep: true }
)
defineExpose({ validAllAppForm })

</script>

<template>
<div style="display: none">
<!-- <app-basic-info-->
<!-- ref="appBasicInfoRef"-->
<!-- :data="applicationData"-->
<!-- :drawer-visible="drawerVisible"-->
<!-- :is-innovate-whole-province-share="isInnovateWholeProvinceShare"-->
<!-- />-->
<!-- <app-safe-info ref="appSafeInfoRef" :data="applicationData" />-->
<!-- <app-resource-info ref="appResourceInfoRef" :data="applicationData" />-->
<application-info
ref="applicationInfoRef"
:data="applicationData"
:is-first="isFirst"
/>
</div>
</template>

+ 103
- 0
src/pages/declareManage/projectDeclare/declarePage/components/newModuleForm.vue Datei anzeigen

@@ -0,0 +1,103 @@
<script name="newModuleForm" setup>
import { fileFormatVerification, handleFileSuccess, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction.js'
import { onMounted, ref } from 'vue'
import store from '@/store'
const
uploadUrl = store.dictStore.uploadUrl,
props = defineProps({
data: {
type: Object,
default: null
}
}),
formData = ref({
formList: []
}),
formRef = ref(),
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
}
onMounted(() => {
formData.value = props.data
})
defineExpose({ validForm, formData })
</script>

<template>
<el-form
v-if="formData&&formData.formList?.length"
ref="formRef"
:model="formData"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
@submit.prevent
>
<el-row :gutter="40">
<el-col
v-for="(eachForm,order) in props.data&&props.data.formList"
:key="order"
:span="12"
>
<el-form-item
:label="eachForm.name"
:prop="`formList[${order}].value`"
:rules="[{
required:eachForm.props.required,
message:'请完善必填内容'
}]"
>
<el-input
v-if="eachForm.props.type === '输入'"
v-model="formData.formList[order].value"
placeholder="请输入"
:maxlength="eachForm.props.maxLength"
/>
<el-input-number
v-else-if="eachForm.props.type === '数值输入'"
v-model="formData.formList[order].value"
placeholder="请输入"
:min="eachForm.props.minNumber"
:max="eachForm.props.maxNumber"
:controls="false"
@mousewheel.prevent
/>
<el-radio-group v-else-if="eachForm.props.type === '单选'" v-model="formData.formList[order].value">
<el-radio v-for="( radioOption,radioIndex ) in eachForm.props.options" :key="radioIndex" :label="radioOption.name">{{ radioOption.name }}</el-radio>
</el-radio-group>
<el-checkbox-group v-else-if="eachForm.props.type === '多选'" v-model="formData.formList[order].value">
<el-checkbox v-for="( checkboxOption,checkboxIndex ) in eachForm.props.options" :key="checkboxIndex" :label="checkboxOption.name">{{ checkboxOption.name }}</el-checkbox>
</el-checkbox-group>
<el-upload
v-else
v-model:file-list="formData.formList[order].value"
class="w-full"
:limit="eachForm.props.fileNumber"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.formList[order].value, false)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 92
- 0
src/pages/declareManage/projectDeclare/declarePage/components/projectImageProgress.vue Datei anzeigen

@@ -0,0 +1,92 @@
<script name="safetyInput" setup>
import { ref } from 'vue'
const formData = ref({}),
formRef = ref(),
rules = {
engineeringSpeedOne: [
{ required: true, message: '请填写第一季度进度', trigger: 'blur' }
],
engineeringSpeedTwo: [
{ required: true, message: '请填写第二季度进度', trigger: 'blur' }
],
engineeringSpeedThree: [
{ required: true, message: '请填写第三季度进度', trigger: 'blur' }
],
engineeringSpeedFour: [
{ required: true, message: '请填写第四季度进度', trigger: 'blur' }
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
engineeringSpeedOne: data.engineeringSpeedOne,
engineeringSpeedTwo: data.engineeringSpeedTwo,
engineeringSpeedThree: data.engineeringSpeedThree,
engineeringSpeedFour: data.engineeringSpeedFour
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item label="第一季度" prop="engineeringSpeedOne">
<el-input
v-model="formData.engineeringSpeedOne"
maxlength="50"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="第二季度" prop="engineeringSpeedTwo">
<el-input
v-model="formData.engineeringSpeedTwo"
maxlength="50"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="第三季度" prop="engineeringSpeedThree">
<el-input
v-model="formData.engineeringSpeedThree"
maxlength="50"
placeholder="请填写"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="第四季度" prop="engineeringSpeedFour">
<el-input
v-model="formData.engineeringSpeedFour"
maxlength="50"
placeholder="请填写"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 53
- 0
src/pages/declareManage/projectDeclare/declarePage/components/projectRemark.vue Datei anzeigen

@@ -0,0 +1,53 @@
<script name="projectRemark" setup>
import { ref } from 'vue'
const formData = ref({}),
formRef = ref(),
rules = {},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
projectRemarks: data.projectRemarks
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item
label="备注"
>
<el-input
v-model="formData.projectRemarks"
maxlength="2000"
type="textarea"
placeholder="请填写"
show-word-limit
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 179
- 0
src/pages/declareManage/projectDeclare/declarePage/components/provincialExamine.vue Datei anzeigen

@@ -0,0 +1,179 @@
<script name="provincialExamine" setup>
import { nextTick, reactive, ref } from 'vue'
import { govStripList } from '@/http/apis/declareMange'
const formData = ref({}),
formRef = ref(),
rules = {
operationManageUnitName: [{ required: true, message: '请选择业务主管部门' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
operationManageUnit: data.operationManageUnit,
operationManageUnitName: ''
}
if (data.operationManageUnit) {
getTableData(true)
}
},
dialogVisible = ref(false),
tableListRef = ref(),
searchForm = reactive({
businessStripName: undefined
}),
showDialog = async () => {
dialogVisible.value = true
getTableData()
},
column = [
{
type: 'selection',
key: 'businessStripCode',
width: '60'
},
{
label: '单位名称',
key: 'businessStripName',
prop: 'businessStripName',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '单位编码',
key: 'businessStripCode',
prop: 'businessStripCode',
minWidth: '150',
showOverflowTooltip: true
}
],
tableData = ref(),
getTableData = async (flag) => {
const res = await govStripList({ ...searchForm })
tableData.value = res.data
await nextTick()
const operationManageUnitName = []
tableData.value && tableData.value.forEach(item => {
const dataIds = formData.value?.operationManageUnit?.split(',') || []
if (dataIds.includes(item.businessStripCode)) {
if (!flag) {
tableListRef.value.toggleRowSelect(item, true)
} else {
operationManageUnitName.push(item.businessStripName)
}
}
})
if (flag) {
formData.value.operationManageUnitName = operationManageUnitName.join(',') || ''
}
},
reset = () => {
searchForm.businessStripName = undefined
getTableData()
},
selectUnit = ref([]),
selectionChange = (val) => {
selectUnit.value = val
},
submit = () => {
dialogVisible.value = false
formData.value.operationManageUnitName = selectUnit.value.map(i => i.businessStripName).join(',')
formData.value.operationManageUnit = selectUnit.value.map(i => i.businessStripCode).join(',')
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-row :gutter="40">
<el-col :span="24">
<el-form-item label="业务主管部门(省级)" prop="operationManageUnitName">
<el-input
v-model="formData.operationManageUnitName"
placeholder="请选择"
readonly
@click="showDialog"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-dialog
:model-value="dialogVisible"
title="上级条线主管单位"
width="60%"
@close="dialogVisible = false"
>
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
class="mb-16"
>
<el-col :span="8">
<el-form-item label="单位名称">
<el-input
v-model="searchForm.businessStripName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="getTableData"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:pagination="false"
style="height: 600px;overflow: auto"
@get-table-data="getTableData"
@selection-change="selectionChange"
/>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
<el-button
type="primary"
@click="submit"
>
提交
</el-button>
</span>
</template>
</el-dialog>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 81
- 0
src/pages/declareManage/projectDeclare/declarePage/components/reviewCheck.vue Datei anzeigen

@@ -0,0 +1,81 @@
<script name="reviewCheck" setup>
import { ref } from 'vue'

const props = defineProps({
detailData: {
type: Object,
default: () => {
return {}
}
},
data: {
type: Array,
default: () => []
}
})
const formData = ref({
reviewChecklist: props.data
}),
formRef = ref(),
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
reviewChecklist: data.reviewChecklist
}
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
label-suffix=":"
label-position="top"
scroll-to-error
>
<template v-for="(item,index) in formData.reviewChecklist" :key="index">
<p class="font-bold text-16">{{ item.title }}</p>
<template v-for="(child,key) in item.modules" :key="key">
<el-row :gutter="16" class="items-center">
<el-col :span="9">
<el-form-item :label="child.subTitle">
<el-input v-model="child.content" type="textarea" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="否决情形">
<el-input v-model="child.rejectionSituation" type="textarea" disabled />
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item
label="响应情况"
class="flex-form-item"
style="margin-bottom: 14px"
:prop="`reviewChecklist[${index}].modules[${key}].responseSituation`"
:rules="[{required:true,message:'请输入'}]"
>
<el-input v-model="child.responseSituation" />
</el-form-item>
<el-form-item
label="对应页面"
class="flex-form-item"
style="margin-bottom: 0"
:prop="`reviewChecklist[${index}].modules[${key}].corrPageNum`"
:rules="[{required:true,message:'请输入'}]"
>
<el-input v-model="child.corrPageNum" />
</el-form-item>
</el-col>
</el-row>
</template>
</template>
</el-form>
</template>

+ 143
- 0
src/pages/declareManage/projectDeclare/declarePage/components/safetyInput.vue Datei anzeigen

@@ -0,0 +1,143 @@
<script name="safetyInput" setup>
import { ref, getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance(),
formData = ref({
safetyInput: [{}]
}),
formRef = ref(),
moneyValidator = (rule, value, callback) => {
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
} else {
callback()
}
},
rules = {
safetyInputTitle: [
{ required: true, message: '请输入投入项', trigger: 'blur' }
],
safetyInputDescribe: [
{ required: true, message: '请输入内容描述', trigger: 'blur' }
],
safetyInputAmount: [
{ required: true, message: '请输入金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
safetyInput: data.safetyInputDescribe ? JSON.parse(data.safetyInputDescribe) : [{}]
}
},
// 添加
add = () => {
if (formData.value.safetyInput.length >= 10) {
proxy.$message.warning('最多添加10项')
return
}
formData.value.safetyInput.push({})
},
// 删除
del = (index) => {
formData.value.safetyInput.splice(index, 1)
}
defineExpose({ validForm, formData, setFormData })
</script>

<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<div
v-for="(item,index) in formData.safetyInput"
:key="index"
style="background: #f5f8fa"
class="p-8 mb-16 relative"
>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item
label="投入项"
:prop="`safetyInput[${index}].safetyInputTitle`"
:rules="{
required: true,
message: '请输入',
}"
>
<el-input
v-model="formData.safetyInput[index].safetyInputTitle"
placeholder="请输入"
:maxlength="50"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="内容描述"
:prop="`safetyInput[${index}].safetyInputDescribe`"
:rules="{
required: true,
message: '请输入',
}"
>
<el-input
v-model="formData.safetyInput[index].safetyInputDescribe"
:rows="4"
maxlength="2000"
type="textarea"
show-word-limit
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="金额(万元)"
:prop="`safetyInput[${index}].safetyInputDescribe`"
:rules="{
required: true,
message: '请输入',
}"
>
<el-input-number
v-model="formData.safetyInput[index].safetyInputAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
<span v-if="formData.safetyInput.length>1" class="text-danger absolute right-8 top-8 cursor-pointer" @click="del(index)">删除</span>
</div>
<el-button
type="primary"
icon="Plus"
plain
@click="add"
>添加投入项</el-button>
</el-form>
</template>

<style lang="less">
.el-upload-list{
width: 100%;
}
</style>

+ 870
- 0
src/pages/declareManage/projectDeclare/declarePage/index.vue Datei anzeigen

@@ -0,0 +1,870 @@
<script name="declarePage" setup>
import { getCurrentInstance, nextTick, onMounted, reactive, ref } from 'vue'
import { getFormConfig } from '@/http/apis/systemManage/formConfiguration'
import { useRoute, useRouter } from 'vue-router'
import { storeToRefs } from 'pinia'
import store from '@/store'
import BasicInfo from './components/basicInfo.vue'
import FundsInfo from './components/fundsInfo.vue'
import FundsAllocation from './components/fundsAllocation.vue'
import AnnualPaymentPlan from './components/annualPaymentPlan.vue'
import CoreBusiness from './components/coreBusiness.vue'
import SafetyInput from './components/safetyInput.vue'
import ProjectImageProgress from './components/projectImageProgress.vue'
import Accessory from './components/accessory.vue'
import ProjectRemark from './components/projectRemark.vue'
import NewModuleForm from './components/newModuleForm.vue'
import Applications from './components/applications.vue'
import HiddenAppForm from './components/hiddenAppForm.vue'
import FlowRecordDialog from '@/pages/projectStoreManage/projectStore/projectDetail/components/flowRecordDialog.vue'
import { declareConstructionScheme, getDraftDetail, projectStart, saveDraft } from '@/http/apis/declareMange'
import { projectDetail } from '@/http/apis/projectStoreManage/projectStore'
import { annualPlanModify } from '@/http/apis/projectStoreManage/annualPlanStore'
import { adjustAndHandle, progressDetail } from '@/http/apis/toDoCenter/todoList'
import { changFilesParam, reviewFileParam } from '@/utils/uploadAction'
import { dictionary } from '@/http/apis/projectCollection/projectCollectionEnter'
import ReviewCheck from '@/pages/declareManage/projectDeclare/declarePage/components/reviewCheck.vue'
import { getIsShowReviewCheck } from '@/utils/getIsShowReviewCheck'
import ProvincialExamine from '@/pages/declareManage/projectDeclare/declarePage/components/provincialExamine.vue'

const { proxy } = getCurrentInstance(),
route = useRoute(),
router = useRouter(),
userInfo = storeToRefs(store.userStore).userInfo || {},
formConfig = ref({}),
collapseModal = ref(['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']),
basicInfoRef = ref(), // 基本信息
fundsInfoRef = ref(), // 资金申报情况
fundsAllocationRef = ref(), // 资金分配情况
provincialExamineRef = ref(), // 重大项目省级联审
annualPaymentPlanRef = ref(), // 年度计划支付
coreBusinessRef = ref(), // 核心业务
safetyInputRef = ref(), // 安全投入
projectImageProgressRef = ref(), // 工程形象进度
accessoryRef = ref(), // 附件
projectRemarkRef = ref(), // 备注
newModuleformRef = ref({}), // 新增模块
applicationsRef = ref(), // 应用
hiddenAppFormRef = ref(),
reviewCheckRef = ref(), // 审查清单
// 提交
submitAllForm = () => {
const form = []
if (basicInfoRef.value.formData?.baseProjIsConfidentiality === '02') {
form.push(new Promise((resolve, reject) => {
basicInfoRef.value.validForm((valid) => {
if (valid) {
resolve()
}
})
}))
} else {
form.push(new Promise((resolve, reject) => {
basicInfoRef.value.validForm((valid) => {
if (valid) {
if (fundsInfoRef.value.formData.declareAmount >= 1000 && basicInfoRef.value.formData.baseProvManDeprtType === '2') {
basicInfoRef.value.formData.baseProvManDeprtType = ''
reject('根据《浙江省电子政务重大应用项目联审》要求:大于1000万元的重大项目将由省级数改牵头部门及业务主管单位进行联审,请将上级主管单位修改为您对应条线的省级主管单位。')
} else {
resolve()
}
}
})
}))
form.push(new Promise((resolve, reject) => {
fundsInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
fundsAllocationRef.value.validForm((valid) => {
if (valid) resolve()
})
}))

form.push(new Promise((resolve, reject) => {
annualPaymentPlanRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
formConfig.value.isCoreBusiness && form.push(new Promise((resolve, reject) => {
coreBusinessRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
formConfig.value.isSafetyInput && form.push(new Promise((resolve, reject) => {
safetyInputRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
formConfig.value.isProjectImageProgress && form.push(new Promise((resolve, reject) => {
projectImageProgressRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
getIsShowReviewCheck() && formConfig.value.isReviewChecklist && (route.name === 'declarePlan' || [10012, 10013, 10016].includes(detailData.value?.status)) && form.push(new Promise((resolve, reject) => {
reviewCheckRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
accessoryRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
for (const key in newModuleformRef.value) {
form.push(new Promise((resolve, reject) => {
newModuleformRef.value[key].validForm((valid) => {
if (valid) resolve()
})
}))
}
applicationsRef.value && form.push(new Promise((resolve, reject) => {
applicationsRef.value.validForm((valid) => {
if (valid) resolve()
})
}))

form.push(new Promise((resolve, reject) => {
fundsInfoRef.value.validForm((valid) => {
if (valid) {
const total = floatAdd([fundsInfoRef.value.formData.declareHaveAmount, fundsInfoRef.value.formData.declareGovOwnFinanceAmount, fundsInfoRef.value.formData.declareGovSuperiorFinanceAmount, fundsInfoRef.value.formData.declareBankLendingAmount, fundsInfoRef.value.formData.declareOtherAmount])
if (fundsInfoRef.value.formData.declareAmount > 0 && fundsInfoRef.value.formData.declareAmount === total) { resolve() } else {
reject('资金申报情况:5类资金总和必须等于申报金额')
}
}
})
}))
form.push(new Promise((resolve, reject) => {
fundsAllocationRef.value.validForm(valid => {
if (valid) {
const total = floatAdd([fundsAllocationRef.value.formData.softwareDevelopmentAmount, fundsAllocationRef.value.formData.cloudHardwarePurchaseAmount, fundsAllocationRef.value.formData.thirdPartyAmount])
if (fundsInfoRef.value.formData.declareAmount > 0 && fundsInfoRef.value.formData.declareAmount === total) { resolve() } else {
reject('资金分配情况:3类资金总和必须等于申报金额')
}
}
})
}))
applicationsRef.value?.formData.includeApplication === 1 && form.push(new Promise((resolve, reject) => {
hiddenAppFormRef.value.validAllAppForm((valid) => {
if (valid) {
resolve()
} else {
reject('请完善已添加的应用信息')
}
})
}))
}
Promise.all([...form]).then(async () => {
if (basicInfoRef.value.formData?.baseProjIsConfidentiality === '02') {
saveData(1)
} else {
if (formConfig.value.isSafetyInput) {
const num = safetyInputRef.value?.formData.safetyInput.reduce((acc, cur) => acc + cur.safetyInputAmount, 0)
const precent = (num / fundsInfoRef.value.formData.declareAmount) * 100
if (precent < 5) {
proxy.$messageBox
.confirm(`当前安全投入占比低于5%,确认要提交吗?`, '确认要提交吗?', {
type: 'warning'
})
.then(async () => {
saveData(1)
})
} else {
saveData(1)
}
} else {
saveData(1)
}
}
}).catch(err => {
if (err) {
proxy.$message.warning(err)
}
})
},
floatAdd = (args) => {
const data = []
args.forEach(i => {
try {
data.push(i.toString().split('.')[1].length)
} catch (e) {
data.push(0)
}
})
const m = Math.pow(10, Math.max(...data))
let sum = 0
args.forEach(item => {
sum += item * m
})
return sum / m
},
// 保存草稿
toSaveDraft = async () => {
saveData(2)
},
// 设置应用是否填写完全的值
changeIsFirst = (val) => {
if (applicationsRef.value?.formData && applicationsRef.value?.formData.includeApplication === 1 && applicationsRef.value?.formData?.applicationList?.length) {
applicationsRef.value.formData.applicationList = applicationsRef.value.formData?.applicationList?.map(data => {
return {
...data,
applicationName: val ? data.applicationName : undefined,
relatedExistsApplication: !val ? data.relatedExistsApplication : undefined,
relatedExistsApplicationCode: !val ? data.relatedExistsApplication : undefined
}
})
}
},
saveLoading = ref(false),
submitLoading = ref(false),
saveData = async (type) => {
// const buildBasis = basicInfoRef.value.formData?.buildBasis?.map(i => {
// return {
// ...i,
// fileList: changFilesParam(i.fileList),
// fileName: i.fileList?.[0].name || ''
// }
// })
var postData = {}
if (basicInfoRef.value.formData?.baseProjIsConfidentiality === '02') {
postData = {
isRemarks: formConfig.value.isRemarks,
isOpenCoreBusiness: formConfig.value.isCoreBusiness,
isOpenSafetyInput: formConfig.value.isSafetyInput,
isEngineeringSpeed: formConfig.value.isProjectImageProgress,
isReviewChecklist: formConfig.value.isReviewChecklist,
id: route.query.id * 1 || undefined,
baseProjIsConfidentiality: basicInfoRef.value.formData?.baseProjIsConfidentiality,
projectName: basicInfoRef.value.formData?.projectName,
projectType: basicInfoRef.value.formData?.projectType,
baseConstructionType: basicInfoRef.value.formData?.baseConstructionType?.join(';') || '',
responsibleMan: basicInfoRef.value.formData?.responsibleMan,
responsibleManMobile: basicInfoRef.value.formData?.responsibleManMobile,
contactName: basicInfoRef.value.formData?.contactName,
contactPhone: basicInfoRef.value.formData?.contactPhone,
buildOrgName: basicInfoRef.value.formData?.buildOrgName,
orgCreditCode: basicInfoRef.value.formData?.orgCreditCode,
baseProvManDeprtType: basicInfoRef.value.formData.baseProvManDeprtType * 1 || undefined,
higherSuperOrg: basicInfoRef.value.formData?.higherSuperOrg,
higherSuperOrgCode: basicInfoRef.value.formData?.higherSuperOrgCode,
superOrg: basicInfoRef.value.formData?.superOrg,
superOrgCode: basicInfoRef.value.formData?.superOrgCode,
superOrgCreditCode: basicInfoRef.value.formData?.superOrgCreditCode,
projectYear: basicInfoRef.value.formData?.projectYear * 1,
declareAmount: basicInfoRef.value.formData?.declareAmount,
annualPlanAmount: basicInfoRef.value.formData?.declareAmount
}
} else {
postData = {
isRemarks: formConfig.value.isRemarks,
isOpenCoreBusiness: formConfig.value.isCoreBusiness,
isOpenSafetyInput: formConfig.value.isSafetyInput,
isEngineeringSpeed: formConfig.value.isProjectImageProgress,
isReviewChecklist: formConfig.value.isReviewChecklist,
id: route.query.id * 1 || undefined,
...basicInfoRef.value.formData,
...fundsInfoRef.value.formData,
...fundsAllocationRef.value.formData,
bizDomain: basicInfoRef.value.formData?.isDigitalReform === 1 ? basicInfoRef.value.formData.bizDomain.join(',') : undefined,
baseConstructionType: basicInfoRef.value.formData?.baseConstructionType?.join(';') || '',
baseProvManDeprtType: basicInfoRef.value.formData.baseProvManDeprtType * 1 || undefined,
projectYear: fundsInfoRef.value.formData?.projectYear * 1,
beginTime: basicInfoRef.value.formData?.buildDuration?.length && basicInfoRef.value.formData.buildDuration[0],
endTime: basicInfoRef.value.formData?.buildDuration?.length && basicInfoRef.value.formData.buildDuration[1],
buildDuration: undefined,
lowestLevel: !(basicInfoRef.value.formData?.baseConstructionType?.includes('03') && !basicInfoRef.value.formData?.baseConstructionType?.includes('01')) && basicInfoRef.value.formData?.lowestLevel || '',
// buildBasis: buildBasis && JSON.stringify(buildBasis),
baseProjBasis: basicInfoRef.value.formData?.baseProjBasis?.map(i => i.value)?.join(';') || undefined,
baseProjBasisFile: basicInfoRef.value.formData?.baseProjBasis?.map(i => i.fileList && JSON.stringify(changFilesParam(i.fileList)))?.join(';') || '',
cloudType: basicInfoRef.value.formData?.isCloud && basicInfoRef.value.formData?.cloudType?.length && basicInfoRef.value.formData.cloudType.join(',') || undefined,
baseHistorProjId: basicInfoRef.value.formData?.baseHistorProjs?.map(i => i.baseProjId)?.join(';') || '',
baseHistorProjName: basicInfoRef.value.formData?.baseHistorProjs?.map(i => i.baseProjName)?.join(';') || '',
baseHistorProjYear: basicInfoRef.value.formData?.baseHistorProjs?.map(i => i.baseProjSetYear)?.join(';') || '',
baseHistorProjs: undefined,
beseExpectedResults: basicInfoRef.value.formData?.beseExpectedResults?.length && JSON.stringify(basicInfoRef.value.formData.beseExpectedResults) || '',
baseBasisAmountOri: fundsInfoRef.value?.formData.declareOtherAmount > 0 && fundsInfoRef.value.formData?.baseBasisAmountOri || '',
consultancy: fundsInfoRef.value?.formData.declareAmount > 400 && fundsInfoRef.value.formData?.consultancy || '',
operationManageUnit: fundsInfoRef.value?.formData.declareAmount >= 1000 && provincialExamineRef.value.formData.operationManageUnit || undefined,
...applicationsRef.value?.formData,
...annualPaymentPlanRef.value.formData,
...accessoryRef.value.formData,
constructionPlanFile: accessoryRef.value.formData?.constructionPlanFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.constructionPlanFile)),
preliminaryPlanFile: accessoryRef.value.formData?.preliminaryPlanFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.preliminaryPlanFile)),
mainResponsibilitiesApplicantFile: accessoryRef.value.formData?.mainResponsibilitiesApplicantFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.mainResponsibilitiesApplicantFile)),
supportingMaterialsFile: accessoryRef.value.formData?.supportingMaterialsFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.supportingMaterialsFile)),
calculationTotalInvestmentFile: accessoryRef.value.formData?.calculationTotalInvestmentFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.calculationTotalInvestmentFile)),
projectApplicationForm: basicInfoRef.value.formData?.projectType !== '03' && accessoryRef.value.formData?.projectApplicationForm && JSON.stringify(changFilesParam(accessoryRef.value.formData.projectApplicationForm)) || '',
baseResearchReportFile: basicInfoRef.value.formData?.projectType !== '03' && accessoryRef.value.formData?.baseResearchReportFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.baseResearchReportFile)) || '',
baseProjOtherFile: accessoryRef.value.formData?.baseProjOtherFile && JSON.stringify(changFilesParam(accessoryRef.value.formData.baseProjOtherFile)),
mainAccusationDoc: fundsInfoRef.value?.formData.declareAmount >= 1000 && accessoryRef.value.formData?.mainAccusationDoc && JSON.stringify(changFilesParam(accessoryRef.value.formData.mainAccusationDoc)) || '',
reviewChecklist: reviewCheckRef.value?.formData?.reviewChecklist || undefined
}
if (formConfig.value.isCoreBusiness) {
postData = Object.assign(postData, { ...coreBusinessRef.value.formData, coreBusiness: coreBusinessRef.value.formData.coreBusiness && JSON.stringify(coreBusinessRef.value.formData.coreBusiness) })
}
if (formConfig.value.isSafetyInput) {
// ...safetyInputRef.value.formData
postData = Object.assign(postData, {
safetyInputDescribe: JSON.stringify(safetyInputRef.value.formData.safetyInput)
})
}
if (formConfig.value.isProjectImageProgress) {
postData = Object.assign(postData, { ...projectImageProgressRef.value.formData })
}
if (formConfig.value.isRemark) {
postData = Object.assign(postData, { ...projectRemarkRef.value.formData })
}
if (applicationsRef.value?.formData?.includeApplication && applicationsRef.value?.formData.applicationList?.length) {
postData.applicationList = applicationsRef.value.formData.applicationList.map(i => {
return {
...i,
isFirst: !basicInfoRef.value.formData?.isFirst ? 0 : 1,
relatedExistsApplication: ((!basicInfoRef.value.formData?.isFirst && userInfo.value.regionCode === '331123') || userInfo.regionCode !== '331123') && i.relatedExistsApplication?.applicationName || undefined,
relatedExistsApplicationCode: ((!basicInfoRef.value.formData?.isFirst && userInfo.value.regionCode === '331123') || userInfo.regionCode !== '331123') && i.relatedExistsApplicationCode || undefined,
applicationName: (basicInfoRef.value.formData?.isFirst && userInfo.regionCode === '331123') && i.applicationName || undefined,
coreBusinessList: i.coreBusinessList.map(j => {
return {
...j,
projectId: detailData.value?.projectId || undefined,
projectCode: detailData.value?.projectCode || undefined
}
})
}
})
}
if (formConfig.value.safetyInputModular?.length) {
postData.safetyInputModular = []
for (const key in newModuleformRef.value) {
postData.safetyInputModular.push(
newModuleformRef.value[key].formData
)
}
const safetyInputModular = postData.safetyInputModular.map(i => {
return {
...i,
formList: i.formList.map(j => {
return {
...j,
value: !j.value ? undefined : j.props.type === '文件上传' ? changFilesParam(j.value) : j.value
}
})
}
})
postData.safetyInputModular = JSON.stringify(safetyInputModular)
} else {
postData.safetyInputModular = undefined
}
}

if (type === 1) {
submitLoading.value = true
try {
const data = {
projectInfo: { ...postData, id: !route.query.isDraft ? postData.id : undefined, draftId: route.query.isDraft ? route.query.id * 1 : undefined }
}

if (route.name === 'declarePage') {
await projectStart(!route.query.isDraft && route.query.id ? 2 : 1, data)// 申报
} else if (route.name === 'planEdit') {
await annualPlanModify(data.projectInfo) // 年度计划编辑
} else if (route.name === 'handleAfterGiveBack') {
await adjustAndHandle({
...data,
projectId: route.query.id,
instanceId: route.query.instanceId,
taskId: route.query.taskId
})
} else if (route.name === 'declarePlan') {
await declareConstructionScheme(data)
}
proxy.$message.success('提交成功')
submitLoading.value = false
if (route.name === 'projectDeclare') {
router.push({ name: 'projectDeclare' })
} else {
router.go(-1)
}
} catch (e) {
submitLoading.value = false
}
} else if (type === 2) {
saveLoading.value = true
try {
await saveDraft({
projectInfo: { ...postData },
user: userInfo.value // 测试需要
})
proxy.$message.success('保存成功')
saveLoading.value = false
router.go(-1)
} catch (e) {
saveLoading.value = false
}
}
},
// 回显
detailData = ref({}),
// allApplicationsDone = ref(1), // 所有应用信息校验字段
setData = () => {
basicInfoRef.value.setFormData(detailData.value)
if (detailData.value?.baseProjIsConfidentiality !== '02') {
fundsInfoRef.value.setFormData(detailData.value)
fundsAllocationRef.value.setFormData(detailData.value)
annualPaymentPlanRef.value.setFormData(detailData.value)
formConfig.value.isCoreBusiness && coreBusinessRef.value.setFormData(detailData.value)
formConfig.value.isSafetyInput && safetyInputRef.value.setFormData(detailData.value)
formConfig.value.isProjectImageProgress && projectImageProgressRef.value.setFormData(detailData.value)
accessoryRef.value.setFormData(detailData.value)
formConfig.value.isRemark && projectRemarkRef.value.setFormData(detailData.value)
// detailData.value.safetyInputModular?.length && newModuleformRef.value.setFormData(detailData.value)
applicationsRef.value?.setFormData(detailData.value)
setTimeout(() => {
provincialExamineRef.value?.setFormData(detailData.value)
})
}
},
// 被退回处理
// 获取审核详情
flowData = ref({
processProgressVo: {
progressInfo: [
]
}
}),
lastData = ref(),
getFlowData = async () => {
const res = await progressDetail({ instanceId: route.query.instanceId, projectId: route.query.id, nodeId: route.query.nodeId })
flowData.value = {
...res.data,
processProgressVo: {
...res.data.processProgressVo,
progressInfo: changeProgressInfo(res.data.processProgressVo.progressInfo)
}
}
lastData.value = flowData.value.processProgressVo.progressInfo.slice(-1)[0]?.children?.slice(-1)[0] || flowData.value.processProgressVo.progressInfo.slice(-1)[0]
},
// 审核记录
flowRecordDialogData = reactive({
visible: false,
flowData: undefined
}),
showFlowRecordDialog = (data) => {
flowRecordDialogData.visible = true
flowRecordDialogData.flowData = flowData.value.processProgressVo.progressInfo
},
changeProgressInfo = (data) => {
data.forEach(res => {
if (res.children) {
const nodeIds = []
const newChildren = []
res.children.forEach(child => {
if (!nodeIds.includes(child.nodeId)) {
nodeIds.push(child.nodeId)
newChildren.push({
nodeId: child.nodeId,
approvalMode: child.approvalMode,
name: child.name,
taskId: child.taskId,
nodeType: child.nodeType,
list: [{ ...child }],
userIds: [child.userId]
})
} else {
newChildren.find(i => i.nodeId === child.nodeId).list.push(child)
newChildren.find(i => i.nodeId === child.nodeId).userIds.push(child.userId)
}
})
res.children = newChildren
} else {
res['userIds'] = [res.userId]
}
})
return data
},
closeFlowRecordDialog = () => {
flowRecordDialogData.visible = false
},
dictionaryList = ref([]),
basicInfoData = ref(),
getBasicInfoData = (data) => {
basicInfoData.value = data
}
onMounted(async () => {
dictionaryList.value = (await dictionary()).data
if (!route.query.id) {
const res = await getFormConfig({
regionCode: userInfo.value.regionCode
})
formConfig.value = {
isCoreBusiness: res.data.isCoreBusiness,
isProjectImageProgress: res.data.isProjectImageProgress,
isRemark: res.data.isRemark,
isSafetyInput: res.data.isSafetyInput,
safetyInputModular: res.data.safetyInputModular || []
}
} else {
var res = {}, res1 = {}, reviewChecklist = [], isReviewChecklist = false
if (route.query?.isDraft) {
res = await getDraftDetail({ id: route.query.id })
} else {
res = await projectDetail(route.query.id)
res1 = await getFormConfig({
regionCode: userInfo.value.regionCode
})
if ((route.name === 'declarePlan' || [10012, 10013, 10016].includes(detailData.value?.status))) {
isReviewChecklist = res.data.reviewChecklist && JSON.parse(res.data.reviewChecklist)?.length ? true : res1.data.isReviewChecklist
reviewChecklist = res1.data.reviewChecklist && JSON.parse(res1.data.reviewChecklist) || []
}
}
detailData.value = {
...res.data,
reviewChecklist: res.data.reviewChecklist ? JSON.parse(res.data.reviewChecklist) : undefined
}
const safetyInputModular = res.data.safetyInputModular && JSON.parse(res.data.safetyInputModular).map(i => {
return {
...i,
formList: i.formList.map(j => {
return {
...j,
value: !j.value ? undefined : j.props.type === '文件上传' ? reviewFileParam(j.value) : j.value
}
})
}
})
formConfig.value = {
isCoreBusiness: res.data.isOpenCoreBusiness,
isProjectImageProgress: res.data.isEngineeringSpeed,
isRemark: res.data.isRemark,
isSafetyInput: res.data.isOpenSafetyInput,
safetyInputModular: safetyInputModular || [],
isReviewChecklist,
reviewChecklist
}
nextTick(() => {
setData()
})
if (route.name === 'handleAfterGiveBack') {
getFlowData()
}
}

if (formConfig.value.safetyInputModular?.length) {
let index = 11
formConfig.value.safetyInputModular.forEach(i => {
collapseModal.value.push(index++ + '')
})
}
})
</script>
<template>
<div class="declarePage footerPage">
<!-- 退回编辑-->
<div v-if="route.name==='handleAfterGiveBack'" class="errorTip mb-16">
<el-icon class="icon"><Warning /></el-icon>
<div>
<p class="title">流程被退回</p>
<p>
<span>{{ detailData?.projectName }}的{{ flowData?.processProgressVo?.processDefName }}被退回,请根据审核记录调整项目信息</span>
<el-button
type="primary"
plain
size="small"
class="ml-16"
@click="showFlowRecordDialog"
>查看审核记录</el-button>
</p>
</div>

</div>

<!-- 建设方案申报-->
<el-card v-if="route.name==='declarePlan'" shadow="never" class="mb-16">
<div class="card-header">
<div class="flex justify-between items-center">
<div class="flex-1">
<p class="font-bold">{{ detailData.projectName }}</p>
<div class="mt-8 search">
<el-form label-suffix=":">
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="申报单位">{{ detailData.buildOrgName||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="主管单位">{{ detailData.superOrg||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="创建时间">{{ detailData.createOn||'-' }}</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</div>
</div>
</el-card>
<el-row>
<el-col class="leftCol" :span="24">
<el-collapse v-model="collapseModal">
<el-collapse-item name="1" class="mb-16">
<template #title>
<div class="collapse-title">基本信息</div>
</template>
<div class="p-24">
<basic-info
ref="basicInfoRef"
:detail-data="detailData"
:dictionary-list="dictionaryList"
:declare-amount="fundsInfoRef?.formData.declareAmount"
@change-is-first="changeIsFirst"
@get-basic-info-data="getBasicInfoData"
/>
</div>
</el-collapse-item>
<template v-if="basicInfoRef?.formData?.baseProjIsConfidentiality==='01'">
<el-collapse-item v-if="basicInfoRef?.formData?.baseProjIsConfidentiality==='01'" name="2" class="mb-16">
<template #title>
<div class="collapse-title">
<span>资金申报情况(单位:万元)</span>
<span class="text-info">申报金额 = 自有资金 + 政府投资-本级财政资金 + 政府投资-上级补助资金 + 银行贷款 + 其他资金</span>
</div>
</template>
<div class="p-24">
<funds-info ref="fundsInfoRef" :detail-data="detailData" />
</div>
</el-collapse-item>
<el-collapse-item v-if="basicInfoRef?.formData?.baseProjIsConfidentiality==='01'" name="3" class="mb-16">
<template #title>
<div class="collapse-title">
资金分配情况(单位:万元)
<span class="text-info">软件开发 + 云资源、硬件配置 + 第三方服务 = 申报金额</span>
</div>
</template>
<div class="p-24">
<funds-allocation ref="fundsAllocationRef" />
</div>
</el-collapse-item>
<el-collapse-item v-if="fundsInfoRef?.formData.declareAmount>=1000&&basicInfoRef?.formData?.baseProjIsConfidentiality==='01'" name="10" class="mb-16">
<template #title>
<div class="collapse-title">
重大项目省级联审信息
</div>
</template>
<div class="p-24">
<provincial-examine ref="provincialExamineRef" />
</div>
</el-collapse-item>
<el-collapse-item
v-if="basicInfoRef?.formData?.baseProjIsConfidentiality==='01'"
name="4"
class="mb-16"
>
<template #title>
<div class="collapse-title">
年度支付计划(单位:万元)
<span class="text-info">年度支付金额 = 自有资金 + 政府投资-本级财政资金 + 政府投资-上级补助资金 + 银行贷款 + 其他资金</span>
</div>
</template>
<div class="p-24">
<annual-payment-plan ref="annualPaymentPlanRef" />
</div>
</el-collapse-item>
<el-collapse-item v-if="formConfig.isCoreBusiness" name="5" class="mb-16">
<template #title>
<div class="collapse-title">核心业务</div>
</template>
<div class="p-24">
<core-business ref="coreBusinessRef" :basic-info-data="basicInfoRef?.formData" />
</div>
</el-collapse-item>
<el-collapse-item v-if="formConfig.isSafetyInput" name="6" class="mb-16">
<template #title>
<div class="collapse-title">安全投入</div>
</template>
<div class="p-24">
<safety-input ref="safetyInputRef" />
</div>
</el-collapse-item>
<el-collapse-item v-if="formConfig.isProjectImageProgress" name="7" class="mb-16">
<template #title>
<div class="collapse-title">工程形象进度</div>
</template>
<div class="p-24">
<projectImageProgress ref="projectImageProgressRef" />
</div>
</el-collapse-item>
<el-collapse-item v-if="getIsShowReviewCheck()&&formConfig.isReviewChecklist&&($route.name==='declarePlan'||[10012,10013,10016].includes(detailData?.status))" name="8" class="mb-16">
<template #title>
<div class="collapse-title">审查清单</div>
</template>
<div class="p-24">
<review-check ref="reviewCheckRef" :detail-data="detailData" :data="detailData.reviewChecklist||formConfig.reviewChecklist" />
</div>
</el-collapse-item>
<el-collapse-item name="8" class="mb-16">
<template #title>
<div class="collapse-title">附件</div>
</template>
<div class="p-24">
<accessory
ref="accessoryRef"
:detail-data="detailData"
:project-type="basicInfoRef?.formData?.projectType"
:declare-amount="fundsInfoRef?.formData.declareAmount"
/>
</div>
</el-collapse-item>
<el-collapse-item v-if="formConfig.isRemark" name="9" class="mb-16">
<template #title>
<div class="collapse-title">备注</div>
</template>
<div class="p-24">
<projectRemark ref="projectRemarkRef" />
</div>
</el-collapse-item>
<template v-if="formConfig.safetyInputModular?.length">
<el-collapse-item
v-for="(item,index) in formConfig.safetyInputModular"
:key="index"
:name="11+index+''"
class="mb-16"
>
<template #title>
<div class="collapse-title">{{ item.moduleName }}</div>
</template>
<div class="p-24">
<newModuleForm :ref="el => {newModuleformRef[item.id] = el}" :data="item" />
</div>
</el-collapse-item>
</template>
<el-collapse-item
v-if="($route.name==='declarePlan')||([10012,10016,10013].includes(detailData.status))"
name="4"
class="mb-16"
>
<template #title>
<div class="collapse-title">应用信息</div>
</template>
<div class="p-24">
<applications ref="applicationsRef" :is-first="basicInfoRef?.formData?.isFirst" :core-business="coreBusinessRef?.formData?.coreBusiness" />
</div>
</el-collapse-item>
</template>
</el-collapse>
</el-col>
</el-row>
<hidden-app-form
ref="hiddenAppFormRef"
:application-list="applicationsRef?.formData?.applicationList"
:is-first="basicInfoRef?.formData?.isFirst"
/>
<div class="footer">
<el-button @click="router.go(-1)"> 返回 </el-button>
<el-button
v-if="route.name==='declarePage'&&(!route.query.id||(route.query.id&&route.query.isDraft))"
plain
type="primary"
:loading="saveLoading"
@click="toSaveDraft"
> 暂 存 </el-button>
<el-button type="primary" :loading="submitLoading" @click="submitAllForm"> 提交审核 </el-button>
</div>
</div>
<flow-record-dialog :visible="flowRecordDialogData.visible" :flow-data="flowRecordDialogData.flowData" @close="closeFlowRecordDialog" />
</template>
<style lang="less" scoped>
.declarePage {
//position: relative;

.errorTip{
background: #FFF0EF;
border-radius: 4px;
border: 1px solid #FF9E99;
padding: 18px 24px;
display: flex;
font-size: 14px;
color: rgba(0,0,0,0.85);
.icon{
color:#FF3B30;
font-size: 24px;
margin-right: 8px;
}
.title{
font-size: 20px;
font-weight: 500;
color: rgba(0,0,0,0.85);
line-height: 28px;
margin-bottom: 17px;
}
}
}
:deep(.el-collapse) {
.el-collapse-item__header {
padding: 0px 16px;
font-size: 14px;
}
.el-collapse-item__content {
padding: 16px 16px 16px 0px;
}
.el-collapse-item__header.is-active {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.collapse-title {
flex: 1 0 90%;
order: 1;
.el-collapse-item__header {
flex: 1 0 auto;
order: -1;
}
.el-input-number {
width: 150px !important;
}
}
}
.btnClass {
:deep(.el-form-item__content) {
line-height: 24px;
}
}

.marginTop {
margin-top: 16px;
}
.delClass {
color: #e65151;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
color: rgba(0, 100, 235, 1);
width: 100%;
padding: 2px 0px;
border-radius: 4px;
border: 1px solid rgba(0, 100, 235, 1);
cursor: pointer;
}
.bottomBtn {
width: calc(100% - 201px);
position: fixed;
z-index: 999;
right: 0px;
bottom: 0px;
background: #fff;
padding: 10px 0px;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.applyBottomBtn {
width: 1000px;
position: fixed;
z-index: 999;
right: 0px;
bottom: 0px;
background: #fff;
padding: 10px 0px;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.ocupation{
height: 80px;
}
</style>

+ 61
- 0
src/pages/declareManage/projectDeclare/draftDetails/index.vue Datei anzeigen

@@ -0,0 +1,61 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import projectInfo from '../../../projectStoreManage/projectStore/projectDetail/components/projectInfo.vue'
import { getDraftDetail } from '@/http/apis/declareMange'
const route = useRoute(),
// 项目详情
detailData = ref({
projectName: '12',
status: 10002,
stage: 1
}),
GetProjectDetail = async () => {
const detailRes = await getDraftDetail({ id: route.query.id })
detailData.value = detailRes.data
}
onMounted(() => {
GetProjectDetail()
})
</script>
<template>
<el-row>
<el-card class="w-full">
<div class="card-header">
<span class="font-bold">{{ detailData.projectName }}</span>
<div class="mt-8 search">
<el-form label-suffix=":">
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="申报单位">{{ detailData.buildOrgName||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="主管单位">{{ detailData.superOrg||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="创建时间">{{ detailData.beginTime||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="更新时间">{{ detailData.updatedAt||'-' }}</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</el-card>
<el-card class="mt-10 w-full">
<project-info :detail-data="detailData" />
</el-card>
</el-row>
</template>
<style lang='less' scoped>
.textSize{
font-size: 13px;
margin-top: 10px;
}
.myCardTab{
:deep(.el-tabs__header){
margin: 0;
}
}
</style>

+ 427
- 0
src/pages/declareManage/projectDeclare/index.vue Datei anzeigen

@@ -0,0 +1,427 @@
<script setup name = 'projectDeclare'>
import { ref, reactive, h, onMounted, getCurrentInstance } from 'vue'
import { useRouter } from 'vue-router'
import { getProjectList, draftList, declareExport, removeProject } from '@/http/apis/declareMange'
import store from '@/store'
import useExportExc from '@/utils/useExportExc'
const {
statusOptionsCascader, statusOptions,
projectConTypeOptions
} = store.dictStore.globalDicts || {},
{ proxy } = getCurrentInstance(),
// 搜索栏表单数据
searchForm = reactive({
stage: undefined,
status: undefined,
projectName: '',
projectType: undefined,
projectYear: undefined,
createTiming_: undefined
}),
// 获取项目列表
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const params = {
...pageParams,
...searchForm,
createOnMin: searchForm.createTiming_?.length && searchForm.createTiming_[0],
createOnMax: searchForm.createTiming_?.length && searchForm.createTiming_[1],
projectYear: searchForm.projectYear * 1 || undefined,
createTiming_: undefined,
status: searchForm.status?.[searchForm.status.length - 1]
}
const res = tabStatus.value ? await getProjectList(params) : await draftList(params)
projectData.value = res.data.records
total.value = res.data.total
},
activeName = ref('已申报'),
// 切换栏
handleClick = (tab, event) => {
switch (tab.props.name) {
case '已申报':
tabStatus.value = true
formReset()
break
case '草稿箱':
tabStatus.value = false
formReset()
break
default:
break
}
},
tabStatus = ref(true),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '250',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '100'
},
{
label: '申报金额(万元)',
key: 'declaredAmount',
prop: 'declaredAmount',
width: '120'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '100'
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
showOverflowTooltip: true,
width: '180'
},
{
label: '项目状态',
key: 'status',
prop: 'status',
width: '220',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${row.status && statusOptions[row.status]?.color}`]
}),
h(
'span',
{
class: `text-${row.status && statusOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name + '-' + statusOptions[row.status]?.name
)
]
},
{
label: '操作',
slot: 'action',
width: '200',
fixed: 'right'
}
]),
column2 = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '250',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '100'
},
{
label: '申报金额(万元)',
key: 'declareAmount',
prop: 'declareAmount',
width: '120'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '80'
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
showOverflowTooltip: true,
width: '180'
},
{
label: '操作',
slot: 'action',
width: '160',
fixed: 'right'
}
]),
projectData = ref([]),
// 数据总数
total = ref(1),
editProject = (row) => {
$router.push({ name: 'declarePage', query: { id: row.id, isDraft: 1 }})
},
checkDetail = (detailData) => {
if (tabStatus.value) {
$router.push({ name: 'projectDeclareDetail', query: { id: detailData.id }})
} else {
$router.push({ name: 'draftDetails', query: { id: detailData.id }})
}
},
reDeclare = (row) => {
if (row.status === 20005) {
$router.push({ name: 'reDeclarationFinal', query: { id: row.id }})
} else {
$router.push({ name: 'declarePage', query: { id: row.id }})
}
},
// 提交查询
onSearch = () => {
getTableData()
},
formReset = () => {
searchForm.status = undefined
searchForm.projectName = undefined
searchForm.createTiming_ = undefined
searchForm.projectType = undefined
searchForm.projectYear = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
$router = useRouter(),
// 去项目申报页
toDeclarePage = () => {
$router.push({ name: 'declarePage' })
},
tableListRef = ref(),
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(1, {
...searchForm,
createOnMin: searchForm.createTiming_?.length && searchForm.createTiming_[0],
createOnMax: searchForm.createTiming_?.length && searchForm.createTiming_[1],
projectYear: searchForm.projectYear * 1 || undefined,
status: searchForm.status?.[searchForm.status.length - 1]
}))
},
dictionaryList = ref([]),
// 删除项目
remove = (data) => {
proxy.$messageBox
.confirm(`确定要删除${data.projectName}吗?`, '提示!', {
type: 'warning'
})
.then(async () => {
await removeProject(data.projectCode)
proxy.$message.success('删除成功')
getTableData()
})
}
onMounted(async () => {
tabStatus.value = ref(true)
getTableData()
})
</script>
<template>
<el-row>
<el-card class="w-full search">
<!-- 已申报 -->
<el-form
v-show="tabStatus"
size="small"
:model="searchForm"
label-suffix=":"
>
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称" class="w-full">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectConTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item v-show="tabStatus" label="项目状态">
<el-cascader
v-model="searchForm.status"
class="w-full"
:props="{label:'name',value:'code'}"
:options="statusOptionsCascader"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
class="w-full"
type="year"
format="YYYY"
value-format="YYYY"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建时间" class="w-full">
<el-date-picker
v-model="searchForm.createTiming_"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="onSearch">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 草稿箱 -->
<el-form
v-show="!tabStatus"
label-suffix=":"
:model="searchForm"
size="small"
>
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称" class="w-full">
<el-input
v-model="searchForm.projectName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(item,index) in dictionaryList?.filter(i => i.type === 'PROJECT_TYPE')"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
class="w-full"
type="year"
value-format="YYYY"
placeholder="请选择"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="10">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.createTiming_"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="onSearch">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8 tab-card">
<template #header>
<div class="flex justify-between items-center">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="已申报" name="已申报" />
<el-tab-pane label="草稿箱" name="草稿箱" />
</el-tabs>
<div>
<el-button
v-show="tabStatus"
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>导出</el-button>
<el-button
type="primary"
size="small"
icon="plus"
@click="toDeclarePage"
>项目申报</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="tabStatus ? column : column2"
:data="projectData"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="checkDetail(scope.row)">详情</a>
<a v-if="!tabStatus" @click="editProject(scope.row)">编辑</a>
<a v-if="tabStatus && [10002,10005,10007,10013,20005].includes(scope.row.status)" @click="reDeclare(scope.row)">重新申报</a>
<a v-if="tabStatus && [10007].includes(scope.row.status)" @click="remove(scope.row)">删除</a>
</template>
</table-list>
</el-card>
</el-row>
</template>
<style lang='less' scoped>

</style>


+ 154
- 0
src/pages/declareManage/purchaseResults/components/implementPlanDialog.vue Datei anzeigen

@@ -0,0 +1,154 @@
<script name="implementPlanDialog" setup>
import { getCurrentInstance, nextTick, ref, watch } from 'vue'
import { operationDetail, pushOperation } from '@/http/apis/declareMange/purchaseResults'
import { projectDetail } from '@/http/apis/projectStoreManage/projectStore'

const { proxy } = getCurrentInstance(),
props = defineProps({
visible: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
}
}),
emits = defineEmits(['close']),
formData = ref({}),
formRef = ref(),
validatorTime1 = (rule, value, callback) => {
if (new Date(value).getTime() >= new Date(formData.value.finalInspectionDate).getTime()) {
return callback(new Error('项目开工时间必须在项目终验时间之前'))
} else if (new Date(value).getTime() >= new Date(formData.value.initialInspectionDate).getTime()) {
return callback(new Error('项目开工时间必须在项目初验时间之前'))
} else if (new Date(value).getTime() >= new Date(formData.value.startTrialOperationDate).getTime()) {
return callback(new Error('项目开工时间必须在项目试运行开始时间之前'))
} else {
return callback()
}
},
validatorTime2 = (rule, value, callback) => {
if (new Date(value).getTime() <= new Date(formData.value.projectStartDate).getTime()) {
return callback(new Error('项目初验时间必须在项目开工时间之后'))
} else if (new Date(value).getTime() >= new Date(formData.value.startTrialOperationDate).getTime()) {
return callback(new Error('项目初验时间必须在项目试运行开始时间之前'))
} else if (new Date(value).getTime() >= new Date(formData.value.finalInspectionDate).getTime()) {
return callback(new Error('项目初验时间必须在项目终验时间之前'))
} else {
return callback()
}
},
validatorTime3 = (rule, value, callback) => {
if (new Date(value).getTime() <= new Date(formData.value.projectStartDate).getTime()) {
return callback(new Error('项目试运行开始时间必须在项目开工时间之后'))
} else if (new Date(value).getTime() <= new Date(formData.value.initialInspectionDate).getTime()) {
return callback(new Error('项目试运行开始时间必须在项目初验时间之后'))
} else if (new Date(value).getTime() >= new Date(formData.value.finalInspectionDate).getTime()) {
return callback(new Error('项目初验时间必须在项目终验时间之前'))
} else {
return callback()
}
},
rules = {
projectStartDate: [{ required: true, message: '请输入' }, { validator: validatorTime1 }],
initialInspectionDate: [{ required: true, message: '请选择' }, { validator: validatorTime2 }],
startTrialOperationDate: [{ required: true, message: '请选择' }, { validator: validatorTime3 }],
finalInspectionDate: [{ required: true, message: '请选择' }]
},
loading = ref(false),
submit = async (formEl) => {
if (!formEl) return
await formEl.validate(async valid => {
if (valid) {
loading.value = true
try {
const postData = {
...formData.value,
projectId: props.data.id
}
await pushOperation(postData)
proxy.$message.success('提交成功!')
loading.value = false
emits('close', true)
} catch (e) {
loading.value = false
}
}
})
}
watch(
() => props.visible,
async val => {
if (val) {
await nextTick()
formRef.value.clearValidate()
const detail = await projectDetail(props.data.id)
const res = await operationDetail(props.data.id)
formData.value = res?.data ? {
...res.data,
finalInspectionDate: detail.data.planAcceptanceTime
} : {
finalInspectionDate: detail.data.planAcceptanceTime
}
}
}
)
defineExpose({ formRef })
</script>

<template>
<el-dialog :model-value="visible" title="填写实施计划" @close="emits('close')">
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-suffix=":"
label-width="140"
>
<el-form-item label="项目开工时间" prop="projectStartDate">
<el-date-picker
v-model="formData.projectStartDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择"
/>
</el-form-item>
<el-form-item label="项目初验时间" prop="initialInspectionDate">
<el-date-picker
v-model="formData.initialInspectionDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择"
/>
</el-form-item>
<el-form-item label="试运行开始时间" prop="startTrialOperationDate">
<el-date-picker
v-model="formData.startTrialOperationDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择"
/>
</el-form-item>
<el-form-item label="项目终验时间" prop="finalInspectionDate">
<el-date-picker
v-model="formData.finalInspectionDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择"
disabled
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" :loading="loading" @click="submit(formRef)">提交</el-button>
<el-button @click="emits('close')">关闭</el-button>
</span>
</template>
</el-dialog>
</template>

+ 355
- 0
src/pages/declareManage/purchaseResults/fillPurchasingResult/index.vue Datei anzeigen

@@ -0,0 +1,355 @@
<script setup name="fillPurchasingResult">
import { getCurrentInstance, onMounted, ref } from 'vue'
import { changFilesParam, fileFormatVerification, handleFileSuccess, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction.js'
import store from '@/store'
import { useRouter, useRoute } from 'vue-router'
import { submitResult } from '@/http/apis/declareMange/purchaseResults'
import { dictionary } from '@/http/apis/projectCollection/projectCollectionEnter'

const uploadUrl = store.dictStore.uploadUrl,
{ proxy } = getCurrentInstance(),
router = useRouter(),
route = useRoute()
const formRef = ref(),
// 手机号码校验
checkTelPhone = (rule, value, callback) => {
if (value === '') {
return callback(new Error('请输入正确的手机号'))
} else {
const regIdCard =
/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
if (regIdCard.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的手机号'))
}
}
},
rules = {
bidName: [{ required: true, message: '请输入标段名称' }],
supplier: [{ required: true, message: '请输入供应商' }],
supplierContact: [{ required: true, message: '请输入供应商联系人' }],
supplierContactInfo: [
{ required: true, message: '请输入供应商联系方式' },
{ validator: checkTelPhone, trigger: 'blur' }
],
purchaseMethod: [{ required: true, message: '请选择采购方式' }],
transactionAmount: [{ required: true, message: '请输入成交金额' }],
transactionTime: [{ required: true, message: '请选择成交时间' }],
biddingDoc: [{ required: true, message: '请上传投标文件' }],
bidDoc: [{ required: true, message: '请上传招标文件' }],
acceptanceLetter: [{ required: true, message: '请上传中标通知书' }]
},
formData = ref({
sections: [{
biddingDoc: [],
bidDoc: [],
acceptanceLetter: []
}]
}),
submitLoading = ref(false),
submit = async (formEl) => {
if (!formEl) {
return
}
formEl.validate(async (valid) => {
if (valid) {
submitLoading.value = true
const postData = {
projectId: route.query.id,
tenders: formData.value.sections.map(i => {
return {
...i,
biddingDoc: i.biddingDoc && JSON.stringify(changFilesParam(i.biddingDoc)),
bidDoc: i.bidDoc && JSON.stringify(changFilesParam(i.bidDoc)),
acceptanceLetter: i.acceptanceLetter && JSON.stringify(changFilesParam(i.acceptanceLetter))
}
})
}
try {
await submitResult(postData)
submitLoading.value = false
proxy.$message.success('提交成功')
router.go(-1)
} catch (e) {
submitLoading.value = false
}
}
})
},
// 添加标段
add = () => {
if (formData.value.sections?.length >= 10) {
proxy.$message.warning('最多添加10个标段')
return
}
formData.value.sections.push({
biddingDoc: [],
bidDoc: [],
acceptanceLetter: []
})
},
// 删除标段
del = (index) => {
formData.value.sections.splice(index, 1)
},
dictionaryList = ref([])
onMounted(async () => {
dictionaryList.value = (await dictionary()).data
})
</script>
<template>
<div class="fillPurchasingResult footerPage">
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="180px"
label-suffix=":"
scroll-to-error
>
<el-card v-for="(item,index) in formData.sections" :key="index" class="w-full mb-16">
<template #header>
<div class="flex justify-between">
<span>标段{{ index+1 }}</span>
<el-button
v-if="formData.sections?.length>1"
link
type="danger"
@click="del(index)"
>删除</el-button>
</div>
</template>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item label="标段名称" :prop="`sections[${index}].bidName`" :rules="[{ required: true, message: '请输入' }]">
<el-input v-model="formData.sections[index].bidName" maxlength="50" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商" :prop="`sections[${index}].supplier`" :rules="[{ required: true, message: '请输入' }]">
<el-input v-model="formData.sections[index].supplier" maxlength="50" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商统一社会信用代码" :prop="`sections[${index}].supplierSocialCreditCode`" :rules="[{ required: true, message: '请输入' }]">
<el-input v-model="formData.sections[index].supplierSocialCreditCode" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商联系人" :prop="`sections[${index}].supplierContact`" :rules="[{ required: true, message: '请输入' }]">
<el-input v-model="formData.sections[index].supplierContact" maxlength="50" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商联系方式" :prop="`sections[${index}].supplierContactInfo`" :rules="[{ required: true, message: '请输入' }]">
<el-input v-model="formData.sections[index].supplierContactInfo" maxlength="11" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="采购方式" :prop="`sections[${index}].purchaseMethod`" :rules="[{ required: true, message: '请选择' }]">
<el-radio-group v-model="formData.sections[index].purchaseMethod">
<el-radio
v-for="(row,key) in dictionaryList?.filter(i => i.type === 'PURCHASE_METHOD')"
:key="key"
:label="row.value"
>{{ row.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="成交金额" :prop="`sections[${index}].transactionAmount`" :rules="[{ required: true, message: '请输入' }]">
<el-input-number
v-model="formData.sections[index].transactionAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="成交时间"
:prop="`sections[${index}].transactionTime`"
:rules="[{ required: true, message: '请选择' }]"
>
<el-date-picker
v-model="formData.sections[index].transactionTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item v-if="['00','05'].includes(formData.sections[index].purchaseMethod)" label="采购代理机构">
<el-input v-model="formData.sections[index].agency" maxlength="50" placeholder="请输入" />
</el-form-item>
<el-form-item
v-else
label="采购代理机构"
:prop="`sections[${index}].agency`"
:rules="[{ required: true, message: '请输入' }]"
>
<el-input v-model="formData.sections[index].agency" maxlength="50" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="['00','05'].includes(formData.sections[index].purchaseMethod)" label="采购代理机构统一社会信用代码">
<el-input v-model="formData.sections[index].purchaseSocialCreditCode" placeholder="请输入" />
</el-form-item>
<el-form-item
v-else
label="采购代理机构统一社会信用代码"
:prop="`sections[${index}].purchaseSocialCreditCode`"
:rules="[{ required: true, message: '请输入' }]"
>
<el-input v-model="formData.sections[index].purchaseSocialCreditCode" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预算执行确认书编号">
<el-input v-model="formData.sections[index].budgetExecConfirmNo" placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item
label="投标文件"
:prop="`sections[${index}].biddingDoc`"
:rules="[{ required: true, message: '请上传' }]"
>
<el-upload
v-model:file-list="formData.sections[index].biddingDoc"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].biddingDoc)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="formData.sections[index].purchaseMethod!=='00'"
label="招标文件"
:prop="`sections[${index}].bidDoc`"
:rules="[{ required: true, message: '请上传' }]"
>
<el-upload
v-model:file-list="formData.sections[index].bidDoc"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].bidDoc)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="招标文件"
>
<el-upload
v-model:file-list="formData.sections[index].bidDoc"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].bidDoc)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="!['00','05'].includes(formData.sections[index].purchaseMethod)"
label="中标通知书"
:prop="`sections[${index}].acceptanceLetter`"
:rules="[{ required: true, message: '请上传' }]"
>
<el-upload
v-model:file-list="formData.sections[index].acceptanceLetter"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].acceptanceLetter)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
<el-form-item
v-else
label="中标通知书"
>
<el-upload
v-model:file-list="formData.sections[index].acceptanceLetter"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, formData.sections[index].acceptanceLetter)"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:on-preview="handleFilePreview"
>
<el-button type="primary" plain>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持{{ fileDesc }}文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-card>
<p>
<el-button
type="primary"
plain
icon="Plus"
class="w-full"
@click="add"
>添加标段</el-button>
</p>
</el-form>
<div class="footer">
<el-button @click="router.go(-1)"> 返回 </el-button>
<el-button type="primary" :loading="submitLoading" @click="submit(formRef)"> 提交 </el-button>
</div>
</div>
</template>

+ 252
- 0
src/pages/declareManage/purchaseResults/index.vue Datei anzeigen

@@ -0,0 +1,252 @@
<script setup name="purchaseResults">
import { ref, reactive, onMounted, h } from 'vue'
import { declareExport } from '@/http/apis/declareMange'
import { useRouter } from 'vue-router'
import useExportExc from '@/utils/useExportExc'
import { purchaseList } from '@/http/apis/declareMange/purchaseResults'
import ImplementPlanDialog from '@/pages/declareManage/purchaseResults/components/implementPlanDialog.vue'
import store from '@/store'
const router = useRouter(),
{
statusOptions,
projectTypeOptions
} = store.dictStore.globalDicts || {}
// 搜索栏表单数据
const searchForm = reactive({
projectType: undefined,
status: undefined,
projectYear: undefined,
projectName: undefined,
createOnMin: undefined,
createOnMax: undefined,
times: []
}),
column = reactive([
{
label: '序号',
type: 'index',
width: '80'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '批复金额(万元)',
key: 'approvedAmount',
prop: 'approvedAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: 80
},
{
label: '批复时间',
key: 'approvalDate',
prop: 'approvalDate',
width: '200'
},
{
label: '项目状态',
key: 'status',
prop: 'status',
showOverflowTooltip: true,
width: '180',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${statusOptions[row.status].color}`]
}),
h(
'span',
{
class: `text-${statusOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name + '-' + statusOptions[row.status]?.name
)
]
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '200'
},
{
label: '操作',
slot: 'action',
width: '180',
fixed: 'right'
}
]),
data = ref([]),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await purchaseList({
...pageParams,
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
// 数据总数
total = ref(2),
// 提交查询
search = () => {
getTableData()
},
// 重置
formReset = () => {
searchForm.projectYear = undefined
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.createOnMin = undefined
searchForm.createOnMax = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(6, {
...searchForm,
createOnMin: searchForm.times?.[0],
createOnMax: searchForm.times?.[1],
projectYear: searchForm.projectYear * 1 || undefined,
times: undefined
}))
},
// 实施计划
implementPlanDialogData = reactive({
visible: false,
data: undefined
}),
showImplementPlanDialog = (data) => {
implementPlanDialogData.visible = true
implementPlanDialogData.data = data
},
close = (flag) => {
implementPlanDialogData.visible = false
flag && getTableData()
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-card class="w-full search">
<el-form :model="searchForm" size="small" label-suffix=":">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="btn">
<div class="flex">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="formReset">重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<div>
<el-button
type="primary"
size="small"
plain
:loading="exportLoading"
@click="handleExcel"
>
导出
</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a v-if="scope.row.status===20001" @click="router.push({ name: 'fillPurchasingResult', query: { id: scope.row.id }})">填写采购结果</a>
<a v-if="scope.row.status===20006" @click="showImplementPlanDialog(scope.row)">填写实施计划</a>
<a @click="router.push({name:'purchasingResultDetail',query:{id:scope.row.id}})">详情</a>
</template>
</table-list>
</el-card>
<implement-plan-dialog :visible="implementPlanDialogData.visible" :data="implementPlanDialogData.data" @close="close" />
</template>
<style lang="less" scoped></style>

+ 289
- 0
src/pages/declareManage/renewalProjectCapitalDeclare/index.vue Datei anzeigen

@@ -0,0 +1,289 @@
<script setup name="projectStore">
import { getCurrentInstance, h, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import store from '@/store'
import { renewalProjectDelete, renewalProjectList } from '@/http/apis/projectStoreManage/renewalProjectTreasury'
import useExportExc from '@/utils/useExportExc'
import { declareExport } from '@/http/apis/declareMange'
const
{ proxy } = getCurrentInstance(),
router = useRouter(),
{ reAuditStatusOptions, projectTypeOptions } = store.dictStore.globalDicts || {},
searchForm = reactive({
projectName: undefined,
projectType: undefined,
approvalStatus: undefined,
year: undefined,
times: undefined
}),
tableListRef = ref(),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectType',
prop: 'projectType',
minWidth: '80',
render: row => h('span', projectTypeOptions[row.projectType] || '-')
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '80'
},
{
label: '下一年度支付金额(万元)',
key: 'annualPaymentAmount',
prop: 'annualPaymentAmount',
width: '200'
},
{
label: '项目状态',
key: 'approvalStatus',
prop: 'approvalStatus',
width: '180',
render: row => [
h('span', {
class: [
'dot mr-4',
`bg-${row.approvalStatus === 'PENDING' ? 'warning' : row.approvalStatus === 'PASS' ? 'success' : 'danger'}`
]
}),
h(
'span',
{
class: `text-${row.approvalStatus === 'PENDING' ? 'warning' : row.approvalStatus === 'PASS' ? 'success' : 'danger'}`
},
row.approvalStatus === 'PENDING' ? '待审核' : row.approvalStatus === 'PASS' ? '审核通过' : '审核不通过'
)
]
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '180'
},
{
label: '操作',
slot: 'action',
width: '200',
fixed: 'right'
}
]),
data = ref([]),
areaCode = ref(),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await renewalProjectList({
...pageParams,
...searchForm,
year: searchForm.year * 1 || undefined,
startTime: searchForm.times?.[0] || undefined,
endTime: searchForm.times?.[1] || undefined,
regionCode: areaCode.value || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
search = () => {
getTableData()
},
reset = () => {
searchForm.projectName = undefined
searchForm.projectType = undefined
searchForm.approvalStatus = undefined
searchForm.maxDeclareAmount = undefined
searchForm.maxApprovalAmount = undefined
searchForm.year = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 导出excel文件
{ exportLoading, exportData } = useExportExc(),
handleExcel = () => {
exportData(() => declareExport(5, {
...searchForm,
year: searchForm.year * 1 || undefined,
maxDeclareAmount: searchForm.maxDeclareAmount * 1 || undefined,
maxApprovalAmount: searchForm.maxApprovalAmount * 1 || undefined,
startTime: searchForm.times?.[0] || undefined,
endTime: searchForm.times?.[1] || undefined,
areaCode: areaCode.value || undefined,
times: undefined
}))
},
deleteItem = (data) => {
proxy.$messageBox
.confirm('确定要删除该项吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await renewalProjectDelete({ projectRenewalId: data.id })
proxy.$message.success('删除成功!')
getTableData()
})
},
checkDetail = (row) => {
router.push({ name: 'renewProjectDetail', query: { id: row.id }})
},
redeclare = (row) => {
router.push({ name: 'renewalCapitalDeclare', query: { id: row.id }})
}
onMounted(async () => {
getTableData()
})
</script>
<template>
<el-row>
<el-col :span="24">
<el-card class="w-full search">
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
class="mb-16"
>
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目类型">
<el-select
v-model="searchForm.projectType"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in projectTypeOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目状态">
<el-select
v-model="searchForm.approvalStatus"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(v,k) in reAuditStatusOptions"
:key="k"
:label="v"
:value="k"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter="16"
>
<el-col :span="8">
<el-form-item label="预算年度">
<el-date-picker
v-model="searchForm.year"
type="year"
value-format="YYYY"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
:editable="false"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="search"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>申报列表</span>
<div>
<el-button
type="primary"
plain
size="small"
:loading="exportLoading"
@click="handleExcel"
>导出</el-button>
<el-button
type="primary"
size="small"
icon="Plus"
@click="router.push({ name: 'renewalCapitalDeclare'})"
>续建资金申报</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="checkDetail(scope.row)">详情</a>
<a v-if="scope.row.approvalStatus==='NOT_PASS'" @click="redeclare(scope.row)">重新申报</a>
<a v-if="scope.row.approvalStatus==='NOT_PASS'" class="text-danger" @click="deleteItem(scope.row)">删除</a>
</template>
</table-list>
</el-card>
</el-col>
</el-row>
</template>
<style lang='less' scoped>
</style>

+ 377
- 0
src/pages/declareManage/renewalProjectCapitalDeclare/renewProjectDetail/index.vue Datei anzeigen

@@ -0,0 +1,377 @@
<script setup name='renewProjectDetail'>
import { getCurrentInstance, h, onMounted, reactive, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { renewalDeclaredDetail } from '@/http/apis/declareMange/renewalProjectCapitalDeclare'
import store from '@/store'
import { renewalProjectAsscess } from '@/http/apis/projectStoreManage/renewalProjectTreasury'
import { contractDetail } from '@/http/apis/declareMange/contractRecord'
const { statusOptions, projectTypeOptions, statusGjOptions } =
store.dictStore.globalDicts || {},
tableListRef = ref(),
ruleFormRef = ref(),
router = useRouter(),
route = useRoute(),
total = ref(0),
dialogFormVisible = ref(false),
{ proxy } = getCurrentInstance(),
// 列表数据
column = reactive([
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectType',
prop: 'projectType',
minWidth: '80',
render: row => h('span', projectTypeOptions[row.projectType] || '-')
},
{
label: '批复总金额(万元)',
key: 'approvalAmount',
prop: 'approvalAmount',
width: 150
},
{
label: '累计年度投资资金',
key: 'annualAccumulateAmountList',
slot: 'annualAccumulateAmountList',
width: 150
},
{
label: '项目状态',
key: 'status',
prop: 'status',
width: '120',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${statusOptions[row.status]?.color || statusGjOptions[row.status]?.color}`]
}),
h(
'span',
{
class: `text-${statusOptions[row.status]?.color || statusGjOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name ? `${statusOptions[row.stage]?.name}-${statusOptions[row.status]?.name}` : statusGjOptions[row.status]?.name || '-'
)
]
}
]),
data = ref([]),
form = reactive({}),
rules = reactive({
recommend: [
{ required: true, message: '请填写审核意见', trigger: 'blur' }
]
}),
submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
await renewalProjectAsscess({
...form,
projectRenewalId: route.query.id,
result: false
})
dialogFormVisible.value = false
proxy.$message.success('审核成功!')
router.push({ name: 'renewalProjectTreasury' })
} else {
console.log('error submit!')
}
})
},
redeclare = () => {
router.push({ name: 'renewalCapitalDeclare', query: { id: route.query.id }})
},
adopt = () => {
proxy.$messageBox
.confirm('确认审核通过吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await renewalProjectAsscess({
projectRenewalId: route.query.id,
result: true
})
proxy.$message.success('审核成功!')
router.push({ name: 'renewalProjectTreasury' })
})
},
goBack = () => {
router.go(-1)
},
routeName = ref(''),
detail = ref({}),
getDetail = async () => {
const res = await renewalDeclaredDetail(route.query.id)
detail.value = res.data
data.value = [{ ...res.data }]
getPayInfo(data.value[0].projectId)
},
// 支付信息
payColumn = [
{
label: '付款笔数',
key: 'number',
slot: 'number'
},
{
label: '付款计划',
key: 'planAmount',
slot: 'planAmount'
},
{
label: '付款比例(%)',
key: 'ratio',
slot: 'ratio'
},
{
label: '付款金额(万元)',
key: 'paymentAmount',
slot: 'paymentAmount'
},
{
label: '预计付款时间',
key: 'paymentTime',
slot: 'paymentTime'
},
{
label: '实际支付金额(万元)',
key: 'actualPaymentAmount',
slot: 'actualPaymentAmount',
width: 180
}
],
paymentsData = ref(),
getPayInfo = async (id) => {
const res = await contractDetail(id)
paymentsData.value = res?.data?.payments || []
}
watch(
route,
(val) => {
routeName.value = route.meta.title
},
{ immediate: true, deep: true }
)
onMounted(() => {
getDetail()
})
</script>

<template>
<div class="">
<el-alert
v-if="detail.approvalStatus==='NOT_PASS'"
title="审核不通过"
type="error"
:description="`审核意见:${detail.auditOpinion||'-'}`"
show-icon
/>
<el-alert
v-if="detail.approvalStatus==='PASS'"
title="审核通过"
type="success"
:description="`审核意见:${detail.auditOpinion||'-'}`"
show-icon
/>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>申报信息</span>
</div>
</template>
<div class="flex justify-around">
<div style="font-size: 14px;flex-shrink:0">关联项目:</div>
<table-list
ref="tableListRef"
class="flex-1 mb-16"
:column="column"
:data="data"
:total="total"
:height="200"
:pagination="false"
>
<template #annualAccumulateAmountList="{scope}">
<p v-for="(item,index) in scope.row.annualAccumulateAmountList" :key="index">{{ index+1 }}、{{ item.projectYear }}年投资{{ item.annualAmount }}万元</p>
</template>
</table-list>
</div>
<p class="font-bold mb-8">支付信息</p>
<table-list
ref="tableListRef"
:column="payColumn"
:data="paymentsData"
:pagination="false"
:empty-temp="false"
class="mb-16"
>
<template #number="{scope}">
<span>第{{ scope.$index+1 }}笔</span>
</template>
<template #planAmount="{scope}">
{{ scope.row.planAmount }}
</template>
<template #ratio="{scope}">
{{ scope.row.ratio }}
</template>
<template #paymentAmount="{scope}">
{{ scope.row.paymentAmount }}
</template>
<template #paymentTime="{scope}">
{{ scope.row.paymentTime }}
</template>
<template #actualPaymentAmount="{scope}">
{{ scope.row.actualPaymentAmount }}
</template>
</table-list>
<template v-if="detail.annualAccumulateAmountList?.filter((i,key)=>key!==0&&i.projectYear!==detail.projectYear)?.length">
<p class="font-bold mt-20">历史续建资金信息</p>
<el-descriptions
v-for="(item,index) in detail.annualAccumulateAmountList.filter((i,key)=>key!==0&&i.projectYear!==detail.projectYear)"
:key="index"
class="mt-20"
:column="2"
border
>
<el-descriptions-item
label="预算年度"
span="1"
width="250px"
>
{{ item.projectYear }}
</el-descriptions-item>
<el-descriptions-item
:label="`${item.projectYear}年支付金额(万元)`"
width="250px"
>
{{ item.annualAmount }}
</el-descriptions-item>
<el-descriptions-item label="自有金额(万元)">
{{ item.haveAmount }}
</el-descriptions-item>
<el-descriptions-item label="政府投资-本级财政资金(万元)">
{{ item.govOwnFinanceAmount }}
</el-descriptions-item>
<el-descriptions-item label="政府投资-上级补助资金(万元)">
{{ item.govSuperiorFinanceAmount }}
</el-descriptions-item>
<el-descriptions-item label="银行贷款(万元)">
{{ item.bankLendingAmount }}
</el-descriptions-item>
<el-descriptions-item
label="其他(万元)"
span="2"
>
{{ item.otherAmount }}
</el-descriptions-item>
</el-descriptions>
</template>
<el-descriptions
class="mt-20"
title="申报续建资金信息"
:column="2"
border
>
<el-descriptions-item
label="预算年度"
span="1"
width="250px"
>
{{ detail.projectYear }}
</el-descriptions-item>
<el-descriptions-item
:label="`${detail.projectYear}年支付金额(万元)`"
width="250px"
>
{{ detail.annualPaymentAmount }}
</el-descriptions-item>
<el-descriptions-item label="自有金额(万元)">
{{ detail.haveAmount }}
</el-descriptions-item>
<el-descriptions-item label="政府投资-本级财政资金(万元)">
{{ detail.govOwnFinanceAmount }}
</el-descriptions-item>
<el-descriptions-item label="政府投资-上级补助资金(万元)">
{{ detail.govSuperiorFinanceAmount }}
</el-descriptions-item>
<el-descriptions-item label="银行贷款(万元)">
{{ detail.bankLendingAmount }}
</el-descriptions-item>
<el-descriptions-item
label="其他(万元)"
span="2"
>
{{ detail.otherAmount }}
</el-descriptions-item>
</el-descriptions>
<div class="flex justify-center items-center mt-10">
<el-button
v-if="routeName =='续建项目资金申报详情'&&detail.approvalStatus==='NOT_PASS'"
class="mr-20"
type="primary"
@click="redeclare"
>重新申报</el-button>
<template v-if="routeName !=='续建项目资金申报详情'&&detail.approvalStatus==='PENDING'">
<el-button
class="mr-20"
type="primary"
@click="adopt"
>通过</el-button>
<el-button
class="mr-20"
type="danger"
@click="dialogFormVisible = true"
>不通过</el-button>
</template>
<el-button
plain
@click="goBack"
>返回</el-button>
</div>
</el-card>
<el-dialog
v-model="dialogFormVisible"
title="不通过"
>
<el-form
ref="ruleFormRef"
:model="form"
:rules="rules"
status-icon
>
<el-form-item
label="审核意见"
label-width="auto"
prop="auditOpinion"
>
<el-input
v-model="form.auditOpinion"
maxlength="200"
placeholder="请输入"
show-word-limit
type="textarea"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button
type="primary"
@click="submitForm(ruleFormRef)"
>
提交
</el-button>
<el-button @click="dialogFormVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</div>
</template>

<style lang='less' scoped> </style>

+ 862
- 0
src/pages/declareManage/renewalProjectCapitalDeclare/renewalCapitalDeclare/index.vue Datei anzeigen

@@ -0,0 +1,862 @@
<script setup name='renewalCapitalDeclare'>
import { reactive, ref, onMounted, h, getCurrentInstance } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import store from '@/store'
import {
convertToCollection,
renewalDeclared,
renewalDeclaredDetail,
libAllList
} from '@/http/apis/declareMange/renewalProjectCapitalDeclare'
import { detail } from '@/http/apis/projectCollection/projectCollectionEnter'
import { storeToRefs } from 'pinia'
import { dictionary, save } from '@/http/apis/projectCollection/projectCollectionEnter'
import BasicInfo from '@/pages/projectCollection/projectCollectionEnter/components/basicInfo.vue'
import ProjectDeclareInfo from '@/pages/projectCollection/projectCollectionEnter/components/projectDeclareInfo.vue'
import ApplicationInfo from '@/pages/projectCollection/projectCollectionEnter/components/applicationInfo.vue'
import CoreBusiness from '@/pages/projectCollection/projectCollectionEnter/components/coreBusiness.vue'
import ProjectApprovalInfo from '@/pages/projectCollection/projectCollectionEnter/components/projectApprovalInfo.vue'
import PurchaseInfo from '@/pages/projectCollection/projectCollectionEnter/components/purchaseInfo.vue'
import EmpMaterials from '@/pages/projectCollection/projectCollectionEnter/components/empMaterials.vue'
import { contractDetail } from '@/http/apis/declareMange/contractRecord'
import { changFilesParam } from '@/utils/uploadAction'
const { proxy } = getCurrentInstance(),
{ statusOptions, statusGjOptions, projectTypeOptions } = store.dictStore.globalDicts || {},
userInfo = storeToRefs(store.userStore).userInfo || {},
router = useRouter(),
route = useRoute(),
// 列表
column = reactive([
{
type: 'radio',
key: 'id',
width: '50'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectType',
prop: 'projectType',
minWidth: '80',
render: row => h('span', projectTypeOptions[row.projectType] || '-')
},
{
label: '批复总金额(万元)',
key: 'approvedAmount',
prop: 'approvedAmount',
width: '180'
},
{
label: '累计年度投资资金',
key: 'annualAccumulateAmountList',
slot: 'annualAccumulateAmountList',
width: '180'
},
{
label: '项目状态',
key: 'status',
prop: 'status',
width: '180',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${statusOptions[row.status]?.color || statusGjOptions[row.status]?.color}`]
}),
h(
'span',
{
class: `text-${statusOptions[row.status]?.color || statusGjOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name ? `${statusOptions[row.stage]?.name}-${statusOptions[row.status]?.name}` : statusGjOptions[row.status]?.name || '-'
)
]
}
]),
column1 = reactive([
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '200',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectType',
prop: 'projectType',
minWidth: '80',
render: row => h('span', projectTypeOptions[row.projectType] || '-')
},
{
label: '批复总金额(万元)',
key: 'approvalAmount',
prop: 'approvalAmount',
width: 150
},
{
label: '累计年度投资资金',
key: 'annualAccumulateAmountList',
slot: 'annualAccumulateAmountList',
width: 150
},
{
label: '项目状态',
key: 'status',
prop: 'status',
width: '120',
render: row => [
h('span', {
class: ['dot mr-4', `bg-${statusOptions[row.status]?.color || statusGjOptions[row.status]?.color}`]
}),
h(
'span',
{
class: `text-${statusOptions[row.status]?.color || statusGjOptions[row.status]?.color}`
},
row.status && statusOptions[row.stage]?.name ? `${statusOptions[row.stage]?.name}-${statusOptions[row.status]?.name}` : statusGjOptions[row.status]?.name || '-'
)
]
}
]),
total = ref(0),
data = ref([]),
tableListRef = ref(),
maxYear = ref(),
totalAmount = ref(0),
approvedAmount = ref(),
radioChange = (val) => {
ruleForm.value.projectId = val.id
ruleForm.value.projectCode = val.projectCode
maxYear.value = val.annualAccumulateAmountList?.length > 1 && val.annualAccumulateAmountList.reduce((acc, cur) => Math.max(acc.projectYear, cur.projectYear)) || val.annualAccumulateAmountList[0].projectYear
totalAmount.value = val.annualAccumulateAmountList?.map(i => i.annualAmount)?.reduce((acc, cur) => { return acc + cur }, 0)
approvedAmount.value = val.approvedAmount
getPayInfo(val.id)
getProjectDetail(val.projectCode, val.fromType)
},
searchForm = reactive({
projectName: undefined
}),
search = () => {
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await libAllList({
...pageParams,
projectName: searchForm.projectName
})
data.value = res.data.records.map(i => {
return {
...i,
isRadioDisabled: i.annualAccumulateAmountList?.map(i => i.annualAmount)?.reduce((acc, cur) => { return acc + cur }, 0) === i.approvedAmount
}
})
total.value = res.data.total
},
// 表单
ruleFormRef = ref(),
moneyValidator = (rule, value, callback) => {
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
} else {
callback()
}
},
moneyValidator1 = (rule, value, callback) => {
if (!value) callback()
if (!/^\d+(\.\d{1,6})?$/.test(value)) {
callback('请输入正确格式,最多保留六位小数')
} else if (value * 1 >= 100000000) {
callback('请输入正确格式,小于100000000')
}
let maxData = 0
paymentsData.value.forEach(i => {
if (new Date(i.paymentTime).getFullYear() < ruleForm.value.projectYear * 1) {
maxData += i.paymentAmount - i.actualPaymentAmount
}
})
maxData += paymentsData.value.find(i => new Date(i.paymentTime).getFullYear() === ruleForm.value.projectYear * 1)?.paymentAmount
if (value > maxData) {
callback(`支付金额最大不能超过${maxData}万元`)
} else {
callback()
}
},
// yearValidator = (rule, value, callback) => {
// if (!value) callback()
// if (!paymentsData.value?.length) {
// callback('未有支付信息,无法提交')
// }
// const years1 = paymentsData.value.map(i => new Date(i.paymentTime).getFullYear() + '')
// // const years2 = paymentsData.value.filter(i => i.actualPaymentAmount || i.actualPaymentAmount === 0).map(i => new Date(i.paymentTime).getFullYear() + '')
// if (!years1.includes(value)) {
// callback('未有所选年度的支付计划,无法提交')
// } else {
// callback()
// }
// // else if (!years2.includes(value)) {
// // callback('未填写当年度的实际支付金额,请去合同备案补充”')
// // }
// },
disabledDate = (time) => {
return new Date(time).getFullYear() <= new Date().getFullYear()
},
rules = reactive({
projectId: [
{ required: true, message: '请选择关联项目', trigger: 'blur' }
],
projectYear: [
{ required: true, message: '请选择预算年度', trigger: 'blur' }
// { validator: yearValidator, trigger: 'blur' }
],
annualPaymentAmount: [
{ required: true, message: '请输入年度支付金额', trigger: 'blur' },
{ validator: moneyValidator1, trigger: 'blur' }
],
haveAmount: [
{ required: true, message: '请输入自有资金金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
govOwnFinanceAmount: [
{ required: true, message: '请输入政府投资-本级财政资金金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
govSuperiorFinanceAmount: [
{ required: true, message: '请输入政府投资-上级补助资金金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
bankLendingAmount: [
{ required: true, message: '请输入银行贷款金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
],
otherAmount: [
{ required: true, message: '请输入其他金额', trigger: 'blur' },
{ validator: moneyValidator, trigger: 'blur' }
]
}),
ruleForm = ref({
id: route.query.id || undefined,
orgCode: userInfo.empPosUnitCode,
regionCode: userInfo.regionCode

}),
// floatAdd = (args) => {
// const data = []
// args.forEach(i => {
// try {
// data.push(i.toString().split('.')[1].length)
// } catch (e) {
// data.push(0)
// }
// })
// const m = Math.pow(10, Math.max(...data))
// let sum = 0
// args.forEach(item => {
// sum += item * m
// })
// return sum / m
// },
submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate(async (valid, fields) => {
if (valid) {
// if (ruleForm.value.projectYear * 1 <= maxYear.value * 1) {
// proxy.$message.warning('预算年度必须大于累计投资的最大年度')
// return
// }
// if (floatAdd([ruleForm.value.annualPaymentAmount, totalAmount.value]) > approvedAmount.value) {
// proxy.$message.warning('累计年度投资金额必须小于等于批复总金额')
// return
// }
if (errorText.value) {
proxy.$message.error(errorText.value)
return
}
// const total = floatAdd([ruleForm.value.haveAmount, ruleForm.value.govOwnFinanceAmount, ruleForm.value.govSuperiorFinanceAmount, ruleForm.value.bankLendingAmount, ruleForm.value.otherAmount])
// if (total !== ruleForm.value.annualPaymentAmount) {
// proxy.$message.warning('各资金来源的和必须等于年度支付金额')
// return
// }
if (!route.query.id) {
const arr = Object.values(formRefs).map(async i => i?.formRef && await i.formRef.validate())
await Promise.all(arr)
}
const postData = {
...ruleForm.value,
projectYear: ruleForm.value.projectYear * 1
}
await renewalDeclared(postData)
!route.query.id && submitProject()
} else {
console.log('error submit!', fields)
}
})
},
getDetail = async () => {
const res = await renewalDeclaredDetail(route.query.id)
ruleForm.value = { ...res.data, projectYear: res.data.projectYear + '' }
data.value = [{ ...res.data }]
maxYear.value = res.data.annualAccumulateAmountList?.length > 1 && res.data.annualAccumulateAmountList.reduce((acc, cur) => Math.max(acc.projectYear, cur.projectYear)) || res.data.annualAccumulateAmountList[0].projectYear
totalAmount.value = res.data.annualAccumulateAmountList?.map(i => i.annualAmount)?.reduce((acc, cur) => { return acc + cur }, 0)
approvedAmount.value = res.data.approvalAmount
getPayInfo(res.data.projectId)
},
// 支付信息
payColumn = [
{
label: '付款笔数',
key: 'number',
slot: 'number'
},
{
label: '付款计划',
key: 'planAmount',
slot: 'planAmount'
},
{
label: '付款比例(%)',
key: 'ratio',
slot: 'ratio'
},
{
label: '付款金额(万元)',
key: 'paymentAmount',
slot: 'paymentAmount'
},
{
label: '预计付款时间',
key: 'paymentTime',
slot: 'paymentTime'
},
{
label: '实际支付金额(万元)',
key: 'actualPaymentAmount',
slot: 'actualPaymentAmount',
width: 180
}
],
paymentsData = ref(),
errorText = ref(''),
getPayInfo = async (id) => {
const res = await contractDetail(id)
paymentsData.value = res?.data?.payments || []
errorText.value = ''
// if (!paymentsData.value?.length) {
// errorText.value = '该项目未有支付信息'
// proxy.$message.error(errorText.value)
// return
// }
// let count = 0
// paymentsData.value.forEach(i => {
// if (new Date(i.paymentTime).getTime() < new Date().getTime() && !(i.actualPaymentAmount || i.actualPaymentAmount === 0)) {
// count++
// }
// })
// if (count > 0) {
// errorText.value = '超过预付款时间的支付计划未填写实际支付金额,请去合同备案补充'
// proxy.$message.error(errorText.value)
// return
// }
return
},
// 补充信息
formRefs = {},
detailData = ref(),
basicInfoData = ref(),
getBasicInfoData = (data) => {
basicInfoData.value = data
},
dictionaryList = ref(),
baseProjSetYear = ref(),
getProYear = (data) => {
baseProjSetYear.value = data
},
approvalInfoData = ref(),
getApprovalInfoData = (data) => {
approvalInfoData.value = data
},
baseProjName = ref(),
getProjectDetail = async (projectCode, fromType) => {
let res = {}
// 归集项目详情使用detail 申报项目详情使用convertToCollection
if (fromType === '2') {
res = await detail('1', projectCode)
} else {
res = await convertToCollection(projectCode)
}
baseProjName.value = res.data.baseinfo.baseProjName
detailData.value = {
...res.data,
baseinfo: {
...res.data.baseinfo,
baseProjType: '03'
},
cimplement: {
...res.data.cimplement,
baseCheckFile: res.data.cimplement?.baseCheckFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseCheckFile))) || undefined,
baseInitialOpinionFile: res.data.cimplement?.baseInitialOpinionFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseInitialOpinionFile))) || undefined,
baseEstaSummFile: res.data.cimplement?.baseEstaSummFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseEstaSummFile))) || undefined,
baseSummReportFile: res.data.cimplement?.baseEstaSummFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseSummReportFile))) || undefined,
baseThirdAcceptFile: res.data.cimplement?.baseEstaSummFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseThirdAcceptFile))) || undefined,
baseInforLevelFile: res.data.cimplement?.baseInforLevelFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseInforLevelFile))) || undefined,
basePasswAssessFile: res.data.cimplement?.basePasswAssessFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.basePasswAssessFile))) || undefined,
baseFinanlAuditFile: res.data.cimplement?.baseFinanlAuditFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseFinanlAuditFile))) || undefined,
baseUserConsFile: res.data.cimplement?.baseUserConsFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseUserConsFile))) || undefined,
baseFinalExpertOpinionFile: res.data.cimplement?.baseFinalExpertOpinionFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseFinalExpertOpinionFile))) || undefined,
baseEngineerPostpoFile: res.data.cimplement?.baseEngineerPostpoFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseEngineerPostpoFile))) || undefined,
baseChangeFormFile: res.data.cimplement?.baseChangeFormFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseChangeFormFile))) || undefined,
baseChanFile: res.data.cimplement?.baseChanFile && JSON.stringify(changFilesParam(JSON.parse(res.data.cimplement?.baseChanFile))) || undefined
}
}
},
changeYear = () => {
detailData.value.baseinfo.baseProjName = baseProjName.value + `(${ruleForm.value.projectYear})`
},
changePostData = () => {
const baseinfo = JSON.parse(JSON.stringify(formRefs['baseinfo'].formData))
const apply = JSON.parse(JSON.stringify(formRefs['apply'].formData))
const application = formRefs['application'] && JSON.parse(JSON.stringify(formRefs['application'].formData)) || {}
const baseCore = formRefs['baseCore'] && JSON.parse(JSON.stringify(formRefs['baseCore'].formData)) || {}
const approve = formRefs['approve'] && JSON.parse(JSON.stringify(formRefs['approve'].formData)) || {}
const procures = formRefs['procures'] && JSON.parse(JSON.stringify(formRefs['procures'].formData)) || []
const cimplement = formRefs['cimplement'] && JSON.parse(JSON.stringify(formRefs['cimplement'].formData)) || []
return {
baseProjId: '',
baseinfo: {
...baseinfo,
baseProvManDeprtType: baseinfo?.baseProvManDeprtType * 1 || undefined,
baseConstructionType: baseinfo?.baseConstructionType?.join(';')
// baseAreaCode: baseinfo?.baseArea?.baseAreaCode || undefined,
// baseAreaName: baseinfo?.baseArea?.baseAreaName || undefined,
// baseArea: undefined
},
apply: {
...apply,
baseProjStartTime: apply?.baseProjTime?.length ? apply?.baseProjTime[0] + ' 00:00:00' : undefined,
baseProjEndTime: apply?.baseProjTime?.length ? apply?.baseProjTime[1] + ' 00:00:00' : undefined,
baseProjTime: undefined,
baseHistorProjId: apply?.missing || baseinfo?.baseProjType === '01' ? '' : apply?.baseHistorProjs?.map(i => i.baseProjId)?.join(';'),
baseHistorProjName: apply?.missing || baseinfo?.baseProjType === '01' ? '' : apply?.baseHistorProjs?.map(i => i.baseProjName)?.join(';'),
baseHistorProjYear: apply?.missing || baseinfo?.baseProjType === '01' ? '' : apply?.baseHistorProjs?.map(i => i.baseProjSetYear)?.join(';'),
baseProjAmountOri: apply?.baseProjAmountOri?.join(';') || undefined,
baseProjBasis: apply?.baseProjBasis?.map(i => i.value)?.join(';') || undefined,
baseProjBasisFile: apply?.baseProjBasis?.map(i => i.fileList && JSON.stringify(changFilesParam(i.fileList)))?.join(';') || '',
beseExpectedResults: apply?.beseExpectedResults?.length && JSON.stringify(apply.beseExpectedResults) || '',
baseProjApplyFile: ((['01', '02', '04', '05'].includes(baseinfo?.baseProjType) && apply?.baseProjSetYear * 1 >= 2023) || apply?.baseProjSetYear * 1 < 2023) && apply?.baseProjApplyFile?.length ? JSON.stringify(changFilesParam(apply?.baseProjApplyFile)) : '',
baseResearchReportFile: (baseinfo?.baseProjType === '01' || baseinfo?.baseProjType === '02') && apply?.baseResearchReportFile?.length ? JSON.stringify(changFilesParam(apply?.baseResearchReportFile)) : '',
baseProjOtherFile: apply?.baseProjOtherFile?.length ? JSON.stringify(changFilesParam(apply?.baseProjOtherFile)) : '',
baseHistorProjs: undefined,
...application,
baseProjSysCode: application?.applications?.map(i => i.application.applicationCode).join(';') || '',
baseProjSys: application?.applications?.map(i => i.application.applicationName).join(';') || '',
baseAccountAppName: application?.applications?.map(i => i.baseAccountAppName).join(';') || '',
baseBrainName: application?.applications?.map(i => i.baseBrainName).join(';') || '',
applications: undefined,
...baseCore,
baseCoreBusinessCode: baseCore?.coreBusiness?.map(i => i.id).join(';') || '',
baseCoreBusiness: baseCore?.coreBusiness?.map(i => i.matterName).join(';') || '',
baseCoreBusinessOrg: baseCore?.coreBusiness?.map(i => i.orgName).join(';') || '',
coreBusiness: undefined,
baseProjId: ''
},
approve: {
...approve,
baseReviewResults: baseinfo?.baseProjSetProg !== '01' ? approve?.baseReviewResults : '',
baseReviewOpinion: baseinfo?.baseProjSetProg !== '01' ? approve?.baseReviewOpinion : '',
baseReviewCommentsFile: baseinfo?.baseProjSetProg !== '01' ? approve?.baseReviewCommentsFile?.length && JSON.stringify(changFilesParam(approve?.baseReviewCommentsFile)) : '',
equalProtectionLevel: baseinfo?.baseProjIsConfidentiality === '01' && !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.equalProtectionLevel : '',
approvalFile: !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.approvalFile?.length && JSON.stringify(changFilesParam(approve?.approvalFile)) : '',
baseExpertTotalMoney: !['01', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseExpertTotalMoney : '',
baseExpertYearMoney: !['01', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseExpertYearMoney : '',
baseInitialReviewTotalMoney: !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseInitialReviewTotalMoney : '',
baseProjReplyAmount: !['01', '02', '03'].includes(baseinfo?.baseProjSetProg) ? approve?.baseProjReplyAmount : '',
releaseYearMoney: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) ? approve?.releaseYearMoney : '',
preliminaryDesignScheme: approve?.baseProjReplyAmount >= 5000 && ['04', '05', '06', '07', '00'].includes(baseinfo.baseProjSetProg) ? approve?.preliminaryDesignScheme?.length && JSON.stringify(changFilesParam(approve.preliminaryDesignScheme)) : '',
preliminaryDesignFile: approve?.baseProjReplyAmount >= 5000 && ['04', '05', '06', '07', '00'].includes(baseinfo.baseProjSetProg) ? approve?.preliminaryDesignFile?.length && JSON.stringify(changFilesParam(approve.preliminaryDesignFile)) : ''
},
procures: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && procures?.sections?.map(i => {
return {
...i,
baseBidName: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseBidName || '',
baseProjPurchaseWay: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseProjPurchaseWay || '',
basePurchaseCode: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.basePurchaseCode || '',
basePurchasingAgencies: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.basePurchasingAgencies || '',
baseUnifiedCreditCode: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.baseUnifiedCreditCode || '',
baseWinningBidTime: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseWinningBidTime || '',
baseProjPurchaseAmount: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseProjPurchaseAmount || '',
baseConsDeprt: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseConsDeprt || '',
baseConsDeprtUsci: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.baseConsDeprtUsci || '',
basePaymentTime: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.basePaymentTime || '',
paymentProgress: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && i.paymentProgress || '',
purchaseFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.purchaseFile?.length ? JSON.stringify(changFilesParam(i.purchaseFile)) : '',
biddingFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.biddingFile?.length ? JSON.stringify(changFilesParam(i.biddingFile)) : '',
purchaseContract: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && i.purchaseContract?.length ? JSON.stringify(changFilesParam(i.purchaseContract)) : ''
}
}) || [],
cimplement: {
...cimplement,
baseInitialOpinionFile: cimplement?.baseInitialOpinionFile?.length ? JSON.stringify(changFilesParam(cimplement.baseInitialOpinionFile)) : '',
baseInforLevelFile: ((['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && baseinfo?.baseConstructionType?.includes('01')) || !baseinfo?.baseConstructionType?.includes('01')) && cimplement?.baseInforLevelFile?.length ? JSON.stringify(changFilesParam(cimplement.baseInforLevelFile)) : '',
basePasswAssessFile: (['04', '05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.basePasswAssessFile?.length ? JSON.stringify(changFilesParam(cimplement.basePasswAssessFile)) : '',
baseThirdAcceptFile: cimplement.baseThirdAcceptFile?.length ? JSON.stringify(changFilesParam(cimplement.baseThirdAcceptFile)) : '',
baseCheckFile: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.baseCheckFile?.length ? JSON.stringify(changFilesParam(cimplement.baseCheckFile)) : '',
baseFinanlAuditFile: ['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) && approve?.releaseYearMoney * 1 >= 2000 && cimplement?.baseFinanlAuditFile?.length ? JSON.stringify(changFilesParam(cimplement.baseFinanlAuditFile)) : '',
baseUserConsFile: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.baseUserConsFile?.length ? JSON.stringify(changFilesParam(cimplement.baseUserConsFile)) : '',
baseEstaSummFile: cimplement?.baseEstaSummFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseEstaSummFile)) : '',
baseSummReportFile: (['05', '06', '07', '00'].includes(baseinfo?.baseProjSetProg) || apply?.baseProjSetYear * 1 < 2023) && cimplement?.baseSummReportFile?.length ? JSON.stringify(changFilesParam(cimplement.baseSummReportFile)) : '',
baseFinalExpertOpinionFile: baseinfo?.baseProjSetProg === '07' && cimplement.baseFinalExpertOpinionFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseFinalExpertOpinionFile)) : '',
baseEngineerPostpoFile: cimplement?.baseEngineerPostpoFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseEngineerPostpoFile)) : '',
baseChangeFormFile: cimplement?.baseChangeFormFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseChangeFormFile)) : '',
baseChanFile: cimplement?.baseChanFile?.length ? JSON.stringify(changFilesParam(cimplement?.baseChanFile)) : ''
}
}
},
submitProject = async () => {
const postData = changePostData()
await save(postData)
proxy.$message.success('提交成功!')
router.go(-1)
}

onMounted(async () => {
dictionaryList.value = (await dictionary()).data
if (route.query.id) {
getDetail()
} else {
getTableData()
}
})
</script>

<template>
<div class="footerPage">
<el-alert
v-if="ruleForm.approvalStatus==='NOT_PASS'"
style="marginBottom:20px;"
title="审核不通过"
type="error"
:description="`审核意见:${ruleForm.auditOpinion}`"
show-icon
/>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>申报信息</span>
</div>
</template>
<el-form
ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
status-icon
>
<el-input
v-if="!$route.query.id"
v-model="searchForm.projectName"
placeholder="搜索项目名称"
style="width: 200px;margin-left: 100px;"
class="mb-8"
>
<template #append>
<el-button icon="Search" @click="search" />
</template>
</el-input>
<el-form-item
label="关联项目"
prop="projectId"
:label-width="100"
clas="mb-16"
>
<table-list
v-if="!route.query.id"
ref="tableListRef"
:column="column"
:height="350"
:data="data"
:total="total"
class="w-full"
row-key="id"
@radio-change="radioChange"
@get-table-data="getTableData"
>
<template #annualAccumulateAmountList="{scope}">
<p v-for="(item,index) in scope.row.annualAccumulateAmountList" :key="index">{{ index+1 }}、{{ item.projectYear }}年投资{{ item.annualAmount }}万元</p>
</template>
</table-list>
<table-list
v-else
ref="tableListRef"
:column="column1"
:data="data"
:height="200"
:pagination="false"
class="flex-1"
><template #annualAccumulateAmountList="{scope}">
<p v-for="(item,index) in scope.row.annualAccumulateAmountList" :key="index">{{ index+1 }}、{{ item.projectYear }}年投资{{ item.annualAmount }}万元</p>
</template></table-list>
</el-form-item>
<p class="mb-16 flex items-center">
<span class="mr-24">支付信息</span>
<span class="text-danger text-14">温馨提示:实际支付金额请去合同信息填写</span>
</p>
<table-list
ref="tableListRef"
:column="payColumn"
:data="paymentsData"
:pagination="false"
:empty-temp="false"
class="mb-16"
>
<template #number="{scope}">
<span>第{{ scope.$index+1 }}笔</span>
</template>
<template #planAmount="{scope}">
{{ scope.row.planAmount }}
</template>
<template #ratio="{scope}">
{{ scope.row.ratio }}
</template>
<template #paymentAmount="{scope}">
{{ scope.row.paymentAmount }}
</template>
<template #paymentTime="{scope}">
{{ scope.row.paymentTime }}
</template>
<template #actualPaymentAmount="{scope}">
{{ scope.row.actualPaymentAmount }}
</template>
</table-list>
<p style="margin-bottom: 16px;">申报续建资金信息</p>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="预算年度"
prop="projectYear"
>
<el-date-picker
v-model="ruleForm.projectYear"
type="year"
placeholder="请选择"
format="YYYY"
value-format="YYYY"
:disabled-date="disabledDate"
@change="changeYear"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
:label="`${ruleForm.projectYear||''}支付金额`"
prop="annualPaymentAmount"
>
<el-input-number
v-model="ruleForm.annualPaymentAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="自有资金(万元)"
prop="haveAmount"
>
<el-input-number
v-model="ruleForm.haveAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="政府投资-本级财政资金(万元)"
prop="govOwnFinanceAmount"
>
<el-input-number
v-model="ruleForm.govOwnFinanceAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="政府投资-上级补助资金(万元)"
prop="govSuperiorFinanceAmount"
>
<el-input-number
v-model="ruleForm.govSuperiorFinanceAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="银行贷款(万元)"
prop="bankLendingAmount"
>
<el-input-number
v-model="ruleForm.bankLendingAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="其他"
prop="otherAmount"
>
<el-input-number
v-model="ruleForm.otherAmount"
placeholder="请填写"
:min="0"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
</el-col>
</el-row>
<template v-if="!route.query.id">
<p style="margin-bottom: 16px;">补充项目信息</p>
<el-collapse>
<el-collapse-item name="1" class="mb-16">
<template #title>
<div class="collapse-title">项目基本信息</div>
</template>
<div class="pb-24">
<basic-info
:ref="el=>formRefs['baseinfo']=el"
:detail="detailData"
:dictionary-list="dictionaryList"
:is-supplemented="true"
@get-basic-info-data="getBasicInfoData"
/>
</div>
</el-collapse-item>
<el-collapse-item name="2" class="mb-16">
<template #title>
<div class="collapse-title">项目申报信息</div>
</template>
<div class="pb-24">
<project-declare-info
:ref="el=>formRefs['apply']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:dictionary-list="dictionaryList"
:is-supplemented="true"
@get-pro-year="getProYear"
/>
</div>
</el-collapse-item>
<el-collapse-item v-if="!(basicInfoData?.baseConstructionType?.length===1&&basicInfoData?.baseConstructionType.includes('01'))" name="3" class="mb-16">
<template #title>
<div class="collapse-title">项目关联信息</div>
</template>
<div class="pb-24">
<application-info
:ref="el=>formRefs['application']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:is-supplemented="true"
/>
</div>
</el-collapse-item>
<el-collapse-item name="4" class="mb-16">
<template #title>
<div class="collapse-title">核心业务</div>
</template>
<div class="pb-24">
<core-business :ref="el=>formRefs['baseCore']=el" :detail="detailData" :is-supplemented="true" />
</div>
</el-collapse-item>
<el-collapse-item v-if="basicInfoData?.baseProjSetProg!=='01'" name="5" class="mb-16">
<template #title>
<div class="collapse-title">项目立项评审信息</div>
</template>
<div class="pb-24">
<project-approval-info
:ref="el=>formRefs['approve']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:dictionary-list="dictionaryList"
:is-supplemented="true"
@get-approval-info-data="getApprovalInfoData"
/>
</div>
</el-collapse-item>
<el-collapse-item v-show="['05','06','07','00'].includes(basicInfoData?.baseProjSetProg)||baseProjSetYear*1<2023" name="6" class="mb-16">
<template #title>
<div class="collapse-title">项目采购、资金支付信息</div>
</template>
<div class="pb-24">
<purchase-info
:ref="el=>formRefs['procures']=el"
:detail="detailData"
:dictionary-list="dictionaryList"
:base-proj-set-year="baseProjSetYear"
:basic-info-data="basicInfoData"
:is-supplemented="true"
/>
</div>
</el-collapse-item>
<el-collapse-item name="7" class="mb-16">
<template #title>
<div class="collapse-title">实施材料信息</div>
</template>
<div class="pb-24">
<emp-materials
:ref="el=>formRefs['cimplement']=el"
:detail="detailData"
:basic-info-data="basicInfoData"
:base-proj-set-year="baseProjSetYear"
:approval-info-data="approvalInfoData"
:is-supplemented="true"
/>
</div>
</el-collapse-item>
</el-collapse>
</template>
</el-form>
</el-card>
</div>
<div class="footer">
<el-button
type="primary"
@click="submitForm(ruleFormRef)"
>
提交
</el-button>
<el-button @click="router.go(-1)">返回</el-button>
</div>
</template>

<style lang='less' scoped> </style>

+ 431
- 0
src/pages/expertEnroll/index.vue Datei anzeigen

@@ -0,0 +1,431 @@
<script name="expertEnroll" setup>
import { getCurrentInstance, ref, onMounted, reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import BasicInfo from '@/pages/expertManage/expertStore/addOrEditExpert/components/basicInfo.vue'
import EduInfo from '@/pages/expertManage/expertStore/addOrEditExpert/components/eduInfo.vue'
import JobInfo from '@/pages/expertManage/expertStore/addOrEditExpert/components/jobInfo.vue'
import ProfessionalInfo from '@/pages/expertManage/expertStore/addOrEditExpert/components/professionalInfo.vue'
import RecommendInfo from '@/pages/expertManage/expertStore/addOrEditExpert/components/recommendInfo.vue'
import { expertEdit, expertSignUp, registration } from '@/http/apis/expertManage/expertStore'
import { downloadFileUrl } from '@/utils/uploadAction.js'
import { getExpertDetail } from '@/http/apis/expertManage/expertVerify'
import { getVerificationCode } from '@/http/apis/auth'
import getTimeDiffer from '@/utils/getTimeDiffer'
import ExpertOtherInfo from '@/pages/expertManage/expertStore/addOrEditExpert/components/expertOtherInfo.vue'
const { proxy } = getCurrentInstance(),
route = useRoute(),
router = useRouter(),
formData = ref({
basicInfo: {
// isDingUser: false
}
}),
collapseModal = ref(['1', '2', '3', '4', '5', '6']),
basicInfoRef = ref(), // 基本信息
eduInfoRef = ref(), // 学历信息
jobInfoRef = ref(), // 职业信息
professionalInfoRef = ref(), // 专业信息
recommendInfoRef = ref(), // 推荐信息
expertOtherInfoRef = ref(), // 其他信息
// 提交
submitForm = async () => {
const form = []
form.push(new Promise((resolve, reject) => {
basicInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
eduInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
jobInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
professionalInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
recommendInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
expertOtherInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
Promise.all([...form]).then(async () => {
saveData()
}).catch(err => {
if (err) {
proxy.$message.warning(err)
}
})
},
saveData = async () => {
var data = {
expertUserId: route.query.id || undefined,
basicInfo: {
...basicInfoRef.value.formData,
// isDingUser: formData.value.basicInfo.isDingUser,
avatarUrl: basicInfoRef.value.formData?.avatarFile?.fileId && await downloadFileUrl(basicInfoRef.value.formData.avatarFile.fileId),
expertIntentionWorkRegions:
basicInfoRef.value.formData.expertIntentionWorkRegions?.map((i, index) => ({
regionName: i.unionCode?.join('@@'),
regionCode: i.unionCode?.slice(-1)[0]?.split('##')[0],
regionLevel: i.unionCode?.slice(-1)[0]?.split('##')[2]
})),
expertRegionInfo: {
regionName: basicInfoRef.value.formData.expertRegionInfo?.join('@@'),
regionCode: basicInfoRef.value.formData.expertRegionInfo?.slice(-1)[0].split('##')[0],
regionLevel: basicInfoRef.value.formData.expertRegionInfo?.slice(-1)[0].split('##')[2]
},
political: basicInfoRef.value.formData.political && [basicInfoRef.value.formData.political] || [],
expertSource: basicInfoRef.value.formData.expertSource && [basicInfoRef.value.formData.expertSource] || [],
expertType: basicInfoRef.value.formData.expertType && [basicInfoRef.value.formData.expertType] || []
},
eduInfo: {
...eduInfoRef.value.formData,
edu: eduInfoRef.value.formData.edu && [eduInfoRef.value.formData.edu],
degree: eduInfoRef.value.formData.degree && [eduInfoRef.value.formData.degree],
degreeCertificateFile: eduInfoRef.value.formData.degreeCertificateFile && await Promise.all(
eduInfoRef.value.formData.degreeCertificateFile && eduInfoRef.value.formData.degreeCertificateFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || [],
graduationCertificateFile: eduInfoRef.value.formData.graduationCertificateFile && await Promise.all(
eduInfoRef.value.formData.graduationCertificateFile && eduInfoRef.value.formData.graduationCertificateFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || []
},
jobInfo: {
...jobInfoRef.value.formData,
administrativeRank: jobInfoRef.value.formData.administrativeRank && [jobInfoRef.value.formData.administrativeRank] || [],
jobStatus: jobInfoRef.value.formData.jobStatus && [jobInfoRef.value.formData.jobStatus] || [],
companyAttribute: jobInfoRef.value.formData.companyAttribute && [jobInfoRef.value.formData.companyAttribute] || []
},
professionalInfo: {
...professionalInfoRef.value.formData,
goodAt: professionalInfoRef.value.formData.goodAt && [professionalInfoRef.value.formData.goodAt] || [],
titleLevel: professionalInfoRef.value.formData.titleLevel && [professionalInfoRef.value.formData.titleLevel] || [],
titleCertificateFile: professionalInfoRef.value.formData.titleCertificateFile && await Promise.all(
professionalInfoRef.value.formData.titleCertificateFile && professionalInfoRef.value.formData.titleCertificateFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || [],
technicalExpertise: professionalInfoRef.value.formData.technicalExpertise && professionalInfoRef.value.formData.technicalExpertise.map(i => {
return {
tagCode: i.split('##')[1],
tagName: i.split('##')[0]
}
}),
industrySector: professionalInfoRef.value.formData.industrySector && professionalInfoRef.value.formData.industrySector.map(i => {
return {
tagCode: i.split('##')[1],
tagName: i.split('##')[0]
}
})
},
recommendInfo: {
...recommendInfoRef.value.formData,
recommendedWay: recommendInfoRef.value.formData.recommendedWay && [recommendInfoRef.value.formData.recommendedWay] || [],
recommendationProofFile: recommendInfoRef.value.formData.recommendationProofFile && await Promise.all(
recommendInfoRef.value.formData.recommendationProofFile && recommendInfoRef.value.formData.recommendationProofFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || []
},
expertOtherInfo: {
...expertOtherInfoRef.value.formData,
other: expertOtherInfoRef.value.formData.other && expertOtherInfoRef.value.formData.other.map(i => {
return {
tagCode: i.split('##')[1],
tagName: i.split('##')[0]
}
})
}
}
if (route.name === 'expertEnroll') {
showSmsDiaglog(data)
} else {
if (!route.query.id) {
await expertSignUp(data)
proxy.$message.success('专家新增成功')
router.go(-1)
} else {
await expertEdit(data)
proxy.$message.success('专家编辑成功')
router.go(-1)
}
}
},
// 专家报名-短信验证
smsDialogData = reactive({
visible: false,
data: {}
}),
showSmsDiaglog = (data) => {
smsDialogData.data = data
smsDialogData.visible = true
},
smsDialogFormRef = ref(),
smsDialogForm = ref({
verificationCode: ''
}),
smsDialogRules = {
'verificationCode': [{ required: true, message: '请输入' }]
},
smsDialogLoading = ref(false),
submitSms = async (formEl) => {
if (!formEl) {
return
}
formEl.validate(async (valid) => {
if (valid) {
await registration({
...smsDialogData.data,
verificationCode: smsDialogForm.value.verificationCode
})
proxy.$message.success('提交成功')
router.go(0)
}
}
)
},
timer = ref(null),
count = ref(0),
getVerificationCodeFunc = async () => {
await getVerificationCode({ mobile: basicInfoRef.value.formData.phoneNo, verificationType: 'EXPERT_REGISTER' })
proxy.$message.success('验证码已发送')
const TIME_COUNT = 60
if (!timer.value) {
count.value = TIME_COUNT
timer.value = setInterval(() => {
if (count.value > 0 && count.value <= TIME_COUNT) {
count.value--
} else {
clearInterval(timer.value)
timer.value = null
}
}, 1000)
}
},
// 获取详情
getDetail = async () => {
const res = await getExpertDetail({ expertUserId: route.query.id })
basicInfoRef.value.setFormData(res.data.basicInfo)
eduInfoRef.value.setFormData(res.data.eduInfo)
jobInfoRef.value.setFormData(res.data.jobInfo)
professionalInfoRef.value.setFormData(res.data.professionalInfo)
recommendInfoRef.value.setFormData(res.data.recommendInfo)
expertOtherInfoRef.value.setFormData(res.data.expertOtherInfo)
},
// 是否失效
isFailure = ref(false),
getIsFailure = () => {
const time = window.atob(route.query.time)
if (getTimeDiffer(new Date(), new Date(time * 1), 'd') > 3) {
isFailure.value = true
}
}
onMounted(() => {
if (route.query.time) {
getIsFailure()
setInterval(() => {
getIsFailure()
}, 10000)
} else {
isFailure.value = true
}
if (route.query.id) {
getDetail()
}
})
</script>

<template>
<div class="expertEnroll footerPage" :class="{ 'relative':route.path === 'expertEnroll'}">
<div class="top">丽水市信息化专家报名</div>
<template v-if="!isFailure">
<div class="px-[107px] mt-[-60px]">
<el-collapse v-model="collapseModal">
<el-collapse-item name="1" class="mb-16">
<template #title>
<div class="collapse-title">基本信息</div>
</template>
<div class="pb-24">
<basic-info ref="basicInfoRef" :basic-info="formData.basicInfo" />
</div>
</el-collapse-item>
<el-collapse-item name="2" class="mb-16">
<template #title>
<div class="collapse-title">学历信息</div>
</template>
<div class="pb-24">
<edu-info ref="eduInfoRef" />
</div>
</el-collapse-item>
<el-collapse-item name="3" class="mb-16">
<template #title>
<div class="collapse-title">职业信息</div>
</template>
<div class="pb-24">
<job-info ref="jobInfoRef" />
</div>
</el-collapse-item>
<el-collapse-item name="4" class="mb-16">
<template #title>
<div class="collapse-title">专业信息</div>
</template>
<div class="pb-24">
<professional-info ref="professionalInfoRef" />
</div>
</el-collapse-item>
<el-collapse-item name="5" class="mb-16">
<template #title>
<div class="collapse-title">推荐信息</div>
</template>
<div class="pb-24">
<recommend-info ref="recommendInfoRef" />
</div>
</el-collapse-item>
<el-collapse-item name="6" class="mb-16">
<template #title>
<div class="collapse-title">其他信息</div>
</template>
<div class="pb-24">
<expert-other-info ref="expertOtherInfoRef" />
</div>
</el-collapse-item>
</el-collapse>
</div>
<div class="footer">
<el-button
type="primary"
@click="submitForm"
>
提交
</el-button>
<el-button @click="router.go(-1)">取消</el-button>
</div>
</template>
<template v-else>
<img src="@/assets/images/link-failure-img.png" style="width: 320px;height: 245px;margin: 160px auto 0" />
<p style="color: #83868C;" class="mt-32 text-19 text-center">链接已失效,请联系管理员</p>
</template>
<el-dialog
:model-value="smsDialogData.visible"
title="短信验证"
width="400px"
destroy-on-close
@close="smsDialogData.visible=false"
>
<el-form
ref="smsDialogFormRef"
:model="smsDialogForm"
:rules="smsDialogRules"
label-width="auto"
label-suffix=":"
>
<el-form-item label="手机号">
<span>{{ basicInfoRef.formData.phoneNo }}</span>
</el-form-item>
<el-form-item label="验证码" prop="verificationCode">
<el-input v-model="smsDialogForm.verificationCode" placeholder="请输入验证码">
<template #suffix>
<a v-if="!count" class="itemBlue" @click="getVerificationCodeFunc"> 获取验证码</a>
<span v-else class="itemBlue">{{ count }}</span>
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button
type="primary"
:loading="smsDialogLoading"
@click="submitSms(smsDialogFormRef)"
>
提交
</el-button>
<el-button
@click="smsDialogData.visible=false"
>
关闭
</el-button>
</template>
</el-dialog>
</div>
</template>
<style lang="less" scoped>
.expertEnroll{
.top{
background: url("@/assets/images/expertTopBg.png");
background-size: 100% 100%;
background-repeat: no-repeat;
padding-top: 60px;
padding-bottom: 117px;
font-size: 53px;
font-weight: 600;
color: #FFFFFF;
text-align: center;
line-height: 75px;
}
.header{
height: 60px;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
margin-bottom: 15px;
font-size: 20px;
}
:deep(.el-collapse) {
.el-collapse-item__header {
padding: 0px 16px;
font-size: 14px;
}
.el-collapse-item__content {
padding: 16px 16px 16px 0px;
// margin-left: -50px;
}
.el-collapse-item__header.is-active {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.collapse-title {
flex: 1 0 90%;
order: 1;
.el-collapse-item__header {
flex: 1 0 auto;
order: -1;
}
.el-input-number {
width: 150px !important;
}
}
}
}

</style>

+ 124
- 0
src/pages/expertManage/expertReview/components/leaveDialog.vue Datei anzeigen

@@ -0,0 +1,124 @@
<script name="leaveDialog" setup>
import { ref, getCurrentInstance, watch } from 'vue'
import { leaveSave } from '@/http/apis/expertManage/expertReview'
import { storeToRefs } from 'pinia'
import store from '@/store'
const userInfo = storeToRefs(store.userStore).userInfo
const
{ proxy } = getCurrentInstance(),
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: {
type: Object,
default: undefined
},
title: {
type: String,
default: undefined
}
}),
emits = defineEmits(['close']),
formRef = ref(),
form = ref({
}),
rules = {
postscript: [{ required: true, message: '请输入请假原因', trigger: 'blur' }]
},
submit = async formEl => {
if (!formEl) {
return
}
await formEl.validate(async valid => {
if (valid) {
await leaveSave({
...form.value,
type: 3,
expertId: props.data.expertId || userInfo.value.userId,
meetingId: props.data.meetingId
})
proxy.$message.success('提交成功!')
emits('close', true)
}
})
}
watch(
() => props.visible,
async val => {
if (val) {
console.log(props.data)
} else {
formRef.value.resetFields()
form.value = {}
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
:title="props.title||`填写请假原因-${data?.meetingName}`"
width="600px"
destroy-on-close
@close="emits('close')"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="auto"
label-suffix=":"
>
<el-row>
<template v-if="data?.connecter">
<el-col :span="24">
<el-form-item
label="联系人"
>
{{ data?.connecter }}
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="联系方式"
>{{ data?.contact }}</el-form-item>
</el-col>
</template>
<el-col :span="24">
<el-form-item
label="请假原因"
prop="postscript"
>
<el-input
v-model="form.postscript"
maxlength="200"
placeholder="请输入"
show-word-limit
type="textarea"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="flex justify-center">
<el-button
class="ml-22"
type="primary"
@click="submit(formRef)"
>
提交
</el-button>
<el-button
@click="emits('close')"
>
关闭
</el-button>
</div>
</template>
</el-dialog>
</template>

+ 171
- 0
src/pages/expertManage/expertReview/components/meetingsLeaveDialog.vue Datei anzeigen

@@ -0,0 +1,171 @@
<script name="meetingsLeaveDialog" setup>
import { ref, reactive, watch, h } from 'vue'
import meetingProjectDialog from '../../reviewMeeting/components/meetingProjectDialog.vue'
import store from '@/store'
import leaveDialog from './leaveDialog.vue'
import { meetingListForLeave } from '@/http/apis/expertManage/expertReview'
import { storeToRefs } from 'pinia'
const props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
}
}),
userInfo = storeToRefs(store.userStore).userInfo || {},
emits = defineEmits(['close']),
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '会议名称',
key: 'meetingName',
prop: 'meetingName',
minWidth: '180',
showOverflowTooltip: true
},
{
label: '评审类型',
key: 'meetingTypeName',
prop: 'meetingTypeName'
},
{
label: '评审项目',
key: 'projectName',
slot: 'projectName',
minWidth: '80'
},
{
label: '联系人/联系方式',
key: 'contact',
prop: 'contact',
minWidth: '180',
render: row => h('span', row.connecter + '/' + row.contact)
},
{
label: '是否参与',
key: 'isAbsent',
prop: 'isAbsent',
width: '80',
render: row => h('span', row.expertStatus === 3 || row.expertStatus === 5 ? '是' : '否')
},
{
label: '是否请假',
key: 'isAbsent',
prop: 'isAbsent',
width: '80',
render: row => h('span', row.expertStatus === 5 ? '是' : '否')
},
{
label: '会议状态',
key: 'status',
prop: 'status',
width: '80',
render: row => [
h('span', {
class: ['dot mr-4', `${row.status === 1 ? 'bg-success' : row.status === 3 ? 'bg-danger' : ''}`]
}),
h(
'span',
{
class: `${row.status === 1 ? 'text-success' : row.status === 3 ? 'text-danger' : ''}`
},
row.status === 1 ? '正常' : '已取消'
)
]
},
{
label: '评审时间',
key: 'startTime',
prop: 'startTime',
width: '280',
render: row => h('span', row.startTime + '~' + row.endTime)
},
{
label: '操作',
slot: 'action',
width: '80',
fixed: 'right'
}
]),
tableData = ref(),
total = ref(0),
tableListRef = ref(),
getTableData = async (pageParams = tableListRef.value?.pageParams) => {
const res = await meetingListForLeave({
...pageParams,
expertId: userInfo.value.userId
})
total.value = res.data.total
tableData.value = res.data.records
},
// 查看项目
viewProject = (data) => {
meetingProjectDialogData.value.visible = true
meetingProjectDialogData.value.meetingId = data.meetingId
},
meetingProjectDialogData = ref({
visible: false,
meetingId: undefined
}),
closeMeetingProjectDialog = () => {
meetingProjectDialogData.value.visible = false
},
// 请假
leaveDialogData = reactive({
visible: false,
data: undefined
}),
leave = (data) => {
leaveDialogData.visible = true
leaveDialogData.data = data
},
closeLeaveDialog = (flag) => {
leaveDialogData.visible = false
flag && getTableData()
}
watch(
() => props.visible,
async val => {
if (val) {
getTableData()
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="会议请假"
width="80%"
@close="emits('close')"
>
<table-list
ref="tableListRef"
:column="column"
:total="total"
:data="tableData"
@get-table-data="getTableData"
>
<template #projectName="{scope}">
<a @click="viewProject(scope.row)">查看</a>
</template>
<template #action="{scope}">
<a v-if="scope.row.expertStatus !== 5" @click="leave(scope.row)">请假</a>
<span v-else>-</span>
</template>
</table-list>
<template #footer>
<span class="dialog-footer">
<el-button @click="emits('close')">关闭</el-button>
</span>
</template>
</el-dialog>
<meeting-project-dialog :visible="meetingProjectDialogData.visible" :meeting-id="meetingProjectDialogData.meetingId" @close="closeMeetingProjectDialog" />
<leave-dialog :visible="leaveDialogData.visible" :data="leaveDialogData.data" @close="closeLeaveDialog" />
</template>


+ 88
- 0
src/pages/expertManage/expertReview/components/memberOpinion.vue Datei anzeigen

@@ -0,0 +1,88 @@
<script setup name="memberOpinion">
import store from '@/store'
import Accessory from '@/components/accessory/index.vue'

defineProps({
memberOpinions: Array
})
const { reviewResultOptions } = store.dictStore.globalDicts || {}
</script>
<template>
<div class="memberOpinion">
<div v-for="(item,index) in memberOpinions" :key="index" class="box mb-16">
<div class="flex items-center justify-between title">
<p class="name font-bold flex items-center">
<span>{{ item.creator }}</span>
<el-tag v-if="item.isFinal" class="ml-8">最终评审意见</el-tag>
</p>
<p class="time">
<svg-icon name="time" class="mr-2" />
<span>{{ item.createOn }}</span>
</p>
</div>
<div class="content">
<div v-for="(option,key) in item.reviewTemplateOptions" :key="key" class="item">
<p class="label">{{ option.title }}:</p>
<div>
<p class="value">{{ option.optionsValue }}。</p>
<p class="value">{{ option.otherAdvice }}</p>
</div>

</div>
<div class="item">
<p class="label">其他意见或建议:</p>
<p class="value">{{ item. otherAdvice }}</p>
</div>
<div class="item">
<p class="label">附件:</p>
<p class="value">
<accessory :file-name="item.attachFile?.originalFileName" :file-id="item?.attachFileId" />
</p>
</div>
<div class="item">
<p class="label">评审结果:</p>
<p class="value ">
<span
:class="`dot ${item.reviewResult===1?'bg-success':item.reviewResult===2?'bg-warning':'bg-danger'}`"
></span>
&nbsp;<span>{{ reviewResultOptions[item.reviewResult] }}</span>
</p>
</div>
</div>
</div>
</div>
</template>
<style lang="less">
.memberOpinion{
.box{
background: #FFFFFF;
box-shadow: 0px 3px 6px 0px rgba(62,99,170,0.06);
border-radius: 4px;
border: 1px solid #D8DADF;
padding: 24px;
.title{
margin-bottom: 24px;
.time{
display: flex;
align-items: center;
color: rgba(0,0,0,0.45);
}
}
.content{
.item{
display: flex;
align-items: center;
&:not(:last-of-type){
margin-bottom: 8px;
}
}
.label{
color: rgba(0,0,0,0.45);
}
.value{
color: rgba(0,0,0,0.65);
}
}
}
}
</style>

+ 188
- 0
src/pages/expertManage/expertReview/components/projectList.vue Datei anzeigen

@@ -0,0 +1,188 @@
<script setup name="projectList">
import { reactive } from 'vue'
import store from '@/store'
import noData from '@/components/noData/index.vue'
const { projectTypeOptions, businessTerritory, meetingTypeOptions } = store.dictStore.globalDicts || {},
props = defineProps({
listData: Array,
// 分页
pageSizes: {
type: Array,
default: () => [10, 20, 30, 40]
},
total: {
type: Number,
default: 0
},
small: {
type: Boolean,
default: false
}
}),
emits = defineEmits(['getTableData', 'preExamDeclare', 'toDetail']),
// 分页
pageParams = reactive({
pageNumber: 1,
pageSize: props.pageSizes[0]
}),
handleSizeChange = () => {
emits('getTableData', pageParams)
},
handleCurrentChange = () => {
emits('getTableData', pageParams)
},
goToDetail = (item) => {
if (new Date().getTime() >= new Date(item.reviewTime).getTime() && (!item.reviewed || (item.isHeadman && item.reviewed < 2))) {
emits('toDetail', item, 1)
} else {
emits('toDetail', item, 2)
}
}
defineExpose({ pageParams })

</script>

<template>
<div class="projectList">
<template v-if="listData?.length">
<div v-for="(item,index) in listData" :key="index" class="list">
<div class="left">
<svg-icon
name="projectIcon"
class="icon"
/>
<div class="info">
<div class="tit">
<p class="mb-4 pointTit" @click="goToDetail(item)">{{ item.projectName }}</p>
<el-tag v-if="item.bizDomain">{{ businessTerritory[item.bizDomain] }}</el-tag>
</div>
<el-row :gutter="4">
<el-col :span="6" class="mb-8">
<span class="label">申报单位:</span>
<span class="value">{{ item.buildOrgName || '-' }}</span>
</el-col>
<el-col :span="6" class="mb-8">
<span class="label">项目类型:</span>
<span class="value">{{ projectTypeOptions[item.projectType] || '-' }}</span>
</el-col>
<el-col :span="6" class="mb-8">
<span class="label">申报金额:</span>
<span class="value">{{ item.declaredAmount || '-' }}万元</span>
</el-col>
<el-col :span="6" class="mb-8">
<span class="label">预算年度:</span>
<span class="value">{{ item.projectYear }}年</span>
</el-col>
<el-col :span="12" class="mb-8">
<span class="label">评审时间:</span>
<span class="value">{{ item.reviewTime }}~{{ item.endReviewTime }}</span>
</el-col>
<el-col :span="6" class="mb-8">
<span class="label">评审类型:</span>
<span class="value">{{ meetingTypeOptions[item.reviewType] }}</span>
</el-col>
<el-col :span="6" class="mb-8">
<span class="label">联系人:</span>
<span class="value">{{ item.connecter }}</span>
</el-col>
<el-col :span="6" class="mb-8">
<span class="label">联系方式:</span>
<span class="value">{{ item.contact }}</span>
</el-col>
</el-row>
</div>
</div>
<div class="right">
<a v-if="new Date().getTime()>=new Date(item.reviewTime).getTime()&&(!item.reviewed||(item.isHeadman&&item.reviewed<2))" @click="emits('toDetail',item,1)">处理</a>
<a v-else @click="emits('toDetail',item,2)">详情</a>
</div>
</div>
</template>
<noData v-else />
<el-pagination
v-model:currentPage="pageParams.pageNumber"
v-model:page-size="pageParams.pageSize"
:small="small"
background
:page-sizes="props.pageSizes"
layout="total, sizes, prev, pager, next"
:total="props.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<style lang="less">
.projectList {
.list {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding: 16px;
box-shadow: inset 0px -1px 0px 0px #D8DADF;

.left {
display: flex;
flex: 1;

.icon {
font-size: 44px;
margin-right: 24px;
}

.info {
flex: 1;

.tit {
font-weight: 400;
color: rgba(0, 0, 0, 0.85);
margin: 11px 0 16px;
}

.label {
color: rgba(0, 0, 0, 0.45);
}

.value {
color: rgba(0, 0, 0, 0.65);
}
.statusTag {
font-weight: 400;
line-height: 18px;
border-radius: 4px;
display: inline-block;
padding: 4px;

&.status-warning {
color: #FFA43D;
background: rgba(255, 164, 61, 0.06);
}
&.status-success {
color: #4ECB74;
background: rgba(78,203,116,0.06);
}
&.status-danger {
color: #FF3B30;
background: rgba(255,59,48,0.06);
}
}
}
}
.right{
display: flex;
flex-direction: column;
align-items: center;
a{
margin:0
}
}
}

.el-pagination {
padding: 16px 16px 0 16px;
flex-wrap: wrap;
justify-content: flex-end;
}
}
</style>

+ 157
- 0
src/pages/expertManage/expertReview/components/reviewComments.vue Datei anzeigen

@@ -0,0 +1,157 @@
<script name="reviewCommentsDialog" setup>
import { ref, onMounted } from 'vue'
import { fileFormatVerification, handleFileSuccess, handleFileError, handleFilePreview, fileTypes, fileDesc } from '@/utils/uploadAction.js'
import store from '@/store'
const
uploadUrl = store.dictStore.uploadUrl,
props = defineProps({
templateData: Object
}),
formRef = ref(),
form = ref({
templates: [],
attachments: []
}),
rules = {
otherAdvice: [{ required: true, message: '请输入意见', trigger: 'blur' }],
reviewResult: [{ required: true, message: '请选择评审结果', trigger: 'blur' }]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
}
onMounted(async () => {
form.value.templates = props.templateData.templates.map(i => {
return {
optionSerialNo: undefined,
otherAdvice: '',
questionSerialNo: i.serialNo
}
})
form.value.templateId = props.templateData.templateId
})
defineExpose({ validForm, form })
</script>

<template>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="auto"
label-suffix=":"
label-position="top"
class="reviewForm"
>
<el-row>
<template v-if="form.templates?.length">
<el-col
v-for="(item,index) in templateData.templates"
:key="index"
:span="24"
>
<el-form-item
:label="item.title"
:prop="`templates[${index}].optionSerialNo`"
:rules="[{required:true,message:'请选择'}]"
>
<el-checkbox-group v-if="item.optionType===2" v-model="form.templates[index].optionSerialNo">
<el-checkbox
v-for="(option,key) in item.options"
:key="key"
:label="option.serialNo"
>{{ option.option }}</el-checkbox>
</el-checkbox-group>
<el-radio-group
v-else
v-model="form.templates[index].optionSerialNo"
class="myWrap"
>
<el-radio
v-for="(option,key) in item.options"
:key="key"
:label="option.serialNo"
>{{ option.option }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:prop="`templates[${index}].otherAdvice`"
>
<el-input
v-model="form.templates[index].otherAdvice"
:rows="2"
type="textarea"
:placeholder="`请输入${item.title}的其他意见或建议`"
/>
</el-form-item>
</el-col>
</template>
<el-col :span="24">
<el-form-item
label="其他意见或建议"
prop="otherAdvice"
>
<el-input
v-model="form.otherAdvice"
:rows="2"
maxlength="200"
type="textarea"
show-word-limit
placeholder="请输入其他意见或建议"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="附件"
prop="attachments"
>
<el-upload
v-model:file-list="form.attachments"
class="w-full"
:action="uploadUrl"
:on-success="res => handleFileSuccess(res, form.attachments,true)"
:on-error="handleFileError"
:before-upload="file=>fileFormatVerification(file, {types: fileTypes})"
:accept="fileTypes.map(i=>`.${i}`).join(',')"
:limit="1"
:on-preview="handleFilePreview"
>
<el-button type="primary" class="mr-4">上传附件</el-button>
<template #tip>
<div class="el-upload__tip">支持{{ fileDesc }}文件</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="24" class="result">
<el-form-item
label="评审结果"
prop="reviewResult"
class="mb-0"
>
<el-radio-group
v-model="form.reviewResult"
class="ml-4"
>
<el-radio :label="1">评审通过</el-radio>
<el-radio :label="2">通过需调整</el-radio>
<el-radio :label="3">修改方案后重新评审</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less">
.reviewForm{
.result{
background: rgba(0,87,255,0.06);
border-radius: 4px;
border: 1px solid #0057FF;
padding:24px 24px 0;
}
}
</style>

+ 141
- 0
src/pages/expertManage/expertReview/fillReviewComments/index.vue Datei anzeigen

@@ -0,0 +1,141 @@
<script name="fillReviewComments" setup>
import { getCurrentInstance, onMounted, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import reviewComments from '../components/reviewComments.vue'
import memberOpinion from '../components/memberOpinion.vue'
import { template } from '@/http/apis/expertManage/reviewTemplateConfig'
import { listForGroupLeader, save, templatesById } from '@/http/apis/expertManage/expertReview'

const { proxy } = getCurrentInstance(),
router = useRouter(),
route = useRoute(),

// 获取模板
templateData = ref(),
getTemplate = async () => {
const res = await template({ templateType: route.query.reviewType, regionCode: route.query.regionCode })
templateData.value = res.data
reviewVisible.value = true
},
reviewVisible = ref(false),
// 提交
loading = ref(false),
reviewCommentsRef = ref(),
submit = () => {
reviewCommentsRef.value.validForm(async (valid) => {
if (valid) {
loading.value = true
const postData = {
meetingId: route.query.meetingId,
projectId: route.query.projectId,
projectCode: route.query.projectCode,
...reviewCommentsRef.value.form,
reviewTemplateOptions: reviewCommentsRef.value.form.templates.map(i => {
return {
...i,
optionSerialNo: Array.isArray(i.optionSerialNo) ? i.optionSerialNo.map(r => r) : [i.optionSerialNo]
}
}),
attachFileId: reviewCommentsRef.value.form.attachments?.length && reviewCommentsRef.value.form.attachments[0].response.data.id || undefined,
isFinal: route.query.type * 1 === 2,
templates: undefined,
attachments: undefined
}
try {
await save(postData)
proxy.$message.success('提交成功')
loading.value = false
router.go(-2)
} catch (e) {
loading.value = false
}
}
})
},
// 组员意见-抽屉
drawerVisible = ref(false),
templatesData = ref([]), // 模板数据
memberOpinions = ref([]), // 组员意见
showDrawer = async () => {
const res = await listForGroupLeader({ projectId: route.query.projectId, meetingId: route.query.meetingId })
const res1 = await templatesById({ templateIds: res.data.map(i => i.templateId).join(',') })
templatesData.value = res1.data
memberOpinions.value = res.data && res.data.map(i => {
return {
...i,
reviewTemplateOptions: i.reviewTemplateOptions && i.reviewTemplateOptions.map(temp => {
const data = templatesData.value.find(j => i.templateId === j.templateId).templates
return {
...temp,
title: data.find(r => r.serialNo === temp.questionSerialNo)?.title,
optionsValue: data.find(r => r.serialNo === temp.questionSerialNo)?.options.filter(j => temp.optionSerialNo.includes(j.serialNo)).map(j => j.option).join('、')
}
}) || []
}
}) || []
drawerVisible.value = true
}
onMounted(() => {
getTemplate()
})
</script>

<template>
<div class="footerPage">
<el-card class="w-full" shadow="never">
<el-row :gutter="16">
<el-col :span="14">
<review-comments v-if="reviewVisible" ref="reviewCommentsRef" :template-data="templateData" />
</el-col>

<!-- 最终意见显示按钮-->
<el-col v-if="route.query.type*1===2" :span="10">
<div
v-if="!drawerVisible"
class="viewBtn"
@click="showDrawer"
>
<svg-icon name="eye" />
<span>查看评审意见</span>
</div>
</el-col>
</el-row>
</el-card>
<div class="footer">
<el-button type="primary" :loading="loading" @click="submit">提交</el-button>
<el-button @click="router.go(-1)">关闭</el-button>
</div>
</div>
<el-drawer
v-model="drawerVisible"
title="组员意见"
style="position: absolute"
direction="rtl"
size="40%"
:modal="false"
:append-to-body="false"
modal-class="myDrawerModal"
>
<member-opinion :member-opinions="memberOpinions" />
</el-drawer>
</template>
<style lang="less">
.viewBtn{
width: 36px;
background: rgba(0,87,255,0.08);
border-radius: 4px;
border: 1px solid #0057FF;
padding: 8px;
font-size: 14px;
display: flex;
align-items: center;
flex-direction: column;
text-align: center;
justify-content: center;
color: #0057FF;
cursor: pointer;
}
.myDrawerModal{
position: static !important;
}
</style>

+ 66
- 0
src/pages/expertManage/expertReview/handleExpertReview/index.vue Datei anzeigen

@@ -0,0 +1,66 @@
<script name='handleExpertReview' setup>
import { onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import projectInfo from '../../../projectStoreManage/projectStore/projectDetail/components/projectInfo.vue'
import { getProjectDetail } from '@/http/apis/declareMange'
import { storeToRefs } from 'pinia'
import store from '@/store'
import { meetingBasicInfo } from '@/http/apis/expertManage/reviewMeeting'
// 项目详情
const userInfo = storeToRefs(store.userStore).userInfo || {},
detailData = ref({}),
router = useRouter(),
route = useRoute(),
getDetail = async () => {
const res = await getProjectDetail({ id: route.query.projectId })
detailData.value = res.data
},
toReviewComments = (type) => {
router.push({ name: 'fillReviewComments', query: { ...route.query, type, regionCode: basicInfo.value.regionCode, projectCode: detailData.value.projectCode }})
},
// 获取会议详情
basicInfo = ref(),
getMeetingDetail = async () => {
const res = await meetingBasicInfo(route.query.meetingId)
basicInfo.value = res.data
}
onMounted(() => {
getDetail()
getMeetingDetail()
})
</script>

<template>
<div class="w-full footerCard handleExpertReview">
<div
v-waterMarker="{text:userInfo.realName+userInfo.phoneNo.substring(userInfo.phoneNo.length - 4)}"
style="position: absolute;pointer-events: none;width:100%;height:100%"
>
</div>
<project-info :detail-data="detailData" />
<div class="footer">
<template v-if="new Date().getTime()>=new Date(basicInfo?.startTime).getTime()&&route.query.type==='1'">
<el-button
v-if="route.query.reviewed==='0'"
type="primary"
@click="toReviewComments(1)"
>填写评审意见</el-button>
<el-button
v-if="route.query.isHeadman==='true'&&route.query.reviewed==='1'"
type="primary"
@click="toReviewComments(2)"
>填写最终意见</el-button>
</template>
<el-button
plain
@click="router.go(-1)"
>返回</el-button>
</div>
</div>
</template>

<style lang='less'>
.handleExpertReview{
padding-bottom: 56px;
}
</style>

+ 189
- 0
src/pages/expertManage/expertReview/index.vue Datei anzeigen

@@ -0,0 +1,189 @@
<script setup name='expertReview'>
import { reactive, ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { listReviewProject } from '@/http/apis/expertManage/expertReview'
import projectList from './components/projectList.vue'
import { storeToRefs } from 'pinia'
import store from '@/store'
import meetingsLeaveDialog from './components/meetingsLeaveDialog.vue'
const userInfo = storeToRefs(store.userStore).userInfo,
listRef = ref(),
router = useRouter(),
searchForm = reactive({
projectName: undefined,
buildOrgName: undefined
}),
// 列表数据
data = ref([]),
total = ref(0),
count = ref(0),
getTableData = async (pageParams = listRef.value.pageParams) => {
const res = await listReviewProject({
...pageParams,
...searchForm,
reviewed: activeName.value,
userId: userInfo.value.userId
})
console.log(activeName.value)
data.value = res.data.records
total.value = res.data.total
if (activeName.value === 'false') {
count.value = res.data.total
}
},
// 查询
search = () => {
getTableData()
},
// 重置
reset = () => {
searchForm.projectName = undefined
searchForm.buildOrgName = undefined
listRef.value.pageParams.pageNumber = 1
listRef.value.pageParams.pageSize = 10
getTableData()
},
activeName = ref('false'),
handleClick = ({ props }) => {
activeName.value = props.name
getTableData()
},
// 详情
toDetail = (item, type) => {
router.push({
name: 'handleExpertReview',
query: {
projectId: item.projectId, // 项目id
meetingId: item.meetingId, // 会议id
isHeadman: item.isHeadman, // 是否组长
reviewType: item.reviewType, // 评审类型
type,
reviewed: item.reviewed
}
})
},
// 会议请假
meetingsLeaveDialogData = reactive({
visible: false
}),
showMeetingsLeaveDialog = () => {
meetingsLeaveDialogData.visible = true
},
closeMeetingsLeaveDialog = () => {
meetingsLeaveDialogData.visible = false
}

onMounted(() => {
getTableData()
})
</script>

<template>
<el-row class="box-card">
<el-col :span="24">
<el-card class="w-full search">
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
>
<el-col :span="8">
<el-form-item label="项目名称">
<el-input
v-model="searchForm.projectName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申报单位">
<el-input
v-model="searchForm.buildOrgName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="search"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8 tab-card">
<template #header>
<div class="flex justify-between items-center">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane :label="`待评审(${count})`" name="false" />
<el-tab-pane label="已评审" name="true" />
</el-tabs>
<el-button
type="primary"
plain
size="small"
@click="showMeetingsLeaveDialog"
>会议请假</el-button>
</div>
</template>
<project-list
ref="listRef"
:list-data="data"
:total="total"
@get-table-data="getTableData"
@to-detail="toDetail"
/>
</el-card>
</el-col>
</el-row>
<meetings-leave-dialog :visible="meetingsLeaveDialogData.visible" @close="closeMeetingsLeaveDialog" />
</template>

<style lang='less' scoped>
.projectDynamicContainer{
height: 540px;
overflow: scroll;
.projectDynamic {
width: 100%;
height: 150px;
// background-color: #bfc;
border-bottom: solid 1px rgba(216, 218, 223);
margin-bottom: 10px;
display: flex;
.leftPart{
width: 84px;
height: auto;
display: flex;
justify-content: center;
}
.rightPart{
flex: 1;
height: auto;
.checkDetail{
color: rgba(0, 87, 255, 1);
cursor: pointer;
}
}
.projectAvartarStyle{
width: 44px;
height: 44px;
}
}

}
.el-pagination {
padding: 16px 16px 0 16px;
flex-wrap: wrap;
justify-content: flex-end;
}</style>

+ 546
- 0
src/pages/expertManage/expertStore/addOrEditExpert/components/basicInfo.vue Datei anzeigen

@@ -0,0 +1,546 @@
<script name="basicInfo" setup>
import { onMounted, ref } from 'vue'
import store from '@/store'
import { storeToRefs } from 'pinia'
import { districtList } from '@/http/apis/commonApi'
import { fileFormatVerification, downloadFileUrl } from '@/utils/uploadAction.js'
import { zzdInfo } from '@/http/apis/expertManage/expertStore'
const uploadUrl = store.dictStore.uploadUrl,
userInfo = storeToRefs(store.userStore).userInfo,
{ nationList } = store.dictStore.globalDicts,
{ tagList } = storeToRefs(store.dictStore),
formData = ref({
expertIntentionWorkRegions: [{}], // 履职意向
avatarFile: { fileId: '' }
}),
formRef = ref(),
// 手机号码校验
checkTelPhone = (rule, value, callback) => {
if (value === '') {
return callback(new Error('请输入正确的手机号'))
} else {
const regIdCard =
/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
if (regIdCard.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的手机号'))
}
}
},
idCardValidator = (rule, value, callback) => {
const _IDRe18 = /^([1-6][1-9]|50)\d{4}(18|19|20)\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
const _IDre15 = /^([1-6][1-9]|50)\d{4}\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}$/
// 校验身份证:
if (!(_IDRe18.test(value) || _IDre15.test(value))) {
callback('请输入正确格式')
} else {
callback()
}
},
rules = {
phoneNo: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ validator: checkTelPhone, trigger: 'blur' }
],
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' }
],
gender: [
{ required: true, message: '请选择性别', trigger: 'blur' }
],
hometown: [
{ required: true, message: '请选择籍贯', trigger: 'blur' }
],
nationality: [
{ required: true, message: '请选择民族', trigger: 'blur' }
],
political: [
{ required: true, message: '请选择政治面貌', trigger: 'blur' }
],
idCard: [
{ required: true, message: '请输入正确的身份证号', trigger: 'blur' },
{ validator: idCardValidator, tigger: 'blur' }
],
birth: [
{ required: true, message: '请选择出生年月', trigger: 'blur' }
],
bankNo: [
{ required: true, message: '请输入银行卡号', trigger: 'blur' }
],
bank: [
{ required: false, message: '请输入开户行', trigger: 'blur' }
],
email: [
{ required: false, message: '请输入电子邮箱', trigger: 'blur' },
{
pattern: /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
message: '请输入正确邮箱',
trigger: 'blur'
}
],
expertSource: [
{
required: true,
trigger: 'change',
message: '请选择专家来源'
}
],
expertRegionInfo: [
{
required: true,
trigger: 'change',
message: '请选择专家级别'
}
],
expertIntentionWorkRegions: [
{
required: true,
trigger: 'change',
message: '请选择履职意向'
}
],
expertType: [
{ required: true, message: '请选择专家类型', trigger: 'blur' }
],
avatarUrl: [
{
required: true,
message: '请上传免冠照'
}
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = async (data) => {
formData.value = {
...data,
political: data.political?.[0] || undefined,
expertSource: data.expertSource?.[0] || undefined,
expertType: data.expertType?.[0] || undefined,
expertRegionInfo: data.expertRegionInfo.regionName?.split('@@').slice(1),
expertIntentionWorkRegions: data.expertIntentionWorkRegions?.map(i => { return { unionCode: i.regionName.split('@@').slice(1) } }),
avatarUrl: data?.avatarFile?.fileId && await downloadFileUrl(data.avatarFile.fileId),
avatarFile: data?.avatarFile || { fileId: '' }
}
},
regionTree = ref(),
// 增加或删除履职意向
updateWorkRegions = (type, index) => {
if (type === 'add') {
formData.value.expertIntentionWorkRegions.push({
id: new Date().getTime()
})
} else {
formData.value.expertIntentionWorkRegions.splice(index, 1)
}
},
// 上传免冠照
handleAvatarSuccess = res => {
formData.value.avatarFile['fileId'] = res.data.id
downloadFileUrl(res.data.id).then(res => {
formData.value.avatarUrl = res
})
},
// 获取浙政钉信息
getZzdInfo = async () => {
const res = await zzdInfo({ phoneNo: formData.value.phoneNo })
formData.value.isDingUser = res.data.isDingUser
if (res.data.isDingUser) {
formData.value.name = res.data.name
}
}
defineExpose({ validForm, formData, setFormData })
onMounted(async () => {
const res = await districtList({ regionCode: 330500, regionLevel: 2 })
regionTree.value = [res.data]
})
</script>
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="120px"
label-suffix=":"
scroll-to-error
class="basicInfo"
>
<el-row :gutter="8">
<el-col :span="8">
<el-form-item
label="手机号"
prop="phoneNo"
>
<el-input
v-model="formData.phoneNo"
placeholder="请输入"
:maxlength="11"
:disabled="!!$route.query.id||$route.name==='selfEditExpertInfo'"
@blur="getZzdInfo"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="姓名"
prop="name"
>
<el-input
v-model="formData.name"
placeholder="请输入"
:disabled="!!$route.query.id||$route.name==='selfEditExpertInfo'"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="性别"
prop="gender"
>
<el-select
v-model="formData.gender"
class="w-full"
placeholder="请选择"
>
<el-option value="1" label="男" />
<el-option value="0" label="女" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="籍贯"
prop="hometown"
>
<el-input
v-model="formData.hometown"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="民族"
prop="nationality"
>
<el-select
v-model="formData.nationality"
class="m-2 w-full"
placeholder="请选择"
>
<el-option
v-for="item in nationList"
:key="item.id"
:label="item.info"
:value="item.info"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="政治面貌"
prop="political"
>
<el-select
v-model="formData.political"
class="w-full"
placeholder="请选择"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.politicalDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="身份证"
prop="idCard"
>
<el-input
v-model="formData.idCard"
placeholder="请输入"
:maxlength="18"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="办公电话"
prop="officePhone"
>
<el-input
v-model="formData.officePhone"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="出生年月"
prop="birth"
>
<el-date-picker
v-model="formData.birth"
type="month"
placeholder="请选择"
format="YYYY-MM"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="银行卡号"
prop="bankNo"
>
<el-input
v-model="formData.bankNo"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="开户银行"
prop="bank"
>
<el-input
v-model="formData.bank"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="电子邮箱"
prop="email"
>
<el-input
v-model="formData.email"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col v-if="false" :span="8">
<el-form-item
label="入库意向"
prop="expertSource"
>
<el-select
v-model="formData.expertSource"
class="w-full"
placeholder="请选择"
clearable
>
<el-option
v-for="(item,index) in tagList &&
tagList.length &&
tagList.find(i => i.tagCode === 'expert_source')
.children"
:key="index"
:label="item.tagName"
:value="item.unionCode"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="专家级别"
prop="expertRegionInfo"
>
<el-cascader
v-model="formData.expertRegionInfo"
:options="regionTree"
:props="{
value: 'unionCode',
label: 'name'
}"
clearable
placeholder="请选择"
class="w-full"
:disabled="$route.name==='selfEditExpertInfo'||$route.query.id&&userInfo.regionCode!==formData?.expertRegionInfo?.[formData.expertRegionInfo?.length-1].split('##')[0]"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="专家来源"
>
<el-select
v-model="formData.expertSource"
class="w-full"
placeholder="请选择"
clearable
value-key="tagCode"
>
<el-option
v-for="(item,index) in store.dictStore.expertSourceDict"
:key="index"
:label="item.tagName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="专家类型"
prop="expertType"
>
<el-select
v-model="formData.expertType"
class="w-full"
placeholder="请选择"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.expertTypeDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="履职意向"
prop="expertIntentionWorkRegions"
>
<el-row
v-for="(item, index) in formData
.expertIntentionWorkRegions"
:key="item.id"
class="intention-item w-full"
>
<el-col :span="24">
<el-cascader
v-model="
formData.expertIntentionWorkRegions[index]
.unionCode
"
:options="regionTree"
:props="{
value: 'unionCode',
label: 'name'
}"
clearable
style="width: 100%"
class="mb-4"
/>
<span
v-if="index > 0"
style="position: absolute; right: -20px"
@click="updateWorkRegions('del', index)"
>
<el-icon>
<Delete color="#D40000" />
</el-icon>
</span>
</el-col>
</el-row>
<p class="addGhostBtn mt-8 w-full">
<el-button
class="w-full"
type="primary"
plain
style="margin: 0"
@click="updateWorkRegions('add')"
>
+ 增加履职意向地区
</el-button>
</p>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
class="avatarForm"
label="一寸免冠照"
prop="avatarUrl"
style="margin-bottom: 32px"
>
<el-upload
class="avatar-uploader"
:action="uploadUrl"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="
file =>
fileFormatVerification(file, {
size: 500,
types: ['png', 'jpg', 'jpeg']
})
"
accept="image/png,image/jpeg"
>
<img
v-if="formData.avatarUrl"
:src="formData.avatarUrl"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon">
<el-icon><Camera /></el-icon>
</i>
</el-upload>
<div class="limit-name ml-4">请上传蓝底1寸免冠照片,小于500Kb</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less">
.basicInfo{
.avatarForm {
:deep(.el-form-item__content) {
display: block;
}
}
.avatar-uploader {
.el-upload {
background: #edf4ff;
border-radius: 4px;
border: 1px dashed #007df1;
cursor: pointer;
position: relative;
overflow: hidden;
&:hover {
border-color: #409eff;
}
}
.avatar-uploader-icon {
border-radius: 4px;
border: 1px dashed #007df1;
font-size: 28px;
color: #007df1;
width: 104px;
height: 104px;
display: flex;
justify-content: center;
align-items: center;
}
.avatar {
width: 80px;
height: 80px;
display: block;
}
}
.limit-name {
margin-top: 13px;
color: #999999;
font-size: 12px;
}
}
</style>

+ 232
- 0
src/pages/expertManage/expertStore/addOrEditExpert/components/eduInfo.vue Datei anzeigen

@@ -0,0 +1,232 @@
<script name="eduInfo" setup>
import { onMounted, getCurrentInstance, ref } from 'vue'
import store from '@/store'
import { districtList } from '@/http/apis/commonApi'
import { fileFormatVerification, handleFileSuccess, handleFilePreview } from '@/utils/uploadAction.js'
const uploadUrl = store.dictStore.uploadUrl,
{ proxy } = getCurrentInstance(),
formData = ref({
}),
formRef = ref(),
rules = {
edu: [
{ required: true, message: '请选择学历', trigger: 'blur' }
],
degree: [
{ required: true, message: '请选择学位', trigger: 'blur' }
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
fileExceed = (files, uploadFiles) => {
proxy.$message.warning('仅限上传一个文件')
},
// 回显
setFormData = async (data) => {
formData.value = {
...data,
edu: data.edu?.[0] || undefined,
degree: data.degree?.[0] || undefined,
degreeCertificateFile: data.degreeCertificateFile && data.degreeCertificateFile.map(i => {
return {
name: i.fileName,
response: {
data: {
id: i.fileId
}
},
fileUrlById: i.url
}
}),
graduationCertificateFile: data.graduationCertificateFile && data.graduationCertificateFile.map(i => {
return {
name: i.fileName,
response: {
data: {
id: i.fileId
}
},
fileUrlById: i.url
}
})
}
},
regionTree = ref()
defineExpose({ validForm, formData, setFormData })
onMounted(async () => {
const res = await districtList({ regionCode: 330500, regionLevel: 2 })
regionTree.value = [res.data]
})
</script>
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="100px"
label-suffix=":"
scroll-to-error
class="eduInfo"
>
<el-row :gutter="8">
<el-col :span="8">
<el-form-item
label="毕业学校"
prop="school"
>
<el-input
v-model="formData.school"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="毕业时间"
prop="graduatedAt"
>
<el-date-picker
v-model="formData.graduatedAt"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="所学专业"
prop="academicTitle"
>
<el-input
v-model="formData.academicTitle"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="学历" prop="edu">
<el-select
v-model="formData.edu"
placeholder="请选择学历"
value-key="dictionaryCode"
clearable
class="w-full"
>
<el-option
v-for="(item, index) in store.dictStore.eduDict "
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="学位" prop="degree">
<el-select
v-model="formData.degree"
placeholder="请选择学位"
value-key="dictionaryCode"
class="w-full"
>
<el-option
v-for="(item, index) in store.dictStore.degreeDict "
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="毕业证书"
prop="graduationCertificateFile"
>
<el-upload
v-model:file-list="formData.graduationCertificateFile"
class="w-full"
:action="uploadUrl"
:limit="1"
:on-exceed="fileExceed"
:on-success="
res =>
handleFileSuccess(
res,
formData.graduationCertificateFile
)
"
:on-preview="handleFilePreview"
accept="application/pdf,image/png,image/jpeg"
:before-upload="
file =>
fileFormatVerification(file, {
size: 1024,
types: ['png', 'jpg', 'jpeg','pdf']})"
>
<el-button
type="primary"
plain
>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持扩展名:.pdf.png .jpg .pdf ,文件大小不超过1M
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="学位证书"
prop="degreeCertificateFile"
>
<el-upload
v-model:file-list="formData.degreeCertificateFile"
class="w-full"
:action="uploadUrl"
:on-exceed="fileExceed"
:limit="1"
:on-success="
res =>
handleFileSuccess(
res,
formData.degreeCertificateFile
)
"
:before-upload="
file =>
fileFormatVerification(file, {
size: 1024,
types: ['png', 'jpg', 'jpeg','pdf']
})
"
accept="application/pdf,image/png,image/jpeg,image/jpg"
:on-preview="handleFilePreview"
>
<el-button
type="primary"
plain
>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持扩展名:.pdf.png .jpg .pdf,文件大小不超过1M
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less">
.eduInfo{
}
</style>

+ 80
- 0
src/pages/expertManage/expertStore/addOrEditExpert/components/expertOtherInfo.vue Datei anzeigen

@@ -0,0 +1,80 @@
<script name="expertOtherInfo" setup>
import { onMounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import store from '@/store'
const { tagList } = storeToRefs(store.dictStore),
formData = ref({
}),
formRef = ref(),
rules = {},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
...data,
other: data.other && data.other.map(i => `${i.tagName}##${i.tagCode}`)
}
}
defineExpose({ validForm, formData, setFormData })
onMounted(async () => {
})
</script>
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="120px"
label-suffix=":"
scroll-to-error
class="expertOtherInfo"
>
<el-row :gutter="8">
<el-col :span="24">
<el-form-item label="其他标签">
<el-tree-select
v-model="formData.other"
placeholder="请选择其他标签"
:data="
tagList &&
tagList.length &&
tagList.find(i => i.tagCode === 'other').children||[]
"
:props="{
label: 'tagName',
value: 'unionCode'
}"
node-key="unionCode"
collapse-tags
multiple
show-checkbox
check-on-click-node
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="备注"
>
<el-input
v-model="formData.remark"
maxlength="200"
show-word-limit
type="textarea"
placeholder="请输入"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less">
.expertOtherInfo{
}
</style>

+ 315
- 0
src/pages/expertManage/expertStore/addOrEditExpert/components/jobInfo.vue Datei anzeigen

@@ -0,0 +1,315 @@
<script name="jobInfo" setup>
import { onMounted, ref } from 'vue'
import { getOrgLevelByLevel, getOrgTree } from '@/http/apis/systemManage/unitManage'
import { getBusinessstripLine } from '@/http/apis/commonApi'
import store from '@/store'
const formData = ref({
companyAttribute: undefined
}),
formRef = ref(),
rules = {
company: [
{ required: true, message: '请上选择工作单位', trigger: 'blur' }
],
companyUniqCode: [
{ required: true, message: '工作单位code不能为空', trigger: 'blur' }
],
legalEntityCode: [
{ required: true, message: '请输入单位法人编号', trigger: 'blur' }
],
administrativeDuties: [
{ required: true, message: '请输入行政职务', trigger: 'blur' }
],
startWorkAt: [
{ required: true, message: '请选择开始工作日期', trigger: 'blur' }
],
administrativeRank: [
{ required: true, message: '请选择行政职级', trigger: 'blur' }
],
jobStatus: [
{ required: true, message: '请选择在职状态', trigger: 'blur' }
],
retiredAt: [
{ required: true, message: '请选退休日期', trigger: 'blur' }
],
companyAttribute: [
{ required: true, message: '请选单位类型', trigger: 'blur' }
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
// 回显
setFormData = (data) => {
formData.value = {
...data,
administrativeRank: data.administrativeRank?.[0] || undefined,
jobStatus: data.jobStatus?.[0] || undefined,
companyAttribute: data.companyAttribute?.[0] || undefined
}
},
// 工作单位
orgTreeRef = ref(),
changeCompany = () => {
formData.value.company = orgTreeRef.value.getCurrentNode().name
},
// 获取单位组织架构
loadNode = async (node, resolve) => {
if (node.level === 0) {
const res = await getOrgLevelByLevel({
isCompetentUnit: true,
isSuperiorLineCompetentUnit: true
})
resolve(res.data)
} else {
const res = await getOrgLevelByLevel({
parentCode: node.data.organizationCode
})
if (res.data?.length) {
resolve(res.data)
} else {
resolve([])
}
}
},
lineListData = ref([]),
getLineList = async () => {
const res = await getBusinessstripLine()
lineListData.value = res.data
},
companyTreeData = ref(),
getCompany = (data) => {
const items = []
data.forEach(i => {
items.push({
name: i.title,
organizationCode: i.key,
children: i.children?.lengt ? getCompany(i.children) : []
})
})
return items
},
remoteMethod = async (query) => {
const res = await getOrgTree({ organizationName: query })
companyTreeData.value = getCompany(res.data)
}
defineExpose({ validForm, formData, setFormData })
onMounted(async () => {
getLineList()
})
</script>
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="120px"
label-suffix=":"
scroll-to-error
class="jobInfo"
>
<el-row :gutter="8">
<el-col :span="8">
<el-form-item
label="工作单位"
prop="company"
>
<el-tree-select
ref="orgTreeRef"
v-model="formData.companyUniqCode"
:data="companyTreeData"
class="w-full"
node-key="organizationCode"
lazy
:check-strictly="true"
:load="loadNode"
:cache-data="formData.company&&formData.companyUniqCode?[{organizationCode:formData.companyUniqCode,name:formData.company}]:[]"
:props="{
label:'name',
value:'organizationCode'
}"
filterable
remote
:remote-method="remoteMethod"
@change="changeCompany"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="工作单位code"
prop="formData.companyUniqCode"
>
<el-input
v-model="formData.companyUniqCode"
placeholder="请选择"
disabled
/>
</el-form-item>
</el-col>

<el-col :span="8">
<el-form-item
label="单位法人编号"
>
<el-input
v-model="formData.legalEntityCode"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="行政职务"
prop="administrativeDuties"
>
<el-input
v-model="formData.administrativeDuties"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="开始工作日期"
prop="startWorkAt"
>
<el-date-picker
v-model="formData.startWorkAt"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="行政职级"
prop="administrativeRank"
>
<el-select
v-model="formData.administrativeRank"
class="w-full"
placeholder="请选择"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.administrativeRankDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="在职状态"
prop="jobStatus"
>
<el-select
v-model="formData.jobStatus"
class="w-full"
placeholder="请选择"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.jobStatusDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="formData.jobStatus?.dictionaryName==='退休'" :span="8">
<el-form-item
label="退休日期"
prop="retiredAt"
>
<el-date-picker
v-model="formData.retiredAt"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="单位类型"
prop="companyAttribute"
>
<el-select
v-model="formData.companyAttribute"
placeholder="请选择"
class="w-full"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.companyAttributeDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="条线">
<el-select
v-model="formData.businessStrips"
multiple
value-key="businessStripCode"
filterable
class="w-full"
>
<el-option
v-for="(item,index) in lineListData"
:key="index"
:label="item.businessStripName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="工作地址"
prop="address"
>
<el-input
v-model="formData.address"
maxlength="50"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="工作经历"
prop="experience"
>
<el-input
v-model="formData.experience"
maxlength="200"
:rows="5"
type="textarea"
show-word-limit
placeholder="请输入"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less">
.jobInfo{
}
</style>

+ 347
- 0
src/pages/expertManage/expertStore/addOrEditExpert/components/professionalInfo.vue Datei anzeigen

@@ -0,0 +1,347 @@
<script name="professionalInfo" setup>
import { getCurrentInstance, onMounted, reactive, ref } from 'vue'
import store from '@/store'
import orgTree from '@/components/orgTree/index.vue'
import { storeToRefs } from 'pinia'
import { fileFormatVerification, handleFileSuccess, handleFilePreview } from '@/utils/uploadAction.js'
const uploadUrl = store.dictStore.uploadUrl
const { tagList } = storeToRefs(store.dictStore),
{ proxy } = getCurrentInstance(),
formData = ref({
}),
formRef = ref(),
rules = {
technicalTitles: [
{ required: true, message: '请输入技术职称', trigger: 'blur' }
],
titleLevel: [
{ required: true, message: '请选择职称级别', trigger: 'blur' }
],
goodAt: [
{ required: true, message: '请选择擅长方向', trigger: 'blur' }
],
technicalExpertise: [
{ required: true, message: '请选择技术专长', trigger: 'blur' }
],
industrySector: [
{ required: true, message: '请选择行业领域', trigger: 'blur' }
],
avoidCompanyList: [
{ required: true, message: '请输入回避单位', trigger: 'blur' }
],
titleCertificateFile: [
{ required: true, message: '请上传职称证明', trigger: 'blur' }
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
fileExceed = (files, uploadFiles) => {
proxy.$message.warning('仅限上传一个文件')
},
// 回显
setFormData = (data) => {
formData.value = {
...data,
goodAt: data.goodAt && data.goodAt || undefined,
titleLevel: data.titleLevel && data.titleLevel[0] || undefined,
industrySector: data.industrySector && data.industrySector.map(i => `${i.tagName}##${i.tagCode}`),
technicalExpertise: data.technicalExpertise && data.technicalExpertise.map(i => `${i.tagName}##${i.tagCode}`),
titleCertificateFile: data.titleCertificateFile && data.titleCertificateFile.map(i => {
return {
name: i.fileName,
response: {
data: {
id: i.fileId
}
},
fileUrlById: i.url
}
})
}
},
handleChangeTreeTag = (checkedKeys, checkedNodes, name) => {
console.log(checkedNodes)
},
// 回避单位单位
orgProps = reactive({
unitVisible: false,
showCheckbox: false,
data: undefined,
name: undefined
}),
showOrgTree = (name) => {
orgProps.name = name
orgProps.unitVisible = true
orgProps.showCheckbox = true
orgProps.data = formData.value.avoidCompanyList?.map(i => {
return {
key: i.companyUniqCode,
title: i.companyName
}
})
},
closeOrg = () => {
orgProps.unitVisible = false
},
getOrgData = (data, expandedKeys) => {
formData.value[orgProps.name] = data.map(i => {
return {
companyUniqCode: i.key,
companyName: i.title
}
})
},
// 删除回避单位
delTag = (index) => {
formData.value.avoidCompanyList.splice(index, 1)
}
defineExpose({ validForm, formData, setFormData })
onMounted(async () => {
})
</script>
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="120px"
label-suffix=":"
scroll-to-error
class="professionalInfo"
>
<el-row :gutter="8">
<el-col :span="8">
<el-form-item
label="技术职称"
prop="technicalTitles"
>
<el-input
v-model="formData.technicalTitles"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="职称级别"
prop="titleLevel"
>
<el-select
v-model="formData.titleLevel"
class="w-full"
placeholder="请选择"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.titleLevelDict "
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>

<el-col :span="8">
<el-form-item
label="擅长方向"
prop="goodAt"
>
<el-select
v-model="formData.goodAt"
class="w-full"
placeholder="请选择"
clearable
value-key="tagCode"
multiple
>
<el-option
v-for="(item,index) in store.dictStore.goodAtDict"
:key="index"
:label="item.tagName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="技术专长"
prop="technicalExpertise"
>
<el-tree-select
v-model="formData.technicalExpertise"
class="w-full"
placeholder="请选择技术专长"
:data="
tagList &&
tagList.length &&
tagList.find(i => i.tagCode === 'technical_expertise')
.children||[]
"
:props="{
label: 'tagName',
value: 'unionCode'
}"
node-key="unionCode"
collapse-tags
multiple
show-checkbox
check-on-click-node
@check="
(checkedKeys, checkedNodes) =>
handleChangeTreeTag(
checkedKeys,
checkedNodes,
'technicalExpertise'
)
"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="行业领域"
prop="industrySector"
>
<el-tree-select
v-model="formData.industrySector"
class="w-full"
placeholder="请选择行业领域"
:data="
tagList &&
tagList.length &&
tagList.find(i => i.tagCode === 'industry_sector').children||[]
"
:props="{
label: 'tagName',
value: 'unionCode'
}"
node-key="unionCode"
collapse-tags
multiple
show-checkbox
check-on-click-node
@check="
(checkedKeys, checkedNodes) =>
handleChangeTreeTag(
checkedKeys,
checkedNodes,
'industrySector'
)
"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="获奖情况"
prop="awards"
>
<el-input
v-model="formData.awards"
maxlength="200"
show-word-limit
type="textarea"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="表彰奖励"
prop="recognitionReward"
>
<el-input
v-model="formData.recognitionReward"
maxlength="200"
show-word-limit
type="textarea"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="回避单位"
prop="avoidCompanyList"
>
<div class="flex flex-col items-start">
<el-button
type="primary"
@click="showOrgTree('avoidCompanyList')"
>
<el-icon>
<Plus />
</el-icon>选择回避单位
</el-button>
<p>
<el-tag
v-for="(item,index) in formData.avoidCompanyList"
:key="index"
class="mr-8"
closable
@close="delTag(index)"
>
{{ item.companyName }}
</el-tag>
</p>
</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="职称证明"
prop="titleCertificateFile"
>
<el-upload
v-model:file-list="formData.titleCertificateFile"
class="w-full"
:action="uploadUrl"
:on-exceed="fileExceed"
:limit="1"
:on-success="
res =>
handleFileSuccess(
res,
formData.titleCertificateFile
)
"
:on-preview="handleFilePreview"
accept="application/pdf,image/png,image/jpeg"
:before-upload="
file =>
fileFormatVerification(file, {
types: ['png', 'jpg', 'jpeg','pdf'],size:1024})"
>
<el-button
type="primary"
plain
>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持扩展名:.pdf .png .jpg .pdf,文件大小不超过1M
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
<org-tree
:visible="orgProps.unitVisible"
:show-checkbox="orgProps.showCheckbox"
:default-data="orgProps.data"
@close="closeOrg"
@get-select-unit="getOrgData"
/>
</template>
<style lang="less">
.professionalInfo{
}
</style>

+ 124
- 0
src/pages/expertManage/expertStore/addOrEditExpert/components/recommendInfo.vue Datei anzeigen

@@ -0,0 +1,124 @@
<script name="recommendInfo" setup>
import { getCurrentInstance, onMounted, ref } from 'vue'
import store from '@/store'
import { fileFormatVerification, handleFileSuccess, handleFilePreview } from '@/utils/uploadAction.js'
const uploadUrl = store.dictStore.uploadUrl,
{ proxy } = getCurrentInstance(),
formData = ref({
}),
formRef = ref(),
rules = {
recommendedWay: [
{ required: true, message: '请选择推荐类型', trigger: 'blur' }
],
recommendationProofFile: [
{ required: true, message: '请上传推荐证明', trigger: 'blur' }
]
},
// 校验
validForm = (callback) => {
formRef.value.validate(valid => {
callback(valid)
})
},
fileExceed = (files, uploadFiles) => {
proxy.$message.warning('仅限上传一个文件')
},
// 回显
setFormData = (data) => {
formData.value = {
...data,
recommendedWay: data.recommendedWay?.[0] || undefined,
recommendationProofFile: data.recommendationProofFile && data.recommendationProofFile.map(i => {
return {
name: i.fileName,
response: {
data: {
id: i.fileId
}
},
fileUrlById: i.url
}
})
}
}
defineExpose({ validForm, formData, setFormData })
onMounted(async () => {
})
</script>
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-position="right"
label-width="120px"
label-suffix=":"
scroll-to-error
class="recommendInfo"
>
<el-row :gutter="8">
<el-col :span="8">
<el-form-item
label="推荐类型"
prop="recommendedWay"
>
<el-select
v-model="formData.recommendedWay"
class="w-full"
placeholder="请选择"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.recommendedWayDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="推荐证明"
prop="recommendationProofFile"
>
<el-upload
v-model:file-list="formData.recommendationProofFile"
class="w-full"
:action="uploadUrl"
:limit="1"
:on-exceed="fileExceed"
:on-success="
res =>
handleFileSuccess(
res,
formData.recommendationProofFile
)
"
:on-preview="handleFilePreview"
accept="application/pdf,image/png,image/jpeg,image/jpg"
:before-upload="
file =>
fileFormatVerification(file, {
types:['png', 'jpg', 'jpeg','pdf'],size:1024})"
>
<el-button
type="primary"
plain
>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
支持扩展名:.pdf .png .jpg .pdf ,文件大小不超过1M
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less">
.recommendInfo{
}
</style>

+ 409
- 0
src/pages/expertManage/expertStore/addOrEditExpert/index.vue Datei anzeigen

@@ -0,0 +1,409 @@
<script name="addOrEditExpert" setup>
import { getCurrentInstance, ref, onMounted, reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import basicInfo from './components/basicInfo.vue'
import eduInfo from './components/eduInfo.vue'
import jobInfo from './components/jobInfo.vue'
import professionalInfo from './components/professionalInfo.vue'
import recommendInfo from './components/recommendInfo.vue'
import expertOtherInfo from './components/expertOtherInfo.vue'
import { expertEdit, expertSignUp, modifyApply, registration } from '@/http/apis/expertManage/expertStore'
import { downloadFileUrl } from '@/utils/uploadAction.js'
import { getExpertDetail } from '@/http/apis/expertManage/expertVerify'
import { getVerificationCode } from '@/http/apis/auth'
import { storeToRefs } from 'pinia'
import store from '@/store'
const { proxy } = getCurrentInstance(),
route = useRoute(),
router = useRouter(),
formData = ref({
basicInfo: {
// isDingUser: false
}
}),
basicInfoRef = ref(), // 基本信息
eduInfoRef = ref(), // 学历信息
jobInfoRef = ref(), // 职业信息
professionalInfoRef = ref(), // 专业信息
recommendInfoRef = ref(), // 推荐信息
expertOtherInfoRef = ref(), // 其他信息
// 提交
submitForm = async () => {
const form = []
form.push(new Promise((resolve, reject) => {
basicInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
eduInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
jobInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
professionalInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
recommendInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
form.push(new Promise((resolve, reject) => {
expertOtherInfoRef.value.validForm((valid) => {
if (valid) resolve()
})
}))
Promise.all([...form]).then(async () => {
saveData()
}).catch(err => {
if (err) {
proxy.$message.warning(err)
}
})
},
saveData = async () => {
var data = {
expertUserId: route.name === 'selfEditExpertInfo' ? userInfo.value.userId : route.query.id || undefined,
basicInfo: {
...basicInfoRef.value.formData,
isDingUser: basicInfoRef.value.formData.isDingUser,
avatarUrl: basicInfoRef.value.formData?.avatarFile?.fileId && await downloadFileUrl(basicInfoRef.value.formData.avatarFile.fileId),
expertIntentionWorkRegions:
basicInfoRef.value.formData.expertIntentionWorkRegions?.map((i, index) => ({
regionName: i.unionCode?.join('@@'),
regionCode: i.unionCode?.slice(-1)[0]?.split('##')[0],
regionLevel: i.unionCode?.slice(-1)[0]?.split('##')[2]
})),
expertRegionInfo: {
regionName: basicInfoRef.value.formData.expertRegionInfo?.join('@@'),
regionCode: basicInfoRef.value.formData.expertRegionInfo?.slice(-1)[0].split('##')[0],
regionLevel: basicInfoRef.value.formData.expertRegionInfo?.slice(-1)[0].split('##')[2]
},
political: basicInfoRef.value.formData.political && [basicInfoRef.value.formData.political] || [],
expertSource: basicInfoRef.value.formData.expertSource && [basicInfoRef.value.formData.expertSource] || [],
expertType: basicInfoRef.value.formData.expertType && [basicInfoRef.value.formData.expertType] || []
},
eduInfo: {
...eduInfoRef.value.formData,
edu: eduInfoRef.value.formData.edu && [eduInfoRef.value.formData.edu],
degree: eduInfoRef.value.formData.degree && [eduInfoRef.value.formData.degree],
degreeCertificateFile: eduInfoRef.value.formData.degreeCertificateFile && await Promise.all(
eduInfoRef.value.formData.degreeCertificateFile && eduInfoRef.value.formData.degreeCertificateFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || [],
graduationCertificateFile: eduInfoRef.value.formData.graduationCertificateFile && await Promise.all(
eduInfoRef.value.formData.graduationCertificateFile && eduInfoRef.value.formData.graduationCertificateFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || []
},
jobInfo: {
...jobInfoRef.value.formData,
administrativeRank: jobInfoRef.value.formData.administrativeRank && [jobInfoRef.value.formData.administrativeRank] || [],
jobStatus: jobInfoRef.value.formData.jobStatus && [jobInfoRef.value.formData.jobStatus] || [],
companyAttribute: jobInfoRef.value.formData.companyAttribute && [jobInfoRef.value.formData.companyAttribute] || []
},
professionalInfo: {
...professionalInfoRef.value.formData,
goodAt: professionalInfoRef.value.formData.goodAt.map(i => {
return {
...i,
tagFieldName: 'good_at'
}
}) || [],
titleLevel: professionalInfoRef.value.formData.titleLevel && [professionalInfoRef.value.formData.titleLevel] || [],
titleCertificateFile: professionalInfoRef.value.formData.titleCertificateFile && await Promise.all(
professionalInfoRef.value.formData.titleCertificateFile && professionalInfoRef.value.formData.titleCertificateFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || [],
technicalExpertise: professionalInfoRef.value.formData.technicalExpertise && professionalInfoRef.value.formData.technicalExpertise.map(i => {
return {
tagCode: i.split('##')[1],
tagName: i.split('##')[0]
}
}),
industrySector: professionalInfoRef.value.formData.industrySector && professionalInfoRef.value.formData.industrySector.map(i => {
return {
tagCode: i.split('##')[1],
tagName: i.split('##')[0]
}
})
},
recommendInfo: {
...recommendInfoRef.value.formData,
recommendedWay: recommendInfoRef.value.formData.recommendedWay && [recommendInfoRef.value.formData.recommendedWay] || [],
recommendationProofFile: recommendInfoRef.value.formData.recommendationProofFile && await Promise.all(
recommendInfoRef.value.formData.recommendationProofFile && recommendInfoRef.value.formData.recommendationProofFile.map(async i => {
return {
fileName: i.name,
fileId: i.response.data.id,
url: i.fileUrlById
}
})
) || []
},
expertOtherInfo: {
...expertOtherInfoRef.value.formData,
other: expertOtherInfoRef.value.formData.other && expertOtherInfoRef.value.formData.other.map(i => {
return {
tagCode: i.split('##')[1],
tagName: i.split('##')[0]
}
})
}
}
if (route.name === 'expertEnroll') {
showSmsDiaglog(data)
} else {
if (!route.query.id && route.name !== 'selfEditExpertInfo') {
await expertSignUp(data)
proxy.$message.success('专家新增成功')
router.go(-1)
} else {
const apiFn = route.name === 'selfEditExpertInfo' ? modifyApply : expertEdit
await apiFn(data)
proxy.$message.success(route.name === 'selfEditExpertInfo' ? '申请成功' : '专家编辑成功')
route.name !== 'selfEditExpertInfo' && router.go(-1)
}
}
},
// 专家报名-短信验证
smsDialogData = reactive({
visible: false,
data: {}
}),
showSmsDiaglog = (data) => {
smsDialogData.data = data
smsDialogData.visible = true
},
smsDialogFormRef = ref(),
smsDialogForm = ref({
verificationCode: ''
}),
smsDialogRules = {
'verificationCode': [{ required: true, message: '请输入' }]
},
smsDialogLoading = ref(false),
submitSms = async (formEl) => {
if (!formEl) {
return
}
formEl.validate(async (valid) => {
if (valid) {
await registration({
...smsDialogData.data,
verificationCode: smsDialogForm.value.verificationCode
})
proxy.$message.success('提交成功')
router.go(0)
}
}
)
},
timer = ref(null),
count = ref(0),
getVerificationCodeFunc = async () => {
await getVerificationCode({ mobile: basicInfoRef.value.formData.phoneNo, verificationType: 'RECOMMENDATION_PROOF_FILE_SUBMIT' })
proxy.$message.success('验证码已发送')
const TIME_COUNT = 60
if (!timer.value) {
count.value = TIME_COUNT
timer.value = setInterval(() => {
if (count.value > 0 && count.value <= TIME_COUNT) {
count.value--
} else {
clearInterval(timer.value)
timer.value = null
}
}, 1000)
}
},
// 获取详情
getDetail = async () => {
const res = await getExpertDetail({ expertUserId: route.name === 'selfEditExpertInfo' ? userInfo.value.userId : route.query.id })
// formData.value.basicInfo.isDingUser = res.data.basicInfo.isDingUser
basicInfoRef.value.setFormData(res.data.basicInfo)
eduInfoRef.value.setFormData(res.data.eduInfo)
jobInfoRef.value.setFormData(res.data.jobInfo)
professionalInfoRef.value.setFormData(res.data.professionalInfo)
recommendInfoRef.value.setFormData(res.data.recommendInfo)
expertOtherInfoRef.value.setFormData(res.data.expertOtherInfo)
},
userInfo = storeToRefs(store.userStore).userInfo
onMounted(() => {
if (route.query.id || route.name === 'selfEditExpertInfo') {
getDetail()
}
})
</script>

<template>
<div class="addOrEditExpert footerPage" :class="{ 'relative':route.path === 'expertEnroll'}">
<div v-if="route.name === 'expertEnroll'" class="header">丽水市信息化专家报名</div>
<el-card shadow="never" class="mb-16">
<template #header>
<div class="card-header flex items-center justify-between">
<span>基本信息</span>
<!-- <span class="flex items-center">是否在浙政钉组内:
<el-switch
v-model="formData.basicInfo.isDingUser"
inline-prompt
active-text="是"
inactive-text="否"
/>
</span> -->
</div>
</template>
<basic-info ref="basicInfoRef" :basic-info="formData.basicInfo" />
</el-card>
<el-card shadow="never" class="mb-16">
<template #header>
<div>
<span>学历信息</span>
</div>
</template>
<edu-info ref="eduInfoRef" />
</el-card>
<el-card shadow="never" class="mb-16">
<template #header>
<div>
<span>职业信息</span>
</div>
</template>
<job-info ref="jobInfoRef" />
</el-card>
<el-card shadow="never" class="mb-16">
<template #header>
<div>
<span>专业信息</span>
</div>
</template>
<professional-info ref="professionalInfoRef" />
</el-card>
<el-card shadow="never" class="mb-16">
<template #header>
<div>
<span>推荐信息</span>
</div>
</template>
<recommend-info ref="recommendInfoRef" />
</el-card>
<el-card shadow="never" class="mb-16">
<template #header>
<div>
<span>其他信息</span>
</div>
</template>
<expert-other-info ref="expertOtherInfoRef" />
</el-card>
<div class="footer">
<el-button
type="primary"
@click="submitForm"
>
提交
</el-button>
<el-button @click="router.go(-1)">取消</el-button>
</div>
<el-dialog
:model-value="smsDialogData.visible"
title="短信验证"
width="400px"
destroy-on-close
@close="smsDialogData.visible=false"
>
<el-form
ref="smsDialogFormRef"
:model="smsDialogForm"
:rules="smsDialogRules"
label-width="auto"
label-suffix=":"
>
<el-form-item label="手机号">
<span>{{ basicInfoRef.formData.phoneNo }}</span>
</el-form-item>
<el-form-item label="验证码" prop="verificationCode">
<el-input v-model="smsDialogForm.verificationCode" placeholder="请输入验证码">
<template #suffix>
<a v-if="!count" class="itemBlue" @click="getVerificationCodeFunc"> 获取验证码</a>
<span v-else class="itemBlue">{{ count }}</span>
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button
type="primary"
:loading="smsDialogLoading"
@click="submitSms(smsDialogFormRef)"
>
提交
</el-button>
<el-button
@click="smsDialogData.visible=false"
>
关闭
</el-button>
</template>
</el-dialog>
</div>
</template>
<style lang="less" scoped>
.addOrEditExpert{
.header{
height: 60px;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
margin-bottom: 15px;
font-size: 20px;
}
:deep(.el-collapse) {
.el-collapse-item__header {
padding: 0px 16px;
font-size: 14px;
}
.el-collapse-item__content {
padding: 16px 16px 16px 0px;
// margin-left: -50px;
}
.el-collapse-item__header.is-active {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.collapse-title {
flex: 1 0 90%;
order: 1;
.el-collapse-item__header {
flex: 1 0 auto;
order: -1;
}
.el-input-number {
width: 150px !important;
}
}
}
}

</style>

+ 168
- 0
src/pages/expertManage/expertStore/deputyActivityRecord/components/evaluateDialog.vue Datei anzeigen

@@ -0,0 +1,168 @@
<script name="evaluateDialog" setup>
import { getCurrentInstance, nextTick, ref, watch } from 'vue'
import { judgeDetail, judgeSubmit } from '@/http/apis/expertManage/expertStore'

const { proxy } = getCurrentInstance(),
props = defineProps({
visible: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
},
isEdit: {
type: Boolean,
default: true
}
}),
emits = defineEmits(['close']),
formData = ref({}),
formRef = ref(),
rules = {
score: [{ required: true, message: '请输入' }],
attended: [{ required: true, message: '请选择' }],
performance: [{ required: true, message: '请选择' }],
advised: [{ required: true, message: '请选择' }],
leaveEarly: [{ required: true, message: '请选择' }],
brokeRule: [{ required: true, message: '请选择' }],
brokeRuleContent: [{ required: true, message: '请选择' }]
},
loading = ref(false),
submit = async (formEl) => {
if (!formEl) return
await formEl.validate(async valid => {
if (valid) {
loading.value = true
try {
const postData = {
...formData.value
}
await judgeSubmit(postData)
proxy.$message.success('提交成功!')
loading.value = false
emits('close', true)
} catch (e) {
loading.value = false
}
}
})
},
getDetail = async () => {
const res = await judgeDetail(props.data.meetingExpertId)
formData.value = {
...res.data
}
}
watch(
() => props.visible,
async val => {
if (val) {
await nextTick()
formRef.value.clearValidate()
formData.value = {
meetingExpertId: props.data.meetingExpertId,
meetingId: props.data.meetingId
}
if (!props.isEdit) {
getDetail()
}
}
}
)
defineExpose({ formRef })
</script>

<template>
<el-dialog :model-value="visible" :title="isEdit?'履职评价':'查看评价'" @close="emits('close')">
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-suffix=":"
>
<el-form-item v-if="isEdit" label="评分" prop="score">
<el-input-number
v-model="formData.score"
placeholder="请对该专家在本次会议的表现进行评分,最低0分,满分10分"
:min="0"
:max="10"
:controls="false"
@mousewheel.prevent
/>
</el-form-item>
<el-form-item v-else label="评分">
<span>{{ formData.score }}</span>
</el-form-item>
<el-form-item v-if="isEdit" label="专家是否参加" prop="attended">
<el-radio-group v-model="formData.attended">
<el-radio :label="1">准时参加</el-radio>
<el-radio :label="2">迟到</el-radio>
<el-radio :label="3">缺席</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-else label="专家是否参加">
<span>{{ formData.attended===1?'准时参加':formData.attended===2?'迟到':'缺席' }}</span>
</el-form-item>
<template v-if="formData.attended!==3">
<el-form-item v-if="isEdit" label="专家参与程度" prop="performance">
<el-radio-group v-model="formData.performance">
<el-radio :label="1">积极</el-radio>
<el-radio :label="2">消极</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-else label="专家参与程度">
<span>{{ formData.performance===1?'积极':formData.performance===2?'消极':'-' }}</span>
</el-form-item>
<el-form-item v-if="isEdit" label="专家是否提出专业建议" prop="advised">
<el-radio-group v-model="formData.advised">
<el-radio :label="true">有提出</el-radio>
<el-radio :label="false">未提出</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-else label="专家是否提出专业建议">
<span>{{ formData.advised?'有提出':'未提出' }}</span>
</el-form-item>
<el-form-item v-if="isEdit" label=" 专家是否早退" prop="leaveEarly">
<el-radio-group v-model="formData.leaveEarly">
<el-radio :label="false">未早退</el-radio>
<el-radio :label="true">早退</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-else label="专家是否早退">
<span>{{ formData.leaveEarly?'早退':'未早退' }}</span>
</el-form-item>
<el-form-item v-if="isEdit" label="专家有无违规行为" prop="brokeRule">
<el-radio-group v-model="formData.brokeRule">
<el-radio :label="false">无</el-radio>
<el-radio :label="true">有</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-else label="专家有无违规行为">
<span>{{ formData.brokeRule?'有':'无' }}</span>
</el-form-item>
<template v-if="formData.brokeRule">
<el-form-item v-if="isEdit" label="违规行为" prop="brokeRuleContent">
<el-input
v-model="formData.brokeRuleContent"
placeholder="请填写"
type="textarea"
:maxlength="200"
show-word-limit
/>
</el-form-item>
<el-form-item v-else label="违规行为">
<span>{{ formData.brokeRuleContent }}</span>
</el-form-item>
</template>
</template>
</el-form>
<template v-if="isEdit" #footer>
<span class="dialog-footer">
<el-button type="primary" :loading="loading" @click="submit(formRef)">提交</el-button>
<el-button @click="emits('close')">关闭</el-button>
</span>
</template>
</el-dialog>
</template>

+ 147
- 0
src/pages/expertManage/expertStore/deputyActivityRecord/index.vue Datei anzeigen

@@ -0,0 +1,147 @@
<script>
import { defineComponent } from 'vue'

export default defineComponent({
beforeRouteEnter (to, from, next) {
if (to.query.name) {
to.meta.title = '履职记录-' + to.query.name
}
next()
}
})
</script>
<script setup name='deputyActivityRecord'>
import { reactive, ref, onMounted, h } from 'vue'
import { getDeputyActivityRecord } from '@/http/apis/expertManage/expertStore'
import MeetingProjectDialog from '@/pages/expertManage/reviewMeeting/components/meetingProjectDialog.vue'
import { useRoute } from 'vue-router'
import EvaluateDialog from '@/pages/expertManage/expertStore/deputyActivityRecord/components/evaluateDialog.vue'
const route = useRoute(),
tableListRef = ref(),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '会议名称',
key: 'meetingName',
prop: 'meetingName',
minWidth: '80',
showOverflowTooltip: true
},
{
label: '评审项目',
slot: 'projectName',
minWidth: '100',
showOverflowTooltip: true
},
{
label: '评审时间',
key: 'createOn',
prop: 'createOn',
width: '180'
},
{
label: '是否参会',
key: 'inviteStatus',
prop: 'inviteStatus',
width: '150',
render: row => h('span', '是')
},
{
label: '是否请假',
key: 'expertStatus',
prop: 'expertStatus',
width: '150',
render: row => h('span', row.expertStatus === 5 ? '是' : '否')
},
{
label: '是否评价',
key: 'hasJudge',
prop: 'hasJudge',
width: '150',
render: row => h('span', row.hasJudge ? '是' : '否')
},
{
label: '操作',
slot: 'action',
width: '100',
fixed: 'right'
}
]),
data = ref([]),
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await getDeputyActivityRecord({
...pageParams,
expertId: route.query.id
})
data.value = res.data.records
total.value = res.data.total
},
// 查看项目
viewProject = (data) => {
meetingProjectDialogData.value.visible = true
meetingProjectDialogData.value.meetingId = data.meetingId
},
meetingProjectDialogData = ref({
visible: false,
meetingId: undefined
}),
close = () => {
meetingProjectDialogData.value.visible = false
},
// 履职评价
evaluateDialogData = reactive({
visible: false,
data: {},
isEdit: true
}),
evaluateDialogRef = ref(),
showEvaluateDialog = (data, isEdit) => {
evaluateDialogData.data = data
evaluateDialogData.isEdit = isEdit
evaluateDialogData.visible = true
},
closeEvaluateDialog = (flag) => {
evaluateDialogData.visible = false
flag && getTableData()
}
onMounted(() => {
getTableData()
})
</script>

<template>
<div class="">
<el-card class="box-card">
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #projectName="{scope}">
<a @click="viewProject(scope.row)">查看</a>
</template>
<template #action="{scope}">
<a v-if="!scope.row.hasJudge" @click="showEvaluateDialog(scope.row,true)">履职评价</a>
<a v-else @click="showEvaluateDialog(scope.row,false)">查看评价</a>
</template>
</table-list>
</el-card>
<meeting-project-dialog :visible="meetingProjectDialogData.visible" :meeting-id="meetingProjectDialogData.meetingId" @close="close" />
</div>
<evaluate-dialog
ref="evaluateDialogRef"
:visible="evaluateDialogData.visible"
:data="evaluateDialogData.data"
:is-edit="evaluateDialogData.isEdit"
@close="closeEvaluateDialog"
/>
</template>


+ 315
- 0
src/pages/expertManage/expertStore/expertDetail/index.vue Datei anzeigen

@@ -0,0 +1,315 @@
<script setup name='expertDetail'>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getExpertDetail } from '@/http/apis/expertManage/expertVerify'
import Accessory from '@/components/accessory/index.vue'
const route = useRoute()
const router = useRouter()
const activeName = ref('basicInfo')
const handleClick = (tab, event) => {
console.log(tab, event)
}
const expertInfo = ref({ basicInfo: {}, eduInfo: {}, jobInfo: {}, professionalInfo: {}, recommendInfo: {}})
const getVerifyDetail = async () => {
const res = await getExpertDetail({ expertUserId: route.query.id })
expertInfo.value = res.data
}
// 查看文件
const view = (data) => {
const routeUrl = router.resolve({
path: '/fileView',
query: { id: data }
})
window.open(routeUrl.href, '_blank')
}
onMounted(async () => {
getVerifyDetail()
})
</script>

<template>
<div class="">
<el-card class="box-card">
<el-tabs
v-model="activeName"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane
label="基本信息"
name="basicInfo"
>
<el-descriptions
class="mt-20"
title=""
:column="2"
border
>
<el-descriptions-item
label="专家名称"
span="1"
width="200px"
>
{{ expertInfo.basicInfo.name }}
</el-descriptions-item>
<el-descriptions-item label="是否在浙政钉组织">
{{ expertInfo.basicInfo.isDingUser?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item
label="手机号码"
width="200px"
>
{{ expertInfo.basicInfo.phoneNo }}
</el-descriptions-item>
<el-descriptions-item label="性别">
{{ expertInfo.basicInfo.gender === '1' ? '男': '女' }}
</el-descriptions-item>
<el-descriptions-item label="籍贯">
{{ expertInfo.basicInfo.hometown ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="民族">
{{ expertInfo.basicInfo.nationality ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="政治面貌">
{{ expertInfo.basicInfo.political?.[0].dictionaryName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="身份证号">
{{ expertInfo.basicInfo.idCard||'-' }}
</el-descriptions-item>
<el-descriptions-item label="办公电话">
{{ expertInfo.basicInfo.officePhone||'-' }}
</el-descriptions-item>
<el-descriptions-item label="出生年月">
{{ expertInfo.basicInfo.birth ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="银行卡号">
{{ expertInfo.basicInfo.bankNo||'-' }}
</el-descriptions-item>
<el-descriptions-item label="开户银行">
{{ expertInfo.basicInfo.bank||'-' }}
</el-descriptions-item>
<el-descriptions-item label="电子邮箱">
{{ expertInfo.basicInfo.email||'-' }}
</el-descriptions-item>
<el-descriptions-item label="专家级别">
{{ expertInfo.basicInfo?.expertRegionInfo?.regionName.split('@@').map(i=>i.split('##')[1]).join('-') }}
</el-descriptions-item>
<el-descriptions-item label="专家来源">
{{ expertInfo.basicInfo.expertSource?.[0].tagName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="专家类型">
{{ expertInfo.basicInfo.expertType?.[0].dictionaryName||'-' }}
</el-descriptions-item>
<el-descriptions-item label="履职意向">
{{ expertInfo.basicInfo.expertIntentionWorkRegions?.map(i=>i.regionName.split('@@').map(j=>j.split('##')[1]).join('-')).join(';') }}
</el-descriptions-item>
<el-descriptions-item
label="头像(免冠照)"
span="2"
>
<a target="_blank" @click="view(expertInfo.basicInfo.avatarFile.fileId)">{{ expertInfo.basicInfo.avatarFile?.fileName }}</a>

</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane
label="学历信息"
name="eduInfo"
>
<el-descriptions
class="mt-20"
title=""
:column="2"
border
>
<el-descriptions-item
label="毕业院校"
span="2"
width="200px"
>
{{ expertInfo.eduInfo.school||'-' }}
</el-descriptions-item>
<el-descriptions-item label="毕业时间">
{{ expertInfo.eduInfo.graduatedAt||'-' }}
</el-descriptions-item>
<el-descriptions-item
label="所学专业"
width="200px"
>
{{ expertInfo.eduInfo.academicTitle ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="学位">
{{ expertInfo.eduInfo.degree?.[0].dictionaryName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="学历">
{{ expertInfo.eduInfo.edu?.[0].dictionaryName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="毕业证书">
<p v-for="(file,fileIndex) in expertInfo.eduInfo.graduationCertificateFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
<el-descriptions-item label="学位证书">
<p v-for="(file,fileIndex) in expertInfo.eduInfo.degreeCertificateFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane
label="职业信息"
name="professionInfo"
>
<el-descriptions
class="mt-20"
title=""
:column="2"
border
>
<el-descriptions-item
label="工作单位"
width="200px"
>
{{ expertInfo.jobInfo.company||'-' }}
</el-descriptions-item>
<el-descriptions-item label="工作单位code">
{{ expertInfo.jobInfo.companyUniqCode ||'-' }}
</el-descriptions-item>
<el-descriptions-item
label="单位法人编号"
width="200px"
>
{{ expertInfo.jobInfo.legalEntityCode||'-' }}
</el-descriptions-item>
<el-descriptions-item label="行政职务">
{{ expertInfo.jobInfo.administrativeDuties ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="开始工作日期">
{{ expertInfo.jobInfo.startWorkAt ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="行政职级">
{{ expertInfo.jobInfo.administrativeRank?.[0].dictionaryName||'-' }}
</el-descriptions-item>
<el-descriptions-item label="在职状态">
{{ expertInfo.jobInfo.jobStatus?.[0].dictionaryName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="退休日期">
{{ expertInfo.jobInfo.retiredAt||'-' }}
</el-descriptions-item>
<el-descriptions-item label="单位类型">
{{ expertInfo.jobInfo.companyAttribute?.[0].dictionaryName ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="条线">
{{ expertInfo.jobInfo?.businessStrips?.map(i=>i.businessStripName).join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="工作地址">
{{ expertInfo.jobInfo.address||'-' }}
</el-descriptions-item>
<el-descriptions-item label="工作经历">
{{ expertInfo.jobInfo.experience||'-' }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane
label="专业信息"
name="majorInfo"
>
<el-descriptions
class="mt-20"
title=""
:column="2"
border
>
<el-descriptions-item
label="技术职称"
width="200px"
>
{{ expertInfo.professionalInfo.technicalTitles||'-' }}
</el-descriptions-item>
<el-descriptions-item label="职称级别">
{{ expertInfo.professionalInfo.titleLevel?.[0].dictionaryName ||'-' }}
</el-descriptions-item>
<el-descriptions-item
label="擅长方向"
width="200px"
>
{{ expertInfo.professionalInfo.goodAt?.map(i=>i.tagName).join('、') ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="技术专长">
<span v-for="(item,index) in expertInfo.professionalInfo.technicalExpertise" :key="index">{{ item.tagName }}&nbsp;&nbsp;</span>
</el-descriptions-item>
<el-descriptions-item label="行业领域">
<span v-for="(item,index) in expertInfo.professionalInfo.industrySector" :key="index">{{ item.tagName }}&nbsp;&nbsp;</span>
</el-descriptions-item>
<el-descriptions-item label="获奖情况">
{{ expertInfo.professionalInfo.awards||'-' }}
</el-descriptions-item>
<el-descriptions-item label="表彰奖励">
{{ expertInfo.professionalInfo.recognitionReward ||'-' }}
</el-descriptions-item>
<el-descriptions-item label="回避单位">
<span v-for="(item, index) in expertInfo.professionalInfo.avoidCompanyList" :key="index">{{ item.companyName }}&nbsp;&nbsp;</span>
</el-descriptions-item>
<el-descriptions-item label="职称证明">
<p v-for="(file,fileIndex) in expertInfo.professionalInfo.titleCertificateFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane
label="推荐信息"
name="recommendInfo"
>
<el-descriptions
class="mt-20"
title=""
:column="2"
border
>
<el-descriptions-item
label="推荐类型"
width="200px"
>
{{ expertInfo.recommendInfo.recommendedWay?.[0].dictionaryName||'-' }}
</el-descriptions-item>
<el-descriptions-item
width="200px"
label="推荐证明"
>
<p v-for="(file,fileIndex) in expertInfo.recommendInfo.recommendationProofFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane
label="其他信息"
name="otherInfo"
>
<el-descriptions
class="mt-20"
title=""
:column="2"
border
>
<el-descriptions-item
label="其他标签"
width="200px"
>
{{ expertInfo.expertOtherInfo?.other?.map(i=>i.tagName)?.join('、') ||'-' }}
</el-descriptions-item>
<el-descriptions-item
width="200px"
label="备注"
>
{{ expertInfo.expertOtherInfo?.remark ||'-' }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</template>

<style lang='less' scoped> </style>

+ 249
- 0
src/pages/expertManage/expertStore/index.vue Datei anzeigen

@@ -0,0 +1,249 @@
<script setup name="expertStore">
import { getCurrentInstance, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import ElTree from '@/components/elTree/index.vue'
import store from '@/store'
import { storeToRefs } from 'pinia'
import { delivery, getExpertList } from '@/http/apis/expertManage/expertStore'
import { getIsShowRegionTree, getTreeParams } from '@/utils/getIsShowRegionTree'

const
{ dictList } = storeToRefs(store.dictStore),
router = useRouter(),
{ proxy } = getCurrentInstance(),
searchForm = reactive({
expertName: undefined,
company: undefined,
expertTypeDictionaryCode: undefined,
status: undefined,
maxDeclareAmount: undefined,
maxApprovalAmount: undefined
}),
tableListRef = ref(),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '专家姓名',
key: 'expertName',
prop: 'expertName',
minWidth: '80',
showOverflowTooltip: true
},
{
label: '工作单位',
key: 'company',
prop: 'company',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '手机号码',
key: 'phoneNo',
prop: 'phoneNo',
width: '120'
},
{
label: '专家类型',
key: 'expertType[0].dictionaryName',
prop: 'expertType[0].dictionaryName',
width: '80'
},
{
label: '创建时间',
key: 'createTime',
prop: 'createTime',
width: '180'
},
{
label: '操作',
slot: 'action',
width: '240',
fixed: 'right'
}
]),
data = ref([]),
areaCode = ref(),
getTree = (value) => {
searchForm.intentionRegionInfo = {
regionCode: value.regionCode,
regionLevel: value.regionLevel
}
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await getExpertList({
...pageParams,
...searchForm,
year: searchForm.year * 1 || undefined,
areaCode: areaCode.value || undefined
})
data.value = res.data.records
total.value = res.data.total
},
search = () => {
getTableData()
},
reset = () => {
searchForm.expertName = undefined
searchForm.company = undefined
searchForm.expertTypeDictionaryCode = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
toAddorEditExpert = (row) => {
if (row.userId) {
router.push({ name: 'addOrEditExpert', query: { id: row.userId }})
} else {
router.push({ name: 'addOrEditExpert' })
}
},
checkDetail = (row) => {
router.push({ name: 'expertDetail', query: { id: row.userId }})
},
checkDeputyActivityRecord = (row) => {
router.push({ name: 'deputyActivityRecord', query: { id: row.userId, name: row.expertName }})
},
expertApply = () => {
const timestamp = new Date().getTime()
const time = window.btoa(timestamp)
const routeData = router.resolve({
name: 'expertEnroll',
query: { time }
})
window.open(routeData.href, '_blank')
},
del = (data) => {
proxy.$messageBox
.confirm(`确定要删除${data.expertName}专家吗?`, '提示!', {
type: 'warning'
}).then(async () => {
await delivery(data.userId)
proxy.$message.success('删除成功')
getTableData()
})
}
onMounted(() => {
if (!getIsShowRegionTree(['SUPER_ADMIN', 'REGION_MANAGER', 'EXPERT_ADMIN'])) getTableData()
})
</script>
<template>
<el-row>
<el-col
v-if="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])"
style="padding-right: 16px"
:span="4"
>
<elTree :params="getTreeParams({'SUPER_ADMIN':false,'REGION_MANAGER':false,'EXPERT_ADMIN':false})" @get-tree="getTree" />
</el-col>
<el-col :span="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])?20:24">
<el-card class="w-full search">
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
class="mb-16"
>
<el-col :span="8">
<el-form-item label="专家姓名">
<el-input
v-model="searchForm.expertName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工作单位">
<el-input
v-model="searchForm.company"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="专家类型">
<el-select
v-model="searchForm.expertTypeDictionaryCode"
placeholder="全部"
class="w-full"
>
<el-option
v-for="(item,index) in dictList &&
dictList.length &&
dictList.find(i => i.dictionaryName === 'expert_type')
.dictionaryList"
:key="index"
:label="item.describe"
:value="item.dictionaryCode"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="search"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<div>
<el-button
type="primary"
plain
size="small"
icon="Plus"
@click="toAddorEditExpert"
>新增专家</el-button>
<el-button
type="primary"
size="small"
@click="expertApply"
>专家报名</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="toAddorEditExpert(scope.row)">编辑</a>
<a @click="checkDetail(scope.row)">详情</a>
<a @click="checkDeputyActivityRecord(scope.row)">履职记录</a>
<a class="text-danger" @click="del(scope.row)">删除</a>
</template>
</table-list>
</el-card>
</el-col>
</el-row>
</template>
<style lang='less' scoped>
</style>

+ 234
- 0
src/pages/expertManage/expertVerify/index.vue Datei anzeigen

@@ -0,0 +1,234 @@
<script setup name='expertVerify'>
import elTree from '@/components/elTree/index.vue'
import { reactive, ref, onMounted, h } from 'vue'
import { useRouter } from 'vue-router'
import { getExpertVerifyList } from '@/http/apis/expertManage/expertVerify'
import { getIsShowRegionTree, getTreeParams } from '@/utils/getIsShowRegionTree'
import store from '@/store'

const tableListRef = ref(),
router = useRouter(),
searchForm = reactive({
expertName: undefined,
companyName: undefined,
expertType: undefined,
applyStatusList: ['pending_review'],
maxDeclareAmount: undefined,
maxApprovalAmount: undefined
}),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '专家姓名',
key: 'name',
prop: 'name',
minWidth: '80',
showOverflowTooltip: true
},
{
label: '工作单位',
key: 'company',
prop: 'company',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '手机号码',
key: 'phoneNo',
prop: 'phoneNo',
width: '120'
},
{
label: '专家类型',
key: 'expertType',
prop: 'expertType',
width: '80',
render: row => h('span', row?.expertType?.[0].dictionaryName || '-')
},
{
label: '报名时间',
key: 'applyTime',
prop: 'applyTime',
width: '180'
},
{
label: '操作',
slot: 'action',
width: '200',
fixed: 'right'
}
]),
data = ref([]),
areaCode = ref(),
getTree = (value) => {
searchForm.expertRegionInfo = {
regionCode: value.regionCode,
regionLevel: value.regionLevel
}
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await getExpertVerifyList({
...pageParams,
...searchForm,
year: searchForm.year * 1 || undefined,
maxDeclareAmount: searchForm.maxDeclareAmount * 1 || undefined,
maxApprovalAmount: searchForm.maxApprovalAmount * 1 || undefined,
startTime: searchForm.times?.[0] || undefined,
endTime: searchForm.times?.[1] || undefined,
areaCode: areaCode.value || undefined
})
data.value = res.data.records
total.value = res.data.total
},
activeName = ref('待审核'),
search = () => {
getTableData()
},
reset = () => {
searchForm.expertName = undefined
searchForm.companyName = undefined
searchForm.expertType = undefined
searchForm.maxDeclareAmount = undefined
searchForm.maxApprovalAmount = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
checkDetail = (data) => {
if (activeName.value === '待审核') {
router.push({ name: 'expertVerifyAction', query: { applyId: data.id, applyType: data.applyType }})
} else {
router.push({ name: 'verifyDetail', query: { applyId: data.id }})
}
},
handleClick = ({ props: { name }}) => {
if (name === '待审核') {
searchForm.applyStatusList = ['pending_review']
getTableData()
} else {
searchForm.applyStatusList = ['passed', 'refused', 'revoked']
getTableData()
}
}
onMounted(() => {
if (!getIsShowRegionTree(['SUPER_ADMIN', 'REGION_MANAGER', 'EXPERT_ADMIN'])) getTableData()
})
</script>

<template>
<el-row>
<el-col
v-if="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])"
style="padding-right: 16px"
:span="4"
>
<elTree :params="getTreeParams({'SUPER_ADMIN':false,'REGION_MANAGER':false,'EXPERT_ADMIN':false})" @get-tree="getTree" />
</el-col>
<el-col :span="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])?20:24">
<el-card class="w-full search">
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
class="mb-16"
>
<el-col :span="8">
<el-form-item label="专家姓名">
<el-input
v-model="searchForm.expertName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工作单位">
<el-input
v-model="searchForm.companyName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="专家类型">
<el-select
v-model="searchForm.expertType"
placeholder="全部"
class="w-full"
value-key="dictionaryCode"
>
<el-option
v-for="(item,index) in store.dictStore.expertTypeDict"
:key="index"
:label="item.dictionaryName"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter="16"
>
<el-col :span="24">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="search"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8 tab-card">
<template #header>
<el-tabs
v-model="activeName"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane
label="待审核"
name="待审核"
/>
<el-tab-pane
label="已审核"
name="已审核"
/>
</el-tabs>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #action="{ scope }">
<a @click="checkDetail(scope.row)">{{ activeName==='待审核'?'处理':'详情' }}</a>
</template>
</table-list>
</el-card>
</el-col>
</el-row>
</template>

<style lang='less' scoped>

</style>

+ 428
- 0
src/pages/expertManage/expertVerify/verifyDetail/index.vue Datei anzeigen

@@ -0,0 +1,428 @@
<script setup name='verifyDetail'>
import { getCurrentInstance, ref, reactive, watch, onMounted, nextTick } from 'vue'
import {
getExpertVerifyDetail,
submitVerifyResult,
getExpertDetail,
modifyDetail
} from '@/http/apis/expertManage/expertVerify'
import { useRouter, useRoute } from 'vue-router'
import Accessory from '@/components/accessory/index.vue'
import store from '@/store'
const { expertAuditStatusOptions } = store.dictStore.globalDicts
const activeName = ref('basicInfo'),
{ proxy } = getCurrentInstance(),
dialogFormVisible = ref(false),
route = useRoute(),
router = useRouter(),
routeName = ref(''),
form = reactive({
applyId: route.query.applyId
}),
rules = reactive({
auditOpinion: [
{ required: true, message: '请填写审核意见', trigger: 'blur' }
]
}),
ruleFormRef = ref(''),
submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate(async (valid, fields) => {
if (valid) {
if (recommendTitle.value === '通过') {
form.applyResult = true
} else {
form.applyResult = false
}
await submitVerifyResult(form)
form.auditOpinion = undefined
dialogFormVisible.value = false
proxy.$message.success('审核意见提交成功!')
router.push({ name: 'expertVerify' })
} else {
console.log('error submit!', fields)
}
})
},
recommendTitle = ref(''),
adopt = (title) => {
recommendTitle.value = title
dialogFormVisible.value = true
nextTick(() => {
ruleFormRef.value.resetFields()
})
},
goBack = () => {
router.push({ name: 'expertVerify' })
},
expertDetail = ref({ basicInfo: {}, eduInfo: {}, jobInfo: {}, professionalInfo: {}, recommendInfo: {}}),
verifyInfo = ref(),
getVerifyDetail = async () => {
const res = await getExpertVerifyDetail({ applyId: route.query.applyId })
verifyInfo.value = res.data
},
getExpertDetailRequest = async () => {
const apiFn = route.query.applyType === 'expert_info_modify_admin' ? modifyDetail : getExpertDetail
const res = await apiFn({ expertUserId: verifyInfo.value.expertUserId })
expertDetail.value = res.data
},
// 查看文件
view = (data) => {
const routeUrl = router.resolve({
path: '/fileView',
query: { id: data }
})
window.open(routeUrl.href, '_blank')
}
onMounted(async () => {
await getVerifyDetail()
await getExpertDetailRequest()
})
watch(
route,
(val) => {
routeName.value = route.meta.title
},
{ immediate: true, deep: true }
)
</script>

<template>
<div class="footerPage">
<el-card
v-if="routeName ==='专家审核详情'"
shadow="never"
class="mb-16"
>
<div>
<div class="flex justify-between items-center">
<div class="flex-1">
<p class="font-bold">关于{{ expertDetail.basicInfo.name }}的专家审核结果</p>
<div class="mt-8 search">
<el-form label-suffix=":">
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="审核人">{{ verifyInfo?.auditor||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="审核时间">{{ verifyInfo?.auditTime||'-' }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="审核意见">{{ verifyInfo?.auditOption||'-' }}</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
<div class="textRight">
<p>
<span :class="`dot mr-4 bg-${verifyInfo&&verifyInfo.auditStatus&&expertAuditStatusOptions[verifyInfo.auditStatus]?.color}`"></span>
<span :class="`font-semibold text-${verifyInfo&&verifyInfo.auditStatus&&expertAuditStatusOptions[verifyInfo.auditStatus]?.color}`">{{ verifyInfo&&verifyInfo.auditStatus&&expertAuditStatusOptions[verifyInfo.auditStatus]?.name }}</span>
</p>
<p>审核结果</p>
</div>
</div>
</div>
</el-card>
<el-card class="tab-card" shadow="never">
<template #header>
<el-tabs v-model="activeName">
<el-tab-pane label="基本信息" name="basicInfo" />
<el-tab-pane label="学历信息" name="eduInfo" />
<el-tab-pane label="职业信息" name="professionInfo" />
<el-tab-pane label="专业信息" name="majorInfo" />
<el-tab-pane label="推荐信息" name="recommendInfo" />
<el-tab-pane label="其他信息" name="expertOtherInfo" />
</el-tabs>
</template>
<el-descriptions
v-if="activeName==='basicInfo'"
:column="2"
border
>
<el-descriptions-item
label="专家名称"
span="1"
width="200px"
>
{{ expertDetail.basicInfo.name }}
</el-descriptions-item>
<el-descriptions-item label="是否在浙政钉组织" width="200px">
{{ expertDetail.basicInfo.isDingUser?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item
label="手机号码"
width="200px"
>
{{ expertDetail.basicInfo.phoneNo }}
</el-descriptions-item>
<el-descriptions-item label="性别">
{{ expertDetail.basicInfo.gender === '1' ? '男': '女' }}
</el-descriptions-item>
<el-descriptions-item label="籍贯">
{{ expertDetail.basicInfo.hometown }}
</el-descriptions-item>
<el-descriptions-item label="民族">
{{ expertDetail.basicInfo.nationality }}
</el-descriptions-item>
<el-descriptions-item label="政治面貌">
{{ expertDetail.basicInfo.political?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="身份证号">
{{ expertDetail.basicInfo.idCard }}
</el-descriptions-item>
<el-descriptions-item label="办公电话">
{{ expertDetail.basicInfo.officePhone }}
</el-descriptions-item>
<el-descriptions-item label="出生年月">
{{ expertDetail.basicInfo.birth }}
</el-descriptions-item>
<el-descriptions-item label="银行卡号">
{{ expertDetail.basicInfo.bankNo }}
</el-descriptions-item>
<el-descriptions-item label="开户银行">
{{ expertDetail.basicInfo.bank }}
</el-descriptions-item>
<el-descriptions-item span="1" label="电子邮箱">
{{ expertDetail.basicInfo.email }}
</el-descriptions-item>
<el-descriptions-item label="专家级别">
{{ expertDetail.basicInfo?.expertRegionInfo?.regionName.split('@@').map(i=>i.split('##')[1]).join('-') }}
</el-descriptions-item>
<el-descriptions-item label="专家来源">
{{ expertDetail.basicInfo.expertSource?.[0].tagName }}
</el-descriptions-item>
<el-descriptions-item label="专家类型">
{{ expertDetail.basicInfo.expertType?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="履职意向">
{{ expertDetail.basicInfo.expertIntentionWorkRegions?.map(i=>i.regionName.split('@@').map(j=>j.split('##')[1]).join('-')).join(';') }}
</el-descriptions-item>
<el-descriptions-item
label="头像(免冠照)"
span="2"
>
<a target="_blank" @click="view(expertDetail.basicInfo.avatarFile.fileId)">{{ expertDetail.basicInfo.avatarFile?.fileName }}</a>

</el-descriptions-item>
</el-descriptions>
<el-descriptions
v-if="activeName==='eduInfo'"
:column="2"
border
>
<el-descriptions-item
label="毕业院校"
span="2"
width="200px"
>
{{ expertDetail.eduInfo.school }}
</el-descriptions-item>
<el-descriptions-item label="毕业时间">
{{ expertDetail.eduInfo.graduatedAt }}
</el-descriptions-item>
<el-descriptions-item
label="所学专业"
width="200px"
>
{{ expertDetail.eduInfo.academicTitle }}
</el-descriptions-item>
<el-descriptions-item label="学位">
{{ expertDetail.eduInfo.degree?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="学历">
{{ expertDetail.eduInfo.edu?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="毕业证书">
<p v-for="(file,fileIndex) in expertDetail.eduInfo.graduationCertificateFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
<el-descriptions-item label="学位证书">
<p v-for="(file,fileIndex) in expertDetail.eduInfo.degreeCertificateFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
v-if="activeName==='professionInfo'"
:column="2"
border
>
<el-descriptions-item
label="工作单位"
width="200px"
>
{{ expertDetail.jobInfo.company }}
</el-descriptions-item>
<el-descriptions-item label="工作单位code" width="200px">
{{ expertDetail.jobInfo.companyUniqCode }}
</el-descriptions-item>
<el-descriptions-item
label="单位法人编号"
width="200px"
>
{{ expertDetail.jobInfo.legalEntityCode }}
</el-descriptions-item>
<el-descriptions-item label="行政职务">
{{ expertDetail.jobInfo.administrativeDuties }}
</el-descriptions-item>
<el-descriptions-item label="开始工作日期">
{{ expertDetail.jobInfo.startWorkAt }}
</el-descriptions-item>
<el-descriptions-item label="行政职级">
{{ expertDetail.jobInfo.administrativeRank?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="在职状态">
{{ expertDetail.jobInfo.jobStatus?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="退休日期">
{{ expertDetail.jobInfo.retiredAt }}
</el-descriptions-item>
<el-descriptions-item label="单位类型">
{{ expertDetail.jobInfo.companyAttribute?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item label="工作地址">
{{ expertDetail.jobInfo.address }}
</el-descriptions-item>
<el-descriptions-item label="工作经历">
{{ expertDetail.jobInfo.experience }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions
v-if="activeName==='majorInfo'"
:column="2"
border
>
<el-descriptions-item
label="技术职称"
width="200px"
>
{{ expertDetail.professionalInfo.technicalTitles }}
</el-descriptions-item>
<el-descriptions-item label="职称级别" width="200px">
{{ expertDetail.professionalInfo.titleLevel?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item
label="擅长方向"
width="200px"
>
{{ expertDetail.professionalInfo.goodAt?.map(i=>i.tagName).join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="技术专长">
{{ expertDetail.professionalInfo.technicalExpertise?.[0].tagName }}
</el-descriptions-item>
<el-descriptions-item label="行业领域">
{{ expertDetail.professionalInfo.industrySector?.[0].tagName }}
</el-descriptions-item>
<el-descriptions-item label="获奖情况">
{{ expertDetail.professionalInfo.awards }}
</el-descriptions-item>
<el-descriptions-item label="表彰奖励">
{{ expertDetail.professionalInfo.recognitionReward }}
</el-descriptions-item>
<el-descriptions-item label="回避单位">
<span v-for="(item,index) in expertDetail.professionalInfo.avoidCompanyList" :key="index">{{ item.companyName }}&nbsp;&nbsp;</span>
</el-descriptions-item>
<el-descriptions-item label="职称证明">
<p v-for="(file,fileIndex) in expertDetail.professionalInfo.titleCertificateFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
v-if="activeName==='recommendInfo'"
:column="2"
border
>
<el-descriptions-item
label="推荐类型"
width="200px"
>
{{ expertDetail.recommendInfo.recommendedWay?.[0].dictionaryName }}
</el-descriptions-item>
<el-descriptions-item
width="200px"
label="推荐证明"
>
<p v-for="(file,fileIndex) in expertDetail.recommendInfo.recommendationProofFile" :key="fileIndex" class="mb-4">
<accessory :file-name="file.fileName" :file-id="file.fileId" />
</p>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
v-if="activeName==='expertOtherInfo'"
:column="2"
border
>
<el-descriptions-item
label="其他标签"
width="200px"
>
{{ expertDetail.expertOtherInfo?.other?.map(i=>i.tagName)?.join('、') ||'-' }}
</el-descriptions-item>
<el-descriptions-item
width="200px"
label="备注"
>
{{ expertDetail.expertOtherInfo?.remark ||'-' }}
</el-descriptions-item>
</el-descriptions>
</el-card>
<div class="footer">
<el-button
v-if="routeName !=='专家审核详情'"
type="primary"
@click="adopt('通过')"
>通过</el-button>
<el-button
v-if="routeName !=='专家审核详情'"
plain
type="danger"
@click="adopt('驳回')"
>驳回</el-button>
<el-button
@click="goBack"
>返回</el-button>
</div>
</div>
<el-dialog
v-model="dialogFormVisible"
:title="recommendTitle"
>
<el-form
ref="ruleFormRef"
:model="form"
:rules="rules"
status-icon
>
<el-form-item
label="审核意见"
label-width="auto"
prop="auditOpinion"
>
<el-input
v-model="form.auditOpinion"
maxlength="200"
placeholder="请输入"
show-word-limit
type="textarea"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button
type="primary"
@click="submitForm(ruleFormRef)"
>
提交
</el-button>
<el-button @click="dialogFormVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>

</template>

<style lang='less' scoped> </style>

+ 218
- 0
src/pages/expertManage/reviewMeeting/addMeeting/components/addExpertDialog.vue Datei anzeigen

@@ -0,0 +1,218 @@
<script setup name="driverDialog">
import { getCurrentInstance, reactive, ref, watch } from 'vue'
import { getExpertList } from '@/http/apis/expertManage/expertStore'
import store from '@/store'
import { districtList } from '@/http/apis/commonApi'

const { proxy } = getCurrentInstance(),
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: {
type: Array,
default: undefined
},
selectExpertType: {
type: Number,
default: 1
}
}),
emits = defineEmits(['close', 'getUserData']),
searchForm = reactive({
expertRegionLevel: undefined,
expertName: undefined,
company: undefined
}),
tableListRef = ref(),
total = ref(0),
column = [
{
type: 'selection',
reserveSelection: true,
width: '55'
},
{
label: '姓名',
key: 'expertName',
prop: 'expertName'
},
{
label: '工作单位',
key: 'company',
prop: 'company',
showOverflowTooltip: true,
width: 250
},
{
label: '专家级别',
key: 'expertRegionInfo',
slot: 'expertRegionInfo',
width: '150'
},
{
label: '手机号码',
key: 'phoneNo',
prop: 'phoneNo',
width: '150'
},
{
label: '专家类型',
key: 'expertType[0].dictionaryName',
prop: 'expertType[0].dictionaryName',
width: '150'
}
],
tableData = ref([]),
getTableData = async (pageParams = tableListRef.value?.pageParams) => {
const res = await getExpertList({
...pageParams,
...searchForm,
expertRegionInfo: searchForm.expertRegionInfo ? {
regionCode: searchForm.expertRegionInfo.slice(-1)[0].split('##')[0],
regionLevel: searchForm.expertRegionInfo.slice(-1)[0].split('##')[2],
regionName: searchForm.expertRegionInfo.slice(-1)[0].split('##')[1]
} : undefined
})
total.value = res.data.total
tableData.value = res.data.records || []
const selectCopyData = JSON.parse(JSON.stringify(selectData.value))
if (selectCopyData?.length) {
tableData.value && tableData.value.forEach(item => {
const dataIds = selectCopyData.map(i => i.userId * 1)
if (dataIds.includes(item.userId)) {
tableListRef.value.toggleRowSelect(item, true)
}
})
}
},
search = () => {
getTableData()
},
reset = () => {
searchForm.expertRegionInfo = undefined
searchForm.expertName = undefined
searchForm.company = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
selectData = ref([]),
selectionChange = val => {
// selectData.value = val
const ids = val.map(i => i.userId)
tableData.value.forEach(row => {
if (ids.includes(row.userId)) {
selectData.value.push(row)
} else {
selectData.value = selectData.value.filter(i => i.userId !== row.userId)
}
})
},
confirm = () => {
const obj = {}
const data = selectData.value.reduce((cur, next) => {
obj[next.userId] ? '' : obj[next.userId] = true && cur.push(next)
return cur
}, [])
if (props.selectExpertType === 1 && data?.length > 10) {
proxy.$message.warning('最多选择10位人员')
} else {
emits('getUserData', data)
}
},
regionTree = ref([])
watch(
() => props.visible,
async val => {
if (val) {
if (props.data?.length) {
selectData.value = props.data.map(i => i)
}
const res = await districtList({ regionCode: 330500, regionLevel: 2 })
regionTree.value = [res.data]
getTableData()
store.userStore.setRoleStore()
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="选择人员"
width="840px"
destroy-on-close
@close="emits('close')"
>
<div class="search mb-16">
<el-form label-suffix=":" :model="searchForm" size="small">
<el-row :gutter="16" class="mb-16">
<el-col :span="8">
<el-form-item label="专家级别">
<el-cascader
v-model="searchForm.expertRegionInfo"
:options="regionTree"
placeholder="请选择"
class="w-full"
:props="{
value:'unionCode',
label:'name'
}"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="专家姓名">
<el-input
v-model="searchForm.expertName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工作单位">
<el-input
v-model="searchForm.company"
maxlength="11"
placeholder="请输入"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item class="btn">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:total="total"
row-key="userId"
@selection-change="selectionChange"
@get-table-data="getTableData"
>
<template #expertRegionInfo="{scope}">
<span>{{ scope.row?.expertRegionInfo?.regionName||'-' }}</span>
</template>
</table-list>
<template #footer>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
<el-button size="small" @click="emits('close')">
关闭
</el-button>
</template>
</el-dialog>
</template>

+ 149
- 0
src/pages/expertManage/reviewMeeting/addMeeting/components/addProjectDialog.vue Datei anzeigen

@@ -0,0 +1,149 @@
<script setup name="driverDialog">
import { nextTick, reactive, ref, watch } from 'vue'
import { getMeetingProjectList } from '@/http/apis/expertManage/reviewMeeting'
import store from '@/store'
const { projectTypeOptions } = store.dictStore.globalDicts || {}

const
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
data: {
type: Array,
default: undefined
},
meetingType: {
type: String,
default: '1'
},
dictionaryList: {
type: Array,
default: undefined
}
}),
emits = defineEmits(['close', 'getProjectData']),
tableListRef = ref(),
total = ref(0),
column = reactive([
{
type: 'selection',
width: '50'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '申报单位',
key: 'buildOrg',
prop: 'buildOrg',
minWidth: '120',
showOverflowTooltip: true
},
{
label: '项目类型',
slot: 'projectTypeName',
prop: 'projectTypeName',
width: '100'
},
{
label: '申报金额',
key: 'declaredAmount',
prop: 'declaredAmount',
width: '100'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '80'
}
]),
tableData = ref([]),
getTableData = async (pageParams = tableListRef.value?.pageParams) => {
const res = await getMeetingProjectList({
meetingType: props.meetingType,
...pageParams
})
total.value = res.data.total
tableData.value = res.data.records || []
await nextTick()
const selectCopyData = JSON.parse(JSON.stringify(selectData.value)) || []
if (selectCopyData?.length) {
tableData.value && tableData.value.forEach(item => {
const dataIds = selectCopyData.map(i => i.id * 1)
if (dataIds.includes(item.id)) {
tableListRef.value.toggleRowSelect(item, true)
}
})
}
},
selectData = ref([]),
selectionChange = val => {
const ids = val.map(i => i.id)
tableData.value.forEach(row => {
if (ids.includes(row.id)) {
selectData.value.push(row)
} else {
selectData.value = selectData.value.filter(i => i.id !== row.id)
}
})
},
confirm = () => {
const obj = {}
const data = selectData.value.reduce((cur, next) => {
obj[next.id] ? '' : obj[next.id] = true && cur.push(next)
return cur
}, [])
emits('getProjectData', data)
}
watch(
() => props.visible,
async val => {
if (val) {
if (props.data?.length) {
selectData.value = props.data.map(i => i)
}
getTableData()
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="添加项目"
width="840px"
destroy-on-close
@close="emits('close')"
>
<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:total="total"
row-key="id"
@selection-change="selectionChange"
@get-table-data="getTableData"
>
<template #projectTypeName="{scope}">
{{ projectTypeOptions[scope.row?.projectType] }}
</template>
</table-list>
<template #footer>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
<el-button size="small" @click="emits('close')">
关闭
</el-button>
</template>
</el-dialog>
</template>

+ 1181
- 0
src/pages/expertManage/reviewMeeting/addMeeting/index.vue
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 92
- 0
src/pages/expertManage/reviewMeeting/components/meetingProjectDialog.vue Datei anzeigen

@@ -0,0 +1,92 @@
<script name="meetingProjectDialog" setup>
import { ref, reactive, watch } from 'vue'
import { projects } from '@/http/apis/expertManage/reviewMeeting'

const props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
meetingId: {
type: Number,
default: null
}
}),
emits = defineEmits(['close']),
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '申报单位',
key: 'buildOrg',
prop: 'buildOrg',
minWidth: '80',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '100'
},
{
label: '申报金额(万元)',
key: 'declaredAmount',
prop: 'declaredAmount',
width: '150'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear',
width: '80'
}
]),
tableData = ref(),
getTableData = async () => {
const res = await projects(props.meetingId)
tableData.value = res.data
}
watch(
() => props.visible,
async val => {
if (val) {
getTableData()
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="评审项目"
width="60%"
@close="emits('close')"
>
<table-list
ref="tableListRef"
:column="column"
:data="tableData"
:pagination="false"
@get-table-data="getTableData"
/>
<template #footer>
<span class="dialog-footer">
<el-button @click="emits('close')">关闭</el-button>
</span>
</template>
</el-dialog>
</template>


+ 263
- 0
src/pages/expertManage/reviewMeeting/index.vue Datei anzeigen

@@ -0,0 +1,263 @@
<script setup name="reviewMeeting">
import { h, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import ElTree from '@/components/elTree/index.vue'
import { meetingList } from '@/http/apis/expertManage/reviewMeeting'
import MeetingProjectDialog from './components/meetingProjectDialog.vue'
import { getIsShowRegionTree, getTreeParams } from '@/utils/getIsShowRegionTree'

const
router = useRouter(),
searchForm = reactive({
name: undefined,
projectName: undefined,
times: undefined
}),
tableListRef = ref(),
total = ref(0),
// 列表数据
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '会议名称',
key: 'meetingName',
prop: 'meetingName',
minWidth: '180',
showOverflowTooltip: true
},
{
label: '评审项目',
key: 'projectName',
slot: 'projectName',
minWidth: '80'
},
{
label: '评审时间',
key: 'startTime',
prop: 'startTime',
width: '290',
render: row => h('span', row.startTime + '~' + row.endTime)
},
{
label: '会议状态',
key: 'status',
prop: 'status',
width: '80',
render: row => [
h('span', {
class: ['dot mr-4', `${row.status === 1 ? 'bg-success' : row.status === 3 ? 'bg-danger' : ''}`]
}),
h(
'span',
{
class: `${row.status === 1 ? 'text-success' : row.status === 3 ? 'text-danger' : ''}`
},
row.status === 1 ? '正常' : '已取消'
)
]
},
{
label: '抽取方式',
key: 'inviteType',
prop: 'inviteType',
width: '80',
render: row => h('span', row.inviteType === 1 ? '随机抽取' : '指定抽取')

},
{
label: '抽取状态',
key: 'inviteStatus',
prop: 'inviteStatus',
width: '80',
render: row => h('span', !row.inviteStatus ? '抽取中' : '抽取结束')
},
{
label: '名单确认状态',
key: 'confirmedRoster',
prop: 'confirmedRoster',
width: '120',
render: row => [
h(
'span',
{
class: `${row.confirmedRoster ? 'text-success' : ''}`
},
row.confirmedRoster ? '已确认' : '未确认'
)
]
},
{
label: '创建时间',
key: 'createOn',
prop: 'createOn',
width: '180'
},
{
label: '操作',
slot: 'action',
width: '80',
fixed: 'right'
}
]),
data = ref([]),
getTree = (value) => {
searchForm.regionCode = value.regionCode
searchForm.regionLevel = value.regionLevel
tableListRef.value.pageParams.pageNumber = 1
getTableData()
},
getTableData = async (pageParams = tableListRef.value.pageParams) => {
const res = await meetingList({
...pageParams,
...searchForm,
startTime: searchForm.times?.[0] || undefined,
endTime: searchForm.times?.[1] || undefined,
times: undefined
})
data.value = res.data.records
total.value = res.data.total
},
search = () => {
getTableData()
},
reset = () => {
searchForm.name = undefined
searchForm.projectName = undefined
searchForm.times = undefined
tableListRef.value.pageParams.pageNumber = 1
tableListRef.value.pageParams.pageSize = 10
getTableData()
},
// 新增会议
toAddMeeting = (data) => {
router.push({ name: 'addMeeting' })
},
checkDetail = (row) => {
router.push({ name: 'meetingDetail', query: { id: row.meetingId }})
},
// 查看项目
viewProject = (data) => {
meetingProjectDialogData.value.visible = true
meetingProjectDialogData.value.meetingId = data.meetingId
},
meetingProjectDialogData = ref({
visible: false,
meetingId: undefined
}),
close = () => {
meetingProjectDialogData.value.visible = false
}

onMounted(() => {
if (!getIsShowRegionTree(['SUPER_ADMIN', 'REGION_MANAGER', 'EXPERT_ADMIN'])) getTableData()
})
</script>
<template>
<el-row>
<el-col
v-if="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])"
style="padding-right: 16px"
:span="4"
>
<elTree :params="getTreeParams({'SUPER_ADMIN':false,'REGION_MANAGER':false,'EXPERT_ADMIN':true})" @get-tree="getTree" />
</el-col>
<el-col :span="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])?20:24">
<el-card class="w-full search">
<el-form
:model="searchForm"
size="small"
label-suffix=":"
>
<el-row
:gutter="16"
class="mb-16"
>
<el-col :span="12">
<el-form-item label="会议名称">
<el-input
v-model="searchForm.name"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="评审项目">
<el-input
v-model="searchForm.projectName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter="16"
>
<el-col :span="16">
<el-form-item label="评审时间">
<el-date-picker
v-model="searchForm.times"
type="datetimerange"
:editable="false"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="btn">
<div class="flex">
<el-button
type="primary"
@click="search"
>查询</el-button>
<el-button
@click="reset"
>重置</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="w-full mt-8">
<template #header>
<div class="flex justify-between">
<span>列表</span>
<div>
<el-button
type="primary"
size="small"
icon="Plus"
@click="toAddMeeting"
>新增会议</el-button>
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column"
:data="data"
:total="total"
@get-table-data="getTableData"
>
<template #projectName="{scope}">
<a @click="viewProject(scope.row)">查看</a>
</template>
<template #action="{ scope }">
<a @click="checkDetail(scope.row)">详情</a>
</template>
</table-list>
</el-card>
</el-col>
</el-row>
<meeting-project-dialog :visible="meetingProjectDialogData.visible" :meeting-id="meetingProjectDialogData.meetingId" @close="close" />
</template>
<style lang='less' scoped>
</style>

+ 860
- 0
src/pages/expertManage/reviewMeeting/meetingDetail/index.vue Datei anzeigen

@@ -0,0 +1,860 @@
<script setup name='meetingDetail'>
import { ref, reactive, onMounted, h, getCurrentInstance, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import {
batchAppoint,
confirmedRoster, convertToAppoint, expertConfirm,
expertRelease,
inviteExpertList,
meetingBasicInfo,
meetingCancel,
meetingInviteRuleDetail, setUpHeadman, stopInvite,
continueInvite, listReview, expertRemove, exportTable
} from '@/http/apis/expertManage/reviewMeeting'
import store from '@/store'
import addExpertDialog from '../addMeeting/components/addExpertDialog.vue'
import { districtList } from '@/http/apis/commonApi'
import { templatesById } from '@/http/apis/expertManage/expertReview'
import memberOpinion from '@/pages/expertManage/expertReview/components/memberOpinion.vue'
import LeaveDialog from '@/pages/expertManage/expertReview/components/leaveDialog.vue'

const { proxy } = getCurrentInstance(),
router = useRouter(),
route = useRoute(),
{ meetingTypeOptions } = store.dictStore.globalDicts || {},
dialogVisible = ref(false),
// 评审项目
column = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '项目名称',
key: 'projectName',
prop: 'projectName',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '申报单位',
key: 'buildOrg',
prop: 'buildOrg',
minWidth: '80',
showOverflowTooltip: true
},
{
label: '项目类型',
key: 'projectTypeName',
prop: 'projectTypeName',
width: '80'
},
{
label: '申报金额(万元)',
key: 'declareAmount',
prop: 'declareAmount'
},
{
label: '预算年度',
key: 'projectYear',
prop: 'projectYear'
},
{
label: '评审结果',
key: 'reviewResult',
prop: 'reviewResult',
render: row => h('span', row.reviewResult || '-')
},
{
label: '操作',
slot: 'action',
width: '80',
fixed: 'right'
}
]),

column2 = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '规则',
key: 'ruleId',
slot: 'ruleId'
},
{
label: '申请人数',
key: 'inviteCnt',
prop: 'inviteCnt'
},
{
label: '已确认参会人数',
key: 'agreeCnt',
slot: 'agreeCnt'
},
{
label: '实抽人数',
key: 'noticedCnt',
prop: 'noticedCnt'
}
]),
column3 = reactive([
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '专家姓名',
key: 'name',
prop: 'name',
width: '140',
render: row => h('span', `${row.name}${row.isHeadman ? '(组长)' : ''}`)
},
{
label: '手机号码',
key: 'contact',
slot: 'contact',
width: '120'
},
{
label: '匹配规则',
key: 'ruleId',
slot: 'ruleId'
},
{
label: '是否参加',
key: 'confirmedAttend',
prop: 'confirmedAttend',
render: row => h('span', `${row.noticeStatus === '已通知' && row.confirmedAttend ? '确认参加' : row.noticeStatus === '已通知' && !row.confirmedAttend ? '拒绝参加' : '-'}`)
},
{
label: '专家请假',
key: 'leaved',
slot: 'leaved'
},
{
label: '语音通知状态',
key: 'noticeStatus',
prop: 'noticeStatus',
width: '200'
},
{
label: '语音通知时间',
key: 'noticeTime',
prop: 'noticeTime',
width: '200'
}
]),
column4 = reactive([
{
type: 'radio',
key: 'expertId',
width: '60'
},
{
label: '专家姓名',
key: 'name',
prop: 'name'
},
{
label: '工作单位',
key: 'company',
prop: 'company',
minWidth: '150',
showOverflowTooltip: true
},
{
label: '手机号码',
key: 'mobile',
slot: 'mobile'
},
{
label: '专家类型',
key: 'expertTypeName',
prop: 'expertTypeName'
}
]),
column5 = reactive([
{
label: '专家姓名',
key: 'name',
prop: 'name',
render: row => h('span', `${row.name}${row.isHeadman ? '(组长)' : ''}`)
},
{
label: '手机号码',
key: 'mobile',
slot: 'mobile'
},
{
label: '是否参会',
key: 'status',
prop: 'status',
render: row => h('span', row.status === 3 ? '是' : row.status === 4 || row.status === 5 || row.status === 7 ? '否' : '-')
},
{
label: '操作',
slot: 'action',
width: '180',
fixed: 'right'
}
]),
// 获取会议详情
basicInfo = ref({}),
inviteRuleDetail = ref({}),
isExpertConfirmed = ref(false),
getDetail = async () => {
const res = await meetingBasicInfo(route.query.id)
isExpertConfirmed.value = res.data.confirmedRoster
const res1 = await meetingInviteRuleDetail(route.query.id)
basicInfo.value = res.data
inviteRuleDetail.value = res1.data
},
// 抽取情况、通知情况
inviteExpertListData = ref({}),
getInviteExpertList = async () => {
const res = await inviteExpertList(route.query.id)
console.log(res.data)
inviteExpertListData.value = res.data
},
// 查看规则
ruleDialogData = reactive({
visible: false,
data: []
}),
viewRule = (id) => {
ruleDialogData.visible = true
ruleDialogData.data = inviteRuleDetail.value.randomRules.find(i => i.id === id)
},
// 取消会议
cancelMeeting = () => {
proxy.$messageBox
.confirm('确认取消该会议吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await meetingCancel({ meetingId: route.query.id * 1 })
proxy.$message.success('取消会议成功!')
onLoad()
})
},
// 释放专家
releaseExpert = () => {
proxy.$messageBox
.confirm('确认释放专家吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await expertRelease({ meetingId: route.query.id * 1 })
proxy.$message.success('释放专家成功!')
onLoad()
})
},
// 1重发短信、2、3确认召开会议
reText = (type) => {
let text = `${type === 1 ? '确认重发短信' : '确认召开会议'}`
if (type === 3) {
const data = inviteExpertListData.value.inviteStatistics?.filter(i => i.inviteCnt > i.agreeCnt).map(i => '规则' + (inviteRuleDetail.value?.randomRules?.findIndex(j => j.id === i.ruleId) + 1)).join('、')
if (data) {
text = `${data}人数不够,确认召开会议`
}
}
proxy.$messageBox
.confirm(`${text}吗?`, '提示!', {
type: 'warning'
})
.then(async () => {
await confirmedRoster({ meetingId: route.query.id * 1 })
proxy.$message.success('操作成功!')
onLoad()
})
},
// 指定抽取-是否所有专家已参会或是不参会
IsAllExpertAttend = () => {
if (inviteExpertListData.value.inviteExpertList.filter(i => !i.status && i.inviteType !== 1)?.length) {
return false
}
return true
},
// 终止抽取
stopInvites = () => {
proxy.$messageBox
.confirm('确认终止抽取吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await stopInvite(route.query.id * 1)
proxy.$message.success('终止抽取成功!')
onLoad()
})
},
// 参会、不参会
confirmExpert = (data, agreed) => {
proxy.$messageBox
.confirm(`确认${agreed ? '参会' : '不参会'}吗?`, '提示!', {
type: 'warning'
})
.then(async () => {
await expertConfirm({
agreed,
expertMeetingId: data.expertMeetingId,
meetingId: route.query.id * 1
})
onLoad()
})
},
// 指定抽取-移除
removeExpert = async (row) => {
await expertRemove({ expertMeetingId: row.expertMeetingId, meetingId: row.meetingId })
proxy.$message.success('移除成功!')
onLoad()
},
// 设置组长
tableHeadListRef = ref(),
headManData = ref(),
radioChange = (val) => {
headManData.value = val
},
showHeadManDialog = async () => {
dialogVisible.value = true
await nextTick() // 必须
tableHeadListRef.value.setRadio(inviteExpertListData.value?.inviteExpertList?.find(i => i.isHeadman)?.expertId || '')
},
submitUpHeadman = async () => {
dialogVisible.value = false
await setUpHeadman({
agreed: true,
expertMeetingId: headManData.value.expertMeetingId,
meetingId: route.query.id * 1
})
proxy.$message.success('设置组长成功!')
onLoad()
},
// 指定专家-补充
expertDialogData = reactive({
visible: false,
data: undefined
}),
regionTree = ref([]),
showExpertDialog = () => {
expertDialogData.visible = true
},
getExpertData = async (row) => {
await batchAppoint({
expertIdList: row.map(i => i.userId),
meetingId: route.query.id * 1
})
expertDialogData.visible = false
proxy.$message.success('添加成功!')
onLoad()
},
// 转为指定抽取
toAppointInvite = async () => {
await convertToAppoint({ meetingId: route.query.id * 1 })
proxy.$message.success('转为指定抽取成功!')
onLoad()
},
// 刷新
reloadLoaing = ref(false),
onLoad = async (flag) => {
reloadLoaing.value = !flag && true
await getDetail()
await getInviteExpertList()
reloadLoaing.value = false
},
// 随机邀请人数是否足够
getIsEnough = () => {
if (inviteExpertListData.value.inviteStatistics.filter(i => i.agreeCnt !== i.inviteCnt)?.length) {
return true
}
return false
},
// 续抽
continueInvites = () => {
proxy.$messageBox
.confirm('续抽后,将重新通知已拒绝参会的专家们,确定继续吗?', '提示!', {
type: 'warning'
})
.then(async () => {
await continueInvite({ meetingId: route.query.id * 1 })
proxy.$message.success('续抽成功!')
onLoad()
})
},
// 查看评审意见详情
// 所有意见-抽屉
drawerVisible = ref(false),
templatesData = ref([]), // 模板数据
memberOpinions = ref([]), // 所有意见
showReviewDetail = async (data) => {
const res = await listReview({ projectId: data.projectId, meetingId: route.query.id })
const res1 = await templatesById({ templateIds: res.data.map(i => i.templateId).join(',') })
templatesData.value = res1.data
memberOpinions.value = res.data && res.data.map(i => {
return {
...i,
reviewTemplateOptions: i.reviewTemplateOptions && i.reviewTemplateOptions.map(temp => {
const data = templatesData.value.find(j => i.templateId === j.templateId).templates
return {
...temp,
title: data.find(r => r.serialNo === temp.questionSerialNo)?.title,
optionsValue: data.find(r => r.serialNo === temp.questionSerialNo)?.options.filter(j => temp.optionSerialNo.includes(j.serialNo)).map(j => j.option).join('、')
}
}) || []
}
}) || []
drawerVisible.value = true
},
tableName = {
1: '劳务费发放审批单',
2: '专家费用单',
3: '专家抽取表',
4: '项目评审单'
},
handleCommand = async (command) => {
const res = await exportTable(command, route.query.id)
let suffix = 'docx'
if (res.type === 'application/zip') {
suffix = 'zip'
}
const url = URL.createObjectURL(res)
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.download = `${tableName[command]}.${suffix}`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
},
// 请假
leaveDialogData = reactive({
visible: false,
data: undefined
}),
leave = (row) => {
leaveDialogData.visible = true
leaveDialogData.data = {
expertId: row.expertId,
meetingId: route.query.id
}
},
closeLeaveDialog = (flag) => {
leaveDialogData.visible = false
flag && getInviteExpertList()
}
onMounted(async () => {
getDetail()
getInviteExpertList()
const res = await districtList()
regionTree.value.push(res.data)
})
</script>

<template>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>会议信息</span>
</div>
</template>
<el-descriptions
title=""
:column="2"
border
>
<el-descriptions-item label="会议名称">
{{ basicInfo.meetingName }}
</el-descriptions-item>
<el-descriptions-item label="评审类型">
{{ meetingTypeOptions[basicInfo.meetingType] }}
</el-descriptions-item>
<el-descriptions-item
label="评审项目"
:span="2"
>
<table-list
ref="tableListRef"
:column="column"
:pagination="false"
style="max-height: 200px;width:95%"
:data="basicInfo.projects"
>
<template #action="{ scope }">
<a v-if="scope.row.reviewResult" @click="showReviewDetail(scope.row)">详情</a>
</template>
</table-list>
</el-descriptions-item>
<el-descriptions-item label="评审时间">
{{ basicInfo.startTime }}~{{ basicInfo.endTime }}
</el-descriptions-item>
<el-descriptions-item
label="评审耗时"
>
{{ basicInfo.meetingUsageTime===1?'半天':'一天' }}
</el-descriptions-item>
<el-descriptions-item label="评审地点">
{{ basicInfo.meetingAddress }}
</el-descriptions-item>
<el-descriptions-item label="评委到场时间">
{{ basicInfo.judgesAttendanceTime }}
</el-descriptions-item>
<el-descriptions-item label="联系人">
{{ basicInfo.connecter }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ basicInfo.contact }}
</el-descriptions-item>
<el-descriptions-item label="会议状态">
<span :class="`dot mr-4 ${basicInfo.status === 1 ? 'bg-success' : 'bg-danger'}`"></span>
<span :class="`${basicInfo.status === 1 ? 'text-success' : 'text-danger'}`">{{ basicInfo.status===1?'正常': '已取消' }}</span>
</el-descriptions-item>
<el-descriptions-item label="抽取方式">
{{ basicInfo.inviteType === 1 ? '随机抽取' : basicInfo.inviteType === 2?'指定抽取':'-' }}
</el-descriptions-item>
<el-descriptions-item label="抽取状态">
{{ basicInfo.invitedStopped?'抽取结束':!basicInfo.inviteStatus ? '抽取中' :'抽取结束' }}
</el-descriptions-item>
<el-descriptions-item label="专家名单确认状态">
{{ basicInfo.confirmedRoster? '已确认' : '未确认' }}
</el-descriptions-item>
<template v-if="basicInfo.inviteType === 1">
<el-descriptions-item label="部门、条线回避规则">
{{ inviteRuleDetail.avoidInfo?.avoidType===2?'回避条线':inviteRuleDetail.avoidInfo?.avoidType===1?'回避单位':inviteRuleDetail.avoidInfo?.avoidType===3?'不回避':'-' }}
</el-descriptions-item>
<el-descriptions-item
label="回避单位"
> {{ inviteRuleDetail.avoidInfo?.avoidUnits?.map(i=>i).join('、')||"-" }}</el-descriptions-item>
<el-descriptions-item label="回避专家">
{{ inviteRuleDetail.avoidInfo?.experts?.map(i=>i.name).join('、')||"-" }}
</el-descriptions-item>
<el-descriptions-item label="回避条线">
{{ inviteRuleDetail.avoidInfo?.avoidOrgs?.map(i=>i).join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="回避次数">
{{ inviteRuleDetail.avoidInfo?.weekInviteCount||'-' }}
</el-descriptions-item>
</template>
<el-descriptions-item
v-else
label="邀请理由"
:span="2"
>{{ basicInfo?.inviteRule?.appointRule?.inviteDesc||'-' }}</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 随机抽取-->
<template v-if="basicInfo.inviteType === 1">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>抽取情况</span>
<div>
<el-button
v-if="basicInfo.invitedStopped||basicInfo.inviteStatus"
class="button"
type="primary"
plain
@click="toAppointInvite"
>转为指定抽取</el-button>
<el-button
v-if="basicInfo.status===1&&(basicInfo.invitedStopped||basicInfo.inviteStatus)&&getIsEnough()"
class="button"
type="primary"
plain
@click="continueInvites"
>续抽</el-button>
<!-- <el-button-->
<!-- v-if="basicInfo.status===1&&(basicInfo.invitedStopped||basicInfo.inviteStatus)&&!basicInfo.confirmedRoster"-->
<!-- class="button"-->
<!-- type="primary"-->
<!-- @click="reText(3)"-->
<!-- >确认召开会议</el-button>-->
</div>
</div>
</template>
<table-list
ref="tableListRef"
:column="column2"
:pagination="false"
:data="inviteExpertListData.inviteStatistics"
>
<template #agreeCnt="{ scope }">
<div class="flex items-center">
<span>{{ scope.row.agreeCnt }}</span>
<el-icon
v-if="scope.row.agreeCnt===scope.row.inviteCnt"
class="ml-8"
style="color: #4ecb74"
><Select /></el-icon>
</div>
</template>
<template
#ruleId="{scope}"
>
<a @click="viewRule(scope.row.ruleId)">规则{{ inviteRuleDetail?.randomRules?.findIndex(i => i.id === scope.row.ruleId)+1||'' }}</a>
</template>
</table-list>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>通知情况</span>
<el-button
v-if="!basicInfo.invitedStopped"
class="button"
type="danger"
plain
@click="stopInvites"
>终止抽取</el-button>
</div>
</template>
<el-alert
type="warning"
:description="`共有${inviteExpertListData.inviteExpertList?.length}位专家,已通知${inviteExpertListData.inviteExpertList?.filter(i=>i.noticeStatus==='已通知')?.length}位,尚未通知${inviteExpertListData.inviteExpertList?.filter(i=>i.noticeStatus==='未通知')?.length}位。`"
show-icon
:closable="false"
/>
<table-list
ref="tableListRef"
:column="column3"
:pagination="false"
class="mt-15"
:data="inviteExpertListData.inviteExpertList"
>
<template #contact="{scope}">
<el-tooltip
class="box-item"
effect="dark"
:content="scope.row.contact"
>
<span>{{ scope.row.contact?.replace(/(\d{3})\d*(\d{4})/, '$1****$2') }}</span>
</el-tooltip>
</template>
<template #leaved="{scope}">
<a v-if="!scope.row.leaved&&scope.row.confirmedAttend" @click="leave(scope.row)">请假</a>
<span v-else-if="scope.row.leaved">已请假</span>
<span v-else>-</span>
</template>
<template #ruleId="{ scope }">
<a @click="viewRule(scope.row.ruleId)">规则{{ inviteRuleDetail?.randomRules?.findIndex(i => i.id === scope.row.ruleId)+1||'' }}</a>
</template>
</table-list>
</el-card>
</template>
<!-- 指定抽取-->
<el-card v-else class="box-card">
<template #header>
<div class="card-header">
<span>通知情况</span>
<span v-if="basicInfo.status===1">
<el-button
v-if="!isExpertConfirmed"
class="button"
plain
@click="showExpertDialog"
>添加专家</el-button>
<el-button
v-if="!basicInfo.confirmedRoster&&IsAllExpertAttend()"
class="button"
type="primary"
plain
@click="reText(2)"
>确认召开会议</el-button>
</span>
</div>
</template>
<el-alert
type="warning"
:description="`共有${inviteExpertListData.inviteExpertList?.length}位专家,确认参会${inviteExpertListData.inviteExpertList?.filter(i=>i.status===3)?.length}位。`"
show-icon
:closable="false"
/>
<table-list
ref="tableListRef"
:column="column5"
:pagination="false"
class="mt-15"
:data="inviteExpertListData.inviteExpertList"
>
<template #mobile="{scope}">
<el-tooltip
class="box-item"
effect="dark"
:content="scope.row.mobile"
>
<span>{{ scope.row.mobile?.replace(/(\d{3})\d*(\d{4})/, '$1****$2') }}</span>
</el-tooltip>
</template>
<template #action="{ scope }">
<div v-if="!scope.row.status&&scope.row.inviteType!==1">
<a @click="confirmExpert(scope.row,true)">参会</a>
<a @click="confirmExpert(scope.row,false)">不参会</a>
<a class="text-danger" @click="removeExpert(scope.row)">移除</a>
</div>
<div v-else>
<span>-</span>
</div>
</template>
</table-list>
</el-card>
<div class="flex h-60 items-center justify-between bg-white ">
<div class="flex items-center ml-20">
<el-button plain @click="router.go(-1)">返回</el-button>
<el-button plain :loading="reloadLoaing" @click="onLoad(false)">刷新</el-button>
<el-button
v-if="basicInfo.status===1"
type="danger"
plain
@click="cancelMeeting"
>取消会议</el-button>
<el-button
v-if="basicInfo.status===1&&basicInfo.inviteStatus"
type="danger"
plain
@click="releaseExpert"
>释放专家</el-button>
</div>
<div class="flex items-center mr-20">
<el-button
v-if="basicInfo.status===1&&basicInfo.confirmedRoster"
plain
type="primary"
@click="showHeadManDialog"
>设置专家组长</el-button>
<el-button
v-if="basicInfo.status===1&&basicInfo.confirmedRoster"
plain
type="primary"
@click="reText(1)"
>重发短信</el-button>
<el-dropdown v-if="basicInfo.status===1&&basicInfo.confirmedRoster" class="ml-12" @command="handleCommand">
<el-button type="primary" plain>
导出<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="1">劳务费发放审批单</el-dropdown-item>
<el-dropdown-item command="2">专家费用单</el-dropdown-item>
<el-dropdown-item command="3">专家抽取表</el-dropdown-item>
<el-dropdown-item command="4">项目评审单</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<el-dialog
v-model="dialogVisible"
title="设置专家组长"
width="50%"
>
<table-list
ref="tableHeadListRef"
:column="column4"
:pagination="false"
class="mt-15"
:data="inviteExpertListData.inviteExpertList.filter(i=>i.status===3)"
@radio-change="radioChange"
>
<template #mobile="{scope}">
<el-tooltip
class="box-item"
effect="dark"
:content="scope.row.mobile"
>
<span>{{ scope.row.mobile?.replace(/(\d{3})\d*(\d{4})/, '$1****$2') }}</span>
</el-tooltip>
</template>
</table-list>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
<el-button
type="primary"
@click="submitUpHeadman"
>
提交
</el-button>
</span>
</template>
</el-dialog>
<el-dialog
v-model="ruleDialogData.visible"
title="规则"
width="70%"
>
<el-descriptions :column="3">
<el-descriptions-item label="内外围:">
{{ ruleDialogData.data?.expertDicts?.find(i=>i.expertDict==='expert_type')?.dictCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="履职意向:">
{{ ruleDialogData.data?.intentionRegions?.map(i=>i.regionName).join('-') }}
</el-descriptions-item>
<el-descriptions-item label="专家来源:">
{{ ruleDialogData.data?.expertTags?.find(i=>i.expertTag==='expert_source')?.tagCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="职称级别:">
{{ ruleDialogData.data?.expertDicts?.find(i=>i.expertDict==='title_level')?.dictCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="擅长方向:">
{{ ruleDialogData.data?.expertTags?.find(i=>i.expertTag==='good_at')?.tagCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="技术专长:">
{{ ruleDialogData.data?.expertTags?.find(i=>i.expertTag==='technical_expertise')?.tagCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="行业领域:">
{{ ruleDialogData.data?.expertTags?.find(i=>i.expertTag==='industry_sector')?.tagCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="其他标签:">
{{ ruleDialogData.data?.expertTags?.find(i=>i.expertTag==='other')?.tagCodes.join('、')||'-' }}
</el-descriptions-item>
<el-descriptions-item label="专家级别:">
{{ ruleDialogData.data?.expertRegions?.map(i=>i.regionName).join('-') }}
</el-descriptions-item>
<el-descriptions-item label="邀请数量:">
{{ ruleDialogData.data.count }}
</el-descriptions-item>
</el-descriptions>
</el-dialog>
<add-expert-dialog
:visible="expertDialogData.visible"
:data="expertDialogData.data"
:region-tree="regionTree"
@get-user-data="getExpertData"
@close="expertDialogData.visible = false"
/>
<el-drawer
v-model="drawerVisible"
title="评审详情"
style="position: absolute"
direction="rtl"
size="70%"
:modal="false"
:append-to-body="false"
modal-class="myDrawerModal"
>
<member-opinion :member-opinions="memberOpinions" />
</el-drawer>
<leave-dialog
:visible="leaveDialogData.visible"
:data="leaveDialogData.data"
title="填写请假原因"
@close="closeLeaveDialog"
/>
</template>

<style lang='less' scoped>
.box-card{
margin-bottom: 20px;
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
}

</style>


+ 251
- 0
src/pages/expertManage/reviewTemplateConfig/index.vue Datei anzeigen

@@ -0,0 +1,251 @@
<script setup name='reviewTemplateConfig'>
import { reactive, ref, onMounted, getCurrentInstance } from 'vue'
import ElTree from '@/components/elTree/index.vue'
import { template, save } from '@/http/apis/expertManage/reviewTemplateConfig'
import { getIsShowRegionTree, getTreeParams } from '@/utils/getIsShowRegionTree'

const { proxy } = getCurrentInstance(),
searchForm = reactive({
regionCode: undefined,
templateType: '1'
}),
// 地区
getTree = (data) => {
searchForm.regionCode = data.regionLevel === 3 ? data.regionCode : undefined
getTemplate()
},
// 切换模板类型
handleClickTab = ({ props }) => {
searchForm.templateType = props.name
getTemplate()
},
// 获取模板
getTemplate = async () => {
try {
const res = await template({ ...searchForm, templateType: searchForm.templateType * 1 })
formData.value = res.data || { templates: [] }
} catch (e) {
formData.value = { templates: [] }
}
},
// 模板列表
column = [
{
label: '序号',
type: 'index',
width: '60'
},
{
label: '意见标题',
slot: 'title'
},
{
label: '选项类型',
slot: 'optionType',
width: 120
},
{
label: '包含的选项',
slot: 'options'
},
{
label: '操作',
slot: 'action',
width: 60
}
],
formData = ref({
templates: []
}),
formRef = ref(),
// 增加问题
addTemp = () => {
formData.value.templates.push({ title: '', optionType: undefined, options: [{}] })
},
// 删除
removeTemp = (index) => {
formData.value.templates.splice(index, 1)
},
// 增加选项
addOptions = (index) => {
formData.value.templates[index].options.push({ option: '' })
},
// 删除选项
removeOption = (index, key) => {
formData.value.templates[index].options.splice(key, 1)
},
loading = ref(false),
submit = async formEl => {
if (!formEl) {
return
}
await formEl.validate(async valid => {
if (valid) {
const postData = getData()
loading.value = true
try {
await save(postData)
proxy.$message.success('提交成功!')
loading.value = false
} catch (e) {
loading.value = false
}
}
})
},
// 插入序号
getData = () => {
return {
regionCode: searchForm.regionCode,
templateType: searchForm.templateType * 1,
templates: formData.value?.templates.map((item, index) => {
return {
...item,
serialNo: index,
options: item.options.map((option, key) => {
return {
...option,
serialNo: key
}
})
}
}) || []
}
}
onMounted(() => {
if (!getIsShowRegionTree(['SUPER_ADMIN', 'REGION_MANAGER', 'EXPERT_ADMIN'])) getTemplate()
})
</script>

<template>
<el-row :gutter="16">
<el-col
v-if="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])"
style="padding-right: 16px"
:span="4"
>
<elTree :params="getTreeParams({'SUPER_ADMIN':false,'REGION_MANAGER':false,'EXPERT_ADMIN':false})" @get-tree="getTree" />
</el-col>
<el-col :span="getIsShowRegionTree(['SUPER_ADMIN','REGION_MANAGER','EXPERT_ADMIN'])?20:24">
<el-card class="w-full tab-card footerCard">
<template #header>
<el-tabs
v-model="searchForm.templateType"
class="demo-tabs"
@tab-click="handleClickTab"
>
<el-tab-pane
label="初步方案评审模版"
name="1"
/>
<el-tab-pane
label="建设方案评审模版"
name="2"
/>
<el-tab-pane
label="验收评审模版"
name="3"
/>
<el-tab-pane
label="部门联审模版"
name="4"
/>
<el-tab-pane
label="公平性审查"
name="5"
/>
</el-tabs>
</template>
<el-form ref="formRef" :model="formData">
<table-list
ref="tableListRef"
:column="column"
:data="formData?.templates||[]"
:pagination="false"
>
<template #title="{scope}">
<el-form-item
v-if="formData.templates[scope.$index]"
:prop="`templates[${scope.$index}].title`"
:rules="[
{
required: true,
message: '请输入',
}
]"
>
<el-input v-model="formData.templates[scope.$index].title" />
</el-form-item>
</template>
<template #optionType="{scope}">
<el-form-item
v-if="formData.templates[scope.$index]"
:prop="`templates[${scope.$index}].optionType`"
:rules="[
{
required: true,
message: '请选择',
}
]"
>
<el-select v-model="formData.templates[scope.$index].optionType">
<el-option label="单选" :value="1" />
<el-option label="多选" :value="2" />
</el-select>
</el-form-item>
</template>
<template #options="{scope}">
<template v-if="formData.templates[scope.$index]">
<div
v-for="(item,key) in formData.templates[scope.$index].options"
:key="key"
class="flex items-center mb-8"
>
<el-form-item
class="flex-1"
style="margin-bottom: 0;"
:prop="`templates[${scope.$index}].options[${key}].option`"
:rules="[
{
required: true,
message: '请输入',
}
]"
>
<el-input v-model="formData.templates[scope.$index].options[key].option" />
</el-form-item>
<svg-icon name="deleteIcon" class="ml-4 cursor-pointer text-24" @click="removeOption(scope.$index,key)" />
</div>
<el-button
type="primary"
size="small"
class="w-full"
plain
icon="Plus"
@click="addOptions(scope.$index)"
>添加选项</el-button>
</template>
</template>
<template #action="{scope}">
<a v-if="formData.templates[scope.$index]" class="text-danger" @click="removeTemp(scope.$index)">移除</a>
</template>
</table-list>
</el-form>
<el-button
type="primary"
class="w-full"
plain
icon="Plus"
@click="addTemp"
>添加意见类型</el-button>
<div class="footer">
<el-button type="primary" :loading="loading" @click="submit(formRef)">
提交
</el-button>
</div>
</el-card>
</el-col>
</el-row>
</template>

<style lang='less' scoped> </style>

+ 108
- 0
src/pages/home/components/initialBootDialog.vue Datei anzeigen

@@ -0,0 +1,108 @@
<script name="leaveDialog" setup>
import { watch } from 'vue'
import { useRouter } from 'vue-router'
const
props = defineProps({
visible: {
type: Boolean,
default: false,
required: true
},
initData: {
type: Array,
default: () => {
return [
{
name: '配置单位流程',
remark: '用于项目审核,请先配置单位默认流程。',
path: 'systemManage/unitSet/flowPathConfiguration'
},
// {
// name: '配置财政编码',
// remark: '用于生成项目唯一编码。',
// path: 'unitSet/fiscalCodeSet'
// },
{
name: '配置印章编码',
remark: '用于电子签章。',
path: 'systemManage/unitSet/fiscalCodeSet'
}]
}
}

}),
router = useRouter(),
emits = defineEmits(['close']),
getUrlParams = (url) => {
// 通过 ? 分割获取后面的参数字符串
const urlStr = url?.split('?')[1] || ''
if (!urlStr) {
return {}
}
// 创建空对象存储参数
const obj = {}
// 再通过 & 将每一个参数单独分割出来
const paramsArr = urlStr.split('&')
for (let i = 0, len = paramsArr.length; i < len; i++) {
// 再通过 = 将每一个参数分割为 key:value 的形式
const arr = paramsArr[i].split('=')
obj[arr[0]] = arr[1]
}
return obj
},
view = (path) => {
const routeUrl = router.resolve({
path: `/systemManage/${path}`,
query: getUrlParams(path)
})
window.open(routeUrl.href, '_blank')
}
watch(
() => props.visible,
async val => {
if (val) {
console.log(val)
}
}
)
</script>

<template>
<el-dialog
:model-value="visible"
title="初始化引导"
width="600px"
destroy-on-close
@close="emits('close')"
>
<div>
<el-alert
title="为保证正常申报项目,请完成以下配置工作:"
:closable="false"
type="info"
show-icon
class="primary-alert"
/>
</div>
<div class="p-16">
<el-steps
direction="vertical"
:space="100"
:active="-1"
>
<el-step
v-for="(item, index) in initData.filter(i=>i.name!=='配置财政编码')"
:key="index"
:title="item.name"
:status="item.isFinish?'success':'wait'"
>
<template #description>
<p>{{ item.remark }}</p>
<el-button link type="primary" @click="view(item.path)">前往配置</el-button>
</template>
</el-step>
</el-steps>
</div>
</el-dialog>
</template>


+ 2140
- 0
src/pages/home/index.vue
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.

Laden…
Abbrechen
Speichern