Compare commits

...

3 Commits

Author SHA1 Message Date
e19c8ae50e Merge branch 'wxd' into hebing
# Conflicts:
#	src/components/workbench/TaskManagement.vue
2025-12-28 19:59:05 +08:00
a8ab4382a2 123 2025-12-28 19:55:42 +08:00
92b9bf9dd1 23号BUG修复 2025-12-27 19:29:46 +08:00
51 changed files with 1143 additions and 323 deletions

2
.env
View File

@@ -1,5 +1,5 @@
# 网站主标题 # 网站主标题
VITE_GLOBAL_TITLE= 'PIGX ADMIN' VITE_GLOBAL_TITLE= '投资管理门户'
# footer # footer
VITE_FOOTER_TITLE= '©2025 pig4cloud.com' VITE_FOOTER_TITLE= '©2025 pig4cloud.com'

View File

@@ -10,3 +10,14 @@ export const getByProcessInstanceId = (processInstanceId: any) => {
} }
}); });
} }
// 企业微信登录
export const loginWx = (code: any) => {
return request({
url: '/admin/oauth2/token',
method: 'get',
params:{
grant_type: 'wechat_work',
code:code
}
});
}

View File

@@ -35,6 +35,16 @@ export const investmentProjectsPlanGetById = (id: number|string) => {
}, },
}); });
}; };
// 根据模板id查询项目投资计划
export const getInvestmentProjectsPlanByTemplateId = (templateId: string) => {
return request({
url: '/admin/investmentProjectsPlan/getByTemplateId',
method: 'get',
params: {
templateId: templateId
}
})
}
// 推送国资 投资项目计划 // 推送国资 投资项目计划
export const investmentProjectsPlanPush = (id: string) => { export const investmentProjectsPlanPush = (id: string) => {
return request({ return request({

View File

@@ -46,6 +46,14 @@ export const getInvestmentProjectsProgressViewAPI = (id: number|string) => {
params: { id } params: { id }
}) })
} }
// 根据模板id查询投资项目进度
export const getInvestmentProjectsProgressByTemplateIdAPI = (templateId: string) => {
return request<InvestmentProjectProgress>({
url: '/admin/investmentProjectsProgress/getByTemplateId',
method: 'get',
params: { templateId }
})
}
// 报送国资 // 报送国资
export const investmentProjectsProgressSubmitAPI = (id: string) => { export const investmentProjectsProgressSubmitAPI = (id: string) => {
return request({ return request({

View File

@@ -27,3 +27,11 @@ export function getProjectExitPlanFeedbackByProcessInstanceId(processInstanceId:
export function getProjectExitPlanFeedbackPage(data: paramsDataProjectExitPlanFeedback) { export function getProjectExitPlanFeedbackPage(data: paramsDataProjectExitPlanFeedback) {
return request<feedbackResponseData>({ url: '/admin/projectExitPlan/feedbackPage', method: 'post', data }) return request<feedbackResponseData>({ url: '/admin/projectExitPlan/feedbackPage', method: 'post', data })
} }
// 根据模板id查询项目退出计划详情
export function getProjectExitPlanByTemplateId(templateId: string) {
return request({ url: '/admin/projectExitPlan/getByTemplateId?templateId=' + templateId, method: 'get' })
}
// 根据模板id查询项目退出计划反馈详情
export function getProjectExitPlanFeedbackByTemplateId(templateId: string) {
return request({ url: '/admin/projectExitPlan/getFeedbackByTemplateId?templateId=' + templateId, method: 'get' })
}

View File

@@ -53,3 +53,11 @@ export const getPropertyRightsByProcessInstanceIdAPI = (processInstanceId: strin
params: { processInstanceId }, params: { processInstanceId },
}); });
} }
// 根据id查询流程详情
export const getProcessInfoByIdAPI = (id: string | number) => {
return request({
url:'/admin/flow/form/processInfo',
method: 'get',
params: { id },
})
}

View File

@@ -14,7 +14,7 @@
<script setup lang="ts" name="StrengthMeter"> <script setup lang="ts" name="StrengthMeter">
import { verifyPasswordStrength } from '/@/utils/toolsValidate'; import { verifyPasswordStrength } from '/@/utils/toolsValidate';
const props = defineProps({ const props = defineProps({
value: { modelValue: {
type: String, type: String,
}, },
showInput: { showInput: {
@@ -28,7 +28,7 @@ const props = defineProps({
}, },
}); });
const emit = defineEmits(['score', 'change', 'update:value']); const emit = defineEmits(['score', 'change', 'update:modelValue']);
// 计算密码强度 // 计算密码强度
const getPasswordStrength = computed(() => { const getPasswordStrength = computed(() => {
@@ -47,13 +47,13 @@ const handleChange = (e: any) => {
}; };
watchEffect(() => { watchEffect(() => {
innerValueRef.value = props.value || ''; innerValueRef.value = props.modelValue || '';
}); });
watch( watch(
() => unref(innerValueRef), () => unref(innerValueRef),
(val) => { (val) => {
emit('update:value', val); emit('update:modelValue', val);
emit('change', val); emit('change', val);
} }
); );

View File

@@ -16,7 +16,9 @@
> >
<template v-if="imageUrl"> <template v-if="imageUrl">
<!-- 如果返回的是OSS 地址则不需要增加 baseURL --> <!-- 如果返回的是OSS 地址则不需要增加 baseURL -->
<img :src="imageUrl.includes('http') ? imageUrl : baseURL + imageUrl" class="upload-image" /> <el-image :src="imageUrl.includes('http') ? imageUrl : baseURL + imageUrl" class="upload-image" @error="()=>imageUrl=''">
</el-image>
<div class="upload-handle" @click.stop> <div class="upload-handle" @click.stop>
<div class="handle-icon" @click="editImg" v-if="!self_disabled"> <div class="handle-icon" @click="editImg" v-if="!self_disabled">
<el-icon :size="props.iconSize"><Edit /></el-icon> <el-icon :size="props.iconSize"><Edit /></el-icon>

View File

@@ -5,18 +5,18 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item prop="actualTotalIncome" :label="t('postInvestmentEvaluationForm.actualTotalRevenue')" required> <el-form-item prop="actualTotalIncome" :label="t('postInvestmentEvaluationForm.actualTotalRevenue')" required>
<el-input v-model="submitFormData.actualTotalIncome" <el-input-number :controls="false" v-model="submitFormData.actualTotalIncome"
:placeholder="t('postInvestmentEvaluationForm.inputPlaceholder')"> :placeholder="t('postInvestmentEvaluationForm.inputPlaceholder')">
<template #append>{{ t('postInvestmentEvaluationForm.unitSuffix') }}</template> <template #append>{{ t('postInvestmentEvaluationForm.unitSuffix') }}</template>
</el-input> </el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item prop="actualInvestmentGain" :label="t('postInvestmentEvaluationForm.actualInvestmentIncome')" required> <el-form-item prop="actualInvestmentGain" :label="t('postInvestmentEvaluationForm.actualInvestmentIncome')" required>
<el-input v-model="submitFormData.actualInvestmentGain" <el-input-number :controls="false" v-model="submitFormData.actualInvestmentGain"
:placeholder="t('postInvestmentEvaluationForm.inputPlaceholder')"> :placeholder="t('postInvestmentEvaluationForm.inputPlaceholder')">
<template #append>{{ t('postInvestmentEvaluationForm.unitSuffix') }}</template> <template #append>{{ t('postInvestmentEvaluationForm.unitSuffix') }}</template>
</el-input> </el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -125,7 +125,7 @@
<div class="info-row"> <div class="info-row">
<div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.projectDirection') }} <div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.projectDirection') }}
</div> </div>
<div class="info-value required">{{ formData.projectInvestmentDirection || 'XXX' }}</div> <div class="info-value required">{{ initTypeString(projectDirectionOptions,formData.projectInvestmentDirection) }}</div>
<div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.directionSubdivision') <div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.directionSubdivision')
}} }}
</div> </div>
@@ -143,7 +143,7 @@
<div class="info-label required">{{ <div class="info-label required">{{
t('postInvestmentEvaluationForm.basicInfo.majorInvestmentProject') }} t('postInvestmentEvaluationForm.basicInfo.majorInvestmentProject') }}
</div> </div>
<div class="info-value required">{{ formData.majorInvestmentProjects || 'XXX' }}</div> <div class="info-value required"> {{ initTypeString(yesOrNo,formData.majorInvestmentProjects) }}</div>
<div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.keyProject') }}</div> <div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.keyProject') }}</div>
<div class="info-value required">{{ initTypeString(projectImportantOptions,formData.keyProject) || 'XXX' }}</div> <div class="info-value required">{{ initTypeString(projectImportantOptions,formData.keyProject) || 'XXX' }}</div>
</div> </div>
@@ -151,7 +151,7 @@
<div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.isWithinMainBusiness') <div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.isWithinMainBusiness')
}} }}
</div> </div>
<div class="info-value required">{{ formData.isMainBusiness || 'XXX' }}</div> <div class="info-value required">{{ initTypeString(yesOrNo,formData.isMainBusiness) }}</div>
<div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.mainBusinessType') }} <div class="info-label required">{{ t('postInvestmentEvaluationForm.basicInfo.mainBusinessType') }}
</div> </div>
<div class="info-value required">{{ initTypeString(mainBusinessOptions,formData.mainBusinessTypes) || 'XXX' }}</div> <div class="info-value required">{{ initTypeString(mainBusinessOptions,formData.mainBusinessTypes) || 'XXX' }}</div>
@@ -274,7 +274,7 @@
<div class="info-value">{{ formData.decisionType || 'XXX' }}</div> <div class="info-value">{{ formData.decisionType || 'XXX' }}</div>
<div class="info-label">{{ <div class="info-label">{{
t('postInvestmentEvaluationForm.decisionInfo.isProjectApprovalProcedureCompleted') }}</div> t('postInvestmentEvaluationForm.decisionInfo.isProjectApprovalProcedureCompleted') }}</div>
<div class="info-value">{{ formData.isProjectApprovalCompleted || 'XXX' <div class="info-value">{{ initTypeString(yesOrNo,formData.isProjectApprovalCompleted) || 'XXX'
}}</div> }}</div>
</div> </div>
<div class="info-row"> <div class="info-row">
@@ -292,7 +292,7 @@
<div class="info-label">{{ <div class="info-label">{{
t('postInvestmentEvaluationForm.decisionInfo.isDecisionProcedureCompleted') t('postInvestmentEvaluationForm.decisionInfo.isDecisionProcedureCompleted')
}}</div> }}</div>
<div class="info-value">{{ formData.isDecisionProcedureCompleted || 'XXX' }}</div> <div class="info-value">{{ initTypeString(yesOrNo,formData.isDecisionProcedureCompleted) || 'XXX' }}</div>
<div class="info-label">{{ <div class="info-label">{{
t('postInvestmentEvaluationForm.decisionInfo.decisionProcedureDocumentNumber') }}</div> t('postInvestmentEvaluationForm.decisionInfo.decisionProcedureDocumentNumber') }}</div>
<div class="info-value">{{ formData.decisionProcedureFileNo || 'XXX' }} <div class="info-value">{{ formData.decisionProcedureFileNo || 'XXX' }}
@@ -531,7 +531,8 @@ import {
constructionNatureOptions, constructionStageOptions, constructionNatureOptions, constructionStageOptions,
Enums, investmentAreaOptions, investmentCategoryOptions, mainBusinessOptions, projectDirectionDetailsOptions, Enums, investmentAreaOptions, investmentCategoryOptions, mainBusinessOptions, projectDirectionDetailsOptions,
projectImportantOptions, projectNatureOptions, projectImportantOptions, projectNatureOptions,
projectSourceOptions, projectStatusOptions, strategicIndustryOptions projectSourceOptions, projectStatusOptions, strategicIndustryOptions,projectDirectionOptions,
yesOrNo
} from '/@/hooks/enums'; } from '/@/hooks/enums';
import { PostInvestmentEvaluation, ProjectInvestmentInfo } from '/@/views/invBid/postInvestmentEvaluation/interface/type'; import { PostInvestmentEvaluation, ProjectInvestmentInfo } from '/@/views/invBid/postInvestmentEvaluation/interface/type';
import { InvestmentProjectProgress } from '/@/views/invMid/progressReport/interface/type'; import { InvestmentProjectProgress } from '/@/views/invMid/progressReport/interface/type';
@@ -648,7 +649,7 @@ const formData = reactive<ProjectInvestmentInfo>({ ...defaultForm });
* 提交数据表单 * 提交数据表单
* */ * */
const submitFormData = ref<PostInvestmentEvaluation>({} as PostInvestmentEvaluation); const submitFormData = ref<PostInvestmentEvaluation>({} as PostInvestmentEvaluation);
const requiredRule = [{ required: true, message: `${t('该字段必填')}` },{validator: (rule: any, value:any,callback: (e?: Error) => void) => { const requiredRule = [{ required: true, message: `该字段必填` },{validator: (rule: any, value:any,callback: (e?: Error) => void) => {
// 检查是否为空值 // 检查是否为空值
if (value === '' || value === null || value === undefined) { if (value === '' || value === null || value === undefined) {
callback() callback()
@@ -659,7 +660,7 @@ const requiredRule = [{ required: true, message: `${t('该字段必填')}` },{va
if (!isNaN(numValue) && isFinite(numValue)) { if (!isNaN(numValue) && isFinite(numValue)) {
callback() callback()
} else { } else {
callback(new Error(`${t('common.isNumber')}`)) callback(new Error(`必须是一个数字`))
} }
}}] }}]
const rules = ref<FormRules<PostInvestmentEvaluation>>({ const rules = ref<FormRules<PostInvestmentEvaluation>>({
@@ -763,7 +764,7 @@ defineExpose({
if (res){ if (res){
return submitFormData.value; return submitFormData.value;
} }
return false; return false
}, },
}) })
const uploadChange = (type:number,_:any,data:any[],index?:number) => { const uploadChange = (type:number,_:any,data:any[],index?:number) => {

View File

@@ -32,7 +32,7 @@
{{ detail.workUnit || '-' }} {{ detail.workUnit || '-' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item :label="t('expertApply.table.level')"> <el-descriptions-item :label="t('expertApply.table.level')">
{{ levelLabel(detail.level) }} <span>{{ level.find((item:any) => item.value === detail.level)?.label || '--' }}</span>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item :label="t('expertLibrary.table.status')"> <el-descriptions-item :label="t('expertLibrary.table.status')">
<el-tag :type="['info', 'primary', 'success', 'danger'][detail.status]">{{ statusLabel(detail.status) }}</el-tag> <el-tag :type="['info', 'primary', 'success', 'danger'][detail.status]">{{ statusLabel(detail.status) }}</el-tag>
@@ -82,6 +82,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import {level} from "/@/hooks/enums";
const baseURL = import.meta.env.VITE_API_URL const baseURL = import.meta.env.VITE_API_URL

View File

@@ -251,7 +251,7 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.strategicEmergingIndustry')" required prop="strategicEmergingIndustry"> <el-form-item :label="t('reserveRegistration.basicInfo.strategicEmergingIndustry')" required prop="strategicEmergingIndustry">
<el-select v-model="formData.strategicEmergingIndustry" :placeholder="t('reserveRegistration.basicInfo.selectPlaceholder')" > <el-select v-model="formData.strategicEmergingIndustry" :placeholder="t('reserveRegistration.basicInfo.selectPlaceholder')" >
<el-option v-for="item in yesOrNo" :key="item.value" :label="item.label" :value="item.value"/> <el-option v-for="item in strategicIndustryOptions" :key="item.value" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -572,12 +572,12 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.decisionInfo.establishmentDocumentNumber')" :prop="formData.isCompleteEstablishmentProcedures === '1' ? 'establishmentDocumentNumber':''"> <el-form-item :label="t('reserveRegistration.decisionInfo.establishmentDocumentNumber')" :prop="formData.isCompleteEstablishmentProcedures === '0' ? 'establishmentDocumentNumber':''">
<el-input maxlength="255" v-model="formData.establishmentDocumentNumber" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" /> <el-input maxlength="255" v-model="formData.establishmentDocumentNumber" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.decisionInfo.establishmentDocumentInfo')" :prop="formData.isCompleteEstablishmentProcedures === '1'?'establishmentDocumentInfo':''"> <el-form-item :label="t('reserveRegistration.decisionInfo.establishmentDocumentInfo')" :prop="formData.isCompleteEstablishmentProcedures === '0'?'establishmentDocumentInfo':''">
<el-input maxlength="255" v-model="formData.establishmentDocumentInfo" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" /> <el-input maxlength="255" v-model="formData.establishmentDocumentInfo" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -597,14 +597,14 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.decisionInfo.decisionProgramDocumentNumber')" :prop="formData.isCompleteDecisionProcedures === '1'?'decisionProgramDocumentNumber' : ''"> <el-form-item :label="t('reserveRegistration.decisionInfo.decisionProgramDocumentNumber')" :prop="formData.isCompleteDecisionProcedures === '0'?'decisionProgramDocumentNumber' : ''">
<el-input maxlength="255" v-model="formData.decisionProgramDocumentNumber" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" /> <el-input maxlength="255" v-model="formData.decisionProgramDocumentNumber" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="24"> <el-col :span="24">
<el-form-item :label="t('reserveRegistration.decisionInfo.decisionDocumentInfo')" :prop="formData.isCompleteDecisionProcedures === '1'?'decisionDocumentInfo':''"> <el-form-item :label="t('reserveRegistration.decisionInfo.decisionDocumentInfo')" :prop="formData.isCompleteDecisionProcedures === '0'?'decisionDocumentInfo':''">
<el-input maxlength="255" v-model="formData.decisionDocumentInfo" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" /> <el-input maxlength="255" v-model="formData.decisionDocumentInfo" :placeholder="t('reserveRegistration.decisionInfo.inputPlaceholder')" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -646,7 +646,8 @@ import {
projectSourceOptions, projectSourceOptions,
constructionNatureOptions, constructionNatureOptions,
investmentAreaOptions, yesOrNo, decisionTypeOptions, projectImportantOptions, cooperationPartnerNatureOptions, investmentAreaOptions, yesOrNo, decisionTypeOptions, projectImportantOptions, cooperationPartnerNatureOptions,
cityStrategyOptions, mainBusinessOptions, projectDirectionDetailsOptions,projectDirectionOptions cityStrategyOptions, mainBusinessOptions, projectDirectionDetailsOptions, projectDirectionOptions,
strategicIndustryOptions
} from '/@/hooks/enums'; } from '/@/hooks/enums';
import UserSelect from '/@/components/UserSelect/index.vue'; import UserSelect from '/@/components/UserSelect/index.vue';
import ProjectNameList from '/@/components/ProjectNameList/index.vue'; import ProjectNameList from '/@/components/ProjectNameList/index.vue';

View File

@@ -103,12 +103,12 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.keyProject')"> <el-form-item :label="t('reserveRegistration.basicInfo.keyProject')">
{{ formData.keyProject === 'yes' ? '是' : '' }} {{ projectImportantOptions.find(item => item.value === formData.keyProject)?.label || formData.keyProject || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.majorInvestmentProject')"> <el-form-item :label="t('reserveRegistration.basicInfo.majorInvestmentProject')">
{{ formData.majorInvestmentProject || '--' }} {{ yesOrNo.find(item => item.value === formData.majorInvestmentProject)?.label || formData.majorInvestmentProject || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -116,7 +116,7 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="24"> <el-col :span="24">
<el-form-item :label="t('reserveRegistration.basicInfo.withinMainBusiness')"> <el-form-item :label="t('reserveRegistration.basicInfo.withinMainBusiness')">
{{ formData.withinMainBusiness || '--' }} {{ yesOrNo.find(item => item.value === formData.withinMainBusiness)?.label || formData.withinMainBusiness || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -124,7 +124,7 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.mainBusinessType')"> <el-form-item :label="t('reserveRegistration.basicInfo.mainBusinessType')">
{{ formData.mainBusinessType || '--' }} {{ mainBusinessOptions.find(item => item.value === formData.mainBusinessType)?.label || formData.mainBusinessType || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -138,12 +138,12 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.projectDirection')"> <el-form-item :label="t('reserveRegistration.basicInfo.projectDirection')">
{{ formData.projectDirection || '--' }} {{ projectDirectionOptions.find(item => item.value === formData.projectDirection)?.label || formData.projectDirection || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.directionSubdivision')"> <el-form-item :label="t('reserveRegistration.basicInfo.directionSubdivision')">
{{ formData.directionSubdivision || '--' }} {{ projectDirectionDetailsOptions.find(item => item.value === formData.directionSubdivision)?.label || formData.directionSubdivision || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -151,12 +151,12 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.strategicEmergingIndustry')"> <el-form-item :label="t('reserveRegistration.basicInfo.strategicEmergingIndustry')">
{{ formData.strategicEmergingIndustry || '--' }} {{ yesOrNo.find(item => item.value === formData.strategicEmergingIndustry)?.label || formData.strategicEmergingIndustry || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.urbanStrategy')"> <el-form-item :label="t('reserveRegistration.basicInfo.urbanStrategy')">
{{ formData.urbanStrategy || '--' }} {{ cityStrategyOptions.find(item => item.value === formData.urbanStrategy)?.label || formData.urbanStrategy || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -164,7 +164,7 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.isManufacturing')"> <el-form-item :label="t('reserveRegistration.basicInfo.isManufacturing')">
{{ formData.isManufacturing || '--' }} {{ yesOrNo.find(item => item.value === formData.isManufacturing)?.label || formData.isManufacturing || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -191,7 +191,7 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.basicInfo.isControllingShareholder')"> <el-form-item :label="t('reserveRegistration.basicInfo.isControllingShareholder')">
{{ formData.isControllingShareholder || '--' }} {{ yesOrNo.find(item => item.value === formData.isControllingShareholder)?.label || formData.isControllingShareholder || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -307,12 +307,12 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.decisionInfo.decisionType')"> <el-form-item :label="t('reserveRegistration.decisionInfo.decisionType')">
{{ formData.decisionType || '--' }} {{ decisionTypeOptions.find(item => item.value === formData.decisionType)?.label || formData.decisionType || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.decisionInfo.isCompleteEstablishmentProcedures')"> <el-form-item :label="t('reserveRegistration.decisionInfo.isCompleteEstablishmentProcedures')">
{{ formData.isCompleteEstablishmentProcedures === 'yes' ? '是' : '' }} {{ yesOrNo.find(item => item.value === formData.isCompleteEstablishmentProcedures)?.label || formData.isCompleteEstablishmentProcedures || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -333,7 +333,7 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('reserveRegistration.decisionInfo.isCompleteDecisionProcedures')"> <el-form-item :label="t('reserveRegistration.decisionInfo.isCompleteDecisionProcedures')">
{{ formData.isCompleteDecisionProcedures === 'yes' ? '是' : '' }} {{ yesOrNo.find(item => item.value === formData.isCompleteDecisionProcedures)?.label || formData.isCompleteDecisionProcedures || '--' }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -369,14 +369,21 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, watch, ref } from 'vue'; import { reactive, watch, ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { import {
projectNatureOptions, projectNatureOptions,
investmentCategoryOptions, investmentCategoryOptions,
projectSourceOptions, projectSourceOptions,
constructionNatureOptions, constructionNatureOptions,
investmentAreaOptions investmentAreaOptions,
yesOrNo,
decisionTypeOptions,
projectImportantOptions,
cityStrategyOptions,
mainBusinessOptions,
projectDirectionDetailsOptions,
projectDirectionOptions
} from '/@/hooks/enums' } from '/@/hooks/enums'
import type { ExternalCooperationUnitItemT } from '/@/api/investment/cooperationUnit' import type { ExternalCooperationUnitItemT } from '/@/api/investment/cooperationUnit'
@@ -433,7 +440,10 @@ export interface ProjectBasicInfoFormData {
isCompleteDecisionProcedures: string; isCompleteDecisionProcedures: string;
reviewOpinions: ReviewOpinions; reviewOpinions: ReviewOpinions;
processInstanceId: string; processInstanceId: string;
cooperationUnits?: ExternalCooperationUnitItemT[] cooperationUnits?: ExternalCooperationUnitItemT[];
parentId?: string;
status: number;
deptId: string;
} }
export interface PartnerInfo { export interface PartnerInfo {
@@ -442,6 +452,7 @@ export interface PartnerInfo {
nature: string; nature: string;
controller: string; controller: string;
share: string; share: string;
cooperationController: string;
} }
export interface ReviewOpinions { export interface ReviewOpinions {
@@ -451,9 +462,15 @@ export interface ReviewOpinions {
submitUnitMainLeadershipOpinion: string; submitUnitMainLeadershipOpinion: string;
} }
const props = defineProps<{ const props = withDefaults(defineProps<{
modelValue?: ProjectBasicInfoFormData; modelValue?: ProjectBasicInfoFormData;
}>(); mainTitle?: string;
}>(), {
mainTitle: ''
});
const mainTitle = computed(() => props.mainTitle);
watch(mainTitle, () => undefined);
const defaultPartnerRow: PartnerInfo = { const defaultPartnerRow: PartnerInfo = {
id: '', id: '',
@@ -519,6 +536,10 @@ const defaultFormData: ProjectBasicInfoFormData = {
submitUnitLeadershipOpinion: '', submitUnitLeadershipOpinion: '',
submitUnitMainLeadershipOpinion: '', submitUnitMainLeadershipOpinion: '',
}, },
parentId: '',
status: 1,
deptId: '',
cooperationUnits: [],
}; };
const formData = reactive<ProjectBasicInfoFormData>({ ...defaultFormData }); const formData = reactive<ProjectBasicInfoFormData>({ ...defaultFormData });
@@ -570,6 +591,19 @@ watch(
.form-row:last-of-type { .form-row:last-of-type {
margin-bottom: 0; margin-bottom: 0;
} }
/* 新增确保el-form-item内容自动换行 */
:deep(.el-form-item) {
word-wrap: break-word;
word-break: break-all;
overflow-wrap: break-word;
}
/* 对于表格中的内容也确保换行 */
:deep(.el-table .cell) {
word-wrap: break-word;
word-break: break-all;
overflow-wrap: break-word;
white-space: pre-wrap;
}
:deep(.el-form-item__label) { :deep(.el-form-item__label) {
font-weight: 500; font-weight: 500;

View File

@@ -177,7 +177,7 @@
</template> </template>
<el-select v-model="formData.entity.constructionNature" <el-select v-model="formData.entity.constructionNature"
:placeholder="t('planApply.placeholder.select')" clearable> :placeholder="t('planApply.placeholder.select')" clearable>
<el-option v-for="item in constructionNatureOptions" :key="item.value" :label="item.label" <el-option v-for="item in ziDian" :key="item.value" :label="item.label"
:value="item.value" /> :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -687,6 +687,7 @@ import { ElMessage } from 'element-plus';
import { FolderOpened } from '@element-plus/icons-vue'; import { FolderOpened } from '@element-plus/icons-vue';
import LibrarySelect from '/@/views/invMid/projectLibrary/components/LibrarySelect.vue'; import LibrarySelect from '/@/views/invMid/projectLibrary/components/LibrarySelect.vue';
import { selectTreeCompanyTree } from '/@/api/admin/dept'; import { selectTreeCompanyTree } from '/@/api/admin/dept';
import {formatStartNodeShow} from "/@/api/flow/task";
const { t } = useI18n(); const { t } = useI18n();
const useForm = ref<FormInstance | undefined>(); const useForm = ref<FormInstance | undefined>();
const props = withDefaults( const props = withDefaults(
@@ -859,7 +860,7 @@ const defaultForm: ProjectPlanApplyFormData = {
submitUnitLeadershipOpinion: '', submitUnitLeadershipOpinion: '',
submitUnitMainLeadershipOpinion: '', submitUnitMainLeadershipOpinion: '',
planImageQuota: '', planImageQuota: '',
deptId: 0, deptId:'0',
processInstanceId: '', processInstanceId: '',
status: 0, status: 0,
}, },
@@ -1103,6 +1104,14 @@ const projectNameFn = (row: any) => {
Object.assign(formData.value.entity, mappedData); Object.assign(formData.value.entity, mappedData);
visible.value = false; visible.value = false;
}; };
const initYiJR = (data:any[]) => {
if (data.length < 0){
return []
}
// formData.entity.submitUnitOpinion
return data.map(item => item.userVoList)
}
const userYj = ref<any[]>([]);
const handleLibrarySelect = (row: any) => { const handleLibrarySelect = (row: any) => {
Object.assign(formData.value.entity, { Object.assign(formData.value.entity, {
...row, ...row,
@@ -1110,6 +1119,13 @@ const handleLibrarySelect = (row: any) => {
parentId: row.id, parentId: row.id,
projectPreliminaryPlanAttachment: row.projectPreliminaryPlanAttachment ? JSON.parse(row.projectPreliminaryPlanAttachment) : [], projectPreliminaryPlanAttachment: row.projectPreliminaryPlanAttachment ? JSON.parse(row.projectPreliminaryPlanAttachment) : [],
}); });
// processInstanceId
const id:string = row.processInstanceId;
formatStartNodeShow({
processInstanceId: id,
}).then((res:any)=>{
userYj.value = initYiJR(res.data)
})
librarySelectVisible.value = false; librarySelectVisible.value = false;
}; };
defineExpose({ defineExpose({
@@ -1159,6 +1175,30 @@ const ProjectDirectionDetailsOptionsEnums = computed(() => {
const handleProjectMainUnitChange = (value: any) => { const handleProjectMainUnitChange = (value: any) => {
formData.value.entity.deptId = value.id formData.value.entity.deptId = value.id
} }
const ziDian = computed(() => {
if (formData.value.entity.investmentCategory === '1'){
return [
{ label: '新开工', value: '1' },
{ label: '续建', value: '2' },
{ label: '加快前期', value: '3' },
]
}
if(formData.value.entity.investmentCategory === '2'){
return [{ label: '新设', value: '4' },
{ label: '续投', value: '5' },
{ label: '完成', value: '6' },
{ label: '储备', value: '7' },]
}
if (formData.value.entity.investmentCategory === '99'){
return [
{ label: '新增', value: '8' },
{ label: '续投', value: '5' },
{ label: '完成', value: '6' },
{ label: '储备', value: '7' },
]
}
return []
})
</script> </script>
<style scoped> <style scoped>

View File

@@ -503,7 +503,7 @@ import {
cityStrategyOptions, Enums cityStrategyOptions, Enums
} from "/@/hooks/enums" } from "/@/hooks/enums"
import type { FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
import FlowFormView from '/@/components/workbench/common/FlowFormView.vue' import FlowFormView from '/@/components/workbench/common/FlowFormView.vue';
const { t } = useI18n(); const { t } = useI18n();
const useForm = ref<FormInstance | undefined>(); const useForm = ref<FormInstance | undefined>();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
@@ -588,9 +588,9 @@ const defaultForm: ProjectPlanApplyFormData = {
submitUnitLeadershipOpinion: '', submitUnitLeadershipOpinion: '',
submitUnitMainLeadershipOpinion: '', submitUnitMainLeadershipOpinion: '',
planImageQuota:'', planImageQuota:'',
processInstanceId: '',
status:0, status:0,
deptId: 0 deptId:0,
processInstanceId:'',
}, },
investmentProjects: [ investmentProjects: [
{ {

View File

@@ -75,7 +75,7 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="t('progressReport.form.completionRate')" required prop="completionRate"> <el-form-item :label="t('progressReport.form.completionRate')" required prop="completionRate">
<el-input v-model="formData.completionRate" <el-input v-model="formData.completionRate"
:placeholder="t('progressReport.form.completionRatePlaceholder')"> :placeholder="t('progressReport.form.completionRatePlaceholder')" disabled>
<template #append>%</template> <template #append>%</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
@@ -107,13 +107,14 @@
<div style="flex: 1;"> <div style="flex: 1;">
<el-form-item style="height: 82px;" :label="t('progressReport.form.reportYear')"> <el-form-item style="height: 82px;" :label="t('progressReport.form.reportYear')">
<el-date-picker v-model="formData.annualReport" type="year" value-format="YYYY" <el-date-picker v-model="formData.annualReport" type="year" value-format="YYYY"
:placeholder="t('progressReport.form.selectYearPlaceholder')" style="width: 100%" /> :placeholder="t('progressReport.form.selectYearPlaceholder')" style="width: 100%"
@change="handleYearChange" />
</el-form-item> </el-form-item>
<el-form-item style="height: 82px;" <el-form-item style="height: 82px;"
:label="t('progressReport.form.currentYearPlannedInvestment')" required :label="t('progressReport.form.currentYearPlannedInvestment')" required
prop="annualPlannedInvestment"> prop="annualPlannedInvestment">
<el-input v-model="formData.annualPlannedInvestment" <el-input v-model="formData.annualPlannedInvestment"
:placeholder="t('progressReport.form.inputPlaceholder')"> :placeholder="t('progressReport.form.inputPlaceholder')" disabled>
<template #append>{{ t('progressReport.form.unitSuffix') }}</template> <template #append>{{ t('progressReport.form.unitSuffix') }}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
@@ -128,7 +129,7 @@
<el-form-item style="height: 82px;" <el-form-item style="height: 82px;"
:label="t('progressReport.form.investmentCompletionRate')"> :label="t('progressReport.form.investmentCompletionRate')">
<el-input v-model="formData.investmentCompletionRate" <el-input v-model="formData.investmentCompletionRate"
:placeholder="t('progressReport.form.inputPlaceholder')"> :placeholder="t('progressReport.form.inputPlaceholder')" disabled>
<template #append>%</template> <template #append>%</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
@@ -141,7 +142,7 @@
<div style="flex: 1;"> <div style="flex: 1;">
<el-form-item style="height: 82px;" :label="t('progressReport.form.plannedPaymentAmount')"> <el-form-item style="height: 82px;" :label="t('progressReport.form.plannedPaymentAmount')">
<el-input v-model="formData.plannedPayment" <el-input v-model="formData.plannedPayment"
:placeholder="t('progressReport.form.inputPlaceholder')"> :placeholder="t('progressReport.form.inputPlaceholder')" disabled>
<template #append>{{ t('progressReport.form.unitSuffix') }}</template> <template #append>{{ t('progressReport.form.unitSuffix') }}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
@@ -155,7 +156,7 @@
<el-form-item style="height: 82px;" <el-form-item style="height: 82px;"
:label="t('progressReport.form.plannedAmountPaymentCompletionRate')"> :label="t('progressReport.form.plannedAmountPaymentCompletionRate')">
<el-input v-model="formData.investmentPlanCompletionRate" <el-input v-model="formData.investmentPlanCompletionRate"
:placeholder="t('progressReport.form.inputPlaceholder')"> :placeholder="t('progressReport.form.inputPlaceholder')" disabled>
<template #append>%</template> <template #append>%</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
@@ -194,13 +195,8 @@
<el-row :gutter="20" class="form-row"> <el-row :gutter="20" class="form-row">
<el-col :span="24"> <el-col :span="24">
<el-form-item :label="t('progressReport.form.currentStageEvidenceMaterials')"> <el-form-item :label="t('progressReport.form.currentStageEvidenceMaterials')">
<el-input v-model="formData.supportingDocuments" <UploadFile :data="formData.supportingDocuments" @change="uploadChange" :fileSize="20"
:placeholder="t('progressReport.form.selectAttachmentPlaceholder')" readonly> type="simple" :limit="10" :isShowTip="false" />
<template #append>
<UploadFile :modelValue="formData.supportingDocuments" @change="uploadChange"
:fileSize="20" type="simple" :limit="10" :isShowTip="false" />
</template>
</el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -278,6 +274,10 @@ const emit = defineEmits<{
(e: 'update:modelValue', value: InvestmentProjectProgress): void; (e: 'update:modelValue', value: InvestmentProjectProgress): void;
}>(); }>();
const useForm = ref<FormInstance | undefined>() const useForm = ref<FormInstance | undefined>()
// 获取当前年份
const currentYear = String(new Date().getFullYear());
const defaultForm = reactive<InvestmentProjectProgress>({ const defaultForm = reactive<InvestmentProjectProgress>({
id: undefined, id: undefined,
projectName: '', projectName: '',
@@ -290,7 +290,7 @@ const defaultForm = reactive<InvestmentProjectProgress>({
completionRate: undefined, completionRate: undefined,
cumulativePaymentToDate: undefined, cumulativePaymentToDate: undefined,
paymentCompletionRate: undefined, paymentCompletionRate: undefined,
annualReport: undefined, annualReport: currentYear, // 默认当前年度
annualPlannedInvestment: undefined, annualPlannedInvestment: undefined,
ytdRemainingInvestment: undefined, ytdRemainingInvestment: undefined,
investmentCompletionRate: undefined, investmentCompletionRate: undefined,
@@ -313,6 +313,12 @@ const defaultForm = reactive<InvestmentProjectProgress>({
deptId: '' deptId: ''
}) })
const formData = reactive<InvestmentProjectProgress>({ ...defaultForm, ...props.modelValue }); const formData = reactive<InvestmentProjectProgress>({ ...defaultForm, ...props.modelValue });
// 确保汇报年度有默认值
if (!formData.annualReport) {
formData.annualReport = currentYear;
}
const projectNameData = ref<ProjectPlanApplyFormItem[]>([]); const projectNameData = ref<ProjectPlanApplyFormItem[]>([]);
// 获取当前日期作为汇报时间 // 获取当前日期作为汇报时间
const reportTime = computed(() => { const reportTime = computed(() => {
@@ -338,6 +344,17 @@ const getProjectNameList = async () => {
} }
} }
getProjectNameList(); getProjectNameList();
// 项目总计划支付额(所有年度计划支付额度的和)
const totalPlannedPayment = ref<number>(0);
/**
* 项目选择改变
* @param {string | number} value - 选中的项目ID
*/
// 当前选中的项目
const currentSelectedProject = ref<ProjectPlanApplyFormItem | null>(null);
/** /**
* 项目选择改变 * 项目选择改变
* @param {string | number} value - 选中的项目ID * @param {string | number} value - 选中的项目ID
@@ -349,11 +366,190 @@ const handelSelectChange = (value: string | number) => {
); );
// 如果找到了对应的项目,则更新实施单位字段 // 如果找到了对应的项目,则更新实施单位字段
if (selectedProject) { if (selectedProject) {
currentSelectedProject.value = selectedProject;
formData.implementingBody = selectedProject.projectMainEntity || selectedProject.projectOwnerUnit || ''; formData.implementingBody = selectedProject.projectMainEntity || selectedProject.projectOwnerUnit || '';
formData.projectName = selectedProject.projectName || ''; formData.projectName = selectedProject.projectName || '';
formData.deptId = String(selectedProject.deptId); formData.deptId = String(selectedProject.deptId);
// 从项目中获取项目总投资金额
const projectTotalAmount = selectedProject.projectTotalAmount || selectedProject.totalInvestment;
if (projectTotalAmount) {
formData.projectTotalAmount = Number(projectTotalAmount);
}
// 计算项目总计划支付额(所有年度计划支付额度的和)
const investmentEntities = selectedProject.projectInvestmentEntities || [];
let totalPayment = 0;
investmentEntities.forEach((entity: any) => {
const paymentAmount = Number(entity.plannedPaymentAmount) || 0;
totalPayment += paymentAmount;
});
totalPlannedPayment.value = totalPayment;
// 根据当前选中的年份更新本年度计划投资额和计划支付额
updateAnnualPlanData(formData.annualReport as string, investmentEntities);
// 触发完成率计算
calculateCompletionRates();
} }
} }
/**
* 年份变化处理
* @param {string} year - 选中的年份
*/
const handleYearChange = (year: string) => {
if (currentSelectedProject.value) {
const investmentEntities = currentSelectedProject.value.projectInvestmentEntities || [];
updateAnnualPlanData(year, investmentEntities);
// 重新计算本年度完成率
calculateAnnualCompletionRates();
}
}
/**
* 更新本年度计划投资额和计划支付额
* @param {string} year - 年份
* @param {any[]} investmentEntities - 投资计划实体列表
*/
const updateAnnualPlanData = (year: string, investmentEntities: any[]) => {
// 查找当前年份对应的投资计划
const currentYearPlan = investmentEntities.find((entity: any) =>
entity.plannedInvestmentYear === year ||
String(entity.plannedInvestmentYear) === year
);
if (currentYearPlan) {
// 设置本年度计划投资额
formData.annualPlannedInvestment = Number(currentYearPlan.plannedImageAmount) || 0;
// 设置本年度计划支付额
formData.plannedPayment = Number(currentYearPlan.plannedPaymentAmount) || 0;
} else {
// 如果没有找到当前年份的计划,清空数据
formData.annualPlannedInvestment = 0;
formData.plannedPayment = 0;
}
}
/**
* 计算总投资完成率和总支付完成率
*/
const calculateCompletionRates = () => {
// 总投资完成率 = 项目开始截至本月末累计完成投资 / 项目总投资金额 * 100
const cumulativeInvestment = Number(formData.cumulativeInvestmentToDate) || 0;
const projectTotal = Number(formData.projectTotalAmount) || 0;
if (projectTotal > 0) {
const rate = (cumulativeInvestment / projectTotal) * 100;
formData.completionRate = Number(rate.toFixed(2));
} else {
formData.completionRate = 0;
}
// 总支付完成率 = 项目开始截至本月末累计完成支付额 / 项目总计划支付额 * 100
const cumulativePayment = Number(formData.cumulativePaymentToDate) || 0;
const totalPayment = totalPlannedPayment.value || 0;
if (totalPayment > 0) {
const rate = (cumulativePayment / totalPayment) * 100;
formData.paymentCompletionRate = Number(rate.toFixed(2));
} else {
formData.paymentCompletionRate = 0;
}
// 同时计算本年度完成率
calculateAnnualCompletionRates();
}
/**
* 计算本年度投资完成率和支付完成率
*/
const calculateAnnualCompletionRates = () => {
// 本年度投资完成率 = 本企业本年度截至本月末完成投资 / 本年度计划投资额 * 100
const ytdInvestment = Number(formData.ytdRemainingInvestment) || 0;
const annualPlannedInvestment = Number(formData.annualPlannedInvestment) || 0;
if (annualPlannedInvestment > 0) {
const rate = (ytdInvestment / annualPlannedInvestment) * 100;
formData.investmentCompletionRate = Number(rate.toFixed(2));
} else {
formData.investmentCompletionRate = 0;
}
// 本年度支付完成率 = 本企业本年度支付完成额 / 本年度计划支付额 * 100
const actualPayment = Number(formData.actualPayment) || 0;
const plannedPayment = Number(formData.plannedPayment) || 0;
if (plannedPayment > 0) {
const rate = (actualPayment / plannedPayment) * 100;
formData.investmentPlanCompletionRate = Number(rate.toFixed(2));
} else {
formData.investmentPlanCompletionRate = 0;
}
}
// 监听累计完成投资和项目总投资金额变化,自动计算总投资完成率
watch(
[() => formData.cumulativeInvestmentToDate, () => formData.projectTotalAmount],
() => {
const cumulativeInvestment = Number(formData.cumulativeInvestmentToDate) || 0;
const projectTotal = Number(formData.projectTotalAmount) || 0;
if (projectTotal > 0) {
const rate = (cumulativeInvestment / projectTotal) * 100;
formData.completionRate = Number(rate.toFixed(2));
} else {
formData.completionRate = 0;
}
}
);
// 监听累计完成支付额变化,自动计算总支付完成率(可编辑,仅作为默认值)
watch(
() => formData.cumulativePaymentToDate,
() => {
const cumulativePayment = Number(formData.cumulativePaymentToDate) || 0;
const totalPayment = totalPlannedPayment.value || 0;
if (totalPayment > 0) {
const rate = (cumulativePayment / totalPayment) * 100;
formData.paymentCompletionRate = Number(rate.toFixed(2));
}
}
);
// 监听本年度完成投资额变化,自动计算本年度投资完成率
watch(
() => formData.ytdRemainingInvestment,
() => {
const ytdInvestment = Number(formData.ytdRemainingInvestment) || 0;
const annualPlannedInvestment = Number(formData.annualPlannedInvestment) || 0;
if (annualPlannedInvestment > 0) {
const rate = (ytdInvestment / annualPlannedInvestment) * 100;
formData.investmentCompletionRate = Number(rate.toFixed(2));
} else {
formData.investmentCompletionRate = 0;
}
}
);
// 监听本年度完成支付额变化,自动计算本年度支付完成率
watch(
() => formData.actualPayment,
() => {
const actualPayment = Number(formData.actualPayment) || 0;
const plannedPayment = Number(formData.plannedPayment) || 0;
if (plannedPayment > 0) {
const rate = (actualPayment / plannedPayment) * 100;
formData.investmentPlanCompletionRate = Number(rate.toFixed(2));
} else {
formData.investmentPlanCompletionRate = 0;
}
}
);
/** /**
* 页码大小改变 * 页码大小改变
* @param {number} pageSize - 新的页码大小 * @param {number} pageSize - 新的页码大小
@@ -389,6 +585,10 @@ watch(
if (typeof newVal.annualReport === 'number') newVal.annualReport = newVal.annualReport.toString() if (typeof newVal.annualReport === 'number') newVal.annualReport = newVal.annualReport.toString()
Object.assign(formData, defaultForm, newVal); Object.assign(formData, defaultForm, newVal);
} }
// 确保汇报年度有默认值
if (!formData.annualReport) {
formData.annualReport = currentYear;
}
}, },
{ immediate: true, deep: true } { immediate: true, deep: true }
); );
@@ -426,6 +626,9 @@ defineExpose({
font-size: 20px; font-size: 20px;
font-weight: 600; font-weight: 600;
text-align: center; text-align: center;
position: relative;
bottom: 20px;
} }
.page-report-time { .page-report-time {

View File

@@ -42,10 +42,9 @@
</div> </div>
<!-- 输入框 --> <!-- 输入框 -->
<template v-else> <template v-else>
<el-input-number v-if="field.type === 'number'" :length="field.length" <el-input-number v-if="field.type === 'number'" align="left" v-model="basicInfoForm[field.key]"
v-model="basicInfoForm[field.key]" :controls="false" :min="0" /> :controls="false" :min="0"/>
<el-input v-else maxlength="255" v-model="basicInfoForm[field.key]" <el-input v-else maxlength="255" v-model="basicInfoForm[field.key]" :placeholder="t('mixedRegister.placeholder.input')" />
:placeholder="t('mixedRegister.placeholder.input')" />
</template> </template>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -59,6 +58,7 @@
import type { FormInstance } from 'element-plus'; import type { FormInstance } from 'element-plus';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import LibrarySelect from '/@/views/investment/mixedReformRegister/components/LibrarySelect.vue'; import LibrarySelect from '/@/views/investment/mixedReformRegister/components/LibrarySelect.vue';
import{ElInputNumber} from 'element-plus'
const { t } = useI18n(); const { t } = useI18n();
type FieldConfig = { type FieldConfig = {
@@ -66,7 +66,7 @@ type FieldConfig = {
label: string; label: string;
span?: number; span?: number;
type?: string; type?: string;
fieldProps?: any; fieldProps?: any; length?: number;
}; };
const props = defineProps<{ const props = defineProps<{

View File

@@ -2,7 +2,7 @@
<div class="task-management"> <div class="task-management">
<div class="task-header"> <div class="task-header">
<el-tabs v-model="activeTab" @tab-change="handleTabChange"> <el-tabs v-model="activeTab" @tab-change="handleTabChange">
<el-tab-pane :label="t('workbench.task.pendingReview') + ` (${pendingCount})`" name="pending" <el-tab-pane :label="t('workbench.task.pendingReview') + ` (${pendingTotal})`" name="pending"
class="task-tab-pane"> class="task-tab-pane">
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="t('workbench.task.saved')" name="saved"></el-tab-pane> <el-tab-pane :label="t('workbench.task.saved')" name="saved"></el-tab-pane>
@@ -30,6 +30,8 @@ import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import {queryMineStarted, queryMineTask} from "/@/api/flow/task"; import {queryMineStarted, queryMineTask} from "/@/api/flow/task";
import {useMessage} from "/@/hooks/message"; import {useMessage} from "/@/hooks/message";
import request from "/@/utils/request";
import {examineDict} from "/@/hooks/enums";
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
@@ -46,6 +48,8 @@ const emit = defineEmits<{
const activeTab = ref('pending'); const activeTab = ref('pending');
const tableData = ref<any[]>([]); const tableData = ref<any[]>([]);
const loading = ref(false); const loading = ref(false);
const pendingTotal = ref(0);
/** /**
* 根据任务名称判断类型 * 根据任务名称判断类型
* @param name 任务名称 * @param name 任务名称
@@ -105,7 +109,7 @@ const handleRowClick = (row: any) => {
}, },
}); });
}; };
const getQueryMineTask = () =>{ const getQueryMineTask = (): Promise<any> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
queryMineTask({ queryMineTask({
title: '', title: '',
@@ -144,6 +148,7 @@ const loadData = async (tab: string) => {
if (tab === 'pending') { if (tab === 'pending') {
const response = await getQueryMineTask() const response = await getQueryMineTask()
res = response?.data?.records res = response?.data?.records
pendingTotal.value = response?.data?.total || 0
} }
if (tab === 'myInitiated') { if (tab === 'myInitiated') {
const response = await getQueryMineStarted() const response = await getQueryMineStarted()

View File

@@ -68,11 +68,11 @@
{{ getStatusLabel(item.approveDesc?.startsWith('拒绝原因:') ? 'rejected' : 'approved') }} {{ getStatusLabel(item.approveDesc?.startsWith('拒绝原因:') ? 'rejected' : 'approved') }}
</div> </div>
<div class="record-opinion"> <div class="record-opinion">
{{ item.approveDesc }} <span>{{ item.approveDesc }}</span>
</div> </div>
</template> </template>
<div class="record-opinion" v-else> <div class="record-opinion" v-else>
发起审批 <!-- 发起审批-->
</div> </div>
</div> </div>
</div> </div>
@@ -508,7 +508,13 @@ onMounted(() => {
font-size: 14px; font-size: 14px;
} }
.record-status { .record-item .record-content .record-status {
max-width: 100%;
text-wrap: wrap;
word-wrap: break-word; /* 允许长单词换行 */
word-break: break-all; /* 打断所有单词 */
white-space: pre-wrap; /* 保留空白符和换行符 */
overflow-wrap: break-word; /* 确保超长内容能换行 */
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
line-height: 1; line-height: 1;
@@ -526,7 +532,15 @@ onMounted(() => {
color: var(--el-text-color-regular); color: var(--el-text-color-regular);
} }
.record-opinion { .record-item .record-content .record-opinion {
max-width: 100%;
text-wrap: wrap;
word-wrap: break-word; /* 允许长单词换行 */
word-break: break-all; /* 打断所有单词 */
white-space: pre-wrap; /* 保留空白符和换行符 */
overflow-wrap: break-word; /* 确保超长内容能换行 */
overflow-x: hidden;
height: auto;
color: var(--el-text-color-regular); color: var(--el-text-color-regular);
font-size: 14px; font-size: 14px;
line-height: 1.6; line-height: 1.6;

View File

@@ -415,6 +415,6 @@ export const yesOrNo:Enums[] = [
* 级别 * 级别
* */ * */
export const level:Enums[] = [ export const level:Enums[] = [
{label:'一级',value:'1'}, {label:'一级',value:'national'},
{label:'二级',value:'2'}, {label:'二级',value:'provincial'},
] ]

View File

@@ -82,8 +82,8 @@ const setShowAside = computed(() => {
if(layout !== 'classic'){ if(layout !== 'classic'){
return true return true
} }
// 首页和工作台不显示侧边栏 // 首页不显示侧边栏
return (route.path !== '/home' && route.path !== '/workbench/index') return route.path !== '/home'
}); });
// 设置显示/隐藏 logo // 设置显示/隐藏 logo

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }"> <div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }">
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange"> <!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
<div class="layout-navbars-breadcrumb-user-icon"> <div class="layout-navbars-breadcrumb-user-icon">
<i class="iconfont" :class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('user.title1')"></i> <i class="iconfont" :class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('user.title1')"></i>
</div> </div>
@@ -10,7 +10,7 @@
<el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item> <el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown> -->
<div class="layout-navbars-breadcrumb-user-icon" @click="onLockClick"> <div class="layout-navbars-breadcrumb-user-icon" @click="onLockClick">
<el-icon :title="$t('layout.threeLockScreenTime')"> <el-icon :title="$t('layout.threeLockScreenTime')">
<ele-Lock /> <ele-Lock />
@@ -55,7 +55,7 @@
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="/workbench/index">{{ $t('user.dropdown1') }}</el-dropdown-item> <el-dropdown-item command="/home">{{ $t('user.dropdown1') }}</el-dropdown-item>
<el-dropdown-item command="personal">{{ $t('user.dropdown2') }}</el-dropdown-item> <el-dropdown-item command="personal">{{ $t('user.dropdown2') }}</el-dropdown-item>
<el-dropdown-item divided command="logOut">{{ $t('user.dropdown5') }}</el-dropdown-item> <el-dropdown-item divided command="logOut">{{ $t('user.dropdown5') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>

View File

@@ -255,11 +255,11 @@ export function verifyPasswordPowerful(val: string) {
export function verifyPasswordStrength(val: string) { export function verifyPasswordStrength(val: string) {
let v = '0'; let v = '0';
// 弱:纯数字,纯字母,纯特殊字符 // 弱:纯数字,纯字母,纯特殊字符
if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\.*]+){6,100}$/.test(val)) v = '1'; if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\.\*_]+){6,100}$/.test(val)) v = '1';
// 中:字母+数字,字母+特殊字符,数字+特殊字符 // 中:字母+数字,字母+特殊字符,数字+特殊字符
if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,100}$/.test(val)) v = '2'; if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.\*_]+$)[a-zA-Z\d!@#$%^&\.\*_]{6,100}$/.test(val)) v = '2';
// 强:字母+数字+特殊字符 // 强:字母+数字+特殊字符
if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,100}$/.test(val)) if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.\*_]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.\*_]+$)(?![\d!@#$%^&\.\*_]+$)[a-zA-Z\d!@#$%^&\.\*_]{6,100}$/.test(val))
v = '3'; v = '3';
// 返回结果 // 返回结果
return v; return v;

View File

@@ -20,7 +20,7 @@
</el-col> </el-col>
<el-col :span="12" class="mb20"> <el-col :span="12" class="mb20">
<el-form-item :label="$t('sysuser.role')" prop="role"> <el-form-item :label="$t('sysuser.role')" prop="role">
<el-select clearable placeholder="请选择角色" v-model="dataForm.roleId"> <el-select clearable placeholder="请选择角色" v-model="dataForm.role" :multiple="true">
<el-option :key="item.roleId" :label="item.roleName" :value="item.roleId" v-for="item in roleData" /> <el-option :key="item.roleId" :label="item.roleName" :value="item.roleId" v-for="item in roleData" />
</el-select> </el-select>
</el-form-item> </el-form-item>

View File

@@ -38,7 +38,7 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-row> </el-row>
<el-row> <!-- <el-row>
<div class="mb8" style="width: 100%"> <div class="mb8" style="width: 100%">
<el-button v-auth="'sys_user_add'" icon="folder-add" type="primary" @click="userDialogRef.openDialog()"> <el-button v-auth="'sys_user_add'" icon="folder-add" type="primary" @click="userDialogRef.openDialog()">
{{ $t('common.addBtn') }} {{ $t('common.addBtn') }}
@@ -68,7 +68,7 @@
style="float: right" style="float: right"
/> />
</div> </div>
</el-row> </el-row> -->
<el-table <el-table
v-loading="state.loading" v-loading="state.loading"
:data="state.dataList" :data="state.dataList"
@@ -111,7 +111,7 @@
{{ $t('common.editBtn') }} {{ $t('common.editBtn') }}
</el-button> </el-button>
<!-- 删除用户 --> <!-- 删除用户 -->
<el-tooltip :content="$t('sysuser.deleteDisabledTip')" :disabled="scope.row.userId !== '1'" placement="top"> <!-- <el-tooltip :content="$t('sysuser.deleteDisabledTip')" :disabled="scope.row.userId !== '1'" placement="top">
<span style="margin-left: 12px"> <span style="margin-left: 12px">
<el-button <el-button
icon="delete" icon="delete"
@@ -123,7 +123,7 @@
>{{ $t('common.delBtn') }} >{{ $t('common.delBtn') }}
</el-button> </el-button>
</span> </span>
</el-tooltip> </el-tooltip> -->
</div> </div>
</template> </template>
</el-table-column> </el-table-column>

View File

@@ -22,30 +22,30 @@
</el-col> </el-col>
<el-col :span="24" class="mb20"> <el-col :span="24" class="mb20">
<el-form-item label="用户名" prop="username"> <el-form-item label="用户名" prop="username">
<el-input v-model="formData.username" clearable disabled></el-input> <el-input v-model="formData.name" clearable disabled></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24" class="mb20"> <el-col :span="24" class="mb20">
<el-form-item label="手机" prop="phone"> <el-form-item label="账号" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机" clearable></el-input> <el-input disabled v-model="formData.username" placeholder="请输入账号" clearable></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24" class="mb20"> <el-col :span="24" class="mb20">
<el-form-item label="邮箱" prop="email"> <el-form-item label="公司" prop="orgName">
<el-input v-model="formData.email" placeholder="请输入邮箱" clearable></el-input> <el-input v-model="formData.orgName" placeholder="请输入公司" clearable></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24" class="mb20"> <el-col :span="24" class="mb20">
<el-form-item label="昵称" prop="nickname"> <el-form-item label="部门" prop="deptName">
<el-input v-model="formData.nickname" placeholder="请输入昵称" clearable></el-input> <el-input v-model="formData.deptName" placeholder="请输入部门" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" placeholder="请输入姓名" clearable></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- <el-col :span="24" class="mb20">-->
<!-- <el-form-item label="姓名" prop="name">-->
<!-- <el-input v-model="formData.name" placeholder="请输入姓名" clearable></el-input>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="24" class="mb20"> <el-col :span="24" class="mb20">
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleSaveUser"> 更新个人信息 </el-button> <el-button type="primary" @click="handleSaveUser"> 更新个人信息 </el-button>
@@ -65,7 +65,7 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24" class="mb20"> <el-col :span="24" class="mb20">
<el-form-item label="原密码" prop="password"> <el-form-item label="原密码" prop="password">
<el-input v-model="passwordFormData.password" :type="showPassword ? 'text' : 'password'" placeholder="请输入密码" clearable type="password"> <el-input v-model="passwordFormData.password" :type="showPassword ? 'text' : 'password'" placeholder="请输入密码" clearable>
<template #suffix> <template #suffix>
<i <i
class="iconfont el-input__icon login-content-password" class="iconfont el-input__icon login-content-password"
@@ -102,7 +102,7 @@
</el-row> </el-row>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="第三方账号"> <!-- <el-tab-pane label="第三方账号">
<template #label> <template #label>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M7.864 4.243A7.5 7.5 0 0 1 19.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 0 0 4.5 10.5a7.464 7.464 0 0 1-1.15 3.993m1.989 3.559A11.209 11.209 0 0 0 8.25 10.5a3.75 3.75 0 1 1 7.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 0 1-3.6 9.75m6.633-4.596a18.666 18.666 0 0 1-2.485 5.33" /> <path stroke-linecap="round" stroke-linejoin="round" d="M7.864 4.243A7.5 7.5 0 0 1 19.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 0 0 4.5 10.5a7.464 7.464 0 0 1-1.15 3.993m1.989 3.559A11.209 11.209 0 0 0 8.25 10.5a3.75 3.75 0 1 1 7.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 0 1-3.6 9.75m6.633-4.596a18.666 18.666 0 0 1-2.485 5.33" />
@@ -126,7 +126,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-tab-pane> </el-tab-pane> -->
</el-tabs> </el-tabs>
</el-drawer> </el-drawer>
</template> </template>
@@ -154,9 +154,9 @@ const formData = ref({
userId: '', userId: '',
username: '', username: '',
name: '', name: '',
email: '', orgName: '',
avatar: '', avatar: '',
nickname: '', deptName: '',
wxDingUserid: '', wxDingUserid: '',
wxCpUserid: '', wxCpUserid: '',
phone: ('' as string) || undefined, phone: ('' as string) || undefined,
@@ -177,9 +177,9 @@ const ruleForm = reactive({
{ required: true, message: '手机号不能为空', trigger: 'blur' }, { required: true, message: '手机号不能为空', trigger: 'blur' },
{ validator: rule.validatePhone, trigger: 'blur' }, { validator: rule.validatePhone, trigger: 'blur' },
], ],
nickname: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '昵称不能为空', trigger: 'blur' }], deptName: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '部门不能为空', trigger: 'blur' }],
email: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '邮箱不能为空', trigger: 'blur' }], orgName: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '邮箱不能为空', trigger: 'blur' }],
name: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '姓名不能为空', trigger: 'blur' }], userId: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '姓名不能为空', trigger: 'blur' }],
}); });
const validatorPassword2 = (rule: any, value: any, callback: any) => { const validatorPassword2 = (rule: any, value: any, callback: any) => {
if (value !== passwordFormData.newpassword1) { if (value !== passwordFormData.newpassword1) {

View File

@@ -21,7 +21,7 @@
> >
<el-table-column type="index" :label="$t('projectReviewPolicy.index')" width="60" /> <el-table-column type="index" :label="$t('projectReviewPolicy.index')" width="60" />
<el-table-column prop="projectType" :label="$t('projectReviewPolicy.projectType')"> <el-table-column prop="projectType" label="投资类别">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<el-select <el-select
v-model="row.projectType" v-model="row.projectType"
@@ -30,7 +30,7 @@
style="width: 100%" style="width: 100%"
> >
<el-option <el-option
v-for="item in projectTypeOptions" v-for="item in investmentCategoryOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
@@ -109,6 +109,7 @@ import {
deleteProjectReviewPolicy deleteProjectReviewPolicy
} from '/@/api/config/projectReviewPolicy'; } from '/@/api/config/projectReviewPolicy';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { investmentCategoryOptions } from '/@/hooks/enums';
const { t } = useI18n(); const { t } = useI18n();
const message = useMessage(); const message = useMessage();

View File

@@ -28,15 +28,15 @@
<!-- Content Area --> <!-- Content Area -->
<el-scrollbar class="h-[calc(100vh-20px)]"> <el-scrollbar class="h-[calc(100vh-20px)]">
<step1 v-show="activeStep === 0" :groupId="paramGroupId" ref="step1Ref" /> <step1 v-show="activeStep === 0" :groupId="paramGroupId" ref="step1Ref" />
<step2 v-show="activeStep === 1" ref="step2Ref" /> <!-- <step2 v-show="activeStep === 1" ref="step2Ref" />-->
<step3 v-show="activeStep === 2" :nodeConfigObj="step3NodeConfig" ref="step3Ref" /> <step3 v-show="activeStep === 1" :nodeConfigObj="step3NodeConfig" ref="step3Ref" />
</el-scrollbar> </el-scrollbar>
<!-- Validation Dialog --> <!-- Validation Dialog -->
<el-dialog v-model="validateDialogShow" :title="$t('flow.processCheck')"> <el-dialog v-model="validateDialogShow" :title="$t('flow.processCheck')">
<el-steps :active="validateFlowStep" finish-status="success" simple class="mt-5"> <el-steps :active="validateFlowStep" finish-status="success" simple class="mt-5">
<el-step :title="$t('flow.basicInformation')" /> <el-step :title="$t('flow.basicInformation')" />
<el-step :title="$t('flow.formDesign')" /> <!-- <el-step :title="$t('flow.formDesign')" />-->
<el-step :title="$t('flow.processDesign')" /> <el-step :title="$t('flow.processDesign')" />
</el-steps> </el-steps>
@@ -178,7 +178,7 @@ const checkStep1 = () => {
validateFlowStep.value = 1; validateFlowStep.value = 1;
setTimeout(function () { setTimeout(function () {
checkStep2(); checkStep3();
}, 500); }, 500);
} else { } else {
validatingShow.value = false; validatingShow.value = false;
@@ -248,5 +248,7 @@ const submitFlow = () => {
}; };
// Add steps data // Add steps data
const steps = [{ title: 'flow.basicInformation' }, { title: 'flow.formDesign' }, { title: 'flow.processDesign' }]; const steps = [{ title: 'flow.basicInformation' },
// { title: 'flow.formDesign' },
{ title: 'flow.processDesign' }];
</script> </script>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import selectShow from '/@/components/OrgSelector/index.vue'; import selectShow from '/@/components/OrgSelector/index.vue';
import uploadImg from "/@/components/Upload/Image.vue"
interface UserVo { interface UserVo {
id: string; id: string;
name: string; name: string;
@@ -28,6 +28,7 @@ const props = defineProps<{
nodeUser: Record<string, any>; nodeUser: Record<string, any>;
row: FlowNode[]; row: FlowNode[];
disableSelect: boolean; disableSelect: boolean;
disabled: boolean;
}>(); }>();
// Create a map to store active tabs for each node // Create a map to store active tabs for each node
@@ -71,7 +72,7 @@ import { Check, Plus, Refresh } from '@element-plus/icons-vue';
<div v-if="node.userVoList?.length" class="flex flex-wrap gap-2 mb-3"> <div v-if="node.userVoList?.length" class="flex flex-wrap gap-2 mb-3">
<div v-for="(item1, index1) in node.userVoList" :key="index1" class="w-10 text-center"> <div v-for="(item1, index1) in node.userVoList" :key="index1" class="w-10 text-center">
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<upload-img v-model:image-url="item1.avatar" width="30px" height="30px"></upload-img> <upload-img v-model:image-url="item1.avatar" width="30px" height="30px" :disabled="disabled"></upload-img>
<div class="mt-1 w-full text-xs truncate">{{ item1.name }}</div> <div class="mt-1 w-full text-xs truncate">{{ item1.name }}</div>
</div> </div>
</div> </div>
@@ -89,7 +90,7 @@ import { Check, Plus, Refresh } from '@element-plus/icons-vue';
<span class="ml-1 text-gray-500">(添加了评论) {{ item1.showTime }}</span> <span class="ml-1 text-gray-500">(添加了评论) {{ item1.showTime }}</span>
</div> </div>
</div> </div>
<div class="p-3 text-sm bg-gray-50 rounded">{{ item1.approveDesc }}</div> <div class="p-3 text-sm bg-gray-50 rounded break-words break-all whitespace-pre-wrap">{{ item1.approveDesc }}</div>
</div> </div>
</div> </div>

View File

@@ -28,6 +28,10 @@ let props = defineProps({
type: Array, type: Array,
dafault: () => [], dafault: () => [],
}, },
disabled: {
type: Boolean,
default: false,
},
}); });
const row = ref([]); const row = ref([]);
@@ -88,5 +92,5 @@ defineExpose({ validate, formatSelectNodeUser });
</script> </script>
<template> <template>
<flow-node-format :row="row" :node-user="nodeUser" :disableSelect="disableSelect" ref="flowNodeFormatRef"></flow-node-format> <flow-node-format :row="row" :node-user="nodeUser" :disableSelect="disableSelect" ref="flowNodeFormatRef" :disabled="disabled"></flow-node-format>
</template> </template>

View File

@@ -8,27 +8,34 @@
<main class="h5-body"> <main class="h5-body">
<div class="card"> <div class="card">
<p class="lead">这是一个简单的移动端页面示例</p> <p class="lead">这是一个简单的移动端页面示例</p>
<p>{{code}}</p>
<ul> <ul>
<li>独立路由/h5</li> <li>独立路由/h5</li>
<li>演示子页面/h5/demo</li> <li>演示子页面/h5/demo</li>
{{ logStr }} {{ logStr }}
<li>请求数据{{JSON.stringify(resDat)}}</li>
<li>登录数据{{res}}</li>
</ul> </ul>
<div id="ww_login" class="w-[200px] h-[200px] border"></div>
<el-button type="primary" size="large"><router-link to="/h5/demo">前往 H5 Demo</router-link></el-button> <el-button type="primary" size="large"><router-link to="/h5/demo">前往 H5 Demo</router-link></el-button>
</div> </div>
</main> </main>
<!-- 桌面提示仅在较宽屏幕下显示 --> <!-- 桌面提示仅在较宽屏幕下显示 -->
<div class="desktop-warning">请用手机或缩小浏览器窗口预览移动端效果</div> <div class="desktop-warning">请用手机或缩小浏览器窗口预览移动端效果</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import {loginWx} from "/@/api/h5/expert";
// import * as ww from '@wecom/jssdk' // import * as ww from '@wecom/jssdk'
const route = useRoute()
const logStr = ref('') const logStr = ref('')
const code = ref('')
const res = ref('')
const resDat = ref<any>({})
onMounted(() => { onMounted(() => {
// alert(ww.SDK_VERSION) // alert(ww.SDK_VERSION)
// 初始化登录组件 // 初始化登录组件
@@ -62,6 +69,19 @@ onMounted(() => {
// } catch (e) { // } catch (e) {
// logStr.value = JSON.stringify(e) // logStr.value = JSON.stringify(e)
// } // }
console.log('code',window.location)
code.value = <string>route.query.code
if (code.value){
resDat.value = {
code:code.value,
grant_type: 'wechat_work',
}
loginWx(code.value).then(res => {
res.value = res
}).catch(err => {
res.value = err
})
}
}) })
</script> </script>

View File

@@ -59,16 +59,17 @@ const handleSubmit = async () => {
return; return;
} }
const submitFormData = await formDataRef.value.validateRefFn(); const submitFormData:PostInvestmentEvaluation|boolean = await formDataRef.value.validateRefFn();
// 提交表单数据 // 提交表单数据
if (submitFormData) { if (submitFormData) {
submitFormData.attachmentUrl = JSON.stringify(submitFormData.attachmentUrl); submitFormData.attachmentUrl = JSON.stringify(submitFormData.attachmentUrl);
submitFormData.deptId = formData.value.deptId;
await addInvestmentEvaluation(submitFormData as PostInvestmentEvaluation); await addInvestmentEvaluation(submitFormData as PostInvestmentEvaluation);
message.success(t('common.success')); message.success(t('成功'));
router.back(); router.back();
} }
} catch (error: any) { } catch (error: any) {
message.error(error.msg || 'Submission failed'); message.error(error.msg || '失败');
} }
}; };

View File

@@ -513,6 +513,9 @@ const createEmptyDetail = (): ProjectPlanApplyFormData => ({
submitUnitLeadershipOpinion: '', submitUnitLeadershipOpinion: '',
submitUnitMainLeadershipOpinion: '', submitUnitMainLeadershipOpinion: '',
planImageQuota:'', planImageQuota:'',
deptId:0,
status:0,
processInstanceId:'',
}, },
investmentProjects: [ investmentProjects: [
{ {

View File

@@ -40,6 +40,8 @@ export interface PostInvestmentEvaluation {
/** 创建时间 */ /** 创建时间 */
createTime?: string; // date-time createTime?: string; // date-time
/**部门id*/
deptId?: string; // integer(int64)
} }
/** /**
@@ -225,6 +227,8 @@ export interface ProjectInvestmentInfo {
/** 投资项目进度实体列表 */ /** 投资项目进度实体列表 */
investmentProjectsProgressEntities?: InvestmentProjectProgress[]; investmentProjectsProgressEntities?: InvestmentProjectProgress[];
/**部门id*/
deptId?: string; // integer(int64)
} }
export interface requestData { export interface requestData {
page: number, page: number,

View File

@@ -76,12 +76,12 @@
</el-col> </el-col>
<el-col :span="20"> <el-col :span="20">
<el-form-item> <el-form-item>
<el-input v-model="formData.projectName" :placeholder="t('committeeReview.form.selectPlaceholder')" readonly> <el-input v-model="formData.projectName" :placeholder="t('committeeReview.form.inputPlaceholder')">
<template #append> <!-- <template #append>-->
<el-icon class="cursor-pointer interactive-icon" @click="handleSelect"> <!-- <el-icon class="cursor-pointer interactive-icon" @click="handleSelect">-->
<FolderOpened /> <!-- <FolderOpened />-->
</el-icon> <!-- </el-icon>-->
</template> <!-- </template>-->
</el-input> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -177,10 +177,10 @@
@select="handleProjectSelect" @select="handleProjectSelect"
/> />
<LibrarySelect <!-- <LibrarySelect-->
v-model="librarySelectVisible" <!-- v-model="librarySelectVisible"-->
@select="handleLibrarySelect" <!-- @select="handleLibrarySelect"-->
/> <!-- />-->
<templet-table-comom/> <templet-table-comom/>
</div> </div>
</template> </template>
@@ -356,6 +356,8 @@ watch(()=>tmpId.value,async ()=>{
const saveTemplateLoading = ref<boolean>(false); const saveTemplateLoading = ref<boolean>(false);
// 处理保存模板事件 // 处理保存模板事件
const handleSaveTemplate = async () => { const handleSaveTemplate = async () => {
const valid = await headerFormRef.value?.validate();
if (!valid) return;
if (saveTemplateLoading.value) return; if (saveTemplateLoading.value) return;
try { try {
const isUpdate = props.isUpdate; const isUpdate = props.isUpdate;

View File

@@ -10,10 +10,10 @@
<el-button icon="Document" @click="handleSaveDraft" :loading="saveLoading"> <el-button icon="Document" @click="handleSaveDraft" :loading="saveLoading">
{{ t('planApply.actions.saveDraft') }} {{ t('planApply.actions.saveDraft') }}
</el-button> </el-button>
<el-button icon="FolderOpened" @click="handleLoadTemplate"> <el-button icon="FolderOpened" @click="handleLoadTemplate" :loading="folderLoading">
{{ t('planApply.actions.loadTemplate') }} {{ t('planApply.actions.loadTemplate') }}
</el-button> </el-button>
<el-button icon="FolderAdd" @click="handleSaveTemplate"> <el-button icon="FolderAdd" @click="handleSaveTemplate" :loading="saveTemplateLoading">
{{ t('planApply.actions.saveTemplate') }} {{ t('planApply.actions.saveTemplate') }}
</el-button> </el-button>
</div> </div>
@@ -46,15 +46,17 @@
<ProjectPlanApplyForm v-model="formData" :rules="formDataRules" ref="formDataRef" <ProjectPlanApplyForm v-model="formData" :rules="formDataRules" ref="formDataRef"
:is-update="props.isUpdate" /> :is-update="props.isUpdate" />
<templateTable/>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue'; import {computed, reactive, ref, watch} from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useMessage } from '/@/hooks/message'; import { useMessage } from '/@/hooks/message';
import { import {
getInvestmentProjectsPlanByTemplateId,
investmentProjectsPlanAdd, investmentProjectsPlanGetById, investmentProjectsPlanAdd, investmentProjectsPlanGetById,
investmentProjectsPlanUserDeptBelong investmentProjectsPlanUserDeptBelong
} from '/@/api/investment/investmentManagement'; } from '/@/api/investment/investmentManagement';
@@ -62,11 +64,16 @@ import ProjectPlanApplyForm from '/@/components/investment/common/ProjectPlanApp
import type { ProjectPlanApplyFormData } from '/@/components/investment/interface/types'; import type { ProjectPlanApplyFormData } from '/@/components/investment/interface/types';
import type { FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
import UploadFile from '/@/components/Upload/index.vue'; import UploadFile from '/@/components/Upload/index.vue';
import { useRoute } from 'vue-router'; import { useRoute,useRouter } from 'vue-router';
import { flowFn } from "/@/utils/flowFn"; import { flowFn } from "/@/utils/flowFn";
import { addFlowForm } from "/@/api/flow/flow"; import { addFlowForm } from "/@/api/flow/flow";
import { flowNameOptions } from "/@/hooks/enums"; import { flowNameOptions } from "/@/hooks/enums";
import templateTable from "/@/components/templetTableComom/index.vue";
import {templateStore} from "/@/stores/template"
import {getPropertyRightsByIdAPI} from "/@/api/workbench/miOwLibr/ownershipCreate";
import {addTemplate} from "/@/api/common";
const temp = templateStore();
const tempId = computed(()=>temp.temp_id)
const props = defineProps({ const props = defineProps({
isUpdate: { isUpdate: {
type: Boolean, type: Boolean,
@@ -76,6 +83,7 @@ const props = defineProps({
const { t } = useI18n(); const { t } = useI18n();
const message = useMessage(); const message = useMessage();
const route = useRoute(); const route = useRoute();
const router = useRouter();
const submitLoading = ref(false); const submitLoading = ref(false);
const headerForm = reactive<{ title: string, description: string, attachments: any[] | string }>({ const headerForm = reactive<{ title: string, description: string, attachments: any[] | string }>({
title: '', title: '',
@@ -292,13 +300,14 @@ const handleInitiateApproval = async () => {
entity: { entity: {
...formData.value.entity, ...formData.value.entity,
attachments: formData.value.entity.attachments ? JSON.stringify(formData.value.entity.attachments) : '', attachments: formData.value.entity.attachments ? JSON.stringify(formData.value.entity.attachments) : '',
projectPreliminaryPlanAttachment: formData.value.entity.projectPreliminaryPlanAttachment ? JSON.stringify(formData.value.entity.projectPreliminaryPlanAttachment) : '' projectPreliminaryPlanAttachment: formData.value.entity.projectPreliminaryPlanAttachment
} }
} }
investmentProjectsPlanAdd(params) investmentProjectsPlanAdd(params)
.then(() => { .then(() => {
submitLoading.value = false; submitLoading.value = false;
message.success(t('planApply.messages.initiateApproval')); message.success(t('planApply.messages.initiateApproval'));
router.push('/flow/task/started')
}) })
.catch((err: any) => { .catch((err: any) => {
submitLoading.value = false; submitLoading.value = false;
@@ -322,14 +331,14 @@ const handleSaveDraft = async () => {
const flowName = props.isUpdate ? 'investmentPlanUpdates' : 'investmentPlanRegistration'; const flowName = props.isUpdate ? 'investmentPlanUpdates' : 'investmentPlanRegistration';
const flowNameObj = flowNameOptions.filter(item => item.label === flowName)[0] const flowNameObj = flowNameOptions.filter(item => item.label === flowName)[0]
formData.value.entity.projectPreliminaryPlanAttachment = JSON.stringify(formData.value.entity.projectPreliminaryPlanAttachment); formData.value.entity.projectPreliminaryPlanAttachment = JSON.stringify(formData.value.entity.projectPreliminaryPlanAttachment);
formData.value.entity.status = 1 formData.value.entity.status = 0
Object.assign(formData.value.entity, { flowType: flowNameObj.value }) Object.assign(formData.value.entity, { flowType: flowNameObj.value })
const params = { const params = {
...formData.value, ...formData.value,
entity: { entity: {
...formData.value.entity, ...formData.value.entity,
attachments: formData.value.entity.attachments ? JSON.stringify(formData.value.entity.attachments) : '', attachments: formData.value.entity.attachments ? JSON.stringify(formData.value.entity.attachments) : '',
projectPreliminaryPlanAttachment: formData.value.entity.projectPreliminaryPlanAttachment ? JSON.stringify(formData.value.entity.projectPreliminaryPlanAttachment) : '' projectPreliminaryPlanAttachment: formData.value.entity.projectPreliminaryPlanAttachment
}, },
temporaryStorage: { temporaryStorage: {
title: headerForm.title, title: headerForm.title,
@@ -349,13 +358,56 @@ const handleSaveDraft = async () => {
console.log(error, 'error'); console.log(error, 'error');
} }
}; };
const folderLoading = ref(false);
watch(()=>tempId.value,()=>{
getInvestmentProjectsPlanByTemplateId(tempId.value).then(data => {
Object.assign(formData, data.data);
})
})
const handleLoadTemplate = () => { const handleLoadTemplate = () => {
message.info(t('planApply.messages.loadTemplate')); const flowName = props.isUpdate ? 'investmentPlanUpdates' : 'investmentPlanRegistration';
const flowNameObj = flowNameOptions.filter(item => item.label === flowName)[0]
temp.changeTempShow(true,flowNameObj.value)
}; };
const saveTemplateLoading = ref(false);
const handleSaveTemplate = async () => {
// addTemplate()
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) return;
const handleSaveTemplate = () => { const valid = await formDataRef.value?.validateForm().catch(() => false);
message.info(t('planApply.messages.saveTemplate')); if (!valid) return;
saveTemplateLoading.value = true;
try {
const flowName = props.isUpdate ? 'investmentPlanUpdates' : 'investmentPlanRegistration';
const flowNameObj = flowNameOptions.filter(item => item.label === flowName)[0]
const templateId = await addTemplate({templateName:headerForm.title,
templateType:flowNameObj.value,})
formData.value.entity.projectPreliminaryPlanAttachment = JSON.stringify(formData.value.entity.projectPreliminaryPlanAttachment);
formData.value.entity.status = 0
Object.assign(formData.value.entity, { flowType: flowNameObj.value,templateId })
const params = {
...formData.value,
entity: {
...formData.value.entity,
attachments: formData.value.entity.attachments ? JSON.stringify(formData.value.entity.attachments) : '',
projectPreliminaryPlanAttachment: formData.value.entity.projectPreliminaryPlanAttachment
},
}
investmentProjectsPlanAdd(params)
.then(() => {
saveLoading.value = false;
message.success('保存代发成功');
})
.catch((err: any) => {
saveLoading.value = false;
message.error(err.msg);
});
}catch (error) {
console.log(error, 'error');
}finally {
saveTemplateLoading.value = false;
}
}; };
const handleViewWorkflow = () => { const handleViewWorkflow = () => {

View File

@@ -7,10 +7,10 @@
<el-button type="primary" icon="Check" :loading="submitLoading" @click="handleInitiateApproval"> <el-button type="primary" icon="Check" :loading="submitLoading" @click="handleInitiateApproval">
{{ t('progressReport.actions.initiateApproval') }} {{ t('progressReport.actions.initiateApproval') }}
</el-button> </el-button>
<el-button icon="Document" @click="handleSaveDraft"> <el-button icon="Document" @click="handleSaveDraft" :loading="saveLoading">
{{ t('progressReport.actions.saveDraft') }} {{ t('progressReport.actions.saveDraft') }}
</el-button> </el-button>
<el-button icon="FolderOpened" @click="handleLoadTemplate"> <el-button icon="FolderOpened" @click="handleLoadTemplate" :loading="templateLoading">
{{ t('progressReport.actions.loadTemplate') }} {{ t('progressReport.actions.loadTemplate') }}
</el-button> </el-button>
<el-button icon="FolderAdd" @click="handleSaveTemplate"> <el-button icon="FolderAdd" @click="handleSaveTemplate">
@@ -45,26 +45,34 @@
</el-row> </el-row>
<ProjectProgressReportForm v-model="formData" :rules="formDataRef" ref="formRef" /> <ProjectProgressReportForm v-model="formData" :rules="formDataRef" ref="formRef" />
<templateTable/>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue'; import templateTable from "/@/components/templetTableComom/index.vue"
import {computed, reactive, ref, watch} from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useMessage } from '/@/hooks/message'; import { useMessage } from '/@/hooks/message';
import ProjectProgressReportForm from '/@/components/investment/common/ProjectProgressReportForm.vue'; import ProjectProgressReportForm from '/@/components/investment/common/ProjectProgressReportForm.vue';
import { InvestmentProjectProgress } from '/@/views/invMid/progressReport/interface/type'; import { InvestmentProjectProgress } from '/@/views/invMid/progressReport/interface/type';
import { FormRules } from 'element-plus'; import { FormRules } from 'element-plus';
import { import {
addInvestmentProjectsProgressAPI, addInvestmentProjectsProgressAPI, getInvestmentProjectsProgressByTemplateIdAPI,
getInvestmentProjectsProgressUserDeptBelongAPI getInvestmentProjectsProgressUserDeptBelongAPI
} from '/@/api/investment/progressOfInvestmentProjects'; } from '/@/api/investment/progressOfInvestmentProjects';
import UploadFile from "/@/components/Upload/index.vue"; import UploadFile from "/@/components/Upload/index.vue";
import { flowFn } from "/@/utils/flowFn"; import { flowFn } from "/@/utils/flowFn";
import { addFlowForm } from "/@/api/flow/flow"; import { addFlowForm } from "/@/api/flow/flow";
import { flowNameOptions } from "/@/hooks/enums"; import { flowNameOptions } from "/@/hooks/enums";
import {templateStore} from "/@/stores/template"
import {useRouter} from "vue-router";
import {addTemplate} from "/@/api/common";
import {getPropertyRightsByIdAPI} from "/@/api/workbench/miOwLibr/ownershipCreate";
const router = useRouter();
const temp = templateStore();
const { t } = useI18n(); const { t } = useI18n();
const message = useMessage(); const message = useMessage();
@@ -171,6 +179,7 @@ const handleInitiateApproval = async () => {
valid.processInstanceId = processInstanceId; valid.processInstanceId = processInstanceId;
valid.supportingDocuments = JSON.stringify(valid.supportingDocuments); valid.supportingDocuments = JSON.stringify(valid.supportingDocuments);
valid.status = 1; valid.status = 1;
valid.flowType = flowNameObj.value
await addInvestmentProjectsProgressAPI(valid).then(() => { await addInvestmentProjectsProgressAPI(valid).then(() => {
message.success(t('common.success')); message.success(t('common.success'));
}).finally(() => { }).finally(() => {
@@ -183,17 +192,94 @@ const handleInitiateApproval = async () => {
submitLoading.value = false; submitLoading.value = false;
} }
}; };
const saveLoading = ref(false)
const handleSaveDraft = () => { const handleSaveDraft = async () => {
message.info(t('progressReport.messages.saveDraft')); try {
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) {
return;
}
const valid = await formRef.value?.validate();
submitLoading.value = true;
headerForm.attachments = JSON.stringify(headerForm.attachments);
const processInstanceId = '';
const flowNameObj = flowNameOptions.filter(item => item.label === 'projectProgressDeclaration')[0]
await addFlowForm({
title: headerForm.title,
description: headerForm.description,
attachments: headerForm.attachments,
processInstanceId,
flowType: flowNameObj.value
})
valid.processInstanceId = processInstanceId;
valid.supportingDocuments = JSON.stringify(valid.supportingDocuments);
valid.status = 0;
valid.flowType = flowNameObj.value
valid.temporaryStorage={
businessType:flowNameObj.value,
title: headerForm.title,
}
await addInvestmentProjectsProgressAPI(valid).then(() => {
message.success(t('common.success'));
}).finally(() => {
saveLoading.value = false;
}).catch((err: any) => {
saveLoading.value = false;
message.error(err.msg);
});
} catch (error) {
saveLoading.value = false;
}
}; };
const templateLoading = ref(false)
const handleLoadTemplate = () => { const tempId = computed(()=>temp.temp_id)
message.info(t('progressReport.messages.loadTemplate')); const handleLoadTemplate = async () => {
const flowNameObj = flowNameOptions.filter(item => item.label === 'projectProgressDeclaration')[0]
temp.changeTempShow(true,flowNameObj.value)
}; };
watch(()=>tempId.value,()=>{
const handleSaveTemplate = () => { getInvestmentProjectsProgressByTemplateIdAPI(tempId.value).then(data => {
message.info(t('progressReport.messages.saveTemplate')); Object.assign(formData, data.data);
})
})
const handleSaveTemplate = () => async () => {
try {
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) {
return;
}
const valid = await formRef.value?.validate();
templateLoading.value = true;
headerForm.attachments = JSON.stringify(headerForm.attachments);
const processInstanceId = '';
const flowNameObj = flowNameOptions.filter(item => item.label === 'projectProgressDeclaration')[0]
await addFlowForm({
title: headerForm.title,
description: headerForm.description,
attachments: headerForm.attachments,
processInstanceId,
flowType: flowNameObj.value
})
const {data: templateId} = await addTemplate({
templateName:headerForm.title,
templateType:flowNameObj.value,
})
valid.processInstanceId = processInstanceId;
valid.supportingDocuments = JSON.stringify(valid.supportingDocuments);
valid.status = 0;
valid.flowType = flowNameObj.value
valid.templateId = templateId
await addInvestmentProjectsProgressAPI(valid).then(() => {
message.success(t('common.success'));
}).finally(() => {
templateLoading.value = false;
}).catch((err: any) => {
templateLoading.value = false;
message.error(err.msg);
});
} catch (error) {
templateLoading.value = false;
}
}; };
const handleViewWorkflow = () => { const handleViewWorkflow = () => {

View File

@@ -7,13 +7,13 @@
<el-button type="primary" icon="Check" @click="handleInitiateApproval" :loading="submitLoading"> <el-button type="primary" icon="Check" @click="handleInitiateApproval" :loading="submitLoading">
{{ t('projectExitFeedback.actions.initiateApproval') }} {{ t('projectExitFeedback.actions.initiateApproval') }}
</el-button> </el-button>
<el-button icon="Document" @click="handleSaveDraft"> <el-button icon="Document" @click="handleSaveDraft" :loading="saveLoading">
{{ t('projectExitFeedback.actions.saveDraft') }} {{ t('projectExitFeedback.actions.saveDraft') }}
</el-button> </el-button>
<el-button icon="FolderOpened" @click="handleLoadTemplate"> <el-button icon="FolderOpened" @click="handleLoadTemplate">
{{ t('projectExitFeedback.actions.loadTemplate') }} {{ t('projectExitFeedback.actions.loadTemplate') }}
</el-button> </el-button>
<el-button icon="FolderAdd" @click="handleSaveTemplate"> <el-button icon="FolderAdd" @click="handleSaveTemplate" :loading="saveTemplateLoading">
{{ t('projectExitFeedback.actions.saveTemplate') }} {{ t('projectExitFeedback.actions.saveTemplate') }}
</el-button> </el-button>
</div> </div>
@@ -44,25 +44,33 @@
</el-row> </el-row>
<ProjectExitFeedbackForm v-model="formData" /> <ProjectExitFeedbackForm v-model="formData" />
<templateTable/>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue'; import {computed, reactive, ref, watch} from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useMessage } from '/@/hooks/message'; import { useMessage } from '/@/hooks/message';
import ProjectExitFeedbackForm from '/@/components/investment/common/ProjectExitFeedbackForm.vue'; import ProjectExitFeedbackForm from '/@/components/investment/common/ProjectExitFeedbackForm.vue';
import { ProjectExitFeedback } from '/@/views/invMid/projectExitFeedback/interface/type'; import { ProjectExitFeedback } from '/@/views/invMid/projectExitFeedback/interface/type';
import { addProjectExitPlanFeedback } from "/@/api/investment/projectExitPlan"; import {addProjectExitPlanFeedback, getProjectExitPlanFeedbackByTemplateId} from "/@/api/investment/projectExitPlan";
import { ProjectTask } from "/@/views/invMid/projectExitPlan/interface/type"; import { ProjectTask } from "/@/views/invMid/projectExitPlan/interface/type";
import UploadFile from "/@/components/Upload/index.vue"; import UploadFile from "/@/components/Upload/index.vue";
import { flowFn } from "/@/utils/flowFn"; import { flowFn } from "/@/utils/flowFn";
import { addFlowForm } from "/@/api/flow/flow"; import { addFlowForm } from "/@/api/flow/flow";
import { flowNameOptions } from "/@/hooks/enums"; import { flowNameOptions } from "/@/hooks/enums";
import templateTable from "/@/components/templetTableComom/index.vue"
const { t } = useI18n(); const { t } = useI18n();
const message = useMessage(); const message = useMessage();
import {templateStore} from "/@/stores/template"
import {useRouter} from "vue-router";
import {getPropertyRightsByIdAPI} from "/@/api/workbench/miOwLibr/ownershipCreate";
import {addTemplate} from "/@/api/common";
const temp = templateStore()
const router = useRouter()
const headerFormRef = ref<any>(); const headerFormRef = ref<any>();
const headerFormRules = { const headerFormRules = {
title: [{ required: true, message: '标题必填', trigger: ['blur', 'change'] }] title: [{ required: true, message: '标题必填', trigger: ['blur', 'change'] }]
@@ -127,17 +135,84 @@ const handleInitiateApproval = async () => {
submitLoading.value = false; submitLoading.value = false;
}); });
}; };
const saveLoading = ref(false);
const handleSaveDraft = () => { const flowNameObj = flowNameOptions.filter(item => item.label === 'exitFeedback')[0]
message.info(t('projectExitFeedback.messages.saveDraft')); const handleSaveDraft = async () => {
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) {
return;
}
if (!formData.value.projectId) {
message.error('项目名称必填');
return
}
saveLoading.value = true;
const attachments = JSON.stringify(headerForm.attachments);
const { processInstanceId } = { processInstanceId: ''};
await addFlowForm({
title: headerForm.title,
description: headerForm.description,
attachments,
processInstanceId,
flowType: flowNameObj.value
})
formData.value.processInstanceId = processInstanceId;
const exitAttachment = JSON.stringify(formData.value.exitAttachment);
const params = { ...formData.value, exitAttachment,temporaryStorage:{
businessType:flowNameObj.value,
title: headerForm.title,
} } as ProjectTask;
addProjectExitPlanFeedback(params).then(() => {
message.success(t('common.success'));
}).catch((err: any) => {
message.error(err.msg);
}).finally(() => {
saveLoading.value = false;
});
}; };
const tempId = computed(()=>temp.temp_id)
const handleLoadTemplate = () => { const handleLoadTemplate = () => {
message.info(t('projectExitFeedback.messages.loadTemplate')); temp.changeTempShow(true,flowNameObj.value)
}; };
watch(()=>tempId.value,()=>{
const handleSaveTemplate = () => { getProjectExitPlanFeedbackByTemplateId(tempId.value).then(data => {
message.info(t('projectExitFeedback.messages.saveTemplate')); Object.assign(formData, data.data);
})
})
const saveTemplateLoading = ref(false);
const handleSaveTemplate = async() => {
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) {
return;
}
if (!formData.value.projectId) {
message.error('项目名称必填');
return
}
saveTemplateLoading.value = true;
const attachments = JSON.stringify(headerForm.attachments);
const { processInstanceId } = { processInstanceId: ''};
await addFlowForm({
title: headerForm.title,
description: headerForm.description,
attachments,
processInstanceId,
flowType: flowNameObj.value
})
const {data: templateId} = await addTemplate({
templateName:headerForm.title,
templateType:flowNameObj.value,
})
formData.value.processInstanceId = processInstanceId;
const exitAttachment = JSON.stringify(formData.value.exitAttachment);
const params = { ...formData.value, exitAttachment,templateId} as ProjectTask;
addProjectExitPlanFeedback(params).then(() => {
message.success(t('common.success'));
}).catch((err: any) => {
message.error(err.msg);
}).finally(() => {
saveTemplateLoading.value = false;
});
}; };
const handleViewWorkflow = () => { const handleViewWorkflow = () => {

View File

@@ -7,13 +7,13 @@
<el-button type="primary" icon="Check" :loading="submitLoading" @click="handleInitiateApproval"> <el-button type="primary" icon="Check" :loading="submitLoading" @click="handleInitiateApproval">
{{ t('projectExitPlan.actions.initiateApproval') }} {{ t('projectExitPlan.actions.initiateApproval') }}
</el-button> </el-button>
<el-button icon="Document" @click="handleSaveDraft"> <el-button icon="Document" @click="handleSaveDraft" :loading="saveLoading">
{{ t('projectExitPlan.actions.saveDraft') }} {{ t('projectExitPlan.actions.saveDraft') }}
</el-button> </el-button>
<el-button icon="FolderOpened" @click="handleLoadTemplate"> <el-button icon="FolderOpened" @click="handleLoadTemplate">
{{ t('projectExitPlan.actions.loadTemplate') }} {{ t('projectExitPlan.actions.loadTemplate') }}
</el-button> </el-button>
<el-button icon="FolderAdd" @click="handleSaveTemplate"> <el-button icon="FolderAdd" @click="handleSaveTemplate" :loading="saveTemplateLoading">
{{ t('projectExitPlan.actions.saveTemplate') }} {{ t('projectExitPlan.actions.saveTemplate') }}
</el-button> </el-button>
</div> </div>
@@ -45,26 +45,35 @@
<ProjectExitPlanForm v-model="formData" :rules="rules" ref="formDataRef" /> <ProjectExitPlanForm v-model="formData" :rules="rules" ref="formDataRef" />
</div> </div>
<templateTable/>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue'; import {computed, reactive, ref, watch} from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useMessage } from '/@/hooks/message'; import { useMessage } from '/@/hooks/message';
import type { ProjectTask } from '/@/views/invMid/projectExitPlan/interface/type'; import type { ProjectTask } from '/@/views/invMid/projectExitPlan/interface/type';
import ProjectExitPlanForm from '/@/components/investment/common/ProjectExitPlanForm.vue'; import ProjectExitPlanForm from '/@/components/investment/common/ProjectExitPlanForm.vue';
import { FormRules } from 'element-plus'; import { FormRules } from 'element-plus';
import { addProjectExitPlan } from '/@/api/investment/projectExitPlan'; import {addProjectExitPlan, getProjectExitPlanByTemplateId} from '/@/api/investment/projectExitPlan';
import UploadFile from "/@/components/Upload/index.vue"; import UploadFile from "/@/components/Upload/index.vue";
import { flowFn } from "/@/utils/flowFn"; import { flowFn } from "/@/utils/flowFn";
import { addFlowForm } from "/@/api/flow/flow"; import { addFlowForm } from "/@/api/flow/flow";
import { flowNameOptions } from "/@/hooks/enums"; import { flowNameOptions } from "/@/hooks/enums";
import {addTemplate} from "/@/api/common";
import {getPropertyRightsByIdAPI} from "/@/api/workbench/miOwLibr/ownershipCreate";
const formDataRef = ref<HTMLFormElement | null>() const formDataRef = ref<HTMLFormElement | null>()
import templateTable from "/@/components/templetTableComom/index.vue"
import {templateStore} from "/@/stores/template"
import {useRouter} from "vue-router";
const { t } = useI18n(); const { t } = useI18n();
const message = useMessage(); const message = useMessage();
const temp = templateStore()
const router = useRouter()
const headerFormRef = ref<any>(); const headerFormRef = ref<any>();
const headerFormRules = { const headerFormRules = {
title: [{ required: true, message: '标题必填', trigger: ['blur', 'change'] }] title: [{ required: true, message: '标题必填', trigger: ['blur', 'change'] }]
@@ -131,6 +140,7 @@ const handleInitiateApproval = async () => {
formData.value.processInstanceId = processInstanceId; formData.value.processInstanceId = processInstanceId;
addProjectExitPlan(formData.value).then((res: any) => { addProjectExitPlan(formData.value).then((res: any) => {
useMessage().success(t('common.success')); useMessage().success(t('common.success'));
router.push('/flow/task/started')
}).catch((err: any) => { }).catch((err: any) => {
useMessage().error(err.msg); useMessage().error(err.msg);
}).finally(() => { }).finally(() => {
@@ -142,17 +152,90 @@ const handleInitiateApproval = async () => {
} }
}; };
const saveLoading = ref<boolean>(false);
const handleSaveDraft = async () => {
try {
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) {
return;
}
const valid = await formDataRef?.value?.validateRef();
if (!valid) return;
saveLoading.value = true;
const attachments = JSON.stringify(headerForm.attachments);
const flowNameObj = flowNameOptions.filter(item => item.label === 'exitPlan')[0]
await addFlowForm({
title: headerForm.title,
description: headerForm.description,
attachments,
processInstanceId:'',
flowType: flowNameObj.value
})
formData.value.processInstanceId = '';
Object.assign(formData.value,{status:0,temporaryStorage:{
businessType:flowNameObj.value,
title: headerForm.title,
}})
addProjectExitPlan(formData.value).then(() => {
useMessage().success(t('common.success'));
}).catch((err: any) => {
useMessage().error(err.msg);
}).finally(() => {
saveLoading.value = false;
});
} catch (e) {
console.log(e);
saveLoading.value = false;
}
const handleSaveDraft = () => {
message.info(t('projectExitPlan.messages.saveDraft'));
}; };
const tempId = computed(()=>temp.temp_id)
watch(()=>tempId.value,()=>{
getProjectExitPlanByTemplateId(tempId.value).then(data => {
Object.assign(formData, data.data);
})
})
const handleLoadTemplate = () => { const handleLoadTemplate = () => {
message.info(t('projectExitPlan.messages.loadTemplate')); const flowNameObj = flowNameOptions.filter(item => item.label === 'exitPlan')[0]
temp.changeTempShow(true,flowNameObj.value)
}; };
const saveTemplateLoading = ref<boolean>(false);
const handleSaveTemplate = async () => {
try {
const headerValid = await headerFormRef.value?.validate().catch(() => false);
if (!headerValid) {
return;
}
const valid = await formDataRef?.value?.validateRef();
if (!valid) return;
saveTemplateLoading.value = true;
const attachments = JSON.stringify(headerForm.attachments);
const flowNameObj = flowNameOptions.filter(item => item.label === 'exitPlan')[0]
await addFlowForm({
title: headerForm.title,
description: headerForm.description,
attachments,
processInstanceId:'',
flowType: flowNameObj.value
})
const {data: templateId} = await addTemplate({
templateName:headerForm.title,
templateType:flowNameObj.value,
})
formData.value.processInstanceId = '';
Object.assign(formData.value,{status:0,templateId})
addProjectExitPlan(formData.value).then(() => {
useMessage().success(t('common.success'));
}).catch((err: any) => {
useMessage().error(err.msg);
}).finally(() => {
saveTemplateLoading.value = false;
});
} catch (e) {
console.log(e);
saveTemplateLoading.value = false;
}
const handleSaveTemplate = () => {
message.info(t('projectExitPlan.messages.saveTemplate'));
}; };
const handleViewWorkflow = () => { const handleViewWorkflow = () => {

View File

@@ -293,7 +293,7 @@ import {
} from '/@/api/investment/cooperationUnit'; } from '/@/api/investment/cooperationUnit';
import UnitNameSelectDialog from '/@/components/investment/UnitNameSelectDialog.vue'; import UnitNameSelectDialog from '/@/components/investment/UnitNameSelectDialog.vue';
import SelectCompanyDialog from '/@/components/investment/SelectCompanyDialog.vue'; import SelectCompanyDialog from '/@/components/investment/SelectCompanyDialog.vue';
import {useMessage,} from '/@/hooks/message'; import {useRouter} from 'vue-router';
import {useI18n} from 'vue-i18n'; import {useI18n} from 'vue-i18n';
import {useUserInfo} from '/@/stores/userInfo'; import {useUserInfo} from '/@/stores/userInfo';
import {formatDate} from '/@/utils/formatTime'; import {formatDate} from '/@/utils/formatTime';
@@ -305,6 +305,9 @@ import {getExternalCooperationUnitsUserDeptBelong,addTemplate} from "/@/api/comm
import {templateStore} from "/@/stores/template"; import {templateStore} from "/@/stores/template";
import type {FormInstance, FormRules} from "element-plus"; import type {FormInstance, FormRules} from "element-plus";
import { selectTreeCompanyTree} from "/@/api/admin/dept"; import { selectTreeCompanyTree} from "/@/api/admin/dept";
const router = useRouter();
const temp = templateStore(); const temp = templateStore();
const props = defineProps({ const props = defineProps({
isUpdate: { isUpdate: {
@@ -442,6 +445,7 @@ const handleInitiateApproval = async () => {
}; };
await addExternalCooperationUnitAPI(payload); await addExternalCooperationUnitAPI(payload);
useMessage().success('成功'); useMessage().success('成功');
await router.push('/flow/task/started')
} catch (error: any) { } catch (error: any) {
useMessage().error(error?.msg || error?.message || '操作失败'); useMessage().error(error?.msg || error?.message || '操作失败');
} finally { } finally {
@@ -774,7 +778,7 @@ onMounted(() => {
const projectMainEntityOptions = ref([]); const projectMainEntityOptions = ref([]);
const getDeptTree = async () => { const getDeptTree = async () => {
const res = await selectTreeCompanyTree(); const res = await selectTreeCompanyTree();
projectMainEntityOptions.value = res.data || []; projectMainEntityOptions.value = res.data?.filter((item:any) => item.id !== '-7283586818552608318');
}; };
getDeptTree() getDeptTree()
watch(editId, (id) => { watch(editId, (id) => {

View File

@@ -150,12 +150,12 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="isUpdate" prop="expertStatus" min-width="120" :label="t('expertApply.table.expertStatus')"> <el-table-column v-if="isUpdate" prop="externalStatus" min-width="120" :label="t('expertApply.table.externalStatus')">
<template #default="scope"> <template #default="scope">
<el-select v-model="scope.row.expertStatus" :placeholder="t('expertApply.table.selectPlaceholder')" <el-select v-model="scope.row.externalStatus" :placeholder="t('expertApply.table.selectPlaceholder')"
style="width: 100%;"> style="width: 100%;">
<el-option :label="t('expertApply.expertStatusOptions.normal')" value="normal" /> <el-option :label="t('expertApply.externalStatusOptions.normal')" value="normal" />
<el-option :label="t('expertApply.expertStatusOptions.invalid')" value="invalid" /> <el-option :label="t('expertApply.externalStatusOptions.invalid')" value="invalid" />
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
@@ -164,7 +164,7 @@
<SelectExpertDialog v-model:visible="expertDialogVisible" @confirm="onExpertSelected" /> <SelectExpertDialog v-model:visible="expertDialogVisible" @confirm="onExpertSelected" />
<!-- <UserSelect v-model:visible="userSelectVisible" @ok="handleUserSelectOk" /> --> <!-- <UserSelect v-model:visible="userSelectVisible" @ok="handleUserSelectOk" /> -->
<template-table-common /> <template-table-common />
<templateTable/>
</div> </div>
</div> </div>
</template> </template>
@@ -175,6 +175,7 @@ import { useI18n } from 'vue-i18n';
import { formatDate } from '/@/utils/formatTime'; import { formatDate } from '/@/utils/formatTime';
import { useUserInfo } from '/@/stores/userInfo'; import { useUserInfo } from '/@/stores/userInfo';
import { useMessage } from '/@/hooks/message'; import { useMessage } from '/@/hooks/message';
import templateTable from "/@/components/templetTableComom/index.vue";
import SelectExpertDialog from '/@/components/investment/SelectExpertDialog.vue'; import SelectExpertDialog from '/@/components/investment/SelectExpertDialog.vue';
import {addExpertInformationAPI, getExpertInformationByTemplateIdAPI} from '/@/api/investment/cooperationUnit'; import {addExpertInformationAPI, getExpertInformationByTemplateIdAPI} from '/@/api/investment/cooperationUnit';
import {flowFn} from "/@/utils/flowFn"; import {flowFn} from "/@/utils/flowFn";
@@ -182,6 +183,7 @@ import { addFlowForm } from '/@/api/flow/flow';
import {flowNameOptions, level} from '/@/hooks/enums'; import {flowNameOptions, level} from '/@/hooks/enums';
import {FormInstance} from "element-plus"; import {FormInstance} from "element-plus";
import {addTemplate} from "/@/api/common"; import {addTemplate} from "/@/api/common";
import {useRouter} from "vue-router";
// import UserSelect from '/@/components/UserSelect/index.vue' // import UserSelect from '/@/components/UserSelect/index.vue'
import templateTableCommon from "/@/components/templetTableComom/index.vue" import templateTableCommon from "/@/components/templetTableComom/index.vue"
import {templateStore} from "/@/stores/template" import {templateStore} from "/@/stores/template"
@@ -230,8 +232,7 @@ const createEmptyExpert = () => ({
attachments: '', attachments: '',
evidences: '', evidences: '',
level: '', level: '',
expertStatus: 'normal', externalStatus: 'normal',
externalStatus: '',
attachmentUrl: '', attachmentUrl: '',
testimonyMaterials: '', testimonyMaterials: '',
createBy: '', createBy: '',
@@ -267,7 +268,7 @@ const onExpertSelected = (row: any) => {
target.professionalTitle = row?.professionalTitle ?? target.professionalTitle; target.professionalTitle = row?.professionalTitle ?? target.professionalTitle;
target.workUnit = row?.workUnit ?? target.workUnit; target.workUnit = row?.workUnit ?? target.workUnit;
target.level = row?.level ?? target.level; target.level = row?.level ?? target.level;
target.expertStatus = row?.expertStatus ?? target.expertStatus; target.externalStatus = row?.externalStatus ?? target.externalStatus;
target.attachments = row?.attachmentUrl ? JSON.parse(row.attachmentUrl) : [] target.attachments = row?.attachmentUrl ? JSON.parse(row.attachmentUrl) : []
target.evidences = row?.testimonyMaterials ? JSON.parse(row.testimonyMaterials) : [] target.evidences = row?.testimonyMaterials ? JSON.parse(row.testimonyMaterials) : []
}; };
@@ -312,8 +313,7 @@ const toSubmitExpert = (expert: ReturnType<typeof createEmptyExpert>) => ({
attachmentUrl: JSON.stringify(expert.attachments), attachmentUrl: JSON.stringify(expert.attachments),
testimonyMaterials: JSON.stringify(expert.evidences), testimonyMaterials: JSON.stringify(expert.evidences),
level: expert.level || '', level: expert.level || '',
expertStatus: expert.expertStatus || 'normal', externalStatus: expert.externalStatus || 'normal',
externalStatus: expert.externalStatus || '',
createBy: expert.createBy || '', createBy: expert.createBy || '',
createTime: expert.createTime || '', createTime: expert.createTime || '',
updateBy: expert.updateBy || '', updateBy: expert.updateBy || '',
@@ -353,7 +353,7 @@ const verifyTableFields = () => {
// const handleUserSelectOk = (user: any) => { // const handleUserSelectOk = (user: any) => {
// console.log(user) // console.log(user)
// } // }
const router = useRouter();
const handleInitiateApproval = async () => { const handleInitiateApproval = async () => {
if (submitLoading.value) return; if (submitLoading.value) return;
const r = await headerFormRef.value?.validate(); const r = await headerFormRef.value?.validate();
@@ -384,6 +384,7 @@ const handleInitiateApproval = async () => {
}; };
await addExpertInformationAPI(payload); await addExpertInformationAPI(payload);
useMessage().success('成功'); useMessage().success('成功');
await router.push('/flow/task/started')
} catch (error: any) { } catch (error: any) {
useMessage().error(error?.msg || error?.message || '操作失败'); useMessage().error(error?.msg || error?.message || '操作失败');
} finally { } finally {
@@ -431,7 +432,7 @@ const handleLoadTemplate = () => {
const handleSaveTemplate = async () => { const handleSaveTemplate = async () => {
if (submitLoading.value) return; if (submitLoading.value) return;
const r = await headerFormRef.value?.validate(); const r = await headerFormRef.value?.validate();
if (!verifyTableFields()) { if (!verifyTableFields()&& !r) {
useMessage().warning('请完成表格必填项'); useMessage().warning('请完成表格必填项');
return return
} }
@@ -460,7 +461,7 @@ watch(()=>tempId.value,()=>{
professionalTitle: item.professionalTitle, professionalTitle: item.professionalTitle,
workUnit: item.workUnit, workUnit: item.workUnit,
level: item.level, level: item.level,
expertStatus: item.expertStatus || 'normal', externalStatus: item.externalStatus || 'normal',
attachments: item.attachmentUrl ? JSON.parse(item.attachmentUrl) : [], attachments: item.attachmentUrl ? JSON.parse(item.attachmentUrl) : [],
evidences: item.testimonyMaterials ? JSON.parse(item.testimonyMaterials) : [] evidences: item.testimonyMaterials ? JSON.parse(item.testimonyMaterials) : []
} }

View File

@@ -26,13 +26,13 @@
<el-table-column :label="t('expertLibrary.table.level')" prop="level" min-width="100" <el-table-column :label="t('expertLibrary.table.level')" prop="level" min-width="100"
show-overflow-tooltip> show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<span>{{ levelLabel(row.level) }}</span> <span>{{ level.find((item:any) => item.value === row.level)?.label || '--' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('expertLibrary.table.status')" prop="externalStatus" min-width="120" <el-table-column :label="t('expertApply.table.externalStatus')" prop="externalStatus" min-width="120"
show-overflow-tooltip> show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="['info', 'primary', 'success', 'danger'][row.status]">{{ externalStatusLabel(row.status) }}</el-tag> <el-tag :type="row.externalStatus === 'normal' ? 'success' : 'danger'">{{ externalStatusLabel(row.externalStatus) }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('expertLibrary.table.action')" width="100" fixed="right"> <el-table-column :label="t('expertLibrary.table.action')" width="100" fixed="right">
@@ -60,6 +60,7 @@ import ExpertDetailDialog from '/@/components/investment/ExpertDetailDialog.vue'
import { useUserInfo } from '/@/stores/userInfo'; import { useUserInfo } from '/@/stores/userInfo';
import { dayjs } from 'element-plus'; import { dayjs } from 'element-plus';
import FlowFormView from '/@/components/workbench/common/FlowFormView.vue'; import FlowFormView from '/@/components/workbench/common/FlowFormView.vue';
import {level} from "/@/hooks/enums";
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute() const route = useRoute()
@@ -107,19 +108,15 @@ const handleView = (row: any) => {
}; };
const levelLabel = (val: string) => { const levelLabel = (val: string) => {
if (val === 'national') return t('expertApply.level.national'); if (val === 'national') return '一级';
if (val === 'provincial') return t('expertApply.level.provincial'); if (val === 'provincial') return '二级';
if (val === 'city') return t('expertApply.level.city');
return val || '-'; return val || '-';
}; };
const externalStatusLabel = (val: string) => { const externalStatusLabel = (val: string) => {
return { if (val === 'normal') return t('expertApply.externalStatusOptions.normal');
'0': t('expertLibrary.status.pending'), if (val === 'invalid') return t('expertApply.externalStatusOptions.invalid');
'1': t('expertLibrary.status.reviewing'), return val || '-';
'2': t('expertLibrary.status.approved'),
'3': t('expertLibrary.status.rejected'),
}[val] || 1
}; };
onMounted(() => { onMounted(() => {

View File

@@ -109,11 +109,11 @@ export default {
attachments: 'Attachments', attachments: 'Attachments',
evidences: 'Supporting Materials', evidences: 'Supporting Materials',
level: 'Level', level: 'Level',
expertStatus: 'Expert Status', externalStatus: 'Expert Status',
inputPlaceholder: 'Please enter', inputPlaceholder: 'Please enter',
selectPlaceholder: 'Please select', selectPlaceholder: 'Please select',
}, },
expertStatusOptions: { externalStatusOptions: {
normal: 'Normal', normal: 'Normal',
invalid: 'Invalid', invalid: 'Invalid',
}, },

View File

@@ -109,11 +109,11 @@ export default {
attachments: '附件', attachments: '附件',
evidences: '佐证材料', evidences: '佐证材料',
level: '级别', level: '级别',
expertStatus: '专家状态', externalStatus: '专家状态',
inputPlaceholder: '请输入', inputPlaceholder: '请输入',
selectPlaceholder: '请选择', selectPlaceholder: '请选择',
}, },
expertStatusOptions: { externalStatusOptions: {
normal: '正常', normal: '正常',
invalid: '作废', invalid: '作废',
}, },

View File

@@ -138,7 +138,7 @@ const instructionFields = computed<Array<{ key: InstructionFieldKey; label: stri
const basicInfoFields = computed<Array<{ key: BasicFieldKey; label: string }>>(() => [ const basicInfoFields = computed<Array<{ key: BasicFieldKey; label: string }>>(() => [
{key: 'groupBelonging', label: t('mixedRegister.basicFields.groupName')}, {key: 'groupBelonging', label: t('mixedRegister.basicFields.groupName')},
{ key: 'projectYear', label: t('mixedRegister.basicFields.year'), type: 'year', fieldProps: { valueFormat: 'YYYY' } }, {key: 'projectYear', label: t('mixedRegister.basicFields.year'),type:'number',length:4},
{key: 'projectName', label: t('mixedRegister.basicFields.projectName')}, {key: 'projectName', label: t('mixedRegister.basicFields.projectName')},
{key: 'implementEnterprise', label: t('mixedRegister.basicFields.companyFullName')}, {key: 'implementEnterprise', label: t('mixedRegister.basicFields.companyFullName')},
{key: 'enterpriseCreditCode', label: t('mixedRegister.basicFields.creditCode')}, {key: 'enterpriseCreditCode', label: t('mixedRegister.basicFields.creditCode')},

View File

@@ -124,7 +124,19 @@
<span class="detail-title">{{ t('reserveLibrary.detail.title') }}</span> <span class="detail-title">{{ t('reserveLibrary.detail.title') }}</span>
<el-button class="close-btn" link icon="Close" @click="detailDrawerVisible = false" /> <el-button class="close-btn" link icon="Close" @click="detailDrawerVisible = false" />
</div> </div>
<div class="detail-content"> <!-- Tab 锚点导航 -->
<div class="detail-tabs">
<div
v-for="tab in detailTabs"
:key="tab.id"
class="detail-tab-item"
:class="{ active: activeTab === tab.id }"
@click="scrollToSection(tab.id)"
>
{{ tab.label }}
</div>
</div>
<div class="detail-content" ref="detailContentRef" @scroll="handleDetailScroll">
<ProjectBasicInfoView :model-value="detailFormData" :main-title="t('reserveLibrary.detail.formTitle')" /> <ProjectBasicInfoView :model-value="detailFormData" :main-title="t('reserveLibrary.detail.formTitle')" />
</div> </div>
</el-drawer> </el-drawer>
@@ -235,6 +247,59 @@ const detailFormData = reactive<ProjectBasicInfoFormData>(createEmptyDetail());
const tableLoading = ref(false); const tableLoading = ref(false);
const detailLoading = ref(false); const detailLoading = ref(false);
// Tab 锚点导航相关
const detailContentRef = ref<HTMLElement | null>(null);
const activeTab = ref('basicInfo');
const detailTabs = [
{ id: 'basicInfo', label: t('reserveRegistration.basicInfo.title') || '项目基本信息' },
{ id: 'investmentEstimate', label: t('reserveRegistration.investmentEstimate.title') || '投资估算' },
{ id: 'partnerInfo', label: t('reserveRegistration.partnerInfo.title') || '合作方信息' },
{ id: 'decisionInfo', label: t('reserveRegistration.decisionInfo.title') || '决策信息' },
];
const scrollToSection = (sectionId: string) => {
activeTab.value = sectionId;
const contentEl = detailContentRef.value;
if (!contentEl) return;
// 根据 sectionId 查找对应的标题元素
const sectionMap: Record<string, number> = {
'basicInfo': 0,
'investmentEstimate': 1,
'partnerInfo': 2,
'decisionInfo': 3,
};
const sectionTitles = contentEl.querySelectorAll('.form-section-title, .sub-section-title');
const targetIndex = sectionMap[sectionId];
if (sectionTitles[targetIndex]) {
sectionTitles[targetIndex].scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
const handleDetailScroll = () => {
const contentEl = detailContentRef.value;
if (!contentEl) return;
const sectionTitles = contentEl.querySelectorAll('.form-section-title, .sub-section-title');
const scrollTop = contentEl.scrollTop;
const offsetTop = 100; // 偏移量
let currentSection = 'basicInfo';
const sectionIds = ['basicInfo', 'investmentEstimate', 'partnerInfo', 'decisionInfo'];
sectionTitles.forEach((el, index) => {
const rect = el.getBoundingClientRect();
const containerRect = contentEl.getBoundingClientRect();
if (rect.top - containerRect.top <= offsetTop) {
currentSection = sectionIds[index] || currentSection;
}
});
activeTab.value = currentSection;
};
const resetDetailForm = () => { const resetDetailForm = () => {
const empty = createEmptyDetail(); const empty = createEmptyDetail();
Object.assign(detailFormData, empty); Object.assign(detailFormData, empty);
@@ -453,10 +518,39 @@ onMounted(() => {
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
} }
.detail-tabs {
display: flex;
align-items: center;
gap: 0;
padding: 0 20px;
border-bottom: 1px solid var(--el-border-color);
background: var(--el-bg-color);
}
.detail-tab-item {
padding: 12px 20px;
font-size: 14px;
color: var(--el-text-color-regular);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.2s ease;
white-space: nowrap;
}
.detail-tab-item:hover {
color: var(--el-color-primary);
}
.detail-tab-item.active {
color: var(--el-color-primary);
border-bottom-color: var(--el-color-primary);
font-weight: 500;
}
.detail-content { .detail-content {
padding: 0 20px 20px; padding: 0 20px 20px;
overflow: auto; overflow: auto;
height: calc(100% - 52px); height: calc(100% - 96px);
} }
.el-form-item--default { .el-form-item--default {

View File

@@ -74,7 +74,9 @@ import {flowNameOptions} from '/@/hooks/enums';
import {addTemplate, getUserDeptBelong} from "/@/api/common"; import {addTemplate, getUserDeptBelong} from "/@/api/common";
import {templateStore} from "/@/stores/template"; import {templateStore} from "/@/stores/template";
import type {FormInstance, FormRules} from "element-plus"; import type {FormInstance, FormRules} from "element-plus";
import {useRouter} from "vue-router";
const router = useRouter();
const temp = templateStore(); const temp = templateStore();
const props = defineProps({ const props = defineProps({
isUpdate: { isUpdate: {
@@ -308,6 +310,7 @@ const handleInitiateApproval = async () => {
message.success(t('common.success')); message.success(t('common.success'));
resetHeaderForm(); resetHeaderForm();
resetProjectForm(); resetProjectForm();
await router.push('/flow/task/started')
} }
} catch (error: any) { } catch (error: any) {
message.error(error?.msg || error?.message || t('common.fail')); message.error(error?.msg || error?.message || t('common.fail'));

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="fixed top-0 right-0 z-10 flex items-center p-5 space-x-2"> <div class="fixed top-0 right-0 z-10 flex items-center p-5 space-x-2">
<!-- 语言切换 --> <!-- 语言切换 -->
<el-dropdown v-if="isI18nEnabled" trigger="click" @command="onLanguageChange"> <!-- <el-dropdown v-if="isI18nEnabled" trigger="click" @command="onLanguageChange">
<div <div
class="flex items-center justify-center transition-colors rounded-lg cursor-pointer w-9 h-9 bg-white/80 dark:bg-slate-800/80 hover:bg-gray-100 dark:hover:bg-slate-700 backdrop-blur-sm" class="flex items-center justify-center transition-colors rounded-lg cursor-pointer w-9 h-9 bg-white/80 dark:bg-slate-800/80 hover:bg-gray-100 dark:hover:bg-slate-700 backdrop-blur-sm"
> >
@@ -16,7 +16,7 @@
<el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item> <el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown> -->
<!-- 主题切换 --> <!-- 主题切换 -->
<el-tooltip v-if="isDarkModeEnabled" :content="getThemeConfig.isDark ? '切换亮色模式' : '切换暗色模式'" placement="bottom"> <el-tooltip v-if="isDarkModeEnabled" :content="getThemeConfig.isDark ? '切换亮色模式' : '切换暗色模式'" placement="bottom">

View File

@@ -208,6 +208,7 @@ export default {
startTime: 'Initiation Time', startTime: 'Initiation Time',
receivedTime: 'Received Time', receivedTime: 'Received Time',
processTime: 'Process Time', processTime: 'Process Time',
currentNode: 'Current Node',
status: 'Approval Status', status: 'Approval Status',
actions: 'Actions', actions: 'Actions',
}, },

View File

@@ -208,6 +208,7 @@ export default {
startTime: '发起时间', startTime: '发起时间',
receivedTime: '接收时间', receivedTime: '接收时间',
processTime: '处理时间', processTime: '处理时间',
currentNode: '当前节点',
status: '审批状态', status: '审批状态',
actions: '操作', actions: '操作',
}, },

View File

@@ -667,6 +667,7 @@ import {addTemplate, getPropertyRightsUserDeptBelong} from "/@/api/common";
import {FormInstance} from "element-plus"; import {FormInstance} from "element-plus";
import templateTable from "/@/components/templetTableComom/index.vue" import templateTable from "/@/components/templetTableComom/index.vue"
import {templateStore} from "/@/stores/template" import {templateStore} from "/@/stores/template"
import {useRouter} from "vue-router";
const temp = templateStore() const temp = templateStore()
const props = defineProps({ const props = defineProps({
@@ -1079,6 +1080,7 @@ const scrollToSection = (id: TabId) => {
}; };
const submitting = ref(false) const submitting = ref(false)
const router = useRouter()
const handleSubmit = async () => { const handleSubmit = async () => {
const re = await headerFormRef.value?.validate() const re = await headerFormRef.value?.validate()
if (!re) return if (!re) return
@@ -1116,6 +1118,7 @@ const handleSubmit = async () => {
const res = await addPropertyRightsAPI(params) const res = await addPropertyRightsAPI(params)
if (res.ok) { if (res.ok) {
message.success(t('common.success')); message.success(t('common.success'));
await router.push('/flow/task/started')
} else { } else {
message.error(res.msg) message.error(res.msg)
} }
@@ -1168,7 +1171,6 @@ const handleLoadTemplate = () => {
const flowName = props.isUpdate ? 'propertyRightsUpdate' : 'propertyRightsRegistration' const flowName = props.isUpdate ? 'propertyRightsUpdate' : 'propertyRightsRegistration'
const flowNameObj = flowNameOptions.filter(item => item.label === flowName)[0]; const flowNameObj = flowNameOptions.filter(item => item.label === flowName)[0];
temp.changeTempShow(true,flowNameObj.value) temp.changeTempShow(true,flowNameObj.value)
message.info(t('ownershipCreate.messages.loadTemplate'));
}; };
watch(()=>tempId.value,()=>{ watch(()=>tempId.value,()=>{

View File

@@ -55,13 +55,18 @@
min-width="180" /> min-width="180" />
<el-table-column prop="updateTime" :label="t('workbenchPage.pending.table.processTime')" <el-table-column prop="updateTime" :label="t('workbenchPage.pending.table.processTime')"
min-width="180" /> min-width="180" />
<el-table-column prop="taskName" :label="t('workbenchPage.pending.table.currentNode')" min-width="140">
<template #default="scope">
{{ scope.row.taskName || scope.row.nodeName || scope.row.currentNode || '--' }}
</template>
</el-table-column>
<el-table-column prop="status" :label="t('workbenchPage.pending.table.status')" min-width="140"> <el-table-column prop="status" :label="t('workbenchPage.pending.table.status')" min-width="140">
<template #default="scope"> <template #default="scope">
<el-tag v-if="scope.row.status == 1" type="primary">待审批</el-tag> <el-tag v-if="scope.row.status == 1" type="primary">进行中</el-tag>
<el-tag v-else type="success">已结束</el-tag> <el-tag v-else type="success">已结束</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('workbenchPage.pending.table.actions')" width="120" fixed="right"> <el-table-column label="查看" width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button link type="primary" @click="handleView(row)"> <el-button link type="primary" @click="handleView(row)">
{{ t('workbenchPage.pending.actions.view') }} {{ t('workbenchPage.pending.actions.view') }}
@@ -75,6 +80,27 @@
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination"></pagination> <pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination"></pagination>
</el-card> </el-card>
</div> </div>
<!-- <el-dialog v-model="visible" width="80%" title="流程节点">-->
<!-- <flow-node-format :selectUserNodeId="flowUserData.root.map(item => item.id)" :flow-id="flowIdCon" ref="flowNodeFormatRef"></flow-node-format>-->
<!-- </el-dialog>-->
<!-- v-if="visible" 确保关闭时销毁组件 -->
<el-drawer v-model="visible" v-if="visible" direction="rtl" size="600px">
<template #header>
<h3>{{ currentData?.name }}</h3>
</template>
<template #default>
<el-card class="box-card">
<FormCreate :rule="rule" v-model="formData" v-model:api="fApi" />
</el-card>
<flow-node-format
:disableSelect="true"
:processInstanceId="currentData.processInstanceId"
:flow-id="currentData.flowId"
ref="flowNodeFormatRef"
:disabled="true"
></flow-node-format>
</template>
</el-drawer>
</div> </div>
</template> </template>
@@ -86,13 +112,15 @@ import { queryMineStarted } from '/@/api/flow/task';
import { BasicTableProps, useTable } from '/@/hooks/table'; import { BasicTableProps, useTable } from '/@/hooks/table';
import { useUserInfo } from '/@/stores/userInfo'; import { useUserInfo } from '/@/stores/userInfo';
import { flowNameOptions } from '/@/hooks/enums'; import { flowNameOptions } from '/@/hooks/enums';
import { getProcessInfoByIdAPI } from '/@/api/workbench/miOwLibr/ownershipCreate';
import FlowNodeFormat from "/@/views/flow/form/tools/FlowNodeFormatData.vue";
import FormCreate from "/@/views/flow/workflow/components/FormCreate.vue";
const { t } = useI18n(); const { t } = useI18n();
const message = useMessage(); const message = useMessage();
const loading = ref(false); const loading = ref(false);
const stores = useUserInfo(); const stores = useUserInfo();
const { userInfos } = storeToRefs(stores); const { userInfos } = storeToRefs(stores);
const state: BasicTableProps = reactive<BasicTableProps>({ const state: BasicTableProps = reactive<BasicTableProps>({
pageList: queryMineStarted, pageList: queryMineStarted,
queryForm: { queryForm: {
@@ -117,9 +145,18 @@ const handleSearch = () => {
state.queryForm.title = keyword.value state.queryForm.title = keyword.value
getDataList(true) getDataList(true)
}; };
const currentData = ref<any>(null);
const visible = ref(false);
/**查看流程*/
const handleView = (row: any) => { const handleView = (row: any) => {
message.info(`${row.title} ${t('workbenchPage.pending.messages.viewPlaceholder')}`); getProcessInfoByIdAPI(row.id).then(res =>{
currentData.value = {
name: res.data.name,
processInstanceId: res.data.processInstanceId,
flowId: res.data.flowId
}
visible.value = true
})
}; };
const handleReview = (row: any) => { const handleReview = (row: any) => {