470 lines
18 KiB
Vue
470 lines
18 KiB
Vue
<template>
|
||
<a-spin :spinning="loading">
|
||
<JFormContainer :disabled="disabled">
|
||
<template #detail>
|
||
<a-form v-bind="formItemLayout" name="ImprovementProposalForm" ref="formRef">
|
||
<a-row>
|
||
<a-col :span="12">
|
||
<a-form-item label="提案编号" :required="false" id="ImprovementProposalForm-proposalNo" name="proposalNo">
|
||
<a-input v-model:value="formData.proposalNo" :disabled="true" allow-clear></a-input>
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="提出日期" id="ImprovementProposalForm-proposalDate" name="proposalDate">
|
||
<a-input v-model:value="formData.proposalDate" :disabled="true" allow-clear></a-input>
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="提案名称" v-bind="validateInfos.proposalName" id="ImprovementProposalForm-proposalName" name="proposalName">
|
||
<a-input v-model:value="formData.proposalName" placeholder="请输入提案名称" allow-clear ></a-input>
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="提案类别" v-bind="validateInfos.proposalCategory" id="ImprovementProposalForm-proposalCategory" name="proposalCategory">
|
||
<j-dict-select-tag v-model:value="formData.proposalCategory" dictCode="proposal_category" placeholder="请选择提案类别" allow-clear />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="提案部门" :required="false" id="ImprovementProposalForm-proposalDeptId" name="proposalDeptId">
|
||
<a-input v-model:value="formData.proposalDeptName" :disabled="true" allow-clear></a-input>
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="提案人" v-bind="validateInfos.applicantName" id="ImprovementProposalForm-applicantName" name="applicantName">
|
||
<a-input v-model:value="formData.applicantName" placeholder="请输入申请人姓名" allow-clear ></a-input>
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="团队名称" v-bind="validateInfos.teamName" id="ImprovementProposalForm-teamName" name="teamName">
|
||
<a-input v-model:value="formData.teamName" placeholder="请输入团队名称" allow-clear ></a-input>
|
||
</a-form-item>
|
||
</a-col>
|
||
|
||
<a-col :span="24">
|
||
<a-form-item label="问题描述" v-bind="validateInfos.problemDesc" id="ImprovementProposalForm-problemDesc" name="problemDesc" :labelCol="longLabelCol" :wrapperCol="longWrapperCol">
|
||
<a-textarea v-model:value="formData.problemDesc" :rows="4" placeholder="请输入问题描述" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="24">
|
||
<a-form-item label="改善方法及措施" v-bind="validateInfos.improvementMethod" id="ImprovementProposalForm-improvementMethod" name="improvementMethod" :labelCol="longLabelCol" :wrapperCol="longWrapperCol">
|
||
<a-textarea v-model:value="formData.improvementMethod" :rows="4" placeholder="请输入改善方法及措施" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="改善前情况描述" v-bind="validateInfos.beforeDesc" id="ImprovementProposalForm-beforeDesc" name="beforeDesc" :labelCol="halfLabelCol" :wrapperCol="halfWrapperCol">
|
||
<a-textarea v-model:value="formData.beforeDesc" :rows="4" placeholder="请输入改善前情况描述" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="改善前图片" :labelCol="halfLabelCol" :wrapperCol="halfWrapperCol">
|
||
<SUploadFile ref="beforeFileRef" :bussiness-id="formData.id ? `${formData.id}:before` : ''" :multiple="true" :disabled="disabled" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="改善后情况描述" v-bind="validateInfos.afterDesc" id="ImprovementProposalForm-afterDesc" name="afterDesc" :labelCol="halfLabelCol" :wrapperCol="halfWrapperCol">
|
||
<a-textarea v-model:value="formData.afterDesc" :rows="4" placeholder="请输入改善后情况描述" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<a-form-item label="改善后图片" :labelCol="halfLabelCol" :wrapperCol="halfWrapperCol">
|
||
<SUploadFile ref="afterFileRef" :bussiness-id="formData.id ? `${formData.id}:after` : ''" :multiple="true" :disabled="disabled" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="24">
|
||
<a-form-item label="改善效果" v-bind="validateInfos.improvementEffect" id="ImprovementProposalForm-improvementEffect" name="improvementEffect" :labelCol="longLabelCol" :wrapperCol="longWrapperCol">
|
||
<a-textarea v-model:value="formData.improvementEffect" :rows="4" placeholder="请输入改善效果" />
|
||
</a-form-item>
|
||
</a-col>
|
||
</a-row>
|
||
</a-form>
|
||
</template>
|
||
</JFormContainer>
|
||
|
||
<!-- 新增申请只填写主表,子表由后续评分和投票流程维护。 -->
|
||
<a-tabs v-if="showSubTables" v-model:activeKey="activeKey" animated style="overflow:hidden;">
|
||
<a-tab-pane tab="部门评议评分表" key="improvementDeptScore" :forceRender="true">
|
||
<j-vxe-table
|
||
:keep-source="true"
|
||
resizable
|
||
ref="improvementDeptScoreTableRef"
|
||
:loading="improvementDeptScoreTable.loading"
|
||
:columns="improvementDeptScoreTable.columns"
|
||
:dataSource="improvementDeptScoreTable.dataSource"
|
||
:height="340"
|
||
:disabled="disabled"
|
||
:rowNumber="true"
|
||
:rowSelection="true"
|
||
:toolbar="true"/>
|
||
</a-tab-pane>
|
||
<a-tab-pane tab="所级评议投票表" key="improvementInstituteVote" :forceRender="true">
|
||
<j-vxe-table
|
||
:keep-source="true"
|
||
resizable
|
||
ref="improvementInstituteVoteTableRef"
|
||
:loading="improvementInstituteVoteTable.loading"
|
||
:columns="improvementInstituteVoteTable.columns"
|
||
:dataSource="improvementInstituteVoteTable.dataSource"
|
||
:height="340"
|
||
:disabled="disabled"
|
||
:rowNumber="true"
|
||
:rowSelection="true"
|
||
:toolbar="true"/>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
<div v-if="showFlowSubmitButton" :span="24" style="width: 100%;text-align: center;margin-top: 10px">
|
||
<a-button preIcon="ant-design:check-outlined" style="width: 126px" type="primary" @click="submitForm">提 交</a-button>
|
||
</div>
|
||
</a-spin>
|
||
</template>
|
||
|
||
<script lang="ts">
|
||
import { defineComponent, ref, reactive, computed, toRaw, onMounted, nextTick } from 'vue';
|
||
import { defHttp } from '/@/utils/http/axios';
|
||
import { useValidateAntFormAndTable } from '/@/hooks/system/useJvxeMethods';
|
||
import { queryImprovementDeptScoreListByMainId, queryImprovementInstituteVoteListByMainId, queryDataById, saveOrUpdate, getLatestProposalSequence } from '../ImprovementProposal.api';
|
||
import { JVxeTable } from '/@/components/jeecg/JVxeTable';
|
||
import {improvementDeptScoreColumns, improvementInstituteVoteColumns} from '../ImprovementProposal.data';
|
||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||
import { Form } from 'ant-design-vue';
|
||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||
import SUploadFile from '/@/components/semri/fileComponent/SUploadFile.vue';
|
||
import { useUserStore } from '/@/store/modules/user';
|
||
const useForm = Form.useForm;
|
||
|
||
export default defineComponent({
|
||
name: "ImprovementProposalForm",
|
||
components:{
|
||
JVxeTable,
|
||
JFormContainer,
|
||
JDictSelectTag,
|
||
SUploadFile,
|
||
},
|
||
props:{
|
||
formDisabled:{
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
formData: { type: Object, default: ()=>{} },
|
||
formBpm: { type: Boolean, default: true }
|
||
},
|
||
emits:['success'],
|
||
setup(props, {emit}) {
|
||
const loading = ref(false);
|
||
const formRef = ref();
|
||
const beforeFileRef = ref();
|
||
const afterFileRef = ref();
|
||
const improvementDeptScoreTableRef = ref();
|
||
const improvementDeptScoreTable = reactive<Record<string, any>>({
|
||
loading: false,
|
||
columns: improvementDeptScoreColumns,
|
||
dataSource: []
|
||
});
|
||
const improvementInstituteVoteTableRef = ref();
|
||
const improvementInstituteVoteTable = reactive<Record<string, any>>({
|
||
loading: false,
|
||
columns: improvementInstituteVoteColumns,
|
||
dataSource: []
|
||
});
|
||
const activeKey = ref('improvementDeptScore');
|
||
const userStore = useUserStore();
|
||
|
||
const formData = reactive<Record<string, any>>({
|
||
id: '',
|
||
proposalNo: '',
|
||
proposalName: '',
|
||
proposalDate: '',
|
||
proposalDeptId: '',
|
||
proposalDeptName: '',
|
||
proposalDeptCode: '',
|
||
applicantId: '',
|
||
applicantName: '',
|
||
teamName: '',
|
||
proposalCategory: '',
|
||
problemDesc: '',
|
||
improvementMethod: '',
|
||
beforeDesc: '',
|
||
afterDesc: '',
|
||
improvementEffect: '',
|
||
finalAward: '',
|
||
});
|
||
|
||
//表单验证
|
||
const validatorRules = reactive({
|
||
proposalName: [{ required: true, message: '请输入提案名称!'},],
|
||
applicantName: [{ required: true, message: '请输入申请人姓名!'},],
|
||
proposalCategory: [{ required: true, message: '请选择提案类别!'},],
|
||
problemDesc: [{ required: true, message: '请输入问题描述!'},],
|
||
improvementMethod: [{ required: true, message: '请输入改善方法及措施!'},],
|
||
});
|
||
const {resetFields, validate, validateInfos} = useForm(formData, validatorRules, {immediate: false});
|
||
const dbData = {};
|
||
const formItemLayout = {
|
||
labelCol: {xs: {span: 24}, sm: {span: 5}},
|
||
wrapperCol: {xs: {span: 24}, sm: {span: 16}},
|
||
};
|
||
const longLabelCol = {
|
||
xs: {span: 24},
|
||
sm: {span: 4},
|
||
};
|
||
const longWrapperCol = {
|
||
xs: {span: 24},
|
||
sm: {span: 20},
|
||
};
|
||
const halfLabelCol = {
|
||
xs: {span: 24},
|
||
sm: {span: 8},
|
||
};
|
||
const halfWrapperCol = {
|
||
xs: {span: 24},
|
||
sm: {span: 16},
|
||
};
|
||
|
||
const disabled = computed(()=>{
|
||
if(props.formBpm === true){
|
||
if(props.formData.disabled === false){
|
||
return false;
|
||
}else{
|
||
return true;
|
||
}
|
||
}
|
||
return props.formDisabled;
|
||
});
|
||
|
||
// 普通新增没有业务 ID,不展示评分和投票子表;已有数据及流程表单正常展示。
|
||
const showSubTables = computed(() => Boolean(formData.id || props.formData?.dataId));
|
||
|
||
function getCurrentDate() {
|
||
const now = new Date();
|
||
const year = now.getFullYear();
|
||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||
const day = String(now.getDate()).padStart(2, '0');
|
||
return `${year}-${month}-${day}`;
|
||
}
|
||
|
||
function getCurrentLoginDepart() {
|
||
const userInfo = (userStore.getUserInfo || {}) as Record<string, any>;
|
||
const loginInfo = (userStore.getLoginInfo || {}) as Record<string, any>;
|
||
let departs: any[] = [];
|
||
if (Array.isArray(loginInfo.departs)) {
|
||
departs = loginInfo.departs;
|
||
} else if (Array.isArray(userInfo.departs)) {
|
||
departs = userInfo.departs;
|
||
} else if (loginInfo.userInfo && Array.isArray(loginInfo.userInfo.departs)) {
|
||
departs = loginInfo.userInfo.departs;
|
||
}
|
||
if (userInfo.orgCode) {
|
||
const found = departs.find((item) => item && item.orgCode === userInfo.orgCode);
|
||
if (found) return found;
|
||
}
|
||
if (departs.length === 1) {
|
||
return departs[0];
|
||
}
|
||
if (departs.length > 0) {
|
||
return departs[0];
|
||
}
|
||
return undefined;
|
||
}
|
||
|
||
async function getCurrentDepartInfo() {
|
||
const userInfo = (userStore.getUserInfo || {}) as Record<string, any>;
|
||
const loginDepart = getCurrentLoginDepart();
|
||
if (loginDepart) {
|
||
return {
|
||
id: loginDepart.id || '',
|
||
departName: loginDepart.departName || loginDepart.name || '',
|
||
orgCode: loginDepart.orgCode || '',
|
||
};
|
||
}
|
||
if (userInfo.orgCode) {
|
||
try {
|
||
const depart = await defHttp.get({ url: '/sys/sysDepart/getDepartName', params: { orgCode: userInfo.orgCode } }, { successMessageMode: 'none' });
|
||
if (depart && (depart.id || depart.departName)) {
|
||
return {
|
||
id: depart.id || '',
|
||
departName: depart.departName || depart.depart_name || '',
|
||
orgCode: userInfo.orgCode,
|
||
};
|
||
}
|
||
} catch (e) {
|
||
// ignore
|
||
}
|
||
}
|
||
const deptId = userInfo.departIds || userInfo.deptId || userInfo.deptid || '';
|
||
const deptName = userInfo.departIds_dictText || userInfo.orgCodeTxt || userInfo.deptName || '';
|
||
return { id: deptId, departName: deptName, orgCode: userInfo.orgCode || '' };
|
||
}
|
||
|
||
async function applyCurrentUserDeptInfo() {
|
||
const departInfo = await getCurrentDepartInfo();
|
||
formData.proposalDeptId = departInfo.id;
|
||
formData.proposalDeptName = departInfo.departName;
|
||
formData.proposalDeptCode = departInfo.orgCode;
|
||
}
|
||
|
||
async function getProposalSequence() {
|
||
const year = new Date().getFullYear();
|
||
const latestSequence = await getLatestProposalSequence(year);
|
||
// return Number(latestSequence) + 1;
|
||
return String(Number(latestSequence) + 1).padStart(4, '0');
|
||
}
|
||
|
||
async function generateProposalNo() {
|
||
const deptCode = formData.proposalDeptName || '';
|
||
const year = new Date().getFullYear();
|
||
const proposalSequence = await getProposalSequence();
|
||
return `${deptCode}-${year}年-${proposalSequence}`;
|
||
}
|
||
|
||
onMounted(()=>{
|
||
initFormData();
|
||
});
|
||
const queryByIdUrl = '/improvementproposal/improvementProposal/queryById';
|
||
async function initFormData(){
|
||
if(props.formBpm === true){
|
||
let params = {id: props.formData.dataId};
|
||
const row = await defHttp.get({url: queryByIdUrl, params});
|
||
Object.keys(row).map(k => {
|
||
formData[k] = row[k];
|
||
});
|
||
const improvementDeptScoreDataList = await queryImprovementDeptScoreListByMainId(row['id']);
|
||
improvementDeptScoreTable.dataSource = [...improvementDeptScoreDataList];
|
||
const improvementInstituteVoteDataList = await queryImprovementInstituteVoteListByMainId(row['id']);
|
||
improvementInstituteVoteTable.dataSource = [...improvementInstituteVoteDataList];
|
||
}
|
||
}
|
||
|
||
const showFlowSubmitButton = computed(()=>{
|
||
if(props.formBpm === true){
|
||
if(props.formData.disabled === false){
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
});
|
||
|
||
async function add() {
|
||
resetFields();
|
||
improvementDeptScoreTable.dataSource = [];
|
||
improvementInstituteVoteTable.dataSource = [];
|
||
formData.proposalDate = getCurrentDate();
|
||
await applyCurrentUserDeptInfo();
|
||
formData.proposalNo = await generateProposalNo();
|
||
}
|
||
|
||
async function edit(row) {
|
||
//主表数据
|
||
await queryMainData(row.id);
|
||
//子表数据
|
||
const improvementDeptScoreDataList = await queryImprovementDeptScoreListByMainId(row['id']);
|
||
improvementDeptScoreTable.dataSource = [...improvementDeptScoreDataList];
|
||
const improvementInstituteVoteDataList = await queryImprovementInstituteVoteListByMainId(row['id']);
|
||
improvementInstituteVoteTable.dataSource = [...improvementInstituteVoteDataList];
|
||
}
|
||
|
||
async function queryMainData(id) {
|
||
const row = await queryDataById(id);
|
||
resetFields();
|
||
const tmpData = {};
|
||
Object.keys(formData).forEach((key) => {
|
||
if(row.hasOwnProperty(key)){
|
||
tmpData[key] = row[key]
|
||
}
|
||
})
|
||
//赋值
|
||
Object.assign(formData,tmpData);
|
||
}
|
||
|
||
const {getSubFormAndTableData, transformData} = useValidateAntFormAndTable(activeKey, {
|
||
'improvementDeptScore': improvementDeptScoreTableRef,
|
||
'improvementInstituteVote': improvementInstituteVoteTableRef,
|
||
});
|
||
|
||
async function getFormData() {
|
||
try {
|
||
// 触发表单验证
|
||
await validate();
|
||
} catch ({ errorFields }) {
|
||
if (errorFields) {
|
||
const firstField = errorFields[0];
|
||
if (firstField) {
|
||
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
|
||
}
|
||
}
|
||
return Promise.reject(errorFields);
|
||
}
|
||
return transformData(toRaw(formData))
|
||
}
|
||
|
||
async function submitForm() {
|
||
const mainData = await getFormData();
|
||
const isUpdate = Boolean(mainData.id);
|
||
const values = Object.assign({}, dbData, mainData);
|
||
// 新增提案只保存主表;已有提案编辑或流程提交时才采集子表数据。
|
||
if (isUpdate) {
|
||
const subData = await getSubFormAndTableData();
|
||
Object.assign(values, subData);
|
||
}
|
||
console.log('表单提交数据', values)
|
||
const result = await saveOrUpdate(values, isUpdate);
|
||
// 新增时,保存成功后绑定附件的 bussinessId
|
||
if (!isUpdate) {
|
||
const newId = typeof result === 'string' ? result : (result?.id || result);
|
||
if (newId) {
|
||
formData.id = newId;
|
||
await beforeFileRef.value?.bindBussinessId(`${newId}:before`);
|
||
await afterFileRef.value?.bindBussinessId(`${newId}:after`);
|
||
}
|
||
}
|
||
emit('success');
|
||
}
|
||
|
||
function setFieldsValue(values) {
|
||
if(values){
|
||
Object.keys(values).map(k=>{
|
||
formData[k] = values[k];
|
||
});
|
||
}
|
||
}
|
||
|
||
function handleFormChange(key, value) {
|
||
formData[key] = value;
|
||
}
|
||
|
||
return {
|
||
improvementDeptScoreTableRef,
|
||
improvementDeptScoreTable,
|
||
improvementInstituteVoteTableRef,
|
||
improvementInstituteVoteTable,
|
||
validatorRules,
|
||
validateInfos,
|
||
activeKey,
|
||
loading,
|
||
formData,
|
||
setFieldsValue,
|
||
handleFormChange,
|
||
formItemLayout,
|
||
longLabelCol,
|
||
longWrapperCol,
|
||
halfLabelCol,
|
||
halfWrapperCol,
|
||
disabled,
|
||
showSubTables,
|
||
showFlowSubmitButton,
|
||
getFormData,
|
||
submitForm,
|
||
add,
|
||
edit,
|
||
formRef,
|
||
beforeFileRef,
|
||
afterFileRef,
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
<style lang="less" scoped>
|
||
.ant-tabs-tabpane.sub-one-form {
|
||
max-height: 340px;
|
||
overflow: auto;
|
||
}
|
||
</style>
|